📢본 게시물은 바닥에서 시작하는 딥러닝 3에 따라 만들었습니다.
배운 내용을 기록하고 개인적인 공부를 위해 작성하는 게시물입니다.
자세한 내용은 교재 구입을 적극 권장합니다.
이 단계에서는 이전 단계에서 사용한 Dataset 클래스에 대해 자세히 설명합니다.
사용자가 실제로 사용하는 데이터 세트는, 베이스 클래스를 상속해 구현합니다.
먼저 기본 클래스 코드를 살펴보겠습니다.
Dataset 클래스에서는 __getitem__ 및 __len__ 메소드가 중요합니다.
__len__ 메서드는 len 함수를 사용하면 호출되며 __getitem__ 메서드는 지정된 인덱스에 있는 데이터를 검색하는 데 사용됩니다.
기본적으로 딥 러닝 학습에는 데이터와 레이블이 필요하므로 생성자에 지정하십시오. 별도로 transform은 데이터세트의 전처리 시에 활용합니다.
학습하기 전에 데이터에서 특정 값을 삭제하거나 좌우 반전과 같은 데이터 수를 인위적으로 늘리는 경우가 많습니다.
이러한 전처리 기술을 수용하기 위해 변환 기능을 추가합니다.
변환이 인수에 들어가지 않으면 lambda x:x를 통해 원래 데이터를 그대로 반환합니다.
class Dataset:
def __init__(self, train=True, transform=None, target_transform=None):
self.train = train
self.transform = transform
self.target_transform = target_transform
if self.transform is None:
self.transform = lambda x: x
if self.target_transform is None:
self.target_transform = lambda x: x
self.data = None
self.label = None
self.prepare()
def __getitem__(self, index):
assert np.isscalar(index)
if self.label is None:
return self.transform(self.data(index)), None
else:
return self.transform(self.data(index)),\
self.target_transform(self.label(index))
def __len__(self):
return len(self.data)
def prepare(self):
pass
이제 위의 Dataset 클래스를 상속하여 나선형 데이터 세트를 구현해 보겠습니다.
실제로 코어 데이터 구성은 get_spiral 메소드에 구현되지만 Dataset 클래스를 상속하고 구현한다는 점에 유의하십시오.
class Spiral(Dataset):
def prepare(self):
self.data, self.label = get_spiral(self.train)
데이터 세트가 매우 큰 경우 다른 방법을 사용해야 합니다.
예를 들어, data 디렉토리와 label 디렉토리에 각각 100만 개의 데이터가 저장되어 있는 경우는, BigData 클래스의 초기화시에 데이터를 읽는 것이 아니라, 데이터에 액세스 했을 때에 읽도록 하는 것입니다.
np.load는 53단계에서 설명합니다.
class BigData(Dataset):
def __getitem__(index):
x = np.load('data/{}.npy'.format(index))
t = np.load('label/{}.npy'.format(index))
return x, t
def __len__():
return 1000000
그러면 학습을 진행합니다.
이전과 다른 점은 Dataset을 호출할 때 클래스를 활용하는 것입니다.
또한 Spiral 클래스에서 데이터를 미니 배치로 가져올 때 코드가 달랐습니다.
이 부분은 아래에서 따로 따릅니다.
import math
import numpy as np
import dezero
import dezero.functions as F
from dezero import optimizers
from dezero.models import MLP
max_epoch = 300
batch_size = 30
hidden_size = 10
lr = 1.0
train_set = dezero.datasets.Spiral(train=True)
model = MLP((hidden_size, 3))
optimizer = optimizers.SGD(lr).setup(model)
data_size = len(train_set)
max_iters = math.ceil(data_size / batch_size)
for epoch in range(max_epoch):
index = np.random.permutation(data_size)
sum_loss = 0
for i in range(max_iters):
batch_index = index(i * batch_size:(i + 1) * batch_size)
batch = (train_set(i) for i in batch_index)
batch_x = np.array((example(0) for example in batch))
batch_t = np.array((example(1) for example in batch))
y = model(batch_x)
model.cleargrads()
loss = F.softmax_cross_entropy(y, batch_t)
loss.backward()
optimizer.update()
sum_loss += float(loss.data) * len(batch_t)
avg_loss = sum_loss / data_size
print('epoch %d, loss %.2f' % (epoch + 1, avg_loss))
먼저 인덱스를 지정하여 미니 배치를 검색합니다.
그런 다음 인덱스에 따라 배치에 여러 데이터를 목록으로 저장합니다.
그런 다음 batch_x, batch_t에 하나의 ndarray 인스턴스로 변환하고 할당합니다.
이 과정을 반복하여 신경망에 미니 배치를 입력합니다.
train_set = dezero.datasets.Spiral()
batch_index = (0, 1, 2) # 0번째에서 2번째까지의 데이터 꺼내기
batch = (train_set(i) for i in batch_index)
# batch = ((data_0, label_0), (data_1, label_1), (data_2, label_2))
batch_x = np.array((example(0) for example in batch))
batch_t = np.array((example(1) for example in batch))
print(x.shape)
print(t.shape)
(3, 2)
(3,)
위에서 설명한 데이터 전처리 transform은 dezero/transform.py에 복수의 변환 처리가 준비되어 있다고 합니다.
책에서 별도로 설명하지 않습니다.
흥미가 있는 분은 참고로 해 주었으면 합니다.