이전 시간에는 간단히 2계층 신경망을 구성해 보았다, 엄청 느리지만 몇줄 안되는 코드로 숫자 맞추기가 86% 넘는 정확도로 학습되었다. 중간에 학습된 매개변수를 저장했다면 직접 손글씨를 써서 예측을 돌려 볼 수도 있었을 것이다.
신경망은 학습데이터를 입력받고 손실을 출력한다. \(W\), \(b\) 매개변수를 미분하는 것이 신경만의 첫번째 핵심 원리이다. 이전 장에서처럼 미분을 한다면 많은 연산량으로 인해 컴퓨팅 성능에 한계가 생긴다. 미분을 빨리 수행하는 것이 두번째 핵심 원리이다.
오차역전파법
오차역 전파법의 핵심은 합성함수의 미분이다. \(z = g(f(x))\) 라는 함수가 있을 때 \(y = f(x)\) 와 \(z = g(y)\) 라는 두 함수로 표현할 수 있다. \(x\) 에 대한 \(z\)의 미분을 합성함수의 미분이라고 한다. 이 경우 합성함수의 미분은 \(y = f(x)\) 의 미분과 \(z = g(y)\) 의 미분을 곱해서 얻을 수 있다. 이것이 바로 연쇄 법칙이다. 함수가 중첩된 형태로 복잡하더라도 개별 함수의 미분을 이용해 쉽게 구할 수 있다.
신경망은 결국 중첩된 함수에 불과하며 이 중첩된 함수는 단일 국소적 함수의 미분을 구해서 곱하면 된다. 위 경우를 수식으로 표현하면 아래와 같다.
$$ \frac{\partial z}{\partial x} = \frac{\partial z}{\partial y}\frac{\partial y}{\partial x} $$
예를 들어\(z = (x + y)^2\) 라는 함수는 아래 두개의 함수로 나눌 수 있다.
$$ z = t^2 $$
$$ t = x + y $$
첫번째 함수의 도함수는 \(2t\) 가 되고, 두번째 함수의 도함수는 \(1\) 이 된다. 결국 \(2t \times 1\)이 합성함수의 미분법칙인 연쇄법칙이되며 \(2t = 2(x+y)\) 이 된다.
이를 수식으로 최종정리하면,
\(x\) 에대한 \(z\)의 미분은 \(t\) 에 대한 \(z\) 의 미분 \(x\) 에 대한 \(t\) 의 미분의 곱으로 나타낼 수 있다.
$$ \frac{\partial z}{\partial x} = \frac{\partial z}{\partial t}\frac{\partial t}{\partial x} = 2t \times 1 = 2(x + y)$$
연쇄법칙
연쇄 법칙은 함성 함수의 미분에 대한 성질이며, 다음과 같이 정의된다.
합성 함수의 미분은 함성함수를 구성하는 각 함수의 미분의 곱으로 나타낼 수 있다.
위 수식을 연쇄적으로 풀이한다고 하면 \( t = x + y \) 를 계산하고 나서 --> 다음에 \(t^2\)을 계산할 것이다. 당연한 것이 \(x + y\) 값이 결정되고 나서야 결정된 값의 제곱이 결정될 것이기 때문이다. 미분을 할 때는 \( t^2\)을 먼저 미분하고 \(x+y\) 를 미분합니다. 힙성함수이 미분과정은 함성함수 연산의 반대방향으로 가기 때문에 오차역전파로 불립니다. 계산 그래프로 보면 이전 단계의 미분결과에 국소함수의 미분결과 계속 곱해 나가는 과정입니다.
신경망 계층에 대한 역전파
이전 장에서 2계층 신경망을 구성하는데, 사용한 함수는 matmul, sigmoid(활성화), softmax(분류), cross entropy (손실) 이렇게 네가지 이다. 2계층 신경망 전체는 각각의 함수를 이어 놓은 것이므로 연쇄법칙의 성질을 이용하여 역방향으로 미분을 해나가면 동일한 미분 결과가 나온다.
이렇게 함성함수의 연쇄법칙의 성질을 이용하는 이유는 연산량이 극단적으로 줄어들기 때문에 계산 속도가 무척 빨라지는데 있다. 위의 예에서 순방향 미분을 하면 하면 \(\t^2\) 에서 보이는 것처럼 제곱 연산이 필요하지만, 합성함수의 미분을 이용하면 \(2t\) 로 제곱연산이 곱하기 연산으로 줄어든다.
앞선 장에서 MNIST 손글씨 학습 시, 순방향 미분으로만 했을 때는 50시간 가까이 걸렸는데, 역방향 미분을 하면 불과 수분 혹은 수십분 안에 연산이 끝난다.
성능을 높이기 위해서 4가지 함수는 순방향의 결과를 가지고 역방향을 계산해야한다. 소스를 클래스 형태로 바꾸고 각 클래스에 forward(순방향), backward(역방향) 함수를 구현하겠다. 먼저 matmul 함수의 역방향 까지 고려한 MatMul 클래스를 추가해 보자
layers.py
...
class MatMul:
def __init__(self, W):
self.params = [W]
self.grads = [np.zeros_like(W)]
self.x = None
def forward(self, x):
W, = self.params
out = np.matmul(x, W)
self.x = x
return out
def backward(self, dout):
W, = self.params
dx = np.matmul(dout, W.T)
dW = np.matmul(self.x.T, dout)
self.grads[0][...] = dW
return dx
...
'A.I.(인공지능) & M.L.(머신러닝) > 신경망 이론' 카테고리의 다른 글
GCN 코드를 통해 이해 (0) | 2024.08.14 |
---|---|
Attention LSTM + GCN + 커머스 (0) | 2024.08.13 |
2. 초간단 신경망(2/3) (0) | 2024.02.17 |
1. 초 간단 신경망(1/3) (0) | 2024.02.04 |