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`。
相关文件:
- dump 目录:`checkpoints/v9_10hz_eval_dump/v9_real_balanced_10hz`
- 统计脚本:[scripts/analyze_csv_dump.py](/apdcephfs_cq10/share_1603164/user/schmittzhu/code/unilm/beats/scripts/analyze_csv_dump.py)
## 1. 背景
用户的核心问题不是 “aggregate 指标多少”,而是:
1. `real_ov1 / real_ov2 / real_ov3` 到底差在哪;
2. 是类错、角度错,还是对的 track 没被最终输出;
3. `10Hz + real mix` 到底有没有把模型带坏。
为避免继续靠 `oracle_* / F20 / LE_CD` 猜,我们直接分析了导出的 `__pred.csv / __gt.csv`
## 2. 统计脚本
新增脚本:
```bash
python3 scripts/analyze_csv_dump.py \
--dump-dir checkpoints/v9_10hz_eval_dump/v9_real_balanced_10hz
```
默认行为:
- 不做阈值,直接分析 raw `__pred.csv` 的全部 track
分析阈值后的最终输出:
```bash
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_10hz``pred.csv` 保存的是 **每帧 4 条 raw track 输出**,不是已经过 `activity_prob>=0.5` 筛选后的最终预测。
这非常重要,因为它允许我们把问题拆成两层:
1. **raw 4-track 里有没有可用候选**
2. **过阈值以后,最终留下来的到底是什么**
## 4. Raw 4-track 结果
命令:
```bash
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` 后的结果
命令:
```bash
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:是不是纯阈值问题
命令:
```bash
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/frame` 从 `1.82 -> 2.15`
- `under_frames``161 -> 140`
- `no_same_cls``43.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`,先把问题拆成这三类,再决定改哪一层。