DLwPT项目末次epoch后计算验证集标准化RMSE的最佳方法
《Deep Learning with PyTorch》配套代码training.py 新增最终验证集标准化RMSE计算最佳实践
直接按原项目的代码风格和现有逻辑做最小改动即可,不要额外写冗余逻辑,落地步骤如下:
- 不要在训练循环外单独重写验证集加载、推理逻辑。原脚本每个epoch结束本来就会跑全量验证流程,直接复用这套逻辑的数据流,避免重复推理浪费算力。找到训练循环的epoch遍历入口
for epoch in range(1, cl_args.epochs + 1),在现有epoch结束的验证指标计算块里,加epoch == cl_args.epochs的判断,把标准化RMSE的计算逻辑放在这个分支内,和原有指标计算代码放一块,保持代码结构一致。 - 不要自己重写标签归一化/反归一化逻辑。直接复用项目util模块中已经封装好的标签缩放、还原工具函数,调用训练集预处理阶段保存的标签均值、标准差固定统计量,绝对不能用验证集自身的统计量做标准化,避免数据泄露导致指标失真。
- 指标计算直接用PyTorch内置算子,不要手写循环遍历:用
torch.nn.functional.mse_loss计算验证集预测值和真实标签的均方误差,开根号得到RMSE后,除以训练集标签的全局标准差,就得到标准化RMSE。 - 日志和结果存储对齐原有规范。不要单独用print输出结果,把算好的标准化RMSE作为
val_norm_rmse字段,塞入原有传给logMetrics函数的指标字典里,和其他训练、验证指标一块写入项目默认生成的csv日志文件,和原有日志格式完全兼容,方便后续做实验对比、可视化。如果需要持久化指标,可以在训练结束保存模型state_dict时,把这个最终指标作为自定义字段一块存入权重文件。
最小改动代码示例
# 插入到原有每个epoch结束后的验证指标聚合块内 if epoch == cl_args.epochs: # 直接复用验证阶段已经收集好的批次预测、标签列表 val_pred_all = torch.cat(val_pred_list, dim=0).detach().cpu() val_label_all = torch.cat(val_label_list, dim=0).detach().cpu() # 如果训练时对标签做过归一化,这里调用项目自带的反归一化函数还原到原始尺度 # val_pred_all = denormalize_label(val_pred_all) # val_label_all = denormalize_label(val_label_all) # 计算标准化RMSE,training_label_std为训练集预处理阶段保存的固定标签标准差 rmse = torch.sqrt(F.mse_loss(val_pred_all, val_label_all)) norm_rmse = (rmse / training_label_std).item() # 塞入原有指标字典,走默认日志逻辑 metrics["val_norm_rmse"] = norm_rmse
避坑提示
- 计算前记得对张量做
detach().cpu()操作,不要保留计算图,也不要直接操作CUDA张量转Python原生数值,避免显存泄漏、设备不匹配报错。 - 不要为了算这个指标在最后一轮额外多跑一遍全量验证,30G以上的验证集多跑一轮会多花十几分钟到半小时,完全没必要。
- 标准化用的标签标准差必须是训练集拆分时计算的固定值,绝对不能当场用验证集标签计算标准差,否则得到的指标没有参考意义。
内容的提问来源于stack exchange,提问作者Paul Reiners
相关产品推荐
相关产品推荐

