添加新FC层后预训练ResNet50仍输出原类别数问题排查
问题分析:新增FC层未参与前向传播的原因
问题场景
加载预训练ResNet50模型(原FC层输出51类),为适配43类任务新增输出43类的fc1层,冻结其他层仅微调原FC和fc1层,但前向传播仍输出51类;用nn.Sequential包裹模型与新层则正常输出43类。
用户测试代码:
# 加载模型路径与预训练权重 sys.path.append("/home/imantha/workspace/RemSens_SSL/RSP/Scene Recognition") from models.resnet import resnet50 path_to_weights = "pretrain_weights/rsp-aid-resnet-50-e300-ckpt.pth" res50 = resnet50(num_classes = 51) res50_state = torch.load(path_to_weights) res50.load_state_dict(res50_state["model"]) # 冻结所有层,仅解冻原FC层 for param in res50.parameters(): param.requires_grad = False res50.fc.weight.requires_grad = True res50.fc.bias.requires_grad = True # 新增fc1层 res50.fc1 = nn.Linear(51, 43) # 前向传播测试 for X, y in train_loader: yhat = res50(X) print(f"yhat.shape : {yhat.shape} , y.shape : {y.shape}") break # 输出:yhat.shape : torch.Size([64, 51]) , y.shape : torch.Size([64, 43])
查看模型结构可见fc1层已存在,但未参与前向传播;而用nn.Sequential包裹则正常:
new_model = nn.Sequential( res50, nn.Linear(51,43) ) for X, y in train_loader: yhat = new_model(X) print(f"yhat.shape : {yhat.shape} , y.shape : {y.shape}") break # 输出:yhat.shape : torch.Size([64, 43]) , y.shape : torch.Size([64, 43])
核心原因
PyTorch模型的前向传播逻辑完全由forward方法定义。你给res50实例新增了fc1属性,但原ResNet50的forward函数只实现了到fc层的计算流程:输入经过特征提取、avgpool后,仅传入self.fc输出结果,不会自动调用新增的fc1层。
而nn.Sequential的执行逻辑是按顺序遍历内部模块,将前一个模块的输出作为下一个模块的输入,所以res50输出的51类结果会被传入后续的Linear层,最终得到43类输出。
解决方法
方法1:修改模型的forward方法
自定义继承自原ResNet的子类,重写forward方法,在fc层之后调用fc1层:
from models.resnet import resnet50 import torch class ModifiedResNet(resnet50): def forward(self, x): # 保留原forward的特征提取流程 x = self.conv1(x) x = self.bn1(x) x = self.relu(x) x = self.maxpool(x) x = self.layer1(x) x = self.layer2(x) x = self.layer3(x) x = self.layer4(x) x = self.avgpool(x) x = torch.flatten(x, 1) x = self.fc(x) # 新增调用fc1层 x = self.fc1(x) return x # 实例化并加载权重 res50 = ModifiedResNet(num_classes=51) res50_state = torch.load(path_to_weights) res50.load_state_dict(res50_state["model"]) res50.fc1 = nn.Linear(51, 43)
方法2:替换原fc层为Sequential结构
直接把原fc层替换成包含原fc和新fc1的Sequential,这样原forward方法调用self.fc时会自动执行两层:
# 冻结层操作不变 res50.fc = nn.Sequential( res50.fc, # 保留原51类输出的fc层 nn.Linear(51, 43) # 新增43类输出层 )
内容的提问来源于stack exchange,提问作者imantha
相关产品推荐
相关产品推荐

