PyTorch迁移学习:仅训练第一层、冻结其余层的参数异常排查
问题分析与解决
核心错误点
- 逻辑完全颠倒:你要训练第一层、冻结其余层,但代码里是先冻结所有参数,再开启最后一层(
_fc)的梯度,和需求完全相反。 - 变量名混淆:代码中混用了
model_b0和model_b7,优化器用了model_b7.parameters(),训练时又传入model_b7,但实际定义的模型是model_b0,这会导致使用未正确配置梯度的模型训练,触发反向传播错误。 - 优化器冗余:传入所有参数(包括冻结的)会浪费资源,应该只传入需要训练的参数。
修正后的代码
from efficientnet_pytorch import EfficientNet import torch.nn as nn import torch.optim as optim from torch.optim import lr_scheduler # 加载预训练模型 model_b0 = EfficientNet.from_pretrained('efficientnet-b0') num_ftrs = model_b0._fc.in_features model_b0._fc = nn.Linear(num_ftrs, 10) # 1. 冻结所有参数 for param in model_b0.parameters(): param.requires_grad = False # 2. 找到第一层并开启梯度(EfficientNet的第一层是features模块下的conv_stem,即features[0]) first_layer = model_b0.features[0] for param in first_layer.parameters(): param.requires_grad = True # 3. 优化器仅传入需要训练的参数(若仅训练第一层,可去掉model_b0._fc.parameters();若全连接层也需训练则保留) params_to_train = list(first_layer.parameters()) + list(model_b0._fc.parameters()) optimizer_ft = optim.SGD(params_to_train, lr=0.001, momentum=0.9) exp_lr_scheduler = lr_scheduler.StepLR(optimizer_ft, step_size=7, gamma=0.1) # 训练模型(确保传入正确的model_b0) model_b0 = train_model(model_b0, criterion, optimizer_ft, exp_lr_scheduler, num_epochs=3)
关键细节说明
- 第一层定位:EfficientNet的特征提取部分在
model_b0.features下,第一个子模块features[0]就是输入卷积层(conv_stem),即模型的第一层。 - 梯度控制:通过
requires_grad=False冻结参数,True开启训练,确保只有目标层参与反向传播更新。 - 优化器参数筛选:只传入需要训练的参数,避免优化器处理大量冻结参数,提升训练效率,同时避免潜在的梯度计算问题。
- 变量名统一:全程使用
model_b0,避免因变量名混淆导致的模型配置不匹配问题。
报错原因解释
你之前的报错源于两点:
- 混用
model_b0和model_b7,导致训练时使用的模型未正确设置梯度(model_b7可能未定义或未配置requires_grad)。 - 即使变量名正确,原逻辑是训练最后一层,若该层梯度设置有问题,或反向传播时没有任何可训练的参数,就会触发
RuntimeError——因为loss的计算路径中没有可求导的参数,无法完成反向传播。
内容的提问来源于stack exchange,提问作者log moment
相关产品推荐
相关产品推荐

