如何获取训练/测试集单值性能指标?解决Epoch重复打印问题
问题分析与解决方案
你的代码存在的核心问题
- 重复输出+指标无法捕获:
test函数每次被调用(不管传入训练集还是测试集Loader),都会直接打印所有指标、弹出PR曲线和混淆矩阵图。主循环每个epoch会调用两次test,导致每个epoch重复输出两次指标;同时test只返回了准确率(Acc),精确率、召回率等其他指标你在主循环里拿不到,没法统一整理输出。 - 缺少梯度禁用:
test函数里仅用了model.eval()但没加torch.no_grad(),评估阶段会保留计算图,浪费显存,甚至可能影响结果稳定性。
解决方案:重构代码,统一控制指标输出
1. 修改test函数,返回所有需要的指标
把打印、画图逻辑从test中剥离,让它只负责计算指标并返回,这样你可以在主循环里统一控制输出节奏:
import torch from sklearn.metrics import precision_score, recall_score, classification_report, confusion_matrix from sklearn.metrics import PrecisionRecallDisplay import seaborn as sns import matplotlib.pyplot as plt import numpy as np def test(loader): output_predictions = [] target = [] model.eval() correct = 0 # 禁用梯度计算,节省显存 with torch.no_grad(): for data in loader: model_output = my_model(data) predictions = model_output.argmax(dim=1) correct += predictions.eq(data.y).sum().item() output_predictions.extend(predictions.tolist()) target.extend(data.y.tolist()) # 计算所有指标 acc = correct / len(loader.dataset) class_likelihood = class_likelihood_ratios(target, output_predictions, labels=[0,1]) cls_report = classification_report(target, output_predictions, labels=[0,1]) precision = precision_score(target, output_predictions, labels=[0,1]) recall = recall_score(target, output_predictions, labels=[0,1]) conf_matrix = confusion_matrix(target, output_predictions) # 返回所有指标,不在这里打印/画图 return acc, precision, recall, class_likelihood, cls_report, conf_matrix, target, output_predictions
2. 单独写可视化函数(可选)
把画图逻辑抽成独立函数,方便控制是否/何时画图:
def plot_eval_metrics(target, predictions, conf_matrix, set_name): # 绘制PR曲线 fig, ax = plt.subplots() PrecisionRecallDisplay.from_predictions(target, predictions, ax=ax) ax.set_title(f"{set_name} 精确率-召回率曲线") plt.show() # 绘制归一化混淆矩阵 plt.figure() sns.heatmap(conf_matrix/np.sum(conf_matrix), annot=True, fmt='.2%', xticklabels=[1,0], yticklabels=[1,0]) plt.title(f"{set_name} 混淆矩阵(归一化)") plt.show()
3. 主循环统一打印汇总结果
在主循环里调用test获取所有指标,一次性输出每个epoch的训练/测试性能:
for epoch in range(1, 50): train() # 获取训练集所有指标 train_acc, train_p, train_r, train_lh, train_cr, train_conf, train_target, train_pred = test(train_loader) # 获取测试集所有指标 test_acc, test_p, test_r, test_lh, test_cr, test_conf, test_target, test_pred = test(test_loader) # 统一打印当前epoch的结果 print(f"=== 第 {epoch:03d} 轮训练 ===") print("训练集:") print(f"准确率: {train_acc:.4f}, 精确率: {train_p:.4f}, 召回率: {train_r:.4f}") print("分类报告:\n", train_cr) print("正负类似然比:", train_lh) print("\n测试集:") print(f"准确率: {test_acc:.4f}, 精确率: {test_p:.4f}, 召回率: {test_r:.4f}") print("分类报告:\n", test_cr) print("正负类似然比:", test_lh) # 可选:每隔N轮画一次图,避免频繁弹窗 if epoch % 5 == 0: plot_eval_metrics(train_target, train_pred, train_conf, "训练集") plot_eval_metrics(test_target, test_pred, test_conf, "测试集")
效果说明
现在每个epoch只会打印一次汇总的训练/测试指标,精确率、召回率都是单个数值,完全符合你的预期。你可以根据需求调整打印内容,比如只保留关键指标,把分类报告等详细内容写入日志文件,避免控制台杂乱。
内容的提问来源于stack exchange,提问作者Susan
相关产品推荐
相关产品推荐

