Hyeon Lee 2023. 1. 10. 13:42
728x90

※ 신경망에서의 기울기

 

형상 2×3 행렬, 가중치 W, loss function이 L인 신경망을 생각해보자.

 

이와 같은 W 행렬을 통해 기울기를 구현해보면

 

 

이와 같은 편미분 행렬을 구해낼 수 있을 것이다. 여기서 1행 1번째 원소의 경우 w11을 변경했을 때 손실 함수 L이 얼마나 변화하느냐를 나타낸다. 또한, 미분을 적용한 행렬의 형상이 기존 W 행렬과 같은 2×3 행렬이라는 점을 알 수 있다.

 

import sys, os
sys.path.append(os.pardir)
import numpy as np

def softmax(a):
    c = np.max(a)
    exp_a = np.exp(a-c)
    sum_exp_a = np.sum(exp_a)
    y = exp_a / sum_exp_a
    
    return y
    
def numerical_gradient(f, x):
    h = 1e-4 # 0.0001
    grad = np.zeros_like(x)
    
    it = np.nditer(x, flags=['multi_index'], op_flags=['readwrite'])
    while not it.finished:
        idx = it.multi_index
        tmp_val = x[idx]
        x[idx] = float(tmp_val) + h
        fxh1 = f(x) # f(x+h)
        
        x[idx] = tmp_val - h 
        fxh2 = f(x) # f(x-h)
        grad[idx] = (fxh1 - fxh2) / (2*h)
        
        x[idx] = tmp_val # 값 복원
        it.iternext()   
        
    return grad
    
def cross_entropy_error(y, t):
    delta = 1e-7
    return -np.sum(t * np.log(y + delta))
    
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

 

앞에서 배워왔던 활성화함수 softmax, loss function인 cross_entropy_error, 미분값 numerical gradient를 사용해서 simpleNet Class를 구현해보았다. 간단한 신경망 속에서 2×3행렬의 더미 인수를 사용해서 구현했으며 predict()함수는 예측값을 불러오는 것, loss함수는 예측과 교차 엔트로피 오차를 이용한 loss 값을 불러오는 기능을 하는 Class이다.

 

net = simpleNet()
print(net.W)
[[-0.68065703  1.19968356  0.7072641 ]
 [-0.06380419  2.14776974  0.44823901]]

 

먼저 위와 같은 더미값을 불러왔다.

 

x = np.array([0.6, 0.9])
p = net.predict(x)
print(p)
[-0.46581799  2.6528029   0.82777357]

 

예측값을 이처럼 불러올 수 있다.

 

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

net = simpleNet()

f = lambda w: net.loss(x, t)
dW = numerical_gradient(f, net.W)

print(dW)
[[ 0.26184894  0.24028043 -0.50212937]
 [ 0.39277341  0.36042064 -0.75319405]]

 

t에 정답 레이블을 답고 loss 값을 구현할 수 있는 f 변수를 lamda 식으로 나타내어주었으며 numerical_gradient 함수를 사용하여 net.W를 인수로 받아 f로 구해진 loss 값의 변화량을 dW에 담아 출력해주었다.

 

결과값은 net.W로 받은 2×3 행렬의 더미값의 loss 값의 변화량을 의미한다.

그렇다면 1행 1열의 0.26184894는 무엇을 의미할까? 이는 w11을 h만큼 늘리면 0.26184894h 만큼 증가한다는 의미이다.

그렇다면 2행 3열의 -0.75319405는 또 무엇을 의미할까? 부호가 (-) 인 것을 통해 w23을 h 만큼 늘리면 0.75319405 만큼 감소한다는 것을 의미한다.

 

손실 함수를 줄인다는 개념에서는 w11의 경우는 음의 방향으로, w23의 경우는 양의 방향으로 갱신해야 한다. 또한, 변화량의 관점에서 w23이 w11보다 더 많은 양을 기여한다는 것을 알 수 있다.

 

이렇게 신경망의 기울기를 구한 다음 경사법에 따라 가중치 매개변수를 갱신하는 방향으로 구현이 가능하다.

728x90