2025.05.18
Part12. 파이토치
- Chapter.06 데이터다루기
- 01_ImageFolder
- 02_Custom Dataset
- 03_Transforms
ImageFolder
torch의 데이터불러오기 구조
Pytorch에서는 utils 패키지에서 Load할 수 있다. torch.utils.data.DataLoader( ) → 인수로 batch_size와 datasets을 받는다.
import torch
from torch import nn
from torch import optim
import torch.nn.functional as F
from torchvision import datasets, transforms
batch_size = 32
train_loader = torch.utils.data.DataLoader(
datasets.MNIST('datasets/', train=True, download=True,
transform=transforms.Compose([
transforms.ToTensor(),
transforms.Normalize(mean=(0.5,), std=(0.5,))
])),
batch_size=batch_size,
shuffle=True
)
여기에서 datasets.MNIST(...)만 따로 보면, 이는 하나의 Iterator (아직은 아니지만, iterable한 객체이다)이다.
그래서 아래처럼 iterator로 변환하여 사용할수도 있다.
제대로 확인되는지.. 아래처럼 확인해볼 수 있다. 여기서 커널 충돌현상은 제거하고 해야한다. (imshow와 tensor 혹은 torch 충돌제거는 해당 링크 참조)
아래처럼 확인 시, 정상적으로 확인되는 것을 알 수 있다.
import os
os.environ['KMP_DUPLICATE_LIB_OK'] = 'True'
import matplotlib.pyplot as plt
import numpy as np
img = x
img = img.squeeze(0) # [1, 28, 28]에서 1 채널 차원 제거
img = img * 0.5 + 0.5 # Normalize 복원
img = img.numpy()
plt.imshow(img, 'gray')
plt.axis('off')
plt.show()
- 배치사이즈 32 → 한 번에 32개 데이터씩 학습
- 60000개 데이터 → 1875번 배치학습(60000 ÷ 32)
- 에포크 5 → 1875번 배치학습을 5회 반복
ImageFolder란?
Local에 있는 데이터를 torch.utils.data.dataset.Dataset 으로 만들기
ImageFolder : 간단하게 로컬에 있는 이미지 데이터셋을 불러온다. 다만, 디렉토리 구조가 아래와 같아야 한다.
- Dataset(디렉토리)
- Class_0
- xxx.png
- yyy.png
- ....
- Class_1
- xxx.png
- yyy.png
- ....
- Class_2
- xxx.png
- yyy.png
- ....
- Class_0
우선 디렉토리 구조를 위와 같이 구현한다. (*기존의 MNIST 데이터셋 다운로드 받은 폴더 활용)
아래와 같이 train_dir 경로의 폴더를 보면, class로 분류되어 있는 것을 확인할 수 있다.
datasetdir = "../datasets"
train_dir = datasetdir + '/mnist_png/training'
test_dir = datasetdir + '/mnist_png/testing'
폴더의 구조가 규칙에 맞게 되어있기 때문에 ImageFolder 메서드를 이용해서 해당 데이터를 DataLoad 하고, 이터레이터로 사용할 수 있다.
train_dataset = datasets.ImageFolder(
root=train_dir,
transform=transforms.Compose([
transforms.ToTensor(),
transforms.Normalize((0.5,), (0.5,))
])
)
test_dataset = datasets.ImageFolder(
root=test_dir,
transform=transforms.Compose([
transforms.ToTensor(),
transforms.Normalize((0.5,), (0.5,))
])
)
이제 DataLoader를 생성할 수 있다. (batch_size와 Dataset을 인자로 받는)
train_loader = torch.utils.data.DataLoader(
train_dataset,
batch_size=32,
shuffle=True
)
test_loader = torch.utils.data.DataLoader(
test_dataset,
batch_size=32,
shuffle=True
)
x, y = next(iter(train_loader))
x.shape, y.shape
>> (torch.Size([32, 3, 28, 28]), torch.Size([32]))
위가 로컬에 있는 데이터셋(이미지)을 불러오는 가장 기본적인 방법이다.
Custom Dataset
앞서 배웠던 ImageFolder는 디렉토리의 구조가 잘 정해져있어야 한다. Custom Dataset은 실무에 조금 더 가까운 데이터셋을 만들 수 있다. 이는 직접 torch.utils.data.Dataset 메서드를 상속 받아서 데이터셋을 구현하는 것이다.
필요한 라이브러리, 패키지는 아래와 같다.
import os
from glob import glob
import torch
from PIL import Image
from torchvision import datasets, transforms
사용할 데이터셋은 cifar 데이터셋이고, 해당 데이터는 파일 이름으로는 class(라벨) 구분이 가능하지만, 위 MNIST 데이터셋처럼 각 라벨의 폴더가 있지는 않다. 그렇기 때문에 ImageFolder는 사용이 불가능 하다.
일단 cifar_dir폴더에 있는 labels.txt 파일을 읽고 이를 label 리스트로 적용하겠다.
with open(os.path.join(cifar_dir, 'labels.txt'), 'r') as f:
label_list = f.read()
label_list
>> 'airplane\nautomobile\nbird\ncat\ndeer\ndog\nfrog\nhorse\nship\ntruck\n'
string 값을 일부 수정해준다. 그러면 원하는 모양으로 된 것을 알 수 있다.
이제 glob 함수를 이용해서 png 라는 이름이 들어가는 모든 파일들을 읽어온다.
train_path = glob(train_dir + '/*.png')
test_path = glob(test_dir + '/*.png')
이제 Class 를 구현해서 DataLoader를 생성한다.
import torch.utils
class Dataset(torch.utils.data.Dataset):
def __init__(self, data_paths, transform=None):
super(Dataset, self).__init__()
self.data_paths = data_paths
self.transform = transform
def __len__(self, ):
return len(self.data_paths)
def __getitem__(self, idx):
path = self.data_paths[idx]
image = Image.open(path)
label_name= path.split('.png')[0].split('_')[-1].strip()
label = label_list.index(label_name)
if self.transform:
image = self.transform(image)
return image, label
device = torch.device('cuda' if torch.cuda.is_available() else 'cpu')
batch_size = 32
train_loader = torch.utils.data.DataLoader(
Dataset(train_dir, transform=transforms.ToTensor()),
batch_size=batch_size,
shuffle=True
)
이렇게 로컬에 데이터셋이 한 폴더 안에 있어도, 각 데이터 파일의 제목이 이번 Case와 동일하다면, 또는 파일의 이름으로 Label을 구분할 수 있다면..아래와 같이 DataLoader 또는 Dataset으로 만들어서 구현할 수 있다.
Transform 이해하기
transform은 torchvision 패키지에서 제공하는 모듈이다. 데이터의 전처리를 순서대로 처리할 수 있도록 해준다.
import os
from glob import glob
import torch
import torch.nn as nn
import torch.nn.functional as F
from torchvision import datasets, transforms
from PIL import Image
import numpy as np
import matplotlib.pyplot as plt
일단 샘플 이미지를 하나 불러와서 확인해보면..
device = torch.device('cuda' if torch.cuda.is_available() else 'cpu')
image = Image.open('./sample.jpg')
plt.imshow(image)
plt.axis('off')
plt.show()
이제 이 image의 shape을 확인하려면, 일단 numpy의 array 형태로 변환해야 한다. 이 image를 이용해서 실제 transform이 어떻게 작동되는지 알아볼 수 있다.
np.array(image).shape
>> (527, 936, 3)
실제 Transform의 기능들은 아래와 같이 확인할 수 있다.
Transform on Tensor
우선 제일 많이 사용하는 기능은 Resize( ) 이다. 아래와 같이
transforms.Resize((512, 512))(image)
RandomCrop( ) 함수도 잘 쓰인다. 이미지 랜덤하게 자르고 특정 크기로 변환한다.
transforms.RandomCrop(size=(512,512))(image)
또 ColorJitter( ) 함수가 있다. 밝기를 랜덤하게 조정할 수 있다.
transforms.ColorJitter(brightness=1)(image)
Grayscale( )도 많이 사용된다. 흑백전환이다.
Pad( ) 연산도 있다. padding 효과를 보여준다.
transforms.Pad(padding=(20, 10))(image)
RandomAffine(degrees=90) 함수 역시 많이 사용된다. 90도 내에서 랜덤하게 이미지를 회전하는 것이다.
transforms.RandomAffine(degrees=90)(image)
위와 같은 다양한 기능들을 Compose 모듈로 묶어서 적용하던가 또는 리스트 형태로 묶어서 적용할 수 있다.
transforms.Compose([
transforms.ToTensor(),
transforms.RandomAffine(degrees=90)
])
# 또는
transforms_list = [
transforms.ToTensor(),
transforms.RandomAffine(degrees=90)
]
# 랜덤하게 적용한다 p는 확률값이다
transforms.RandomApply(
transforms_list, p=0.5
)
'Bootcamp_zerobase > Pytorch' 카테고리의 다른 글
Pytorch의 모델링 및 학습 (0) | 2025.05.18 |
---|---|
Pytorch 모델 학습 (0) | 2025.04.28 |
최적화 및 미분 (0) | 2025.04.27 |
Tensor 다루기 (1) | 2025.04.27 |
Pytorch #4 : 식물잎 사진으로 질병분류 (0) | 2025.04.26 |