Pytorch不同层设置不同学习率

Posted 呆呆象呆呆

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Pytorch不同层设置不同学习率相关的知识,希望对你有一定的参考价值。

1 主要目标

不同的参数可能需要不同的学习率,本文主要实现的是不同层中参数的不同学习率设置。

尤其是当我们在使用预训练的模型时,需要对一些除了主干网络以外的分支进行单独修改并进行初始化,其他主干网络层的参数采用预训练的模型参数进行初始化,这个时候我们希望在进行训练过程中,除主干网络只进行微调,不需要过多改变参数,因此需要设置较小的学习率。而改正后的其它层则需要以较大的步子去收敛,学习率往往要设置大一点。

2 针对全局的统一学习率设置

根据你选择的优化器的类把具体设置的lr作为可选参数的一部分传入到新建的优化器类初始化中。

优化器初始化方式一般如下所示

其中源码中对应第一个参数的要求为可以迭代索引的参数集合或者字典(理解这一部分就是实现之后不同学习率的设置)

代码举例

optimizer = optim.SGD(net.parameters(), lr=0.001 )

3 针对不同层设置不一样的学习率

其核心就是以字典或者字典列表的形式进行

  • 不同参数的集合行程参数组(字典构成的列表中的每一项都是会形成一个参数组,然后针对这个参数组可以有不一样的优化器的参数设置)
  • 每一个参数组所需要的都是一个参数的迭代器正如所有参数的集合迭代器net.parameters()

方法一

最简单的方法:(适合比较简单的网络)通过实例化之后的网络模型索引到对应的层,索引到具体的参数集合

举例:对偏置和权重采用不同的学习率(也需要进行一层一层的引用进行单个字典的声明)

    optimizer = optim.SGD([
                    {'params': net.net1.weight,'lr': 1e-2},
                    {'params': net.net1.bias, 'lr': 1e-1}])

同时也可以通过列表的方式把不同层组织起来

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()
# 以字典的形式进行对不同参数组的所需要的优化参数定义
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()

好像只能对一个具体的层进行参数的学习率设置,而不能再细化下去对每个层的不同位置的参数进行学习率的精细调整(因为它需要可以构成一个参数组的可迭代索引对象)

方法二

最常用的方法:在网络结构(也可以是层,因为层也继承于nn.Moduel)使用类内函数.parameters(),这样就可以通过该函数获得一个层或者网络的参数迭代器,用来初始化优化器

例1

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()
# 以字典的形式进行对不同参数组的所需要的优化参数定义
optimizer = optim.SGD([
        {"params":net.net1.parameters()},
        {"params":net.net1.parameters(),"lr":1e-5},],
        lr=1e-2, #默认参数
    )

例2

通过一些常用的函数获得参数迭代器lambda,map,filterid

用我们自定义的网络为例

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}
])

例3

class net(nn.Module):
    def __init__(self):
        super(net, self).__init__()
        self.conv1 = nn.Conv2d(3, 64, 1)
        self.conv2 = nn.Conv2d(64, 64, 1)
        self.conv3 = nn.Conv2d(64, 64, 1)
        self.conv4 = nn.Conv2d(64, 64, 1)
        self.conv5 = nn.Conv2d(64, 64, 1)
    def forward(self, x):
        out = conv5(conv4(conv3(conv2(conv1(x)))))
        return out
net = net()
lr = 0.001
conv5_params = list(map(id, net.conv5.parameters()))
conv4_params = list(map(id, net.conv4.parameters()))
base_params = filter(lambda p: id(p) not in conv5_params + conv4_params,
                     net.parameters())
optimizer = torch.optim.SGD([
            {'params': base_params},
            {'params': net.conv5.parameters(), 'lr': lr * 100},
            {'params': net.conv4.parameters(), 'lr': lr * 100},
            , lr=lr, momentum=0.9)

    
    

例4

resnet101为例,分层设置学习率。

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

注:large_lr_layers学习率为 1e-2small_lr_layers学习率为 1e-4,两部分参数共用一个momenum

LAST 参考文献

Pytorch中,动态调整学习率、不同层设置不同学习率和固定某些层训练的方法_我的博客有点东西-CSDN博客

pytorch 模型不同层设置不同的学习率 - 华为云

pytorch在不同的层使用不同的学习率_pytorch在不同的层设置不同的学习率-CSDN博客_pytorch 不同层不同学习率

torch.optim - PyTorch中文文档

Python filter() 函数 | 菜鸟教程

Python map() 函数 | 菜鸟教程

以上是关于Pytorch不同层设置不同学习率的主要内容,如果未能解决你的问题,请参考以下文章

PyTorch中对bias参数单独设置学习率

PyTorch中对bias参数单独设置学习率

第十七篇 PyTorch学习率调整策略

Pytorch学习率相关问题及L2 Penalty

如何在 Pytorch 中应用分层学习率?

pytorch--训练分层学习率设置