데이터과학 유망주의 매일 글쓰기 — 열여섯 번째 일요일
Optimizers
# Optimizers, #Keras
오늘 한일:
어제까지 딥러닝 신경망의 학습을 최적화할 수 있는 여러 방법과 대상에 대한 글을 썼다. 오늘은 이전에 다루었던 교차검증(Cross Validation) 및 가중치 초기화(Weight Initialization), 가중치 규제(Weight Regularization)등에 이어 Keras에서 제공하는 여러 Optimizer들에 대해 다루어 보기로 했다.
Keras 라이브러리는 이전에 언급한 기법들 이외에도, Optimizer라는 것을 통해 learning rate나 momentum등의 하이퍼파라미터들을 이용하여 조금 더 모델의 성능을 올릴 수 있는 옵션을 제공하고있다. 그렇다면 어떠한 Optimizer들이 존재할까?
Keras Optimizers
SGD(Stochastic Gradient Descent)
SGD는 Stochastic Gradient Descent의 약자이며, Gradient Descent는 알다시피 Global Minima를 찾아 에러를 최소화하는 가중치 값을 찾기 위함이다. 일반적인 Gradient Descent는 모든 데이터에 대해 gradient 즉 미분(derivative)를 계산해야 한다. 그렇기 때문에 계산해야하는 총량이 기하급수적으로 늘어날 수 있다는 단점이 있다. SGD는 정해진 반복(iteration)횟수 만큼, 주어진 데이터의 범위에서 랜덤하게 값을 선택하여 Gradient Descent에 비해 계산할 양을 현저하게 줄이는 방식이다. “stochastic”이라는 단어가 “추계론적”이라는 의미를 지니고 있는 만큼, 주어진 데이터에서 랜덤하게 데이터를 선택하여 계산을 함으로써, 불필요한 계산을 줄이고 결과의 신빙성을 좀 더 높일 수 있다는 장점이 있다.
아래와 같이 tf.keras.optimizers의 매소드로 사용할 수 있으며 주요 하이퍼파라미터는 learning_rate와 momentum이다. nesterov를 True로 설정하면 nesterov momentum을 활용할 수 있다.
# SGD 매소드의 코드 예제
tf.keras.optimizers.SGD(learning_rate=0.01, momentum=0.0, nesterov=False, name='SGD', **kwargs)
RMSprop
RMSprop 알고리즘을 적용할 수 있는 optimizer 매소드다. 이 알고리즘은 두 가지 목적을 가지고 있다.
- gradient의 제곱의 동적 평균(moving average)를 유지하는 것
- gradient를 평균의 root값으로 나누어 표준화하는 것
위 공식에서 보는 것과 같이, 동적 평균의 gradient(g, 미분)을 제곱하는 과정을 먼저 거친다. 이후 w에 대한 비용함수의 미분(dC/dw)를 활용하여 가중치를 업데이트한다. 일반적인 Backpropagation과정과 다른 점은, 학습 비율(eta)를 이전에 계산된 gradient의 제곱의 루트로 나누어 표준화 시킨다는 것이다. 여기서 Beta는 동적 평균의 파라미터를 의미한다. 대부분의 어플리케이션에서는 이 값을 0.9로 설정해 주면 상당히 좋은 성능을 보인다.
RMSProp은 Nesterov 모멘텀이 아닌 일반 momentum의 개념을 차용한다. learning_rate와 momentum 이외에도 rho 및 epsilon이라는 하이퍼파라미터가 존재한다.
# RMS prop 코드 예제
tf.keras.optimizers.RMSprop(learning_rate=0.001, rho=0.9, momentum=0.0, epsilon=1e-07, centered=False,name='RMSprop', **kwargs)
Adam
Adam 알고리즘을 구현하기 위한 optimizer 매소드다. Adam 최적화 기법은 SGD(Stochastic Gradient Descent)의 방법으로써, 일차 및 이차 모수의(First and second order moments) 동적 측정에 기반하여 이루어진다. 계산이 효율적이며, 메모리 사용량이 적고, gradient의 대각 스케일링(diagonal rescaling)에 영향을 받지 않는다. 데이터나 파라미터가 많은 큰 스케일의 문제에 효과적이다.
Adam은 learning_rate 이외에도 beta_1과 beta_2가 있는데 각각 0.9와 0.999로 기본 설정이 되어있다. epsilon도 존재하며, 주목할 것은 momentum을 차용하지 않는다는 것이다.
# Adam 코드 예제
tf.keras.optimizers.Adam(learning_rate=0.001, beta_1=0.9, beta_2=0.999, epsilon=1e-07, amsgrad=False,name='Adam', **kwargs)
AdamW
가중치 증가 제한(weight decay)를 고려한 Adam 알고리즘을 적용할 수 있는 optimizer 매소드다. Adam과 비교해서 업데이트하는 과정을 고려한다는 것이 큰 차이가 있다. 변수를 업데이트할 때, 가중치의 증가를 제한한다. 주의할 것은, L2 표준화를 변수에 적용하는 것과는 다른 개념이라는 것이다. L2 표준화 기법보다도 큰 gradient를 가진 변수들을 표준화하려는 경향이 더 크기 때문이다. 결과적으로 L2 표준화와 비교해 훈련 비용(training loss)와 일반화 에러를 더 작게 줄일 수 있다.
tf가 아닌 ‘tfa’라이브러리를 사용하며, Adam과 비교해 weight_decay의 옵션을 설정해 줄 수 있다.
# AdamW 예제
tfa.optimizers.AdamW(weight_decay: Union[FloatTensorLike, Callable],learning_rate: Union[FloatTensorLike, Callable] = 0.001,beta_1: Union[FloatTensorLike, Callable] = 0.9,beta_2: Union[FloatTensorLike, Callable] = 0.999,epsilon: tfa.image.filters.FloatTensorLike = 1e-07,amsgrad: bool = False,name: str = 'AdamW',**kwargs)
만약 tf를 활용한다면, Adam을 사용하고, weight_decay 값을 설정해 줄 수 있다.
extend_with_decoupled_weight_decay(tf.keras.optimizers.Adam,weight_decay=weight_decay)
Adagrad
Adagrad는 특정한 파라미터에 특화된 learning rate를 기반으로한 최적화 기법으로써, learning rate는 학습하는동안 얼마나 자주 해당 파라미터가 업데이트 되는지에 따라 조정된다. 파라미터가 더 많이 업데이트될 수록, 업데이트 되는 양은 더 작아진다. 이 업데이트 기법은 초기 누적 값을 설정해 주어야하는데, 학습을 하면서 계산되는 gradient의 값을 어느 정도의 비율로 누적할지를 지정해 주는 것이다.
아래와 같이 learning_rate와 epsilon를 설정할 수 있고, 초기 누적값(initial_accumulator_value)를 설정할 수 있다.
# Adagrad 코드 예제tf.keras.optimizers.Adagrad(
learning_rate=0.001,
initial_accumulator_value=0.1,
epsilon=1e-07,
name="Adagrad",
**kwargs
)
Adadelta
Adadelta 최적화 기법은 SGD(Stochastic Gradient Descent)의 방법으로써, 차원 당 adaptive learning rate를 기반으로 이루어진다. 이 방법은 주로 다른 최적화 방법에서 나타나는 아래 2가지 단점들을 보완하기 위해 만들어졌다.
- 학습하는 동안 learning_rate가 감소하는 문제
- 수동으로 global learning rate를 설정해 주어야하는 문제
Adagrad와 비교하여 이전까지의 gradient를 누적하는 것보다, 동적인 gradient 업데이트를 가져가 learning_rate를 조정하는 방법을 채택하고 있다. 덕분에 Adadelta를 사용할 때는, gradient의 업데이트가 매우 많이 이루어지더라도 안정적으로 학습을 할 수 있다는 장점이있다.
아래와 같이 tf.keras.optimizers의 매소드로 사용가능하며, 주요 하이퍼파라미터로는 learning_rate, rho, epsilon이 존재한다.
# Adadelta 코드 예제
tf.keras.optimizers.Adadelta(
learning_rate=0.001, rho=0.95, epsilon=1e-07, name="Adadelta", **kwargs
)
Adamax
Adam기법의 일종으로써 무한 노름(infinity norm)을 기반으로한다. 그렇기 때문에 embedding같이 벡터화 기법을 사용하는 모델을 활용할 때 Adam보다 더 높은 성능을 낼 수도 있다. 기본적으로 아래 3가지 파라미터를 초기화 시켜주어야 한다.
- m = 0, 첫 번째 moment 벡터 초기화
- v = 0, 지수 가중화(exponentially weighted)되는 무한 노름의 초기화
- t = 0, timestep 초기화
위 3가지 초기값을 바탕으로 Adamax가 가중치를 업데이트하는 방법(학습)을 나타낸다면 아래와 같다.
# Adamax 가중치 업데이트 방식
t += 1
m = beta1 * m + (1 - beta) * g
v = max(beta2 * v, abs(g))
current_lr = learning_rate / (1 - beta1 ** t)
w = w - current_lr * m / (v + epsilon)
Adam의 경우 처럼, v_t ==0 일때, 그 어떤 수도 0으로 나뉘어지는 것을 epsilon이 방지한다. Adam과의 차이점이라면, Adamax는 순방향(forward pass)에서 사용된 해당 변수 부분의 m_t, v_t 값과 slices 만을 업데이트한다. 이는 특정 변수의 slice가 실제로 사용되었을 경우를 제외하고는 momentum을 무시하는 구조라고 할 수 있다.
아래와 같이 learning_rate와 epsilon을 설정할 수 있고, 지수단위의 규제비율을(exponential decay rate) 첫 번째 moment와 무한 노름에 대해, 각각 beta_1과 beta_2로 설정할 수 있다.
# Adamax 코드 예제tf.keras.optimizers.Adamax(
learning_rate=0.001, beta_1=0.9, beta_2=0.999, epsilon=1e-07, name="Adamax", **kwargs
)
Nadam
Adam은 RMSprop에 momentum를 활용하여 적용한 것이라고 볼 수 있다. Nadam은 Adam에 일반 momentum이 아닌, Nesterov momentum를 활용하여 적용한 최적화 기법이라고 보면된다.
Adamax와 같이 learning_rate와 epsilon 및 beta_1, beta_2 등의 하이퍼파라미터가 존재한다. 기본적으로 모든 파라미터의 종류와 목적은 Adamax와 같다.
# Nadam 코드 예제
tf.keras.optimizers.Nadam(
learning_rate=0.001, beta_1=0.9, beta_2=0.999, epsilon=1e-07, name="Nadam", **kwargs
)
Ftrl
Follow the Regularized Leader(Ftrl)의 준말이다. 아래 수식을 활용하여 뎅터를 업데이트 한다.
위 수식에서 G(1:t)는 이전 sub-gradient들의 평균을 의미한다. 다른 차원 마다 learning rate가 다르게 존재한다는 점에서 Adadelta처럼 다른 최적화 기법의 단점을 해결한 기법이라고 볼 수 있다. 학습 중 차원 ‘j’보다 차원’i’가 더 큰 step으로 진행되어야 할때, 그러한 필요를 충족시키는 방향으로 learning rate를 규제할 수 있다.
아래와 같이 learning _rate 뿐만 아니라 learning_rate_power를 설정하여 learning rate를 학습 중 규제하는 것이 가능하다. 이를 ‘0’으로 설정하면 learning rate를 규제하지 않는다는 뜻이다. Adagrad와 같이 initial accumulator value를 통해 초기 누적값을 설정해 줄 수 있다(0 이상의 실수). 위 수식에서 나타나는 것처럼, Beta는 learning rate의 규제를 위해 설정할 수 있는 또 다른 파라미터다.
또한 이전에 언급한 규제(regularization)기법을 사용하는 알고리즘이기 때문에, L1/L2 regularization을 사용한다. 이에 대한 레벨은 “l1/l2_regularization_strength”를 통해 설정 가능하다. 단, l2_regularization_strength는 안정화에 대한 penalty를 설정하는 것이라면, “l2_shrinkage_regularization_strength”의 경우, magnitude에 대한 penalty를 설정한다는 차이가 있다.
아래는 FTRL 코드의 예제이다.
# FTRL 코드 예제
tf.keras.optimizers.Ftrl(
learning_rate=0.001,
learning_rate_power=-0.5,
initial_accumulator_value=0.1,
l1_regularization_strength=0.0,
l2_regularization_strength=0.0,
name="Ftrl",
l2_shrinkage_regularization_strength=0.0,
beta=0.0,
**kwargs
)
앞으로 할일:
오늘은 Keras에서 제공하는 다양한 optimizer들과 각각의 특징들에 대해 알아보았다. 얼마나 모델의 최적화가 중요하면 이런 최적화 도구까지 따로 만들어 두었는가 싶다. 딥러닝에서 가장 널리 사용되는 Keras 라이브러리에서도 딥러닝 모델을 만들 때, 사용자가 모델을 최대한 최적화 할 수 있도록 얼마나 많은 도구를 제공하려 노력하는지 엿보인다.
오늘 글은 현재 Keras에서 다루는 모든 최적화 기법을 간략하게 다룬 것이라, 디테일이 부족할 수 있다. 좀 더 알고 싶은 이들은 Keras의 documentation이나, Towards Data Science에 올라오는 다양한 블로그를 찾아보는 것을 추천한다.
사실 나도 오늘 글을 쓰기 위해 공부한 내용만 가지고 모든 최적화 기법을 충분히 이해했다고 말하기는 어렵다. 하지만, 앞으로 딥러닝 모델을 다룰 때 많이 사용하게 될 것들인 만큼, 기본적으로 각 최적화 기법의 특징과 각각의 차이점을 정리해 두는 것이 도움이 될 것이라 생각했다.
이번 주말 동안 딥러닝 관련 공부를 하면서, 정말 이 분야는 그 어떤 분야보다 알아야하고 배울 것이 많다고 느꼈다. 딥러닝이라는 바다에 나오니 새로운 눈을 뜨게 되었다. 알아야 할 것은 많지만, 그만큼 호기심과 흥미도 더 커졌다. 이 태도를 유지하여, 앞으로도 딥러닝에 대한 지식을 더 쌓아 나갈 수 있도록 노력하겠다. 아무리 어렵더라도 이전의 편안했던 우물보다, 드디어 찾은 이 바다에서 계속 헤엄치고 싶다. 다시 한번 이 바다를 발견할 수 있었던 것에, 또 여기서 앞으로 더 많은 것들을 볼 수 있음에 감사하다.
참조:
(1) https://pyimagesearch.com/wp-content/uploads/2019/08/keras_learning_rate_finder_header.png
(2) https://towardsdatascience.com/understanding-rmsprop-faster-neural-network-learning-62e116fcf29a