Model.eval
Model.eval是深度学习框架PyTorch中torch.nn.Module类提供的一个方法,用于把神经网络模块切换到评估(推理)模式,其效果等同于调用self.train(False)。该调用会递归作用于模型及其全部子模块,把training标志置为False,并使Dropout失效、BatchNorm改用训练阶段累积的滑动统计量。在加载已训练模型做验证或推理时,遗漏这一调用会使前向输出随批次数据变化,因此它是模型部署流程中的基础操作。
定义
Model.eval指PyTorch中torch.nn.Module类的eval()方法,调用形式通常写作model.eval()。官方文档对其的描述是把模块置于评估模式,并说明该操作等价于self.train(False)。它是nn.Module提供的一对模式开关中的一个,另一个是model.train()。在实现层面,两者共用一个training属性:训练调用把它设为True,评估调用把它设为False,且模块创建时默认处于True状态。
因此,model.eval()本身并不修改任何权重参数,也不直接承担梯度开关的职责,它改变的是模块内部若干特殊层在前向计算时的行为分支。官方说明指出,该方法只对部分模块生效,具体影响需查阅各层的文档,例如Dropout与BatchNorm。
原理
nn.Module允许以树形结构嵌套子模块,模式切换由父模块向子模块逐层传播。train方法在设置自身模式后,会遍历children()并对每个子模块递归调用同样的设置,因此一次model.eval()即可让整棵模型树进入评估状态[1]。源码层面eval()直接返回self.train(False),二者是同一操作的两种写法[2]。
两个最典型的受影响层是Dropout与BatchNorm。训练阶段Dropout按给定概率把部分输入元素置零以抑制过拟合,评估阶段则不再随机丢弃,全部单元参与计算[3]。BatchNorm在训练时按当前小批数据求均值与方差,同时用滑动方式累积running_mean与running_var,默认momentum为0.1;评估时不再更新这些统计量,而是直接用累积值做归一化[4]。
滑动统计量的更新规则可写为 $\hat{x}_{\text{new}} = (1 - \text{momentum}) \times \hat{x} + \text{momentum} \times x_t$,其中 $\hat{x}$ 为已有估计值,$x_t$ 为当前批次观测值[4]。若把track_running_stats设为False,BatchNorm不再保存running_mean与running_var,评估阶段也照旧使用批内统计量,此时切换模式对该层不起作用[4]。SyncBatchNorm的跨进程统计同步同样只在训练时进行,进入评估模式后同步即被关闭[5]。
官方文档特别将评估模式与梯度控制机制区分开来:model.eval()与no-grad模式、inference mode在功能上是相互正交的,前者改变的是前向行为,后两者作用于autograd的记录过程[6]。典型写法是在with torch.no_grad()或torch.inference_mode()上下文中调用已切换模式的模型,以同时获得正确的前向行为与更低的内存占用[1]。
发展历程
PyTorch项目的源码仓库中,eval()方法的提交记录可追溯到2016年末至2017年初,与train()方法配套出现。此后2018年3月的代码修改把文档表述由「仅影响Dropout、BatchNorm等模块」改为更谨慎的「只对特定模块生效,具体行为参见各层文档」,这一措辞沿用至今[7]。
2021年,PyTorch在autograd文档中新增了局部禁用梯度计算的说明章节,并在nn.Module的eval()与requires_grad_()文档里加上指向该章节的交叉引用,以便使用者区分模式切换与梯度开关这两类容易混淆的机制[8]。
应用
在模型验证与测试环节,通行做法是先调用model.eval(),再在不记录梯度的上下文中执行前向计算,并在一轮评估结束后用model.train()切回训练模式[3]。这一组合被广泛用于分类、检测等任务的准确率统计和推理部署[9]。
高层封装框架把这一步骤内置于流程之中。例如PyTorch Lightning通过train_step、validation_step等回调组织训练与验证循环,模式切换由框架在后台完成,使用者无需手动书写model.eval()[1]。在昇腾MindX SDK一类的部署工具中,模型评估被封装为model_eval.py之类的独立脚本,由命令行参数指定测试数据集、检查点与输出路径[10]。
局限
model.eval()不改变参数是否需要梯度,也不会自动停止反向传播。官方文档明确指出评估模式并非局部关闭梯度计算的手段,它只是在文档中被并列提及,因为二者常被混为一谈[6]。在评估模式下若执行反向传播,梯度仍会被计算,参数也可能在优化器作用下被更新。
该方法只对定义了训练/评估行为差异的层起作用。Linear、Conv、LayerNorm等在两种模式下的前向计算完全相同,对这类不含Dropout与BatchNorm的模型,调用与否不改变输出结果[9]。因此它并不能解决精度下降的全部问题,数据预处理参数不一致、state_dict加载不正确等同样会导致准确率偏差[11]。
模式状态是模块自身的属性而非全局设置,遗漏调用或调用后忘记切回,都会影响后续计算。在含Dropout或BatchNorm的模型中忘记调用,推理时激活值会被随机置零、归一化改用批内统计量,输出随之出现波动[9]。此外,track_running_stats为False的BatchNorm层在评估模式下依然使用批内统计量,单样本输入时还可能因方差估计失效而报错。
参见
参考资料
- What does model.eval() do in pytorch? [引用日期2026-10-29]
- module [引用日期2026-10-29]
- pytorch测试的时候为何要加上model.eval()? [引用日期2026-10-29]
- BatchNorm2d [引用日期2026-10-29]
- torch.nn.modules.batchnorm.SyncBatchNorm [引用日期2026-10-29]
- notes [引用日期2026-10-29]
- module [引用日期2026-10-29]
- autograd [引用日期2026-10-29]
- Model Inference [引用日期2026-10-29]
- python3 model_eval [引用日期2026-10-29]
- Pytorch中model.eval()的作用是什么 [引用日期2026-10-29]