신경망 학습의 절차
1. 미니배치 (Mini-batch)
훈련 데이터 중 일부를 무작위로 가져온다. 이렇게 선별한 데이터를 미니배치라 하며, 그 미니배치의 손실 함수 값을 줄이는
것이 목표
2. 기울기 산출
미니배치의 손실 함수 값을 줄이기 위해 각 가중치 매개변수의 기울기를 구합니다. 기울기는 손실 함수의 값을 가장 작게하는
방향을 제시
3. 매개변수 갱신
가중치 매개변수를 기울기 방향으로 아주 조금씩 갱신
4. 반복
1~3 단계를 반복
코드 전문
# 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
변수 | 설명 |
params | 신경망의 매개변수를 보관하는 Dict 변수 |
params['W1']은 1번째 층의 가중치, params['b1']은 1번째 층의 편향 | |
params['W2']은 2번째 층의 가중치, params['b2']은 2번째 층의 편향 | |
grads | 기울기를 보관하는 Dict 변수 (numerical_gradient() 메소드의 반환값) |
grad['W1']은 1번째 층의 가중치의 기울기, grads['b1']은 1번째 층의 편향의 기울기 | |
grad['W2']은 2번째 층의 가중치의 기울기, grads['b2']은 2번째 층의 편향의 기울기 |
메소드 | 설명 |
__init__(self, input_size, hidden_size, output_size) | 초기화를 수행한다. 인수는 순서대로 입력층의 뉴런 수, 은닉층의 뉴런수, 출력층의 뉴런 수 |
predict(self, x) | 예측(추론)을 수행한다. 인수 x는 이미지 데이터 |
loss(self, x, t) |
손실 함수의 값을 구한다. 인수 x는 이미지 데이터, t는 정답 레이블 (아래도 마찬가지) |
accuracy(self, x, t) | 정확도를 구한다 |
numerical_gradient(self, x, t) | 가중치 매개변수의 기울기를 구한다 |
하나의 예시를 들어보자
net = TwoLayerNet(input_size=784, hidden_size=100, output_size=10)
net.params['W1'].shape
Out[57]: (784, 100)
net.params['b1'].shape
Out[58]: (100,)
net.params['W2'].shape
Out[59]: (100, 10)
net.params['b2'].shape
Out[60]: (10,)
다음과 같은 행렬 꼴을 가짐을 알 수 있다.
x=np.random.rand(100,784)
y=net.predict(x)
t=np.random.rand(100,10)
grads = net.numerical_gradient(x, t)
grads['W1'].shape
Out[65]: (784, 100)
grads['b1'].shape
Out[66]: (100,)
grads['W2'].shape
Out[67]: (100, 10)
grads['b2'].shape
Out[68]: (10,)
grads 변수의 모양도 확인 할 수 있다.
4.5.2 미니배치 학습 구현하기
이제 앞서 알아본 TwoLayerNet을 mnist에 사용을 해볼 것이다.
# 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 = max(train_size / batch_size, 1)
for i in range(iters_num):
# 미니배치 획득
batch_mask = np.random.choice(train_size, batch_size)
#train_size에서 batch_size 개만큼만 random하게 뽑는다.
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)
미니배치의 크기는 100이다.
매 번 60000개의 훈련 데이터에서 임의로 100개의 데이터를 추려낸다. 그리고 그 100개의 미니배치를 대상으로 확률적 경사 하강법을 수행해 매개변수를 갱신한다. 경사법에 의한 갱신 횟수를 10000번으로 설정하고, 갱신 할 때마다 훈련 데이터에 대한 손실 함수를 계산하고, 그 값을 배열에 추가한다. (train_loss_list)
plt.plot(train_loss_list)
plt.xlabel('iteration')
plt.ylabel('loss')
plt.show()
반복을 진행할 수록, 손실 함수의 값이 감소하는 것을 볼 수 있다. 이는 학습이 잘 되고 있다는 뜻으로, 신경망 가중치 매개변수가 서서히 데이터에 적응하고 있음을 의미한다. 데이터를 반복해서 학습함으로써 최적 가중치 매개변수로 서서히 다가서고 있다.
4.5.3 시험 데이터로 평가하기
손실 함수 값이 작아지는 것은 신경망이 잘 학습하고 있다는 방증이지만, 이 결과만으로는 다른 데이터셋에도 비슷한 실력을 발휘할지 확실하지 않다.
신경망 학습에서는 훈련 데이터 외에 데이터를 올바르게 인식하는지를 확인해야 한다. 즉 '오버피팅'을 일으키지 않는지 확인해야 한다.
오버피팅이 되었다면, 훈련 데이터에 포함된 이미지만 제대로 구분하고, 그렇지 않은 이미지는 식별할 수 없다는 뜻이다.
신경망 학습의 원래 목표는 범용적인 능력을 익히는 것이다. 범용 능력을 평가하기 위해서는 훈련 데이터에 포함됮 ㅣ않은 데이터를 사용해 평가해야 한다. 이를 위해서 1에폭별로 훈련 데이터와 시험 데이터에 대한 정확도를 기록한다.
##에폭(epooch)은 학습에서 훈련 데이터를 모두 소진했을 때의 횟수에 해당한다. 훈련 데이터 10000개를 100개의 미니 배치로 학습할 경우, 확률적 경사 하강법을 100회 반복하면 모든 훈련 데이터를 소진한 게 된다. 이 경우 100회가 1에폭이 된다.
# 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))
위 결과에서는 오버피팅이 일어나지 않았다.
'머신 러닝 및 파이썬 > 밑바닥부터 시작하는 딥러닝' 카테고리의 다른 글
Ch.5 오차역전파법/ 5.5 활성화 함수 계층 구현 (ReLU, Sigmoid) (0) | 2020.03.03 |
---|---|
Ch.5 오차역전파법/ 5.1 계산 그래프, 5.2 연쇄법칙, 5.3 역전파, 5.4 단순한 계층 구현 (0) | 2020.03.03 |
Python: Lambda 식 (0) | 2020.03.02 |
Ch.4 신경망 학습/ 4.3 수치 미분 4.4 기울기 (0) | 2020.02.27 |
Ch.4 신경망 학습/ 4.2 손실함수 (0) | 2020.02.26 |