Spatial-BEATs / docs /0424.md
dieKarotte's picture
Add files using upload-large-folder tool
29ab2d0 verified
|
Raw
History Blame Contribute Delete
7.64 kB

2026-04-24 — v9_real_balanced_10hz real dump 诊断

本文档记录 v9_real_balanced_10hz 在真实数据 dump 上的直接 CSV 诊断结果,不依赖训练日志里的 aggregate val_metrics

相关文件:

1. 背景

用户的核心问题不是 “aggregate 指标多少”,而是:

  1. real_ov1 / real_ov2 / real_ov3 到底差在哪;
  2. 是类错、角度错,还是对的 track 没被最终输出;
  3. 10Hz + real mix 到底有没有把模型带坏。

为避免继续靠 oracle_* / F20 / LE_CD 猜,我们直接分析了导出的 __pred.csv / __gt.csv

2. 统计脚本

新增脚本:

python3 scripts/analyze_csv_dump.py \
  --dump-dir checkpoints/v9_10hz_eval_dump/v9_real_balanced_10hz

默认行为:

  • 不做阈值,直接分析 raw __pred.csv 的全部 track

分析阈值后的最终输出:

python3 scripts/analyze_csv_dump.py \
  --dump-dir checkpoints/v9_10hz_eval_dump/v9_real_balanced_10hz \
  --threshold 0.5 \
  --threshold-sweep 0.3 0.4 0.6

脚本会输出两类统计:

2.1 GT-side

对每个 GT source/frame 看:

  • hit_cls_and_angle 含义:至少存在一个同类预测,且最佳角误差 <=20°
  • class_right_angle_wrong 含义:存在同类预测,但最佳角误差 >20°
  • no_same_class_pred_but_other_preds_exist 含义:这帧模型有别的 active 预测,但没有任何同类预测
  • no_pred_in_frame 含义:这帧一个 active 预测都没有

2.2 Pred-side

对 threshold 后的预测看:

  • matched_tp 含义:能和某个 GT 做同类且 <=20° 的匹配
  • same_class_angle_wrong_fp 含义:有同类 GT,但角度没进 20°
  • wrong_class_or_spurious_fp 含义:没有任何同类 GT

3. 一个重要事实:dump 里的 pred.csv 不是最终输出

这次 v9_real_balanced_10hzpred.csv 保存的是 每帧 4 条 raw track 输出,不是已经过 activity_prob>=0.5 筛选后的最终预测。

这非常重要,因为它允许我们把问题拆成两层:

  1. raw 4-track 里有没有可用候选
  2. 过阈值以后,最终留下来的到底是什么

4. Raw 4-track 结果

命令:

python3 scripts/analyze_csv_dump.py \
  --dump-dir checkpoints/v9_10hz_eval_dump/v9_real_balanced_10hz

核心结果:

4.1 real_ov1

  • avg_gt/frame = 1.00
  • avg_pred/frame = 4.00
  • hit_cls_and_angle = 54.2%
  • class_right_angle_wrong = 45.8%
  • no_same_class_pred_but_other_preds_exist = 0.0%

解释:

  • raw 4 条里,每个 GT 都能找到同类候选
  • 其中一半以上角度也已经进了 20°
  • 所以单源 real 上,raw 候选并不差

4.2 real_ov2

  • avg_gt/frame = 1.98
  • avg_pred/frame = 4.00
  • hit_cls_and_angle = 37.4%
  • class_right_angle_wrong = 56.9%
  • no_same_class_pred_but_other_preds_exist = 5.7%

解释:

  • raw 4 条里,大多数 GT 还是能找到同类候选
  • 主问题已经是角度本身错

4.3 real_ov3

  • avg_gt/frame = 2.88
  • avg_pred/frame = 4.00
  • hit_cls_and_angle = 33.9%
  • class_right_angle_wrong = 41.6%
  • no_same_class_pred_but_other_preds_exist = 24.5%

解释:

  • 即使给满 4 条 raw 候选,仍有 24.5% 的 GT 找不到任何同类预测
  • 所以 real_ov3 从 raw 层面就已经有明显 class/source binding 问题

5. activity>=0.5 后的结果

命令:

python3 scripts/analyze_csv_dump.py \
  --dump-dir checkpoints/v9_10hz_eval_dump/v9_real_balanced_10hz \
  --threshold 0.5

5.1 real_ov1

  • avg_gt/frame = 1.00
  • avg_pred/frame = 1.14
  • hit_cls_and_angle = 22.4%
  • class_right_angle_wrong = 40.2%
  • no_same_class_pred_but_other_preds_exist = 37.3%

解释:

  • raw 4-track 时,同类候选是 100% 存在的
  • 过阈值后,37.3% 的 GT 直接变成 “这帧有别的 active 预测,但没有同类预测”
  • 这说明 real_ov1 的主问题不是 “不会预测”,而是:
    • 对的 track 没被留住
    • 或被别的错 track 抢走
    • 也就是 decode / track ranking / calibration 问题

5.2 real_ov2

  • avg_gt/frame = 1.98
  • avg_pred/frame = 1.93
  • hit_cls_and_angle = 17.9%
  • class_right_angle_wrong = 73.9%
  • no_same_class_pred_but_other_preds_exist = 8.2%

解释:

  • 轨数和 GT 基本对齐,不是明显少报
  • 主要失败项是 同类有了,但角度错
  • 所以 real_ov2 主问题不是 threshold,也不是主要类错,而是 角度本身错

5.3 real_ov3

  • avg_gt/frame = 2.88
  • avg_pred/frame = 1.82
  • 247 帧里有 161 帧是 pred < gt
  • hit_cls_and_angle = 26.3%
  • class_right_angle_wrong = 30.2%
  • no_same_class_pred_but_other_preds_exist = 43.5%

解释:

  • 这里同时有三件事:
    1. active 轨数不够
    2. 同类 track 经常找不到
    3. 即使找到了,同类里也有不少角度不对

因此 real_ov3 是:

  • binding
  • decode 少亮轨
  • angle 也错

三件事叠在一起。

6. Threshold sweep:是不是纯阈值问题

命令:

python3 scripts/analyze_csv_dump.py \
  --dump-dir checkpoints/v9_10hz_eval_dump/v9_real_balanced_10hz \
  --threshold 0.5 \
  --threshold-sweep 0.3 0.4 0.6

6.1 real_ov1

0.3 -> 0.6

  • avg_pred/frame 几乎不变:1.14 -> 1.05
  • hit 基本只在高阈值 0.6 时下降
  • no_same_cls 一直很高:37.3% -> 43.4%

结论:

  • 不是简单阈值问题
  • 更像是对的 track 本来就没排到最终输出前面

6.2 real_ov2

0.3 -> 0.6

  • avg_pred/frame 几乎不变:1.99 -> 1.91
  • hit 几乎不变:17.9% -> 17.8%
  • class_right_angle_wrong 一直卡在 73% 左右

结论:

  • 几乎完全不是 threshold 问题
  • 就是 角度头本身错

6.3 real_ov3

0.5 -> 0.3

  • avg_pred/frame1.82 -> 2.15
  • under_frames161 -> 140
  • no_same_cls43.5% -> 34.7%
  • hit 只从 26.3% -> 27.0%

结论:

  • 降阈值确实能缓一点 “少亮轨”
  • 但收益有限,根问题还在
  • 所以 real_ov3 不是纯阈值问题

7. 最终结论

7.1 每个 split 的主问题

  • real_ov1

    • 主问题:decode / track ranking / calibration
    • 证据:raw 4-track 同类候选 100% 存在,但阈值后大量 GT 找不到同类 track
  • real_ov2

    • 主问题:角度本身错
    • 证据:轨数基本对,class 也不是主要问题,但 73.9% 变成 “同类有了但角度错”
  • real_ov3

    • 主问题:binding 错 + 少亮轨 + 角度错
    • 证据:
      • raw 层 already 24.5% 找不到同类
      • threshold 后 avg_pred/frame = 1.82 < 2.88
      • 同时还有 30.2% 的同类角度错

7.2 这次问题不是一句 “real 很差” 能说清的

更准确的说法应该是:

  • real_ov1:内部候选还可以,但最终输出选坏了
  • real_ov2:主要是 spatial regression 错
  • real_ov3:multi-source 下 source binding 和 spatial 一起掉了

7.3 这也解释了为什么只看 aggregate 指标会误判

同一个 LE_CD / F20 很差,背后可能是三种完全不同的失败机制:

  • 对的候选存在,但没被输出
  • 同类 track 有了,但角度偏得很远
  • raw 4-track 里就没把 source 绑定出来

所以以后继续看 real dump 时,应该固定用 scripts/analyze_csv_dump.py,先把问题拆成这三类,再决定改哪一层。