diff --git a/docs/ML运行手册审查.md b/docs/ML运行手册审查.md new file mode 100644 index 0000000..570564c --- /dev/null +++ b/docs/ML运行手册审查.md @@ -0,0 +1,135 @@ +# 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` 未装)。这些通路只做过静态代码核对。