Posts List

[머신러닝/딥러닝] 6. Optimization for Deep Learning

Optimization for Deep Learning

앞서 딥러닝(Deep Learning)오차역전파(Backpropagation)를 통해 weight가 loss에 얼마나 영향을 미치는지 파악한다는 것을 알았다. 결과적으로 오차역전파는 δL/δw를 구하기 위해 loss에서 input layer방향으로 편미분값을 전파한다는 것인데(오차역전파), δL/δw는 일찍이 배웠던 gradient를 의미한다. 

이제 gradient를 알아냈으니 다음 스텝은 loss를 최소화 하기 위한 최적화(optimization)를 할 차례다. 

우린 아주 심플한 iterative optimization method를 이미 하나 배웠다. 바로 경사하강법(gradient decent)이다. 

  • 지역최소값(local optima)에 빠지지 않고 → 경사하강할 방향(gradient)
  • 보다 빠르게 수렴(converge) 할 수 있는 → 경사하강할 크기(learning rate)

Gradient decent는 위와 같은 원리를 가지는데, 이 알고리즘의 개선 위해 아래와 같이 부던한 노력을 해 왔다.

위와 같이 다양한 알고리즘들이 제안되었지만 결국 가장 근간은 보다시피 경사하강법에서 왔다. 

위 그림에도 표현되어 있지만, 경사하강시킬 방향(Gradient)를 개선시키거나 Step size(=learning rate)를 더 효과적으로 개선시키기 위한 목적으로 발전되었다. 특히 Adam의 경우는 Gradient와 Learning rate 모두 개선시키기 위한 기술이 접목되어 있어 최근까지도 가장 많이 사용하는 Optimizer이다.

위 모든 알고리즘을 모두 소개하기 보다는, 가장 기본이 되는 Gradient Decent, 그리고 수렴 방향(gradient)을 개선시킨 Momentum, Learning rate 개선 사례인 RMSProp에 대해서 알아보고 Momentum과 RMSProp를 접목시킨 Adam, 이 3가지에 대해서 알아보도록 하자.


Stochastic Gradient Decent

1) Gradient Decent

Gradient Decent는 앞 단원에서 많이 설명했듯, 오차함수 J를 최소화 하는 파라미터를 iterative하게 찾아낸다. 위 식의 오차함수를 파라미터로 편미분한 δJ(Θ) / δΘ를 gradient라 하고, Θ는 gradient의 일부(α : learning rate)만큼 update된다. 위 수식을 parameter space에서 살펴보자.


(위 그림에서는 Θ대신 w로 표기했으나 크게 신경쓰진 말자.)

  • 초기 파라미터를 w0라고 하자. 이 때 gradient는 양(+)의 방향을 가진다.
  • w는 w0의 gradient의 반대방향(-)으로 이동해서 w1으로 update된다.
  • 즉, gradient가 증가하는 방향(+)이면 w는 감소한다.
  • gradient가 감소하는 방향(-)이면 w는 증가한다.

  • 즉, gradient는 w가 update되는 decent direction을 결정한다.

  • w의 증가/감소 속도 조절을 위해 0<α<1을 곱해주는데 이를 learning rate 혹은 step size라 한다.
    ※ learning rate가 크면 더욱 빠르게 w가 증가/감소한다. 하지만 최소점을 못 찾을 수 있다.

위 원리를 General form으로 표현하면 아래와 같지만 부호만 다를뿐 의미는 다르지 않다.

  • [Definition]
    Θ가 실수로 주어졌을 때, 그 때 J(Θ)의 direction v를 decent direction이라 하며, 아래 조건을 만족한다.
    J(Θ + αv) < J(Θ)
  • [Lemma]
    Θ가 실수로 주어졌을 때, direction v는 아래 조건을 만족해야한다.
    <▽J(Θ), v> < 0
(위에서 정의한 gradient가 steepest descent direction임을 증명하는 과정이 있지만 본 글에서는 생략한다.)

2) Mini-Batch Gradient Descent

위에서 설명한 gradient decent 알고리즘의 x는 scalar 값이 아니라 vector의 집합인 matrix이다. 즉, N개 샘플의 Total error를 최소화 하는 알고리즘이다. 이 때 전체 샘플을 이용해서 w를 1번 update 한 것을 1 epoch(혹은 1 iteration)이라 한다.

그런데, 만약 N=100,000,000으로 주어진다면 어떤 일이 발생할까? 당연히 모든 샘플의 error를 모두 구해야하기 때문에 1 epoch에 걸리는 시간이 굉장히 길어진다. 그래서 때로는 N개 샘플을 나눠서 틈틈히 w를 update해준다. 이 때 나눠진 샘플 그룹 하나하나를 Mini-Batch라 부른다. (전체 샘플은 Batch 혹은 Full Batch라 부른다.)

이렇게 틈틈히 w를 update했을 때 얻는 장점은 명확하다. 
계산량이 적고,  ② 전체 데이터를 메모리에 올리지 않기 때문에 효율적이다.
③ 그리고 전체 데이터가 학습되기 전 중간중간 성능변화를 관찰할 수 있다.

그런데 치명적인 단점이 있는데, 위 그래프에서 그 단점을 확인할 수 있다.

Full batch(좌측)의 경우는 전체 샘플을 확인하기 때문에, 그때 계산된 error는 전체 데이터를 대표할 수 있는 값이다.

반면, mini-batch(우측)의 경우는, mini-batch로 선택된 샘플이 전체 데이터의 분포와 유사할 수도 있지만 outlier가 많이 포함된 데이터일 수도 있다. 혹은 너무 쉬운 데이터가 포함되어있을 수도 있다. 즉, error가 극단적으로 높거나 낮을 수 있고, 그 말은 w를 update하는 방향(gradient)도 항상 다를 수 있다는 뜻이다. 그래서 우측 그래프처럼 단번에 수렴하지 못하고 시행착오를 많이 겪는다.

다만, 위의 단점이 있더라도 데이터가 많은 경우에는 어쩔 수 없이 Mini-batch gradient decent를 적용할 수 밖에 없다.

※ 참고로 mini-batch size는 64 / 128 / 256 / 512 처럼 2의 배수를 많이 쓴다. 그 이유는 불필요한 메모리 낭비를 줄이기 위해서다. (ex. 550개씩 나누면 애매하게 남은 38개 샘플을 위해서 다 쓰지도 못 할 메모리를 추가로 할당해야 한다.)

3) Stochastic Gradient Decent


[출처 : Stochastic gradient descent, Wikipedia]

Stochastic gradient decent를 해석하면 확률적 경사하강법이다. 

실제로 SGD에서는 무작위 샘플을 1개 뽑아서 w를 update하는 방식인데, 사실 batch size = 1인 mini-batch gradient decent와 동일하다. 다만 sampling에 랜덤확률이 적용되었다.

앞서 설명했듯, mini-batch는 샘플이 매우 많은 경우에 gradient decent 대비 계산량을 획기적으로 줄일 수 있는 장점이 있지만, 위 그래프에서 볼 수 있듯, 수렴하는데는 시간이 필요한 단점이 있다. 

※ 물론, batch size를 1이 아닌 다수의 샘플을 이용할 수도 있다. (Mini-batch Stochastic Gradient Decent)


Gradient Decent with Momentum(1999)

하지만 위 담점에도 불구하고 빅데이터 시대에 우리는 어쩔수 없이 mini-batch나 SGD를 사용해야 하는데, 역시 가장 큰 문제점은 수렴하는 속도며, 개선 포인트는 크게 2가지다.

  • gradient direction을 잘못 파악하는 경우를 방지하자.
  • learning rate(step size)를 고정하지 말고 adaptive하게 변경해서 빨리 수렴하게 하자. 

그 중 이번에 소개할 Momentum은 바로 gradient direction 을 바로 잡아주기 위한 개념이다.

1) Exponentially weighted moving average

mini-batch의 오차함수 J와 같이 oscillation이 심한 신호를 바로 잡기 위한 가장 쉬운 방법은 바로 이동평균(moving average)를 사용하는 것이다.


이동평균 함수는 위와 같이 일종의 noise를 잡는 필터로써 많이 사용되는 기법이다. 원리는 매우 간단한데, noise가 섞인 새로운 값이 들어오더라도, 직전 M개의 평균값으로 fitting 하는 방법이다. m번째 데이터에 noise나 outlier가 섞여도 최근 데이터의 경향을 따라가기 때문에 구현하기도 쉽고, 효과적이고, 간단한 필터로 알려져 있다.

만약 과거 데이터보다 현재 데이터가 더 중요하다면 어떻게 해야할까? 간단하다. 위 식과 같이 과거 데이터의 weight는 낮게, 최근 데이터의 weight는 높게 설명하면 현재 데이터의 추세를 적극 반영할 것이다. 이런 원리를 Weighted Moving Average라 한다. 위 식은 간단하게 아래와 같이 표현할 수도 있다.
convex sum : weight의 합이 1.0인 weighted sum

2) Gradient descent with Momentum

위에서 언급한 Weighted Moving Average를 좀 더 극단적으로 만들어보자.

즉, 예전 데이터 일수록 exponential 하게 가중치를 낮추는 것이다.

위 식은 그 희망사항을 재귀적인 식으로 표현한 것이다. 위 식이 잘 동작하는지 t=1..,3을 한번 대입해보자. 

※ β는 사용자가 지정하는 하이퍼파라미터다. β가 클수록 직전값의 가중치가 높다.

위 예제를 보면 알겠지만 β 에 의해서 예전 데이터의 weight가 exponential 하게 감소하는 것을 확인할 수 있다. 이런 기법을 Exponential Weighted Moving Average라 한다.

※ β=0.9면 대략 직전 10개까지 moving average 적용한 효과가 있다. 대부분 β의 기본값은 0.9로 셋팅되어 있다.

다만, 좀 아쉬운 점은 moving average의 앞 부분을 보면 초반에는 트랜드를 거의 따라가지 못하는 것을 확인할 수 있다. 뭐, 당연하다. 예를들어 10개의 평균을 쳐야하는데 가장 초기에는 10개의 샘플이 준비되어 있지 않기 때문에 0에 가까운 값을 가질 수 밖에 없다.

그래서 기존에 구했던 v를 후처리(Bias Correction) 해주면 위와 같이 초반에 존재하던 bias를 잡을 수도 있다.

그리고 지금까지 언급한 Exponential Weighted Moving Average를 Loss function L에 적용해주면 바로 Momentum을 고려한 Gradient decent알고리즘이 완성된다.

Momentum을 해석하면 '관성'이다. 위 그림을 loss function이라 생각하면, loss가 비록 noise를 가지더라도 그 전에 파악된 loss의 경향을 충분히 반영함으로 관성을 가진다고 할 수 있다. 이렇게 loss function에 관성을 가질 수 있게 하면 크게 2가지 이점을 가질 수 있다.

  • loss function이 oscillation해도  filtering된 loss를 얻을 수 있다.
  • loss function이 작은 언덕을 가지고 있더라도 넘어갈 수 있다.

위 같은 이점으로부터 최적해를 찾아가는 과정을 비교해보면 위와 같다.

Momentum이 없는 SGD의 경우, 샘플이 가지고 있는 noise에 의존하여 시행착오를 많이 하는 반면에, Momentum이 있는 SGD의 경우에는 보다 빠르게 최적해를 찾아가는 효과를 얻을 수 있다.


RMSProp(2012)

그런데 이런 방법도 100% happy하지는 않다. moving average를 활용하기 때문에 direction은 잘 결정했지만 step size 즉, learning rate를 고정으로 쓰고 있는 것이 조금 아쉽다. 즉, learning rate를 고정값으로 사용하는 것이 아니라 adaptive하게 바꿔보기위한 노력도 역시 많았다. 그 중에 대표적인 알고리즘인 RMSProp를 소개한다.

RMSProp는 Rprop와 SGD의 원리를 융합해 adaptive learning rate를 설정하는 방법인데, 이 글에서 Rprop의 원리는 따로 설명하지 않는다.

RMSProp의 원리는 아래와 같다.

RMSPropgradient의 제곱에 moving average를 먼저 구한다. 여기서 구한 gradient의 제곱은 앞서 배운 Hessian과 동일한 개념이며, 곡률 정보 즉, 동역학으로 치면 가속도를 의미한다. (기울기의 변화량)

그리고 gradient를 앞서 구한 gradient의 제곱의 squired root으로 나눠준다. 그리고 이렇게 구해진 v를 파라미터 update에 사용한다.

말이 좀 어렵긴 한데, 위 식을 잘 살펴보면 gradient의 크기가 클수록 큰값으로 v를 나눠주게 되고 이때는 Θ를 많이 update한다. 그리고 작을수록 조금 update하는 것을 확인할 수 있다. 즉, learning rate(=step size)를 adaptive하게 설정할 수 있다. (α는 고정이지만 v는 adaptive하게 변경된다.)


ADAM (2015)

ADAM을 가장 간단하고 직관적으로 설명하면 아래와 같다.

ADAM = momentum + bias correction + RMSProp

즉, momentum을 이용해 direction을 잘 결정할 수 있게 하면서도 learning rate를 adaptive하게 하는 원리를 가진 알고리즘이다. 굳이 이 원리를 수식으로 설명하진 않겠다. 

다만, momentumadaptive learning rate를 적용한 만큼 지금까지 나온 iterative optimization 방법 중 가장 우수한 알고리즘으로 알려져 있다.

※ 대부분의 라이브러리들의 optimizer 옵션은 ADAM이 기본값으로 설정되어 있다.


[출처 : ADAM: A method for stochastic optimizer, ICLR, 2015]

실제로 다양한 optimizer들을 적용했을 때 ADAM이 단연 최고의 성능을 내는 것이 실험적으로 알려져 있다.

※ 풍문으로는 learning rate만 잘 정하면 SGD가 최고라 한다. 그런데 학습률을 잘 정하는 것 자체가 굉장히 어려워서 ADAM으로 귀결된다. ADAM은 알아서 adaptive하게 학습률을 알아서 조정하기 때문.


(Optional) Learning rate decay

solution에 가까워 졌을 때 learning rate를 낮춰서 smooth하게 수렴하도록 하는 방법이 필요하다.  그리고 그 전략은 다양한데, 이 방법들을 Learning rate decay라고 한다. 참고 수준으로 알아두도록 하자.

learning rate가 solution에 가까워졌을 때 작게 만드는 방법은 위와 같이 다양하다.

위 식에서 Ω는 epoch, η는 decay rate이다.

즉, epoch가 많이 진행됐다면 learning rate를 작게 가져가는 전략이다.

댓글 쓰기

0 댓글