You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

添加新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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.29 12:43:17