Files
Robot_Arm/docs/ML运行手册审查.md
T

136 lines
13 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# ML 运行手册审查(ml/README.md)
审查对象:`ml/README.md`(12 阶段运行手册)+ `ml/pipeline.sh` + `ml/gen|prep|model|sim|apg|mining|eval` 全部代码。
判据来源:`docs/Transformer轨迹拟合训练方案.md`(方案)。
硬件:本机 CBB-003,RTX 3090 24 GB(driver 617.42)、28 核 CPU、Python 3.12.10 + torch 2.10.0+cu130 + onnxruntime 1.22.0、Node v24.15.0。
方法:代码逐行读 + 在本机真跑第 2/4/5/6 步(两种头)与闭环仿真。**APG 及之后(8–11 步)未跑**,被中断,不声称可用。
结论:流程骨架是通的(对拍 PASS、数据生成、打包、预训练、闭环仿真都实测跑过)。问题集中在**判据自相矛盾**和**指标口径不一致**两类,不是代码写错。
---
## 一、实测记录(可复现)
冒烟产物落在 gitignore 目录 `ml/data/_smoke/`、`ml/runs/_smoke/`,工作树干净,`ml/assets/kin.json` 未重新生成。
| 步 | 命令 | 实测结果 | 手册声称 | 判定 |
|---|---|---|---|---|
| 2 对拍 | `node ml/eval/dump_parity.cjs 300` + `python -m ml.eval.check_parity` | `PASS: true`,fk 3.4e-13 mm、orient 3.3e-16、间隙 2.5e-13 mm、83 维特征 6.0e-8、间隙梯度相对误差 1.4e-6,7.6 s | 2 分钟,须 PASS | 符合 |
| 4 生成 | `node ml/gen/gen_dataset.cjs --n 80 --seed 7` | **1.56 s/条**,80 条 122 s;老师 plan p50 291 ms / p90 1490 ms,认证 p50 247 ms / p90 944 ms | 约 2 秒/核 | 符合(偏乐观余量) |
| 4 统计 | `node ml/gen/stats.cjs`(88 条) | keepRate **0.977**、samplesPerTask 36.5、projectedSamplesFor50k **178.4 万**、exec_s p50 2.3 / p90 3.0 / max 3.7 s、travel p50 350°、**cert.minGap p50 4.4 / p90 5.9 mm**、尾部补零样本占比 14.7% | keepRate≈0.95、projected≈180 万 | 符合,但 minGap 没进检查项(见 P0-2、口径-4) |
| 5 打包 | `node ml/prep/build_dataset.cjs` + `python -m ml.data --index` | 86 任务 → train 3004 / val 136 样本,`index.json` 键名与手册一致;增广 847 提交 / 5 拒绝 | train 170 万 / val 9 万(5 万条口径) | 比例自洽(5% split) |
| 6 预训练 MeanFlow | `python -m ml.train --steps 250 --no-eval --config ml/configs/base.json` | 参数量 **4.92 M**,吞吐 **6 208 样本/s**(step 200,batch=1024) | 1.5–6 小时;方案 R10 要 ≥2 万样本/s | 与 1.5–6 h 自洽(60 000 步 ≈ **2.8 h**),**与 R10 判据冲突** |
| 6 预训练 WTA | `--config ml/configs/wta.json --steps 40` | 跑通,参数量 4.93 M(同骨干换头成立) | 回退约 1 天 | 通路成立 |
| 闭环仿真 | `python -m ml.sim.closed_loop --split val --n 3` | 跑通 9.7 s,按 cat/mode 出 success/collision(未训模型 0/0,符合预期) | — | 通路成立 |
吞吐换算:60 000 步 × 1024 = 6 144 万样本 ÷ 6 200 = **9 910 s ≈ 2.75 h**(不含 eval)。2 万样本/s 意味着 51 分钟跑完 60 000 步——当前配置在 3090 上不可能达到。
---
## 二、P0:会让人在终端前停住或误判
### P0-1 训练吞吐判据自相矛盾(方案 R10 vs 手册)
- 方案 §10.1 R10:`2000 步吞吐 ≥ 2 万样本/s`,缓解写的是"降 epoch 或增大 batch"。
- 实测 6 208 样本/s → 按 R10 判"不达标",但 60 000 步 2.75 h 完全落在手册 1.5–6 h 的预算内。
- 训练是算力受限(MeanFlow 的 `torch.func.jvp` 双前向 + FK 损失),增大 batch 只拉长每步墙钟,samples/s 不上去。R10 给的缓解措施对它自己定的阈值无效。
- 手册 §6 只写"测吞吐",**没写通过线**:`ml/train.py:98` 打出 `samples_per_s`,读者看到 6k 无从判断该继续还是改配置。
建议:R10 阈值改为终态判据("60 000 步 ≤ 3 h")或把 samples/s 线降到 ~5 千;手册 §6 补一行"实测参考:本机 3090 batch=1024 → 6.2 k 样本/s ≈ 2.8 h/60 k 步"。
### P0-2 共识过滤分支的期望数字整段缺失
- `ml/pipeline.sh:27-31`:`consistentByGateRule < 0.9` 时自动加 `--consensus 4`。
- 方案 §10.1 R1 记录首测一致率 **78%**(100 任务 / 373 对邻居,门禁 90%)→ **默认走的就是 consensus 分支**。
- `ml/gen/gen_dataset.cjs:51`:邻居多数不同意就 `keep=false`(why=consensus)→ keepRate 与样本量双双下降。
- 手册 §4 的 `keepRate≈0.95`、`projectedSamplesFor50k≈180 万`(实测无共识 0.977 / 178 万)是**关共识**的口径;开共识后没有对应期望值,也没写"样本不够要不要加 N_TASKS"。
- §13 回传表要求按 `stats.json` 判下一步 → 判据缺一条分支。
建议:§4 增加共识分支的两行期望(keepRate≈? / projected≈?),并明确"低于 X 就把 N_TASKS 提到 8 万"这类动作。
### P0-3 WTA 回退会覆盖 MeanFlow 的训练产物
- `ml/pipeline.sh:34-35`:`train` 阶段输出目录写死 `ml/runs/bench` 与 `ml/runs/base`,`CFG` 只换头不换目录。
- `ml/pipeline.sh:37`(m5)与 `:44`(apg)写死读 `ml/runs/base/best.pt`。
- `ml/train.py:57`:`log.jsonl` 以 append 打开 → 两次不同头的日志混在同一文件。
- 后果:手册 §7 的 `CFG=ml/configs/wta.json bash ml/pipeline.sh train` 会盖掉已训好的 MeanFlow `best.pt/last.pt`,对比物消失;而方案 §1.1 选头的依据恰恰是两者对比(沙箱里两者 100%/0%,"分不出高下")。
建议:`OUT=${OUT:-ml/runs/base_$HEADTAG}`,m5/apg/bench 用 `CKPT=` 变量指;两头的 run 分目录共存。
### P0-4 手册要求 Linux/WSL2,但本机 Windows 原生可跑,只差一处
- 实测第 2/4/5/6 步与闭环仿真在 Windows + Git Bash 下全部跑通(Python 用 `python`)。
- `ml/prep/run_prep.sh:8` 硬用 `python3`,而 Windows 的 `python3` 是 `WindowsApps` 假壳(`python3 -c` 直接 exit 1)→ 第 5 步在**最后一步**失败,`set -e` 会让 `pipeline.sh all` 在此中止(前面的 npy 已写好,重跑代价大)。
- 同类:`ml/pipeline.sh` 内联的 `python -c`(gate1 的 CONSENSUS 判定、m5 的打印)用的是 `python`,在 Windows 没问题 → 两个脚本各用一种,本身就是不一致。
建议:统一 `${PYTHON:-python}`(或 `${PYTHON:-python3}`);手册 §1 补一句"Windows 原生实测可跑,需 Git Bash + `python` 在 PATH"。
---
## 三、口径不一致("这一步通过"不等于"部署能过")
### 口径-1 闭环仿真的安全层 ≠ 部署运行时的安全层
- 仿真只有"逐步候选干涉则换下一条"(`ml/sim/closed_loop.py:118-130`)。
- 运行时多出:1 步胶囊梯度投影(`webapp/js/ik-policy.js:107`)、刹停段 + 每条候选 40 次距离查询预算(`:177`)、安全层单次推理 30 ms 预算(`:322`)、卡死检测与换向锁 1 s(`:296-304`)。
- §6 EVAL、§7 M5 门禁、§9 挖错/门禁**全部**用仿真那套(默认 `safety=False`)。
- 于是 §7 的"穿柱率 ≤2%"和 §11 的"collisionFrames 必须为 0"是两把尺,互不预示;手册没有任何一处说明这点。
建议:§7 明说"M5 是纯策略指标,§11 是策略+安全层指标";m5 对同一门禁集加跑一遍 `--safety`,两个口径都写进 `m5_gate.json`。
### 口径-2 门禁集/挖错题的时长预算是假的
- `ml/mining/tasks.py:47` 每题写死 `exec_s: 3.0, travel: 0.0`。
- `ml/sim/closed_loop.py:67` 超时 = `clamp(2*exec_s, min=3)` = 6 s;`ml/mining/mine_round.py:38` 又用 `max_sec=6.0` 覆盖。
- 后果:§7 M5 的 1000 题、§9 的门禁集里,"到达"一律 6 s 硬顶、`time_ok_1p3` 一律 3.9 s;而 §6 训练期 EVAL 用的是老师真实时长 ×1.3。两个"到达率"不可比却共用同名指标。`travel=0` 还使 `travel_ratio_median`(`closed_loop.py:154`)在门禁集上直接返回 None。
- 方案 §10.1 R8"3 s 内恢复 ≥95%、活锁=0"在 12 步里没有执行点。
建议:`tasks.py` 出题时带上老师时长(或明确写"门禁集按定长 6 s 口径");R8 补对抗用例集与命令。
### 口径-3 APG 的"到达"是定长 3.6 s 窗口内的距离塑形,且碰撞只查端点
- `configs/apg.json`:`plans:60`,每次推理提交 3 步 × `DT=0.02` → 展开 **3.6 s**(`ml/apg/apg_finetune.py:67`),无"到达即停";到达项只在每个 10 块段末用 `((T-pe)/100)²`(`:104-109`)。
- 实测这批老师轨迹 exec_s p50 2.3 / p90 3.0 / max 3.7 s → 样本刚好压线;真数据里老师时长 >3.6 s 的绕远长任务(正是 C/B 难题)APG **永远看不到绕出段**。
- 碰撞 hinge 只打每步末端点(`:95-97`),仿真与运行时都查端点+中点(`closed_loop.py:142-144`、`ik-policy.js:222`)。
- 手册 §8 写"直接优化到达、碰撞余量",读者会以为是全 horizon 到终点。
建议:§8 补一句"定长 3.6 s 滚动 + 段末距离替代到达项";把 `plans` 提到覆盖 exec_s p90(≥55 s 不现实,折中:对 exec_s>3.6 s 的题按比例加 plans,或在 README 说明这是已知截断)。
### 口径-4 训练余量 5 mm 压在老师轨迹自身的间隙分布上
- 实测 88 条 keep 轨迹 `cert.minGap` **p50 4.4 mm / p90 5.9 mm**(`ml/gen/stats.cjs:18` 已算出 `vertexMinGapMm`)。
- `docs/collide.json` 的 `margin_mm = 0.3`,`kin.gaps()` 的 gap 已减掉它 → 这 4.4 mm 是实打实的几何间隙。
- `configs/apg.json` 的 `margin_train_mm = 5.0` + 运行时投影目标 `margin:5`(`ik-policy.js:174`)→ **约一半 BC 标签落在 5 mm 以下**,APG 碰撞项与 BC 项方向相反。
- 手册 §4 让检查的三项(keepRate / byCatMode / projectedSamples)里没有 `vertexMinGapMm`;方案 §7.1 只写"margin=认证+5",没和老师的间隙分布对齐。
建议:§4 检查项加 `vertexMinGapMm` 并给期望区间;要么 `margin_train_mm` 降到老师分布 p50 附近(~4 mm),要么承认 BC/APG 有对抗并把它当成设计取舍写下来。
---
## 四、缺项与细节
1. **验收表落不了地**:方案 §9 要求 held-out 可达 ≥98%、D 类停靠 ≤老师+5 mm、刹停发生率 <2%、R7 左右比例与行程门禁、R8 对抗用例——12 步里都没有对应命令。`ml/mining/gate.py:41` 只查 3 项(到达增益 / A 类降幅 / 上轮仍对);`tests/policy_bench.cjs:81` 已经算出 `brakes/locks/uncertifiedSegs` 但没进任何门禁。
2. **挖错池累积**:`ml/mining/loop.sh:20` `ls ml/runs/mine/r*/pool.jsonl` 把**所有历史轮**的错题池喂给每轮 APG,池子逐轮变大,且 `mine_round.py:57` 对 E1 复制 ×2、每题再带 10 个邻居。手册 §9 只说"错题与邻居进采样池",没说会跨年累积 → 后期轮次的采样分布严重偏向老错题(A 类降幅门禁是唯一的兜底)。
3. **fp16 导出方向可疑**:手册 §10 把 `--fp16` 报错当偶发("去掉 --fp16 手动导出 fp32")。但部署端是 wasm(`webapp/js/ik-policy-glue.js:36` 默认 wasm)和 Node CPU(`tests/policy_bench.cjs:55` `executionProviders:['cpu']`),fp16 在 CPU EP 上要么缺 kernel 要么靠大量 Cast 兜底,不保证比 fp32 快。参数量实测 4.92 M → fp32 ≈ 20 MB(与手册一致),fp16 省的 10 MB 对浏览器收益有限。**本机 `onnxconverter_common` 未装,此条未实测。**
4. **`--n` 同时控制两个集合**:`tests/policy_bench.cjs:85-86` 的 `+opt('--n')` 对 nc 和 route 一起生效,手册说的"30 例 / 40 例"只在默认值成立。
5. **val 为空时崩**:小样本摸底(几百条、5% split 可能 0 个 val 任务)下 `ml/sim/closed_loop.py:161` 的 `evaluate` 返回空 dict,`ml/train.py:106` 取 `res['success']` KeyError。真实数据不会撞,但手册鼓励先小跑摸底。
6. **文件地图缺 4 个真实文件**:`ml/gen/cert.cjs`(认证实现在 ik-policy.js,这里是跳转壳)、`ml/gen/pathdev.cjs`(同伦类判定,共识过滤与门禁都依赖它)、`ml/prep/npy.cjs`、`ml/toy/toy_bimodal.py`(方案 §沙箱 的依据)。
7. **R2 无执行点**:方案要求"近邻样本标签方差 <10% 步长、起步失败率=0",手册 §3–§5 的检查项里没有。
---
## 五、按优先级的改动清单
| 优先级 | 改什么 | 落点 |
|---|---|---|
| 1 | 吞吐判据对齐:R10 改成终态判据或降线,§6 写实测参考值 | `docs/Transformer轨迹拟合训练方案.md` §10.1、`ml/README.md` §6 |
| 2 | train 阶段输出目录随头分开,m5/apg/bench 用 CKPT 变量 | `ml/pipeline.sh:34-37,44,48` |
| 3 | `python3` → `${PYTHON:-python}`,§1 说明 Windows 原生可跑 | `ml/prep/run_prep.sh:8` |
| 4 | §4 补共识分支的 keepRate/样本量期望与"加 N_TASKS"动作;检查项加 `vertexMinGapMm` | `ml/README.md` §3–§4 |
| 5 | §7 说明 M5 与 §11 两个口径,m5 加 `--safety` 对照 | `ml/pipeline.sh:36-42`、`ml/README.md` §7 |
| 6 | 出题带真实老师时长(或明写定长 6 s),补 R7/R8 执行点 | `ml/mining/tasks.py:47`、`ml/mining/gate.py:41`、`ml/README.md` §9 |
| 7 | §8 明写 APG 的 3.6 s 截断与只查端点;`margin_train_mm` 与老师间隙分布对齐 | `ml/README.md` §8、`ml/configs/apg.json` |
| 8 | §10 默认 fp32 + `__POLICY.latency()` 实测后才考虑 fp16(仅 WebGPU);loop.sh 池子只取本轮;文件地图补全;evaluate 空任务保护 | `ml/README.md` §10/文件地图、`ml/mining/loop.sh:20`、`ml/sim/closed_loop.py:161` |
未验证范围:第 7(m5)、8(apg)、9(mine)、10(export)、11(bench)步与浏览器 `?policy=1` 第 12 步都没跑过(`ml/node_modules` 未安装、`webapp/models/` 无模型、`onnxconverter_common` 未装)。这些通路只做过静态代码核对。