
DeepSpeed 的 DeepSpeedEngine.eval() 方法不返回模型对象,而是直接修改内部状态;若错误地执行 self.model = self.model.eval() 会导致模型变量被赋值为 None,引发后续运行错误。
deepspeed 的 `deepspeedengine.eval()` 方法不返回模型对象,而是直接修改内部状态;若错误地执行 `self.model = self.model.eval()` 会导致模型变量被赋值为 `none`,引发后续运行错误。
在使用 DeepSpeed 加速训练时,一个常见但容易被忽视的陷阱是误将 model.eval() 当作链式调用方法来使用。与标准 PyTorch nn.Module.eval() 不同,DeepSpeedEngine.eval() 是一个无返回值(即返回 None)的就地(in-place)方法,其源码明确实现为:
def eval(self):
self.warn_unscaled_loss = True
self.module.train(False) # 仅设置子模块为 eval 模式这意味着调用 self.model.eval() 的唯一作用是将底层封装的 self.module(即原始 PyTorch 模型)设为评估模式,它不会、也不应被赋值给任何变量。一旦写成:
self.model = self.model.eval() # ❌ 错误!self.model 变为 None
就会导致 self.model 被覆盖为 None,后续如 self.model(input) 或 self.model.train() 均会触发 AttributeError。
✅ 正确写法非常简洁,只需调用方法本身,无需赋值:
def evaluate(self, epoch_num=None, keep_all=True):
print("self.model:", self.model)
self.model.eval() # ✅ 正确:仅触发状态切换
print("self.model after eval:", self.model) # 输出仍为 DeepSpeedEngine 实例
# 后续可正常进行前向推理、指标计算等
with torch.no_grad():
for batch in self.val_dataloader:
outputs = self.model(batch["input"]) # 此处 self.model 依然有效
# ... compute metrics? 补充说明:
- 即使在纯 PyTorch 场景中,
model.eval()也不依赖赋值操作——它的设计本意就是修改model.training属性(model.training == False),所有子模块(如nn.Dropout,nn.BatchNorm1d)均据此自动调整行为。 - DeepSpeed 封装后,
self.model.training仍可读取(反映self.module.training),但请勿依赖其返回值做链式调用。 - 训练阶段切回训练模式时,同样应使用
self.model.train(),而非self.model = self.model.train()。
⚠️ 注意事项:
- 确保
evaluate()中的推理逻辑在torch.no_grad()上下文中执行,避免梯度计算开销及显存泄漏; - 若需在评估后恢复训练模式,请显式调用
self.model.train(); - DeepSpeed 的
eval()不影响 ZeRO 优化器或 FP16 状态,仅控制模型行为,因此无需额外配置。
总结:DeepSpeed 的 eval() 是语义清晰的副作用方法,遵循“调用即生效”原则。摒弃冗余赋值习惯,既可规避 NoneType 错误,也更符合 PyTorch 生态的一致性设计哲学。

















