天天看點

pytorch 動态調整學習率

訂閱專欄

背景

深度煉丹如同炖排骨一般,需要先大火全局加熱,緊接着中火炖出營養,最後轉小火收汁。

本文給出煉丹中的 “火候控制器”-- 學習率的幾種調節方法,架構基于

pytorch

1. 自定義根據 epoch 改變學習率。

這種方法在開源代碼中常見,此處引用 pytorch 官方執行個體中的代碼

adjust_lr
1. def adjust_learning_rate(optimizer, epoch):
2. """Sets the learning rate to the initial LR decayed by 10 every 30 epochs"""
3.     lr = args.lr * (0.1 ** (epoch // 30))
4. for param_group in optimizer.param_groups:
5.         param_group['lr'] = lr      

注釋:在調用此函數時需要輸入所用的 optimizer 以及對應的 epoch ,并且 args.lr 作為初始化的學習率也需要給出。

使用代碼示例:

1. optimizer = torch.optim.SGD(model.parameters(),lr = args.lr,momentum = 0.9)
2. for epoch in range(10):
3.     adjust_learning_rate(optimizer,epoch)
4.     train(...)
5.     validate(...)      

2. 針對模型的不同層設定不同的學習率

當我們在使用預訓練的模型時,需要對分類層進行單獨修改并進行初始化,其他層的參數采用預訓練的模型參數進行初始化,這個時候我們希望在進行訓練過程中,除分類層以外的層隻進行微調,不需要過多改變參數,是以需要設定較小的學習率。而改正後的分類層則需要以較大的步子去收斂,學習率往往要設定大一點以 resnet101 為例,分層設定學習率。

1. model = torchvision.models.resnet101(pretrained=True)
2. large_lr_layers = list(map(id,model.fc.parameters()))
3. small_lr_layers = filter(lambda p:id(p) not in large_lr_layers,model.parameters())
4. optimizer = torch.optim.SGD([
5.             {"params":large_lr_layers},
6.             {"params":small_lr_layers,"lr":1e-4}
7.             ],lr = 1e-2,momenum=0.9)      

注:large_lr_layers 學習率為 1e-2,small_lr_layers 學習率為 1e-4,兩部分參數共用一個 momenum

3. 根據具體需要改變 lr

以前使用 keras 的時候比較喜歡 ReduceLROnPlateau 可以根據 損失或者 準确度的變化來改變 lr。最近發現 pytorch 也實作了這一個功能。

class torch.optim.lr_scheduler.ReduceLROnPlateau(optimizer, mode='min', factor=0.1, patience=10, verbose=False, threshold=0.0001, threshold_mode='rel', cooldown=0, min_lr=0, eps=1e-08)      

以 acc 為例,當 mode 設定為 “max” 時,如果 acc 在給定 patience 内沒有提升,則以 factor 的倍率降低 lr。

使用方法示例:

1. optimizer = torch.optim.SGD(model.parameters(), lr=0.1, momentum=0.9)
2. scheduler = ReduceLROnPlateau(optimizer, 'max',verbose=1,patience=3)
3. for epoch in range(10):
4.     train(...)
5.     val_acc = validate(...)
6. # 降低學習率需要在給出 val_acc 之後
7.     scheduler.step(val_acc)      

4. 手動設定 lr 衰減區間

使用方法示例

1. def adjust_learning_rate(optimizer, lr):
2. for param_group in optimizer.param_groups:
3.         param_group['lr'] = lr
4. 
5. for epoch in range(60):        
6.     lr = 30e-5
7. if epoch > 25:
8.         lr = 15e-5
9. if epoch > 30:
10.         lr = 7.5e-5
11. if epoch > 35:
12.         lr = 3e-5
13. if epoch > 40:
14.         lr = 1e-5
15.     adjust_learning_rate(optimizer, lr)      

5. 餘弦退火

論文:

SGDR: Stochastic Gradient Descent with Warm Restarts
1. epochs = 60
2. optimizer = optim.SGD(model.parameters(),lr = config.lr,momentum=0.9,weight_decay=1e-4) 
3. scheduler = lr_scheduler.CosineAnnealingLR(optimizer,T_max = (epochs // 9) + 1)
4. for epoch in range(epochs):
5.     scheduler.step(epoch)      

目前最常用的也就這麼多了,當然也有很多其他類别,詳情見

how-to-adjust-learning-rate

參考文獻

繼續閱讀