06
05

7. 오차역전파법 구현하기


7.1 신경망 학습의 전체 그림

딥러닝은 손실함수의 값이 최소로 되도록 가중치와 편향인 매개변수를 조정하는 과정을 학습이라고 한다. 딥러닝 학습은 다음 4단계와 같다.

  1. 미니배치(mini-batch) : Train 데이터 중 랜덤하게 샘플을 추출하는데 이것을 미니배치라고 하며, 미니배치의 손실함수 값을 줄이는 것이 학습의 목표이다.

  2. 기울기 계산 : 손실함수의 값을 작게하는 방향을 가리키는 가중치() 매개변수의 기울기를 구한다.

  3. 매개변수 갱신 : 가중치 매개변수를 기울기 방향으로 학습률(learning rate)만큼 갱신한다.

  4. 반복 1~3 단계를 반복한다.

7.2 오차역전파법을 적용한 신경망 구현하기

# two_layer_net.py
import sys,os
sys.path.append(os.pardir)  # 부모 디렉터리의 파일을 가져올 수 있도록 설정
import numpy as np
from collections import OrderedDict
from common.layers import *
from common.gradient import numerical_gradient


class TwoLayerNet:
   '''2층 신경망 구현'''
   def __init__(selfinput_size,
                hidden_sizeoutput_sizeweight_init_std=0.01):
       '''
      초기화 수행
      Params:
          - input_size: 입력층 뉴런 수
          - hidden_size: 은닉층 뉴런 수
          - output_size: 출력층 뉴런 수
          - weight_init_std: 가중치 초기화 시 정규분포의 스케일
      '''
       # 가중치 초기화
       self.params = {
           'W1'weight_init_std * np.random.randn(input_sizehidden_size),
           'b1'np.zeros(hidden_size),
           'W2'weight_init_std * np.random.randn(hidden_sizeoutput_size),
           'b2'np.zeros(output_size)
      }
       
       # 계층 생성
       self.layers = OrderedDict({
           'Affine1'Affine(self.params['W1'], self.params['b1']),
           'Relu1'Relu(),
           'Affine2'Affine(self.params['W2'], self.params['b2'])
      })
       
       self.last_layer = SoftmaxWithLoss()
       
   
   def predict(selfx):
       '''예측(추론)
          Pararms:
              - x: 이미지 데이터'''
       for layer in self.layers.values():
           x = layer.forward(x)
           
       return x
   
   def loss(selfxt):
       '''
      손실함수의 값을 계산
      Params:
          - x: 이미지데이터, t: 정답 레이블
      '''
       y = self.predict(x)
       return self.last_layer.forward(yt)
   
   def accuracy(selfxt):
       '''
      정확도 계산
      Params:
          - x: 이미지 데이터
          - t: 정답 레이블
      '''
       y = self.predict(x)
       y = np.argmax(yaxis=1)
       if t.ndim !1:
           t = np.argmax(taxis=1)
       
       accuracy = np.sum(y==t/ float(x.shape[0])
       return accuracy
   
   
   def numerical_gradient(selfxt):
       '''
      미분을 통한 가중치 매개변수의 기울기 계산
      Params:
          - x: 이미지 데이터
          - t: 정답 레이블
      '''
       loss_W = lambda Wself.loss(xt)
       
       grads = {
           'W1'numerical_gradient(loss_Wself.params['W1']),
           'b1'numerical_gradient(loss_Wself.params['b1']),
           'W2'numerical_gradient(loss_Wself.params['W2']),
           'b2'numerical_gradient(loss_Wself.params['b2'])
      }
       return grads
   
   def gradient(selfxt):
       # forward
       self.loss(xt)
       
       # backward
       dout = 1
       dout = self.last_layer.backward(dout)
       
       layers = list(self.layers.values())
       layers.reverse()
       for layer in layers:
           dout = layer.backward(dout)
           
       # 결과 저장
       grads = {
           'W1'self.layers['Affine1'].dW'b1'self.layers['Affine1'].db,
           'W2'self.layers['Affine2'].dW'b2'self.layers['Affine2'].db
      }
       return grads

7.3 오차역전파법으로 구한 기울기 검증하기

수치 미분을 통해 구한 기울기와 오차역전파법의 결과를 비교하여 오차역전파를 제대로 구현했는지 검증하는 작업을 기울기 확인(gradient check)이라고 한다.

%%time
# gradient_check.py
import sysos
sys.path.append(os.pardir)
import numpy as np
from dataset.mnist import load_mnist

# mnist load
(x_traint_train), (x_testt_test) = load_mnist(normalize=True)

network = TwoLayerNet(input_size=28*28hidden_size=50output_size=10)

x_batch = x_train[:3]
t_batch = t_train[:3]

grad_numerical = network.numerical_gradient(x_batcht_batch)
grad_backprop = network.gradient(x_batcht_batch)

# 각 가중치의 절대 오차의 평균을 구한다.
for key in grad_numerical.keys():
   diff = np.average(np.abs(grad_backprop[key- grad_numerical[key]))
   print(key,":"str(diff))
W1 : 4.479721446541244e-10
b1 : 2.5485543061868916e-09
W2 : 4.349602602871501e-09
b2 : 1.393278526204411e-07
Wall time: 6.78 s


7.4 오차역전파법을 사용한 학습 구현하기

%%time
# train_neuralnet.py
import sysos
sys.path.append(os.pardir)
import numpy as np
from dataset.mnist import load_mnist

# mnist load
(x_traint_train), (x_testt_test) = load_mnist(normalize=True)

network = TwoLayerNet(input_size=28*28hidden_size=50output_size=10)

# Train Parameters
iters_num = 10000
train_size = x_train.shape[0]
batch_size = 100
learning_rate = 0.1
iter_per_epoch = max(train_size / batch_size1)

train_loss_listtrain_acc_listtest_acc_list = [], [], []

for step in range(1iters_num+1):
   # get mini-batch
   batch_mask = np.random.choice(train_sizebatch_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_batcht_batch# 오차역전파법 방식(압도적으로 빠르다)
   
   # Update
   for key in ('W1''b1''W2''b2'):
       network.params[key] -= learning_rate * grad[key]
       
   # loss
   loss = network.loss(x_batcht_batch)
   train_loss_list.append(loss)
   
   if step % iter_per_epoch == 0:
       train_acc = network.accuracy(x_traint_train)
       test_acc = network.accuracy(x_testt_test)
       train_acc_list.append(train_acc)
       test_acc_list.append(test_acc)
       print('Step: {:4d}\tTrain acc: {:.5f}\tTest acc: {:.5f}'.format(step,
                                                                       train_acc,
                                                                       test_acc))
       
print('Optimization finished!')
Step: 600Train acc: 0.90450Test acc: 0.90560
Step: 1200Train acc: 0.92288Test acc: 0.92570
Step: 1800Train acc: 0.93220Test acc: 0.93200
Step: 2400Train acc: 0.94605Test acc: 0.94460
Step: 3000Train acc: 0.95430Test acc: 0.95210
Step: 3600Train acc: 0.95993Test acc: 0.95870
Step: 4200Train acc: 0.96360Test acc: 0.95870
Step: 4800Train acc: 0.96682Test acc: 0.96320
Step: 5400Train acc: 0.96930Test acc: 0.96380
Step: 6000Train acc: 0.97108Test acc: 0.96450
Step: 6600Train acc: 0.97318Test acc: 0.96690
Step: 7200Train acc: 0.97557Test acc: 0.96890
Step: 7800Train acc: 0.97698Test acc: 0.96760
Step: 8400Train acc: 0.97808Test acc: 0.96990
Step: 9000Train acc: 0.97835Test acc: 0.97030
Step: 9600Train acc: 0.98035Test acc: 0.97020
Optimization finished!
Wall time: 26.6 s



출처: https://excelsior-cjh.tistory.com/171?category=940400 [EXCELSIOR]

COMMENT