반응형
간단한 신경망 학습 구현을 위해
확률적 경사 하강법을 이용한
미니배치 학습 방법을
활용하는 예제입니다.
이번 글에서는 MNIST 데이터셋을 사용하여 학습을 수행할 거고 신경망은 은닉층이 1개인 2층 신경망 Two Layer Net 클래스를 정의하여 이용할 것입니다. (아래 코드는 Deep Learning from Scratch의 코드를 참고하였습니다.)
시작하기에 앞서 본 글에서 이용할 방법인 신경망 학습의 4단계 절차를 정리해봅시다.
이 포스트에서는 Stochastic gradient descent(SGD, 확률적 경사 하강법)을 이용할 예정입니다.
(1) 미니배치
|
먼저 2층 신경망 클래스인 TwoLayerNet 클래스를 구현합니다.
# coding: utf-8
import sys, os
sys.path.append(os.pardir) # 부모 디렉터리의 파일을 가져올 수 있도록 설정
from common.functions import *
from common.gradient import numerical_gradient
class TwoLayerNet:
def __init__(self, input_size, hidden_size, output_size, weight_init_std=0.01):
# 가중치 초기화
self.params = {}
self.params['W1'] = weight_init_std * np.random.randn(input_size, hidden_size)
self.params['b1'] = np.zeros(hidden_size)
self.params['W2'] = weight_init_std * np.random.randn(hidden_size, output_size)
self.params['b2'] = np.zeros(output_size)
def predict(self, x):
W1, W2 = self.params['W1'], self.params['W2']
b1, b2 = self.params['b1'], self.params['b2']
a1 = np.dot(x, W1) + b1
z1 = sigmoid(a1)
a2 = np.dot(z1, W2) + b2
y = softmax(a2)
return y
# x : 입력 데이터, t : 정답 레이블
def loss(self, x, t):
y = self.predict(x)
return cross_entropy_error(y, t)
def accuracy(self, x, t):
y = self.predict(x)
y = np.argmax(y, axis=1)
t = np.argmax(t, axis=1)
accuracy = np.sum(y == t) / float(x.shape[0])
return accuracy
# x : 입력 데이터, t : 정답 레이블
def numerical_gradient(self, x, t):
loss_W = lambda W: self.loss(x, t)
grads = {}
grads['W1'] = numerical_gradient(loss_W, self.params['W1'])
grads['b1'] = numerical_gradient(loss_W, self.params['b1'])
grads['W2'] = numerical_gradient(loss_W, self.params['W2'])
grads['b2'] = numerical_gradient(loss_W, self.params['b2'])
return grads
def gradient(self, x, t):
W1, W2 = self.params['W1'], self.params['W2']
b1, b2 = self.params['b1'], self.params['b2']
grads = {}
batch_num = x.shape[0]
# forward
a1 = np.dot(x, W1) + b1
z1 = sigmoid(a1)
a2 = np.dot(z1, W2) + b2
y = softmax(a2)
# backward
dy = (y - t) / batch_num
grads['W2'] = np.dot(z1.T, dy)
grads['b2'] = np.sum(dy, axis=0)
da1 = np.dot(dy, W2.T)
dz1 = sigmoid_grad(a1) * da1
grads['W1'] = np.dot(x.T, dz1)
grads['b1'] = np.sum(dz1, axis=0)
return grads
다음으로 주어진 MNIST 데이터셋을 2층 신경망으로 학습시키기 위한 코드를 구성합니다.
# coding: utf-8
import sys, os
sys.path.append(os.pardir) # 부모 디렉터리의 파일을 가져올 수 있도록 설정
import numpy as np
import matplotlib.pyplot as plt
from dataset.mnist import load_mnist
from two_layer_net import TwoLayerNet
# 데이터 읽기
(x_train, t_train), (x_test, t_test) = load_mnist(normalize=True, one_hot_label=True)
network = TwoLayerNet(input_size=784, hidden_size=50, output_size=10)
# 하이퍼파라미터
iters_num = 10000 # 반복 횟수를 적절히 설정한다.
train_size = x_train.shape[0]
batch_size = 100 # 미니배치 크기
learning_rate = 0.1
train_loss_list = []
train_acc_list = []
test_acc_list = []
# 1에폭당 반복 수
iter_per_epoch = train_size / batch_size
for i in range(iters_num):
# 미니배치 획득
batch_mask = np.random.choice(train_size, batch_size)
x_batch = x_train[batch_mask]
t_batch = t_train[batch_mask]
# 기울기 계산
#grad = network.numerical_gradient(x_batch, t_batch)
grad = network.gradient(x_batch, t_batch)
# 매개변수 갱신
for key in ('W1', 'b1', 'W2', 'b2'):
network.params[key] -= learning_rate * grad[key]
# 학습 경과 기록
loss = network.loss(x_batch, t_batch)
train_loss_list.append(loss)
# 1에폭당 정확도 계산
if i % iter_per_epoch == 0:
train_acc = network.accuracy(x_train, t_train)
test_acc = network.accuracy(x_test, t_test)
train_acc_list.append(train_acc)
test_acc_list.append(test_acc)
print("train acc, test acc | " + str(train_acc) + ", " + str(test_acc))
# 그래프 그리기
markers = {'train': 'o', 'test': 's'}
x = np.arange(len(train_acc_list))
plt.plot(x, train_acc_list, label='train acc')
plt.plot(x, test_acc_list, label='test acc', linestyle='--')
plt.xlabel("epochs")
plt.ylabel("accuracy")
plt.ylim(0, 1.0)
plt.legend(loc='lower right')
plt.show()
여기서 에폭 epoch은 하나의 단위를 말합니다. 1에폭은 학습에서 훈련 데이터를 모두 소진했을 때의 횟수에 해당합니다. 위의 코드에서 훈련 데이터 10,000개를 100개의 미니배치로 학습했으므로, 확률적 경사 하강법을 100회 반복하면 모든 훈련 데이터를 소진하게 되어 이 경우에는 100회가 1에폭이 된다고 할 수 있습니다.
1에폭마다 모든 훈련 데이터와 시험 데이터에 대한 정확도accuracy를 기록하여 그래프를 그려보면 다음과 같은 결과를 볼 수 있습니다.
그래프에서 볼 수 있듯이 train accuracy와 test accuracy가 거의 동일하게 변화하는 양상을 보입니다. 이는 학습이 진행될수록(에폭이 증가할수록) 훈련 데이터와 테스트 데이터의 정확도가 증가하고 오버피팅은 일어나지 않는다는 것을 보여줍니다. 만약 오버피팅이 일어나면 훈련 데이터의 정확도는 계속 증가하는 양상을 보이는 반면, 테스트 데이터의 정확도는 증가하다가 점차 떨어지는 양상을 보였을 겁니다.
오버피팅이 발생하는 경우에는 학습을 조기 종료하거나 가중치 감소, 드롭아웃 등의 해결법으로 문제를 해결할 수 있습니다. 다음에 이 내용에 대해서도 다루려고 합니다.
[출처] Deep Learning from Scratch, ゼロ から作る
728x90
반응형
'Computer Science > Deep Learning' 카테고리의 다른 글
[비전공자용] [Python] Xavier Initialization (Xavier 초기화) & He Initialization (He 초기화) (0) | 2020.07.10 |
---|---|
[비전공자용] [Python] 모멘텀, AdaGrad, Adam 최적화기법 (0) | 2020.07.09 |
[비전공자용] 확률적 경사 하강법 SGD 의 단점 (0) | 2020.07.08 |
[비전공자용] [Python] 오차역전파법 Backpropagation 신경망 구현 (0) | 2020.07.08 |
[비전공자용] [Python] 머신러닝과 딥러닝 구분 (3) | 2020.07.03 |