DataLoader를 왜, 언제 사용하게 될까?
일반적인 예제 수준의 수량이 작은 data의 경우 안써도 무방합니다. 하지만 데이터 크기가 많은 경우 모두 메모리에 올릴 수 없는 상황이 벌어지게 됩니다.
DataLoader는 훈련에 필요한 데이터가 큰 경우 batch size 만큼 데이터를 가져와서 훈련 시키기 위해 사용합니다.
그리고 DataLoader를 사용하기 위해선 Dataset Class에 대해서 알아야 합니다.
- 검정/검증 : validation , test, val 모두 같은 의미로 사용합니다.
- 훈련 : train
- y : 목표값 label 로 표현하기도 합니다.
dataset에 있어서 epoch, batch_size 의 기본은 아래 그림을 참고 바랍니다.
앞서 DataLoader를 사용하기 위해서는 Dataset에 대해서 알아야 한다고 했었습니다.
Dataset 과 DataLoader class 모두 torch.utils.data 패키지 내에 있습니다.
from torch.utils.data import Dataset from torch.utils.data import DataLoader
Dataset
Dataset을 사용하기 위해서는 해당 class를 상속해서 기본적으로 3가지 정도 함수 작업을 해줍니다.
class CustomDataset(Dataset): def __init__(self, x_tensor, y_tensor): self.x = x_tensor self.y = y_tensor def __getitem__(self, index): """ 주어진 인덱스 index 에 해당하는 샘플을 데이터셋에서 불러오고 반환합니다. """ return (self.x[index], self.y[index]) def __len__(self): """ 데이터셋의 샘플 개수를 반환합니다. """ return len(self.x)
__init__() 는 생성될때 호출되는 함수 입니다. 여기에서는 tensor 데이터를 모두 x, y에 넣는 구조이지만 결국 x,y 모두 메모리에 넣는 상태라 이렇게 해버리면 사실 dataset 을 사용하는 이유가 사라집니다. 여기에서는 예제로서 이렇게 사용한 것입니다.
__get_item__(self, index): 데이터셋을 인덱싱 할 수 있으므로 목록( dataset[i]) 처럼 작동할 수 있습니다 . 요청된 데이터 포인트에 해당 하는 튜플(입력, 레이블)을 리턴 해야 합니다.
__len__(self): 전체 데이터 세트의 크기를 반환합니다.
여기 이미지 데이터의 훌륭한 예제가 있습니다. 그러나 이해하기가 어려울 수 있습니다.
https://pytorch.org/tutorials/beginner/data_loading_tutorial.html#dataset-class
설명에서 y는 label과 같은 의미입니다.
Dataset 분리하기
전체 dataset에 대해서 train용과 valid(검정,검증)용 같은 데이터로 분리하는 경우가 있습니다. 대부분 많이들 분리해서 사용합니다.
이때 random_split를 사용하고 몇개를 train 용으로 사용할지 valid용으로 사용할지 인자로 넘겨줍니다. (아무래도 random이 좋습니다.)
아래와 같은 샘플 코드로 사용이 가능합니다.
from torch.utils.data.dataset import random_split train_dataset, val_dataset = random_split(dataset, [80, 20])
DataLoader
이제 DataLoader를 사용할 차례입니다. DataLoader는 dataset에서 일정 조각(batch)크기 만큼 로딩할 수 있는 기능입니다.
여기에서는 임의로 batch_size = 9로 넣었습니다. 이 정도 하면 모든 준비가 끝났고 훈련할 준비가 완료되었습니다.
train_loader = DataLoader(dataset=train_dataset, batch_size=9) val_loader = DataLoader(dataset=val_dataset, batch_size=9)
훈련단에서는 어떻게 사용해야할까요?
for 문에서 간단하게 이 정도로 사용이 가능합니다.
for epoch in range(n_epochs): for x_batch, y_batch in train_loader: x_batch = x_batch.to(device) y_batch = y_batch.to(device) ## model train
전체 예제
import torch import numpy as np from torch.utils.data import Dataset from torch.utils.data import DataLoader from torch.utils.data.dataset import random_split ####################################### 데이터 준비 np.random.seed(42) # np.random.rand(m,n) n*m matrix 로 0~1 랜덤 생성 x = np.random.rand(100, 3) ''' [[0.37454012 0.95071431 0.73199394] [0.59865848 0.15601864 0.15599452] [0.05808361 0.86617615 0.60111501] ... ''' x_one_d = x[:,0:1] * x[:,1:2] * x[:,2:3] ''' [[2.60648878e-01] # <= [0.37454012 * 0.95071431 * 0.73199394] [1.45701819e-02] [3.02424805e-02] ... ''' # y는 원하는 값 목표값인 label로 표현합니다. y = 1 + 2 * x_one_d + .1 * np.random.randn(100, 1) ''' [[1.52585494] [0.96398033] [1.27487937] ... ''' ################################################ x_tensor = torch.from_numpy(x).float() y_tensor = torch.from_numpy(y).float() ''' x_tensor : tensor([[0.3745, 0.9507, 0.7320], [0.5987, 0.1560, 0.1560], [0.0581, 0.8662, 0.6011], ... y_tensor: tensor([[1.5259], [0.9640], [1.2749], ... ''' class CustomDataset(Dataset): def __init__(self, x_tensor, y_tensor): self.x = x_tensor self.y = y_tensor def __getitem__(self, index): """ 주어진 인덱스 index 에 해당하는 샘플을 데이터셋에서 불러오고 반환합니다. """ return (self.x[index], self.y[index]) def __len__(self): """ 데이터셋의 샘플 개수를 반환합니다. """ return len(self.x) dataset = CustomDataset(x_tensor, y_tensor) train_dataset, val_dataset = random_split(dataset, [80, 20]) train_loader = DataLoader(dataset=train_dataset, batch_size=9) val_loader = DataLoader(dataset=val_dataset, batch_size=9) n_epochs = 10 device = 'cuda' if torch.cuda.is_available() else 'cpu' for epoch in range(n_epochs): print(f"epoch ##{epoch}") batch_no = 0 for x_batch, y_batch in train_loader: print(f"train batch #{batch_no}, epoch #{epoch}") x_batch = x_batch.to(device) y_batch = y_batch.to(device) print(x_batch,"\n",y_batch) batch_no += 1 batch_no = 0 for x_val, y_val in val_loader: print(f"val batch #{batch_no}, epoch #{epoch}") x_val = x_val.to(device) y_val = y_val.to(device) print(x_val,"\n",y_val) batch_no += 1 ''' batch 의 값이 전체 dataset의 배수가 아니며 마지막 batch로 들어오는 크기는 줄어들 수 있음 epoch ##0 train batch #0, epoch #0 tensor([[0.3636, 0.9718, 0.9624], [0.5701, 0.0972, 0.6150], [0.7025, 0.3595, 0.2936], [0.3745, 0.9507, 0.7320], [0.3411, 0.1135, 0.9247], [0.8074, 0.8961, 0.3180], [0.2440, 0.9730, 0.3931], [0.0937, 0.3677, 0.2652], [0.2865, 0.5908, 0.0305]], device='cuda:0') tensor([[1.6872], [1.1006], [1.2078], [1.5259], [1.0126], [1.5765], [1.1275], [1.1460], [1.0727]], device='cuda:0') train batch #1, epoch #0 ...... train batch #8, epoch #0 tensor([[0.5467, 0.1849, 0.9696], [0.5568, 0.9362, 0.6960], [0.7751, 0.9395, 0.8948], [0.8353, 0.3208, 0.1865], [0.1834, 0.3042, 0.5248], [0.3887, 0.2713, 0.8287], [0.9083, 0.2396, 0.1449], [0.6452, 0.1744, 0.6909]], device='cuda:0') tensor([[1.3725], [1.6946], [2.3438], [1.1588], [1.0772], [1.3870], [1.2217], [1.1346]], device='cuda:0') val batch #0, epoch #0 tensor([[0.5487, 0.6919, 0.6520], [0.6335, 0.5358, 0.0903], [0.1866, 0.8926, 0.5393], [0.2419, 0.0931, 0.8972], [0.3867, 0.9367, 0.1375], [0.5107, 0.4174, 0.2221], [0.7958, 0.8900, 0.3380], [0.6376, 0.8872, 0.4722], [0.8180, 0.8607, 0.0070]], device='cuda:0') tensor([[1.5698], [1.0461], [1.0360], [0.9711], [1.0503], [1.1409], [1.3574], [1.5283], [0.9116]], device='cuda:0') ...... val batch #1, epoch #9 tensor([[0.3702, 0.0155, 0.9283], [0.2848, 0.0369, 0.6096], [0.8324, 0.2123, 0.1818], [0.4319, 0.2912, 0.6119], [0.5026, 0.5769, 0.4925], [0.0243, 0.6455, 0.1771], [0.8774, 0.7408, 0.6970], [0.6233, 0.3309, 0.0636], [0.7081, 0.0206, 0.9699]], device='cuda:0') tensor([[1.0920], [1.0242], [0.8618], [1.0878], [1.2654], [1.1154], [1.9157], [1.1037], [1.0917]], device='cuda:0') val batch #2, epoch #9 tensor([[0.5613, 0.7710, 0.4938], [0.8172, 0.5552, 0.5297]], device='cuda:0') tensor([[1.3249], [1.5163]], device='cuda:0') '''
위 예제에서 model train 관련 코드는 빠져있습니다. 훈련시 데이터가 몇개나 어떤 형태로 올라오는지에 대한 예제입니다. batch, epoch 관계를 보다 이해하기 쉬울것이라 생각됩니다.
Pytorch 링크
pytorch 파일 기반(file based) DataLoader
Machine Learning(머신러닝) 기초, Pytorch train 기본
Machine Learning(머신러닝) 기초, Pytorch 영상 분류, 영상 불량 검출, 개 고양이 분류 (image classification)
댓글 없음:
댓글 쓰기