PyTorch中#1与#2代码的区别及优化器设置相关疑问
PyTorch迁移学习代码疑问解答
原代码片段
model_conv = torchvision.models.resnet18(pretrained=True) for param in model_conv.parameters(): # 1 param.requires_grad = False # 1 # Parameters of newly constructed modules have requires_grad=True by default num_ftrs = model_conv.fc.in_features model_conv.fc = nn.Linear(num_ftrs, 2) model_conv = model_conv.to(device) criterion = nn.CrossEntropyLoss() # Observe that only parameters of final layer are being optimized as # opposed to before. optimizer_conv = optim.SGD(model_conv.fc.parameters(), lr=0.001, momentum=0.9) # 2 # Decay LR by a factor of 0.1 every 7 epochs exp_lr_scheduler = lr_scheduler.StepLR(optimizer_conv, step_size=7, gamma=0.1)
问题解答
1. #1和#2部分的区别
- #1段代码是冻结预训练模型的所有参数:遍历ResNet18的全部参数,将它们的
requires_grad设为False,反向传播时这些参数不会被更新,相当于固定住预训练阶段学到的特征提取能力。 - #2段代码是仅针对最后一层全连接层(fc)创建优化器:明确指定优化器只优化替换后的新fc层参数,因为前面的特征层已经被冻结,无需纳入优化范围。
两者配合实现的是「固定特征提取层、仅训练分类头」的轻量迁移学习模式。
2. 设置#1后,能否把#2改成optimizer_ft = optim.SGD(model_ft.parameters(), lr=1e-3, momentum=0.9, weight_decay=0.1)?
可以,但完全没必要,还会浪费计算资源:
- 因为#1已经把旧层参数的
requires_grad设为False,即便把整个模型参数传给优化器,PyTorch会自动忽略这些无梯度更新需求的参数,最终还是只优化新fc层。 - 直接传整个模型参数的话,优化器会遍历所有参数做一次筛选,效率不如直接指定
model_conv.fc.parameters()。另外注意变量名要对应,原代码用的是model_conv,你写的model_ft属于笔误,需要修正。
3. 删除#1只保留#2是否可行?
代码能跑,但属于不合理操作:
- 删除#1后,原预训练层的
requires_grad默认是True,但优化器只优化fc层,反向传播时会计算所有层的梯度,却只更新fc层参数——这会做大量无用的梯度计算,拖慢训练速度。 - 如果想做全模型微调(所有参数都更新),应该删除#1,同时把优化器改成
optim.SGD(model_conv.parameters(), ...);如果还是只想训练fc层,保留#1才是正确的做法,能避免无意义的梯度计算。
内容的提问来源于stack exchange,提问作者yy G
相关产品推荐
相关产品推荐

