Deep learning/모델 구현

9. 오차역전법(3) - 오차역전법 구현하기

jwjwvison 2021. 4. 22. 22:24

이 포스팅은 밑바닥부터 시작하는 딥러닝을 공부하고 정리한것 입니다.


 1. 신경망 학습의 전체 그림

 지금까지 설명한 오차역전파법이 등장하는 단계는 두 번째인 '기울기 산출' 이다. 앞에서는 기울기를 구하기 위해서 수치 미분을 사용했는데 수치 미분은 구현하기 쉽지만 계산이 오래걸렸다. 오차역전파법을 이용하면 느린 수치 미분과 달리 기울기를 효율적이고 빠르게 구할 수 있다.

 

 

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

import sys,os
sys.path.append(os.pardir)
import numpy as np
from common.layers import *
from 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):
        # 가중치 초기화
        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)
        
        # 계층생성
        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):
        # 순전파
        self.loss(x,t)
        
        # 역전파
        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['Affine1'].dw
        grads['b2']=self.layers['Affine1'].db
        
        return grads

 이처럼 신경망의 구성 요소를 '계층'으로 구현한 덕분에 신경망을 쉽게 구축할 수 있다.

 

 

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

수치 미분은 오차역전파법을 정확히 구현했는지 확인하기 위해 필요하다.

import sys,os
sys.path.append(os.pardir)
import numpy as np
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)

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

grad_numerical=network.numerical_gradient(x_batch,t_batch)
grad_backprop=network.gradient(x_batch,t_batch)

# 각 가중치의 차이의 절대값을 구한 후, 그 절대값들의 평균을 낸다
for key in grad_numerical.keys():
    diff=np.average(np.abs(grad_backprop[key] - grad_numerical[key]))
    print(key + ':' + str(diff))

 이 결과는 수치 미분과 오차역전파법으로 구한 기울기의 차이가 매우 작다고 말해준다.

 

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

 

import sys,os
sys.path.append(os.pardir)
import numpy as np
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)

iter_num=10000
train_size=x_train.shape[0]
batch_size=100
learning_rate=0.1

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

iter_per_epoch=max(train_size/batch_size,1)

for i in range(iter_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:
        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)

 

 

결론


 이번 장에서는 계산 과정을 시각적으로 보여주는 방법인 계산 그래프를 공부했다. 이처럼 동작을 계층으로 모듈화한 덕분에, 신경망의 계층을 자유롭게 조합하여 원하는 신경망을 쉽게 만들 수 있다.