신경망 학습의 절차
전제
신경망에는 적응 가능한 가중치와 편향이 있고 이 가중치와 편향을 훈련데이터에 적응하도록 조정하는 과정을 '학습' 이라한다.
1단계 - 미니배치
훈련데이터중 일부를 무작위로 가져옵니다. 이렇게 선별한 데이터를 미니배치라 하며, 그 미니배치의 손실함수 값을 줄이는 것이 목표이다.
2단계 - 기울기 산출
미니배치의 손실 함수 값을 줄이기 위해 각 가중치 매개변수의 기울기를 구한다. 기울기는 손실 함수의 값을 가장 작게 하는 방향을 제시한다.
3단계 - 매개변수 갱신
가중치 매개변수를 기울기 방향으로 아주 조금 갱신한다.
4단계 - 반복
이것은 경사하강법으로 매개변수를 갱신하는 방법이며, 이때 데이터를 미니배치로 무작위로 선정하기 때문에 확률경사하강법(SGD)라고 부른다.
이제 손글씨 숫자를 학습하는 신경망을 구성해보자
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
|
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
|
cs |
코드를 설명해보면
변수
- params - 신경망의 매개변수를 보관하는 딕셔너리 변수
params[W1]은 1번째 층의 가중치, params[b1]은 1번째 층의 편향
params[W2]는 2번째 층의 가중치, params[b2]는 2번재 층의 편향
- grads - 기울기 보관하는 딕셔너리 변수(numerical_gradient() 매서드의 반환값)
params[W1]은 1번째 층의 가중치, grads[b1]은 1번째 층의 편향
params[W2]는 2번째 층의 가중치, grads[b2]는 2번재 층의 편향
메서드
- __init__(self,input_size, hidden_size, output_size) : 초기화를수행
인수는 순서대로 입력층 뉴런수, 은닉층의 뉴런수, 출력층의 뉴런수
- predict(self,x) : 예측을 수행한다. 인수 x는 이미지 데이터
- loss(sef,x,t) : 손실함수의 값을 구한다.(x는 이미지 데이터, t는 정답레이블. 아래 메서드들도 마찬가지)
- accuracy(self, x, t) :정확도
- numerical_gradient(self, x, t) : 가중치 매개변수의 기울기를 구한다.
- gradient(self, x, t) : 가중치 매개변수의 기울기를 구한다.(numerical_gradient()의 개선판.)
이제 미니배치 학습을구현해보자(TwoLayerNet 크래스와 MNIST 데이터셋을 사용)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
|
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)
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)
|
cs |
batch크기를 100으로 하여 매번 60,000개의 데이터중에서 임의로 100개의 데이터를 추출한다.
그리고 100개의 배치를 대상으로 확률적 경사하강법을 수행해 매개변수를 갱신한다.
경사법에 의한 갱신 횟수(반복횟수)를 10,000번으로 설정하고 갱신할 때마다 훈련데이터에 대한 손실 함수를 계산하고,
그 값을 배열에 추가한다.
이것을 그래프로 나타내면 아래와 같다.
이제 시험 데이터로 평가를 해보자.
시험 데이터로 하는 이유는 오버피팅이 안되고 범용적으로 활용될수 있는지 확인하기 위해서이다.
여기에서는 1에폭별로 훈련 데이터와 시험 데이터에 대한 정확도를 기록한다.
에폭은 하나의 단위이다. 1에폭은 학습에서 훈련데이터를 모두 소진했을 대의 횟수에 해당한다.
ex. 훈련데이터 10,000개를 100개의 배치로 학습시, 확률적 경사하강법을 100회 반복하면 모든 훈련 데이터를 소진한게 된다. 이경우 100회가 1에폭이된다.
1에폭당 하는이유는 for문으로 일일이 하면 시간이 오래 걸리기 때문이다.
에폭이 진행될수록(학습이 진행될수록) 훈련 데이터와 시험 데이터를 사용하고 평가한 정확도가 모두 좋아지고 있다.
두데이터에 차이가 거의없다. 즉, 오버피팅이 없다는 소리다. (오버피팅이엇다면 두데이터의 차이가 컸을 것이다.)
이번 걸 구현하면서
중간에 MNIST를 구분하는 것을 생략하여 완벽하지는 않지만
대충 신경망 학습이 어떤식으로 구성되고 진행되는지 알수 있었다.
'DATA Science > DeepLearing from scratch' 카테고리의 다른 글
딥러닝 학습 관련 기술들 (0) | 2021.05.17 |
---|---|
오차역전파법 (0) | 2021.05.14 |
신경망 학습 (2) | 2021.05.12 |
신경망 (0) | 2021.05.12 |
퍼셉트론 (0) | 2021.05.11 |
댓글