PyTorch修改ResNet50的layer4.conv3输出通道数报错求解
问题
想要修改PyTorch中ResNet50的输出通道数,尝试了以下代码却出现“weight should contain 2048 elements not 300”错误,使用ChatGPT给出的方案也出现其他错误,请问问题出在哪里?
代码如下:
# Model training routine print("\nTraining:-\n") new_num_channels = 300 #----# resnet_v2 = models.resnet50(pretrained=True) #print(resnet_v2) #print("fc_layer.in_features") #print(fc_layer.in_features) resnet_v2.layer4[-1].conv3.out_channels = new_num_channels num_classes = 3 weight = torch.nn.Parameter(torch.Tensor(new_num_channels)) torch.nn.init.uniform_(weight) # Initialize the weight tensor resnet_v2.layer4[-1].bn3.weight = weight resnet_v2.layer4[-1].bn3.num_features = new_num_channels fc_layer = resnet_v2.fc fc_layer.in_features = new_num_channels fc_layer.weight = torch.nn.Parameter(torch.Tensor(new_num_channels, fc_layer.out_features)) gap_layer = resnet_v2.avgpool gap_layer.num_features = fc_layer.in_features resnet_v2.fc = nn.Sequential( nn.Linear(new_num_channels, 128), # Change the number of channels in Fully connected layer nn.ReLU(inplace=True), nn.Linear(128, num_classes)) fc_layer.reset_parameters() resnet_v2 = resnet_v2.to(device) print(resnet_v2) changed_model = train_model(resnet_v2, loss_fn, opt, scheduler, num_epochs=train_epoch)
问题分析与解决方案
错误根源
- 直接修改层属性无效:你仅修改
conv3.out_channels、bn3.num_features这类数值属性,并没有改变卷积层和BN层的权重张量形状。比如原conv3权重是(2048, in_channels, k, k),修改out_channels为300后,实际权重还是2048通道的形状,后续绑定新参数时维度不匹配,直接触发报错。 - BN层参数替换逻辑错误:BN层的
weight和bias需与特征通道数对应,但前面卷积层未正确修改,导致即使替换BN参数也无法匹配卷积输出。 - AvgPool层修改多余:ResNet的
avgpool是AdaptiveAvgPool2d((1,1)),不存在num_features属性,此修改会引发属性不存在的错误。 - FC层操作逻辑混乱:先修改原
fc_layer属性,随后又直接替换resnet_v2.fc为新的Sequential,之前的操作完全无效,还会因原fc_layer权重形状不匹配报错。
正确修改方式
要修改ResNet50最后一个卷积块的输出通道数,需重新实例化卷积层和BN层,而非直接修改属性:
import torch import torch.nn as nn from torchvision import models new_num_channels = 300 num_classes = 3 device = torch.device("cuda" if torch.cuda.is_available() else "cpu") # 加载预训练模型 resnet_v2 = models.resnet50(pretrained=True) # 获取最后一个残差块 last_residual_block = resnet_v2.layer4[-1] # 保留原卷积层的输入通道、核尺寸、步长等参数 in_channels = last_residual_block.conv3.in_channels kernel_size = last_residual_block.conv3.kernel_size stride = last_residual_block.conv3.stride padding = last_residual_block.conv3.padding bias = last_residual_block.conv3.bias is not None # 重新定义conv3:输出通道改为目标值 last_residual_block.conv3 = nn.Conv2d( in_channels=in_channels, out_channels=new_num_channels, kernel_size=kernel_size, stride=stride, padding=padding, bias=bias ) # 重新定义bn3:匹配新的通道数 last_residual_block.bn3 = nn.BatchNorm2d(num_features=new_num_channels) # 替换全连接层,输入特征数对应新的通道数 resnet_v2.fc = nn.Sequential( nn.Linear(new_num_channels, 128), nn.ReLU(inplace=True), nn.Linear(128, num_classes) ) # 移动到计算设备 resnet_v2 = resnet_v2.to(device) # 后续训练逻辑 # changed_model = train_model(resnet_v2, loss_fn, opt, scheduler, num_epochs=train_epoch)
关键说明
- 卷积层必须重新实例化,确保权重张量形状为
(new_num_channels, in_channels, k, k),才能与前一层输出维度匹配。 - BN层需同步重新定义,保证参数数量与新的卷积输出通道一致。
- 全连接层直接替换即可,自适应池化层会自动适配输入通道数,输出展平后刚好匹配新全连接层的输入维度。
- 无需修改AvgPool层,它会根据输入自动调整输出形状。
内容的提问来源于stack exchange,提问作者Shale
相关产品推荐
相关产品推荐

