ch4. 신경망 학습(2)

pasongtak·2024년 5월 7일

딥러닝

목록 보기
5/11

수치 미분

미분

한순간의 변화량을 표시한 것이다.


이 미분은 두가지의 문제점이 있는데, 첫번째는 너무 작은 값이 생략되어 최종 계산 결과에 오차가 생기게 하는 반올림 오차 문제이고, 진정한 미분은 x위치의 함수의 기울기에 해당하지만, 이 구현에서 미분은 (x+h)와 x 사이의 기울기에 해당하므로 진정한 미분과 이번 구현의 값은 일치하지 않는다. 이것은 h를 무한히 0으로 좁히는 것이 불가능해 생기는 한계이다.
위의 오차를 줄이기 위해 (x+h)와 (x-h)의 함수 f의 차분을 계산하는 방법인 중심 차분(중앙 차분)방법을 쓴다.

수치 미분의 예

f에 대한 해석적해로 진정한 미분의 결과를 비교해보면 x=5일 때 0.2이고, x=10일 때 0.3이다. 사진의 수치 미분 결과와 비교하면 오차가 매우 작은 것을 볼 수 있다. ## 편미분 변수가 여럿인 함수에 대한 미분을 **편미분**이라고 한다. 미분해야하는 변수만 있는 함수를 정의하고, 그 함수를 미분하는 형태로 구현할 수 있다. - x0=3, x1=4일 때 x0에 대한 편미분 - x0=3, x1=4일 때 x1에 대한 편미분

기울기

모든 변수의 편미분을 벡터로 정리한 것을 기울기라고 한다.

def numerical_gradient(f, x):
	h = 1e-4
    grad = np.zeros_like(x)
    
	for idx in range(x.size):
    	tmp_val = x[idx]
        
        x[idx] = tmp_val + h
        fxh1 = f(x)
        
        x[idx] = tmp_val - h
        fxh2 = f(x)
        
        grad[idx] = (fxh1 - fxh2) / (2*h)
        x[idx] = tmp_val
        
return grad

-np.zeros_like(x): x와 형상이 같고 그 원소가 모두 0인 배열을 만든다.

경사법

신경망에서 학습 시에 손실 함수가 최솟값이 되는 최적의 매개변수를 찾을 때 기울기를 이용해 찾는다. 현 위치에서 기울어진 방향으로 일정 거리만큼 이동하고, 이동한 곳에서도 마찬가지로 기울기를 구한다. 그 다음 기울어진 방향으로 계속 나아가면서 함수의 값을 점차 줄이는 것이 경사법이다.

한 번의 학습으로 얼마만큼 학습해야 할지, 매개변수 값을 얼마나 갱신하느냐를 정하는 것이 학습률이다.

위 식은 1회에 해당하는 갱신이고, 이 단계를 반복해서 함수의 값을 줄인다.

경사하강법: 최솟값을 찾는다.

  • f: 최적화 하려는 함수, init_x: 초깃값, lr(learning rate): 학습률, step_num: 경사법에 따른 반복 횟수
def gradient_descent(f, init_x, lr=0.01, step_num=100):
	x = init_x
    
    for i in range(step_num):
    	grad = numerical_gradient(f, x)
        x -= lr * grad
    return x

신경망에서의 기울기

신경망 학습에서는 가중치 매개변수에 대한 손실 함수의 기울기를 구해야 한다.

import sys, os
sys.path.append(os.pardir)
import numpy as np
from common.functions import softmax, cross_entropy_error
from common.gradient import numerical_gradient

class simpleNet:
	def __init__(self):
    	self.W = np.random.randn(2, 3)
    def predict(self, x):
    	return np.dot(x, self.W)
    def loss(self, x, t):
    	z = self.predict(x)
        y = softmax(z)
        loss = cross_entropy_error(y, t)
        
        return loss

학습 알고리즘 구현하기

  • 신경망 학습 절차
  1. 미니배치: 훈련 데이터 중 일부를 선별해 미니배치라고 하고, 미니배치의 손실 함수 값을 줄이는 것을 목표로한다.
  2. 기울기 산출: 미니배치의 손실 함수 값을 줄이기 위해 각 가중치 배개변수의 기울기를 구한다.
  3. 매개변수 갱신: 가중치 매개변수를 기울기 방향으로 갱신한다.
  4. 1~3단계를 반복한다.
    경사 하강법을 이용하고 데이터를 미니배치로 무작위로 선정하기 때문에 확률적 경사 하강법(SGD)이라고 한다.

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=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
        
    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
        
    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
  • np.random.rand(m, n): 가우시안 표준정규분포에서 난수 matrix array(m x n) 생성

변수

  • params: 신경망의 매개변수를 보관하는 딕셔너리 변수
    params['W1']는 1번째층의 가중치, params['b1']은 1번째 층의 편향
  • grads: 기울기 보관하는 딕셔너리 변수
    grads['W1']은 1번째 층의 가중치의 기울기, grads['b1']은 1번째 층의 편향의 기울기

메서드

  • __init__(self, input_size, hidden_size, output_size): 초기화 수행
  • predict(self, x): 예측 수행
  • loss(self, x, t): 손실 함수 값
  • accuracy(self, x, t): 정확도
  • numerical_gradient(self, x, t): 가중치 매개변수의 기울기
  • gradient(self, x, t): 가중치 매개변수의 기울기(numerical_gradient()의 성능 개선판)

미니배치 학습 구현하기

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)
    
train_lostt_list = []

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

network = TwoLayerNet(input_size=784, hidden_size=50, output_size=10)

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)
    
    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)

미니배치 크기를 100으로 하고, 100개의 미니배치를 대상으로 확률적 경사 하강법을 수행해 매개변수를 갱신한다. 갱신할 때마다 훈련 데이터에 대한 손실 함수를 계산하고, 그 값을 배열에 추가한다.

시험 데이터로 평가하기

범용 능력을 평가하기 위해 학습 도중 정기적으로 훈련 데이터와 시험 데이터를 대상으로 정확도를 평가한다.

  • 1에폭별로 훈련 데이터와 시험 데이터에 대한 정확도를 기록한다.
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)

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 = []

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)
    
    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" + str(train_acc) + ", " + str(test_acc))

정리

ㅋㅋㅋㅋㅋㅋㅋ.... 내일 다시 보는걸로 ,,,,,

0개의 댓글