몇일 전부터 쓰고 있던 포스팅인데 딴짓하고 그러느라 좀 늦었다. 이번에는 꼭 포스팅을 마무리하리라. 사실 딴짓이라기 보다는 포스팅을 하기 위해 사용해야할 수식들을 만들고 친구들 만나느라 우하하하.....


에헴.. 그러니까 예전에 다시 예제와 같이 설명하겠다는 Artificial Neural Network의 Backpropagation에 대해서 다시 한번 설명해보려고 한다. Backpropagation은 Artificial Neural Network를 training하기 위한 알고리즘으로 보면 된다. 조금 더 구체적으로 말하면 Artificial Neural Network의 Weight을 update하는데 사용된다고 보면 된다. 


우선 살짝 Artificial Neural Network에 대해서 복습하고 넘어갈까? Artificial Neural Network은 Input layer, Hidden layer, Output layer로 이루어져있는 network이다. 각각의 layer는 각각 다른 개수의 Neuron으로 이루어져있다. 하나의 Neuron을 보면 아래와 같이 생겼다.


무언가 input n개를 받고 그것을 각각의 weight에 곱하고 더해서 z를 구한다. 이 z값을 f(z)에 적용하여 output을 낸다. 이 때 f(z) 함수의 특성에 따라 output은 무조건 0과 1사이가 된다. 


지금까지 한 이야기들은 모두 이전 포스팅에도 했었던 내용이다. 사실 앞으로 쓸 내용도 모두 했던 얘기이다. 그렇지만 조금 더 숫자를 이용해서 구체적으로 쓰려고 하는 것이다. 예전에 이야기했던 것처럼 Artificial Neural Network은 한개의 Input layer 여러개의 Hidden layer 한개의 Output layer를 가지고 있다. 이번 포스팅에는 나는 아래와 같은 한개의 Input layer, 두개의 Hidden layer, 한개의 Output layer를 가지고 이야기를 해보려고 한다.


각각의 Weight을 모두 쓰려면 너무 시간이 걸리고 복잡해보이기만 할 것 같아서 위와 같이 몇개만 예시로 Weight 넘버링 해봤다. wN_{ij}는 Layer{N-1}에서의 i번째 Neuron과 Layer{N}의 j번째 Neuron 사이의 Weight을 표현한 것이다.


Backpropagation은 epoch를 계속 반복하면서 최적의 weight으로 update되는 과정이다. 따라서 제일 처음에는 weight은 random값으로 설정된다. 우리는 공부를 하고 있는 것이므로 아래와 같이 initialize되었다고 가정하고 생각해보련다.

자 여기서 Backpropagation을 시작해보자. Input layer는 3 dimension이기 때문에 세 개의 Input, Output layer는 2 dimension이기 때문에 두 개의 Output, bias는 Input layer를 제외한 나머지 모든 layer에 각각 하나씩 주기로 하고 그래서 3 dimension (4 - 1). 위와 같이 초기화시켜놓고 Backpropagation을 시작해보자.


이 식과 그 값을 앞으로 계속 사용할 것이다. 즉 Backpropagation을 하기 위해서는 우선 젤 먼저 feedforward를 할 이유가 있다는 것이다. (위의 식처럼 주어진 input과 weight을 가지고 output을 구하는 것을 feedforward라고 한다.) 위의 식에서 f(x)는 x에 대한 sigmoid function이다.


아무튼 위의 값을 가지고 Backpropagation을 시작해보자. Backpropagation의 목적은 Error를 최소한으로 하는 weight을 만드는데 목적이 있다. Error는 sum of squared error로 아래와 같이 구한다.


위의 식에서 y는 실제 값 y_hat은 우리가 feedforward 해서 나온 예측값이다. 즉 우리의 예측값과 실제값의 차이의 제곱의 합의 절반을 Error라고 정의하고 그것을 최소화하겠다는 것이다. (왜 절반이냐? 계산을 쉽게하기 위해서!! 미분하기 쉽기 위해서!! 제곱을 미분하면 2가 앞으로 튀어나올 것이고 서로 상쇄되서 없어지니까.)


우리가 정확히 구하고 싶은 것은 Error가 아니라 Error를 최소로 만드는 weight을 구하고 싶은 것이다. 따라서 우리는 Error를 weight으로 미분할 것이다. 각 층별로 우리는 w1 w2 w3을 가지고 있으니까 결국 우리는 아래의 값을 순서대로 구할 것이다.


de/dw3

de/dw2

de/dw1


de/dw3를 젤 먼저 구할 것이다. 그래서 BACKpropagation이다. 뒤에 것부터!! 뭐 그런의미이다. 


위와 같이 de/dw3를 구하면 된다. w3는 4x2 matrix이니까 당연히 위와 같이 8개의 element를 구해야 한다. 여기서 질문!! 위의 식에서, 예를 들어 de/dw3_{11}를 보자. 이 식이 de_{total}/dOUT_{o1} * dOUT_{o1}/dOUT_{z1} * dOUT_{z1}/dw3_{11}와 같이 되는 것은 알겠지? 그런데 이것이 왜 그 다음 식으로 전개가 될까? 왜 ...


de_{total}/dOUT_{o1} = -(y1 - OUT_{o1})

dOUT_{o1}/dOUT_{z1} = OUT_{o1}(1-OUT_{o1})

dOUT_{z1}/dw3_{11} = H2_{o1}


이렇게 될까??? 위의 세 식이 저렇게 되는 이유를 알면 backpropagation은 거의 모두 이해했다고 보면 된다. de_{total}/dOUT_{o1}부터 차례대로 봐보자.


이기 때문에 이것을 OUT_{o1}로 미분을 하면 


이렇게 되는 것이다 y2에 대해서는 마찬가지로 OUT_{02}로 똑같이 해주면 된다.


dOUT_{o1}/dOUT_{z1}를 구해보자. 이거는 조금 더 복잡하다. 그렇지만 어렵지는 않다.


dOUT_{z1}/dw3_{11}는 굉장히 간단하다. OUT_{z1}을 젤 위의 식에서 


로 표현했기 때문에 이것을 w3_{11}로 미분하면 H2_{o1}이 나오는 것이다.


결국 de_{total}/dOUT_{o1}, dOUT_{o1}/dOUT_{z1}, dOUT_{z1}/dw3_{11}는 우리가 이미 feedforward를 통해 구해놓은 그 값을 짜맞춰서 구할 수 있게 된다는 뜻이다.


자 de_{total}/dOUT_{o1}, dOUT_{o1}/dOUT_{z1}를 미분하는 공식은 그냥 "외워"두자. 왜냐하면 앞으로도 계속 쓰이기 때문이다. 아래와 같이 공식화해보자.

위의 공식을 생각하며 de/dw2를 구해보자.


위와 같이 구할수 있다. 위의 값중에서 de_{total}/dH2_{o1}, de_{total}/dH2_{o2}, de_{total}/dH2_{o3}, de_{total}/dH2_{o4}는 아래와 같이 구할 수 있다.


이 식의 수식 전개는 모두 위에서 "외우"라고 했던 공식 세개를 통해서 이해가 가능할 것이고 추가로 설명해야할 내용이 있다면 왜 de_{total}/dH2_{o1} = de_{1}/dH2_{o1} + de_{2}/dH2_{o1} 이와 같이 되는가? 정도일 것 같다. 왜인지 생각해보자. H2_{o1}가 error에 영향을 주는 것은 e_{1}에도 영향을 주고 e_{2}에도 영향을 주기 때문이다. 즉 H2_{o1}의 변화량은 e_{1}과 e_{2} 모두에게 영향을 준다는 뜻이다. 그래서 두 개를 더한 것이다.


자 de/dw2 식 설명을 모두 끝냈으니까 실제로 값을 구해볼까나. 우선 de_{total}/dH2_{o1}, de_{total}/dH2_{o2}, de_{total}/dH2_{o3}, de_{total}/dH2_{o4}는 아래와 같은 값을 갖게 되기 때문에


이와 같은 값을 가지게 되고, de/dw2는 아래와 같이 계산이 된다.


이제 마지막으로 de/dw1을 구할 차례이다. 이거는 아래와 같이 구하면 된다.


de_{total}/dH1_{o1}, de_{total}/dH1_{o2}, de_{total}/dH1_{o3}, de_{total}/dH1_{o4}, de_{total}/dH1_{o5}는 아래와 같이 구한다. 여기서부터 조금 많이 복잡해진다. 종이하고 연필꺼내서 적어가면서 봐라. 눈으로는 이해하기 힘들것이다.


우선 H1_{o1}, H1_{o2}, H1_{o3}, H1_{o4}, H1_{o5}는 e1과 e2모두 영향을 주게 된다. 따라서 기본적으로 


de_{total}/dH1_{o1} = de_{1}/dH1_{o1} + de_{2}/dH1_{o1}

de_{total}/dH1_{o2} = de_{1}/dH1_{o2} + de_{2}/dH1_{o2}

de_{total}/dH1_{o3} = de_{1}/dH1_{o3} + de_{2}/dH1_{o3}

de_{total}/dH1_{o4} = de_{1}/dH1_{o4} + de_{2}/dH1_{o4}

de_{total}/dH1_{o5} = de_{1}/dH1_{o5} + de_{2}/dH1_{o5}


위와 같이 나오고. e1과 e2는 각각 아래와 같이 OUT_{o1}과 OUT_{o2}로 표현이 가능하고 OUT_{o1}과 OUT_{o2}는 모두 H1_{o1}, H1_{o2}, H1_{o3}, H1_{o4}, H1_{o5}로 표현이 가능하다. 아래와 같이 말이다.

(위의 식이 복잡하여 일부러 g(x)라는 함수를 만들어놨다. g(x)는 sigmoid function 말하는 것이다. f(x)와 같다고 생각하고 보면 된다.)


복잡하다... 그래도 어쩌겠냐.. 해야지.. 아무튼 이것을 알고 

de_{total}/dH1_{o1} = de_{1}/dH1_{o1} + de_{2}/dH1_{o1}

de_{total}/dH1_{o2} = de_{1}/dH1_{o2} + de_{2}/dH1_{o2}

de_{total}/dH1_{o3} = de_{1}/dH1_{o3} + de_{2}/dH1_{o3}

de_{total}/dH1_{o4} = de_{1}/dH1_{o4} + de_{2}/dH1_{o4}

de_{total}/dH1_{o5} = de_{1}/dH1_{o5} + de_{2}/dH1_{o5}


이것을 구해보자.


고등학교 때 f(g(x))를 미분하면 f'(g(x)) * g'(x)라는 것을 배웠을 것이다. 그것을 이용해서 e_{1}과 e_{2}를 H1_{o1}, H1_{o2}, H1_{o3}, H1_{o4}, H1_{o5}로 각각 미분하면 위와 같이 되는 것이다. (나 혼자 미분하고 굿하고 장구치고 한거라.. 틀릴수도 있다. 하지만 원리는 위와 같이 구하는 것이 맞다)


g1, g2, g3, g4의 값과 그 미분값을 구해봤을 때 아래의 값이 나오고

이것을 대입해서 우리가 원하는 값을 구하면...

이렇게 나오게 된다. 그러면 우리는 이제 드디어 de/dw1, de/dw2, de/dw3를 모두 구하게 됐다!!! 이것을 가지고 최종적으로 w1, w2, w3을 update시켜보자. weight update는 아래와 같이 할 수 있다.


위의 공식에 따라서 weight을 update해보면 아래와 같이 update된다. (단, learning_rate은 0.1이라고 하면...)


지금까지 무지하게 많은 숫자와 공식들을 가지고 고생했다... 우와... 드디어 했다 아무튼... 참고로 말하자면 위의 식들 중 틀린 것이 있을 수도 있다. 그렇지만 원리는 제대로 설명했으니 '이 사람 실수했꾸먼?' 하고 봐주면서 읽기를 바란다. 


다음 포스팅은 뭘까? 잘 모르겠따. 이번 포스팅 역시 무지하게 오랜만에 한 포스팅인데.... 아무튼 언제가 될지 모를 다음 포스팅을 기다려주시길...

Posted by 빛나유
,