1. Stochastic Gradient descent(SGD)
추출된 데이터 한 개에 대해서 error gradient를 계산하고, gradient descent 알고리즘을 적용하는 방법이다.
모델의 레이어 층은 하나의 행렬곱으로 생각할 수 있고, 여러개의 묶음 데이터는 행렬이라고 생각할 수 있다.
SGD의 장점
위 그림에서 볼수 있듯이 Shooting이 일어나기 때문에 local optimal에 빠질 리스크가 적다.
step에 걸리는 시간이 짧기 때문에 수렴속도가 상대적으로 빠르다.
SGD의 단점
global optimal을 찾지 못 할 가능성이 있다.
데이터를 한개씩 처리하기 때문에 GPU의 성능을 전부 활용할 수 없다.
코드로 살펴보면 다음과 같다.
class SGD:
def __init__(self,lr=0.01):
self.lr=lr
def update(self,params, grads):
for key in params.keys():
params[key]-=self.lr*grads[key]
[출처] light-tree.tistory.com/133
2. Momentum
모멘텀(momentum)은 '운동량'을 뜻하는 단어로, 물리와 관계가 있다.
W는 갱신할 가중치 매개변수, dL/dW는 W에 대한 손실 함수의 기울기, η은 학습률이다. v라는 변수가 새로 나오는데, 이는 물리에서 말하는 valocity에 해당한다.
momentum은 위 그림과 같이 공이 그릇의 바닥을 구른는 듯한 움직임을 보여준다.
코드로 살펴보면 다음과 같다.
class Momentum:
def __init__(self, lr=0.01,momentum=0.9):
self.lr=lr
self.momentum=momentum
self.v=None
def update(self,params,grads):
if self.v is None:
self.v={}
for key, val in params.items():
self.v[key]=np.zeros_like(val)
for key in params.keys():
self.v[key]=self.momentum*self.v[key]-self.lr*grads[key]
params[key]+=self.v[key]
위 그림에서 볼 수있듯, 모멘텀의 갱신 경로는 공이 그릇 바닥을 구르듯 움직인다. SGD와 비교하면 '지그재그 정도'가 덜한 것을 알 수 있다. 즉, x축의 힘은 아주 작지만 방향은 변하지 않아서 한 방향으로 일정하게 가속하기 때문이다. 거꾸로 y축의 힘은 크지만 위아래로 번갈아 받아서 상충하여 y축 방향의 속도는 안정적이지 않다. 전체적으로 SGD보다 x축 방향으로 빠르게 다가가 지그재그 움직임이 줄어든다.
3. AdaGrad
신경망 학습에서는 학습률(수식에서는 η로 표기) 값이 중요하다.
이 학습률을 정하는 효과적 기술로 learning rate decay(학습률 감소)가 있다. 이는 학습률을 점차 줄여가는 방법이다.
학습률을 서서히 낮추는 가장 간단한 방법은 매개변수 '전체'의 합습률 값을 일괄적으로 낮추는 것이다. 이를 더욱 바전시킨 것이 AdaGrad이다. AdaGrad는 '각각의' 매개변수에 '맞춤형'값을 만들어준다.
AdaGrad는 개별 매개변수에 적응적으로 학습률을 조정하면서 학습을 진행한다. AdaGrad의 갱신 방법은 수식으로는 다음과 같다.
[Note] AdaGrad는 과거의 기울기를 제곱하여 계속 더해간다. 그래서 학습을 진행할수록 갱신 강도가 약해진다. 실제로 무한히 계속 학습한다면 어느 순간 갱신량이 0이 되어 전혀 갱신되지 않게 된다. 이 문제를 개선한 기법으로서 RMSProp이라는 방법이 있다. RMSProp은 과거의 모든 기울기를 균일하게 더해가는 것이 아니라, 먼 과거의 기울기는 서서히 잊고 새로운 기울기 정보를 크게 반영한다. 이를 Exponential Moving average,EMA(지수이동평균)이라 하며, 과거 기울기의 반영 규모를 기하급수적으로 감소시킨다.
코드로 살펴보면 다음과 같다.
class AdaGrad:
def __init__(self,lr=0.01):
self.lr=lr
self.h=None
def update(self,params,grads):
if self.h is None:
self.h={}
for key, val in params.items():
self.h[key]=np.zeros_like(val)
for key in params.keys():
self.h[key]+=grads[key]*grads[key]
params[key]-=self.lr*grads[key]/(np.sqrt(self.h[key])*1e-7)
위 코딩에서 주의해야 할 점은 마지막 줄에 1e-7이라는 작은 값을 더하는 부분이다. 이 작은 값은 self.h[key]에 0이 담겨 있다 해도 0으로 나누는 사태를 막아준다. 대부분의 딥러닝 프레임워크에서는 이 값도 인수로 설정할 수 있다.
위 그림을 보면 최솟값을 향해 효율적으로 움직이는 것을 알 수 있다. y축 방향은 기울기가 커서 처음에는 크게 움직이지만, 그 큰 움직임에 비례해 갱신 정도도 큰 폭으로 작아지도록 조정된다. 그래서 y축 방향으로 갱신 강도가 빠르게 약해지고, 지그재그 움직임이 줄어든다.
4. Adam
모멘텀은 공이 그릇 바닥을 구르는 듯한 움직임을 보였다. AdaGrad는 매개변수의 원소마다 적응적으로 갱신 정도를 조정했다. 그 두 기법을 융합한 아이디어에서 출발한 기법이 Adam이다.
Adam의 갱신 과정도 그릇 바닥을 구르듯 움직인다. 모멘텀과 비슷한 패턴이지만, 모멘텀보다 공의 좌우 흔들림이 적다.
[Note]
Adam은 하이퍼파라미터를 3개 설정한다. 하나는 지금까지의 학습률(논문에서는 α로 등장), 나머지 두 개는 일차 모멘텀용 계수 β1과 이차 모멘텀용 계수 β2이다. 논문에 따르면 기본 설정값은 β1은0.9, β2는0.999이며, 이 값이면 많은 경우에 좋은 결과를 얻을 수 있다.
SGD, Momentum, AdaGrad, Adam 총 4가지의 optimizer를 알아보았다. 하지만 모든 경우에 항상 뛰어난 기법은 없다. 각자의 장단점이 있기 때문에 해당 issue에 맞는 optimizer를 선택하는게 좋다.
'Deep Learning > 밑바닥부터 시작하는 딥러닝(1)' 카테고리의 다른 글
Chapter 6. 학습 관련 기술들(3) (0) | 2021.03.04 |
---|---|
Chapter 6. 학습 관련 기술들(2) (0) | 2021.03.03 |
Chapter 5. 오차역전파법 (0) | 2021.01.25 |
Chapter 4. 신경망 학습 (0) | 2021.01.23 |
Chapter 3-2 다차원 배열의 계산 (0) | 2021.01.18 |