신경망 학습의 절차
0. 전제 : 신경망에는 적응 가능한 가중치와 편향이 있고, 이 가중치와 편향을 훈련 데이터에 적응하도록 조정하는 과정을 학습이라 한다.
1. 미치배치 : 훈련 데이터 중 일부를 무작위로 가져온다. 이렇게 선별한 데이터를 미니배치라 하며, 그 미니배치의 손실함수 값을 줄이는 것이 목표.
2. 기울기 산출 : 미니배치의 손실 함수 값을 줄이기 위해 각 가중치 매개변수의 기울기를 구한다. 기울기는 손실 함수의 값을 가장 작게 하는 방향을 제시한다.
3. 매개변수 갱신 : 가중치 매개변수를 기울기 방향으로 아주 조금 갱신한다.
4. 반복 : 1-3 단계를 반복한다.
위의 절차는 경사 하강법으로 매개변수를 갱신하는 방법이며, 데이터를 미니배치로 무작위로 선정하기 때문에 확률적 경사 하강법(stochastic gradient descent, SGD)이라고 한다. 확률적으로 무작위로 골라낸 데이터에 대해 수행하는 경사 하강법이라는 의미이다.
1. 2층 신경망 클래스 구현
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 = sigmod(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])
# 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['W1'])
grads['b2'] = numerical_gradient(loss_W, self.params['b2'])
return grads
- TwoLayerNet 클래스가 사용하는 변수
변수 | 설명 |
params | 신경망의 매개변수를 보관하는 딕셔너리 변수(인스턴스 변수) |
params['W1']은 1번째 층의 가중치, params['b1']은 1번째 층의 편향 | |
params['W2']는 2번째 층의 가중치, params['b2']는 2번째 층의 편향 | |
grads | 기울기를 보관하는 딕셔너리 변수(numerical_gradient() 메서드의 반환 값) |
grads['W1']은 1번째 층이 가중치의 기울기, grads['b1']은 1번째 층의 편향의 기울기 | |
grads['W2']는 2번째 층의 가중치의 기울기, grads['b2]는 2번째 층의 편향의 기울기 |
- TwoLayerNet 클래스의 메소드
메소드 | 설명 |
__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) | 가중치 매개변수의 기울기를 구한다. |
gradient(self, x, t) | 가중치 매개변수의 기울기를 구한다. numerical_gradient()의 개선판. 구현은 다음에. |
n번째 층의 가중치 매개변수는 params['Wn']키에 넘파이 배열로 저장된다.
ex)
net = TwoLayerNet(input_size= 784, hidden_size=100, output_size=10)
print(net.params['W1'].shape)
print(net.params['b1'].shape)
print(net.params['W2'].shape)
print(net.params['b2'].shape)
[실행 결과]
(784, 100)
(100,)
(100, 10)
(10,)
이처럼 params 변수에는 신경망에 필요한 매개변수가 모두 저장된다. 그리고 params 변수에 저장된 가중치 매개변수가 예측 처리(순방향 처리)에서 사용된다.
예측 처리 코드
x = np.random.rand(100, 784) #더미 입력 데이터(100장 분량)
y = net.predict(x)
grads 변수에는 params 변수에 대응하는 각 매개변수의 기울기가 저장된다. numerical_gradient() 메소드를 이용해서 기울기를 계산하면 grads 변수에 기울기 정보가 저장된다.
x = np.random.rand(100, 784) #더미 입력 데이터(100장 분량)
t = np.random.rand(100, 10) #더미 정답 레이블 (100장 분량)
grads = net.numerical_gradient(x, t) #기울기 계산
print(grads['W1'].shape)
print(grads['b1'].shape)
print(grads['W2'].shape)
print(grads['b2'].shape)
[실행 결과]
(784, 100)
(100,)
(784, 100)
(10,)
손글씨 숫자 인식에서 크기가 28X28인 입력 이미지가 총 784개이고, 출력은 10개가 된다. 이에 따라 값을 지정해주고, 은닉층의 갯수인 hidden_size는 적당한 값을 설정한다.
초기화 메소드는 가중치 매개변수도 초기화한다. 가중치 매개변수의 초기값을 무엇으로 설정하느냐가 신경망 학습의 성공을 좌우한다.
predict(self, x)와 accuracy(self, x, t)의 구현은 앞부분의 신경망의 추론 처리와 거의 같다.
loss(self, x, t)는 predict()의 결과와 정답 레이블을 바탕으로 교차 엔트로피 오차를 구하도록 구현했다.
numerical_gradient(self, x, t)는 수치 미분 방식으로 각 매개변수의 손실 함수에 대한 기울기를 계산한다.
gradient(self, x, t)는 오차역전파법을 사용하여 기울기를 계산한다.
신경망 학습은 시간이 오래 걸리니, 시간을 절약하려면 numerical_gradient(self, x, t) 대신 gradient(self, x, t)를 쓰는 것이 좋다. |
'Deep Learning 1 > 신경망 학습' 카테고리의 다른 글
4. 기울기 (0) | 2020.07.20 |
---|---|
3. 수치 미분 (0) | 2020.05.04 |
2. 손실 함수 (0) | 2020.04.29 |
1. 데이터에서 학습 (0) | 2020.04.28 |