适配3x390x320图像时ResNet34出现尺寸不匹配错误的解决咨询
解决ResNet适配大尺寸图像时的维度不匹配问题
这个错误的根源很明确:你的全连接层输入维度和特征图展开后的维度不匹配。
原ResNet是针对32x32的小图像设计的,经过多次下采样和池化后,最后特征图会被压缩成1x1,展开后刚好是512(对应nn.Linear(512, num_classes))。但你的390x320图像经过网络后,最后得到的特征图是512x49x40,用avg_pool2d(4)处理后变成512x12x10,展开后是61440,而全连接层只接受512维的输入,自然会抛出尺寸不匹配的错误。
下面给你两种可行的修改方案:
方案1:使用自适应平均池化(推荐)
自适应池化可以自动调整池化核的大小,不管输入特征图的尺寸是多少,都能输出你指定的固定大小(比如1x1),这样完全不需要修改全连接层,兼容性最强。
修改ResNet类的forward方法里的池化步骤:
def forward(self, x): x = x.float() # 10, 3, 390, 320 out = F.relu(self.bn1(self.conv1(x).float()).float()) # 10, 64, 390, 320 out = self.layer1(out) # 10, 64, 390, 320 out = self.layer2(out) # 10, 128, 195, 160 out = self.layer3(out) # 10, 256, 98, 80 out = self.layer4(out) # 10, 512, 49, 40 # 替换原来的avg_pool2d为自适应池化,输出1x1的特征图 out = F.adaptive_avg_pool2d(out, (1, 1)) # 10, 512, 1, 1 out = out.view(out.size(0), -1) # 10, 512 out = self.linear(out) # 现在维度匹配了! return out
这种方法的好处是:不管你后续更换什么尺寸的图像,只要网络的下采样逻辑不变,池化后的特征图都会是1x1,全连接层不需要任何改动,非常灵活。
方案2:重新计算全连接层的输入维度
如果你想保留原来的平均池化逻辑,那需要先计算出池化后特征图的总维度,然后修改全连接层的输入特征数。
首先,计算池化后的特征图尺寸:
- layer4输出是512x49x40
- 用
avg_pool2d(4),池化后的高度是49 // 4 = 12,宽度是40 // 4 = 10 - 总维度是
512 * 12 * 10 = 61440
然后修改ResNet类的__init__方法里的全连接层:
def __init__(self, block, num_blocks, num_classes=10): super(ResNet, self).__init__() self.in_planes = 64 self.conv1 = conv3x3(3, 64) self.bn1 = nn.BatchNorm2d(64) self.layer1 = self._make_layer(block, 64, num_blocks[0], stride=1) self.layer2 = self._make_layer(block, 128, num_blocks[1], stride=2) self.layer3 = self._make_layer(block, 256, num_blocks[2], stride=2) self.layer4 = self._make_layer(block, 512, num_blocks[3], stride=2) # 替换原来的512*block.expansion为计算出的61440 self.linear = nn.Linear(61440, num_classes)
不过这种方法的局限性很明显:如果后续更换图像尺寸,你需要重新计算特征图维度,再修改全连接层,不够灵活。
另外注意:你代码里的ResNet18函数引用了PreActBlock,但你定义的是BasicBlock,这里可能是笔误,记得要保持一致,避免其他错误。
内容的提问来源于stack exchange,提问作者feiland
相关产品推荐
相关产品推荐

