[딥러닝] Deep Learning 공부

김대웅·2024년 3월 16일

Deep Learning

목록 보기
2/16
post-thumbnail

목표

딥러닝에 대해 차근차근 배워보자!

이 강의는 혁펜하임님의 ALL DEEP DIVE 강의를 기반으로 작성함.

MLP, 행렬과 벡터로 나타내기

일단 MLP에 대해 다시 짚어보자면 다음과 같다.

MLP : 다중 퍼셉트론, 입력층과 출력층 사이에 은닉층을 하나 이상 가지고 있는 퍼셉트론.

이를 그림으로 간단히 표현하면 다음과 같다.

위처럼 은닉층이 하나인 경우에 대해 웨이트와 바이어스를 각각 표현하였다.
이 때, f1(activation)에 들어오는 값은 각각 다음과 같다.
f1(x1w1+x2w2+b1), f1(x1w3+x2w4+b2), f1(x1w5+x2w6+b3)f_1( x1\cdot w1 + x2\cdot w2 + b1) , ~f_1 (x1\cdot w3 + x2\cdot w4 + b2), ~f_1 ( x1\cdot w5 + x2\cdot w6 + b3)

근데 이렇게 쓰면 너무 길게 표현해야하므로 이를 벡터와 행렬로 표현하면 다음과 같다!
fˉ1([x1x2][w1w3w5w2w4w6]+[b1b2b3])\bar f_1 ( \begin{bmatrix} x1 & x2 \end{bmatrix}\cdot \begin{bmatrix} w1 & w3 & w5 \\ w2 & w4 & w6 \end{bmatrix} + \begin{bmatrix}b1 & b2 & b3 \end{bmatrix})

이렇게 행렬과 벡터로 표현하였는데, 이를 더 간단하게 하고자 다시 표현하면 다음과 같다.

  • [x1x2]\begin{bmatrix} x1 & x2 \end{bmatrix}은 입력층이므로 xˉ\bar x로 나타냄.

  • [w1w3w5w2w4w6]\begin{bmatrix} w1 & w3 & w5 \\ w2 & w4 & w6 \end{bmatrix}은 첫번째 layer의 웨이트 값이므로 W1W_1으로 표현.

  • [b1b2b3]\begin{bmatrix}b1 & b2 & b3 \end{bmatrix}은 첫번째 layer의 바이어스 값이므로 bˉ1\bar b_1로 표현.

그러면 fˉ1(xˉW1+bˉ1)\bar f_1(\bar xW_1 + \bar b_1)으로 간단히 표현 가능하다!!

그리고 이를 출력층까지 표현하면 다음과 같다!!

fˉ2(fˉ1(xˉW1+bˉ1)W2+bˉ2)fˉ(xˉ)\bar f_2(\bar f_1(\bar xW_1 + \bar b_1)W_2 + \bar b_2) \rightarrow \bar f(\bar x) ( MLP에 xx를 넣었을 때 나오는 출력값을 의미.)

이것이 곧 출력값이 된다! (여기서 주의할 점은 행렬과 벡터에서 줄였지만 이 나타내는 값들이 몇 by 몇 행렬인지는 알아야 한다!)

결국 MLP는 '행렬' 곱하고 '벡터' 더하고 activation의 반복이라는 것을 알 수 있다!


Non-linear activation이 중요한 이유

위에서 우린 MLP를 행렬과 벡터를 이용해 아주 간결하게 나타내어 보았다.
그렇다면 MLP를 계속 계속 이렇게 은닉층을 이어서 만들어 깊게 깊게 만들면 엄청 복잡한 함수가 만들어 지는 것이라고 유츄할 수 있다..! 과연 그렇게 나올까?
\rightarrow Non-linear activation은 가능하나 linear activation은 그렇지 않다..!

선형 함수(linear activation)은 간단하게 말하자면 '들어가는 대로 나오는 것'이다. (즉, f(x)=xf(x) = x가 성립.)

위의 MLP 설명을 예를 들어 수식으로 나타내면 다음과 같다.
xˉ\bar x를 사용하면 fˉ(xˉ)=f([x1x2])\bar f(\bar x) = f(\begin{bmatrix} x_1 & x_2 \end{bmatrix}) 이고, 들어가는 대로 나오기 때문에 [f(x1)f(x2)]\begin{bmatrix} f(x_1) & f(x_2) \end{bmatrix}가 된다.
그리고 이 값은 즉, [x1x2]\begin{bmatrix} x_1 & x_2 \end{bmatrix}로 나오게 된다!
결국, 선형 함수의 경우 f()f()의 의미가 아예 없어진채로 나온다고 보면 된다.

이를 가지고 위의 예시의 식인 fˉ2(fˉ1(xˉW1+bˉ1)W2+bˉ2)\bar f_2(\bar f_1(\bar xW_1 + \bar b_1)W_2 + \bar b_2)f()f() 을 신경쓰지 않고 전개를 하면 다음이 나온다.

xˉW1W2+bˉ1W2+bˉ2\bar xW_1W_2 + \bar b_1W_2 + \bar b_2

이제 위의 식을 분석해보자!
W1W_1W2W_2는 각각 2 X 3, 3 X 2이다. 그러므로 이 둘의 곱은 2 X 2가 나오게 된다. 이 곱을 WW라고 정의를 해보자. 무언가 감이 오지 않는가?
전에 우리가 배운 인공신경망 부분에서 웨이트(a)와 바이어스(b)를 구하는 것이 딥러닝의 목표라고 하였고, 이 둘은 머신이 직접 구하는 '파라미터'라고 하였다..!
그런데 a1a2x+ba_1a_2x + bax+bax + b에서 웨이트와 바이어스를 구할 때, 결국 두 식 모두 머신이 웨이트와 바이어스를 구하기에 a1a2a_1a_2이든 aa이든 결국 똑같다는 것이다!
(심지어 앞의 경우 머신이 두 개를 구하기에 더 복잡할 수도 있다..)

결국 위의 식의 W1W2W_1W_2는 두 개의 웨이트의 곱이지만 그냥 웨이트(WW) 하나 구하는 것이라고 볼 수 있다.
또한, 뒷부분의 bˉ1W2\bar b_1W_2은 1 X 3, 3 X 2여서 1 X 2로 나오고 결국, bˉ1W2+bˉ2\bar b_1W_2 + \bar b_2도 위의 논리로 보았을 때 그냥 바이어스(bb) 하나 구하는 것과 다를 바 없다는 것이다.

결론적으로 말하자면, 선형 함수를 쓰면 fˉ2(fˉ1(xˉW1+bˉ1)W2+bˉ2)\bar f_2(\bar f_1(\bar xW_1 + \bar b_1)W_2 + \bar b_2) = xˉW+b\bar x W + b인 것이다!
그리고 선형 함수를 쓴 식 xˉW+b\bar x W + b을 그림으로 나타내면 WW는 2 X 2, bb는 1 X 2 이므로 다음과 같다.

전 그림에선 분명 MLP로 은닉층이 존재하였는데, 위의 그림으로 보니 은식층이 그냥 무시된 것을 확인할 수 있다.

결론을 말하자면 다음과 같다.

linear activation으로는 아무리 깊게 만들어도 hidden layer 없는 FC layer 이하의 표현력만 가진다!
\rightarrow 깊어지는 효과를 전혀 누리지 못하고 그냥 시간 낭비가 된다는 것.

linear activation으로는 입력과 출력 간의 선형적 관계만을 나타낸다.
따라서, Non-linear activation이 중요하다..!
(입력, 출력 간의 비선형적인 관계도 나타낼 수 있고, 깊을수록 복잡한 함수 표현 가능하다.)

물론 머신에서 linear activation을 원하는 경우가 나올 수 있지만, 보통 우리가 쓰는 딥러닝 문제에서는 non-linear activation을 원하는 경우가 대부분이다.

[*] "위에서 hidden layer 없는 FC layer '이하'의 표현력만 가진다."라고 하였는데, 이하가 되는 경우는?
위 그림의 경우는 오히려 그냥 hidden layer 없는 FC layer보다 더 성능이 떨어지는 표현력을 보일 수 있다.

[*] 그렇다면 linear \rightarrow non-linear \rightarrow linear \rightarrow non-linear 이렇게 하면 좀 괜찮지 않을까..?
전혀 아니다. linear의 경우에서 은닉층이 사라진다는 조건은 똑같기 때문에 그냥 non-linear을 두 번 쓰는 것보다 더 표현력이 떨어질 수 있고, 귀찮은 계산만 늘어나게 된다.


Backpropagation (back : 뒤, propagation : 전달)

이제 위처럼 깊은 신경망을 구현하는 방법을 알았으니, 이에 대한 그라디언트를 구하는 방법도 알아야 한다.
그리고 이 방법을 간단히 말하자면 모든 웨이트와 바이어스에 대해 편미분을 진행하여 그라디언트를 만들어주면 된다!
예를 들어 위의 예시였던 그림을 가져오면

이에 대한 웨이트와 바이어스의 개수는 (2 3 + 3) + (3 2 + 2) = 17개가 된다.
그러므로 그라디언트는 17 X 1의 벡터로 나오게 된다..! (전에는 a, b만 있어서 두 개였는데.. 아주 많다..)

이제 웨이트와 바이어스에 대해 하나하나 편미분을 진행해줘야 하는데,
이는 기초 수학에서 배웠던 Chain rule을 이용하면 된다!!
(결국 미분이 뒤(back)로 전달(propagation)되므로 backpropagation인 것이다!)
그리고 17개를 하나하나 구하는 것이 귀찮고 복잡하지만, 하나하나 구해보면 규칙성을 발견할 수 있다!

구하기 위해 위의 그림을 다시 조정하면 다음과 같다.
위 그림에 대해 설명하면 다음과 같다.

  • waw_a는 해당 layer의 가중치(weight)를 말한다.
  • dad_a는 해당 layer에서 들어가는 값을 말한다. 예를 들면 d1=w1x1+b1d_1 = w_1 \cdot x_1 + b_1이 된다.
  • nan_a는 해당 layer에서 나오는 값을 말한다. 예를 들면 n1=f1(d1)n_1 = f_1(d_1)이 된다. (n0n_0x1x_1을 의미한다.)
  • y^a\widehat y_a는 해당 출력값을 말한다. 위에서 보면 y^1\widehat y_1의 값은 n1n_1과 같다.
  • 그리고 위의 그림에 나오는 신경망의 손실 함수(LL)은 MSE를 가지고 정의하여
    (y^1y1)2+(y^2y2)2(\widehat y_1 - y_1)^2 + (\widehat y_2 - y_2)^2으로 정의하였다.

이제 대표적으로 w1w_1w2w_2에 대해서 편미분을 구해 규칙성을 살펴보겠다..!

  1. 일단 Chain rule는 뒤에서 연결하여 구하기 때문에 비교적 구하기 쉬운 w2w_2부터 구해보겠다.

Lw2\frac{\partial L}{\partial w_2}을 뒤에서 뒤로 연결하면 Ln2d2w2L \rightarrow n_2 \rightarrow d_2 \rightarrow w_2가 되어 Lw2=Ln2n2d2d2w2\frac{\partial L}{\partial w_2} = \frac{\partial L}{\partial n_2}\cdot\frac{\partial n_2}{\partial d_2}\cdot\frac{\partial d_2}{\partial w_2}가 된다!
이에 대해 하나씩 구해보면 다음과 같다.

  • Ln2\frac{\partial L}{\partial n_2}(y^1y1)2+(y^2y2)2(\widehat y_1 - y_1)^2 + (\widehat y_2 - y_2)^2에서 y^1=n2\widehat y_1 = n_2이기에 2(y^1y1)2(\widehat y_1 - y_1)이 나온다.
  • n2d2\frac{\partial n_2}{\partial d_2}n2=f2(d2)n_2 = f_2(d_2)이기에 그냥 f2(d2)f'_2(d_2)이다.
  • d2w2\frac{\partial d_2}{\partial w_2}d2=w2n1+d_2 = w_2 \cdot n_1 + \cdots (결국 \cdots은 미분하면 상수로 취급되어 0이 됨.) 이므로 n1n_1이다.

결국 Ln2d2w2L \rightarrow n_2 \rightarrow d_2 \rightarrow w_2가 되어 Lw2=Ln2n2d2d2w2=2(y^1y1)f2(d2)n1\frac{\partial L}{\partial w_2} = \frac{\partial L}{\partial n_2}\cdot\frac{\partial n_2}{\partial d_2}\cdot\frac{\partial d_2}{\partial w_2} = 2(\widehat y_1 - y_1)\cdot f'_2(d_2)\cdot n_1이 나온다!

  1. 그 다음으로 w1w_1에 대해 구해보면 다음과 같이 생각할 수 있다.

똑같이 Chain rule로 하니까 Lw1\frac{\partial L}{\partial w_1}Ln2d2n1d1w1L \rightarrow n_2 \rightarrow d_2 \rightarrow n_1 \rightarrow d_1 \rightarrow w_1으로 가서
(w2w_2에 대해 구하는 것이 아니기 때문에 위의 식과 다르게 중간에 w2w_2가 아닌 n1n_1이 들어감.)
Lw2=Ln2n2d2d2n1n1d1d1w1\frac{\partial L}{\partial w_2} = \frac{\partial L}{\partial n_2}\cdot\frac{\partial n_2}{\partial d_2}\cdot\frac{\partial d_2}{\partial n_1}\cdot\frac{\partial n_1}{\partial d_1}\cdot\frac{\partial d_1}{\partial w_1}이 나오겠다고 생각할 수 있다!!

하지만 이는 w1w_1에 대한 답이 될 수 없다.
그 이유는 w1w_1이 바뀌면서 위 신경망의 손실함수에서 위의 경로만 영향을 주면 상관이 없는데, 다른 경로에도 영향을 주기 때문이다!
\rightarrow 결국 편미분을 구하면 그라디언트를 이용해 손실 함수를 업데이트 할텐데 w1w_1이 바뀌었을 때, d1d_1이 바뀌고 이를 통해 n1n_1이 바뀌고 이를 통해 d2d_2가 바뀌고 이를 통해 n2n_2가 바뀌어서 결국 LL이 바뀌게 된다.
여기서 우리가 간과한 점은 바로 w1w_1이 바뀔 때, y^2\widehat y_2의 값도 바뀌어서 이것이 LL에 영향을 준다는 것이다!!!

그림으로 보면 다음과 같다.
위는 우리가 w1w_1을 바꾸었을 때, LL에 영향을 준다고 생각한 경로이고 위의 결과가 실제 w1w_1이 바뀌었을 때, LL에 영향을 주는 경로이다.
그러므로 Lw2=Ln2n2d2d2n1n1d1d1w1\frac{\partial L}{\partial w_2} = \frac{\partial L}{\partial n_2}\cdot\frac{\partial n_2}{\partial d_2}\cdot\frac{\partial d_2}{\partial n_1}\cdot\frac{\partial n_1}{\partial d_1}\cdot\frac{\partial d_1}{\partial w_1}가 아니라
Lw2=Ln2n2d2d2n1n1d1d1w1+\frac{\partial L}{\partial w_2} = \frac{\partial L}{\partial n_2}\cdot\frac{\partial n_2}{\partial d_2}\cdot\frac{\partial d_2}{\partial n_1}\cdot\frac{\partial n_1}{\partial d_1}\cdot\frac{\partial d_1}{\partial w_1} + \cdots가 붙게 된다!!!
위를 통해 편미분을 구할 땐 모든 path를 고려해야 한다는 점을 알 수 있다!

위 사실을 알 수 있지만, 우린 w1w_1w2w_2를 구하며 규칙성을 찾을 것이기 때문에 cdotscdots까지 계산하는 것은 생략하겠다...!

Ln2n2d2d2n1n1d1d1w1\frac{\partial L}{\partial n_2}\cdot\frac{\partial n_2}{\partial d_2}\cdot\frac{\partial d_2}{\partial n_1}\cdot\frac{\partial n_1}{\partial d_1}\cdot\frac{\partial d_1}{\partial w_1} 부분만 하나씩 구해보면 다음과 같다.

  • Ln2\frac{\partial L}{\partial n_2}은 위에서 구한 것으로 2(y^1y1)2(\widehat y_1 - y_1).
  • n2d2\frac{\partial n_2}{\partial d_2}도 위에서 구한 것으로 f2(d2)f'_2(d_2).
  • d2n1\frac{\partial d_2}{\partial n_1}d2=w2n1+d_2 = w_2 \cdot n_1 + \cdots인데, 이번엔 n1n_1에 대해 미분해서 w2w_2이다.
  • n1d1\frac{\partial n_1}{\partial d_1}는 위와 같이 n1=f1(d1)n_1 = f_1(d_1)이기에 f1(d1)f'_1(d_1)이다.
  • d1w1\frac{\partial d_1}{\partial w_1}d1=w1n0+d_1 = w_1 \cdot n_0 + \cdots이기에 n0n_0이다!

그러므로 Ln2n2d2d2n1n1d1d1w1=2(y^1y1)f2(d2)w2f1(d1)n0\frac{\partial L}{\partial n_2}\cdot\frac{\partial n_2}{\partial d_2}\cdot\frac{\partial d_2}{\partial n_1}\cdot\frac{\partial n_1}{\partial d_1}\cdot\frac{\partial d_1}{\partial w_1} = 2(\widehat y_1 - y_1)\cdot f'_2(d_2)\cdot w_2 \cdot f'_1(d_1) \cdot n_0이 나온다!!

이렇게 w1w_1w2w_2를 구하는 방향을 보았다.
w1w_1을 보면 Lw2=Ln2n2d2d2w2=2(y^1y1)f2(d2)n1\frac{\partial L}{\partial w_2} = \frac{\partial L}{\partial n_2}\cdot\frac{\partial n_2}{\partial d_2}\cdot\frac{\partial d_2}{\partial w_2} = 2(\widehat y_1 - y_1)\cdot f'_2(d_2)\cdot n_1의 값이
'손실 함수 ×\times 액티베이션(activation) ×\times N값' 인 것이고,
Ln2n2d2d2n1n1d1d1w1=2(y^1y1)f2(d2)w2f1(d1)n0\frac{\partial L}{\partial n_2}\cdot\frac{\partial n_2}{\partial d_2}\cdot\frac{\partial d_2}{\partial n_1}\cdot\frac{\partial n_1}{\partial d_1}\cdot\frac{\partial d_1}{\partial w_1} = 2(\widehat y_1 - y_1)\cdot f'_2(d_2)\cdot w_2 \cdot f'_1(d_1) \cdot n_0의 값은
'손실 함수 ×\times 액티베이션 ×\times 웨이트 ×\times 액티베이션 ×\times N값' 이 나옴을 알 수 있다.

이에 대해 규칙성이 보이나?
w1w_1의 경우 '손 ×\times×\times' 이고 w2w_2'손 ×\times×\times×\times×\times 앤' 이다!!
결국 파라미터의 편미분 값들은 아래처럼 규칙성을 가짐을 알 수 있다!! (좀 더러워보이긴 하네....)

(손)액웨액웨액웨...액앤 \rightarrow (손실 함수는 규칙성을 안 따를 수도 있음..!)

그렇다면 layer가 세 개일 때( 은닉층이 2개 ) 가장 입력층에 가까운 웨이트의 값은 '(손)액웨액웨액앤' 으로 나오게 됨을 알 수 있다!

[*] forward propagation : 앞으로 가면서 미분.
\rightarrow 우리가 위 그림에 나오는 모든 변수(dd, nn)에 대해 그라디언트를 구하면서 일일히 구해갈 수 없다..!
그러므로 training data를 한 번 진행하면서 위의 ddnn값들을 모두 저장해 놓는다! (forward propagation)
그리고 그라디언트를 구할 때 미분 값을 구한다. (backpropagation)
그리고 우리가 아는 GD나 SGD나 Adam 등등...을 써서 업데이트를 해주면 끝!!

[*] 실제로 우리가 깊은 신경망에서 그라디언트를 구할 때 위처럼 일일히 구하지 않고 코드를 통해 쉽게 구하면 된다. 하지만 코드 안에서 어떻게 계산 되는지는 알아야 하기 때문에 배운 것..!

[*] 바이어스도 Chain rule을 이용해 구해보자!
\rightarrow b1b_1b2b_2를 구한다면 다음과 같다.
b2:Ln2d2b2b_2 : L \rightarrow n_2 \rightarrow d_2 \rightarrow b_2이기에,
Lb2=Ln2n2d2d2b2=2(y^1y1)f2(d2)x\frac{\partial L}{\partial b_2} = \frac{\partial L}{\partial n_2}\cdot\frac{\partial n_2}{\partial d_2}\cdot\frac{\partial d_2}{\partial b_2} = 2(\widehat y_1 - y_1)\cdot f'_2(d_2) \cdot x 이다.
위에서 xx이외의 값은 모두 구했기에 xx만 구하면

  • d2b2\frac{\partial d_2}{\partial b_2}w1n1+b2w_1\cdot n_1 + b_2에서 나왔으므로 xx는 1이다.

결국 b2b_2'손 ×\times×\times 1' 이 되고, b1b_1도 _손 Ln2d2n1d1b1L \rightarrow n_2 \rightarrow d_2 \rightarrow n_1 \rightarrow d_1 \rightarrow b_1이기에 ×\times×\times×\times×\times 1' 임을 알 수 있다. 즉, 바이어스는 앤을 1로 바꾸면 된다!!


행렬 미분을 이용한 backpropagation

우리가 기초 수학 파트에서 행렬 미분하는 것을 배웠고, backpropagation을 행렬을 가지고 미분하면 더 간결하게 나타낼 수 있다!

이번에도 똑같이 위와 같은 예시를 가져오겠다.

그리고 위처럼 구하기 위해 nˉ0, dˉ1, nˉ1, dˉ2, nˉ2\bar n_0, ~\bar d_1, ~\bar n_1, ~\bar d_2, ~\bar n_2를 정의할 것이다. (xˉ\bar xxx 벡터를 의미함.)

  • nˉ0=xˉ\bar n_0 = \bar x
  • dˉ1=nˉ0W1+bˉ1\bar d_1 = \bar n_0 \cdot W_1 + \bar b_1 (W1W_1wˉ1\bar w_1과 같은 의미.)
  • nˉ1=fˉ1(dˉ1)\bar n_1 = \bar f_1(\bar d_1)
  • dˉ2=nˉ1W2+bˉ2\bar d_2 = \bar n_1 \cdot W_2 + \bar b_2
  • nˉ2=fˉ2(dˉ2)\bar n_2 = \bar f_2(\bar d_2)
  • L=(y^1y1)2+(y^2y2)2L = (\widehat y_1 - y_1)^2 + (\widehat y_2 - y_2)^2인데 이는 (nˉ2yˉ)(nˉ2yˉ)T(\bar n_2 - \bar y)(\bar n_2 - \bar y)^T와 같다.
    (nˉ2yˉ)(nˉ2yˉ)T(\bar n_2 - \bar y)(\bar n_2 - \bar y)^T를 전개하면 ([y^1y^2][y1y2])([y^1y^2][y1y2])=[y^1y1y^2y2][y^1y1y^2y2](\begin{bmatrix} \widehat y_1 & \widehat y_2 \end{bmatrix} - \begin{bmatrix} y_1 & y_2 \end{bmatrix})\cdot(\begin{bmatrix} \widehat y_1 \\ \widehat y_2 \end{bmatrix} - \begin{bmatrix} y_1 \\ y_2 \end{bmatrix}) = \begin{bmatrix} \widehat y_1 - y_1& \widehat y_2 - y_2 \end{bmatrix}\cdot\begin{bmatrix} \widehat y_1 - y_1 \\ \widehat y_2 - y_2 \end{bmatrix}이므로 이 값은 (y^1y1)2+(y^2y2)2(\widehat y_1 - y_1)^2 + (\widehat y_2 - y_2)^2가 나오게 된다.
  • W1,W2W_1, W_2의 경우에는 행렬로 나오는데, dˉa\bar d_a 구하는 과정에서 다른 모든 변수가 벡터이므로 벡터라이징을 해서
    Let w1=vec(W1),w2=vec(W2)Let ~w_1 = vec(W_1), w_2 = vec(W_2)로 정의하겠다.

이렇게 우리가 그라디언트를 구하기 위한 준비는 끝났다.
일단 LL에 대한 w2w_2의 편미분부터 구해보면 다음과 같다. (벡터의 연쇄법칙은 앞으로 앞으로!)
Lw2T=dˉ2w2Tnˉ2dˉ2TLnˉ2T\frac{\partial L}{\partial w_2^T} = \frac{\partial \bar d_2}{\partial w_2^T}\cdot \frac{\partial \bar n_2}{\partial \bar d_2^T}\cdot \frac{\partial L}{\partial \bar n_2^T}가 나온다.

그리고 LL에 대한 w1w_1의 편미분은 다음과 같다. (벡터의 연쇄법칙은 앞으로 앞으로!)
Lw1T=dˉ1w2Tnˉ1dˉ1Tdˉ2nˉ1Tnˉ2dˉ2TLnˉ2T\frac{\partial L}{\partial w_1^T} = \frac{\partial \bar d_1}{\partial w_2^T}\cdot\frac{\partial \bar n_1}{\partial \bar d_1^T}\cdot\frac{\partial \bar d_2}{\partial \bar n_1^T}\cdot\frac{\partial \bar n_2}{\partial \bar d_2^T}\cdot\frac{\partial L}{\partial \bar n_2^T}가 나온다.

여기서 중요한 점은 위 두 미분의 path들은 이미 고려된 값들이라는 것이다!

일단 w2w_2에 대한 미분의 식 Lw2T=dˉ2w2Tnˉ2dˉ2TLnˉ2T\frac{\partial L}{\partial w_2^T} = \frac{\partial \bar d_2}{\partial w_2^T}\cdot \frac{\partial \bar n_2}{\partial \bar d_2^T}\cdot \frac{\partial L}{\partial \bar n_2^T}을 계산하면 다음과 같다.

  • Lnˉ2T\frac{\partial L}{\partial \bar n_2^T} : dLdL을 먼저 구하고 여기에 대한 dnˉ2d\bar n_2의 뒤에 곱해진 값이 그라디언트 값이 된다!
    dLdL : 행렬과 벡터에 대한 미분도 우리가 아는 미분 법칙을 쓸 수 있기 때문에 (nˉ2yˉ)(nˉ2yˉ)T(\bar n_2 - \bar y)(\bar n_2 - \bar y)^T를 '앞에꺼 미분 + 뒤에꺼 미분'으로 보면 dnˉ2(nˉ2yˉ)T+(nˉ2yˉ)dnˉ2Td\bar n_2\cdot(\bar n_2-\bar y)^T + (\bar n_2 - \bar y)\cdot d\bar n_2^T이 된다.
    그리고 이 값은 행벡터 \cdot 열벡터 + 행벡터 \cdot 열벡터 이므로 스칼라 값이 나온다. 그렇기 때문에 Transpose해도 같이 똑같으므로 dnˉ2(nˉ2yˉ)T+((nˉ2yˉ)dnˉ2T)Td\bar n_2\cdot(\bar n_2-\bar y)^T + ((\bar n_2 - \bar y)\cdot d\bar n_2^T)^T이 가능하고, 결국 dL=dnˉ22(nˉ2yˉ)TdL = d\bar n_2\cdot2(\bar n_2-\bar y)^T가 된다!
    그리고 그라디언트 값은 dnˉ2d\bar n_2 뒤의 값 2(nˉ2yˉ)T2(\bar n_2-\bar y)^T이다.

  • nˉ2dˉ2T\frac{\partial \bar n_2}{\partial \bar d_2^T} : 이 값은 풀어서 해석하면 이해하기 쉽다!
    이 식은 분자는 가로로 분모는 세로로 벡터가 쌓여있기 때문에 다음과 같다.
    [n21d21n21d22n22d21n22d22]\begin{bmatrix}\frac{\partial n_{21}}{\partial d_{21}} & \frac{\partial n_{21}}{\partial d_{22}} \\ \frac{\partial n_{22}}{\partial d_{21}} & \frac{\partial n_{22}}{\partial d_{22}}\end{bmatrix}
    그런데 위 그림에서 보면 d21d_{21}n22n_{22}은 어느 하나의 값이 바뀌었을 때, 서로에게 영향을 주지 않는다.
    (d22d_{22}n21n_{21}도 마찬가지.)
    그러므로 n21d22,n22d21\frac{\partial n_{21}}{\partial d_{22}}, \frac{\partial n_{22}}{\partial d_{21}}의 값인 해당 그라디언트는 0이 된다.
    그리고 n21d21\frac{\partial n_{21}}{\partial d_{21}}n22d22\frac{\partial n_{22}}{\partial d_{22}}의 경우 위에서 했던 것처럼 fˉ2(dˉ2)\bar f'_2(\bar d_2)가 나오게 된다!
    위의 결과를 총 정리하면 다음과 같다.
    [f21(d21)00f22(d22)]=diag(fˉ2(dˉ2))\begin{bmatrix} f'_{21}(d_{21}) & 0 \\ 0 & f'_{22}(d_{22}) \end{bmatrix} = diag(\bar f'_2(\bar d_{2})) (diagdiag는 대각 행렬을 의미한다.)

  • dˉ2w2T\frac{\partial \bar d_2}{\partial w_2^T} : 이 값을 구하기 위해선 행렬을 행렬로 미분에서 배웠던 지식을 활용해야 한다.
    위처럼 dˉ2w2T\frac{\partial \bar d_2}{\partial w_2^T}dˉ2=nˉ1W2+bˉ2\bar d_2 = \bar n_1 \cdot W_2 + \bar b_2에서 나오는 값이므로 nˉ1TI\bar n_1^T ⊗ I가 된다!

이렇게 구한 값들을 모두 곱하면 Lw2T=(nˉ1TI)diag(fˉ2(dˉ2))2(nˉ2yˉ)T\frac{\partial L}{\partial w_2^T} = (\bar n_1^T ⊗ I) \cdot diag(\bar f'_2(\bar d_{2})) \cdot 2(\bar n_2-\bar y)^T가 나온다!

다음으로 w1w_1에 대해 구해보면 다음과 같다.
Lw1T=dˉ1w2Tnˉ1dˉ1Tdˉ2nˉ1Tnˉ2dˉ2TLnˉ2T\frac{\partial L}{\partial w_1^T} = \frac{\partial \bar d_1}{\partial w_2^T}\cdot\frac{\partial \bar n_1}{\partial \bar d_1^T}\cdot\frac{\partial \bar d_2}{\partial \bar n_1^T}\cdot\frac{\partial \bar n_2}{\partial \bar d_2^T}\cdot\frac{\partial L}{\partial \bar n_2^T}
이를 하나씩 뜯어보겠다.

  • Lnˉ2T\frac{\partial L}{\partial \bar n_2^T} : 위와 똑같이 2(nˉ2yˉ)T2(\bar n_2-\bar y)^T가 나온다.
  • nˉ2dˉ2T\frac{\partial \bar n_2}{\partial \bar d_2^T} : 위와 똑같이 diag(fˉ2(dˉ2))diag(\bar f'_2(\bar d_{2}))가 나온다.
  • dˉ2nˉ1T\frac{\partial \bar d_2}{\partial \bar n_1^T} : nˉ1W2+bˉ2\bar n_1 \cdot W_2 + \bar b_2에서 dd2=dnˉ1W2d \cdot d_2 = d\bar n_1 \cdot W_2가 되고, dnˉ1d\bar n_1 뒤에 곱해진 W2W_2가 해당 값이 된다.
  • nˉ1dˉ1T\frac{\partial \bar n_1}{\partial \bar d_1^T} : 위를 응용하면 diag(fˉ1(dˉ1))diag(\bar f'_1(\bar d_{1}))가 나온다.
  • dˉ1w2T\frac{\partial \bar d_1}{\partial w_2^T} : 위를 응용하면 nˉ0TI\bar n_0^T ⊗ I가 나온다.

총 정리하면 Lw1T=(nˉ0TI)diag(fˉ1(dˉ1))W2diag(fˉ2(dˉ2))2(nˉ2yˉ)T\frac{\partial L}{\partial w_1^T} = (\bar n_0^T ⊗ I) \cdot diag(\bar f'_1(\bar d_{1})) \cdot W_2 \cdot diag(\bar f'_2(\bar d_{2})) \cdot 2(\bar n_2-\bar y)^T가 나오게 된다!!

이를 통해 규칙을 살펴보면, 순서는 반대로 구하게 되지만 '액웨액웨액웨...액앤!'인 것을 알 수 있다!
이처럼 벡터를 가지고 backpropagation을 하게 되면 스칼라를 할 때 다른 경우의 수를 고려해서 더하는 과정을 생각하지 않아도 모든 path에 대해 나타낼 수 있다! \rightarrow 그러므로 더 간결하다고 볼 수 있다.

[*] 스칼라를 행렬로 미분하는 backpropagation
우리는 위에서 W1,W2W_1, W_2를 vectorize해서 풀었다! 그리고 이것은 사실 굳이 따지자면 야매...? 느낌이 강한데.. 벡터라이징 안하고 행렬 그대로 풀 수는 없을까?
\rightarrow Lw1T\frac{\partial L}{\partial w_1^T}가 아니라 LW1\frac{\partial L}{\partial W_1}을 구해보자는 것!
일단, 우리가 위에서 구한 식을 가져오면 다음과 같다.

Lw1T=(nˉ0TI)diag(fˉ1(dˉ1))W2diag(fˉ2(dˉ2))2(nˉ2yˉ)T\frac{\partial L}{\partial w_1^T} = (\bar n_0^T ⊗ I) \cdot diag(\bar f'_1(\bar d_{1})) \cdot W_2 \cdot diag(\bar f'_2(\bar d_{2})) \cdot 2(\bar n_2-\bar y)^T

여기서 (nˉ0TI)(\bar n_0^T ⊗ I)을 제외한 나머지 diag(fˉ1(dˉ1))W2diag(fˉ2(dˉ2))2(nˉ2yˉ)Tdiag(\bar f'_1(\bar d_{1})) \cdot W_2 \cdot diag(\bar f'_2(\bar d_{2})) \cdot 2(\bar n_2-\bar y)^TvˉT\bar v^T로 치환해보겠다. 그러면 Lw1T=(nˉ0TI)vˉT\frac{\partial L}{\partial w_1^T} = (\bar n_0^T ⊗ I) \cdot \bar v^T가 나오게 될 것이다.

그리고 (nˉ0TI)vˉT(\bar n_0^T ⊗ I) \cdot \bar v^T을 실제로 전개를 해보겠다.
이 그림을 보았을 때, nˉ0\bar n_0x1,x2x_1, x_2 이렇게 두 개 나오고, vˉT\bar v_T는 3 X 1의 벡터가 나오게 된다.
그러므로 전개하면 다음과 같게 표현 된다.
[x1000x1000x1x2000x2000x2][v1v2v3]\begin{bmatrix}x_1 & 0 & 0 \\ 0 & x_1 & 0 \\ 0 & 0 & x_1 \\ x_2 & 0 & 0 \\ 0 & x_2 & 0 \\ 0 & 0 & x_2\end{bmatrix}\cdot \begin{bmatrix} v_1 \\ v_2 \\ v_3\end{bmatrix} (vˉT\bar v^T에 맞춰서 nˉ0I\bar n_0 ⊗ I가 확장되어 3 X 6 행렬이 나온다.)

그리고 위를 계산하면 [x1v1x1v2x1v3x2v1x2v2x2v3]\begin{bmatrix} x_1v_1 \\ x_1v_2 \\ x_1v_3 \\ x_2v_1 \\ x_2v_2 \\ x_2v_3\end{bmatrix}가 나오고, 이를 shape 맞춰주면 [x1v1x1v2x1v3x2v1x2v2x2v3]\begin{bmatrix} x_1v_1 & x_1v_2 & x_1v_3 \\ x_2v_1 & x_2v_2 & x_2v_3\end{bmatrix}가 된다!
결국 LW1=[x1v1x1v2x1v3x2v1x2v2x2v3]\frac{\partial L}{\partial W_1} = \begin{bmatrix} x_1v_1 & x_1v_2 & x_1v_3 \\ x_2v_1 & x_2v_2 & x_2v_3\end{bmatrix}인 것이다.

여기서 더 나아가 보면, [x1v1x1v2x1v3x2v1x2v2x2v3]=[x1x2][v1v2v3]\begin{bmatrix} x_1v_1 & x_1v_2 & x_1v_3 \\ x_2v_1 & x_2v_2 & x_2v_3\end{bmatrix} = \begin{bmatrix}x_1 \\ x_2\end{bmatrix} \cdot \begin{bmatrix}v_1 & v_2 & v_3\end{bmatrix}이고, 이는 nˉ0Tvˉ\bar n_0^T\bar v가 된다!!

결국 Lw1T=(nˉ0TI)vˉT\frac{\partial L}{\partial w_1^T} = (\bar n_0^T ⊗ I)\cdot \bar v^T에서 vec1vec^{-1}(벡터라이징 풀기)을 하면 LW1=nˉ0Tvˉ\frac{\partial L}{\partial W_1} = \bar n_0^T\bar v가 되는 것이다.
여기서 vˉT\bar v^T로 치환한 것을 풀면 최종적으로 다음과 같다.

LW1=nˉ0T( diag(fˉ1(dˉ1))W2diag(fˉ2(dˉ2))2(nˉ2yˉ)T )T\frac{\partial L}{\partial W_1} = \bar n_0^T \cdot (~diag(\bar f'_1(\bar d_{1})) \cdot W_2 \cdot diag(\bar f'_2(\bar d_{2})) \cdot 2(\bar n_2-\bar y)^T~)^T

이렇게 행렬 그대로를 가지고 풀이하는 방법도 알아보았다.


요약

  1. MLP는 '행렬' 곱하고 '벡터' 더하고 activation의 반복!
  2. linear activation으로는 아무리 깊게 만들어도 hidden layer 없는 FC layer 이하의 표현력만 가진다!
    \rightarrow 결국 깊은 MLP를 만들기 위해선 non-linear activation이 필요!
  3. non-linear activation의 그라디언트는 backpropagation을 통해 구하는데,
    이는 '액웨액웨액웨...액앤!' 의 구조를 가진다.
    (linear는 직접 편미분을 통해 그라디언트를 구할 수 있으므로 backpropagation 불필요.)
profile
글쓰기에 미쳐보자

0개의 댓글