데이터 로딩의 3대 요소

__init__ (초기화)

def __init__(self, file_list, transform=None, phase='train'):
    self.file_list = file_list
    self.transform = transform
    self.phase = phase
    
    self.labels = []
    for path in self.file_list:
        folder = os.path.basename(os.path.dirname(path))
        label = 1 if folder == "dog" else 0
        self.labels.append(label)

역할

  • 데이터셋 객체가 생성될 때 단 한 번만 실행되는 초기화 함수
  • 데이터셋에 필요한 메타 정보를 미리 준비하고 저장

상세 동작

  1. 파일 경로 저장: self.file_list에 모든 이미지 파일 경로를 저장
  2. 변환기 저장: 이미지 전처리에 사용할 transform 함수를 저장
  3. 라벨 생성:
    • 각 이미지 파일의 경로에서 부모 폴더명 추출 (os.path.dirnameos.path.basename)
    • 폴더명이 “dog”이면 라벨 1, “cat”이면 라벨 0으로 매핑
    • 모든 이미지의 라벨을 미리 생성하여 리스트에 저장

왜 미리 라벨을 만들까?

  • __getitem__에서 매번 폴더명을 파싱하는 것보다 효율적
  • 한 번만 처리하고 메모리에 저장해두면 반복 접근 시 빠름

__len__ (길이 반환)

def __len__(self):
    return len(self.file_list)

역할

  • 데이터셋의 전체 샘플 개수를 반환
  • Python의 len() 함수 호출 시 자동으로 실행됨

사용 예시

dataset = DogvsCatDataset(file_list, transform)
print(len(dataset))  # __len__() 호출 → 전체 이미지 개수 출력

DataLoader와의 관계

  • DataLoader는 __len__()을 통해 전체 배치 수를 계산
  • 예: 1000개 이미지, batch_size=32 → 32개 배치 생성 (마지막 배치는 8개)

__getitem__ (개별 샘플 반환)

def __getitem__(self, index):
    img_path = self.file_list[index]
    img = Image.open(img_path)
    img_transformed = self.transform(img, self.phase)
    
    label = torch.tensor(self.labels[index], dtype=torch.long)
    
    return img_transformed, label

역할

  • 특정 인덱스의 샘플(이미지 + 라벨) 1개를 반환
  • DataLoader가 배치를 구성할 때 반복적으로 호출

상세 동작

  1. 이미지 로딩:
    • index번째 파일 경로를 가져옴
    • Image.open()으로 디스크에서 이미지를 읽어 메모리에 로드
  2. 이미지 변환:
    • self.transform으로 전처리 (리사이즈, 정규화, 텐서 변환 등)
    • phase 인자로 train/val 모드에 따라 다른 augmentation 적용 가능
  3. 라벨 텐서화:
    • 미리 생성한 self.labels[index]를 PyTorch 텐서로 변환
    • dtype=torch.long → 분류 문제의 정수 레이블용
  4. 반환: (이미지 텐서, 라벨 텐서) 튜플 반환

호출 시점

dataloader = DataLoader(dataset, batch_size=32, shuffle=True)
 
for images, labels in dataloader:
    # 내부적으로 __getitem__(0), __getitem__(15), ... 
    # 32번 호출하여 배치 구성
    print(images.shape)  # torch.Size([32, 3, 224, 224])
    print(labels.shape)  # torch.Size([32])

전체 동작 흐름

1. 데이터셋 생성
   dataset = DogvsCatDataset(file_list, transform)
   → __init__ 호출: 파일 목록 저장, 라벨 생성

2. DataLoader 생성
   dataloader = DataLoader(dataset, batch_size=32)
   → __len__ 호출: 배치 개수 계산

3. 학습 루프
   for batch in dataloader:
       → __getitem__(idx) 32번 호출
       → 각 샘플을 배치로 collate
       → 모델에 전달

핵심 포인트

메서드호출 시점횟수목적
__init__객체 생성 시1번초기화, 메타정보 준비
__len__len() 호출 시필요 시데이터셋 크기 반환
__getitem__배치 구성 시매우 많음개별 샘플 로드
효율성: __init__에서 무거운 작업(라벨 생성)을 미리 하고, __getitem__에서는 빠른 인덱싱만 수행하는 것이 일반적인 패턴입니다.