본문 바로가기

ML&DL/PyTorch

[PyTorch] PyTorch가 제공하는 Learning rate scheduler 정리

 

(여기 내용을 많이 참고하여 작성하였습니다.)

(** learning rate와 lr이라는 용어를 혼용해서 작성하였습니다.)

 

learning rate는 gradient의 보폭을 말한다. learning rate는 성능에 꽤나 영향을 주는 요소(learning rate를 잘못 설정하면 아예 학습이 안되기도 한다.)이기 때문에 learning rate를 어떻게 설정할 지가 중요하다. 아래의 그림이 learning rate 설정에 따라 loss 그래프에서 어떻게 최적의 weight를 찾아나가는 지를 보여준다.

 

 

처음부터 끝까지 같은 learning rate를 사용할 수도 있지만, 학습과정에서 learning rate를 조정하는 learning rate scheduler를 사용할 수도 있다. 처음엔 큰 learning rate(보폭)으로 빠르게 optimize를 하고 최적값에 가까워질수록 learning rate(보폭)를 줄여 미세조정을 하는 것이 학습이 잘된다고 알려져있다. learning rate를 decay하는 방법이외에도 learning rate를 줄였다 늘렸다 하는 것이 더 성능향상에 도움이 된다는 연구결과도 있다. 

 

PyTorch에서는 기본적으로 다양한 learning rate scheduler를 제공하고 있다. 어떤 learning rate scheduler가 있는지 알아보자. (**모든 learning rate curve는 100epoch을 기준으로 plot했다.)

How to use learning rate scheduler? 

optimizer와 scheduler를 먼저 정의한 후, 학습할 때 batch마다 optimizer.step() 하고 epoch마다/batch마다 원하는  부분에서 scheduler.step()을 해주면 된다. 대략적인 코드를 작성하면 아래와 같은 흐름이다.

(**만약 로더 내에서 scheduler를 쓸 때, optimizer 먼저 scheduler 나중에 업뎃하면 user warning 뜬다.)

 

import torch
import torch.nn as nn
import torch.optim as optim
from data import AudioDataset, AudioDataLoader
from matplotlib import pyplot as plt

class Model(nn.Module):
    def __init__(self):
        super(Model, self).__init__()
        self.linear = nn.Linear(10, 10)
        self.activation = nn.ReLU()
    def forward(self, x):
        return self.activation(self.linear1(x))

# data
tr_dataset = AudioDatset('tr')
data_loader = AudioDataLoader(tr_dataset, batch_size=3, shuffle=1)
# model
model = Model()
# loss
loss = nn.MSELoss()
# optimizer
optimizer = optim.Adam(model.parameters(), lr=1e-3)
#scheduler
scheduler = optim.lr_scheduler.LambdaLR(optimizer=optimizer,
                                        lr_lambda=lambda epoch: 0.95 ** epoch,
                                        last_epoch=-1,
                                        verbose=False)

epochs=100
for epoch in range(epochs):
    for i, (data) in enumerate(data_loader):
        x_data, y_data = data
        optimizer.zero_grad()
    
        estimated_y = model(x_data)
        loss = loss(y_data, estimated_y)
        loss.backward()
        optimizer.step()
    scheduler.step() # you can set it like this!

 

다음과 같이 파라미터그룹에서 lr을 찾아서 lr의 변화를 찍어볼 수 있다.

 

...
print("lr: ", optimizer.param_groups[0]['lr'])

공통 parameters

  • last_epoch: default:-1로 설정하면 initial_lr 이 lr이 된다. (모델 저장 후 시작때 어떻게 설정할 것인가)
  • verbose: default:False, True로 설정하면 update될 때 메세지를 출력한다.

LambdaLR

Lambda 표현식으로 작성한 함수를 통해 learning rate를 조절한다. 초기 learning rate에 lambda함수에서 나온 값을 곱해줘서 learning rate를 계산한다.

 

 

optimizer = torch.optim.SGD(model.parameters(), lr=0.001)
scheduler = optim.lr_scheduler.LambdaLR(optimizer=optimizer,
                                        lr_lambda=lambda epoch: 0.95 ** epoch)

Parameters

  • optimizer: 이전에 정의한 optimizer 변수명을 넣어준다.
  • lr_lambda: lr에 곱해질 factor를 정하는 함수

MultiplicativeLR

Lambda 표현식으로 작성한 함수를 통해 learning rate를 조절한다. 초기 learning rate에 lambda함수에서 나온 값을 누적곱해서 learning rate를 계산한다.

 

 

optimizer = torch.optim.SGD(model.parameters(), lr=0.001)
scheduler = optim.lr_scheduler.MultiplicativeLR(optimizer=optimizer,
                                                lr_lambda=lambda epoch: 0.95 ** epoch)

Parameters

  • optimizer: 이전에 정의한 optimizer 변수명을 넣어준다.
  • lr_lambda: lr에 곱해질 factor를 정하는 함수

StepLR

step size마다 gamma 비율로 lr을 감소시킨다. (step_size 마다 gamma를 곱한다.)

 

 

optimizer = torch.optim.SGD(model.parameters(), lr=0.001)
scheduler = optim.lr_scheduler.StepLR(optimizer, step_size=10, gamma=0.5)

Parameters

  • optimizer: 이전에 정의한 optimizer 변수명을 넣어준다.
  • step_size: 몇 epoch마다 lr을 감소시킬지가 step_size를 의미한다.
  • gamma: gamma 비율로 lr을 감소시킨다.

MultiStepLR

step size가 아니라 learning rate를 감소시킬 epoch을 지정해줌

 

 

optimizer = torch.optim.SGD(model.parameters(), lr=0.001)
scheduler = optim.lr_scheduler.MultiStepLR(optimizer, milestones=[30,80], gamma=0.5)

Parameters

  • optimizer: 이전에 정의한 optimizer 변수명을 넣어준다.
  • milestones: learning rate 줄일 epoch index의 list
  • gamma: gamma 비율로 lr을 감소시킨다.

ExponentialLR

learing rate decay가 exponential함수를 따른다.

 

 

optimizer = torch.optim.SGD(model.parameters(), lr=0.0001)
scheduler = optim.lr_scheduler.ExponentialLR(optimizer, gamma=0.5)

Parameters

  • optimizer: 이전에 정의한 optimizer 변수명을 넣어준다.
  • gamma: lr을 감소시킬 때, 곱해지는 factor

CosineAnnealingLR

learing rate가 cos함수를 따라서 eat_min까지 떨어졌다 다시 초기 learning rate까지 올라온다.

 

 

optimizer = torch.optim.SGD(model.parameters(), lr=0.001)
scheduler = optim.lr_scheduler.CosineAnnealingLR(optimizer, T_max=50, eta_min=0)

Parameters

  • optimizer: 이전에 정의한 optimizer 변수명을 넣어준다.
  • T_max: 최대 iteration 횟수
  • eta_min: 최소로 떨어질 수있는 learning rate default=0

T_max=10
T_max=20

ReduceLROnPlateau

성능이 향상이 없을 때 learning rate를 감소시킨다. 그렇기 때문에 validation loss나 metric(평가지표)을 learning rate step함수의 input으로 넣어주어야 한다. 그래서 metric이 향상되지 않을 때, patience횟수(epoch)만큼 참고 그 이후에는 learning rate를 줄인다. optimizer에 momentum을 설정해야 사용할 수 있다.

 

optimizer = torch.optim.SGD(model.parameters(), lr=0.01, momentum=0.9)
scheduler = ReduceLROnPlateau(optimizer, 'min')
for epoch in range(100):
     train(...)
     val_loss = validate(...)
     # Note that step should be called after validate()
     scheduler.step(val_loss)

Parameters

  • optimizer: 이전에 정의한 optimizer 변수명을 넣어준다.
  • mode: 'min'이나 'max'중 하나의 모드로 설정한다. min은 metric이 감소를 멈출 때/ max는 metric이 증가를 멈출 때
  • factor: 감소시킬 비율 lr*factor default:0.1
  • patience: metric이 향상 안될 때, 몇 epoch을 참을 것인가?
  • threshold: 새로운 optimum이 될 수 있는 threshold (얼마 차이나면 optimum update되었다고 볼 수 있나?)
  • threshold_mode: dynamic threshold를 설정할 수 있다. 'rel' 이나 'abs' 중 하나의 모드로 설정한다.  'rel'모드이면 min일 때, best(1-threshold)  max일 때, best(1+threshold)/ 'abs'모드이면 best+threshold
  • cool_down: lr이 감소한 후 몇 epoch동안 lr scheduler동작을 쉴지
  • min_lr: 최소 lr
  • eps: 줄이기 전, 줄인 후 lr의 차이가 eps보다 작으면 무시한다.

CyclicLR

성능이 향상이 없을 때 learning rate를 감소시킨다. 그렇기 때문에 validation loss나 metric(평가지표)을 learning rate step함수의 input으로 넣어주어야 한다. 그래서 metric이 향상되지 않을 때, patience횟수(epoch)만큼 참고 그 이후에는 learning rate를 줄인다. optimizer에 momentum을 설정해야 사용할 수 있다.

 

optimizer = torch.optim.SGD(model.parameters(), lr=0.001, momentum=0.9)
scheduler = torch.optim.lr_scheduler.CyclicLR(optimizer, base_lr=0.00005, 
                                              step_size_up=5, max_lr=0.0001, 
                                              gamma=0.5, mode='exp_range')

Parameters

  • optimizer: 이전에 정의한 optimizer 변수명을 넣어준다.
  • base_lr: 최소 lr
  • max_lr: 최대 lr
  • step_size_up: 증가하는 cycle의 반
  • step_size_down: 감소하는 cycle의 반. 설정안하면 step_size_up과 동일하게 설정된다.
  • mode: 'triangular', 'triangular2', 'exp_range' 중 택 1(아래 그림이 각각의 mode 의미함)
  • gamma: 'exp_range' 모드일 때 scalefunction (gamma**cycle iteration)
  • scale_fn: custom scaling할 수 있는 function 정의 이 옵션을 사용하면 mode무시
  • scale_mode: 
  • cycle_momentum: True이면 momentum이 lr과 반대방향으로 cycle (base_momentum~max_momentum)
  • base_momentum: 최소 momentum default:0.8
  • max_momentum: 최대 momentum default:0.9

triangular1
triangular2
exp_range

OneCycleLR

초기 learing rate에서 1cycle annealing하는 scheduler이다. 1주기 전략은 초기 learning rate에서 최대 learning rate까지 올라간 후 초기 learning rate보다 훨씬 낮은 learning rate로 annealing한다. (논문참고)

 

optimizer = torch.optim.SGD(model.parameters(), lr=0.001)
scheduler = torch.optim.lr_scheduler.OneCycleLR(optimizer, max_lr=0.1, 
                                                steps_per_epoch=10, epochs=10,anneal_strategy='linear')

Parameters

  • optimizer: 이전에 정의한 optimizer 변수명을 넣어준다.
  • max_lr: 최대 lr
  • total_steps: cycle의 total_steps
  • epochs: 훈련할 epoch수
  • steps_per_epoch: epoch당 step수
  • pct_start: learning rate를 언제까지 증가시킬지 epoch에 대한 비율로 나타냄 default:0.3 ex)100epoch일 때, 30epoch까지 증가
  • anneal_strategy: 'cos', 'linear' 중 택 1, default: cos
  • cycle_momentum: learning rate와 반대로 momentum cycle
  • base_momentum: 최소 momentum
  • max_momentum: 최대 momentum
  • div_factor: initial_lr = max_lr/div_factor 로 lr 초기화 default:25
  • final_div_factor: min_lr = initial_lr/final_div_factor로 결정 default:1e-4

cos
linear

CosineAnnealingWarmRestarts

cosine annealing 함수를 따르면서 Ti epoch마다 다시 시작한다.

 

 

optimizer = torch.optim.SGD(model.parameters(), lr=0.0001)
scheduler = torch.optim.lr_scheduler.CosineAnnealingWarmRestarts(optimizer, T_0=10, 
                                                                 T_mult=1, eta_min=0.00001)

Parameters

  • optimizer: 이전에 정의한 optimizer 변수명을 넣어준다.
  • T_0: 첫번째 restart를 위해 몇번 iteration이 걸리는가?
  • T_mult: restart 후에 T_i를 증가시키는 factor
  • eta_min: 최소 lr

Reference

www.kaggle.com/isbhargav/guide-to-pytorch-learning-rate-scheduling

pytorch.org/docs/stable/optim.html

greeksharifa.github.io/pytorch/2018/11/10/pytorch-usage-03-How-to-Use-PyTorch/

wjddyd66.github.io/pytorch/Pytorch-Problem/