PyTorch冻结EfficientNet层设置requires_grad=False报RuntimeError
问题原因
- torchvision实现的EfficientNet系列模型,最终分类层的属性名是
classifier而非传统ResNet所用的fc,你代码中新增的fc层完全没有接入模型的前向计算路径,没有参与任何运算。 - 你设置的替换层输入维度512也是错误的,EfficientNet-B0经过特征提取后的输出通道数为1280。
- 由于实际参与前向计算的所有层都被你设置为
requires_grad=False,计算图中没有任何需要求梯度的张量,反向传播时就会抛出你看到的RuntimeError。
修正方案
直接调整层替换逻辑和优化器参数传入范围即可,训练循环代码无需修改,修正后的完整实现如下:
from torchvision.models import efficientnet_b0 from torch import nn from torch import optim efficientnet_b0_fine = efficientnet_b0(pretrained=True) # 冻结所有预训练骨干网络参数 for param in efficientnet_b0_fine.parameters(): param.requires_grad = False # 正确替换分类头:classifier是包含Dropout和Linear的序列结构,索引1对应最终全连接层 efficientnet_b0_fine.classifier[1] = nn.Linear(1280, 10) # 优化器仅传入需要训练的分类头参数,避免加载无梯度的冗余参数 optimizer = optim.Adam(efficientnet_b0_fine.classifier.parameters(), lr=0.0001) loss_function = nn.CrossEntropyLoss() training(net=efficientnet_b0_fine, n_epochs=epochs, optimizer=optimizer, loss_function=loss_function, train_dl = train_dl)
补充说明
- 如果后续需要做更深层的微调,可以逐层解冻需要训练的骨干网络层,将对应层的
requires_grad设为True,同时把这部分参数加入优化器的参数列表即可。 - 若要验证可训练参数是否符合预期,可以执行如下代码打印所有会被更新的参数名:
正常冻结骨干仅训练分类头的场景下,输出只会包含for name, param in efficientnet_b0_fine.named_parameters(): if param.requires_grad: print(name)classifier.1.weight和classifier.1.bias两项。
内容的提问来源于stack exchange,提问作者tmr
相关产品推荐
相关产品推荐

