深度学习pytorch分层、 分参数设置不同的学习率等

1.

对于bias参数和weight参数,设置不同的学习率

{'params': get_parameters(model, bias=False)},
            {'params': get_parameters(model, bias=True),
             'lr': args.lr * 2, 'weight_decay': 0},

对于不同的层,做不同的处理

 for m in model.modules():

   if xxx

  else if xxx

 

 

 

 

def get_parameters(model, bias=False):
    import torch.nn as nn
    modules_skipped = (
        nn.ReLU,
        nn.MaxPool2d,
        nn.Dropout2d,
        nn.Sequential,
        torchfcn.models.FCN32s,
        torchfcn.models.FCN16s,
        torchfcn.models.FCN8s,
    )
    for m in model.modules():
        if isinstance(m, nn.Conv2d):
            if bias:
                yield m.bias
            else:
                yield m.weight
        elif isinstance(m, nn.ConvTranspose2d):
            # weight is frozen because it is just a bilinear upsampling
            if bias:
                assert m.bias is None
        elif isinstance(m, modules_skipped):
            continue
        else:
            raise ValueError('Unexpected module: %s' % str(m))


    optim = torch.optim.SGD(
        [
            {'params': get_parameters(model, bias=False)},
            {'params': get_parameters(model, bias=True),
             'lr': args.lr * 2, 'weight_decay': 0},
        ],
        lr=args.lr,
        momentum=args.momentum,
        weight_decay=args.weight_decay)

 

 

关键点解析:

点1:首先,

for m in model.modules()中,m依次是什么

以自定义的网络FCN32s为例,m是FCN32s网络module和FCN32s的init函数(只包括init()函数)中所有定义的net module

 

代码:

自定义的FCN32s网络

class FCN32s(nn.Module):    
    def __init__(self, n_class=21):
        super(FCN32s, self).__init__()
        #将每个层都定义为FCN32s类的参数
        # conv1
        self.conv1_1 = nn.Conv2d(3, 64, 3, padding=100)
        self.relu1_1 = nn.ReLU(inplace=True)
        self.conv1_2 = nn.Conv2d(64, 64, 3, padding=1)
        self.relu1_2 = nn.ReLU(inplace=True)
        self.pool1 = nn.MaxPool2d(2, stride=2, ceil_mode=True)  # 1/2

        # conv2
        self.conv2_1 = nn.Conv2d(64, 128, 3, padding=1)
        self.relu2_1 = nn.ReLU(inplace=True)
        self.conv2_2 = nn.Conv2d(128, 128, 3, padding=1)
        self.relu2_2 = nn.ReLU(inplace=True)
        self.pool2 = nn.MaxPool2d(2, stride=2, ceil_mode=True)  # 1/4

        # conv3
        self.conv3_1 = nn.Conv2d(128, 256, 3, padding=1)
        self.relu3_1 = nn.ReLU(inplace=True)
        self.conv3_2 = nn.Conv2d(256, 256, 3, padding=1)
        self.relu3_2 = nn.ReLU(inplace=True)
        self.conv3_3 = nn.Conv2d(256, 256, 3, padding=1)
        self.relu3_3 = nn.ReLU(inplace=True)
        self.pool3 = nn.MaxPool2d(2, stride=2, ceil_mode=True)  # 1/8

        # conv4
        self.conv4_1 = nn.Conv2d(256, 512, 3, padding=1)
        self.relu4_1 = nn.ReLU(inplace=True)
        self.conv4_2 = nn.Conv2d(512, 512, 3, padding=1)
        self.relu4_2 = nn.ReLU(inplace=True)
        self.conv4_3 = nn.Conv2d(512, 512, 3, padding=1)
        self.relu4_3 = nn.ReLU(inplace=True)
        self.pool4 = nn.MaxPool2d(2, stride=2, ceil_mode=True)  # 1/16

        # conv5
        self.conv5_1 = nn.Conv2d(512, 512, 3, padding=1)
        self.relu5_1 = nn.ReLU(inplace=True)
        self.conv5_2 = nn.Conv2d(512, 512, 3, padding=1)
        self.relu5_2 = nn.ReLU(inplace=True)
        self.conv5_3 = nn.Conv2d(512, 512, 3, padding=1)
        self.relu5_3 = nn.ReLU(inplace=True)
        self.pool5 = nn.MaxPool2d(2, stride=2, ceil_mode=True)  # 1/32

        # fc6
        self.fc6 = nn.Conv2d(512, 4096, 7)
        self.relu6 = nn.ReLU(inplace=True)
        self.drop6 = nn.Dropout2d()

        # fc7
        self.fc7 = nn.Conv2d(4096, 4096, 1)
        self.relu7 = nn.ReLU(inplace=True)
        self.drop7 = nn.Dropout2d()


        #用于计算每个类的分值
        self.score_fr = nn.Conv2d(4096, n_class, 1)
        #ConvTranspose2d是Conv2d的逆操作,此处输入通道数和输出通道数都是n_class,上采样卷积核为64,步进为32.上采样反卷积的操作参考github
        self.upscore = nn.ConvTranspose2d(n_class, n_class, 64, stride=32, bias=False)

        self._initialize_weights()

 

net.modules()打印的结果

FCN32s(
  (conv1_1): Conv2d(3, 64, kernel_size=(3, 3), stride=(1, 1), padding=(100, 100))
  (relu1_1): ReLU(inplace)
  (conv1_2): Conv2d(64, 64, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1))
  (relu1_2): ReLU(inplace)
  (pool1): MaxPool2d(kernel_size=2, stride=2, padding=0, dilation=1, ceil_mode=True)
  (conv2_1): Conv2d(64, 128, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1))
  (relu2_1): ReLU(inplace)
  (conv2_2): Conv2d(128, 128, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1))
  (relu2_2): ReLU(inplace)
  (pool2): MaxPool2d(kernel_size=2, stride=2, padding=0, dilation=1, ceil_mode=True)
  (conv3_1): Conv2d(128, 256, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1))
  (relu3_1): ReLU(inplace)
  (conv3_2): Conv2d(256, 256, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1))
  (relu3_2): ReLU(inplace)
  (conv3_3): Conv2d(256, 256, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1))
  (relu3_3): ReLU(inplace)
  (pool3): MaxPool2d(kernel_size=2, stride=2, padding=0, dilation=1, ceil_mode=True)
  (conv4_1): Conv2d(256, 512, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1))
  (relu4_1): ReLU(inplace)
  (conv4_2): Conv2d(512, 512, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1))
  (relu4_2): ReLU(inplace)
  (conv4_3): Conv2d(512, 512, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1))
  (relu4_3): ReLU(inplace)
  (pool4): MaxPool2d(kernel_size=2, stride=2, padding=0, dilation=1, ceil_mode=True)
  (conv5_1): Conv2d(512, 512, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1))
  (relu5_1): ReLU(inplace)
  (conv5_2): Conv2d(512, 512, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1))
  (relu5_2): ReLU(inplace)
  (conv5_3): Conv2d(512, 512, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1))
  (relu5_3): ReLU(inplace)
  (pool5): MaxPool2d(kernel_size=2, stride=2, padding=0, dilation=1, ceil_mode=True)
  (fc6): Conv2d(512, 4096, kernel_size=(7, 7), stride=(1, 1))
  (relu6): ReLU(inplace)
  (drop6): Dropout2d(p=0.5)
  (fc7): Conv2d(4096, 4096, kernel_size=(1, 1), stride=(1, 1))
  (relu7): ReLU(inplace)
  (drop7): Dropout2d(p=0.5)
  (score_fr): Conv2d(4096, 21, kernel_size=(1, 1), stride=(1, 1))
  (upscore): ConvTranspose2d(21, 21, kernel_size=(64, 64), stride=(32, 32), bias=False)
)
Conv2d(3, 64, kernel_size=(3, 3), stride=(1, 1), padding=(100, 100))
ReLU(inplace)
Conv2d(64, 64, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1))
ReLU(inplace)
MaxPool2d(kernel_size=2, stride=2, padding=0, dilation=1, ceil_mode=True)
Conv2d(64, 128, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1))
ReLU(inplace)
Conv2d(128, 128, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1))
ReLU(inplace)
MaxPool2d(kernel_size=2, stride=2, padding=0, dilation=1, ceil_mode=True)
Conv2d(128, 256, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1))
ReLU(inplace)
Conv2d(256, 256, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1))
ReLU(inplace)
Conv2d(256, 256, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1))
ReLU(inplace)
MaxPool2d(kernel_size=2, stride=2, padding=0, dilation=1, ceil_mode=True)
Conv2d(256, 512, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1))
ReLU(inplace)
Conv2d(512, 512, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1))
ReLU(inplace)
Conv2d(512, 512, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1))
ReLU(inplace)
MaxPool2d(kernel_size=2, stride=2, padding=0, dilation=1, ceil_mode=True)
Conv2d(512, 512, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1))
ReLU(inplace)
Conv2d(512, 512, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1))
ReLU(inplace)
Conv2d(512, 512, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1))
ReLU(inplace)
MaxPool2d(kernel_size=2, stride=2, padding=0, dilation=1, ceil_mode=True)
Conv2d(512, 4096, kernel_size=(7, 7), stride=(1, 1))
ReLU(inplace)
Dropout2d(p=0.5)
Conv2d(4096, 4096, kernel_size=(1, 1), stride=(1, 1))
ReLU(inplace)
Dropout2d(p=0.5)
Conv2d(4096, 21, kernel_size=(1, 1), stride=(1, 1))
ConvTranspose2d(21, 21, kernel_size=(64, 64), stride=(32, 32), bias=False)

Process finished with exit code 0

这样,就可以通过for m in net.modules对FCN32s中不同的网络子模块做不同的处理。

每次遍历时,m的类型时nn.Modules神经网络,m.bias的类型是tensor

 

点2:

{'params': get_parameters(model, bias=False)}中,get_parameters返回的是某个神经网络的参数,是一个tensor。我猜测,当参数更新时,要更新到这个参数时,就会查询这个参数的更新方法,而这个参数的更新方法就是通过上面截图来指定的

 

 

 

 

 

 

 

 

 

 

 

<think>好的,我需要帮助用户了解深度学习中优化器的学习率设置与调整方法。首先,我要回顾用户提供的引用内容,确保信息准确。用户提到了学习率的重要性、不同层设置不同学习率的方法,以及PyTorch中的调度器,比如StepLR、MultiStep等。 首先,我应该从基础开始,解释什么是学习率,为什么它重要。根据引用[1],学习率设置不当会导致梯度消失或爆炸,这点必须提到。然后,进入初始学习率的设置方法,比如经验值、预训练模型和网格搜索,这部需要结合实践建议。 接下来是动态调整策略。引用[3]提到PyTorch的lr_scheduler,需要详细介绍各种方法,比如StepLR、MultiStepLR、指数衰减等。每个方法要给出公式,比如用$$...$$格式,例如指数衰减的公式应该是$\eta_t = \eta_0 \times \gamma^t$。同时,余弦退火和自适应方法如Adam也需要涵盖,这部引用[2]提到不同层的学习率和调度器结合使用,可以展开说明。 然后,分层设置学习率的部,引用[2]提到在PyTorch中如何为不同层设置不同学习率,这里需要给出示例代码,用Python代码块展示如何操作。比如用param_groups来别设置全连接层和其他层的参数。 最后,总结最佳实践,比如监控损失、预热策略和结合早停法。这部要简明扼要,给出实用建议。 生成的问题需要覆盖用户可能进一步询问的方向,比如具体调度器的使用、自适应优化器的选择、分层设置的案例,以及学习率与其他超参数的关系。确保问题有针对性,帮助用户深入理解。 检查是否所有数学公式都正确使用了$...$或$$...$$,例如动态调整中的各个公式是否正确。确认引用标记正确添加,比如在提到梯度问题时引用[^1],在PyTorch不同层设置时引用[^2],调度器部引用[^3]。 确保回答结构清晰,步骤讲解,语言通俗易懂,符合中文表达习惯。避免使用复杂术语而不解释,同时保持专业性。最后,验证所有信息是否准确,引用来源是否正确对应。</think>### 深度学习优化器中的学习率设置与调整方法 #### 一、学习率的基本概念与重要性 学习率(Learning Rate)是控制模型参数更新步长的超参数。过大的学习率可能导致训练不稳定(如梯度爆炸),过小的学习率则会使收敛速度缓慢或陷入局部最优[^1]。其数学表达为: $$w_{t+1} = w_t - \eta \nabla J(w_t)$$ 其中$\eta$为学习率,$\nabla J(w_t)$为损失函数梯度。 #### 二、初始学习率设置方法 1. **经验值设定** 常用初始范围为$10^{-5}$到$10^{-2}$,CNN常用$10^{-3}$,Transformer模型可能低至$10^{-4}$。 2. **预训练模型继承** 使用预训练模型时,建议调低学习率(如原始值的$1/10$)以避免破坏已有特征。 3. **学习率探测(LR Range Test)** 通过逐步增加学习率观察损失变化,选择损失开始上升前的临界值。 #### 三、动态学习率调整策略(PyTorch实现) PyTorch通过`torch.optim.lr_scheduler`提供多种调整策略: 1. **等间隔调整(StepLR)** $$ \eta_t = \eta_0 \times \gamma^{\lfloor t/s \rfloor} $$ ```python scheduler = StepLR(optimizer, step_size=30, gamma=0.1) ``` 2. **多间隔调整(MultiStepLR)** ```python scheduler = MultiStepLR(optimizer, milestones=[50, 80], gamma=0.1) ``` 3. **指数衰减(ExponentialLR)** $$ \eta_t = \eta_0 \times \gamma^t $$ ```python scheduler = ExponentialLR(optimizer, gamma=0.95) ``` 4. **余弦退火(CosineAnnealingLR)** $$ \eta_t = \eta_{min} + \frac{1}{2}(\eta_0 - \eta_{min})(1+\cos(\frac{t}{T}\pi)) $$ ```python scheduler = CosineAnnealingLR(optimizer, T_max=100) ``` #### 四、分层学习率设置(以ResNet为例) ```python model = resnet18() optimizer = torch.optim.SGD([ {'params': model.fc.parameters(), 'lr': 1e-3}, # 全连接层 {'params': model.layer4.parameters(), 'lr': 1e-4}, # 深层特征层 {'params': model.layer3.parameters()}, # 默认学习率(如1e-5) ], lr=1e-5) ``` 通过`param_groups`对不同层设置差异化的学习率,通常浅层使用更小的学习率以保留基础特征。 #### 五、自适应优化器的特殊处理 Adam、RMSProp等优化器具有自适应学习率特性: - **初始学习率建议**:通常设为$10^{-4}$到$10^{-3}$ - **结合调度器**:仍需配合学习率衰减 - **权重衰减离**:建议使用`AdamW`优化器以避免学习率与权重衰减耦合 #### 六、最佳实践建议 1. **监控验证损失**:当损失停滞时手动调整学习率 2. **学习率预热**:前5%训练步线性增加学习率 3. **早停法结合**:当学习率降至阈值仍无改进时终止训练
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值