Pytorch下Unet验证集与测试集相同但PSNR结果差异较大问题咨询
问题排查与修复方案
你的代码存在多处逻辑错误,按影响程度从高到低列示如下:
1. 验证阶段PSNR计算完全未使用模型输出
验证循环中,你计算PSNR的入参是验证集的两个原始数据字段data[0]和data[1],完全没有传入模型推理结果out,得到的PSNR是输入数据和标签的原始差值,和模型性能无关,自然和加载模型后测试得到的真实模型输出PSNR不匹配:
# 错误代码片段 for idx, data in enumerate(testDataLoader): out = model(data[1]) psnr = compare_psnr(data[0], data[1]) # 此处未使用out,计算结果和模型无关
修复时需要将模型输出out和对应真值传入PSNR计算函数,同时累加所有batch的结果计算整个验证集的平均PSNR,不能直接用单个batch的结果代表整个验证集的指标:
# 修复后的验证计算逻辑 model.eval() total_psnr = 0.0 sample_count = 0 with torch.no_grad(): # 关闭梯度计算,减少显存占用、加速推理 for idx, data in enumerate(testDataLoader): # 注意输入、真值、模型要放在同一个设备(CPU/GPU)上 input_x = data[1].to(device) gt = data[0].to(device) out = model(input_x) # 计算当前batch PSNR,注意将tensor转到CPU、转为numpy格式,data_range和图像像素范围对齐(归一化到0-1填1.0,0-255填255) batch_psnr = compare_psnr( gt.detach().cpu().numpy(), out.detach().cpu().numpy(), data_range=1.0 ) total_psnr += batch_psnr * input_x.shape[0] sample_count += input_x.shape[0] avg_psnr = total_psnr / sample_count # 整个验证集的平均PSNR,作为最优模型判断依据
2. 模型评估模式切换API调用错误
PyTorch没有内置model.val()方法,切换评估模式的正确接口是model.eval()。
虽然你使用的UNet没有BN和Dropout层,两种模式下前向计算结果理论上一致,但如果网络包含自定义层、其他对模式敏感的层(比如带可学习参数的InstanceNorm),错误的模式切换会直接导致推理结果偏差。每轮训练开始前也要记得调用model.train()切回训练模式,避免影响参数更新。
3. 最优模型保存逻辑存在漏洞
- 变量名不一致:你初始定义的最优PSNR变量是
msxpsnr,判断时用了未定义的maxpsnr,会直接触发运行错误,建议统一变量名,初始值设为负无穷best_psnr = -float('inf'),避免PSNR为负时判断失效。 - 指标取值错误:原有逻辑中
psnr变量每次循环都会被当前batch的结果覆盖,最终只保留验证集最后一个batch的PSNR,不是全局指标,会导致保存非最优模型。 - 保存接口缺参数:
torch.save(model.state_dict())没有传入保存路径,实际运行会报错,需要补充路径参数,比如torch.save(model.state_dict(), 'best_model.pth')。
4. 测试阶段一致性校验项
修复以上问题后如果仍存在微小数值差异,逐一排查以下配置:
- 测试时必须调用
model.eval(),并用torch.no_grad()包裹推理流程 - 验证、测试阶段的数据预处理、后处理逻辑完全一致:包括归一化范围、通道顺序(RGB/BGR)、维度转换顺序、图像量化位深等
- 验证和测试的DataLoader必须关闭
shuffle,同时关闭所有随机数据增强逻辑,保证输入数据完全一致 - 调用
compare_psnr时的参数完全一致,尤其是data_range参数必须和像素值范围匹配,参数错配会导致PSNR出现固定偏差
内容的提问来源于stack exchange,提问作者Haio Liang
相关产品推荐
相关产品推荐

