调整模型中学习率的方法主要有:
- 一种是修改optimizer.param_groups中对应的学习率
- 另一种是新建优化器(简单、方便、快捷)
注意:由于optimizer十分轻量级,构建开销很小,故可以构建新的optimizer。但新建优化器会重新初始化动量等状态信息,这对使用动量的优化器来说(如带momentum的sgd),可能会造成损失函数在收敛过程中出现震荡。
首先我们建立一个LeNet网络:
import torch as t
import torch.nn as nn
from torch import optim
from torch.autograd import Variable as V
#定义个LeNet网络
class Net(nn.Module):
def __init__(self):
super(Net, self).__init__()
self.features=nn.Sequential(
nn.Conv2d(3,6,5),
nn.ReLU(),
nn.MaxPool2d(2,2),
nn.Conv2d(6,16,5),
nn.ReLU(),
nn.MaxPool2d(2,2)
)
self.classifier=nn.Sequential(
nn.Linear(5*5*16,120),
nn.ReLU(),
nn.Linear(120,84),
nn.ReLU(),
nn.Linear(84,10)
)
def forward(self, x):
x=self.features(x)
x=x.view(-1,5*5*16)
x=self.classifier(x)
return x
并初始化参数:
net=Net()
optimizer=optim.SGD(params=net.parameters(),lr=1)
optimizer.zero_grad() #梯度清零,等价于net.zero_grad()
input=V(t.randn(1,3,32,32)) # batch_size,sentence_length/in_channels,height,width
out=net(input)
out.backward(out)
optimizer.step() #执行优化
到这里模型已经搭建好,并可以自动进行梯度更新,接下来看一下优化器种设置学习率的两种方法:
1. 为不同子网络设置不同的学习率,在fintune中经常用到
这里我们分别设置features和classifer两层不同的学习率,分别是1e-5、1e-2。
# 如果对某个参数不指定学习率,就使用默认学习率
optimizer=optim.SGD([{'params':net.features.parameters(),#学习率为1e-5
},
{'params':net.classifier.parameters(),'lr':1e-2}
],lr=1e-5 #默认学习率
)
2. 修改optimizer.param_group中对应学习率
这里只为两个全连接层设置较大的学习率,其余曾的学习率较小:
# 只为两个全连接层设置较大的学习率,其余层的学习率较小
special_layers=nn.ModuleList([net.classifier[0],net.classifier[3]])
#取出这两层里面参数对应的id
special_layers_params=list(map(id,special_layers.parameters()))
#除这两层以外参数的id
base_params=filter(lambda p:id(p) not in special_layers_params,net.parameters())
optimizer=t.optim.SGD([
{'params':base_params}, #这两这两层params会根据id去定位模型层,并更新学习率
{'params':special_layers_params,'lr':0.01}
],lr=0.001)
3. 通过新建optimizer,动态调整学习率(本质上是方法1)
optimizer=optim.SGD([{'params':net.features.parameters(),#学习率为1e-5
},
{'params':net.classifier.parameters(),'lr':old_lr*0.1}
],lr=1e-5 #默认学习率
)