from torchvision import datasets, transforms
from torch.utils.data import DataLoader
import matplotlib.pyplot as plt
import numpy as np
# 🌼 데이터 경로
flowers102_data_dir = "datasets"
# 🌻 Transform 정의
transform = transforms.Compose([
transforms.Resize((128, 128)), # 1. 이미지 크기를 128 x 128 픽셀로 조정
transforms.ToTensor() # PIL 이미지를 tensor형으로 변환
])
# 📦 Flowers102 불러오기 (train split만)
flowers102_trainset = datasets.Flowers102(
root=flowers102_data_dir, # root dir of the dataset
download=True, # 지정 경로에 데이터가 없을시 다운받을지 여부
split='train', # 'train' -> train dataset을 불러온다
transform=transform # 전처리 함수 지정
)
transform은 이미지 데이터를 모델 학습에 적절한 형태로 전처리합니다. 전처리 함수 정의 코드에서 transforms.Compose()는 여러 이미지 변환 작업(Transform)을 순차적으로 묶어주는 역할을 합니다.Flowers102() 객체에 파라미터를 적절히 지정하여 불러옵니다. (Pytorch 공식 홈페이지 참고: Flowers102 — Torchvision 0.22 documentation🧐 전처리, 왜 필요할까요?
transform.Compose() 함수로 이런 전처리 과정들을 하나로 묶어주는 겁니다. print(type(flowers102_trainset))
출력 결과:
<class 'torchvision.datasets.flowers102.Flowers102'>
flowers102_trainset은 torchvision 라이브러리의 Flowers102 클래스 인스턴스입니다.torchvision.datasets.flowers102 모듈에 정의되어 있으며, 이름 그대로 Oxford Flowers 102 데이터셋을 나타냅니다.from torch.utils.data import Dataset
isinstance(flowers102_trainset, Dataset)
출력 결과:
True
isinstance() 함수: isinstance(obj, class)는 obj가 class의 인스턴스인지 확인해서, 맞으면 True, 아니면 False를 반환합니다.True 이므로, flowers102_trainset이 torch.utils.data.Dataset을 상속받고 있다는 의미입니다. 이는 PyTorch의 DataLoader로 로딩하거나, len(), __getitem() 같은 메서드를 사용할 수 있음을 뜻합니다.flowers102_trainset 인스턴스가 생성되기까지의 클래스 및 모듈 호출 흐름을 표현한 구조도입니다.torchvision ← 라이브러리
└── datasets ← 서브모듈 (모듈 모음)
└── flowers102.py ← 모듈 (.py 파일)
└── Flowers102 ← 클래스
└── flowers102_trainset ← 인스턴스 (클래스 호출 결과)
flowers102_trainset
출력 결과:
Dataset Flowers102
Number of datapoints: 1020
Root location: datasets
split=train
StandardTransform
Transform: Compose(
Resize(size=(128, 128), interpolation=bilinear, max_size=None, antialias=True)
ToTensor()
)
# 🛒 Dataloader
train_loader = DataLoader(
flowers102_trainset,
batch_size=8,
shuffle=True,
drop_last=True
)
DataLoader를 이용해학습용 데이터셋을 지정한 배치 크기(batch_size=8)로 나누고,
shuffle=True 옵션을 통해 매 epoch마다 데이터를 무작위로 섞습니다.
drop_last=True 옵션을 통해 마지막 배치의 크기가 지정한 배치의 크기보다 작을 경우 마지막 배치를 버립니다.
이렇게 하면 모든 배치가 동일한 크기(8개)로 유지되어, 모델 학습 시 배치 단위 연산이 일정하게 처리됩니다.
train_loader는 모델 학습 시 반복(iteration) 가능한 iterable 객체입니다.# step
len(train_loader)
출력 결과:
127
len() 함수를 이용해 한 epoch 동안의 총 step 수 계산할 수 있습니다.drop_last=True 옵션을 주었으므로 마지막 배치를 버렸기 때문에 step은 127번이 됩니다.# 🔍 배치 하나 확인
images, labels = next(iter(train_loader))
images, labels
(tensor([[[[0.2549, 0.2706, 0.2980, ..., 0.1765, 0.2000, 0.2000],
[0.2549, 0.2549, 0.2863, ..., 0.1843, 0.1922, 0.1922],
[0.2588, 0.2941, 0.4000, ..., 0.1804, 0.1882, 0.1882],
...,
[0.2588, 0.2549, 0.2353, ..., 0.1961, 0.1961, 0.2039],
[0.2588, 0.2588, 0.2392, ..., 0.2000, 0.2039, 0.2039],
[0.2667, 0.2667, 0.2510, ..., 0.2118, 0.2118, 0.2118]],
...,
[0.1412, 0.2824, 0.2863, ..., 0.1608, 0.1373, 0.1373],
[0.0588, 0.1373, 0.0941, ..., 0.1686, 0.1294, 0.1020],
[0.0314, 0.0392, 0.0314, ..., 0.1647, 0.1373, 0.1216]]]]),
tensor([14, 97, 67, 52, 79, 26, 62, 27]))
train_loader: 배치 단위로 데이터를 꺼낼 수 있는 반복 가능한 객체 (iterable)iter(train_loader): iterable을 iter() 함수를 이용해 iterator로 변환next(iter(train_loader)): 안에 있는 iterator에서 값을 하나씩 꺼냄.💡 (참고) iterable과 iterator
iterable: 리스트, 튜플, 문자열, 딕셔너리 등iterator: `next()` 메서드를 가지고 있어서 값을 하나씩 꺼낼 수 있는 객체iter()는 반복 가능한 객체(iterable)를 이터레이터(iterator) 로 변환합니다.# 🎨 시각화 함수
def imshow(imgs, labels):
imgs = imgs.numpy()
fig, axs = plt.subplots(1, len(imgs), figsize=(15, 4))
for i in range(len(imgs)):
img = np.transpose(imgs[i], (1, 2, 0)) # (C, H, W) → (H, W, C)
axs[i].imshow(img)
axs[i].set_title(f"Label: {labels[i].item()}")
axs[i].axis('off')
plt.show()
# 🖼️ 배치 이미지 확인
imshow(images, labels)

imgs.numpy() : PyTorch 텐서를 NumPy 배열로 변환합니다. (ToTensor()로 변환된 데이터는 Tensor 형태이므로 시각화를 위해 변환 필요)np.transpose(imgs[i], (1, 2, 0)) : 이미지의 채널 순서를 PyTorch 형식 (C, H, W)에서 matplotlib이 인식할 수 있는 (H, W, C)로 변경합니다.imshow(images, labels) : images와 labels로 구성된 한 배치(batch) 를 시각화합니다. images는 DataLoader에서 추출한 이미지 텐서이고, labels는 해당 이미지들의 클래스(정수형 라벨)입니다.