【pytorch】不同层设置不同学习率

原文链接:https://blog.csdn.net/qq_41554005/article/details/119898464

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.Module)使用类内函数.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,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}
])
例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-2,small_lr_layers学习率为 1e-4,两部分参数共用一个momenum

参考文献:

https://blog.csdn.net/qq_34914551/article/details/87699317
https://www.huaweicloud.com/articles/12561377.html
https://blog.csdn.net/wangbin12122224/article/details/79949824

  • 6
    点赞
  • 12
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
PyTorch提供了一些内置的优化器,例如SGD、Adam等,这些优化器都支持自适应学习率设置。一般来说,有两种方式来设置自适应学习率。 第一种方式是使用PyTorch提供的学习率调度器(Learning Rate Scheduler),这些调度器可以根据训练的轮数或者验证集的表现来调整学习率PyTorch提供了一些常见的学习率调度器,比如StepLR、MultiStepLR、ReduceLROnPlateau等。以ReduceLROnPlateau为例,它会根据验证集的表现来调整学习率,当验证集的表现不再提升时,学习率会减半。 ```python from torch.optim.lr_scheduler import ReduceLROnPlateau optimizer = torch.optim.Adam(model.parameters(), lr=0.1) scheduler = ReduceLROnPlateau(optimizer, mode='min', factor=0.1, patience=10, verbose=True) for epoch in range(num_epochs): train_loss = train(model, train_loader, optimizer) val_loss = evaluate(model, val_loader) scheduler.step(val_loss) ``` 第二种方式是使用PyTorch提供的参数组(Parameter Group)来设置不同学习率。有些模型的不同学习率的敏感程度不同,这时候就可以使用参数组来设置不同学习率。以ResNet模型为例,可以将卷积和全连接分别设置不同学习率。 ```python import torch.optim as optim model = ResNet() conv_layers = [model.conv1, model.layer1, model.layer2, model.layer3] fc_layers = [model.layer4, model.fc] optimizer = optim.SGD([ {'params': conv_layers, 'lr': 0.001}, {'params': fc_layers, 'lr': 0.01} ], momentum=0.9) ``` 在这个例子中,我们将卷积和全连接分别放在一个参数组中,并设置不同学习率。这样调整学习率时就可以分别调整不同学习率

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值