Deep Learning/밑바닥부터 시작하는 딥러닝

경사하강법(Gradient Descent method)

대소기 2022. 1. 25. 21:50

 

경사하강법(Gradient Descent method)

* 경사하강법은 최적의 가중치와 편향을 찾기 위한 알고리즘이다. 여기서 최적이란 손실함수의 값을 최소화 하는, 즉 다시 말해 예측값과 정답 레이블의 차이를 최소화 하는 것을 뜻한다. 경사하강법은 방대한 크기의 공간에서 최적의 값을 찾기 위해 '기울기'를 이용한다.

 

$x_0 = x_0 - \eta {\partial f \over \partial x_0}$

$x_1 = x_1 - \eta {\partial f \over \partial x_1}$

 

* 가중치의 갱신은 위와 같이 이뤄진다. 위 식은 가중치 1회 갱신에 대해 나타내고 있다.

* 여기서 $\eta$는 learning rate이라고 한다. learning rate은 가중치 update에 기울기를 얼마나 반영할 것인지를 나타내는 parameter이다. 

 

def numerical_gradient(f,x):
    h = 1e-4 				#0.0001
    grad = np.zeros_like(x) 		#x와 형상이 같은 배열을 생성
    
    for idx in range(x.size):
        tmp_val =x[idx]
        
        #f(x+h)계산
        x[idx] = tmp_val + h
        fxh1 = f(x)
        
        #f(x-h)계산
        x[idx] = tmp_val - h
        fxh2 = f(x)
        
        grad[idx] = (fxh1 - fxh2)/(2*h)
        x[idx] = tmp_val 			#값 복원
        
    return grad

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

 

* gradient_descent 함수는 위에서 설명한 수식을 그대로 구현한 것이다. numerical_gradient는 주어진 점의 기울기를 구하는 함수로 이전 포스팅에

경사하강법의 문제

* 경사가 0인 지점을 따라 내려가다보면 global minimum이 아닌 local minimum에 빠질 위험이 있다.

* 비슷한 개념이지만, 위와 같이 saddle point(안장점) 에서 gradient가 0이 되어 학습이 멈출 위험이 있다.

 

신경망에서의 기울기

 

* 지금까지 배운 것 처럼 손실함수를 최소화 하기 위해서는 gradient descent 방법을 사용하고, gradient descent를 사용하기 위해서는 기울기를 구해야 한다.

* 만약 신경망의 특정 뉴런의 가중치가 W라고 했을 때 가중치 W의 기울기는 위 그림처럼 각 원소의 기울기를 편미분한 값이다. 

* 실제로 기울기를 구하는 코드를 구현하기 앞서 

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): # Loss Function
        z = self.predict(x)
        y = softmax(z)
        loss = cross_entropy_error(y, t)

        return loss

* 뉴런의 개수가 3개인 layer가 1 개로 구성된 neural network를 정의하였다. 다중 label 분류 문제를 위해 마지막 layer는 softmax를 사용하였다.

 

x = np.array([0.6, 0.9])
t = np.array([0, 0, 1])

net = simpleNet()

f = lambda w: net.loss(x, t) # 인수로 w를 받아 손실 함수를 계산
dW = numerical_gradient(f, net.W) # 미분을 사용하여 기울기를 구한다.

print(dW)

>> [[ 0.25448428  0.03691667 -0.29140095]
 [ 0.38172642  0.05537501 -0.43710143]]

* 인수를 w로 받아 손실함수를 계산하는 lambda 함수를 정의하고, 이를 통해 가중치의 기울기 dw를 구하였다. 

* 위 결과를 보면 알 수 있다시피 $w_11$의 편미분 값은 약 0.25이다. 편미분 값이 0.25라는 것은 $w_11$이 0에 한없이 가까운 수인 h만큼 증가할 때 손실함수의 값은 0.25h 만큼 증가한다는 것을 뜻한다. 우리의 목표는 손실함수의 값을 최소로 하는 가중치를 찾는 것이기 떄문에 $w_11$을 음의 방향으로 갱신해 손실함수의 값을 줄여야 할 것이다. 

 

학습 알고리즘 구현하기

 

1단계 - 미니배치

* 훈련 데이터를 random으로 sampling한다.

 

2단계 - 기울기 산출

* 미니배치의 손실함수를 최소로 하는 기울기를 찾기 위해 일단 현재 가중치의 기울기를 계산한다.

 

3단계 - 매개변수 갱신

* 가중치 매개변수를 기울기 방향으로 아주 조금 갱신한다.

 

4단계 - 반복

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