1. Gradient Descent(경사하강법)
Gradient descent는 θ를 미지수로 갖는 목적함수 J(θ)를 최소화시키는 방법이다.
- 어떤 위치에 있는 θ를 그 위치에서의 gradient인 ∇θJ(θ)의 반대 방향으로 이동시켜준다.
- 일반적인 gradient descent의 업데이트 식은 다음과 같다.
θt+1=θt−η∇θJ(θ) - 여기서 η는 learning rate로 gradient 반대 방향으로 얼마나 업데이트할 것인지 결정한다.
- 작은 η는 수렴 속도를 늦출 것이고, 큰 η는 minimum을 그냥 지나쳐버릴 수 있고 심하면 발산한다.
- 작은 η는 수렴 속도를 늦출 것이고, 큰 η는 minimum을 그냥 지나쳐버릴 수 있고 심하면 발산한다.
얼마나 많은 데이터를 목적함수의 gradient 계산에 사용할지에 따라 크게 세 가지의 gradient descent 종류가 있다.
Batch gradient descent
- ML/DL 에서 batch는 의외로 데이터 전체를 의미한다.
- 이론보다 코딩을 먼저 경험했을 경우 batch_size = 32라는 인자를 많이 보기 때문에
- batch가 데이터의 일부라고 알고 있을 수도 있다.
- 몇몇 분들은 누가 그런 하찮은 생각을 한다고 의심할 수도 있겠지만,
- 그게 나였다.
- 여러분이 알고있는 기본적인 gradient descent가 바로 batch gradient descent이다.
- 손실함수는 보통 J=∑i=1Nerror 로 정의되는데
- ∑i=1N 이 데이터 N개 모두를 사용해서 손실함수를 만든다는 의미이다.
- 따라서, 한 번의 업데이트를 위해 모든 데이터가 계산에 포함되므로 속도가 느리다는 단점이 있다.
- batch gradient descent는 손실함수가 convex할 경우 global minimum 수렴을 보장하고, nonconvex일 경우에도 local minimum이 보장된다.
Stochastic gradient descent
- SGD는 한 번의 파라미터 업데이트를 위해 하나의 훈련 데이터를 사용한다.
- 굳이 수식으로 적어보면 다음과 같다.
θt+1=θt−η∇θJ(θ;x(i),y(i))
- 굳이 수식으로 적어보면 다음과 같다.
- 따라서 SGD는 batch gradient보다 훨씬 빠르게 업데이트가 진행되는 장점이 있다.
- 하지만 목적함수의 gradient가 하나의 데이터에 의해 결정되다보니
- 매 업데이트마다 들쭉날쭉한 크기의 gradient로 파라미터를 업데이트하게 된다.
- 이렇게 분산이 큰 gradient는 SGD가 local minimum에서 빠져나오게 만들 수도 있지만
- 반대로 수렴을 방해할 수도 있다.
- 매 업데이트마다 들쭉날쭉한 크기의 gradient로 파라미터를 업데이트하게 된다.
Mini-batch gradient descent
- Mini-batch gradient descent가 흔히 딥러닝을 사용할 때 쓰이는 방법이다.
- 우리는 batch_size 인자를 넘겨 mini-batch 사이즈를 결정한다.
- 그러면 최적화 알고리즘은 mini batch 사이즈의 데이터마다 손실함수를 만들고
- gradient를 계산하여 파라미터를 업데이트한다.
- 당연히 batch GD보다 업데이트 속도가 빠르고, gradient의 크기도 들쭉날쭉하지 않다.
2. Challenges(문제점들)
vanilla gradient descent는 해결해야할 문제점들이 있다.
- 몇몇 뉴비들은 vanilla라는 단어를 처음 봤을 수도 있다.
- 바닐라? 바나나인가? 싶을 것이다.
- “이런 바보같은 생각을 누구해?” 싶겠지만
- 사실 내가 그랬다. 내가 처음 vanilla를 봤을 때 바닐라맛 아이스크림 밖에 떠오르지 않았다.
- vanilla는 그냥 “아주 기본적인”, “아무것도 건들이지 않은” 이런 느낌으로 사용되는 것 같다.
- 바닐라? 바나나인가? 싶을 것이다.
적절한 learning rate를 설정해주어야 한다.
- ML/DL을 하면서 learning rate가 꽤나 많이 중요하다는 것을 느낀다.
- 잘 만든 내 모델이 학습이 안 돼서 속상할 때, learning rate를 줄여주면 학습이 되는 경우도 많이 보았다.
- 수렴지점에서 더 정밀한 minimum을 찾기 위해서는 학습 중간에 learning rate를 조절해줘야한다.
- SGD는 한 번 정해진 learning rate를 현재 학습 상황에 따라 바꿔주는 기능을 갖고 있지 않다.
- 따라서, 우리가 learning rate의 리스트를 만들어서 특정 에포크마다 learning rate를 줄여주어야 한다.
- 물론 실제 코딩에서는 decay를 사용하여 중간에 learning rate를 줄여줄 수 있다.
- 물론 실제 코딩에서는 decay를 사용하여 중간에 learning rate를 줄여줄 수 있다.
모든 파라미터에 대해 동일한 learning rate를 적용해준다.
- 각 파라미터의 중요도나 스케일 등이 모두 다를텐데, 모든 파라미터에 동일한 learning rate를 적용하는 것은 불합리해보인다.
- 앞으로 배울 방법들 중에 Ada가 들어가는 방법은 파라미터에 따라 learning rate를 자동으로 조절해주는 기능이 있다.
- 물론 초기 learning rate를 설정해주어야 한다.
- 물론 초기 learning rate를 설정해주어야 한다.
local minimum이나 saddle point에서 빠져나오기 힘들다.
- SGD가 높은 미끄럼틀에서 쭉 미끄러지다가 이제 막 평평한 밑면을 지나고 있다고 생각하자.
- 우리는 SGD가 현재 파라미터 위치에서의 gradient 크기만큼 움직인다는 것을 알고 있다.
- 밑면이 평평하다는 의미는 gradient가 0이라는 것이다.(극단적으로)
- 따라서 파라미터는 평평한 밑면 도달하자마자 gradient가 0이 되어 멈추고 말 것이다.
- 이는 우리의 직관과 약간 다르다.
- 우리는 미끄럼틀을 타고 내려올 때, 미끄럼틀 끝이 평평하다고 해서 바로 멈추지 않는다.
- 내려오던 관성에 의해 다 내려온 뒤에도 몇 초간 더 이동할 것이다.
Vanilla gradient descent의 문제점을 몇 개 알아보았다.
- 이제부터 다양한 최적화 알고리즘들이 이 문제점들을 해결하는지에 대해 이야기해볼 것이다.
3. Gradient Descent Optimization Algorithms
여기서부터 본론이라고 말할 수 있다. 이 글을 찾아서 읽어볼 정도의 분들이라면 위 내용들은 이미 다 알고 있는 내용일 것이다.
- 사실 여기부터 다 작성하고 1,2,3을 작성한 것이기 때문에 이제부터 내용이 진짜 알차다.
- 1,2,3은 4를 다 쓰고나서 마지막에 초심 잃고 작성했기 때문에 내용이 많이 부실했다. 인정한다.
- 가보자.
Momentum
바로 앞에서 미끄럼틀을 내려오는 SGD 예시를 들어보았다. 그리고 우리의 직관에 대해서도 이야기해보았다. Momentum(관성) 방법은 우리의 직관을 그대로 반영한 최적화 방법이다. Momentum는 현재 파라미터를 업데이트해줄 때 이전 gradient들도 계산해 포함해주면서 이 문제를 해결한다.
- 즉, SGD가 미끄럼틀 끝에서 gradient가 0인 평평한 밑면을 만났다고 해도
- 미끄럼틀의 빗면의 gradient가 남아있어 SGD가 앞으로 쭉 갈 수 있게 만들어준다.
물론 이전에 있던 모든 gradient들을 있는 그대로 고려해준다면, 아주 긴 평평한 땅에서도 SGD는 절대 멈추지 않을 것이다.
- 그래서 Momentum은 이전 gradient들의 영향력을 매 업데이트마다 γ배 씩 감소시킨다.
vt=γvt−1+η∇θtJ(θt)
θt+1=θt−vt - 점화식으로 표현되어있어서 감소한다는 것이 와닿지 않을 수도 있다.
- gt=η∇θt(θt) 그리고 v1=g1 이라고 하면
- v2=g2+γg1
- v3=g3+γg2+γ2g1
- v4=g4+γg3+γ2g2+γ3g1
- γ는 보통 0과 1사이의 값이기 때문에 이런 식으로 점점 오래된 gradient의 영향력을 줄이며 모멘텀을 만든다. γ 값은 주로 0.9를 사용한다.
Momentum의 힘 덕분에 이제 SGD는 관성을 사용해서 낮은 언덕정도는 탈출할 수 있게 되었다.
- 이는 SGD가 낮은 local minimum에서 벗어나 손실함수를 더 탐험할 수 있게 만들어준다.
Momentum 참고문헌
[0] Optimizer overview 논문 : An overview of gradient descent optimization algorithms
NAG(Nesterov accelerated gradient)
다시 미끄럼틀 위의 SGD를 상상해보자.
- 이제 우리의 SGD는 관성을 힘으로 미끄럼틀 끝에서도 더 나아갈 수 있게 되었다.
- 뿐만 아니라, 가파른 미끄럼틀에서 내려올 때면 관성이 그만큼 더 커지기 때문에 경로에 있는 작은 언덕 정도는 쑥 넘어버릴 수 있을 것이다.
관성에 재미를 붙인 SGD가 오늘도 미끄럼틀을 내려오고 있다.
- 앞에 평평한 땅이 있어도 SGD는 앞으로 나아갈 수 있다는 생각에 신이 나있다.
- 하지만 SGD가 밑면에 다다랐을 때쯤 앞에 압정이 있는 것을 발견했다.
- 엉덩이에 압정이 박히지 않으려면 SGD는 속도를 줄여야하지만 관성 때문에 SGD는 계속하여 앞으로 나아갔고,
- 결국 엉덩이에 압정이 박혀버렸다.
위의 끔찍한 예시에서 SGD는 앞에 압정이 있는 것을 알면서도 속도를 멈추지 못했다.
- NAG는 이런 문제를 해결하기 위해 나온 최적화 방법이다.
- NAG는 앞을 미리 보고 현재의 관성을 조절하여 업데이트 크기를 바꾸는 방식으로 이 문제를 해결한다.
- NAG는 앞을 미리 보고 현재의 관성을 조절하여 업데이트 크기를 바꾸는 방식으로 이 문제를 해결한다.
- Momentum 방법을 순서에 주의하여 다시 한 번 서술해보자.
- Momentum은 먼저 현재 parameter 위치에서 gradient를 계산하고, → ∇θtJ(θt)
- 현재의 모먼트를 vt 구하여, → vt=γvt−1+η∇θtJ(θt)
- 모멘텀만큼 업데이트를 해주었다.→ θt+1=θt−vt
- NAG도 순서에 주의하여 살펴보자.
- NAG는 먼저 현재 parameter 위치로부터 현재 모멘텀 vt만큼 떨어진 위치의 gradient를 계산한다. → ∇θtJ(θt−vt)
- momentum 업데이트 식을 보면 θt+1=θt−vt이므로 ∇θtJ(θt+1) 계산하려는 시도인 것이다.
- 즉, 미래를 보려고 노력하는 느낌이다.
- 하지만 현재의 gradient를 구하기 전까지는 현재의 모멘텀을 알 수 없기 때문에 γvt−1을 vt 대신 사용해준다.
- 즉, ∇θtJ(θt−γvt−1)를 식에 사용한다.
- momentum 업데이트 식을 보면 θt+1=θt−vt이므로 ∇θtJ(θt+1) 계산하려는 시도인 것이다.
- 다음으로 현재의 모멘텀을 계산해준다. → vt=γvt−1+η∇θtJ(θt−γvt−1)
- 그리고 모멘텀만큼 업데이트를 해준다. → θt+1=θt−vt
- NAG는 먼저 현재 parameter 위치로부터 현재 모멘텀 vt만큼 떨어진 위치의 gradient를 계산한다. → ∇θtJ(θt−vt)
- 글이 길어졌지만, 다음과 같이 2줄의 식으로 요약할 수 있다.
vt=γvt−1+η∇θt(θt−γvt−1)
θt+1=θt−vt
NAG는 SGD가 관성에 의해 수렴 지점에서 요동치는 것을 방지해준다.
- RNN의 성능을 향상시켰다는 소문이 있다.
NAG 참고문헌
[0] Optimizer overview 논문 : An overview of gradient descent optimization algorithms
Adagrad
지금까지 SGD와 Momentum 그리고 NAG에 대해서 알아보았다.
- 이 세 가지 방법의 공통점 중 하나는 모든 파라미터에 대해서 같은 learning rate를 적용하여 업데이트를 한다는 점이다.
- 이것이 어떤 문제가 될까 싶겠지만, sparse한 데이터를 예시로 들어 알아보자.
- i번 째 레이어의 인풋 노드 값을 차례대로 a1,a2,⋯,an 이라고 하자.
- 이미 잘 알고 있는 것처럼 i+1번 째 레이어로 넘어가기 전에 파라미터들과 선형결합을 해준다.
w0+w1a1+w2a2+⋯+wnan - 이 때, 다른 얘들은 괜찮은데 유독 a2 는 sparse해서 주로 0값이 많이 나온다고 하자
- 그러면 a2=0일 때, w0+w1a1+0+w3a3+⋯+wnan이 되고,
- 손실함수에서도 w2 term이 없어질 것이다.
- w2가 없는 손실함수를 w2로 편미분한 값은 0이 나오고 w2는 업데이트되지 않을 것이다.
- 그렇게 w2가 기억에서 사라질 때쯤 0 아닌 값을 갖는 a2가 등장했다고 하자.
- 아주 오랜만에 손실함수에는 w2 term이 등장할 것이고 드디어 w2를 업데이트할 수 있게 되었다.
- 이 때 w2는 그 동안 상대적으로 조금 업데이트됐기 때문에 수렴점까지 거리가 아직 많이 남은 상태이다.
- 따라서 w2는 다른 파라미터들보다 더 크게 업데이트를 해줘야만 수렴지점으로 조금이라도 빨리 갈 수 있을 것이다.
- 이런 이유로 각 파라미터의 업데이트 빈도 수에 따라 업데이트 크기를 다르게 해줘야 할 필요가 있다.
- 그리고 앞에서 다룬 세 가지 방법은 아쉽게도 이를 반영하지 못한다.
앞으로 다룰 방법들의 이름에는 Ada 라는 단어가 등장하는데 이는 Adaptive의 준말이다.
- ML이나 DL에서 Adaptive는 “상황에 맞게 변화하는” 이라는 맥락으로 사용되는 것 같다.
- 여담으로 Ada를 “아다”나 “에이다” 등으로 부르는 것보다 “어뎁티브”라고 부르는게 조금 더 있어 보인다.
- 예를 들어, 아다그레드보다는 어뎁티브그레드 메서드라고 부르는게 더 있어 보인다.
- 예를 들어, 아다그레드보다는 어뎁티브그레드 메서드라고 부르는게 더 있어 보인다.
Adagrad를 들어가기 전 서두가 다소 길었다. 이제 서두에서 제시한 문제를 Adagrad는 어떻게 해결하는지 알아보자.
- 파라미터마다 지금까지 얼마나 업데이트됐는지 알기 위해서 Adagrad는 parameter의 이전 gradient들을 저장한다.
- t번 째 step의 i 번 파라미터를 θt,i
- t 시점에서 θt,i에 대한 gradient 벡터를 gt,i=∇θtJ(θt,i)라 하자.
- 이 새로운 노테이션으로 SGD의 업데이트 식을 다시 적어보면 다음과 같다.
θt+1,i=θt,i−ηgt,i
- Adagrad는 다음과 같은 업데이트식을 사용한다.
θt+1,i=θt,i−ηGt,ii+ϵgt,i
- Gt는 i번 째 대각원소로 t시점까지의 θi에 대한 gradient들의 제곱의 총합을 갖는 대각행렬이다.
- 즉, Gt,ii=g1,i2+g2,i2+⋯+gt,i2 이다.
- 그리고 ϵ은 분모가 0이 되는 것을 방지해주는 용도로 10−8와 같이 아주 작은 값을 사용한다.
- 신기한 것은, 분모에 루트를 씌어주지 않으면 알고리즘의 성능이 매우 구려진다고 한다.
- Gt는 i번 째 대각원소로 t시점까지의 θi에 대한 gradient들의 제곱의 총합을 갖는 대각행렬이다.
- vectorize form으로 다시 써보면 다음과 같다.
θt+1=θt−ηGt+ϵ⊙gt
- ⊙은 matrix vector 곱셈이다.
- 그리고 분모에 어떻게 행렬이 들어가?라고 생각할 수 있는데
- 대각행렬이기 때문에 성분들을 모두 역수 취하고 ϵ 더해주고 루트 씌워서 η를 곱한 새로운 행렬이라고 생각하자
- 업데이트 빈도 수가 높았던 파라미터는 분모에 의해 η보다 작게 업데이트되는 것을 알 수 있다.
- η 값은 주로 0.01을 사용한다고 한다.
- 하지만 Adagrad는 t가 증가하면서 Gt,ii 값이 점점 커지게 되어 learning rate가 점점 소실되는 문제점이 있다.
Adagrad 참고문헌
[0] Optimizer overview 논문 : An overview of gradient descent optimization algorithms
Adadelta
해결하고자 한 문제점
- Adagrad에서 발생한 iteration 마다 learning rate가 작아지는 문제
- Hyperparameter인 learning rate(η)의 필요
Adadelta는 1을 해결하기 위해 크기 w인 window를 사용한다.
- 즉, 지난 모든 gradient의 정보를 저장하는 것이 아니고 지난 w개의 gradient 정보만을 저장한다.
Adagrad와 또 다른 점은 gradient의 제곱의 합을 저장하지 않고, gradient의 제곱에 대한 기댓값을 저장한다는 것이다. → E[g2]t
또한 과거의 gradient 정보의 영향력을 감소시키기 위해 다음과 같은 식을 사용했다.
- 이를 decaying average of squared gradient 라고 표현한다.
E[g2]t=γE[g2]t−1+(1−γ)gt2 - 이 정보를 사용해서 Δθt를 다음과 같이 결정한다.
Δθt=−ηE[g2]t+ϵgt - RMS(root mean square)가 x12+x22+⋯+xn2n 이므로 다음처럼 더 간략히 표현할 수 있다.
Δθt=−ηRMS[g]tgt
논문의 저자는 first order method를 사용해서 parameter θ를 업데이트할 경우 θ와 Δθ의 단위(unit)가 맞지 않다는 것에 주목했다.
- 예를 들어 미터(m) 단위를 갖는 함수 f를 m/s 단위인 ∇tf를 사용해서 업데이트하면 안 된다는 것이다.
- 함수 f의 단위를 unit(f), 정의역 t을 단위를 unit(t)라고 하면 first order method는
ddtf(t)|t=t0≈f(t)−f(t0)t−t0 - 이므로 단위는 unit(f)unit(t)이 되고, 확장하여 dnfdtn의 단위는 unit(f)unit(t)n 이다.
- 우리의 파라미터 업데이트 식 θt=θt−1+Δθ 에서 Δθ 는 g=∇θtJ(θt) 를 포함하므로
Δθ∝g∝∂J∂θ∝1unit of θ - 마치 m을 변화시키는데 m/s를 사용하는 것으로 볼 수 있다.(편의를 위해 J의 단위가 없다고 하자.)
- 함수 f의 단위를 unit(f), 정의역 t을 단위를 unit(t)라고 하면 first order method는
- 따라서 Δθ=−ηRMS[g]g에 second order method 행렬인 헤시안 행렬을 도입함으로써 unit을 맞춰줄 것이다.
Δθ∝H−1g∝∂J/∂θ∂2J/∂θ2∝unit of θ
- 여기서 1∂2J/∂θ2=−Δθ∂J/∂θ 임을 이용했다.(Newton’s Method)
- 우변의 분모에 해당하는 텀( RMS[g] )은 가지고 있으므로 분자(Δθ) 텀을 만들기 위해 똑같이 다음을 생각한다.
E[Δθ2]t=γE[Δθ2]t−1+(1−γ)Δθt2 - 다시 RMS를 사용해 간단히 적으면
Δθt=−RMS[Δθ]tRMS[g]tgt - 이다. 하지만 현재(t)는 업데이트 전이므로 RMS[Δθ]t 값을 알 수 없기 때문에
- 대신 RMS[Δθ]t−1을 근사값으로 사용한다.
Δθt=−RMS[Δθ]t−1RMS[g]tgt
- 최종적으로 업데이트식은
θt+1=θt+Δθt
위의 단위를 맞춰주는 과정을 통해 우리는 더 이상 learning rate가 필요하지 않게 되었다.(문제 2 해결)
Adadelta 참고문헌
[0] Optimizer overview 논문 : An overview of gradient descent optimization algorithms
[1] 원논문 : ADADELTA: AN ADAPTIVE LEARNING RATE METHOD
[2] unit을 이해하게 된 StackOverFlow : what-are-the-units-of-the-second-derivative
[3] Root Mean Square
[4] 참고한 블로그글 : https://twinw.tistory.com/247 [흰고래의꿈]
[5] 참고한 블로그글 : http://incredible.ai/artificial-intelligence/2017/04/10/Optimizer-Adadelta/
RMSprop
해결하고자 한 문제점
- Adagrad의 learning rate 가 작아지는 문제(Adadelta와 마찬가지)
사실, Adadelta에서 이야기했던 첫 번 째 업데이트식과 같다.
E[g2]t=0.9E[g2]t−1+0.1gt2
θt+1=θt−ηE[g2]+ϵgt
- Adadelta와 비슷한 시기에 Geof Hinton이 그의 코세라 강의에서 제안한 방법
- 적절한 γ 값으로 0.9를, η 값으로 0.001을 제안
RMSProp 참고문헌
[0] Optimizer overview 논문 : An overview of gradient descent optimization algorithms
Adam(Adaptive Moment Estimation)
Adam은 Adagrad, Adadelta, RMSprop 처럼 각 파라미터마다 다른 크기의 업데이트를 적용하는 방법이다.
특히 Adadelta 에서 사용한 decaying average of squared gradients 뿐만 아니라. decaying average of gradients를 사용한다.
- 즉, Adadelta에서 E[g2]t 를 업데이트에 사용한 것처럼, Adam은 E[g]t 도 업데이트에 사용한다.
- 이 맥락에서 Adam의 Full name에 있는 moment의 정체를 알 수 있다.
- 이전 언급한 momentum method의 momentum는 “관성” 같은 느낌이지만
- Adam의 moment는 통계에서 등장하는 용어이다.
- 일반적으로 확률변수 X의 n차 moment를 E[Xn]으로 정의한다.
- 1차 moment E[X]는 모평균이고
- 2차 moment E[X2]와 1차 moment를 사용해서 모분산을 얻을 수 있다.
- 물론, E[X]와 E[X2] 은 모수이기 때문에 알 수 없는 값이다.
- 따라서 표본평균과 표본제곱의평균으로 1,2차 moment를 추정해야한다.
- 그래서 추정(estimation)이 들어가 Adaptive Moment Estimation인 것이다.
- 이 맥락에서 Adam의 Full name에 있는 moment의 정체를 알 수 있다.
- mt를 gradient의 1차 moment에 대한 추정치, vt를 2차 moment에 대한 추정치라 하자.
- 그리고 이제는 익숙한 가중평균식을 도입하면 다음과 같다.
mt=β1mt−1+(1−β1)gt
vt=β2vt−1+(1−β2)gt2 - mt와 vt의 초기값을 0벡터로 주면, 학습 초기에 가중치들이 0으로 편향되는 경향이 있다.
- 특히 decay rate 가 작으면, 즉 β1과 β2가 1에 가까우면 편향이 더 심해진다.
- 편향을 잡아주기 위해 다음과 같이 bias-corrected를 계산한다.
mt^=mt1−β1t
vt^=vt1−β2t
- 최종적으로 업데이트 식은 다음과 같다.
θt+1=θt−ηvt^+ϵmt^
- 저자는 β1=0.9, β2=0,999, ϵ=10−8을 default 값으로 설정하였다.
Adam 참고문헌
[0] Optimizer overview 논문 : An overview of gradient descent optimization algorithms
AdaMax
요약하자면 AdaMax는 Adam의 vt 텀에 다른 norm을 사용한 방법이다.
- Adam의 vt term과 최종 업데이트식 다음과 같다.
vt=β2vt−1+(1−β2)gt2
θt+1=θt−ηvt^+ϵmt^ - 현재 gradient g_t에 제곱이 있고, 최종 업데이트식에는 루트가 있다.
- 즉, 현재 gradient의 l2 norm을 사용했다.
- 따라서 Adam의 l2 norm을 lp norm으로 일반화한 방법을 생각할 수 있다.
vt=β2pvt−1+(1−β2p)‖gt‖p
- 여기서 β2p는 β2의 p 제곱이 아니고 그냥 계수의 노테이션이다.
- lp norm 값은 p이 커질수록 불안정(numerically unstable)해진다.
- 하지만 l∞ norm은 일반적으로 안정적인 양상을 보인다.
- 이런 이유로 AdaMax는 vt에 l∞을 사용했고, stable한 값에 수렴한다는 것을 보였다.
- Adam의 노테이션과 구분짓기 위하여 ut를 사용해서 표현하면 다음과 같다.
ut=β2∞vt−1+(1−β2∞)‖gt‖∞
ut=max(β2vt−1,‖gt‖) - 최종 업데이트식은 다음과 같다.
θt+1=θt−ηutmt^
- Adam과 다르게 max operation은 0으로의 편향이 없기 때문에 편향 보정을 해줄 필요가 없다.
- 적절한 초기값은 η=0.002, β1=0.9, β2=0,999 이다.
AdaMax 참고문헌
[0] Optimizer overview 논문 : An overview of gradient descent optimization algorithms
NAdam(Nesterov-accelerated Adaptive Memoment Adam)
NAdam은 이름에서 알 수 있는 것처럼 NAG와 Adam을 섞은 방법이다.
Momentum과 NAG(Nesterov accelarated gradient)를 다시 한 번 보고가자.
- 순서에 주의해서 Momentum 방법 먼저 살펴보자
- 현재 gradient ∇θtJ(θt)를 구하고
- 구한 gradient에 이전 step의 moment에 γ를 곱해준 γmt−1을 더하여 현재 moment mt를 산출해서
- 최종 업데이트(θt+1)에 사용한다.
- 이를 식으로 보면 다음과 같다.
gt=∇θtJ(θt)
mt=γmt−1+ηgt
θt+1=θt−mt
∴θt+1=θt−(γmt−1+ηgt)
- NAG 또한 순서에 주의하며 복습해보자.
- 현재의 위치 θt에서 현재의 moment mt만큼 움직인 자리의 gradient ∇θtJ(θt−mt)를 구하고,
- 아쉽게도 mt 값을 모르기 때문에 γmt−1을 mt 대신 사용한다.
- 구한 gradient에 이전 step의 moment에 γ를 곱해준 γmt−1을 더하여 현재 moment mt를 산출해서
- 최종 업데이트(θt+1)에 사용한다.
- 이를 식으로 보면 다음과 같다.
gt=∇θtJ(θt−γmt−1)
mt=γmt−1+ηgt
θt+1=θt−mt
∴θt+1=θt−(γmt−1+ηgt)
- 현재의 위치 θt에서 현재의 moment mt만큼 움직인 자리의 gradient ∇θtJ(θt−mt)를 구하고,
이제 다시 NAdam으로 돌아가자.
- NAdam은 NAV를 조금 변형했다.
- mt−1을 gradient를 업데이트할 때와, θ를 업데이트할 때 2번 사용하였다.
- NAdam은 이렇게 momentum을 2번 적용하는 대신 업데이트할 때만 적용할 것과
- mt−1 대신 mt를 사용하는 것을 제안하였다. 즉,
gt=∇θtJ(θt)
mt=γmt−1+ηgt
θt+1=θt−(γmt+ηgt)
∴θt+1=θt−mt+1
- 위에서 본 식들과 3,4번 째 식의 순서가 다름에 주의하자.
- 업데이트 식에서 γmt−1 대신 γmt를 사용함으로써
- 마치 mt+1을 사용하여 미래의 momentum을 사용한 효과를 가졌다.
- 이제 변형된 NAV와 Adam을 합쳐보자. 먼저, Adam의 업데이트식은 다음과 같다.
mt=β1mt−1+(1−β1)gt
mt^=mt1−β1t
θt+1=θt−ηvt^+ϵmt^ - 1,2번 식을 3번 식에 대입하면
θt+1=θt−ηvt^+ϵ(β1mt−11−β1t+(1−β1)gt1−β1t)
θt+1=θt−ηvt^+ϵ(β1m^t−1+(1−β1)gt1−β1t) - 으로 정리할 수 있고, 마지막으로 변형된 NAV처럼 mt−1 대신 mt를 사용해주자
θt+1=θt−ηvt^+ϵ(β1m^t+(1−β1)gt1−β1t)
NAdam 참고문헌
[0] Optimizer overview 논문 : An overview of gradient descent optimization algorithms
결론
SGD부터 NAdam까지 모든 알고리즘을 살펴보았다. 각 알고리즘들은 이전 알고리즘들의 한계점을 보완해가며 발전해갔다.
- 먼저 SGD는 업데이트 한 번에 데이터 하나를 사용하여 Batch GD의 시간 문제를 해결했고,
- Momentum은 SGD의 작은 gradient 때문에 작은 언덕이나 saddle point를 빠져나가지 못하는 것을 momentum을 도입하여 해결했다.
- NAG는 다음 step의 gradient를 먼저 살펴보고 Momentum을 조절하여 minimum에 안정적으로 들어갈 수 있게 했으며,
- Adagrad는 업데이트 빈도가 다른 파라미터에 대해서도 같은 비율로 업데이트하는 것을 이전 gradient들의 합을 기억함으로써 문제를 해결하였다.
- RMSProp과 Adadelta는 Adagrad의 learning rate가 점점 소실되는 것을 gradient의 2차 모먼트를 통해 보완했고,
- Adam은 RMSProp에 1차 모먼트를 도입하여 RMSProp과 Momentum을 합친 효과를 볼 수 있었다.
- AdaMax는 Adam의 2차 모먼트에 있는 gradient의 norm을 max norm으로 바꿔주었고
- 마지막으로 NAdam은 ADAM에 NAG를 더해주어서 momentum을 보완해주었다.
'Deep learning' 카테고리의 다른 글
CIFAR-10 Classification (0) | 2020.05.16 |
---|