Open In Colab

import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
import seaborn as sns

기초 활성화 함수

x = np.arange(-10, 10, 0.1)
y = 1 / (1 + np.exp(-x))

plt.plot(x,y)
plt.axhline(0.5,linewidth=0.5)
plt.show()
<matplotlib.lines.Line2D at 0x7fe0c8707a50>

시그모이드 함수 형태입니다. 입력값에 따라 값을 0~1로 변환해 주기 때문에 출력층에 사용하기 좋은 함수입니다.

단조 증가함수이며 비선형함수라는 점은 활성화 함수로 사용하는데 유리합니다.

하지만 최대 기울기는 0.25로 기울기가 상대적으로 평탄해 역방향 계산시 신경망 학습이 늦어지는 단점이 있습니다.

x = np.arange(-10, 10, 0.1)
y = (np.exp(x) - np.exp(-x)) / (np.exp(x) + np.exp(-x))

plt.plot(x,y)
plt.axhline(0,linewidth=0.5)
plt.show()

하이퍼탄젠트 함수입니다. 시그모이드 함수와 전반적으로 비슷한 형태이고, 출력값이 -1~1로 차이가 있습니다.

단조 증가함수이며 비선형함수라는 점이 시그모이드 함수와 비슷한 특징을 가집니다.

그리고 기울기의 최댓값이 1이고 값의 평균이 0으로, 시그모이드 함수보다 큰 장점이 있습니다.

하지만 입력값의 절대값이 2를 넘어가는 순간 출력값이 수렴하는 모습을 볼 수 있습니다. (시그모이드 또한 조금 늦게 수렴하지만 비슷합니다.)

이 경우 기울기가 0에 가까워지게 되고 그레이언트 소실 문제가 생깁니다.

쉽게 말해서 기울기가 O에 가깝기 때문에 학습이 진행이 안되는 현상이 발생합니다. 이를 방지하기 위해 RELU함수를 사용합니다.

x = np.arange(-10, 10, 0.1)
y = np.where(x > 0, x, 0)

plt.plot(x,y)
plt.axhline(0,linewidth=0.5)
plt.show()

렐루 함수는 입력값이 0보다 크면 그대로, 0보다 작으면 0을 출력하는 함수입니다.

입력값에 따라 on/off 해준다는 관점으로 볼 수 있고, 기울기도 1로 잘 유지가 됩니다.

Gradient Vanishing 문제(layer가 늘어날때 값이 사라지는 현상)가 해결되기 때문에, 가장 기본적인 활성화 함수로 사용합니다.

하지만 0을 기준으로 명확하게 성질이 갈린다는 것은 단점입니다. 이를 극복하기 위해 leaky RELU 함수를 사용합니다.

렐루 함수 변형

x = np.arange(-10, 5, 0.1)
y = np.where(x > 0, x, 0.01 * x)

plt.plot(x,y)
plt.axhline(0,linewidth=0.5)
plt.show()

리키 렐루 함수는 0이상의 입력값일때 렐루함수와 같으며 0이하의 입력값일때 입력을 미세하게 유지하는 함수입니다.

0이하의 입력값에 0.01을 곱하는 대신 다른 방식의 값을 준 함수들도 계속 소계하겠습니다.

다만 연산비용이 상대적으로 크기 때문에 실제로 일반 렐루함수 또한 많이 사용합니다.

a = 1 # 조정가능 
x = np.arange(-10, 10, 0.1)
y = np.where(x > 0, x, a*(np.exp(x) - 1))

plt.plot(x,y)
plt.axhline(0,linewidth=0.5)
plt.show()

활성화 함수로 많이 사용하는 EUL 함수 입니다. 0 이하 입력값에서 비선형함수를 쓴 것이 특징입니다.

0 이하의 입력값에서 죽은 뉴런을 만들지 않는 것이 장점이고, 비선형함수가 섞여있기에 성능도 좋습니다.

하지만 지수함수의 계산이기 때문에 속도가 확실히 느려진다는 단점이 있습니다.

다음으로 SELU 함수입니다. ELU함수의 변종으로 자기 정규화가 일어나는것이 특징입니다.

자기 정규화란 입력특성이 표준화되어 있을때 각 층의 출력이 평균 0과 표준편차 1를 유지하는 경향을 말합니다.

이는 매우 좋은 성질로, 그레이디언트 소실, 폭주 문제를 막아주는 효과가 있습니다.

자기 정규화를 일으키는 조건을 만족시킨다면 SELU가 성능이 우수하고, 조건을 만족하기 힘들때 ELU를 많이 사용합니다.

사전 학습

큰 규모의 DNN을 처음부터 새로 훈련하는 것 보다 비슷한 유형의 신경망을 찾은 이후에 그 신경망의 상위 은닉층을 재사용 하는 방법도 있습니다.

이렇게 할 경우 훈련 속도는 당연히 크게 높아지고, 훈련 데이터도 적게 써도 좋은 성능을 낼 수 있습니다.

옵티마이저

옵티마이저.png

손실함수를 작게 하기 위해 최적의 파라미터를 찾는 방법들입니다.

옵티마이저 : SGD

Stochastic Gradient Descent(확률적 경사 하강법) 가장 기본이 되는 옵티마이저 입니다.

값을 하나씩 대입하여 가장 최적의 파라미터를 찾는 방법입니다. 이때 최적의 파라미터는 손실함수를 작게 만드는 값이죠.

일반적으로 일부 데이터(미니 배치)를 이용해서 기울기를 구한 뒤 최적의 파라미터를 찾습니다.

하지만 최적의 값을 찾아가기 위한 방향설정이 뒤죽박죽하고, 최적의 러닝레이트(학습률)을 찾기 힘들기 때문에 대체제가 등장합니다.

옵티마이저 : Momentum

파라미터 업데이트시 지역 최솟값에 빠질수가 있습니다. SGD는 이런 문제를 겪을 가능성이 높죠.

이를 해결하기 위해 이전 기울기도 파라미터 업데이트 하는 계산에 포함시킵니다. 물론 오래될수록 작은 비율로 포함합니다.

이런 방식의 옵티마이저를 Momentum 라고 합니다.

옵티마이저 : Adagrad

SGD는 모든 파라미터에 같은 러닝레이트(학습률)을 적용합니다. 하지만 수렴지역으로 빨리 수렴하기 위해선 다른방법이 필요한데요.

파라미터마다 많이 업데이트 된 파라미터가 있을 것이고 적게 업데이트된 파라미터도 있을 것입니다.

왜냐하면 특정 입력값이 0이 많이 나올경우 기울기가 0이기 때문에 파라미터 업데이트가 되지 않습니다.

그러면 그 입력값은 업데이트가 많이 안됬기 때문에 다른 입력값보다 상대적으로 최적값과 차이가 큽니다. 다른 입력값보다 학습률이 커야합니다.

이런 이유로 각 파라미터의 업데이트 빈도 수에 따라 러닝레이트(학습률)을 다르게 줍니다. 빈도가 높을수록 학습률을 낮게 설정합니다.

이런 방식의 옵티마이저를 Adagrad 라고 합니다.

옵티마이저 : RMSprop

RMSprop은 Adagrad 에서 학습률이 너무 작아지는 문제를 해결하기 위해 나온 옵티마이저 입니다.

기존 Adagrad에서는 항들을 그냥 더하지만 RMSprop에서는 지수평균으로 더해집니다.

즉 시간이 지난 배치일수록 영향력이 줄어드는 것을 알 수 있습니다.

옵티마이저 : Adam

Adam은 Momentum과 RMSprop의 장점을 결합한 옵티마이저로 현재 가장 많이 사용되는 옵티마이저 중 하나입니다.

방향을 중심으로 한 Momentum 과 보폭을 중심으로 한 RMSprop이 합쳐저 보폭도, 방향도 적절하게 조절한 옵티마이저 입니다.

잘 모르겠다 싶으면 Adam을 사용하면 됩니다.

규제

우선 l1과 l2 규제가 있습니다. l1규제는 파라미터 절대값을, l2규제는 파라미터 제곱값을 손실함수에 포함한 모형입니다.

l1은 라쏘, l2는 릿지 회귀와 유사합니다. 이는 딥러닝 모델이 과적합되는것을 막아줍니다.

또 드롭아웃 규제가 있습니다. 이는 간단한데, 매 훈련 스텝에서 각 뉴런은 드롭아웃될 확률을 가집니다.

이 방식은 이웃한 뉴런에 맞추어 적응하기 보다 자기 자신이 유용한 방식으로 학습합니다. 즉 몇 개의 입력 뉴런에만 지나치게 의존하지 않죠.

느낀점

오늘은 딥러닝을 하기 위해 알아야하는, 튜닝 가능한 것들에 대해 살펴봤습니다.

이름만 알고 지나갔었던 것이 많았는데 조금 지루하긴 하지만 스스로 확실히 다지고 갔기 때문에 유익했던 것 같아요.

실력은 아직 많이 부족하지만 빨리 딥러닝 관련해서 실습도 하고 싶습니다.

참고