Softmax-with-Loss 계층
02 Oct 2017 | Loss Function
이번 글에서는 소프트맥스 함수와 크로스엔트로피 손실함수가 합쳐진 ‘Softmax-with-Loss’ 계층에 대해 살펴보도록 하겠습니다. 이 글은 위키피디아와 ‘밑바닥부터 시작하는 딥러닝’, 그리고 이곳을 정리했음을 먼저 밝힙니다. 그럼 시작하겠습니다.
개요
다범주 분류문제를 풀기 위한 딥러닝 모델 말단엔 소프트맥스 함수가 적용됩니다. 소프트맥스 함수는 범주 수만큼의 차원을 갖는 입력벡터를 받아서 확률(요소의 합이 1)로 변환해 줍니다. 이후 손실 함수로는 크로스엔트로피(cross entropy)가 쓰이는데요. 크로스엔트로피는 소프트맥스 확률의 분포와 정답 분포와의 차이를 나타냅니다. 이를 기본으로 해서 손실(오차)을 최소화하는 방향으로 모델의 각 파라메터를 업데이트하는 과정이 바로 딥러닝 모델의 학습이 되겠습니다.
그런데 딥러닝 모델 학습시 손실에서 나오는 그래디언트를 계산하는 것이 제1관문이 됩니다. 그도 그럴 것이 체인룰(chain rule)에 의해 이 그래디언트에 각 계산 과정에서의 로컬 그래디언트가 끊임없이 곱해져 오차가 역전파(backpropagation)되기 때문입니다. 이렇게 손실(오차)에 대한 각 파라메터의 그래디언트를 구하게 되면 그래디언트 디센트(gradient descent) 기법으로 파라메터를 업데이트해 손실을 줄여 나가게 됩니다. 딥러닝 모델의 손실함수로 왜 크로스엔트로피가 쓰이는지에 대해선 이곳을, 그래디언트 디센트(gradient descent)와 관련해서는 이곳을, 오차 역전파와 관련해서는 이곳을 참고하시면 좋을 것 같습니다.
이번 글에서는 딥러닝 역전파의 첫 단추인 Softmax-with-Loss 계층을 살펴보도록 하겠습니다. 이 글에서는 별도 표시가 없는 한 스칼라를 기준으로 표기하였음을 먼저 밝힙니다.
순전파
분류해야 할 범주 수가 $n$이고 소프트맥스 함수의 $i$번째 입력값을 $a_i$, $i$번째 출력값을 $p_i$라고 할 때 소프트맥스 함수는 다음과 같이 정의됩니다. 소프트맥스 함수의 입력 및 출력벡터의 차원수는 $n$이 됩니다.
[{ p }{ i }=\frac { exp\left( { a }{ i } \right) }{ \sum { k }^{ }{ exp\left( { a }{ k } \right) } }]
딥러닝 모델의 손실(오차) $L$은 다음과 같이 크로스엔트로피로 정의됩니다. 스칼라 값입니다. 아래에서 $y_j$는 정답 벡터의 $j$번째 요소라는 뜻입니다. 예컨대 3범주 분류를 하는 문제에서 어떤 데이터의 정답이 첫번째 범주라면 $y=[1,0,0]$이 되고, $y_1=1$, 나머지 $y_2, y_3$은 0이 됩니다. $p_j$는 소프트맥스 함수의 $j$번째 출력값입니다.
[L=-\sum { j }^{ }{ { y }{ j }\log { { p }_{ j } } }]
미분 기초
역전파를 본격적으로 살펴보기에 앞서 몇 가지 미분 공식을 정리하고 넘어가겠습니다.
[\begin{align}
y=exp\left( x \right) &\leftrightharpoons \frac { \partial y }{ \partial x } =exp\left( x \right) \ y=\log { x } &\leftrightharpoons \frac { \partial y }{ \partial x } =\frac { 1 }{ x } \ y=\frac { f\left( x \right) }{ g\left( x \right) }& \leftrightharpoons \frac { \partial y }{ \partial x } =\frac { f^{ ‘ }\left( x \right) g\left( x \right) -f\left( x \right) g^{ ‘ }\left( x \right) }{ { g\left( x \right) }^{ 2 } }
\end{align}]
소프트맥스 함수의 그래디언트
소프트맥스 함수의 $i$번째 출력값 $p_i$, $j$번째 출력값 $p_j$에 대한 Softmax-with-Loss 계층의 $i$번째 입력값 $a_i$의 그래디언트는 각각 다음과 같습니다. 우선 $i=j$인 경우부터 살펴보겠습니다.
[\frac { \partial { p }{ i } }{ \partial { a }{ i } } =\frac { \partial \frac { exp\left( { a }{ i } \right) }{ \sum _{ k }^{ }{ exp\left( { a }{ k } \right) } } }{ \partial { a }_{ i } }]
$p_i$는 분수형 함수이므로 분자 $exp(a_i)$를 $f$, 분모 $Σ_kexp(a_k)$를 $g$로 보고 위 미분공식을 활용해 다시 적으면 다음과 같습니다. 여기에서 $Σ_kexp(a_k)$를 $a_i$에 대해 편미분한 결과는 $exp(a_i)$를 제외한 나머지 항은 상수 취급돼 소거되므로 $g’$은 $exp(a_i)$가 됩니다.
[\begin{align}
\frac { \partial { p }_{ i } }{ \partial { a }_{ i } } &=\frac { exp\left( { a }_{ i } \right) \sum _{ k }^{ }{ exp\left( { a }_{ k } \right) } -exp\left( { a }_{ i } \right) exp\left( { a }_{ i } \right) }{ { \left( \sum _{ k }^{ }{ exp\left( { a }_{ k } \right) } \right) }^{ 2 } } \ &=\frac { exp\left( { a }_{ i } \right) \left[ \sum _{ k }^{ }{ \left{ exp\left( { a }_{ k } \right) \right} } -exp\left( { a }_{ i } \right) \right] }{ { \left( \sum _{ k }^{ }{ exp\left( { a }_{ k } \right) } \right) }^{ 2 } } \ &=\frac { exp\left( { a }_{ i } \right) }{ \sum _{ k }^{ }{ exp\left( { a }_{ k } \right) } } \frac { \sum _{ k }^{ }{ \left{ exp\left( { a }_{ k } \right) \right} } -exp\left( { a }_{ i } \right) }{ \sum _{ k }^{ }{ exp\left( { a }_{ k } \right) } } \ &=\frac { exp\left( { a }_{ i } \right) }{ \sum _{ k }^{ }{ exp\left( { a }_{ k } \right) } } \left( 1-\frac { exp\left( { a }_{ i } \right) }{ \sum _{ k }^{ }{ exp\left( { a }_{ k } \right) } } \right) \ \&={ p }_{ i }\left( 1-{ p }_{ i } \right)
\end{align}]
다음은 $i≠j$인 경우입니다. $p_i$는 분수형 함수이므로 분자 $exp(a_i)$를 $f$, 분모 $Σ_kexp(a_k)$를 $g$로 보고 미분공식을 활용해 적으면 다음과 같습니다. 그런데 $exp(a_i)$를 $a_j$에 대해 편미분하면 0이 되므로 $f’g$ 역시 0이 됩니다. 아울러 여기에서 $Σ_kexp(a_k)$를 $a_j$에 대해 편미분한 결과는 $exp(a_j)$를 제외한 나머지 항은 상수 취급돼 소거되므로 $g’$은 $exp(a_j)$가 됩니다.
[\begin{align}
\frac { \partial { p }_{ i } }{ \partial { a }_{ j } } &=\frac { 0-exp\left( { a }_{ i } \right) exp\left( { a }_{ j } \right) }{ { \left( \sum _{ k }^{ }{ exp\left( { a }_{ k } \right) } \right) }^{ 2 } } \ &=-\frac { exp\left( { a }_{ i } \right) }{ \sum _{ k }^{ }{ exp\left( { a }_{ k } \right) } } \frac { exp\left( { a }_{ j } \right) }{ \sum _{ k }^{ }{ exp\left( { a }_{ k } \right) } } \ \ &=-{ p }_{ i }{ p }_{ j }
\end{align}]
역전파
손실에 대한 Softmax-with-Loss 계층의 $i$번째 입력값 $a_i$의 그래디언트는 다음과 같이 유도됩니다.
[\begin{align}
\frac { \partial L }{ \partial { a }_{ i } } &=\frac { \partial \left( -\sum _{ j }^{ }{ { y }_{ j }\log { { p }_{ j } } } \right) }{ \partial { a }_{ i } } \ &=-\sum _{ j }^{ }{ { y }_{ j } } \frac { \partial \log { { p }_{ j } } }{ \partial { a }_{ i } } \ &=-\sum _{ j }^{ }{ { y }_{ j } } \frac { 1 }{ { p }_{ j } } \frac { \partial { p }_{ j } }{ \partial { a }_{ i } }
\end{align}]
소프트맥스 함수의 그래디언트($\partial{p_j}/\partial{a_i}$)는 $i$와 $j$가 같을 때와 다를 때 각기 상이한 값이 도출되므로 위 식의 시그마 부분에서 $i$번째 입력값에 해당하는 요소를 분리해 두 개의 항으로 표현하면 다음과 같습니다. 여기에서 소프트맥스 확률의 합 $Σ_jy_j$는 1이 됩니다.
[\begin{align}
-\sum _{ j }^{ }{ { y }_{ j } } \frac { 1 }{ { p }_{ j } } \frac { \partial { p }_{ j } }{ \partial { a }_{ i } } &=-\frac { { y }_{ i } }{ { p }_{ i } } { p }_{ i }\left( 1-{ p }_{ i } \right) -\sum _{ i\neq j }^{ }{ \frac { { y }_{ j } }{ { p }_{ j } } } \left( -{ p }_{ i }{ p }_{ j } \right) \ &=-{ y }_{ i }+{ y }_{ i }{ p }_{ i }+\sum _{ i\neq j }^{ }{ { y }_{ j }{ p }_{ i } } \ &=-{ y }_{ i }+\sum _{ j }^{ }{ { y }_{ j }{ p }_{ i } } \ &=-{ y }_{ i }+{ p }_{ i }\sum _{ j }^{ }{ { y }_{ j } } \ \&={ p }_{ i }-{ y }_{ i }
\end{align}]
코드 구현
요컨대 Softmax-with-Loss 노드의 그래디언트를 구하려면 입력 벡터에 소프트맥스를 취한 뒤, 정답 레이블에 해당하는 요소값만 1을 빼주면 된다는 얘기입니다. 이를 파이썬 코드로 구현하면 아래와 같습니다.
import numpy as np
p = np.exp(a) / np.sum(np.exp(a)) # softmax 확률 계산
da = np.copy(p)
da[target] -= 1 # target=정답 인덱스
수식은 복잡하게 전개됐지만 그래디언트를 구하기가 매우 쉽고, 이렇게 구한 그래디언트 또한 0으로 죽는 일이 많지 않아서 소프트맥스+크로스 엔트로피가 많이들 쓰이는 것 같습니다.
이번 글에서는 소프트맥스 함수와 크로스엔트로피 손실함수가 합쳐진 ‘Softmax-with-Loss’ 계층에 대해 살펴보도록 하겠습니다. 이 글은 위키피디아와 ‘밑바닥부터 시작하는 딥러닝’, 그리고 이곳을 정리했음을 먼저 밝힙니다. 그럼 시작하겠습니다.
개요
다범주 분류문제를 풀기 위한 딥러닝 모델 말단엔 소프트맥스 함수가 적용됩니다. 소프트맥스 함수는 범주 수만큼의 차원을 갖는 입력벡터를 받아서 확률(요소의 합이 1)로 변환해 줍니다. 이후 손실 함수로는 크로스엔트로피(cross entropy)가 쓰이는데요. 크로스엔트로피는 소프트맥스 확률의 분포와 정답 분포와의 차이를 나타냅니다. 이를 기본으로 해서 손실(오차)을 최소화하는 방향으로 모델의 각 파라메터를 업데이트하는 과정이 바로 딥러닝 모델의 학습이 되겠습니다.
그런데 딥러닝 모델 학습시 손실에서 나오는 그래디언트를 계산하는 것이 제1관문이 됩니다. 그도 그럴 것이 체인룰(chain rule)에 의해 이 그래디언트에 각 계산 과정에서의 로컬 그래디언트가 끊임없이 곱해져 오차가 역전파(backpropagation)되기 때문입니다. 이렇게 손실(오차)에 대한 각 파라메터의 그래디언트를 구하게 되면 그래디언트 디센트(gradient descent) 기법으로 파라메터를 업데이트해 손실을 줄여 나가게 됩니다. 딥러닝 모델의 손실함수로 왜 크로스엔트로피가 쓰이는지에 대해선 이곳을, 그래디언트 디센트(gradient descent)와 관련해서는 이곳을, 오차 역전파와 관련해서는 이곳을 참고하시면 좋을 것 같습니다.
이번 글에서는 딥러닝 역전파의 첫 단추인 Softmax-with-Loss 계층을 살펴보도록 하겠습니다. 이 글에서는 별도 표시가 없는 한 스칼라를 기준으로 표기하였음을 먼저 밝힙니다.
순전파
분류해야 할 범주 수가 $n$이고 소프트맥스 함수의 $i$번째 입력값을 $a_i$, $i$번째 출력값을 $p_i$라고 할 때 소프트맥스 함수는 다음과 같이 정의됩니다. 소프트맥스 함수의 입력 및 출력벡터의 차원수는 $n$이 됩니다.
[{ p }{ i }=\frac { exp\left( { a }{ i } \right) }{ \sum { k }^{ }{ exp\left( { a }{ k } \right) } }]
딥러닝 모델의 손실(오차) $L$은 다음과 같이 크로스엔트로피로 정의됩니다. 스칼라 값입니다. 아래에서 $y_j$는 정답 벡터의 $j$번째 요소라는 뜻입니다. 예컨대 3범주 분류를 하는 문제에서 어떤 데이터의 정답이 첫번째 범주라면 $y=[1,0,0]$이 되고, $y_1=1$, 나머지 $y_2, y_3$은 0이 됩니다. $p_j$는 소프트맥스 함수의 $j$번째 출력값입니다.
[L=-\sum { j }^{ }{ { y }{ j }\log { { p }_{ j } } }]
미분 기초
역전파를 본격적으로 살펴보기에 앞서 몇 가지 미분 공식을 정리하고 넘어가겠습니다.
[\begin{align} y=exp\left( x \right) &\leftrightharpoons \frac { \partial y }{ \partial x } =exp\left( x \right) \ y=\log { x } &\leftrightharpoons \frac { \partial y }{ \partial x } =\frac { 1 }{ x } \ y=\frac { f\left( x \right) }{ g\left( x \right) }& \leftrightharpoons \frac { \partial y }{ \partial x } =\frac { f^{ ‘ }\left( x \right) g\left( x \right) -f\left( x \right) g^{ ‘ }\left( x \right) }{ { g\left( x \right) }^{ 2 } } \end{align}]
소프트맥스 함수의 그래디언트
소프트맥스 함수의 $i$번째 출력값 $p_i$, $j$번째 출력값 $p_j$에 대한 Softmax-with-Loss 계층의 $i$번째 입력값 $a_i$의 그래디언트는 각각 다음과 같습니다. 우선 $i=j$인 경우부터 살펴보겠습니다.
[\frac { \partial { p }{ i } }{ \partial { a }{ i } } =\frac { \partial \frac { exp\left( { a }{ i } \right) }{ \sum _{ k }^{ }{ exp\left( { a }{ k } \right) } } }{ \partial { a }_{ i } }]
$p_i$는 분수형 함수이므로 분자 $exp(a_i)$를 $f$, 분모 $Σ_kexp(a_k)$를 $g$로 보고 위 미분공식을 활용해 다시 적으면 다음과 같습니다. 여기에서 $Σ_kexp(a_k)$를 $a_i$에 대해 편미분한 결과는 $exp(a_i)$를 제외한 나머지 항은 상수 취급돼 소거되므로 $g’$은 $exp(a_i)$가 됩니다.
[\begin{align} \frac { \partial { p }_{ i } }{ \partial { a }_{ i } } &=\frac { exp\left( { a }_{ i } \right) \sum _{ k }^{ }{ exp\left( { a }_{ k } \right) } -exp\left( { a }_{ i } \right) exp\left( { a }_{ i } \right) }{ { \left( \sum _{ k }^{ }{ exp\left( { a }_{ k } \right) } \right) }^{ 2 } } \ &=\frac { exp\left( { a }_{ i } \right) \left[ \sum _{ k }^{ }{ \left{ exp\left( { a }_{ k } \right) \right} } -exp\left( { a }_{ i } \right) \right] }{ { \left( \sum _{ k }^{ }{ exp\left( { a }_{ k } \right) } \right) }^{ 2 } } \ &=\frac { exp\left( { a }_{ i } \right) }{ \sum _{ k }^{ }{ exp\left( { a }_{ k } \right) } } \frac { \sum _{ k }^{ }{ \left{ exp\left( { a }_{ k } \right) \right} } -exp\left( { a }_{ i } \right) }{ \sum _{ k }^{ }{ exp\left( { a }_{ k } \right) } } \ &=\frac { exp\left( { a }_{ i } \right) }{ \sum _{ k }^{ }{ exp\left( { a }_{ k } \right) } } \left( 1-\frac { exp\left( { a }_{ i } \right) }{ \sum _{ k }^{ }{ exp\left( { a }_{ k } \right) } } \right) \ \&={ p }_{ i }\left( 1-{ p }_{ i } \right) \end{align}]
다음은 $i≠j$인 경우입니다. $p_i$는 분수형 함수이므로 분자 $exp(a_i)$를 $f$, 분모 $Σ_kexp(a_k)$를 $g$로 보고 미분공식을 활용해 적으면 다음과 같습니다. 그런데 $exp(a_i)$를 $a_j$에 대해 편미분하면 0이 되므로 $f’g$ 역시 0이 됩니다. 아울러 여기에서 $Σ_kexp(a_k)$를 $a_j$에 대해 편미분한 결과는 $exp(a_j)$를 제외한 나머지 항은 상수 취급돼 소거되므로 $g’$은 $exp(a_j)$가 됩니다.
[\begin{align} \frac { \partial { p }_{ i } }{ \partial { a }_{ j } } &=\frac { 0-exp\left( { a }_{ i } \right) exp\left( { a }_{ j } \right) }{ { \left( \sum _{ k }^{ }{ exp\left( { a }_{ k } \right) } \right) }^{ 2 } } \ &=-\frac { exp\left( { a }_{ i } \right) }{ \sum _{ k }^{ }{ exp\left( { a }_{ k } \right) } } \frac { exp\left( { a }_{ j } \right) }{ \sum _{ k }^{ }{ exp\left( { a }_{ k } \right) } } \ \ &=-{ p }_{ i }{ p }_{ j } \end{align}]
역전파
손실에 대한 Softmax-with-Loss 계층의 $i$번째 입력값 $a_i$의 그래디언트는 다음과 같이 유도됩니다.
[\begin{align} \frac { \partial L }{ \partial { a }_{ i } } &=\frac { \partial \left( -\sum _{ j }^{ }{ { y }_{ j }\log { { p }_{ j } } } \right) }{ \partial { a }_{ i } } \ &=-\sum _{ j }^{ }{ { y }_{ j } } \frac { \partial \log { { p }_{ j } } }{ \partial { a }_{ i } } \ &=-\sum _{ j }^{ }{ { y }_{ j } } \frac { 1 }{ { p }_{ j } } \frac { \partial { p }_{ j } }{ \partial { a }_{ i } } \end{align}]
소프트맥스 함수의 그래디언트($\partial{p_j}/\partial{a_i}$)는 $i$와 $j$가 같을 때와 다를 때 각기 상이한 값이 도출되므로 위 식의 시그마 부분에서 $i$번째 입력값에 해당하는 요소를 분리해 두 개의 항으로 표현하면 다음과 같습니다. 여기에서 소프트맥스 확률의 합 $Σ_jy_j$는 1이 됩니다.
[\begin{align} -\sum _{ j }^{ }{ { y }_{ j } } \frac { 1 }{ { p }_{ j } } \frac { \partial { p }_{ j } }{ \partial { a }_{ i } } &=-\frac { { y }_{ i } }{ { p }_{ i } } { p }_{ i }\left( 1-{ p }_{ i } \right) -\sum _{ i\neq j }^{ }{ \frac { { y }_{ j } }{ { p }_{ j } } } \left( -{ p }_{ i }{ p }_{ j } \right) \ &=-{ y }_{ i }+{ y }_{ i }{ p }_{ i }+\sum _{ i\neq j }^{ }{ { y }_{ j }{ p }_{ i } } \ &=-{ y }_{ i }+\sum _{ j }^{ }{ { y }_{ j }{ p }_{ i } } \ &=-{ y }_{ i }+{ p }_{ i }\sum _{ j }^{ }{ { y }_{ j } } \ \&={ p }_{ i }-{ y }_{ i } \end{align}]
코드 구현
요컨대 Softmax-with-Loss 노드의 그래디언트를 구하려면 입력 벡터에 소프트맥스를 취한 뒤, 정답 레이블에 해당하는 요소값만 1을 빼주면 된다는 얘기입니다. 이를 파이썬 코드로 구현하면 아래와 같습니다.
import numpy as np
p = np.exp(a) / np.sum(np.exp(a)) # softmax 확률 계산
da = np.copy(p)
da[target] -= 1 # target=정답 인덱스
수식은 복잡하게 전개됐지만 그래디언트를 구하기가 매우 쉽고, 이렇게 구한 그래디언트 또한 0으로 죽는 일이 많지 않아서 소프트맥스+크로스 엔트로피가 많이들 쓰이는 것 같습니다.