Pytorch를 이용하여 딥러닝 모델을 구현하다 보면 torch.optim에서 SGD, Adam과 같은 다양한 optimizer를 볼 수 있습니다.
이들은 학습(Gradient Descent) 시에 파라미터를 업데이트하는 알고리즘이며 왜 Adam이 많이 쓰이는지, 여러 Gradient Descent 방법론들이 어떤 문제가 있고 어떻게 문제를 해결하고 발전해갔는지 간단하게 적은 해당 글을 보며 배울 수 있었으면 좋겠습니다.
(Stochastic) Gradient Descent
먼저 간단하게 Gradient Descent(경사 하강법)에 대해 알아보겠습니다.
Gradient Descent는 미분 가능한 함수의 Local Minimum을 찾기 위해 1차 미분한 값을 사용하는 반복적인 최적화 알고리즘입니다.
좌표 내의 특정 위치에서 미분 가능한 함수의 1차 미분 값을 빼면 위치가 Local Minumum이 존재하는 방향으로 이동하는 특징을 이용한 알고리즘이며 Learning Rate는 하이퍼 파라미터로 얼마나 위치를 이동할지를 결정합니다.
딥러닝 학습에서는 이를 이용하여 Loss를 최소화하는 Weights를 갖는 모델을 목표로 학습합니다.
Momentum
위의 SGD(Stochastic Gradient Descent)는 유일한 파라미터인 Learning Rate를 적절하게 조정하는 것이 매우 중요하지만, 어렵다는 것이 문제입니다.
이를 해결하기 위해 나온 것이 Momentum(관성)입니다. 여기서 관성이란 mini batch 학습에서 현재 batch를 Gradient Descent할 때, 이전 batch의 정보를 활용하여 학습하는 것입니다.
\( t \)시점의 Gradient(미분 값)인 \( g_t \)를 다음 시점인 \( t+1 \)시점에 버리고 \( g_{t+1} \)만 사용하는 것이 아니라 이전 시점과 현재 시점의 Gradient를 조합하여 만든 Accumulation Gradient (\( a_{t+1} \))을 사용하여 Gradient Descent를 진행합니다.
Accumulation Gradient를 사용하면 흘러가기 시작한 Gradient Direction을 어느 정도 유지시켜주기 때문에 변덕스러운 Gradient에도 학습이 잘됩니다.
Nesterov Accelerated Gradient (NAG)
NAG은 Momentum과 같이 Accumulation Gradient인 \( a_{t+1} \)을 사용하여 Gradient Descent를 진행하지만, Accumulation Gradient를 계산하는 과정이 다릅니다.
Momentum은 이전 시점의 Gradient(\( g_{t-1} \))를 이용하여 구한 Accumulation Gradient(\( a_t \))와 현재 시점의 Gradient(\( g_t \))를 조합하여 현재 시점에서 이용할 Accumulation Gradient(\( g_{t+1} \))를 구합니다.
반면, NAG는 현재 시점의 Gradient(\( g_t \))가 아닌 Lookahead Gradient를 조합하여 현재 시점에서 이용할 Accumulation Gradient(\( g_{t+1} \))를 구합니다.
Lookahead Gradient는 이전 시점의 Gradient(\( g_{t-1} \))를 통해 구한 Accumulation Gradient(\( a_t \))를 이용하여 \( W_t \)를 한번 이동시키고 해당 위치에서의 Gradient를 구한 것입니다.
이는 아래 나타나 있는 Momentum의 문제를 해결해줍니다.
Momentum은 Accumulation Gradient를 구할 때, 이전 시점의 Gradient를 그대로 사용하기 때문에 Local Minimum 근방에 \( W \)가 수렴하지 못하고 왔다 갔다 하는 문제가 있습니다.
NAG는 \( W \)가 한 번 이동한 곳의 Gradient를 이용하여 Accumulation Gradient를 구하기 때문에 Local Minimum에 조금씩 수렴할 수 있습니다.
Adagrad
Adagrad adapts the learning rate, performing larger updates for infrequent and smaller updates for frequent parameters.
Adagrad는 파라미터가 지금까지 얼마나 변해왔는지를 봅니다. 많이 변한 파라미터에 대해서는 더 적게 변화시키고 많이 변하지 않은 파라미터에 대해서는 많이 변화시키는 방향으로 Learning Rate를 조정합니다.
해당 방법론은 Learning Rate에 \( G_t \)를 나누어 Gradient Descent를 진행합니다. \( G_t \)는 처음부터 현재까지의 Gradient를 제곱하여 더한 것이며 각 파라미터가 얼마나 변했는지에 대한 값을 저장합니다.
파라미터가 많이 변할수록 해당 파라미터 위치의 \( G_t \) 값이 커지는데 이를 Learning Rate의 분모 자리에 넣어 위에서 언급한 Adagrad의 기능을 수행하는 것입니다.
\( \varepsilon \)는 분모가 0이 되지 않도록 상수의 기능을 합니다.
Adadelta
위의 Adagrad의 문제는 학습을 할수록 \( G \)는 계속 커져 무한대로 발산하기 때문에 Learning Rate가 0으로 수렴하여 \( W \)의 학습이 되지 않는다는 것입니다.
Adadelta는 \( G_t \)가 계속해서 커지는 Adagrad의 문제를 막기 위해 나왔습니다. 단순히 Gradient를 제곱 합하여 \( G_t \)를 구하는 것이 아닌 Gradient 제곱의 Exponential Moving Average(EMA)를 계산하여 \( G_t \)를 구합니다.
또한, Adagrad처럼 \( G_t \)를 Learning Rate의 분모로 하여 단조적으로 Learning Rate가 감소하는 것을 방지하기 위해 \( H_t \)를 사용합니다. \( H_t \)는 파라미터 \( W \)의 변화량 제곱의 EMA로 계산되며 \( H_t \)와 \( G_t \)가 Learning Rate를 대체하게 됩니다.
RMSprop
RMSprop은 Adadelta에서 \( H_t \) 대신 Learning Rate를 넣은 것입니다. 이는 기존의 \( H_t \)를 사용한 이유와 상관없이 경험적으로 시도해본 방법론이며 잘 동작하였다고 합니다.
Adam
마지막으로 Adam입니다. 가장 잘 동작하고 무난하게 사용되는 Gradient Descent 방법론입니다.
Momentum에서 사용된 Accumulation Gradient와 Adadelta에서 사용된 Gradient 제곱의 EMA를 모두 사용한 방법론입니다. 따라서 위의 방법론을 이해하셨다면 어렵지 않게 Adam의 동작 방식도 이해하실 수 있을 것입니다.
댓글