심층 학습/활성화 함수들

1. 소개



간단히 말하면, 신경망의 풍부한 표현력은 간단한 활성화 함수를 중첩하여 깊은 계층 구조로 만들어 줍니다.

이번에는 신경망에서 사용되는 활성화 함수에 대해 공부한 것을 정리합니다.

2.Sigmoid 함수


# シグモイド関数
def sigmoid(x):
    return 1 / (1 + np.exp(-x))   

# シグモイド関数の微分
def sigmoid_d(x):
    return (1 / (1 + np.exp(-x))) * ( 1- (1 / (1 + np.exp(-x))))

# グラフ表示
x = np.arange(-5.0, 5.0, 0.01)
plt.plot(x, sigmoid(x), label='sigmoid')
plt.plot(x, sigmoid_d(x), label='sigmoid_d')
plt.ylim(-1.1, 1.1)  
plt.legend()  
plt.grid()
plt.show()



sigmoid 함수:
sigmoid(x) = \frac{1}{1+e^{-x}}

sigmoid 함수의 미분 :
sigmoid'(x) = \frac{1}{1+e^{-x}} * ( 1 - \frac{1}{1+e^{-x}})

Sigmoid 함수는, 옛날부터 신경망의 교과서에는 반드시 실려 있어, 미분해도 거의 형태가 변함없이 아름다운 형태를 하고 있습니다만, 최근에는 활성화 함수로서는 거의 사용되고 있지 않습니다. 

그 이유는 그래프에서 알 수 있듯이 x의 값이 커지면 y가 1에 달라붙어 움직이지 않게 되기 때문입니다. 신경망은 y를 미분하여 기울기를 구하여 가중치 파라미터를 최적화하기 때문에, 미분이 거의 0이 되어 버리면 중대히 최적해에 접근할 수 없다(경사 소실)라는 문제점을 가지고 있기 때문입니다.

Sigmoid 함수의 미분 유도
sigmoid'(x) = ((1 + e^{-x})^{-1})'\\
合成関数の微分により、u = 1+e^{-x}と置くと、\frac{dy}{dx}=\frac{dy}{du}\frac{du}{dx} なので\\
= -(1 + e^{-x})^{-2} * (1+e^{-x})'\\
= -\frac{1}{(1+e^{-x})^2} * -e^{-x}\\
= \frac{1}{1+e^{-x}} * \frac{e^{-x}}{1+e^{-x}} \\
= \frac{1}{1+e^{-x}} * (\frac{1+e^{-x}}{1+e^{-x}} - \frac{1}{1+e^{-x}})\\
= \frac{1}{1+e^{-x}} * ( 1 - \frac{1}{1+e^{-x}})

3.tanh 함수


# Tanh関数
def tanh(x):
    return (np.exp(x) -np.exp(-x)) / (np.exp(x) + np.exp(-x))

# Tanh関数の微分
def tanh_d(x):
    return 1- ( (np.exp(x) -np.exp(-x)) / (np.exp(x) + np.exp(-x)) )**2

# グラフ表示
x = np.arange(-5.0, 5.0, 0.01)
plt.plot(x, tanh(x), label='tanh')
plt.plot(x, tanh_d(x), label='tanh_d')
plt.ylim(-1.1, 1.1)  
plt.legend()  
plt.grid()
plt.show()


Tanh 함수:
tanh(x) = \frac{e^x-e^{-x}}{e^x+e^{-x}}

Tanh 함수의 미분:
tanh(x) = \frac{4}{(e^x + e^{-x})^2}\\

Tanh 함수는, Sigmoid 함수의 개량판(미분했을 때의 최대치가 Sigmoid보다 높다)로서 사용되고 있었던 것입니다만, x가 커지면 y가 1에 붙어 붙는 근본적인 문제점은 개선되고 있지 않습니다 .

Tanh 함수의 미분 도출
商の微分公式 (\frac{f(x)}{g(x)})' = \frac{f'(x)*g(x) - f(x)*g'(x)}{g(x)^2} を使って\\
tanh'(x) = \frac{(e^x+e^{-x})^2 - (e^x - e^{-x})^2}{(e^x + e^{-x})^2}\\
= \frac{e^{2x}+2+e^{-2x} - (e^{2x} -2 + e^{-2x})}{(e^x + e^{-x})^2}\\
= \frac{4}{(e^x + e^{-x})^2}\\


또는,
tanh'(x) = \frac{(e^x+e^{-x})^2 - (e^x - e^{-x})^2}{(e^x + e^{-x})^2}\\
= 1 - \frac{(e^x - e^{-x})^2}{(e^x + e^{-x})^2}\\
= 1 - (\frac{e^x - e^{-x}}{e^x + e^{-x}})^2\\

4.ReLU 함수


# ReLU関数
def relu(x):
    return np.maximum(0, x)

# ReLU関数の微分
def relu_d(x):
    return np.array(x > 0, dtype=np.int)

# グラフ表示
x = np.arange(-5.0, 5.0, 0.01)
plt.plot(x, relu(x), label='relu')
plt.plot(x, relu_d(x), label='relu_d')
plt.ylim(-1.1, 1.1)  
plt.legend()  
plt.grid()
plt.show()



ReLU 함수:


ReLU 함수의 미분:


"Sigmoid 함수의 근본적인 문제점을 없애기 위해 태어난 것이 ReLU 함수입니다. x가 커져도 y도 비례하여 커져 항상 미분하면 상수항이 남습니다. 무엇인가, 지금 들으면 당연한 것 같은 생각이 듭니다만, 이것이 사용되어 나온 것은, 무려 2012년경부터입니다.

동대의 마츠오 유타카 선생님은, Sigmoid 함수는 심플하고 미분해도 거의 형태가 변하지 않고, 이공학자에게 있어서 아름다운 함수였다. 한편 ReLU는 괄호가 나쁘고, 게다가(0,0)로 미분 불가한 점이 있기 때문에, 아무도 사용하고 싶지 않았다.

옛날 딥 러닝은 잘 움직일 수 없었기 때문에, 여러가지 식으로서 아름다운 Sigmoid 함수를 사용하고 있었다. 그러나, 움직일 수 있게 되고 나서는 여러가지 것을 시도하는 사람이 나오고, 그러한 가운데에서 사용되게 되어 온 것이 ReLU라고 말하고 있습니다.

5.Leaky ReLU 함수


# Leaky ReLU関数
def leaky_relu(x):
    return np.where(x > 0, x , 0.01 * x)

# Leaky ReLU関数の微分
def leaky_relu_d(x):
    return np.where(x>0,1,0.01)

# グラフ表示
x = np.arange(-5.0, 5.0, 0.01)
plt.plot(x, leaky_relu(x), label='leaky_relu')
plt.plot(x, leaky_relu_d(x), label='leaky_relu_d')
plt.ylim(-1.1, 1.1)  
plt.legend()  
plt.grid()
plt.show()



Leaky ReLU 함수:

Leaky ReLU 함수의 미분:


Leaky ReLU 함수는, ReLU 함수로부터 파생한 것으로, x가 0 이하에서도 0.01x로 기울기를 가집니다. ReLU 함수보다 더욱 최적화가 진행될 것으로 기대되었지만 ReLU 함수보다 최적화가 잘 가는 경우는 상당히 한정적인 것 같습니다.

6. 활성화 함수의 성능 차이를 실감해 본다



마지막으로, 활성화 함수에 의해, 얼마나 최적화 성능이 다른지 실감해 봅시다.

TensorFlow PlayGround 라는 브라우저로 신경망의 시뮬레이션을 할 수 있는 사이트를 들여다 봅니다.


이런 3개의 뉴런이 2층의 뉴럴 네트워크를 설정해, 빨간색 프레임의 Activation(활성화 함수)을 전환해, 수렴 시간을 체크해 보겠습니다.

확률적인 문제도 있어, 어느 정도 불균형은 나오지만, 수렴 시간은 대체로, Tanh가 Sigmoid의 10배 정도 빠르고, ReLU는 Tanh의 한층 더 2배 정도 빠릅니다.

좋은 웹페이지 즐겨찾기