2. 精度对比基础

做精度调优,第一步不是调,而是比。你得先知道“对”的是什么样,才能判断手里的模型偏没偏。这一章咱们就把精度对比的底子打牢——标杆精度怎么拿、对比工具怎么用、评价指标怎么看。我个人习惯把这部分叫“精度调优的锚点”,锚点稳了,后面才不会飘。

精度对比基础 标杆精度获取 精度对比工具 评价指标 CPU / GPU / 标杆dump dump对比 / 余弦 / PSNR 余弦相似度 · PSNR · 相对误差

2.1 标杆精度获取方法

所谓标杆精度,就是你认为“绝对正确”的那份参考输出。我一般用业界公认的框架(比如 PyTorch、TensorFlow 在 GPU 上的 float32 推理结果)作为标杆。你想想看,如果标杆本身就有问题,后面所有对比都是白费功夫。

我的常用做法:
  • 在 GPU 上用 float32 跑一遍完整推理,保存每一层/每一个算子的输出 tensor。
  • 确保输入数据完全一致(包括随机种子、预处理流水线)。
  • 用 torch.save 或 numpy.save 把标杆 dump 成文件,命名带上网络名和算子名。

我在项目中遇到过好几次“假精度问题”——折腾半天发现是标杆数据没对齐,比如图像预处理时像素归一化顺序不同。所以,标杆获取一定要和待测模型走同一份预处理代码,别偷懒。

💡 小技巧:标杆数据建议保存为 float64 或 float32,不要用 float16,避免标杆本身就有精度损失。

2.2 精度对比工具介绍

昇腾平台提供了几款非常顺手的对比工具。我个人最常用的是 compare_dump.py 和 accuracy_compare.sh。它们能自动加载标杆 dump 和昇腾 dump,然后逐算子算指标。

# 典型用法(昇腾工具链)
python compare_dump.py \
    --baseline ./dump_gpu/ \
    --target ./dump_ascend/ \
    --output ./compare_result/ \
    --metric cosine

除了官方工具,我也经常自己写脚本——尤其是当模型结构比较特殊时。比如用 numpy 手动加载两个 npy 文件,然后算余弦相似度。说白了,工具只是辅助,理解背后的计算逻辑才重要。

工具/方法适用场景输出形式
compare_dump.py标准网络逐算子对比CSV + 日志
accuracy_compare.sh整网精度一键对比汇总报告
自定义 numpy 脚本特殊算子或自定义层自定义
⚠️ 注意:对比前一定要确认两个 dump 的 tensor shape 和 dtype 一致。我曾经因为一个 unsqueeze 操作导致 shape 差 1,余弦相似度直接崩到 0.2,排查了半天……

2.3 精度评价指标

指标是尺子。尺子选错了,量出来的结果没有意义。我一般用三个核心指标:余弦相似度、PSNR、相对误差。它们各有侧重,下面展开说。

余弦相似度 (Cosine Similarity)

衡量两个向量在方向上的相似程度。值越接近 1,说明方向越一致。对于 feature map 或 embedding,余弦相似度非常敏感。

import numpy as np
def cosine_sim(a, b):
    a_flat = a.flatten()
    b_flat = b.flatten()
    dot = np.dot(a_flat, b_flat)
    norm = np.linalg.norm(a_flat) * np.linalg.norm(b_flat)
    return dot / (norm + 1e-12)

# 我一般要求余弦相似度 > 0.99,低于 0.95 就要报警

嗯,这里要注意:余弦相似度对整体缩放不敏感。如果某个算子的输出整体乘了一个常数,余弦相似度可能还是 1.0,但实际数值已经错了。所以不能只看余弦。

PSNR (峰值信噪比)

PSNR 在图像领域用得最多,但用在 tensor 对比上也很直观。它基于 MSE,单位是 dB。PSNR 越高,差异越小。我个人习惯:PSNR > 40dB 说明精度很好,30~40dB 可以接受,低于 30dB 就要仔细查了。

def psnr(a, b, max_val=1.0):
    mse = np.mean((a - b) ** 2)
    if mse == 0:
        return float('inf')
    return 20 * np.log10(max_val / np.sqrt(mse))
经验值参考:
PSNR > 45 dB → 几乎无差异
PSNR 35~45 dB → 微小差异,通常可接受
PSNR < 30 dB → 需要排查算子或精度模式

相对误差 (Relative Error)

相对误差是最直观的指标。我常用的是 abs(a - b) / (abs(a) + 1e-8),然后看最大值、均值、中位数。如果最大相对误差超过 1%,基本就有问题了。

def relative_error(a, b):
    diff = np.abs(a - b)
    base = np.abs(a) + 1e-8
    return np.max(diff / base)

# 我曾经遇到一个算子,相对误差达到 5%,最后发现是精度模式没设置成 force_fp32

三个指标要配合使用。我自己的流程是:先看余弦相似度,如果低于 0.99 再看 PSNR,如果 PSNR 也低,最后用相对误差定位具体哪些位置的数值偏差大。你想想看,这样一层层筛下来,根因基本就锁定了。

📌 避坑指南:我曾经在对比时忘了关随机性(比如 dropout 或数据增强),导致两次推理结果天然不同。所以对比前一定要把模型设成 eval 模式,固定所有随机种子。