every blog every motto: You can do more than you think.
记录余弦退火
import torch
import torch.nn as nn
from torch.optim.lr_scheduler import CosineAnnealingLR, CosineAnnealingWarmRestarts
import itertools
import matplotlib.pyplot as plt
class Tmodel(nn.Module):
def __init__(self):
super().__init__()
self.conv1 = nn.Conv2d(in_channels=3, out_channels=3, kernel_size=3)
def forward(self, x):
pass
model = Tmodel()
optimizer = torch.optim.Adam(model.parameters(), lr=0.1)
scheduler = CosineAnnealingWarmRestarts(optimizer, T_0=5)
print("初始化的学习率:", optimizer.defaults['lr'])
lr_list = [] # 把使用过的lr都保存下来,之后画出它的变化
for epoch in range(1, 31):
# train
optimizer.zero_grad()
optimizer.step()
print("第%d个epoch的学习率:%f" % (epoch, optimizer.param_groups[0]['lr']))
lr_list.append(optimizer.param_groups[0]['lr'])
scheduler.step()
# 画出lr的变化
plt.plot(list(range(1, 31)), lr_list)
plt.xlabel("epoch")
plt.ylabel("lr")
plt.title("learning rate's curve changes as epoch goes on!")
plt.show()
说明:
代码如之前相同,唯一不同的时,将默认的T_mult=1修改为T_mult=2,如下图所示:
scheduler = CosineAnnealingWarmRestarts(optimizer, T_0=5,T_mult=2)
T_0:为我们学习率恢复到初始值的迭代次数(epoch)
注意: 学习率恢复到初始值以后,T_0是会更新的,更新公式为:
T_0 = T_0 × T_mult
学习率会从初始值下降到一个最小值(这个最小值根据公式得出),我们这里把这样一个过程定义为“一轮”,从上面的测试中可以看到,
eta_min:最小学习率
我们将上面测试2代码中的如下代码:
片段1:
for epoch in range(1, 31):
# train
optimizer.zero_grad()
optimizer.step()
print("第%d个epoch的学习率:%f" % (epoch, optimizer.param_groups[0]['lr']))
lr_list.append(optimizer.param_groups[0]['lr'])
scheduler.step()
替换为:
说明: 因为我们一个epoch中包含多次迭代
片段2:
for epoch in range(1, 31):
# train
for it in range(1,3):
optimizer.zero_grad()
optimizer.step()
print("第%d个epoch,迭代:%d,学习率:%f" % (epoch,it, optimizer.param_groups[0]['lr']))
lr_list.append(optimizer.param_groups[0]['lr'])
scheduler.step()
替换前,“一轮”的变换为:
替换以后的的结果为:
我们发现其中的值是相同的,依次递减。实际上这个如下代码有关:
scheduler.step()
即我们调用依次,学习率更新一次。但是其中的默认参数为epoch,即,调用依次,参数epoch+1,这和官方文档中的第二份代码注释部分相同,如下:
我们知道,一个epoch表示将所有数据遍历一遍,其中包含多次迭代,正常代码如我们上面替换的所示,但依然有点问题,应该将如下代码添加参数,
scheduler.step()
正确做法如官网所示:
因此,我们将我们的片段2优化为如下:
片段3:
iters = 3
for epoch in range(1, 31):
# train
for it in range(iters):
optimizer.zero_grad()
optimizer.step()
print("第%d个epoch,迭代:%d,学习率:%f" % (epoch, it, optimizer.param_groups[0]['lr']))
lr_list.append(optimizer.param_groups[0]['lr'])
scheduler.step(epoch + it / iters)
这样做到每迭代一次更新一次,但更新幅度不会太大,如下:
最后,我们进行一次结果对比图的展示,如下:
[1] https://pytorch.org/docs/stable/generated/torch.optim.lr_scheduler.CosineAnnealingWarmRestarts.html?highlight=cosineannealingwarmrestarts#torch.optim.lr_scheduler.CosineAnnealingWarmRestarts
[2] https://blog.csdn.net/qq_37612828/article/details/108213578
[3] https://blog.csdn.net/weixin_35848967/article/details/108493217
[4] https://www.jianshu.com/p/7099565063e8
[5] https://zhuanlan.zhihu.com/p/261134624