투명한 기부를 하고싶다면 이 링크로 와보세요! 🥰 (클릭!)
바이낸스(₿) 수수료 평생 20% 할인받는 링크로 가입하기! 🔥 (클릭!)
2018/07/02 - [Programming Project/Pytorch Tutorials] - Pytorch 머신러닝 튜토리얼 강의 1 (Overview)
2018/07/02 - [Programming Project/Pytorch Tutorials] - Pytorch 머신러닝 튜토리얼 강의 2 (Linear Model)
2018/07/03 - [Programming Project/Pytorch Tutorials] - Pytorch 머신러닝 튜토리얼 강의 3 (Gradient Descent)
2018/07/09 - [Programming Project/Pytorch Tutorials] - Pytorch 머신러닝 튜토리얼 강의 6 (Logistic Regression)
2018/07/10 - [Programming Project/Pytorch Tutorials] - Pytorch 머신러닝 튜토리얼 강의 7 (Wide and Deep)
이번 글에서는 data loader에 대해서 다뤄보겠습니다.
우리가 데이터를 읽어들일때 어떻게 읽어들이냐에 관련이 있습니다.
(sung kim님의 강의 ppt에서 가져와서 코드는 조금 다를 수 있습니다만)
이전에 우리는 data 를 load할 때 그냥 바로 통째로 numpy로 csv파일에서 데이터를 불러 온 후에, 그 데이터를 집어넣었습니다.
그리고 우리의 모델에 그 데이터를 몽땅 우리 모델에 넣고, 모든 데이터에 대한 결과값을 한번에 받아서 한번에 모두 다 비교했습니다.
이전 case 에서는 사실 데이터 size가 작기 때문에 별 문제가 되지 않았습니다.
하지만 수백만개 이상의 데이터가 쌓인 상태에서는 저렇게 모든 데이터를 한번에 넣어서 처리할 수 없습니다.
모든 데이터에 대한 결과를 한번에 구하는것도 무리일 뿐더러 모든 데이터에 대해 gradient를 구하는 것 역시 무리이기 때문입니다.
Batch
그래서 우리는 우리의 전체 데이터를 나눠 일부를 묶은 batch 라는 단위를 만들어서 데이터를 나눠서 처리 할 것입니다.
(batch는 직역하면 집단, 혹은 1회분 이라는 뜻이며, 우리는 여기서 한번에 처리할 데이터 묶음이라는 뜻으로 씁니다)
이렇게 이용할 때, 우리는 3가지 용어를 씁니다.
1. epoch : 한번 '모든' 트레이닝 데이터에 대해서 forward와 backward pass를 진행 한 상태를 의미함
2. batch_size : forward 와 backward를 한번에 얼만큼의 데이터씩 진행할 것인지 그 사이즈를 의미함.
3. iterations : batch_size단위로 몇번 forward, backward를 진행했는지 그 수를 의미한다.
정리하자면 data size = batch_size * iterations 이다.
이것을 구현하기 위해서는 모든 데이터를 나누고, 일일히 그 데이터를 나눠서 forward와 backward를 돌리는 식으로 진행해야 하는데, 만약 파이토치에서 제공해주는 DataLoader을 쓴다면 그럴 필요가 없습니다.
우리는 그냥 DataLoader로 부터 batch_size만큼의 데이터를 받아오면 됩니다.
그렇다면 어떻게 코드로 구현할 수 있을까요?
Custom DataLoader
우리가 직접 만드는 custom dataloader은 다음과 같은 세 파트로 이루어져 있습니다.
1. __init__(self)
download, read data 등등을 하는 파트.
2. __getitem__(self,index)
인덱스에 해당하는 아이템을 넘겨주는 파트.
3. __len__(self)
data size를 넘겨주는 파트
한번 코드로 구현 해 봅시다.
import torch import numpy as np from torch.autograd import Variable from torch.utils.data import Dataset, DataLoader class DiabetesDataset(Dataset): """ Diabetes dataset.""" # Initialize your data, download, etc. def __init__(self): xy = np.loadtxt('./data/diabetes.csv.gz', delimiter=',', dtype=np.float32) self.len = xy.shape[0] self.x_data = torch.from_numpy(xy[:, 0:-1]) self.y_data = torch.from_numpy(xy[:, [-1]]) def __getitem__(self, index): return self.x_data[index], self.y_data[index] def __len__(self): return self.len dataset = DiabetesDataset() train_loader = DataLoader(dataset=dataset, batch_size=32, shuffle=True, num_workers=2)
우리가 이전에 받아왔던 데이터를 DiabetesDataset 이라는 class를 이용해서 받아오고 있습니다.
DiabetsDataset은 torch.utils.data에서 받아온 Dataset class를 상속받고 있습니다.
우리가 class 생성시에 해줄것은
self.len 에 길이를 넣어주고
self.x_data에 x 데이터를
self.y_data에 y 데이터를 넣어주고
인덱스에 따라 i 번째 데이터를 잘 리턴해주면 됩니다.
그리고 training을 하기 위해서 loader를 생성할 때는 그 아리에 train_loader을 선언할 때 처럼 dataset에 우리가 만든 class를 넣어주고, batch_size 에는 데이터 사이즈 개수를, 그리고 shuffle은 True로 해주시는게 좋은데, 그냥 데이터를 묶어서 넘겨줄시에 기존 데이터 말고 셔플해서 넘겨준다는 뜻입니다. 그리고 num_workers는 멀티쓰레딩을 지원하기 때문에 빠르게 데이터를 가져오고 싶다면 늘립시다.
* windows 기준으로 num_workers=2 때문에 에러가 날 수도 있습니다. 만약 그렇다면 num_workers=0으로 세팅하시고 그냥 멀티쓰레딩 없이 돌립시다 ㅠㅠ..
그리고 이제 모델은 epoch만 정하면
다음 코드와 같이 한번에 돌릴 수 있습니다.
# Training loop for epoch in range(2): for i, data in enumerate(train_loader): # get the inputs inputs, labels = data # wrap them in Variable inputs, labels = Variable(inputs), Variable(labels) # Forward pass: Compute predicted y by passing x to the model y_pred = model(inputs) # Compute and print loss loss = criterion(y_pred, labels) print(epoch, i, loss.data[0]) # Zero gradients, perform a backward pass, and update the weights. optimizer.zero_grad() loss.backward() optimizer.step()
제 결과는 이렇게 나오네요
0 0 tensor(0.7405) 0 1 tensor(0.7103) 0 2 tensor(0.7059) 0 3 tensor(0.7127) 0 4 tensor(0.6936) 0 5 tensor(0.6949) 0 6 tensor(0.6836) 0 7 tensor(0.6713) 0 8 tensor(0.6715) 0 9 tensor(0.6440) 0 10 tensor(0.6379) 0 11 tensor(0.6759) 0 12 tensor(0.7042) 0 13 tensor(0.6672) 0 14 tensor(0.6665) 0 15 tensor(0.6754) 0 16 tensor(0.6655) 0 17 tensor(0.6236) 0 18 tensor(0.6868) 0 19 tensor(0.6518) 0 20 tensor(0.6146) 0 21 tensor(0.6224) 0 22 tensor(0.6758) 0 23 tensor(0.6687) 1 0 tensor(0.6332) 1 1 tensor(0.6907) 1 2 tensor(0.6760) 1 3 tensor(0.6191) 1 4 tensor(0.6456) 1 5 tensor(0.6455) 1 6 tensor(0.6613) 1 7 tensor(0.6767) 1 8 tensor(0.6611) 1 9 tensor(0.5993) 1 10 tensor(0.6773) 1 11 tensor(0.5963) 1 12 tensor(0.6441) 1 13 tensor(0.5918) 1 14 tensor(0.5882) 1 15 tensor(0.6813) 1 16 tensor(0.6434) 1 17 tensor(0.6808) 1 18 tensor(0.6617) 1 19 tensor(0.6438) 1 20 tensor(0.6063) 1 21 tensor(0.6434) 1 22 tensor(0.7195) 1 23 tensor(0.6210)
전체 소스 공유합니다.
import torch import numpy as np from torch.autograd import Variable from torch.utils.data import Dataset,DataLoader class DiabetesDataset(Dataset): def __init__(self): xy=np.loadtxt('./data/diabetes.csv.gz',delimiter=',',dtype=np.float32) self.len=xy.shape[0] self.x_data=torch.from_numpy(xy[:,0:-1]) self.y_data=torch.from_numpy(xy[:,[-1]]) def __getitem__(self,index): return self.x_data[index], self.y_data[index] def __len__(self): return self.len dataset = DiabetesDataset() train_loader = DataLoader(dataset = dataset, batch_size=32, shuffle=True, num_workers=0) class MyModel(torch.nn.Module): def __init__(self): super(MyModel,self).__init__() self.l1=torch.nn.Linear(8,4) self.l2=torch.nn.Linear(4,6) self.l3=torch.nn.Linear(6,1) self.sigmoid=torch.nn.Sigmoid() def forward(self,x): out1 = self.sigmoid(self.l1(x)) out2 = self.sigmoid(self.l2(out1)) y_pred = self.sigmoid(self.l3(out2)) return y_pred model = MyModel() criterion = torch.nn.BCELoss(size_average = True) optimizer = torch.optim.SGD(model.parameters(),lr=0.1) # Training loop for epoch in range(2): for i, data in enumerate(train_loader): # get the inputs inputs, labels = data # wrap them in Variable inputs, labels = Variable(inputs), Variable(labels) # Forward pass: Compute predicted y by passing x to the model y_pred = model(inputs) # Compute and print loss loss = criterion(y_pred, labels) print(epoch, i, loss.data[0]) # Zero gradients, perform a backward pass, and update the weights. optimizer.zero_grad() loss.backward() optimizer.step()
파이토치는 이미 여러 데이터set을 파이토치에 구비해 놓았습니다.
요로코롬 구현하시면 됩니다.
숙제
이미 있는 데이터set을 한번 찾아보시구요.
케글에 있는 데이터셋을 가져와서 데이터로더로 불러와보세요!