训练MNIST模型遇RuntimeError:输入(10x7x7)输出(10x0x0)
解决MNIST训练中RuntimeError:输出尺寸过小的问题
嘿,我来帮你搞定这个报错!这个错误的核心原因是:你的模型是从处理128x128图像的代码改过来的,但没适配MNIST的28x28小尺寸,导致最后平均池化的时候,输入特征图的尺寸比池化核还小,直接算出了0x0的无效输出。
咱们一步步拆解你的模型运行逻辑(输入是MNIST的(1,28,28)张量):
- 前两层卷积+BN+LeakyReLU后,尺寸保持
(64,28,28)(因为padding=1、stride=1,卷积不会改变特征图尺寸) - 第一次MaxPool2d(2,2)后,尺寸缩小一半:
(64,14,14) - 接下来两层卷积后尺寸还是
(256,14,14) - 第二次MaxPool2d(2,2)后,尺寸变成
(256,7,7) - 最后一层卷积把通道数降到10,输出
(10,7,7) - 这时候你用了
AvgPool2d(32),池化核大小是32,但输入只有7x7,完全不够池化核覆盖,所以计算出来的输出就是(10,0,0),直接触发RuntimeError。
修复方案
这里有两种简单的修复方式,选哪种都可以:
方式一:匹配当前输入尺寸调整池化核
把self.avg_pool = nn.AvgPool2d(32)改成self.avg_pool = nn.AvgPool2d(7),因为经过两次池化后特征图正好是7x7,用7x7的池化核就能得到(10,1,1)的输出,后续flatten后正好能喂进Linear层。
方式二:用自适应平均池化(更灵活)
换成self.avg_pool = nn.AdaptiveAvgPool2d(1),自适应池化会自动调整池化核大小,不管前面输出的特征图是多少尺寸,都能输出1x1的结果,以后换其他尺寸的输入也不用改这部分代码。
修改后的完整模型代码
def __init__(self): super(CNN_mnist, self).__init__() self.conv = nn.Sequential( # 输入: 1 x 28 x 28 nn.Conv2d(1, 32, 3, 1, 1), nn.BatchNorm2d(32), nn.LeakyReLU(0.2), # 输出: 32 x 28 x 28 nn.Conv2d(32, 64, 3, 1, 1), nn.BatchNorm2d(64), nn.LeakyReLU(0.2), # 输出: 64 x 28 x 28 nn.MaxPool2d(2, 2), # 输出: 64 x 14 x 14 nn.Conv2d(64, 128, 3, 1, 1), nn.BatchNorm2d(128), nn.LeakyReLU(0.2), # 输出: 128 x 14 x 14 nn.Conv2d(128, 256, 3, 1, 1), nn.BatchNorm2d(256), nn.LeakyReLU(0.2), # 输出: 256 x 14 x 14 nn.MaxPool2d(2, 2), # 输出: 256 x 7 x 7 nn.Conv2d(256, 10, 3, 1, 1), nn.BatchNorm2d(10), nn.LeakyReLU(0.2) # 输出: 10 x 7 x 7 ) # 这里改成7或者自适应池化二选一即可 self.avg_pool = nn.AvgPool2d(7) # 或者 nn.AdaptiveAvgPool2d(1) # 输出: 10 x 1 x 1 self.classifier = nn.Linear(10, 10) def forward(self, x): features = self.conv(x) flatten = self.avg_pool(features).view(features.size(0), -1) output = self.classifier(flatten) return output, features
我还把注释里的尺寸都改成了MNIST对应的数值,这样你后续调试也更清楚~
内容的提问来源于stack exchange,提问作者user11173832
相关产品推荐
相关产品推荐

