Deep Learning/CS231N

[CS231N] Optimization의 종류 - SGD부터 Adam까지

언킴 2021. 7. 12. 20:49
반응형

Contents

     

    Mini-batch SGD

    1. Sample a batch of data

    2. Forward prop it through the graph, get loss

    3. Backprop to calculate the gradients 

    4. Update the parameters using the gradient 

     

     

    이런 경우에는 몇천만개의 데이터들을 learning rate($\eta$) 하나로 고정을 시키고 최적화를 시키는 것이 과연 좋은 것인가? 라는 물음을 할 수 있다. 아래와 같은 SGD의 약점은 시작을 해서 flatten 지점에서 넘어가지 못하고 local minimum에 빠져버린다. 

     

     

     

    Momentum 

    GD와 Momentum의 다른점은 어떤 것인가? gradient descent의 경우 $ v = v - \eta  {\partial f \over \partial x} $이지만 Momentum의 경우에는 $ v = \mu  v - \eta  {\partial f \over \partial x} $ 로 hyperparameter가 2개가 된다. 처음 gradient가 움직인 방향과 크기에 대해서 $\mu$만큼 보존을 하는 개념으로 생각하면 될 것 같다.  momentum 에서 initialization을 할 때 velocity를 0으로 초기화를 하고 시작한다. 첫 interation 에는 gradient와 똑같이 될 것이다. 다음 iteration 에는 $v$가 0이 아닌 값이 들어가서 전에 학습한 값을 보존하여 추가로 더 움직여 주게 된다.

     

    2차 함수의 그래프를 가정해보았을 때 모멘텀은 local minimum을 지나치더라도 관성이라는 개념을 통해서 그쪽방향으로써의 힘이 전달되기 때문에 계속 좌우로 왔다갔다 하는 현상이 발생해 결과적으로 converge하지 못하는 현상이 발생할 수 있다는 문제점이 존재한다.

     

    Nesterov Accelaerated Gradient

    mometum이 있고, gradient를 mometum이 간 후에 그 지점에서의 gradient를 구해서 update를 한다는 것이 이전 방식과의 가장 큰 차이점이다. 그 지점에서의 gradient를 계산하기 때문에 조금 더 빨리 converge 할 수 있다. ( 기존 식에서 $ \mu v_{t-1} $ 이 값이 추가됨 )

    NAG가 Momentum 보다 saddle 구간을 더 빨리 빠져나갈 수 있다. optim 지점을 갈 때 확 꺽이는 지점이 생기게 되면 Momentum 보다 NAG가 조금 더 빨리 반응 해서 더 좋은 결과를 도출해낼 수 있다. 

     

     

     

    $v_{t} = \mu v_{t-1} - \epsilon \nabla f(\theta_{t-1} + \mu v_{t-1}) $ 

    $ \theta_{t} = \theta_{t-1} + v_{t} $

    AdaGrad

    각각의 iteration 별로 local gradient가 들어오고 gradient를 element 단위로 square를 해서 cache object에 적재를 한다. cache를 적재하는 이유는 상대적으로 적게 계산된 파라미터를 크게 변화시켜 학습을 시키고 싶기 때문이다. cache는 분모로 들어가기 때문에 많이 변화된 파라미터는 작아지고, 적게 계산된 파라미터는 커지는 효과를 볼 수 있다.

     

    그 cache object를 sqrt 한 값을 learning rate에 나누어준다.  $\epsilon$ 은 $\sqrt{cache}$ 부분이 0이 될 수 있기 때문에 그 부분을 보정하기 위한 correctino value. AdaGrad는 $\eta$ 자체를 전체적으로 하자는 것으로도 볼 수 있다. 

     

    Q. AdaGrad에서 step size가 굉장히 커졌을 경우 어떤일이 발생할까? 

     

    cache function을 살펴보면 구조적으로 증가할 수 밖에 없는 구조를 지니고 있다. 그렇기 때문에 증가함수꼴이 분모로 들어가기 때문에 iteration이 점점 증가할수록 update되는 크기 자체가 작아지게 되는 단점이 있다. 그런 AdaGrad의 단점을 보완하기 위해 RMSProp이 나오게 되었다. 

    \[ \text{cache} = \left({\partial f \over \partial x} \right)^{2} \]

    \[ x = - {\eta {\partial f \over \partial x} \over \sqrt{cache} + \epsilon} \]

     

     

     

    RMSprop

    AdaGrad처럼 분모 term이 커지게 되면서 update되는 값이 줄어들게 되는 문제를 해결하기 위해서 batch normalization에서 했던 shift의 개념이 도입된다. cache 에 decay_rate( hyperparameter ) 를 설정해 moving window 개념으로 사용한다. 만약 6번째 iteration에서는 3, 4, 5 의 iteration을 사용하고, 7번째 iteration에서는 4, 5, 6 의 값을 사용하면 어떻게 될까? 만약 parameter가 몇만 단위로 존재한다면 iteration가 3배수 단위로 확 늘어나게 되어버린다. 너무 많은 메모리를 사용하기 때문에 실전에는 사용하지 않는다. 

     

     

     

    Adam

    요즘 가장 많이 사용하고 있는 optimization 방법론이다. 발상 자체는 간단하다. momentum과 RMSProp을 같이 사용하면 좋지 않을까? 라는 아이디어에서 시작 되었다. 앞서 사용했던 방법론과 동일하게 initialization을 0으로 하게 된다. optimizer를 활용할 때에 있어서 Adam이 일반적으로 가장 좋다고 알려져있기 때문에([논문]) 주로 사용되고, 단순히 사용만 하는 것으로 그치는 것이 아니라 내부에 있는 $\beta_0, \beta_1, \eta, \epsilon$ 을 조절하는 것도 중요하다고 볼 수 있다. 그 중에서 $\epsilon$의 기본 값은 1e-8인데 이 부분을 잘 조절하는 것이 좋은 결과를 도출해낼 수 있는 방법 중 하나이다.

     

     

     

    Gradient 기반 방법들은 모두 learning-rate($\eta$) 를 hyperparameter를 가지고 있다. 그런데 학습을 하다 보면 loss 값이 내려가게 될 것이고, loss가 내려가다보면 update가 되는 구간이 되게 세밀해져야 되는 것이 사실적으로 맞다. 거기에 대해서 여러가지 방법론이 존재하는데, 본 강의에서 대표적으로 이야기하는 방법론은 다음과 같다. 사실 어떤 decay 방법을 사용을 해도 본질적인 목적은 같다. 

    \[ \text{exponetial decay: } \alpha = \alpha_0 e^{-kt} \]

    Evaluation : Model ensembles

    1. Train multiple independent models

    2. At test time average their results

     

    iteration별로 학습을 해서 가는 형태이기 때문에 loss가 어느정도 내려갔을 때 saver로 checkpoint안에 weight를 저장해 그 saver 값들로 ensemble을 하자는 것이 이 강의에서 말하는 내용이다. validation set 에서 같은 cross entropy를 가진다 하더라도 weight들의 조합은 굉장히 많기 때문이다. 

     

     

    Dropout

    왼쪽의 그림이 우리가 일반적으로 사용하는 Standard Neural set인데 dropout을 사용하게 되면 layer단위로 node의 percentage를 제한한 다음에 사용을 하자는 것이다. 여기서 hyperparameter로 들어가는 것이 전체의 노드 중에서 얼마만큼을 masking할 것이냐라는 것에 대해서 들어가게 된다. tesorflow에도 method로 구성되어 있다. dropout을 하는 이유는 overfitting 방지와 보안용으로도 사용된다. 

     

     

     

    dropout을 node에 대해서만 그렇게 하는 것이 아니라 weight 자체에서도 똑같이 dropout을 해보자라는 발상이 나왔다.

    dropout을 testing할 때 생각해볼 필요가 있다. node의 반틈(0.5)을 dropout하고 값을 보면 원래 전체 node를 가지고 예측했을 때에 비해 2배의 값이 출력된다. 그렇기 때문에 마지막 testing time때 p 값을 다시 곱해줌으로써 출력값을 조정된다.