HomeAboutMeBlogGuest
© 2025 Sejin Cha. All rights reserved.
Built with Next.js, deployed on Vercel
장지원 페이지/
📕
2024 UGRP
/
Member Page
Member Page
/
권태완
권태완
/
2024/10/01 - GAN 추가 변환

2024/10/01 - GAN 추가 변환

Tags

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.")
split_to_folder.py
1.5KB
 

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파일 생성, 각 감정 폴더 내에 위치.
      notion image
      { "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.")
notion image
 
 

push_to_hub()를 사용할 때 데이터 셋의 구조는 어떻게 되어있을까?

데이터셋의 구조에 대해 물어보았다
🤖
push_to_hub()로 Hugging Face Hub에 업로드된 데이터셋은 Hugging Face Datasets 라이브러리의 데이터셋 형식으로 저장됩니다. 이 형식은 일반적으로 CSV나 JSON 파일처럼 데이터 테이블의 구조를 가지고 있으며, 각 샘플(이미지, 텍스트, 기타 메타데이터)을 데이터셋의 필드에 매핑하여 관리합니다.

저장되는 데이터의 형태:

  1. 열(column) 기반 구조: Hugging Face의 데이터셋은 데이터베이스나 데이터프레임과 유사한 열 기반 구조로 저장됩니다. 즉, 각 필드는 열을 나타내며, 각 이미지에 대한 정보(이미지 파일 경로, 감정 라벨, 이미지 ID 등)가 행으로 추가됩니다.
    1. 예를 들어, 코드에서 생성된 데이터셋은 아래와 같은 구조로 저장됩니다:
      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
      • image: 이미지 파일의 경로(로컬 경로 또는 URL).
      • emotion: 감정에 대한 문자열 값(예: "amusement", "anger" 등).
      • label: 감정에 대응하는 숫자 라벨(0~7).
      • image_id: 이미지 파일의 고유 ID.
  1. 이미지 필드 관리: 이미지 파일 자체는 Hugging Face에서 파일 경로나 URL로 저장됩니다. 데이터셋의 각 행에서 이미지 필드는 해당 이미지 파일의 경로를 저장하며, 업로드할 때 Hugging Face Hub는 이미지 파일을 실제로 호스팅하여 접근할 수 있게 만듭니다. 데이터셋을 다운로드하면 해당 이미지를 로컬 파일 시스템이나 메모리에서 사용할 수 있습니다.
  1. 메타데이터와 함께 저장: 이미지를 포함한 메타데이터(감정, 라벨, 이미지 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로 설정).

결론:

  1. JSON 파일에서 데이터를 읽어와 data 딕셔너리에 저장합니다.
  1. 그 데이터를 기반으로 **new_dataset*이라는 Hugging Face 데이터셋 객체를 생성합니다.
  1. 기존 데이터셋이 있는 경우, 이를 병합하여 하나의 데이터셋으로 만듭니다.
  1. 마지막으로, 병합된 데이터셋을 Hugging Face Hub에 push_to_hub() 함수를 이용해 업로드합니다.
이 코드를 통해 각 감정에 해당하는 이미지 및 메타데이터를 포함하는 데이터셋을 Hub에 업로드할 수 있습니다.
 
🤖
Hugging Face Datasets 라이브러리에서 데이터를 **push_to_hub()**로 업로드하면, 데이터셋은 메타데이터 표로 저장되며, 이미지 파일 자체는 Parquet 형식 또는 파일 경로로 저장되지 않습니다. 대신, 데이터셋의 필드는 각각의 데이터 타입에 맞게 저장되며, 이미지 같은 경우는 Image() 객체로 처리됩니다.

데이터셋의 구성:

  1. 메타데이터 표: Hugging Face Datasets는 일반적으로 CSV나 데이터프레임과 같은 구조로 메타데이터를 다룹니다. 각 이미지에 대한 메타데이터(예: 이미지 경로, 감정, 라벨)는 열(column) 형식으로 테이블에 저장됩니다. 이 메타데이터는 Parquet 형식으로 저장될 수도 있지만, Hugging Face에서는 다른 형식들도 지원합니다.
    1. 예를 들어, 데이터셋의 메타데이터는 아래와 같이 저장됩니다:
      • image: 이미지 파일의 경로(또는 이미지 자체).
      • label: 이미지의 라벨(정수형).
      • emotion: 감정에 대한 설명(문자열).
      • image_id: 이미지 ID(문자열).
  1. 이미지 저장 방식:
      • 이미지 파일 경로: 이미지 필드는 실제로 파일 경로를 저장하며, 데이터셋 로드 시 해당 경로에 있는 이미지 파일에 접근합니다. Hugging Face Hub에 업로드되면, 해당 이미지 파일이 업로드되어 호스팅됩니다. 이렇게 업로드된 이미지에 대한 경로는 클라우드 경로로 변환됩니다.
      • Image 필드: 데이터셋에서 이미지를 처리할 때는 datasets.Image() 형태로 저장되며, 이미지를 직접 파일 시스템에서 불러와 데이터셋에 포함시킬 수 있습니다.
  1. Parquet 형식: Hugging Face Datasets는 Parquet, CSV, JSON, Arrow 등 여러 형식을 지원합니다. 데이터셋이 매우 크거나 고성능 처리가 필요할 경우 Arrow 형식을 기본으로 사용합니다. Parquet 형식은 열 지향 형식으로 데이터 저장 및 처리 속도를 최적화합니다. 하지만 Parquet은 주로 메타데이터와 구조화된 데이터를 저장할 때 사용되며, 이미지는 보통 경로나 직접적인 파일로 관리됩니다.

예시:

데이터셋을 업로드한 후, Hugging Face Hub에서 다운로드하면 다음과 같이 데이터셋이 구성됩니다:
  • 메타데이터 테이블: CSV 또는 Parquet 파일로 메타데이터가 저장되며, 이미지 경로와 이미지와 관련된 정보가 포함됩니다.
  • 이미지 파일: 실제 이미지는 클라우드에 저장되거나 URL로 연결되며, 이미지 필드로 액세스할 수 있습니다.
결론적으로, 데이터셋은 메타데이터 표로 이루어져 있으며, 이미지 파일 자체는 파일 경로 또는 URL을 통해 액세스할 수 있게 됩니다.