GAN 변환을 위한 임시 이미지셋 생성
굳이 모든 이미지를 변환할 필요 없이 각 감정당 3000개만 변환하자…
split 코드
import os import shutil # 원본 이미지 폴더 경로 및 출력 폴더 경로 input_folder = './image' output_folder = './image_parts_3000' emotions = ['amusement', 'anger', 'awe', 'contentment', 'disgust', 'excitement', 'fear', 'sadness'] # 최대 가져올 이미지 개수 max_images = 3000 # 이미지 최대 크기 3MB = 3 * 1024 * 1024 bytes max_file_size = 3 * 1024 * 1024 # 3MB def copy_images(emotion): src_dir = os.path.join(input_folder, emotion) dest_dir = os.path.join(output_folder, emotion) # 폴더가 없으면 생성 if not os.path.exists(dest_dir): os.makedirs(dest_dir) # 이미지 파일 이름 패턴 설정 counter = 0 index = 0 while counter < max_images: # 이미지 이름 형식 맞추기 (00000 -> 00001 등) file_name = f"{emotion}_{index:05d}.jpg" file_path = os.path.join(src_dir, file_name) # 이미지 파일이 존재하고, 크기가 3MB 이하일 때만 복사 if os.path.exists(file_path): file_size = os.path.getsize(file_path) if file_size <= max_file_size: shutil.copy(file_path, os.path.join(dest_dir, file_name)) counter += 1 else: print(f"Skipping {file_path}, size: {file_size / 1024 / 1024:.2f} MB") # 다음 파일로 넘어감 index += 1 # 더 이상 이미지 파일이 없다면 중단 if index > 100000: # 큰 숫자로 안전한 한계 설정 break print(f"{emotion}: {counter} images copied to {dest_dir}") # 모든 감정 폴더에 대해 이미지 처리 for emotion in emotions: copy_images(emotion) print("Image splitting completed.")
주요 특징
- 입력 및 출력 폴더 경로:
- 원본 이미지 폴더는
./image, 출력 폴더는 **./image_parts_3000*로 설정되어 있습니다. - 감정 이름(예:
amusement,anger)을 가진 폴더에서 작업을 진행합니다.
- 이미지 파일 순서대로 가져오기:
- 이미지 파일은
{emotion}_00000.jpg부터 순서대로 읽어옵니다. 만약 이미지가 누락되었으면(00005.jpg가 없으면), 그 번호를 건너뛰고 다음 번호로 넘어갑니다.
- 3000개 제한:
- 각 폴더에서 최대 3000개의 이미지만 가져오며, 빈 번호를 건너뛰고 3000개가 찰 때까지 작업을 진행합니다.
- 폴더 생성:
- 출력 폴더가 없으면 해당 폴더를 새로 생성합니다. 감정 이름에 따라 폴더가 따로 생성됩니다.
shutil.copy:shutil.copy로 파일을 복사합니다. 이미지가 존재할 때만 복사하며, 파일이 없는 경우는 건너뜁니다.
- 파일 크기 확인:
os.path.getsize(file_path)를 사용하여 각 파일의 크기를 바이트 단위로 가져옵니다.- 크기가 3MB(3 * 1024 * 1024 바이트)를 초과하는 파일은 건너뜁니다.
- 파일 크기 조건 추가:
- 이미지가 존재하고 3MB 이하일 때만 복사합니다. 그렇지 않으면 해당 파일을 건너뛰고 다음 파일로 넘어갑니다.
print로 3MB를 초과하는 파일을 건너뛰는 이유를 출력하여 확인할 수 있습니다.
CycleGAN - image to monet style
커맨드 라인
python test.py --dataroot ./datasets/mydata --name style_monet_pretrained --model test --input_nc 3 --no_dropout --results_dir ./output_dir --preprocess none --num_test 30000
총 24000개의 이미지에 대해서 일괄적으로 처리한다.
결과
전부 실행한 이후 커맨드를 통해서 real 이미지를 삭제해준다.
find ./output_dir/style_monet_pretrained/ -name "*_real*" -delete
이미지 분류
이렇게 정리된 24000개의 이미지들은 하나의 폴더 안에 존재하게 되는데, 이를 정리해서 각 감정에 맞는 이미지 폴더에 넣어주자.
import os import shutil # 원본 이미지가 있는 폴더 경로 source_folder = './output_dir/style_monet_pretrained/test_latest/images' # 감정 목록과 각 감정에 해당하는 폴더 경로 emotions = ['amusement', 'anger', 'awe', 'contentment', 'disgust', 'excitement', 'fear', 'sadness'] destination_base_folder = './output_dir_sorted' # 감정에 맞는 폴더를 생성하는 함수 def create_folders(): for emotion in emotions: emotion_folder = os.path.join(destination_base_folder, emotion) if not os.path.exists(emotion_folder): os.makedirs(emotion_folder) # 이미지 파일을 각 감정에 맞는 폴더로 이동하는 함수 def sort_images(): for filename in os.listdir(source_folder): # 파일 이름에서 감정을 추출 (예: 'anger_00001.jpg') for emotion in emotions: if filename.startswith(emotion): source_path = os.path.join(source_folder, filename) destination_folder = os.path.join(destination_base_folder, emotion) destination_path = os.path.join(destination_folder, filename) # 파일 이동 shutil.move(source_path, destination_path) print(f"Moved {filename} to {destination_folder}") break # 메인 실행 부분 if __name__ == "__main__": # 감정별 폴더 생성 create_folders() # 이미지 분류 및 이동 sort_images() print("Image sorting completed.")
push_to_hub
준비 단계 - rename
- 현재 이미지들의 이름은 {감정}_00000_fake.jpg 이다. 이 이름을 새롭게 정의하고 중간중간 숫자가 없어 비어있는 인덱싱도 제대로 rename할 것이다.
import os # 이미지가 저장된 폴더 경로 base_folder_path = 'E:\\EmoSet-118K_MonetStyle\\Image' # 새로운 파일 이름 형식 new_name_format = '{}_{:05d}_GAN_monetstyle.jpg' # 감정 리스트 emotions = ['amusement', 'anger', 'awe', 'contentment', 'disgust', 'excitement', 'fear', 'sadness'] def rename_images(emotion): # 감정 폴더 경로 src_dir = os.path.join(base_folder_path, emotion) if not os.path.exists(src_dir): print(f"Directory {src_dir} does not exist.") return # 감정별로 새로운 인덱스를 0부터 시작 new_index = 0 # 감정별로 파일을 정렬하여 순서대로 처리 image_files = sorted([f for f in os.listdir(src_dir) if f.endswith('.jpg') or f.endswith('.png')]) for filename in image_files: # 원본 파일 경로 old_file_path = os.path.join(src_dir, filename) # 새 파일 이름 형식 지정 (감정 이름, 새로운 인덱스 사용) new_filename = new_name_format.format(emotion, new_index) new_file_path = os.path.join(src_dir, new_filename) # 파일 이름 변경 os.rename(old_file_path, new_file_path) print(f"Renamed {filename} to {new_filename}") # 인덱스 증가 new_index += 1 # 모든 감정 폴더에 대해 이미지 이름 변경 for emotion in emotions: rename_images(emotion) print("Image renaming completed.")
→ 이 코드를 통해서 이름을 {감정}_00000_GAN_monetstyle.jpg로 변경하였다!
준비 단계 - json파일 생성
- 각 감정 폴더 내에 각 이미지에 대응하는 info를 저장한 {감정}.json파일을 생성한다
import os import json # 이미지가 저장된 기본 폴더 경로 base_folder_path = 'E:\\EmoSet-118K_MonetStyle\\Image' # 감정 목록과 대응되는 label 값 emotions = ['amusement', 'anger', 'awe', 'contentment', 'disgust', 'excitement', 'fear', 'sadness'] emotion_to_label = {emotion: idx for idx, emotion in enumerate(emotions)} # JSON 파일을 생성하는 함수 def create_json_for_emotion(emotion): # 감정 폴더 경로 src_dir = os.path.join(base_folder_path, emotion) if not os.path.exists(src_dir): print(f"Directory {src_dir} does not exist.") return # 감정별로 3000개 이미지를 처리 image_files = sorted([f for f in os.listdir(src_dir) if f.endswith('.jpg') or f.endswith('.png')]) json_data_list = [] # JSON 데이터 리스트 for filename in image_files[:3000]: # 최대 3000개만 처리 # 원본 파일 이름에서 확장자를 제외한 부분 base_filename = os.path.splitext(filename)[0] # 새로운 경로를 포함한 이미지 파일 이름 new_image_path = f"image/{emotion}/{filename}" # label 값 설정 (감정에 따른 숫자) label = emotion_to_label[emotion] # 이미지에 맞는 JSON 구조 생성 json_data = { "image": new_image_path, "emotion": emotion, "label": label, "image_id": base_filename } # JSON 데이터 리스트에 추가 json_data_list.append(json_data) # JSON 파일 이름 설정 json_filename = os.path.join(base_folder_path, f"{emotion}_data.json") # JSON 파일 쓰기 with open(json_filename, 'w') as json_file: json.dump(json_data_list, json_file, indent=4) print(f"Created JSON for {emotion} with {len(json_data_list)} images.") # 모든 감정에 대해 JSON 생성 for emotion in emotions: create_json_for_emotion(emotion) print("JSON creation completed.")
→ json파일 생성, 각 감정 폴더 내에 위치.

{ "image": "image/amusement/amusement_00000_GAN_monetstyle.jpg", "emotion": "amusement", "label": 0, "image_id": "amusement_00000_GAN_monetstyle" },
→ json 파일 내 내용물은 이렇게 구성되어 있음. 데이터 학습에 있어 label은 숫자로 되어있어야 하기에 이렇게 구성하였음…
본론 - push_to_hub() 사용
가상환경 패키지
Package Version ------------------ ----------- aiohappyeyeballs 2.4.0 aiohttp 3.10.6 aiosignal 1.3.1 async-timeout 4.0.3 attrs 24.2.0 certifi 2024.8.30 charset-normalizer 3.3.2 colorama 0.4.6 datasets 3.0.0 dill 0.3.8 filelock 3.16.1 frozenlist 1.4.1 fsspec 2024.6.1 huggingface-hub 0.25.1 idna 3.10 multidict 6.1.0 multiprocess 0.70.16 numpy 2.0.2 packaging 24.1 pandas 2.2.3 pillow 10.4.0 pip 24.2 pyarrow 17.0.0 python-dateutil 2.9.0.post0 pytz 2024.2 PyYAML 6.0.2 requests 2.32.3 setuptools 75.1.0 six 1.16.0 tqdm 4.66.5 typing_extensions 4.12.2 tzdata 2024.2 urllib3 2.2.3 wheel 0.44.0 xxhash 3.5.0 yarl 1.12.1
import os import json from datasets import Dataset, Features, Image, Value, concatenate_datasets from huggingface_hub import HfApi # Hugging Face API 키 설정 (옵션) api_token = "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" api = HfApi() # 업로드할 감정 목록 emotions = ["amusement", "anger", "awe", "contentment", "disgust", "excitement", "fear", "sadness"] # 리포지토리 ID 설정 repo_id = "xodhks/Emoset118K_MonetStyle" # 기존 데이터셋 불러오기 (옵션) try: existing_dataset = load_dataset(repo_id, split='train') # 'train' 스플릿만 불러옴 except: existing_dataset = None # 각 감정에 대해 데이터를 처리 for emotion in emotions: json_path = f"E:/EmoSet-118K_MonetStyle/image/{emotion}/{emotion}_data.json" # JSON 파일 로드 with open(json_path, 'r') as f: emotion_data = json.load(f) # 이미지 파일 경로와 JSON에서 읽은 메타데이터를 결합 data = { "image": [], "emotion": [], "label": [], "image_id": [] } for item in emotion_data: # JSON 데이터에서 이미지 경로를 가져오고, 메타데이터를 추가 image_file = item["image"] # 이미지는 full path로 저장되어 있음 data["image"].append(image_file) data["emotion"].append(item["emotion"]) data["label"].append(item["label"]) # label은 이미 숫자 data["image_id"].append(item["image_id"]) # 새로운 Dataset 생성 features = Features({ "image": Image(), # 이미지 필드 "emotion": Value("string"), # 감정 필드 "label": Value("int32"), # 라벨 필드 (숫자) "image_id": Value("string") # 이미지 ID 필드 }) new_dataset = Dataset.from_dict(data, features=features) # 기존 데이터셋과 병합 if existing_dataset: combined_dataset = concatenate_datasets([existing_dataset, new_dataset]) else: combined_dataset = new_dataset existing_dataset = combined_dataset # 병합된 데이터셋을 Hugging Face Hub에 업로드 existing_dataset.push_to_hub( repo_id=repo_id, # 동일한 리포지토리에 업로드 token=api_token, max_shard_size="1GB" # 데이터셋이 큰 경우 샤딩 설정 ) print("All emotion datasets have been merged and uploaded successfully.")

push_to_hub()를 사용할 때 데이터 셋의 구조는 어떻게 되어있을까?
데이터셋의 구조에 대해 물어보았다
push_to_hub()로 Hugging Face Hub에 업로드된 데이터셋은 Hugging Face Datasets 라이브러리의 데이터셋 형식으로 저장됩니다. 이 형식은 일반적으로 CSV나 JSON 파일처럼 데이터 테이블의 구조를 가지고 있으며, 각 샘플(이미지, 텍스트, 기타 메타데이터)을 데이터셋의 필드에 매핑하여 관리합니다.저장되는 데이터의 형태:
- 열(column) 기반 구조: Hugging Face의 데이터셋은 데이터베이스나 데이터프레임과 유사한 열 기반 구조로 저장됩니다. 즉, 각 필드는 열을 나타내며, 각 이미지에 대한 정보(이미지 파일 경로, 감정 라벨, 이미지 ID 등)가 행으로 추가됩니다.
image: 이미지 파일의 경로(로컬 경로 또는 URL).emotion: 감정에 대한 문자열 값(예: "amusement", "anger" 등).label: 감정에 대응하는 숫자 라벨(0~7).image_id: 이미지 파일의 고유 ID.
예를 들어, 코드에서 생성된 데이터셋은 아래와 같은 구조로 저장됩니다:
image | emotion | label | image_id |
image/amusement/amusement_00000.jpg | amusement | 0 | amusement_00000 |
image/anger/anger_00001.jpg | anger | 1 | anger_00001 |
image/awe/awe_00002.jpg | awe | 2 | awe_00002 |
- 이미지 필드 관리: 이미지 파일 자체는 Hugging Face에서 파일 경로나 URL로 저장됩니다. 데이터셋의 각 행에서 이미지 필드는 해당 이미지 파일의 경로를 저장하며, 업로드할 때 Hugging Face Hub는 이미지 파일을 실제로 호스팅하여 접근할 수 있게 만듭니다. 데이터셋을 다운로드하면 해당 이미지를 로컬 파일 시스템이나 메모리에서 사용할 수 있습니다.
- 메타데이터와 함께 저장: 이미지를 포함한 메타데이터(감정, 라벨, 이미지 ID 등)는 각각 열로 저장됩니다. 데이터셋에 포함된 모든 이미지에 대해 해당 메타데이터가 함께 제공되어, 이를 쉽게 조회하거나 접근할 수 있습니다.
데이터셋과 JSON 매핑:
- Hugging Face Datasets 라이브러리는 기본적으로 열(column) 기반의 구조를 사용하므로, 별도로 JSON 파일을 업로드하거나 JSON을 활용하여 이미지 파일과 매핑할 필요가 없습니다.
- 대신, 각 필드(열)가 이미지 파일이나 라벨 등의 데이터를 효율적으로 저장할 수 있게 매핑되며, JSON 파일에서의 필드와 동일한 방식으로 메타데이터를 사용할 수 있습니다.
어떻게 데이터셋을 확인할 수 있나요?
- Hugging Face Hub에 데이터셋이 업로드된 후, 데이터셋 리포지토리 페이지에서 해당 데이터셋을 확인할 수 있습니다. 리포지토리에서 샘플 데이터를 미리 볼 수 있고, 각 **열(column)**이 어떻게 구성되어 있는지, 어떤 데이터가 포함되어 있는지 확인 가능합니다.
- Hugging Face에서 제공하는 데이터셋은 CSV, JSON, Parquet 같은 형식으로 다운로드할 수도 있으며, 파이썬 코드 내에서 Hugging Face Datasets 라이브러리를 사용하여 데이터셋을 쉽게 불러올 수 있습니다.
결론:
- Hugging Face에 **push_to_hub()**로 업로드된 데이터셋은 테이블 형태로 저장되며, 각 필드(열)에 이미지 경로와 라벨, 메타데이터가 저장됩니다.
- 이 데이터셋은 JSON 파일로 직접 저장되기보다는, 데이터베이스나 DataFrame과 같은 구조로 관리되며, 이미지 파일은 경로나 URL을 통해 연결됩니다.
Json파일이 어떻게 처리가 되는지 물어보았다.
JSON 파일이 data 변수에 저장되고 이후 어떻게 처리되는지 설명
코드에서 JSON 파일의 데이터를 **
data**라는 딕셔너리에 저장한 후, 이것을 어떻게 Hugging Face Hub에 업로드하는지 궁금한 것 같습니다. 아래는 코드 흐름을 설명하며, 각 단계에서 무엇이 일어나는지 설명해드리겠습니다.1. JSON 파일에서 데이터를 가져와 data 변수에 저장
data = { "image": [], "emotion": [], "label": [], "image_id": [] } for item in emotion_data: image_file = item["image"] # 이미지를 경로로 저장 data["image"].append(image_file) data["emotion"].append(item["emotion"]) data["label"].append(item["label"]) # 라벨은 이미 숫자로 저장됨 data["image_id"].append(item["image_id"])
- 이 단계에서는: JSON 파일에서 각 이미지와 관련된 이미지 경로, 감정(emotion), 라벨(label), 이미지 ID 등의 데이터를 추출하여
data딕셔너리에 저장합니다.
- 각 키의 의미:
image: 이미지 파일 경로가 저장됩니다.emotion: 감정 정보(예: "amusement", "anger" 등)가 문자열로 저장됩니다.label: 감정에 대한 라벨(숫자)이 저장됩니다.image_id: 이미지 파일의 고유 ID가 저장됩니다.
2. 데이터셋 생성 (new_dataset)
features = Features({ "image": Image(), # 이미지 필드 "emotion": Value("string"), # 감정 필드 "label": Value("int32"), # 라벨 필드 "image_id": Value("string") # 이미지 ID 필드 }) new_dataset = Dataset.from_dict(data, features=features)
- 이 단계에서는:
Dataset.from_dict()함수를 사용하여,data딕셔너리에서 새 데이터셋을 생성합니다.
Features: 데이터셋이 어떤 데이터 타입을 가지고 있는지 정의합니다.Image(): 이미지 필드로 설정되며, 이 값은 실제 이미지 파일을 참조하는 경로를 의미합니다.Value("string"):emotion과image_id는 문자열로 처리됩니다.Value("int32"):label은 정수로 처리됩니다.
new_dataset: 새로 만들어진 데이터셋 객체가 **new_dataset*에 저장됩니다.
3. 데이터셋 병합
if existing_dataset: combined_dataset = concatenate_datasets([existing_dataset, new_dataset]) else: combined_dataset = new_dataset
- 이 단계에서는: 기존 데이터셋과 **
new_dataset*를 병합합니다. 이 과정에서, 각 감정에 대한 데이터를 하나의 데이터셋으로 묶습니다.
concatenate_datasets: 여러 데이터셋을 병합하는 함수로, 기존 데이터셋과 새로 생성된 데이터셋을 하나로 묶습니다.
- 만약 **
existing_dataset*이 없으면,new_dataset이 그대로 **combined_dataset*이 됩니다.
4. Hugging Face Hub에 업로드
existing_dataset.push_to_hub( repo_id=repo_id, # 동일한 리포지토리에 업로드 token=api_token, max_shard_size="1GB" # 데이터셋이 큰 경우 샤딩 설정 )
- 이 단계에서는: 병합된 데이터셋(
existing_dataset)을 Hugging Face Hub에 업로드합니다. repo_id: Hugging Face Hub에서의 리포지토리 이름입니다. 여기서는 **xodhks/Emoset118K*로 지정되었습니다.token: API 토큰으로, Hugging Face Hub에 인증을 위한 키입니다.max_shard_size: 데이터가 매우 클 경우, 데이터를 나누어 업로드하는 최대 용량을 설정합니다(여기서는 1GB로 설정).
결론:
- JSON 파일에서 데이터를 읽어와
data딕셔너리에 저장합니다.
- 그 데이터를 기반으로 **
new_dataset*이라는 Hugging Face 데이터셋 객체를 생성합니다.
- 기존 데이터셋이 있는 경우, 이를 병합하여 하나의 데이터셋으로 만듭니다.
- 마지막으로, 병합된 데이터셋을 Hugging Face Hub에
push_to_hub()함수를 이용해 업로드합니다.
이 코드를 통해 각 감정에 해당하는 이미지 및 메타데이터를 포함하는 데이터셋을 Hub에 업로드할 수 있습니다.
Hugging Face Datasets 라이브러리에서 데이터를 **push_to_hub()**로 업로드하면, 데이터셋은 메타데이터 표로 저장되며, 이미지 파일 자체는 Parquet 형식 또는 파일 경로로 저장되지 않습니다. 대신, 데이터셋의 필드는 각각의 데이터 타입에 맞게 저장되며, 이미지 같은 경우는
Image() 객체로 처리됩니다.데이터셋의 구성:
- 메타데이터 표: Hugging Face Datasets는 일반적으로 CSV나 데이터프레임과 같은 구조로 메타데이터를 다룹니다. 각 이미지에 대한 메타데이터(예: 이미지 경로, 감정, 라벨)는 열(column) 형식으로 테이블에 저장됩니다. 이 메타데이터는 Parquet 형식으로 저장될 수도 있지만, Hugging Face에서는 다른 형식들도 지원합니다.
image: 이미지 파일의 경로(또는 이미지 자체).label: 이미지의 라벨(정수형).emotion: 감정에 대한 설명(문자열).image_id: 이미지 ID(문자열).
예를 들어, 데이터셋의 메타데이터는 아래와 같이 저장됩니다:
- 이미지 저장 방식:
- 이미지 파일 경로: 이미지 필드는 실제로 파일 경로를 저장하며, 데이터셋 로드 시 해당 경로에 있는 이미지 파일에 접근합니다. Hugging Face Hub에 업로드되면, 해당 이미지 파일이 업로드되어 호스팅됩니다. 이렇게 업로드된 이미지에 대한 경로는 클라우드 경로로 변환됩니다.
- Image 필드: 데이터셋에서 이미지를 처리할 때는
datasets.Image()형태로 저장되며, 이미지를 직접 파일 시스템에서 불러와 데이터셋에 포함시킬 수 있습니다.
- Parquet 형식: Hugging Face Datasets는 Parquet, CSV, JSON, Arrow 등 여러 형식을 지원합니다. 데이터셋이 매우 크거나 고성능 처리가 필요할 경우 Arrow 형식을 기본으로 사용합니다. Parquet 형식은 열 지향 형식으로 데이터 저장 및 처리 속도를 최적화합니다. 하지만 Parquet은 주로 메타데이터와 구조화된 데이터를 저장할 때 사용되며, 이미지는 보통 경로나 직접적인 파일로 관리됩니다.
예시:
데이터셋을 업로드한 후, Hugging Face Hub에서 다운로드하면 다음과 같이 데이터셋이 구성됩니다:
- 메타데이터 테이블: CSV 또는 Parquet 파일로 메타데이터가 저장되며, 이미지 경로와 이미지와 관련된 정보가 포함됩니다.
- 이미지 파일: 실제 이미지는 클라우드에 저장되거나 URL로 연결되며, 이미지 필드로 액세스할 수 있습니다.
결론적으로, 데이터셋은 메타데이터 표로 이루어져 있으며, 이미지 파일 자체는 파일 경로 또는 URL을 통해 액세스할 수 있게 됩니다.