2 minute read

딥러닝 공부 5일차

Mini Batch and Data Load



복습하고오세요~! 클릭!

이전 글에서 배치 애기를 하면서 미니배치의 필요성에 대해서 이야기한 바가 있습니다. 링크를 걸어두었으니 잠깐 보고 오면 좋을 것 같습니다.

x_train = torch.FloatTensor([[x1, ~, ~],
                             [x2, ~, ~],
                             [x3, ~, ~],
                             [x4, ~, ~],
                             [x5, ~, ~]])
y_train = torch.FloatTensor([[~], [~], [~], [~], [~]])

앞서 배웠던 다중 선형회귀의 예에서 숫자들을 지웠습니다. 위 데이터에서 샘플의 개수는 5개입니다.

하지만 현업에서는 수십만개 이상의 데이터를 다루는 경우가 많습니다. 데이터가 수십만개 정도의 사이즈가 된다면 일일히 경사하강법을 실행하는 경우에는 시간이 너무 많이 소요될 수 있습니다.

그렇기 때문에 전체 데이터를 나눠서 학습시키는 Mini Batch(미니배치)라는 개념이 나오게 된 것입니다.

미니배치 경사하강법은 전체 데이터를 그림과 같이 여러개의 미니배치로 나누어서 각 미니배치당 손실함수를 계산하고 경사 하강법을 실행하고 그 다음 미니배치로 들어가서 같은 연산을 반복합니다.

그렇게 모든 미니배치의 연산이 끝나고나면 1 Epoch 가 끝나게 됩니다.

  • 전체 데이터에 대해서 한 번에 연산하는 것 👉 ‘배치 경사 하강법’
  • 미니 배치단위로 연산하는 것 👉 ‘미니 배치 경사 하강법’
  • 배치크기는 보통 2의 제곱수를 사용합니다, 왜냐하면 cpu와 gpu의 메모리가 2의 배수이므로 연산 속도를 높이기 위함입니다.

Iteration(이터레이션)

이터레이션은 그림을 보면 빠르게 이해가 가능합니다.

전체 데이터량이 2000이라 할 때, 배치 사이즈를 200이라 한다면 총 10개의 이터레이션이 나오게 됩니다.

데이터 로드하기

파이토치에서는 데이터를 좀 더 쉽게 다룰 수 있도록 유용한 도구로서 데이터셋(Dataset)과 데이터로더(DataLoader)를 제공합니다.

이를 사용하면 미니 배치 학습, 데이터 셔플(shuffle), 병렬 처리까지 간단히 수행할 수 있습니다.

기본적인 사용 방법은 Dataset을 정의하고, 이를 DataLoader에 전달하는 것입니다.

Dataset을 커스텀하여 만들 수도 있지만 여기서는 텐서를 입력받아 Dataset의 형태로 변환해주는 TensorDataset을 사용해보겠습니다.

실습을 위해 기본적으로 필요한 파이토치의 도구들을 임포트합니다. (wikidocs)

import torch
import torch.nn as nn
import torch.nn.functional as F

텐서데이터셋과 데이터로더를 임포트합니다.

from torch.utils.data import TensorDataset # 텐서데이터셋
from torch.utils.data import DataLoader # 데이터로더

TensorDataset은 기본적으로 텐서를 입력으로 받습니다. 텐서 형태로 데이터를 정의합니다.

x_train  =  torch.FloatTensor([[73,  80,  75], 
                               [93,  88,  93], 
                               [89,  91,  90], 
                               [96,  98,  100],   
                               [73,  66,  70]])  
y_train  =  torch.FloatTensor([[152],  [185],  [180],  [196],  [142]])

이제 이를 TensorDataset의 입력으로 사용하고 dataset으로 저장합니다.

dataset = TensorDataset(x_train, y_train)

파이토치의 데이터셋을 만들었다면 데이터로더를 사용 가능합니다. 데이터로더는 기본적으로 2개의 인자를 입력받습니다. 하나는 데이터셋, 미니 배치의 크기입니다.

shuffle=True를 선택하면 Epoch마다 데이터셋을 섞어서 데이터가 학습되는 순서를 바꿉니다.

사람도 같은 문제집을 여러번 풀면 익숙하듯이 모델도 마찬가지입니다. 데이터셋을 학습해야하는데 데이터셋의 순서를 학습하는 경우를 방지하기 위해서 shuffle 은 거의 true로 사용합니다.

dataloader = DataLoader(dataset, batch_size=2, shuffle=True)

이제 모델과 옵티마이저를 설계합니다.

model = nn.Linear(3,1)
optimizer = torch.optim.SGD(model.parameters(), lr=1e-5) 

이제 훈련을 진행해보겠습니다.

nb_epochs = 20
for epoch in range(nb_epochs + 1):
  for batch_idx, samples in enumerate(dataloader):
    print(batch_idx)
    print(samples)
    x_train, y_train = samples

    # H(x) 계산
    prediction = model(x_train)

    # cost 계산
    cost = F.mse_loss(prediction, y_train)

    # cost로 H(x) 계산
    optimizer.zero_grad()
    cost.backward()
    optimizer.step()

    print('Epoch {:4d}/{} Batch {}/{} Cost: {:.6f}'.format(
        epoch, nb_epochs, batch_idx+1, len(dataloader),
        cost.item()
        ))

결과 값은 아래와 같습니다. 미니배치당 연산이 되어서 나오는 것을 확인하실 수 있습니다.

0
[tensor([[73., 66., 70.],
        [73., 80., 75.]]), tensor([[142.],
        [152.]])]
Epoch    0/20 Batch 1/3 Cost: 23071.781250
1
[tensor([[ 89.,  91.,  90.],
        [ 96.,  98., 100.]]), tensor([[180.],
        [196.]])]
Epoch    0/20 Batch 2/3 Cost: 17581.359375
2

...중략...

0
[tensor([[ 73.,  80.,  75.],
        [ 96.,  98., 100.]]), tensor([[152.],
        [196.]])]
Epoch   20/20 Batch 1/3 Cost: 0.408727
1
[tensor([[93., 88., 93.],
        [89., 91., 90.]]), tensor([[185.],
        [180.]])]
Epoch   20/20 Batch 2/3 Cost: 0.194451
2
[tensor([[73., 66., 70.]]), tensor([[142.]])]
Epoch   20/20 Batch 3/3 Cost: 0.004536

Cost 값이 점점 작아지네요~ 성공입니다!

참고문헌 : wikidocs


끝!

Leave a comment