model.eval()仅关闭dropout和BN,不处理预测逻辑、标签对齐、batch累计或指标聚合;准确率需逐样本比较推理输出与真实标签,并注意维度、设备、分类类型及梯度隔离。

准确率计算为什么不能直接用 model.eval() 就完事
因为 model.eval() 只是关闭 dropout 和 BN 的训练行为,不涉及预测逻辑、标签对齐、batch 拼接或指标聚合。实际准确率必须在推理输出和真实标签之间做逐样本比较,而 PyTorch 本身不提供开箱即用的 accuracy_score 类函数(不像 scikit-learn)。常见错误是直接对 logits 调用 torch.argmax() 后和 target 比较,却忽略维度不匹配、device 不一致、或没处理多分类/二分类的输出差异。
写自定义评估 Loop 必须处理的 4 个关键点
一个健壮的评估 loop 不只是跑 forward,还要兜住数据流转全过程:
-
输出对齐:模型输出是
logits(如 shape[B, C]),需用torch.argmax(logits, dim=1)转成预测类别索引;若为二分类且输出是单值([B, 1]),得先torch.sigmoid()再阈值化,或直接torch.round(torch.sigmoid(logits)) -
设备同步:
pred和target必须同 device,否则==会报错;建议统一移至 CPU 再计算(pred.cpu().numpy()),或全程在 GPU 用torch.sum(pred == target).item() - batch 累计方式:不能只算每个 batch 的准确率再平均(会因 batch size 不同而加权失真),应累计正确总数和总样本数,最后全局除法
-
梯度隔离:务必用
with torch.no_grad():包裹整个 eval 过程,否则显存暴涨,且可能意外触发 backward
torchmetrics.Accuracy 能替代手写 loop 吗?什么时候该用它
可以替代,但要注意版本和配置细节。PyTorch Lightning 用户默认推荐它,普通训练 loop 中也适用,不过得明确指定任务类型:
- 多分类:
acc = torchmetrics.Accuracy(task="multiclass", num_classes=10),输入preds=logits和target即可,内部自动 argmax - 二分类:用
task="binary",此时preds应为概率(sigmoid 后)或 logits(需设threshold=0.0并确保模型最后一层无 sigmoid) - 注意:v0.11+ 强制要求
task参数,旧写法Accuracy(num_classes=...)会报错;且所有 metric 实例需调用.reset()清零状态,否则多次.update()会累积
一个最小可行的自定义 eval loop 示例
以下代码跑通即用,已避开常见 device 错误和 batch 权重偏差:
立即学习“Python免费学习笔记(深入)”;
def evaluate(model, dataloader, device):
model.eval()
total_correct = 0
total_samples = 0
with torch.no_grad():
for data, target in dataloader:
data, target = data.to(device), target.to(device)
logits = model(data)
pred = torch.argmax(logits, dim=1)
total_correct += (pred == target).sum().item()
total_samples += target.size(0)
return total_correct / total_samples
<h1>调用</h1><p>acc = evaluate(model, val_loader, "cuda")
print(f"Val Acc: {acc:.4f}")</p>如果模型输出是单 logit(如二分类 ResNet 输出 [B, 1]),把 pred = ... 行换成:pred = (torch.sigmoid(logits) > 0.5).long().squeeze(1)
真正容易被忽略的是:验证集 shuffle 是否关闭(DataLoader(shuffle=False))、target 标签是否从 0 开始连续编号、以及某些 loss(如 nn.CrossEntropyLoss)隐式要求 target 是 long 类型——这些不报错但会导致准确率为 0 或 NaN。


















