深度學習訓練過程中的學習率衰減策略及pytorch實現

gnnu_cv發表於2022-03-29

學習率是深度學習中的一個重要超引數,選擇合適的學習率能夠幫助模型更好地收斂。

本文主要介紹深度學習訓練過程中的6種學習率衰減策略以及相應的Pytorch實現。

1. StepLR

  • 按固定的訓練epoch數進行學習率衰減。
  • 舉例說明:

# lr = 0.05 if epoch < 30

# lr = 0.005 if 30 <= epoch < 60

# lr = 0.0005 if 60 <= epoch < 90

在上述例子中,每30個epochs衰減十倍學習率。

  • 計算公式和pytorch計算程式碼如下:

def _get_closed_form_lr(self):
    return [base_lr * self.gamma ** (self.last_epoch // self.step_size)
            for base_lr in self.base_lrs]
  • pytorch呼叫及相關引數:
torch.optim.lr_scheduler.StepLR(optimizer, step_size, gamma=0.1, last_epoch=- 1, verbose=False)

optimizer:表示使用的優化器;
step_size:表示學習率調整步長;
gamma:表示學習率衰減乘法因子,預設:0.1;
last_epoch:表示上一個epoch數,預設:-1,此時學習率的值為初始學習率;
verbose:表示是否每次更新都輸出一次學習率的值,預設:False。

  • 程式碼示例及結果展示:
lr_scheduler=torch.optim.lr_scheduler.StepLR(optimizer,step_size=3,gamma=0.1,last_epoch=-1)

設定10個epoch時,輸出訓練過程中的學習率如下:

  

2. MultiStepLR

  • 當epoch數達到固定數值進行學習率衰減。
  • 舉例說明:

# milestones=[30,80]

# lr = 0.05 if epoch < 30

# lr = 0.005 if 30 <= epoch < 80

# lr = 0.0005 if epoch >= 80 

在上述例子中,當epoch達到milestones中的數值時進行學習率衰減。

  • 計算公式和pytorch計算程式碼如下:

 

其中bisect_right函式表示epoch數插入milestones中列表的位置,

例如:milstones=[2,5,8]

last_epoch==1→bisect_right(milestones,last_epoch)=0;

last_epoch==3→bisect_right(milestones,last_epoch)=1;

last_epoch==6→bisect_right(milestones,last_epoch)=2;

def _get_closed_form_lr(self):
        milestones = list(sorted(self.milestones.elements()))
        return [base_lr * self.gamma ** bisect_right(milestones, self.last_epoch)
                for base_lr in self.base_lrs]
  • pytorch呼叫及相關引數:
torch.optim.lr_scheduler.MultiStepLR(optimizer, milestones, gamma=0.1, last_epoch=- 1, verbose=False)

milestones:一個關於epoch索引的列表,當epoch值達到列表中的數值時進行學習率衰減。

其他引數相同。

  • 程式碼示例及結果展示:
lr_scheduler=torch.optim.lr_scheduler.MultiStepLR(optimizer,milestones=[2,5,8],gamma=0.1,last_epoch=-1)

3. ExponentialLR

  • 根據當前epoch進行學習率衰減
  • 計算公式和pytorch計算程式碼如下:

def _get_closed_form_lr(self):
      return [base_lr * self.gamma ** self.last_epoch
              for base_lr in self.base_lrs]
  • pytorch呼叫及相關引數:
torch.optim.lr_scheduler.ExponentialLR(optimizer, gamma, last_epoch=- 1, verbose=False) 
  • 程式碼示例及結果展示:
lr_scheduler=torch.optim.lr_scheduler.ExponentialLR(optimizer,gamma=0.1,last_epoch=-1)



4. linearLR

  • 在epoch數達到total_iters數值之前,使用線性改變乘法因子衰減學習率。
  • 計算公式和pytorch計算程式碼如下:

def _get_closed_form_lr(self):
        return [base_lr * (self.start_factor +
                (self.end_factor - self.start_factor) * min(self.total_iters, self.last_epoch) / self.total_iters)
                for base_lr in self.base_lrs]
  • pytorch呼叫及相關引數:
torch.optim.lr_scheduler.LinearLR(optimizer, start_factor=0.3333333333333333, end_factor=1.0, total_iters=5, last_epoch=- 1, verbose=False)
start_factor: 在第一個epoch中乘以base_lr的數值,預設1/3;
end_factor:線上性變化過程結束時乘以base_lr的數值,預設:1;
total_iters:乘法因子達到1的迭代次數,預設:5。
  • 舉例說明:
lr_scheduler = LinearLR(optimizer, start_factor=0.5, total_iters=4)
base_lr=0.05
# epoch == 0→lr = base_lr * start_factor = 0.05 * 0.5=0.025;
# epoch == 1→lr = 0.05 * (0.5 + 0.5 * 0.25) = 0.3125;
......
# epoch ≥ 4→lr = base_lr * end_factor = 0.05(當epoch數等於total_iters時,
min(self.total_iters, self.last_epoch) / self.total_iters = 1)

5. ConstantLR

  • 在epoch數達到total_iters數值之前,使用常數因子衰減學習率。
  • 計算公式和pytorch計算程式碼如下:

    def _get_closed_form_lr(self):
        return [base_lr * (self.factor + (self.last_epoch >= self.total_iters) * (1 - self.factor))
                for base_lr in self.base_lrs]
  • pytorch呼叫及相關引數:
torch.optim.lr_scheduler.ConstantLR(optimizer, factor=0.3333333333333333, total_iters=5, last_epoch=- 1, verbose=False)

 factor:在epoch達到total_iters之前,學習率乘以的常數因子,預設1/3;

 total_iters:衰減學習率的步數。

  • 舉例說明:

lr_scheduler = ConstantLR(self.opt, factor=0.5, total_iters=4)

base_lr = 0.05

# epoch == 0 → lr = base_lr * (factor + 0 * (1-factor)) = 0.05 *  0.5 = 0.025

......

# epoch == 4 → lr = base_lr * (factor + 1 - factor) = 0.05 

6. LambdaLR

  • 使用lambda定義的函式衰減學習率。
  • 計算公式和pytorch計算程式碼如下:

 

    def get_lr(self):
        if not self._get_lr_called_within_step:
            warnings.warn("To get the last learning rate computed by the scheduler, "
                          "please use `get_last_lr()`.")

        return [base_lr * lmbda(self.last_epoch)
                for lmbda, base_lr in zip(self.lr_lambdas, self.base_lrs)]
  • pytorch呼叫及相關引數:
torch.optim.lr_scheduler.LambdaLR(optimizer, lr_lambda, last_epoch=- 1, verbose=False)

lr_lambda:當給定epoch數,計算乘法因子的函式(可以自己定義)

  • 程式碼示例及結果展示:
lr_scheduler=torch.optim.lr_scheduler.LambdaLR(optimizer,lr_lambda=lambda epoch:epoch/30 )

 

 

7. MultiplicativeLR

  • 同樣是使用了與epoch有關的lambda函式,與LambdaLR不同的地方在於,它是對old_lr更新。
  • 計算公式和pytorch計算程式碼如下:

def get_lr(self):
        if not self._get_lr_called_within_step:
            warnings.warn("To get the last learning rate computed by the scheduler, "
                          "please use `get_last_lr()`.", UserWarning)

        if self.last_epoch > 0:
            return [group['lr'] * lmbda(self.last_epoch)
                    for lmbda, group in zip(self.lr_lambdas, self.optimizer.param_groups)]
        else:
            return [group['lr'] for group in self.optimizer.param_groups]
  • pytorch呼叫及相關引數:
torch.optim.lr_scheduler.MultiplicativeLR(optimizer, lr_lambda, last_epoch=- 1, verbose=False)

 

8.CosineAnnealingLR

  • 模擬餘弦退火曲線調整學習率
  • 計算公式和pytorch計算程式碼如下:

 

def _get_closed_form_lr(self):
     return [self.eta_min + (base_lr - self.eta_min) *
           (1 + math.cos(math.pi * self.last_epoch / self.T_max)) / 2
                for base_lr in self.base_lrs]
  • pytorch呼叫及相關引數:
torch.optim.lr_scheduler.CosineAnnealingLR(optimizer, T_max, eta_min=0, last_epoch=- 1, verbose=False)

T_max:最大迭代次數,一次學習率週期的迭代次數。

eta_min:最小學習率,預設:0。

  • 程式碼示例及結果展示:
lr_scheduler=torch.optim.lr_scheduler.CosineAnnealingLR(optimizer,T_max=3,eta_min=0)

base_lr=0.01

當epoch是T_max的奇數倍時,學習率會下降到最小值eta_min。

 

9. ChainedScheduler

  • 可以呼叫其他學習率調整策略。
  • pytorch呼叫及相關引數:
torch.optim.lr_scheduler.ChainedScheduler(schedulers)

schedules:設定的其他學習率調整策略,可以是一個包含多個學習率調整策略的列表

  • 程式碼示例及結果:
scheduler1 = ConstantLR(self.opt, factor=0.1, total_iters=2)
scheduler2 = ExponentialLR(self.opt, gamma=0.9)
lr_scheduler = ChainedScheduler([scheduler1, scheduler2])

schedules裡的學習率調整策略同時使用

base_lr = 1

# lr = 0.09 if epoch == 0 (先使用scheduler2策略得到lr = 0.9;再使用scheduler1策略得到最終new_lr = 0.09)

# lr = 0.081 if epoch == 1

# lr = 0.729 if epoch == 2

# lr = 0.6561 if epoch == 3

# lr = 0.59049 if epoch >= 4

10.SequentialLR

  • 與ChainedScheduler在每一個epoch中同時呼叫schedules中的學習率策略不同的是,SequentialLR針對epoch按順序呼叫schedules中的學習率策略。
  • pytorch呼叫及相關引數:
torch.optim.lr_scheduler.SequentialLR(optimizer, schedulers, milestones, last_epoch=- 1, verbose=False)
  • 程式碼示例及結果:
scheduler1 = ConstantLR(self.opt, factor=0.1, total_iters=2)
scheduler2 = ExponentialLR(self.opt, gamma=0.9)
lr_scheduler = SequentialLR(optimizer, schedulers=[scheduler1, scheduler2], milestones=[2])

base_lr = 1

# lr = 0.1 if epoch == 0

# lr = 0.1 if epoch == 1

# lr = 0.9 if epoch == 2

# lr = 0.81 if epoch == 3

# lr = 0.729 if epoch == 4

epoch<milestones,呼叫scheduler1學習率調整策略,epoch≥milestones,呼叫scheduler2學習率調整策略。

 

11.ReduceLROnPlateau

  • 當訓練指標不再改進時,調整學習率。
  • pytorch呼叫及相關引數:
torch.optim.lr_scheduler.ReduceLROnPlateau(optimizer, mode='min', factor=0.1, patience=10, threshold=0.0001, threshold_mode='rel', cooldown=0, min_lr=0, eps=1e-08, verbose=False)

mode:有min、max兩種模式,在 min 模式下,當指標的數量停止減少時(如loss),學習率將減少; 在max模式下,當指標的數量停止增加時(如accuracy),學習率將減少,預設值:min;

factor:學習率減少的倍數,new_lr = old_lr * factor,預設:0.1;

patience:指標沒有提升的epoch數,之後降低學習率。例如,patience = 2,會忽略前 2 個沒有改善的 epoch,並且只有在第 3 個 epoch 之後指標仍然沒有改善的情況下降低 學習率。 預設值:10。

threshold:衡量新的最佳閾值,只關注重大變化。 預設值:1e-4。

threshold_mode:有rel、abs兩種模式,

cooldown:在 學習率減少後恢復正常操作之前要等待的 epoch 數。 預設值:0。

min_lr:標量或標量列表。學習率的下限。 預設值:0。

eps:應用於 學習率的最小衰減。 如果新舊 學習率之間的差異小於 eps,則忽略更新。 預設值:1e-8。

  • 程式碼示例及結果:
lr_scheduler=torch.optim.lr_scheduler.ReduceLROnPlateau(optimizer,mode='min',patience=2,cooldown=2)

 

第一個epoch是初始學習率;

設定patience = 2,即指標在經歷3個epoch後仍然沒有提升,衰減學習率,new_lr = old_lr * factor(0.1),如圖中第4個epoch時開始衰減學習率;

設定cooldown = 2,即衰減學習率後有2個epoch的cooldown時期(5、6epoch),在cooldown時期不進行patience階段的epoch計數;

cooldown時期結束恢復patience階段epoch計數(圖中從第7個epoch開始計數,在第10個epoch學習率衰減)。

 

12.CyclicLR

  • 根據迴圈學習策略設定學習率。(每訓練一個batch,更新一次學習率)
  • 在《 Cyclical Learning Rates for Training Neural Networks》這篇文章中有詳細描述。
  • pytorch呼叫及相關引數:
torch.optim.lr_scheduler.CyclicLR(optimizer, base_lr, max_lr, step_size_up=2000, step_size_down=None, mode='triangular', gamma=1.0, scale_fn=None, scale_mode='cycle', cycle_momentum=True, base_momentum=0.8, max_momentum=0.9, last_epoch=- 1, verbose=False)

base_lr:初始學習率,迴圈中的學習率下邊界;

max_lr:每個引數組在迴圈中的上層學習率邊界。從功能上講,它定義了週期幅度 (max_lr - base_lr)。任何週期的 lr 是 base_lr 和一些幅度縮放的總和;因此 max_lr 實際上可能無法達到,具體取決於縮放函式。

step_size_up:在一個週期增加的一半中訓練迭代的次數。預設值:2000;

step_size_down:迴圈減半中的訓練迭代次數。如果 step_size_down 為 None,則設定為 step_size_up。預設值:None;

mode:包含三種{triangular, triangular2, exp_range} ,如果 scale_fn 不是 None,則忽略此引數。預設值:“triangular”;

gamma:‘exp_range’ 縮放函式中的常數:gamma**(cycle iterations)預設值:1.0;

scale_fn:由單個引數 lambda 函式定義的自定義縮放策略,其中 0 <= scale_fn(x) <= 1 for all x >= 0。如果指定,則忽略“mode”。預設值:None;

scale_mode:{‘cycle’, ‘iterations’}。定義是否在cycle number或cycle iterations (training iterations since start of cycle)上評估 scale_fn。預設值:cycle;

cycle_momentum:如果為真,則動量與“base_momentum”和“max_momentum”之間的學習率成反比。預設值:True;

base_momentum: 迴圈中的動量下邊界,預設值:0.8;

max_monmentum:迴圈中的動量上邊界,預設值:0.9;

  • 官方程式碼及示例:
 optimizer = torch.optim.SGD(model.parameters(), lr=0.1, momentum=0.9)
 scheduler = torch.optim.lr_scheduler.CyclicLR(optimizer, base_lr=0.01, max_lr=0.1)
 data_loader = torch.utils.data.DataLoader(...)
       for epoch in range(10):
           for batch in data_loader:
                 train_batch(...)
                 scheduler.step()

 

13.OneCycleLR

  • 根據迴圈學習策略設定學習率。(每訓練一個batch,更新一次學習率)
  • 相關文章《Super-Convergence: Very Fast Training of Neural Networks Using Large Learning Rates》
  • pytorch呼叫及相關引數:
torch.optim.lr_scheduler.OneCycleLR(optimizer, max_lr, total_steps=None, epochs=None, steps_per_epoch=None, pct_start=0.3, anneal_strategy='cos', cycle_momentum=True, base_momentum=0.85, max_momentum=0.95, div_factor=25.0, final_div_factor=10000.0, three_phase=False, last_epoch=- 1, verbose=False)

max_lr:在迴圈中的上層學習率邊界;

total_steps:迴圈總步數。如果此處未提供值,則必須通過提供 epochs 和 steps_per_epoch 的值來推斷。預設值:None;

epochs:訓練的epochs;

steps_per_epoch:每個 epoch 訓練的步數;

pct_start:提高學習率所花費的週期百分比(in number of steps)。預設值:0.3;

anneal_strategy:{‘cos’, ‘linear’} 指定退火策略:“cos”表示餘弦退火,“linear”表示線性退火。預設值:'cos';

div_factor:通過 initial_lr = max_lr/div_factor 確定初始學習率 預設值:25;

final_div_factor:通過 min_lr = initial_lr/final_div_factor 確定最小學習率 預設值:1e4;

three_phase:如果為 True,則使用計劃的第三階段根據“final_div_factor”消除學習率,而不是修改第二階段(前兩個階段將關於“pct_start”指示的步驟對稱)。

  • 官方程式碼及示例:
 data_loader = torch.utils.data.DataLoader(...)
     optimizer = torch.optim.SGD(model.parameters(), lr=0.1, momentum=0.9)
     scheduler = torch.optim.lr_scheduler.OneCycleLR(optimizer, max_lr=0.01, steps_per_epoch=len(data_loader), epochs=10)
     for epoch in range(10):
         for batch in data_loader:
            train_batch(...)
            scheduler.step() 

 

14.CosineAnnealingWarmRestarts

  • 和餘弦退火類似,多了warmrestart操作。
  • pytorch呼叫及相關引數:
torch.optim.lr_scheduler.CosineAnnealingWarmRestarts(optimizer, T_0, T_mult=1, eta_min=0, last_epoch=- 1, verbose=False)

T_0:第一次restart的迭代次數;

T_mult:在一次restar後,因子增加:math:`T_{i};

eta_min:最小學習率,預設值:0。

  • 官方程式碼及示例
 scheduler = CosineAnnealingWarmRestarts(optimizer, T_0, T_mult)
                 iters = len(dataloader)
                 for epoch in range(20):
                     for i, sample in enumerate(dataloader):
                         inputs, labels = sample['inputs'], sample['labels']
                         optimizer.zero_grad()
                         outputs = net(inputs)
                         loss = criterion(outputs, labels)
                         loss.backward()
                         optimizer.step()
                         scheduler.step(epoch + i / iters)

 

參考及引用:

1.https://pytorch.org/docs/stable/optim.html#how-to-adjust-learning-rate

2.https://zhuanlan.zhihu.com/p/352744991

3.https://blog.csdn.net/qyhaill/article/details/103043637

 

相關文章