参考:Pytorch不同层设置不同学习率_呆呆象呆呆的博客-CSDN博客_pytorch 不同层不同学习率
自己做记录使用,大家可以去看原作者哦! 他写的更清晰!
有时做优化时不同的层需要设置不同的学习率,例如: 在对预训练语言模型进行调参时,只希望拿自己的数据对模型进行微调,不过多改变模型本身的参数,这时要设置较小的学习率;但是其他网络部分,需要设置相对较大些的学习率加速模型收敛;
这样就需要对模型的部分设置不同的学习率,设置方法如下。
全局设置学习率
优化器参数展示:
params (iterable): iterable of parameters to optimize or dicts defining
parameter groups,该参数为迭代器形式,或者字典形式
lr (float, optional): learning rate (default: 1e-3)
betas (Tuple[float, float], optional): coefficients used for computing
running averages of gradient and its square (default: (0.9, 0.999))
eps (float, optional): term added to the denominator to improve
numerical stability (default: 1e-8)
weight_decay (float, optional): weight decay (L2 penalty) (default: 0)
amsgrad (boolean, optional): whether to use the AMSGrad variant of this
algorithm from the paper `On the Convergence of Adam and Beyond`_
(default: False)
foreach (bool, optional): whether foreach implementation of optimizer
is used (default: None)
maximize (bool, optional): maximize the params based on the objective, instead of
minimizing (default: False)
capturable (bool, optional): whether this instance is safe to capture in a CUDA graph.
Passing True can impair ungraphed performance, so if you don't intend to graph capture this instance, leave it False (default: False)
针对模型全局参数统一设置学习率:
optimizer = optim.SGD(net.parameters(), lr=0.001 )
优化器的第一个参数要设置为迭代器形式。
针对网络不同部分设置学习率
主要做的改变是针对第一个参数
将集合迭代器(net.parameters())分为不同的部分 -- 列表形式,列表内各个元素为字典形式,字典内部设置不同的迭代器和参数;
代码举例:
(1) 不同层的网络结构使用类内函数.parameters()得到不同层的迭代器;
或者, (2)以字典的形式进行对不同参数组的所需要的优化参数定义;
class Net(nn.Module):
def __init__(self):
super(Net, self).__init__()
self.net1 = nn.Linear(2,10)
self.net2 = nn.Linear(10,1)
def forward(self, x):
x = self.net1(x)
x = self.net2(x)
return x
net = Net()
#不同层的网络结构使用类内函数.parameters()得到不同层的迭代器
optimizer = optim.SGD([
{'params': net.net1.parameters(),'lr': 1e-2},
{'params': net.net1.parameters(), 'lr': 1e-1}])
# 或者以字典的形式进行对不同参数组的所需要的优化参数定义
optimizer = optim.SGD([
{'params': [net.net1.weight,net.net2.weight],'lr': 1e-2},
{'params': [net.net1.bias,net.net2.bias], 'lr': 1e-1}])
for epoch in range(100):
print("Epoch:{} Lr:{:.2E}".format(epoch,optimizer.state_dict()['param_groups'][0]['lr']))
print("Epoch:{} Lr:{:.2E}".format(epoch,optimizer.state_dict()['param_groups'][1]['lr']))
optimizer.step()
或者(3)通过一些常用的函数获得参数迭代器lambda
, map
,filter
,id
class Net(nn.Module):
def __init__(self):
super(Net,self).__init__()
self.conv1 = nn.Conv2d(3,32,3)
self.conv2 = nn.Conv2d(32,24,3)
self.prelu = nn.PReLU()
for m in self.modules():
if isinstance(m,nn.Conv2d):
nn.init.xavier_normal_(m.weight.data)
nn.init.constant_(m.bias.data,0)
if isinstance(m,nn.Linear):
m.weight.data.normal_(0.01,0,1)
m.bias.data.zero_()
def forward(self, input):
out = self.conv1(input)
out = self.conv2(out)
out = self.prelu(out)
return out
model = Net()
conv_params = list(map(id,model.conv1.parameters())) #提出前两个卷积层存放参数的地址
conv_params += list(map(id,model.conv2.parameters()))
prelu_params = []
for m in model.modules(): #找到Prelu的参数
if isinstance(m, nn.PReLU):
prelu_params += m.parameters()
#假象网络很大,还有一部分参数,这部分参数使用另一个学习率
rest_params = filter(lambda x:id(x) not in conv_params+list(map(id,prelu_params)),model.parameters()) #提取出剩下的参数
print(list(rest_params))
'''
>> [] #是空的,因为我举的例子没其他参数了
'''
import torch.optim as optim
# 不同部分设置不同的学习率
optimizer = optim.Adam([{'params':model.conv1.parameters(),'lr':0.2},
{'params':model.conv2.parameters(),'lr':0.2},
{'params':prelu_params,'lr':0.02},
{'params':rest_params,'lr':0.3}
])