반응형

/**

날짜 : 2017.01.30

밑바닥부터 시작하는 딥러닝(한빛미디어) 참고

Softmax 구현 및 성질

*/


Softmax 함수는 3-class 이상의 classification을 목적으로 하는 딥러닝 모델의 출력층에서 일반적으로 쓰이는 활성화 함수(activation function)이다. Softmax 함수는 아래와 같이 나타낼 수 있다.




이를 Latex 표기법으로 나타내면 아래와 같다. (Latex는 라텍스라고 읽으면 안되고 레이택으로 읽는다..)


\begin{align}

y_k = {exp(a_k)}/{\sum_{i=1}^{n}(exp(a_i))}

\end{align}


(위 코드를 Jupyter notebook에서 markdown으로 선택하여 입력 후 run을 누르면 위와 같은 수식이 출력되는 것을 확인할 수 있다. Jupyter notebook에서는 Latex 코드를 수식으로 변환하는 기능을 지원한다.)


""" Softmax 구현 """
import numpy as np

def softmax(a) :
    exp_a = np.exp(a)
    sum_exp_a = np.sum(exp_a)
    y = exp_a / sum_exp_a
    
    return y

a = np.array([0.3, 2.9, 4.0])

print softmax(a) # softmax 결과값 출력
print sum(softmax(a)) # softmax 결과값들의 합은 1이 된다.


Softmax 수식을 그대로 파이썬 코드로 옮기면 위와 같다. 결과가 잘 출력되는 것을 확인할 수 있다. 하지만 Softmax는 수식 안에 e의 지수를 포함하고 있는데, 지수함수는 지수가 커질 수록 매우 큰 폭으로 증가하기 때문에 overflow가 발생하기 쉽다. 아래 코드를 보면 overflow가 발생하는 예와 이를 어떻게 해결하는지를 볼 수 있다.


""" Softmax는 Overflow에 취약하다.
    수식에 e^x 들어가기 때문에 Overflow 범위를 넘어설 수 있다. 
    이를 해결하기 위해서는 Softmax의 성질을 이용한다.
"""
def new_softmax(a) : 
    c = np.max(a) # 최댓값
    exp_a = np.exp(a-c) # 각각의 원소에 최댓값을 뺀 값에 exp를 취한다. (이를 통해 overflow 방지)
    sum_exp_a = np.sum(exp_a)
    y = exp_a / sum_exp_a
    return y
    
a = np.array([1010, 1000, 990]) 
print softmax(a) # overflow
print new_softmax(a) # 정상적으로 출력

# 또한 softmax와 new_softmax 의 결과값을 같다.
test = np.array([1,3,6])
print 'softmax', softmax(test) # [ 0.00637746  0.04712342  0.94649912]
print 'new_softmax', new_softmax(test) # [ 0.00637746  0.04712342  0.94649912]


Softmax를 구현할 때 overflow 가 자주 발생하는 문제를 해결하기 위해 위와 같은 새로운 softmax 함수인 new_softmax를 정의한다. 이는 원소에 어떠한 수를 더하여 exp를 취하더라도 결과 값이 같다는 softmax의 성질을 이용한 것인데, 


위의 등식에서 C를 '원소들의 최댓값의 음수'로 한 것이다. 예를 들어 a = [1010,1000,990] a+c = [0,-10,-20] 이 된다. 이 때, a와 a+c의 softmax 결과값은 같다.



반응형