预训练CNN集成模型中不同Batch Size导致推理精度差异过大的问题咨询
我尝试实现基于Softmax的基础投票机制:选取4个从
chenyaofo/pytorch-cifar-models加载的CIFAR10预训练VGG模型,对各模型输出执行Softmax后求和取Argmax得到最终结果。但发现当batch_size设为128/256时精度能到94%,设为1时仅69%。
问题根源分析
这个现象主要由两个核心问题导致:
模型未进入评估(eval)模式
你加载的预训练VGG模型带有BatchNorm层,而PyTorch模型默认处于训练(train)模式。在训练模式下,BatchNorm层会使用当前批次的均值和方差做归一化,而非预训练阶段保存的全局running_mean和running_var。当batch_size=1时,单样本的统计量和训练时的全局统计量偏差极大,直接让模型输出完全偏离预期;而大批次时,批次统计量刚好接近训练时的全局统计量,精度暂时正常,但这只是巧合,并非正确的评估方式。测试数据未做与训练一致的归一化
你当前的测试变换仅包含transforms.ToTensor(),但这些预训练模型是在经过标准化的CIFAR10数据上训练的。ToTensor()仅把像素值从0-255缩放到0-1,没有减去均值、除以标准差,这会导致输入数据分布和模型训练时的分布不匹配,在小批次时这个问题的影响会被进一步放大。
修复方案
1. 强制模型进入评估模式
在构建集成模型后,务必调用model.eval(),让BatchNorm、Dropout等层切换到评估逻辑:
model = MyEnsemble(models[0], models[1], models[2], models[3]) model.to(device) model.eval() # 新增这一行,关键!
2. 添加训练一致的归一化变换
按照CIFAR10的标准归一化参数修改测试数据变换:
test_transform = transforms.Compose([ transforms.ToTensor(), transforms.Normalize(mean=[0.4914, 0.4822, 0.4465], std=[0.2023, 0.1994, 0.2010]) ])
3. 可选:简化集成模型实现
可以用循环批量处理模型,避免重复代码:
class MyEnsemble(nn.Module): def __init__(self, models_list): super(MyEnsemble, self).__init__() self.models = nn.ModuleList(models_list) def forward(self, x): total_output = None for model in self.models: logits = model(x) softmax_out = torch.softmax(logits, dim=1) total_output = softmax_out if total_output is None else total_output + softmax_out return total_output
初始化时直接传入模型列表即可:
model = MyEnsemble(models)
修改完成后,无论batch_size设置为1还是更大的值,模型精度都会稳定在94%左右,符合预期。
内容的提问来源于stack exchange,提问作者JojoHalastra




