三个数字对不上:3D Gaussian Splatting 评估指标 PSNR/SSIM/LPIPS 完整指南
发布时间:2026/10/29 10:48:49 锦皓数字建站

三个数字对不上3D Gaussian Splatting 评估指标 PSNR/SSIM/LPIPS 完整指南【免费下载链接】gaussian-splattingOriginal reference implementation of 3D Gaussian Splatting for Real-Time Radiance Field Rendering项目地址: https://gitcode.com/gh_mirrors/ga/gaussian-splatting跑完一轮 3D Gaussian Splatting 训练测试集上的 PSNR 一路爬升渲染图里却还有一块模糊的斑最后评估时 SSIM 涨了、LPIPS 不降三个数字各说各话。这就是 3D Gaussian Splatting 评估指标PSNR、SSIM、LPIPS最典型的使用困境数字都算出来了却不知道该信哪个。本文以官方仓库的实现为准把这三个数从哪来、各自花多少算力、在哪个阶段该用、读数异常时先查什么一次讲透最后给出一份可直接照做的落地清单。三个数字的来源仓库内置的评估流水线先搞清楚数字是哪里产生的之后排查错在哪一步才有抓手。官方流程分两步边界非常清晰render.py遍历测试相机把每张渲染图和对应的 ground truth 分别存成test/ours_{iteration}/renders与test/ours_{iteration}/gt两个平行目录文件按同一个枚举序号命名一一对应metrics.py按文件名把两图配对逐张算三个指标再对全部测试视角取平均metrics.py 的核心循环只有三行for idx in tqdm(range(len(renders)), descMetric evaluation progress): ssims.append(ssim(renders[idx], gts[idx])) # 结构相似性看局部结构 psnrs.append(psnr(renders[idx], gts[idx])) # 峰值信噪比看像素误差 lpipss.append(lpips(renders[idx], gts[idx], net_typevgg)) # 感知距离VGG 骨干几个影响读数的细节值得先记住图像经tf.to_tensor进入指标函数像素值已归一化到 [0, 1][:, :3, :, :]只取前三个通道PNG 第四通道 alpha 被直接丢弃LPIPS 写死net_typevgg整个仓库的感知对比基准是 VGG16。换骨干会得到另一套不可比的数字结果落两份文件results.json是场景级平均per_view.json保留每个视角的单独读数——后者是你定位坏视角的唯一线索train.py 默认在 7000 和 30000 次迭代时对全部测试相机加 5 张训练相机报告 L1 与 PSNR所以训练期就有曲线可看full_eval.py则把训练、渲染、评估串成一键命令并传--test_iterations -1关掉训练内评估也就是说仓库实际给了你两套体系训练中的监控和收敛后的终评三者出自同一组函数。同一套代码出数是后面能对账的前提。官方 teaser 图就是典型的PSNR FPS汇报方式PSNR 是 NeRF 渲染质量评估排行榜上的通用语言每个方法的 bicycle 场景读数都标在图下。三个指标的真实算法官方实现合起来读三个指标常被写成三章但并排看才见本质它们都是在不同空间里算同一个距离——PSNR 在像素空间SSIM 在局部统计空间LPIPS 在深度特征空间。越靠前算力越低、越像算数越往后算力越贵、越像看图。PSNR最直白也最容易被蒙utils/image_utils.py 里全部实现就两行def psnr(img1, img2): mse (((img1 - img2)) ** 2).view(img1.shape[0], -1).mean(1, keepdimTrue) # 逐像素平方误差取均值 return 20 * torch.log10(1.0 / torch.sqrt(mse)) # MAX1 时与 10·log10(1/MSE) 等价写成公式即 $PSNR 10\log_{10}(MAX^2 / MSE)$输入归一化到 [0,1] 后 MAX1代码里的写法只是同一公式的变形。view(B, -1)把 C·H·W 压平意味着三个颜色通道共用同一个 MSE。这个函数反向说明了它的适用边界只看逐像素误差的平均量级对结构、纹理完全不敏感。整体偏移几像素、边缘发丝变糊只要平均误差没大读数就不会难看。所以 PSNR 适合盯趋势、做优化反馈不适合拍板。SSIM既当考卷又当老师的指标utils/loss_utils.py 用滑动高斯窗默认 11×11σ1.5对两张图逐窗口算局部均值、方差、协方差再代入核心式。实现上用F.conv2d加groupschannel做高斯滤波每通道独立并行C1 0.01 ** 2 # 稳定常数防止低对比度区域除零 C2 0.03 ** 2 ssim_map ((2*mu1*mu2 C1) * (2*sigma12 C2)) / \ ((mu1_sq mu2_sq C1) * (sigma1_sq sigma2_sq C2))ssim_map是与图像同尺寸的结构相似度图最终值取全图均值。窗口大小 11 是写死的小于 11 像素的细节失真基本进不了读数。仓库里更微妙的一点是同一个ssim函数直接参与训练。总损失的计算方式是loss (1.0 - opt.lambda_dssim) * Ll1 opt.lambda_dssim * (1.0 - ssim(image, gt_image))lambda_dssim默认 0.2即 80% L1 20% 结构项。模型在训练时就被往 SSIM 高的方向优化过评估它的 SSIM 相当于考它已经学过的那门课——解读时要把这层偏置算进去别把 SSIM 的涨幅全归功于渲染变好。LPIPS三者中唯一看图的lipsPyTorch/modules/lpips.py 逻辑直接只是贵feat_x, feat_y self.net(x), self.net(y) # 冻结的 ImageNet 预训练 VGG16取 5 层特征 diff [(fx - fy) ** 2 for fx, fy in zip(feat_x, feat_y)] # 逐层特征差的平方 res [l(d).mean((2, 3), True) for d, l in zip(diff, self.lin)] # 1x1 卷积压成 1 通道 return torch.sum(torch.cat(res, 0), 0, True) # 5 层标量求和self.net是全部参数冻结的 VGG16从 5 个指定层64/128/256/512/512 通道抽特征输入先做 z-score 标准化每层差值图再经一个 1×1 卷积self.lin压成标量最后五层相加。这些线性权重不在仓库里脚本首次运行会自动下载 v0.1 预训练文件——第一次跑评估需要联网离线环境要提前备好。LPIPS 的物理含义是在深度网络眼里两张图差多少。它是三者里最接近人眼主观判断的一个但代价也最大每个测试视角都要过一次 VGG16训练期逐迭代计算基本不现实且数值不可解释0.3 只能告诉你有点差指不出差在哪个像素。三者并排看在什么空间算单次成本最擅长盲区PSNR像素极低趋势监控、优化反馈结构失真不敏感SSIM11×11 局部统计低模糊、结构性细节全局语义错误无感LPIPSVGG16 五层特征高整体感知判断无法定位误差来源指标怎么信分阶段适配矩阵特性摊开之后选择其实不复杂指标训练监控每千次迭代收敛后验证对比论文/跨方法对比PSNR✅ 主盯训练脚本已内置✅ 必报✅ 标准列SSIM⚠️ 看损失项即可✅ 必报✅ 标准列LPIPS❌ 别算✅ 必报✅ 标准列固定 vgg按场景走决策分支训练期只盯测试集 PSNR 曲线7000/30000 的默认报告点。曲线突然跳水先查密度控制阶段500–15000 次迭代是 densify 窗口有没有异常而不是换指标单模型终检跑 metrics.py三个数都要但建议按 LPIPS → SSIM → PSNR 的顺序读从感知到数值逐层确认两个方法或两组超参互相比三者全报LPIPS 的骨干保持一致测试切分用同一套--eval划分排查渲染 artifact、破面、缺失区域三个指标都定位不了位置直接看per_view.json找最低分视角再对看renders/与gt/的 PNG为什么读图顺序把 LPIPS 放最前因为 3D 重建里最常见的数值正常、观感拉垮恰恰发生在感知层——整体发糊、重影、纹理涂抹这类失真 LPIPS 最敏感而 PSNR 对此常常无感。反过来大面积平坦的室内场景里 SSIM 很容易虚高此时需要 LPIPS 压阵。三者是互相校核的关系不是三张独立的考卷。PSNR 上不去先查这三处异常读数排查读数不对劲时按数据流方向渲染 → 配对 → 计算从前往后查对照这张表异常读数最可能的原因排查动作三个指标全低PSNR 20测试集混进了训练集或切分错误确认训练时传了--eval核对 COLMAP 相机划分PSNR 正常图像局部明显模糊或缺块局部结构失败被平均数掩盖查per_view.json找最低分视角对看该视角两张图PSNR 涨、LPIPS 同涨像素级正确的糊全局对齐了但细节没了看 densification 配置与 tensorboard 里的 opacity 直方图LPIPS 低、PSNR 低细节噪声大或整体偏色对比两图均值方差核对white_background背景色设置个别视角 NaN / 配对错乱两个目录文件名不匹配核对renders/与gt/是否一一对应render.py按同一序号命名手工增删图片会破坏配对最常见的坑其实在指标之前readImages靠文件名配对os.listdir顺序任意一旦某边缺文件就是在错误的图对上算分。官方脚本里两个目录由同一个循环变量命名天然对齐只有手工往目录里塞图或删图才会出事。另一个排查习惯值得固化第一步永远是看图不是换指标。同一街道场景的两张官方截图就能说明问题——上面这张结构完整、纹理清晰是好读数应该对应的样子下面这张大面积缺失发糊——眼力一下就能分出高下。这类失败在指标上表现为 PSNR 与 SSIM 双杀、LPIPS 同步恶化说明问题出在 3D 表征侧densify 不足、prune 过激而不是指标看不见。排查顺序因此是先看图再对数最后才动指标选择。落地清单评估怎么跑、怎么记、怎么比跑评估训练结束后先python render.py --iteration 30000 -s 场景 -m 输出目录 --skip_train再python metrics.py --model_paths 输出目录/场景要批量刷 Mip-NeRF 360 全部场景用full_eval.py靠--skip_training、--skip_rendering、--skip_metrics分别控制三阶段记两份 JSONresults.json场景均值与per_view.json单视角连同cfg_args一起归档对比实验时在记录里注明迭代数、数据集切分、torch 版本与 GPU 型号缺任何一项日后数字都不可互比设计对比实验一次只动一个变量方法或超参同一场景、同一--eval切分至少覆盖 3 个场景取平均PSNR、SSIM、LPIPS 三列全报备 LPIPS 环境首次运行自动下载 vgg 线性权重联网机器先跑一遍预热再在离线环境复评评估与训练尽量同版本 torch避免卷积实现的细微差异别拿训练 loss 当质量结论进度条里的 total_loss 是训练视角上的 EMA 平滑值对质量有意义的只有测试视角上的评估读数参考资料Kerbl et al., 3D Gaussian Splatting for Real-Time Radiance Field RenderingSIGGRAPH 2023Zhang et al., The Unreasonable Effectiveness of Deep Features as a Perceptual MetricLPIPS 原始论文Wang et al., Image Quality Assessment: From Error Visibility to Structural SimilaritySSIM 原始论文仓库源码入口metrics.py、utils/image_utils.py、utils/loss_utils.py、lpipsPyTorch/【免费下载链接】gaussian-splattingOriginal reference implementation of 3D Gaussian Splatting for Real-Time Radiance Field Rendering项目地址: https://gitcode.com/gh_mirrors/ga/gaussian-splatting创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
锦
锦皓数字建站
深耕本土企业品牌数字化升级,专注原创端正雅致商务官网,从视觉设计到稳定运维全程保驾护航。