Notice
Recent Posts
Recent Comments
Link
250x250
| 일 | 월 | 화 | 수 | 목 | 금 | 토 |
|---|---|---|---|---|---|---|
| 1 | 2 | 3 | 4 | 5 | 6 | 7 |
| 8 | 9 | 10 | 11 | 12 | 13 | 14 |
| 15 | 16 | 17 | 18 | 19 | 20 | 21 |
| 22 | 23 | 24 | 25 | 26 | 27 | 28 |
Tags
- ODQA
- dataset
- seaborn
- 기아
- AI Math
- Ai
- Self-attention
- RNN
- Bert
- GPT
- matplotlib
- N21
- 현대자동차
- Optimization
- word2vec
- pyTorch
- 딥러닝
- 데이터 시각화
- passage retrieval
- nlp
- KLUE
- AI 경진대회
- Data Viz
- Bart
- 데이터 구축
- mrc
- Transformer
- 2023 현대차·기아 CTO AI 경진대회
- N2N
- Attention
Archives
- Today
- Total
쉬엄쉬엄블로그
Custom Dataset 및 Custom DataLoader 생성 본문
728x90
이 색깔은 주석이라 무시하셔도 됩니다.
PyToch의 DataLoader
DataLoader의 기본 구성 요소
dataset (★★★)
- DataLoader에는 앞서 생성한 dataset 인스턴스가 들어감
batch_size (★★★)
- 인자가 나타내고 있는 뜻 그대로 배치 사이즈를 의미
shuffle (★★★)
- 데이터를 DataLoader에서 섞어서 사용하겠는지를 설정할 수 있음
sample / batch_sample (★)
- sampler는 index를 컨트롤하는 방법
- 데이터의 index를 원하는 방식대로 조정
- index를 컨트롤하기 때문에 설정하고 싶다면 shuffle 파라미터는 False(기본값)이어야 함
- 불균형 데이터셋의 경우, 클래스의 비율에 맞게끔 데이터를 제공해야할 필요가 있음
- 이 때 사용하는 옵션이 sampler
num_workers (★★)
- 데이터를 불러올 때 사용하는 서브 프로세스(subprocess) 개수
- 무작정 num_workers를 높인다고 좋진 않음
- 데이터를 불러올 때 CPU와 GPU 사이에서 많은 교류가 일어나면 오히려 병목이 생길 수 있음

collate_fn (★★)

- collate : 함께 합치다
- map-style 데이터셋에서 sample list를 batch 단위로 바꾸기 위해 필요한 기능
- zero-padding이나 Variable Size 데이터 등 데이터 사이즈를 맞추기 위해 사용
collate_fn을 활용하여 하나의 batch에 동일한 길이를 반환할 수 있도록 만들기
완성 예시
tensor([[0., 0.], [1., 1.]]) tensor([0., 1.]) tensor([[2., 2., 2., 0.], [3., 3., 3., 3.]]) tensor([2., 3.]) tensor([[4., 4., 4., 4., 4., 0.], [5., 5., 5., 5., 5., 5.]]) tensor([4., 5.]) tensor([[6., 6., 6., 6., 6., 6., 6., 0.], [7., 7., 7., 7., 7., 7., 7., 7.]]) tensor([6., 7.]) tensor([[8., 8., 8., 8., 8., 8., 8., 8., 8., 0.], [9., 9., 9., 9., 9., 9., 9., 9., 9., 9.]]) tensor([8., 9.])
dataloader_example = torch.utils.data.DataLoader(dataset_example, batch_size=1)
for d in dataloader_example:
print(d['X'])
# batch_size가 1일 때는 문제가 없어보임
tensor([[0.]])
tensor([[1., 1.]])
tensor([[2., 2., 2.]])
tensor([[3., 3., 3., 3.]])
tensor([[4., 4., 4., 4., 4.]])
tensor([[5., 5., 5., 5., 5., 5.]])
tensor([[6., 6., 6., 6., 6., 6., 6.]])
tensor([[7., 7., 7., 7., 7., 7., 7., 7.]])
tensor([[8., 8., 8., 8., 8., 8., 8., 8., 8.]])
tensor([[9., 9., 9., 9., 9., 9., 9., 9., 9., 9.]])
dataloader_example = torch.utils.data.DataLoader(dataset_example, batch_size=2)
for d in dataloader_example:
print(d['X'])
# batch_size가 2가 되면 에러 발생
---------------------------------------------------------------------------
RuntimeError Traceback (most recent call last)
<ipython-input-30-dcb26b561383> in <module>
1 dataloader_example = torch.utils.data.DataLoader(dataset_example, batch_size=2)
----> 2 for d in dataloader_example:
3 print(d['X'])
... 중략 ...
~/anaconda3/envs/pytorch/lib/python3.7/site-packages/torch/utils/data/_utils/collate.py in default_collate(batch)
54 storage = elem.storage()._new_shared(numel)
55 out = elem.new(storage)
---> 56 return torch.stack(batch, 0, out=out)
57 elif elem_type.__module__ == 'numpy' and elem_type.__name__ != 'str_' \
58 and elem_type.__name__ != 'string_':
RuntimeError: stack expects each tensor to be equal size, but got [1] at entry 0 and [2] at entry 1
collate_fn 적용하기
# 적절한 collate_fn을 만듬 def my_collate_fn(samples): collate_X = [] collate_y = [] # print('Original:\n', samples) # print('-'*100) max_len = 0 for sample in samples: max_len = max(max_len, len(sample['X'])) # print(max_len) for sample in samples: m = torch.nn.ConstantPad1d((0, max_len - len(sample['X'])), 0) collate_X.append(m(sample['X'])) collate_y.append(sample['y']) # print('Collated:\n', [collate_X, collate_y]) # print('-'*100) return {'X': torch.stack(collate_X), 'y': torch.stack(collate_y)} # collate_fn을 적용하여 다시 데이터를 불러옴 dataloader_example = torch.utils.data.DataLoader(dataset_example, batch_size=2, collate_fn=my_collate_fn) for d in dataloader_example: print(d['X'], d['y']) # 정상적으로 출력 tensor([[0., 0.], [1., 1.]]) tensor([0., 1.]) tensor([[2., 2., 2., 0.], [3., 3., 3., 3.]]) tensor([2., 3.]) tensor([[4., 4., 4., 4., 4., 0.], [5., 5., 5., 5., 5., 5.]]) tensor([4., 5.]) tensor([[6., 6., 6., 6., 6., 6., 6., 0.], [7., 7., 7., 7., 7., 7., 7., 7.]]) tensor([6., 7.]) tensor([[8., 8., 8., 8., 8., 8., 8., 8., 8., 0.], [9., 9., 9., 9., 9., 9., 9., 9., 9., 9.]]) tensor([8., 9.])
pin_memory
- DataLoader에서 이걸 True로 바꾸면 Tensor를 CUDA 고정 메모리에 할당시킴
- 고정된 메모리에서 데이터를 가져오기 때문에 데이터 전송이 훨씬 빠름
- 일반적인 경우에는 많이 사용하지 않음
drop_last (★)
- batch 단위로 데이터를 불러올 때 batch_size에 따라 마지막 batch의 길이가 달라질 수 있음.
- batch의 길이가 다르면 loss를 구하기 까다로워지는 경우가 생기고, batch의 크기에 따른 의존도 높은 함수를 사용할 때 걱정이 되는 경우 drop_last를 통해 마지막 batch를 사용하지 않도록(생략하도록) 설정할 수 있음
time_out
- 양수로 주어지는 경우, DataLoader가 data를 불러오는데 제한시간을 설정
worker_init_fn
- num_worker가 개수라면, 이 파라미터는 어떤 worker를 불러올 것인가를 리스트로 전달
torchvision에서 제공하는 몇가지 transform 함수
- transform을 하는 이유?
- 딥러닝 학습을 위해선 고정된 입력값이 보장되어야 함
- 하지만 수집한 모든 데이터의 크기가 동일하지 않을 수도 있음
- 이미지의 경우, 정사각형 형태의 이미지가 있는 반면 직사각형 형태의 이미지가 있을 수 있음
- PyTorch에서는 이를 위해 이미지를 Resize하는 함수 등을 제공
transforms.Resize (torchvision.transforms.Resize)
- 이미지 사이즈 변환
transforms.Resize((200,200))(im)
transforms.RandomCrop (torchvision.transforms.RandomCrop)
- 지정된 이미지를 임의의 위치에서 자름
transforms.RandomCrop((100,100))(im)
transforms.RandomRotation (torchvision.transforms.RandomRotation)
- 지정된 이미지를 임의의 각도만큼 회전시킴
transforms.RandomRotation(30)(im)
transforms.ToTensor (torchvision.transforms.ToTensor)
- 지정된 이미지를 tensor로 변환
- 이미지를 하나씩 지정해줘야 함 (2-D array)
transforms.ToTensor()(im)
transforms.Compose (torchvision.transforms.Compose)
- 여러 transforms들을 하나로 묶어서 처리
transforms.Compose([transforms.Resize((224,224)), transforms.RandomVerticalFlip(0.5), transforms.CenterCrop(150)])(im)
그 외 transforms
dir(transforms)
# ['AutoAugment',
# 'AutoAugmentPolicy',
# 'CenterCrop',
# 'ColorJitter',
# 'Compose',
# 'ConvertImageDtype',
# 'FiveCrop',
# 'GaussianBlur',
# 'Grayscale',
# 'InterpolationMode',
# 'Lambda',
# 'LinearTransformation',
# 'Normalize',
# 'PILToTensor',
# 'Pad',
# 'RandAugment',
# 'RandomAdjustSharpness',
# 'RandomAffine',
# 'RandomApply',
# 'RandomAutocontrast',
# 'RandomChoice',
# 'RandomCrop',
# 'RandomEqualize',
# 'RandomErasing',
# 'RandomGrayscale',
# 'RandomHorizontalFlip',
# 'RandomInvert',
# 'RandomOrder',
# 'RandomPerspective',
# 'RandomPosterize',
# 'RandomResizedCrop',
# 'RandomRotation',
# 'RandomSizedCrop',
# 'RandomSolarize',
# 'RandomVerticalFlip',
# 'Resize',
# 'Scale',
# 'TenCrop',
# 'ToPILImage',
# 'ToTensor',
# 'TrivialAugmentWide',
# '__builtins__',
# '__cached__',
# '__doc__',
# '__file__',
# '__loader__',
# '__name__',
# '__package__',
# '__path__',
# '__spec__',
# 'autoaugment',
# 'functional',
# 'functional_pil',
# 'functional_tensor',
# 'transforms']PyTorch의 여러가지 Dataset
torchvision에서의 Dataset
MNIST
- MNIST Dataset
dataset_train_MNIST = torchvision.datasets.MNIST('data/MNIST/', # 다운로드 경로 지정 train=True, # True를 지정하면 훈련 데이터로 다운로드 transform=transforms.ToTensor(), # 텐서로 변환 download=True, ) - MNIST DataLoader
dataloader_train_MNIST = DataLoader(dataset=dataset_train_MNIST, batch_size=16, shuffle=True, num_workers=4, )
torchtext에서의 Dataset
AG_NEWS
AG_NEWS Dataset
# !pip install torchdata dataset_train_AG_NEWS, dataset_test_AG_NEWS = torchtext.datasets.AG_NEWS(root='./data') classes = ['World', 'Sports', 'Business', 'Sci/Tech'] dataset_train_AG_NEWS = list(dataset_train_AG_NEWS) dataset_test_AG_NEWS = list(dataset_test_AG_NEWS)AG_NEWS DataLoader
# this collate function gets list of batch_size tuples, and needs to # return a pair of label-feature tensors for the whole minibatch def bowify(b): return ( torch.stack([to_bow(t[1]) for t in b]), torch.LongTensor([t[0]-1 for t in b]), ) dataset_train_AG_NEWS = list(dataset_train_AG_NEWS) dataset_test_AG_NEWS = list(dataset_test_AG_NEWS)
PyTorch의 Custom Dataset 과 DataLoader
(정형 데이터) Titanic 데이터로 Dataset과 DataLoader 만들어보기
Titanic 데이터 다운로드
dataset_train_titanic = TitanicDataset('./data/titanic/train.csv',
drop_features=['PassengerId', 'Name', 'Ticket', 'Cabin'],
train=True)(이미지 데이터) MNIST 데이터로 Dataset과 DataLoader 만들어보기
MNIST 데이터 다운로드
BASE_MNIST_PATH = '/data/MNIST/MNIST/raw'
TRAIN_MNIST_IMAGE_PATH = os.path.join(BASE_MNIST_PATH, 'train-images-idx3-ubyte.gz')
TRAIN_MNIST_LABEL_PATH = os.path.join(BASE_MNIST_PATH, 'train-labels-idx1-ubyte.gz')
TEST_MNIST_IMAGE_PATH = os.path.join(BASE_MNIST_PATH, 't10k-images-idx3-ubyte.gz')
TEST_MNIST_LABEL_PATH = os.path.join(BASE_MNIST_PATH, 't10k-labels-idx1-ubyte.gz')
TRAIN_MNIST_PATH = {
'image': TRAIN_MNIST_IMAGE_PATH,
'label': TRAIN_MNIST_LABEL_PATH
}
dataset_train_MNIST = torchvision.datasets.MNIST('/data', # 다운로드 경로 지정
train=True, # True를 지정하면 훈련 데이터로 다운로드
transform=transforms.ToTensor(), # 텐서로 변환
download=True,
)
# MNIST RAW 데이터를 가져오는 함수
# https://stackoverflow.com/questions/40427435/extract-images-from-idx3-ubyte-file-or-gzip-via-python
def read_MNIST_images(path):
with gzip.open(path, 'r') as f:
# first 4 bytes is a magic number
magic_number = int.from_bytes(f.read(4), 'big')
# second 4 bytes is the number of images
image_count = int.from_bytes(f.read(4), 'big')
# third 4 bytes is the row count
row_count = int.from_bytes(f.read(4), 'big')
# fourth 4 bytes is the column count
column_count = int.from_bytes(f.read(4), 'big')
# rest is the image pixel data, each pixel is stored as an unsigned byte
# pixel values are 0 to 255
image_data = f.read()
images = np.frombuffer(image_data, dtype=np.uint8)\
.reshape((image_count, row_count, column_count))
return images
def read_MNIST_labels(path):
with gzip.open(path, 'r') as f:
# first 4 bytes is a magic number
magic_number = int.from_bytes(f.read(4), 'big')
# second 4 bytes is the number of labels
label_count = int.from_bytes(f.read(4), 'big')
# rest is the label data, each label is stored as unsigned byte
# label values are 0 to 9
label_data = f.read()
labels = np.frombuffer(label_data, dtype=np.uint8)
return labels
class MyMNISTDataset(Dataset):
def __init__(self, path, transform, train=True):
######################################TODO######################################
self.train = train
self.path = path
self.X = read_MNIST_images(self.path['image'])
self.y = pd.Series(read_MNIST_labels(self.path['label']))
self.classes = self.y.unique()
self._repr_indent = 4
pass
################################################################################
def __len__(self):
len_dataset = None
######################################TODO######################################
len_dataset = len(self.X)
pass
################################################################################
return len_dataset
def __getitem__(self, idx):
X,y = None, None
######################################TODO######################################
X = self.X[idx]
if self.transform:
X = self.transform(X)
y = self.y[idx]
if not self.train:
return torch.tensor(X, dtype=torch.double)
pass
################################################################################
return torch.tensor(X, dtype=torch.double), torch.tensor(y, dtype=torch.long)
def __repr__(self):
'''
https://github.com/pytorch/vision/blob/master/torchvision/datasets/vision.py
'''
head = "(PyTorch HomeWork) My Custom Dataset : MNIST"
data_path = self._repr_indent*" " + "Data path: {}".format(self.path['image'])
label_path = self._repr_indent*" " + "Label path: {}".format(self.path['label'])
num_data = self._repr_indent*" " + "Number of datapoints: {}".format(self.__len__())
num_classes = self._repr_indent*" " + "Number of classes: {}".format(len(self.classes))
return '\n'.join([head,
data_path, label_path,
num_data, num_classes])
dataset_train_MyMNIST = MyMNISTDataset(path=TRAIN_MNIST_PATH,
transform=transforms.Compose([transforms.ToTensor()]),
train=True,
)(텍스트 데이터) AG_NEWS 데이터를 이용하여 Dataset과 DataLoader 만들어보기
AG_NEWS 데이터 다운로드
dataset_train_AG_NEWS, dataset_test_AG_NEWS = torchtext.datasets.AG_NEWS(root='./data')
dataset_train_AG_NEWS = list(dataset_train_AG_NEWS)
dataset_test_AG_NEWS = list(dataset_test_AG_NEWS)
os.listdir('data/datasets/AG_NEWS')
BASE_AG_NEWS_PATH = 'data/datasets/AG_NEWS'
TRAIN_AG_NEWS_PATH = os.path.join(BASE_AG_NEWS_PATH, 'train.csv')
TEST_AG_NEWS_PATH = os.path.join(BASE_AG_NEWS_PATH, 'test.csv')
dataset_train_MyAG_NEWS = MyAG_NEWSDataset(TRAIN_AG_NEWS_PATH, train=True)요약 및 정리
Dataset
from torch.utils.data import Dataset
class CustomDataset(Dataset):
def __init__(self,):
'''
데이터의 위치나 파일명과 같은 초기화 작업을 위해 동작
'''
pass
def __len__(self):
'''
Dataset의 최대 요소 수를 반환하는데 사용
'''
pass
def __getitem__(self, idx):
'''
데이터셋의 idx번째 데이터를 반환하는데 사용
'''
pass
dataset_custom = CustomDataset()DataLoader
DataLoader(dataset, # Dataset 인스턴스가 들어감
batch_size=1, # 배치 사이즈를 설정
shuffle=False, # 데이터를 섞어서 사용하겠는지를 설정
sampler=None, # sampler는 index를 컨트롤
batch_sampler=None, # 위와 비슷하므로 생략
num_workers=0, # 데이터를 불러올때 사용하는 서브 프로세스 개수
collate_fn=None, # map-style 데이터셋에서 sample list를 batch 단위로 바꾸기 위해 필요한 기능
pin_memory=False, # Tensor를 CUDA 고정 메모리에 할당
drop_last=False, # 마지막 batch를 사용 여부
timeout=0, # data를 불러오는데 제한시간
worker_init_fn=None # 어떤 worker를 불러올 것인가를 리스트로 전달
)
dataloader_custom = DataLoader(dataset_custom)일반적인 학습 과정
import torch
import torch.nn as nn
import torch.optim as optim
import torch.nn.functional as F
from torch.utils.data import Dataset, DataLoader
from network import CustomNet
from dataset import ExampleDataset
from loss import ExampleLoss
###############################
# Custom modeling #
###############################
# 모델 생성
model = CustomNet()
model.train()
# 옵티마이저 정의
params = [param for param in model.parameters() if param.requires_grad]
optimizer = optim.Example(params, lr=lr)
# 손실함수 정의
loss_fn = ExampleLoss()
###########################################
# Custom Dataset & DataLoader #
###########################################
# 학습을 위한 데이터셋 생성
dataset_example = ExampleDataset()
# 학습을 위한 데이터로더 생성
dataloader_example = DataLoader(dataset_example)출처: 부스트캠프 AI Tech 4기(NAVER Connect Foundation)
'부스트캠프 AI Tech 4기' 카테고리의 다른 글
| (딥러닝) Historical Review (0) | 2023.05.27 |
|---|---|
| Transfer Learning + Hyper Parameter Tuning (0) | 2023.05.26 |
| PyTorch Troubleshooting (0) | 2023.05.24 |
| Hyperparameter Tuning (0) | 2023.05.23 |
| Multi-GPU - PyTorch (0) | 2023.05.22 |
Comments