본문 바로가기
Data Science/문과생도 이해하는 딥러닝

문과생도 이해하는 딥러닝 (7) - 오차역전파법 실습 2

by 싸코 2018. 1. 5.


2017/09/27 - 문과생도 이해하는 딥러닝 (1) - 퍼셉트론 Perceptron

2017/10/18 - 문과생도 이해하는 딥러닝 (2) - 신경망 Neural Network

2017/10/25 - 문과생도 이해하는 딥러닝 (3) - 오차 역전파, 경사하강법

2017/12/24 - 문과생도 이해하는 딥러닝 (4) - 신경망구현, 활성화함수, 배치

2017/12/26 - 문과생도 이해하는 딥러닝 (5) - 신경망 학습 실습

2018/01/05 - 문과생도 이해하는 딥러닝 (6) - 오차역전파법 실습 1


 


오차역전파법은 계층 형태로 순전파와 역전파를 메서드로 구현하여 효율적으로 기울기를 계산할 수 있도록 모듈화하여 신경망의 layer를 자유롭게 쌓고 쉽게 만들며 계산 속도를 빠르게 해준다. 딥러닝의 신경망 학습 모형은 이러한 layer들과 그 안의 함수들을 모듈로서 레고 블럭을 조립하듯이 조립하여 신경망을 구현할 수 있다.



오차역전파법 실습 2

문과생도 이해하는 딥러닝 (7)

앞선 "신경망 학습 실습" 포스팅에서는 순전파만을 고려하였고 기울기 계산을 수치 미분으로 하면서 계산이 오래 걸려서 결국.... 결과를 내지 못했다. 다행히 이번 오차역전파를 적용한 실습에서는 계산이 빨라 신경망 학습에 대한 결과까지 그래프로 확인할 수 있었다. 학습의 정확도는 약 98%, 테스트의 정확도는 약 97%까지 나왔다.


코드에 대한 설명은 추후 추가


from scratch.common.layers import *
from scratch.common.gradient import numerical_gradient

from collections import OrderedDict
class TwoLayerNet:
    def __init__(self, input_size, hidden_size, output_size, weight_init_std=0.01):
        # initializa Weights
        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)
        
        # Build Layers
        self.layers = OrderedDict()
        self.layers['Affine1'] = Affine(self.params['W1'], self.params['b1'])
        self.layers['Relu1'] = Relu()
        self.layers['Affine2'] = Affine(self.params['W2'], self.params['b2'])
        
        self.lastLayer = SoftmaxWithLoss()
    
    
    def predict(self, x):
        for layer in self.layers.values():
            x = layer.forward(x)
        return x
        
    
    def loss(self, x, t):
        y = self.predict(x)
        return self.lastLayer.forward(y, t)
    
    
    def accuracy(self, x, t):
        y = self.predict(x)
        y = np.argmax(y, axis=1)
        if t.ndim != 1 :
            t = np.argmax(t, axis=1)
        
        accuracy = np.sum(y==t) / float(x.shape[0])
        return accuracy
    
    
    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):
        # foward
        self.loss(x, t)
        
        # backward
        dout = 1
        dout = self.lastLayer.backward(dout)
        
        layers = list(self.layers.values())
        layers.reverse()
        for layer in layers:
            dout = layer.backward(dout)
        
        grads = {}
        grads['W1'] = self.layers['Affine1'].dW
        grads['b1'] = self.layers['Affine1'].db
        grads['W2'] = self.layers['Affine2'].dW
        grads['b2'] = self.layers['Affine2'].db
        return grads
from scratch.dataset.mnist import load_mnist
(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
print('number of iterations is', iters_num)
train_size = x_train.shape[0]
print('train size is', train_size)
batch_size = 100
print('batch size is', batch_size)
learning_rate = 0.1

train_loss_list = []
train_acc_list = []
test_acc_list = []

iter_per_epoch = max(train_size / batch_size, 1)

print('='*20 + '>')
epoch = 0
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.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)

    
    if i % iter_per_epoch == 0:
        epoch += 1
        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('Epoch', epoch, ':  ',train_acc,'\t', test_acc)
        
number of iterations is 10000
train size is 60000
batch size is 100
====================>
Epoch 1 :   0.102966666667 	 0.1055
Epoch 2 :   0.904416666667 	 0.9074
Epoch 3 :   0.9235 	 0.9252
Epoch 4 :   0.936166666667 	 0.9344
Epoch 5 :   0.9447 	 0.9432
Epoch 6 :   0.951983333333 	 0.9506
Epoch 7 :   0.955983333333 	 0.9537
Epoch 8 :   0.960733333333 	 0.9562
Epoch 9 :   0.965166666667 	 0.9602
Epoch 10 :   0.967366666667 	 0.9616
Epoch 11 :   0.969633333333 	 0.9652
Epoch 12 :   0.9721 	 0.966
Epoch 13 :   0.973833333333 	 0.9676
Epoch 14 :   0.975983333333 	 0.9686
Epoch 15 :   0.976883333333 	 0.9703
Epoch 16 :   0.9778 	 0.9694
Epoch 17 :   0.97895 	 0.9702
import matplotlib.pyplot as plt
plt.figure(figsize=(20,8))
plt.plot(train_loss_list[:1000], linewidth=0.5)
plt.title('Train Loss Graph')
plt.xlabel('iteration')
plt.ylabel('loss')
plt.show()
plt.figure(figsize=(20,8))
plt.plot(train_acc_list, linewidth=1)
plt.plot(test_acc_list, '-.' ,linewidth=1)
plt.legend(['train acc', 'test acc'], loc=0)
plt.xlabel('epochs')
plt.ylabel('accuracy')
plt.show()






댓글