2026-10-20 02:40:12 +08:00
# 探索日志:Transformer 机械臂闭环控制
长期锚点:`docs/Transformer轨迹拟合训练方案.md` §9.2(部署形态 = 策略 + 安全层)。
验收口径(§9.2):实际执行碰撞 = 0;held-out 可达任务到达率 ≥ 98%;到达用时 ≤ 老师 ×1.3;关节行程 ≤ 现有规划器 ×1.10;冷启动 < 10 ms;每次推理 + 安全认证 P99 < 20 ms;刹停发生率 < 2% 的推理周期;策略单独(关安全层)碰撞率 < 3%。
2026-10-20 21:55:15 +08:00
记录顺序:**倒序**,最新一轮在最上面(2026-10-20 起,用户要求:打开就看到最近一轮)。
2026-10-20 02:40:12 +08:00
评测约定:val 任务、部署节奏(r = 3 重规划、1 段采样、K=8);「纯策略」= 关安全层;「部署」= 开安全层。时延:桌面 RTX 3090 上 `sample_k(B=64, K=8)` 墙钟均值(均值,非 P99);浏览器 ONNX P99 以 §9.2 R4 的独立测量为准。
2026-10-20 17:06:53 +08:00
**口径更正(2026-10-20,轮次 29 复核;下列历史原始数值保留):**
- 轮次 24–28 的“50 Hz 可行/连续无饥饿”结论撤回。同步 `await plan(); tick()` 不是实际 20 ms 调度;`starveTicks` 只是耗时除以 20 ms 的估算。组件分位数相加不等于整次规划 P99,实测 62–68 ms 也超过 commit=3 的 60 ms。仍须严格认证下的真查看器 R9 测量,且不放松 §9.2 的 P99 < 20 ms。
- Python 端点/中点检查不等于连续认证;JS `--seg 0` 是放松安全的消融,不是部署验收。开安全层碰撞必须为 0,不能套用“纯策略 <3%”判据。既有到达率允许途中碰撞,新指标 `collision_free_success` 才是时限内无碰撞到达率。
- `replan=empty` 是同步仿真的零前缀配方,不是已验证的异步执行配置。所有任务(含 D)继续保留在历史对照分母内;不能与 held-out 可达任务 ≥98% 直接比较。
- 轮次 26 的几何角速度雅可比不等于远离目标时 skew 姿态残差的精确导数,因而既改变控制律又消除差分误差;不能把全部收益归因于去噪。3.58% 是单个位置雅可比样本对拍,不是普遍噪声界。`check_dls.py` 中标 B=256 的测量实际仅有 64 行,不能引用为 B=256 性能。
- `err_fail_med` 是批次结束时未按时到达任务的末端误差,不是每题截止时误差;仿真墙钟/题也不是单次规划延迟。查看器默认选择器仍为 consist,endpoint 仅是可选实验。
2026-10-20 07:23:16 +08:00
2026-10-20 02:40:12 +08:00
## 轮次统计
2026-10-20 21:59:19 +08:00
- 连续无实质进展轮数:0。
- **当前最好(n=256 val,同 seed 同批)**: `ml/runs/base_dag2_dag1/best.pt` + `K=8, select=endpoint, replan=empty, commit_n=2, fb=2.2, fb_block_gain=0.5, dls_safety=1, safety=1` → **到达 57.4%、无碰撞到达 57.4%、时限内(≤1.3×老师) 39.1%、刹停 19.25/题、行程比 2.445、2 s 误差比 0.210** (轮次 33 base)。
- **但这组数含超速**: `speed_ratio_p50=1.660` 、`over_vmax_rate=1.000` ⇒ 每轴实际最大速度是 VMAX 的 1.66 倍(反馈叠在 ±1 限幅之后,轮次 30 定位)。按合法限速 `--inc_cap 1` 重测是 **到达 52.3% / 时限内 26.6%** (轮次 33 cap)。**验收要引用后者**,两者的差就是"以前的分数有一部分是超速换来的"。
- n=512 复核在轮次 28– 30 给过 50.8–52.1%;当前配方(含 `inc_cap` )尚未在 n=512 重跑。
2026-10-21 01:48:46 +08:00
- **合法限速口径下的当前最好格(轮次 51,2×2 补全后)**:`K=16 + select=pre + commit_n=2 + fb=2.2 + inc_cap=1 + cert_batch=1` → **到达 56.6%、时限内 35.9%、2 s 误差比 0.138、行程比 2.414、刹停 14.20/题、碰撞 0、超 VMAX 0** 。相对历史控制(K8 endpoint 0.5234/0.2656)逐题赢 20 丢 9 = 净 +11 题,**McNemar p=0.061 ⇒ 到达仍未确立**; `goal_ratio_2s` 201:55( p=1.0e−20)是这条线最硬的证据。两条杠杆**在时限上可加(无交互)、在到达上饱和**(K16 之上再加 `pre` 只净 +1 题,p=1.0)。
- **口径提醒(对所有历史数字生效)**:`ok = done & (t_done ≤ max(2×老师用时, 3 s))` ⇒ 本链引用的"到达率"本身就带 2× 时限,`time_ok_1p3` 才是 §9.2 的 1.3× 口径,两道门不能混着引用。
2026-10-20 21:59:19 +08:00
- **实时性(GPU,B=1、K=8、一步)**:整周期 P50 33.5 ms、P99 64.7 ms;批量认证把最坏情况从 80.2 → 37.1 ms(轮次 34)。仍未进 §9.2 的 P99 < 20 ms,瓶颈是几何查询不是推理(推理 7.2 ms)。
- **安全层口径**:线上只做**端点 + 中点**点检(`gaps(...).min(-1) > 0` )。轮次 30 那条"认证通过仍碰撞"(−0.149 mm)已被连续段认证抓住(`certify_uniform` n≥8、二分 5 次查询),但它进不了实时预算(轮次 31–32)。
- **失败结构(轮次 38,147 到达 / 109 未到)**:**63 题是走一半被冻住**(离目标 >100 mm 且刹车 >30 次)、23 题方向错、位置差 20~100 mm 15 题、差 5~20 mm 5 题、姿态没到位 3 题、起步失败 0;未到组活动窗内 37% 的步是零运动。
- **与 §9.2 的差距**:到达 52.3% vs ≥98%;时限内 26.6% vs 100%;刹停远大于 2% 的推理周期;P99 未达标。碰撞口径已达标(执行 0)。
- **已试过的训练法(轮次 19–22)都没超过 dag2 基线**:APG(管线修复但尺度失控)、反馈蒸馏(未内化)、DAgger-3(39.5%)、冻结编码器(41.8%)⇒ 再提到达率优先走"推理/选择/安全层"这条,而不是先重训。
- **规矩**:大规模训练与扩数据都要用户放行;不许用放松碰撞/安全/精度/实时来换分数;负结论与本表一起留档(本文件就是报告系统,`ml/monitor.py` 的 `/api/explore` 直接渲染它)。
## 算法优化候选(按实测证据强度排序,2026-10-20)
| 序 | 候选 | 支撑证据 | 状态 |
|---|---|---|---|
2026-10-21 00:33:44 +08:00
| 0 | ~~把"沿路最小间隙"接进候选打分~~ (极端版 = `--tie 1` :只在"前缀最长"的并列集合内按余量定夺,零额外几何) | 轮次 45 两臂:到达 −1.95 pp(净 − 5 题,McNemar p=0.125 与零不可分)、时限 +1.17 pp、刹停 −9%、行程 − 0.076、**碰撞仍 0**;且分辨率被 `gcap=0.5 mm` 截顶锁死(并列 79% 但只有 5.6% 可分辨,与轮次 44 离线 5.6% 对上) | **判掉** :买余量卖进度,且作用在 `maxlen>0` 的人群——失败主人群是全拒(`maxlen=0` )。前置条件见 #28 |
| 0b | ** #28 抬宽相位截顶 `gcap` 并与 `gap_margin` 解耦** | 现在 `--gap_margin 1.5` 会同时抬截顶值和验收门限,动一个必动另一个;`_coarse` 保留 `d ≤ cp_lim + cap` 的胶囊对 ⇒ 成本随壳层体积涨,而 GPU 周期 P50 已 33.5 ms | 未实现(要新增只改数值精度的参数,不许碰判据) |
2026-10-20 22:38:47 +08:00
| 1 | **候选数翻倍 K=8→16** | 轮次 39 实测:到达 ** +3.9 pp**、时限内 ** +3.1 pp**、**刹车 − 30%**( 19.55→13.77)、碰撞仍 0、行程比不变 ⇒ 很多"全拒"是**没备选**而不是真没路 | **正向** ;认证/打分成本要用独占微基准量完才能谈部署 |
2026-10-21 00:57:08 +08:00
| 2 | ~~全拒时缩步顶上~~ ( `--backoff` ) | 四臂实测:转化率 7.7%→37%(能救回停步),但到达 0.5234→0.5156 **不赚** ;且它单独把 `brake_rate` 改善 16% 而行为没变好 ⇒ **可以绕过 §9.2 的刹停判据** ,这是仪表漏洞不是收益 | **已判掉** (轮次 43);同时把 §9.2 的刹停口径标记为"不可由缩步单独满足" |
| 3 | ~~白费比例惩罚~~ ( `select=ep_waste --len_w` ) | 三臂实测行程比不降反升,给出原因:**罚的是没被执行的那段地平线**(16 步打分地平线 vs 实际提交 2 步) | **已判掉** (轮次 42);其诊断直接引出 #29 (把打分地平线换成真会执行到的位置) |
| 3c | ** #29 打分地平线 = 被执行的前缀**( `select=pre` :用 `fut[:,:,commit_n]` 的终点误差代替 `fut[:,:,-1]` ) | 两 seed 独立复现:2 s 误差比符号检验 192:64( p=5e− 16) / 191:65( p=1.5e− 15),时限内 +6.64/+4.30 pp,行程比 − 0.171/− 0.171, **碰撞仍 0**;到达只 +5/+3 题(McNemar p=0.42/0.68 ⇒ 噪声);代价是到达题末态误差 0.22→0.42 mm(判据壳内但余量 4.6×→2.4×) | **正向(时限/进度显著、到达未显著)** ,作可选口径入库,不改默认。下一试 #30 |
2026-10-21 01:11:18 +08:00
| 3d | ~~#30 前瞻长度曲线~~ ( `pre_h` , h=2/4/8/16) | 轮次 48 四点实测:时限内 0.2656/0.2813/0.3047/**0.3320**, 2 s 误差比符号检验随 h 缩短单调增强(p=2.4e− 6/1.8e− 12/4.9e− 16),**到达四点全在噪声内**;末态误差 0.2175/0.2255/**0.3301/0.4151** ⇒ 代价集中在 h≤4; h=8 是坏点(行程比 2.6749 反而最差) | **已完成** :形状=进度单调、精度阶跃在 h≤4。作废 #26 ,派生 ** #31 ** |
| 3e | ** #31 门控地平线**(远端用短前瞻、近终段用整条地平线,一个阈值参数) | 轮次 48 的曲线直接给出机制:时限收益来自短前瞻,精度损失来自"近终段没有终端代价"。若两者能解耦,`time_ok` 与 `err_success_med` 就不必此消彼长 | 待实现(`pre_h` 已在,只差按当前误差选 h) |
2026-10-20 22:38:47 +08:00
| 3b | ~~行程惩罚 `ep_len`(罚候选累计行程)~~ | 三臂实测行程比 2.6216/2.6548/2.6719 vs 对照 2.6158 ⇒ **不降反升** ,只换来 +2 pp 时限 | **负结论** ,被 3 取代 |
| 4 | **一步角点的标定** ( E1 那条线:`mf_target='mid'` 把自举导数移到中点) | 解析高斯场判据:`sq` 只线性收敛(结构性少修一半)、`mid/lin` 二次收敛;实测部署角偏差 MF 3.851 → `mid` 2.364(0.61×);但**线上一步输出比自身两段采样离老师远 10 倍**(4.326 vs 0.434) | 开关已落、默认关;要付训练,且受"一步与认证/DAgger 共同标定"约束 |
| 5 | **认证进 20 ms** ( #16/#18 ) | GPU 周期 P50 33.5 ms,几何宽相位占大头;f32 认证需先抬 eps 到 2e−4 mm | 未解,是验收硬门槛 |
| 6 | 速度/余量口径(#11/#14 ) | `--inc_cap 1` 代价 − 5.1 pp 到达、−12.5 pp 时限;`gap_margin 0.5 mm` 只付 3 题 | 已量化,投影式余量未移植 |
| 7 | 循环内共享 FK( #19 )、FP16/BF16、流水线复用 | 实测分别只有 0.03 ms/次、负收益、−3.1 ms 且扰动特征 | **已判掉** |
2026-10-20 07:40:16 +08:00
2026-10-21 01:55:57 +08:00
## 轮次 53: seed=1 的逐题配对——`pre` 在 §9.2 自己的 1.3× 口径上复现(p=0.035),门控 20 mm 那臂只有 +1 题
2026-10-20 22:05:12 +08:00
2026-10-21 01:55:57 +08:00
- **只跑一条控制臂**(同配方同 seed=1,带 `t_exp` )就能给轮次 47/50 已有的两臂补上配对 ⇒ 先自证确定性:这条控制臂与轮次 47 的控制 **22/22 老键逐位相同** 。
- **1.3× 口径逐题配对(vs 各自 seed 的控制)**:
2026-10-20 22:05:12 +08:00
2026-10-21 01:55:57 +08:00
| 口径 | seed=0 | seed=1 | 合并(各自配对的不一致对相加) |
2026-10-20 22:33:29 +08:00
|---|---|---|---|
2026-10-21 01:55:57 +08:00
| K8 `pre` | 22 新增 / 5 失去,净 ** +17**, p=0.0015 | 17 / 6,净 ** +11**, **p=0.035** | 39 / 11,净 +28, **p=9.0e− 5** |
| 门控 20 mm | 22 / 6,净 +16, p=0.0037 | 12 / 11, **净 +1, p=1.0** | 34 / 17,净 +17, p=0.024 |
2026-10-20 22:33:29 +08:00
2026-10-21 01:55:57 +08:00
- **要修正轮次 50 的一处措辞**:当时写的是门控的时限收益"塌了"。按配对检验的准确说法是**门控把收益吃掉约四成**(合并 +17 对 `pre` 的 +28),而且损失集中在 seed=1 那一臂(+1 题,p=1.0)。⇒ 原判断("门控不是免费午餐,是用时限换末态余量")不变,但强度被我说过了一层。合并检验只是近似:同一批题、不同噪声抽样,两臂并非完全独立。
- **`pre` 这条线到此定性**:**"打分地平线 = 执行地平线"能在不放松任何判据(碰撞 0、超 VMAX 0、n_plans 不变)的前提下,把 §9.2 的"到达用时 ≤ 老师×1.3"这一栏显著往上抬,两个 seed 都复现**;它对"到达率"(自带 2× 预算那道门)没有可用效应。⇒ 下一轮的取舍不该再是"怎么调这条轴"(#30/#31 已把形状量尽),而是**末态余量**要不要用轮次 52 的门控换、以及把预算转到 B/C 类的数据侧(#27 的结论仍未被任何后续轮次推翻)。
2026-10-20 22:13:44 +08:00
2026-10-21 01:48:46 +08:00
## 轮次 52:补上逐题老师用时这把尺子之后,整条"打分地平线"线的结论要翻面——1.3× 口径上的时限收益是显著的
- **仪表缺的是什么**: `--dump` 的逐题行里没有老师用时,所以 §9.2 的 `time_ok_1p3` (≤1.3×老师)此前**只能报整批比例,做不了逐题配对**。本轮把 `t_exp` (老师用时)与 `tr_ref` (老师行程)写进每一行——它们是**题目属性、与臂无关**,所以只要有一条带新字段的控制臂落盘,就能按题号 join 给**所有历史臂**补上配对能力。
- **改了落盘代码必须先自证没动行为**:重跑同配方控制臂 ⇒ **22/22 老键逐位相同** ( `docs/experiment_round52_ctl_ex.json` vs `round45_tie0` )。顺带核对 `limit = 2× t_exp` ( 3.48 s ⇒ 6.96 s),把轮次 51 那句"到达自带 2× 时限"从推断变成实测。
- **逐题配对(vs K8 `endpoint` 控制,n=256、seed=0;判据 = ok 且 `t_done ≤ 1.3·t_exp` ) **:
| 臂 | 新增达标 | 失去达标 | 净 | 精确 McNemar p |
|---|---|---|---|---|
| **K16 `pre`(最好格)** | **27** | **3** | ** +24** | **8.4e− 6** |
| K8 `pre` | 22 | 5 | +17 | **0.0015** |
| 门控 5 mm | 23 | 6 | +17 | 0.0023 |
| 门控 20 mm | 22 | 6 | +16 | 0.0037 |
| K8 `pre` h=4 | 15 | 5 | +10 | 0.041 |
| K16 `endpoint` | 17 | 9 | +8 | 0.169 |
| K8 `pre` h=8 | 11 | 7 | +4 | 0.481 |
| `tie=1` (轮次 45) | 3 | 0 | +3 | 0.250 |
- **这条表纠正的是我自己的判读,不是数据**:轮次 46–51 我一直拿 `success` (自带 2× 预算的那道门)做逐题配对,于是写成"到达与时限收益都在噪声内"。换成 §9.2 真正的 1.3× 口径,`pre` 系列的收益是 **p=0.0015 与 8.4e− 6** ——整条线最硬的一条证据。⇒ ** "到达率没显著变化"仍然成立**(2× 那道门上是净 +1/+5/+11、p≥0.06),但**"时限内到达"这道门是明确被买到的**。两栏必须分开写,之前混过一次。
- **同时被这张表重新定位的两条旧结论**:`K16+endpoint` 的时限收益(+8 题)其实不显著(p=0.169)——轮次 39 报的"+3.1 pp 时限"当时没有配对检验;h=8 那臂在 1.3× 口径下也是 p=0.48 ⇒ 轮次 48 说 h=8 是坏点,现在有了第二重证据。`tie=1` 在 1.3× 上只有 +3 题(p=0.25)且到达净 −5 ⇒ 判掉不变。
- **待办**: seed=1 的 `t_exp` 正在补落盘(轮次 53),以便把轮次 47/50 那句"整批 +4.3 pp / +0.39 pp"也换成配对 p 值。
- **口径纪律**: `--pre_near` 、`--pre_h` 、`--tie` 都是可选口径,默认仍是 `endpoint` 。§9.2 的验收栏仍按"到达未确立、时限内已确立(seed0 配对)"来写,等 s1 配对完成再决定是否给到达之外的第二栏正式换配方。
## 轮次 51: 2× 2 补全(K∈{8,16} × select∈{endpoint,pre})——两条正向杠杆在时限上可加、在到达上饱和
- **为什么补这格**: `K=16` ( #27/#1 ,轮次 39/44 验证)与 `select=pre` ( #29 ,轮次 46 验证)是链上仅有的两条正向杠杆,但从未同时测过。§9.2 要的是**同一份配方**同时满足到达与时限,所以可加性必须直接量,不能各自报喜。
- **四格(全部 n=256、seed=0、同配方、同批口径;缺的那格是本轮新跑)**:
| 格 | 到达 | 时限内(≤1.3×老师) | 2 s 误差比 | 到达题末态误差 | 刹停/题 | 行程比 | 碰撞 / 超 VMAX |
|---|---|---|---|---|---|---|---|
| K8 `endpoint` (历史控制) | 0.5234 | 0.2656 | 0.2792 | 0.2175 | 19.55 | 2.6158 | 0 / 0 |
| K8 `pre` | 0.5430 | 0.3320 | 0.1702 | 0.4151 | 19.84 | 2.4449 | 0 / 0 |
| K16 `endpoint` | 0.5625 | 0.2969 | 0.2800 | 0.1595 | 13.77 | 2.6243 | 0 / 0 |
| **K16 `pre`(新最好格)** | **0.5664** | **0.3594** | **0.1382** | 0.2882 | 14.20 | **2.4142** | **0 / 0** |
- **主效应(这就是可加性的算法)**:
- 时限:`pre` 在 K8 上 ** +6.64 pp**、在 K16 上 ** +6.25 pp**; `K16` 在 endpoint 上 +3.13 pp、在 pre 上 +2.73 pp ⇒ **四个方向同量级、无交互** 。时限这块确实是两个独立瓶颈(候选容量、打分口径)各自买一份。
- 到达:`pre` 在 K8 上 +1.95 pp、在 K16 上只 ** +0.39 pp**(逐题 16 赢 15 丢,净 +1, **McNemar p=1.000**)⇒ **到达饱和** : K16 已经把"有活路可选"这件事买完了,再把打分口径改对,救不回新题。
- 最好格 vs 历史控制(K8 endpoint)逐题:赢 20 丢 9,净 ** +11 题**( 0.5234→0.5664),**McNemar p=0.061** ⇒ 这是整条"选择/认证"线上**最接近显著**的一次到达收益,但按规矩 p=0.061 就是"尚未确立",要在 n=512 或第二个 seed 上复现才算。翻转按类别:B +8/−2、A +8/− 4、C +3/− 2、Dr +1/−1 ⇒ 增益仍然主要在 B(直线被挡)。
- `goal_ratio_2s` 逐题:201 好 / 55 差,**p = 1.0e−20** ⇒ 全程进度是这条线最硬的证据(比任何单臂都强)。
- **一个所有历史数字都被我漏说的口径**:`ok = done & (t_done ≤ limit)` ,而 `limit = time_limit(ex) = max(2×老师用时, 3 s)` 。**⇒ 本链引用的"到达率"本来就带 2× 时限**,不是"最终到没到"。`time_ok_1p3` 才是 §9.2 的 1.3× 口径。两者是两道门,引用时不能再混。轮次 52 已把 `t_exp/tr_ref` 落盘,之后 1.3× 口径能做逐题配对。
- **状态**:合法口径(碰撞 0、超 VMAX 0)下的当前最好配方更新为 **K=16 + select=pre + commit_n=2 + fb=2.2 + inc_cap=1 + cert_batch=1** → 到达 56.6%、时限内 35.9%。§9.2 的缺口仍然是**到达 − 41.4 pp**(时限 − 64.1 pp 是另一栏)。
- **判据没被放松的证据**:四格 `collision_rate` 与 `over_vmax_rate` 全 0, `n_plans_mean` 全 195.0 ⇒ 规划次数不变;K16 的额外成本只在每颗规划的候选数(认证与打分的批量宽度),这条**必须用独占微基准量**才能进部署账(#16/#28 仍未结)。
2026-10-21 01:31:11 +08:00
## 轮次 50:门控 20 mm 的 seed=1 复现——方向对、幅度不稳:时限收益塌了,精度代价只是减小没消除
- **一条臂就够**(控制臂复用 `round47_ep_s1` ,同 seed 同配方,已在盘)。
- **两 seed 并排**(都是 n=256、`collision_rate=0` 、`over_vmax_rate=0` 、`n_plans_mean=195.0` ):
| 读数 | s0 控制 | s0 门控 20 | s1 控制 | s1 门控 20 |
|---|---|---|---|---|
| 到达 | 0.5234 | 0.5352 | 0.5313 | **0.5313** |
| 时限内(≤1.3×老师) | 0.2656 | **0.3281** (+6.25 pp) | 0.2969 | 0.3008 (**+0.39 pp**) |
| 2 s 误差比 | 0.2792 | 0.1702 | 0.2750 | **0.2011** |
| 到达题末态误差中位 | 0.2175 | 0.2248 | 0.2228 | 0.2286 |
| 行程比中位 | 2.6158 | 2.5146 | 2.6369 | 2.6468 |
- **复现矩阵(什么稳、什么不稳)**:
- **稳**: `goal_ratio_2s` 大幅改善(两 seed 都到 0.170/0.201,控制 0.279/0.275)⇒ "打分地平线 = 执行地平线"买**路上的进度**是这条轴唯一稳健的效应;末态误差**中位数**几乎不动(+3.4%/+2.6%)⇒ 门控确实把 `pre` 那个 +91% 的精度损失压掉了大部分。
- **不稳**:时限收益从 ** +6.25 pp 塌到 +0.39 pp**;到达两 seed 合并赢 24 丢 21(净 +3, **p=0.766**)⇒ 到达率在这条轴上彻底没有可用信号。
- **合并后要更正轮次 49 的一句话**:到达题组内末态误差 vs 控制的符号检验,s0 是 67 差/57 好(p=0.419)、s1 是 74/51( **p=0.049**)、两 seed 合并 **141 差/108 好,p=0.042** ⇒ 正确说法是"**精度代价被大幅减小(未门控的 `pre` 是 82/42, p=3.1e− 4)但没有消除**",不是"与控制不可分"。中位数与逐题分布在这里给出相反的印象,正是因为门控把尾部拉近了中位、但把大量题各推一点点。
- **判读规则的兑现**:轮次 49 预注册写的是"若 s1 变成显著变差,则本轮结论降级为阈值恰好躲过一次复现"。时限那一半也塌了 ⇒ **降级为** :门控不是免费午餐,它是"要不要用时限收益换末态余量"的开关;`pre_near=20` 只在 seed=0 上看起来两者都要。
- **本轮另外修掉的一处统计错**:精确 McNemar/符号检验我用的是 `2·Σ_{i≤min(k,n− k)} C(n,i)/2ⁿ` ,在 **k = n/2 的中间点会算出 1.168( >1) ** 。改成定义式 `p = min(1, 2·min(P(X≤k), P(X≥k)))` (X~Bin(n,½))后重算了本轮全部已上报的 p 值:**除中间点那一例外,其余数值全部不变**( 0.125/0.424/0.678/0.455/0.327/0.042/4.9e− 16/1.8e− 12/2.4e− 6 都对得上)。中间点(s1 到达 11 赢 11 丢)的正确值是 **p=1.0** 。
- **状态**: `--pre_near` 作可选口径入库,默认仍 `endpoint` 。**这条轴的可推荐形态是 ungated `pre` **(时限/进度两 seed 都稳),门控留给"末态余量优先"的场景。
- **下一轮(组合而非继续调这条轴)**:`pre` 与 K=16 是两条各自验证过的杠杆,但没一起测过。§9.2 要的是同一份配方同时满足到达与时限,所以**可加性**必须直接量:跑 `K=16 + select=pre` (对照 `K16+endpoint` 与 `K8+pre` 都已在盘)。若不可加,说明两条买的是同一个瓶颈(候选被拒后的"没活路"),那是重要的机理结论。
2026-10-21 01:24:21 +08:00
## 轮次 49:#31 门控地平线成立——终端段盖到 20 mm 时,时限收益与精度代价被解耦(预注册判据由该臂满足)
- **假设(由轮次 48 的四点曲线给出,不是拍脑袋)**:时限收益来自"打分地平线 = 执行地平线",精度代价来自"近终段没有终端代价"。两件事若真能分开,就应该存在一个终端段长度,使得短前瞻的时限收益基本不损、而末态误差回到控制水平。
- **做法**: `select=pre --pre_near <mm>` ——当前误差 ≤ 阈值时打分改用**整条地平线**末端,远端仍用提交窗口点。多一次 `goal_err(B× K 点)` 只在门控口径下发生。
- **四列对照(全部 seed=0、同配方同批;控制=`round45_tie0` , pre=`round46_pre256` ) **:
| 读数 | 控制 h=16 | `pre` h=2 | 门控 5 mm | 门控 20 mm |
|---|---|---|---|---|
| 到达 | 0.5234 | 0.5430 | **0.5469** | 0.5352 |
| 时限内(≤1.3×老师) | 0.2656 | **0.3320** | **0.3320** | 0.3281 |
| 2 s 误差比 | 0.2792 | 0.1702 | 0.1702 | 0.1702 |
| 到达题末态误差中位 | 0.2175 | 0.4151 | 0.3768 | **0.2248** |
| 行程比中位 | 2.6158 | 2.4449 | **2.4218** | 2.5146 |
| 刹停/题 | 19.55 | 19.84 | 19.84 | 19.64 |
| 执行碰撞 / 超 VMAX | 0 / 0 | 0 / 0 | **0 / 0** | **0 / 0** |
| `n_plans_mean` | 195.0 | 195.0 | 195.0 | 195.0 |
- **逐题配对(vs 控制)**:到达 门控5 赢 16 丢 10(净 +6, p=0.327)、门控20 赢 13 丢 10(净 +3, p=0.678)、`pre` 净 +5( p=0.424)⇒ **到达率在这条轴上任何一点都没跨过显著** 。到达题组内的末态误差符号检验才是分界:`pre` 82 差/42 好 **p=4.2e− 4** 、门控 5 mm 79/45 **p=0.0029** (仍显著变差)、门控 20 mm 67/57 **p=0.42 ⇒ 与控制不可分** 。
- **预注册判据的落点**(规则在看到数据前写在 `ml/runs/_r49_gate.sh` ):成立 = `err_success_med` 回到接近控制(≈0.22 mm) 且 `time_ok ≥ 0.31` 。**门控 20 mm 两条都满足**( 0.2248、0.3281)⇒ 假设成立。门控 5 mm 只满足时限一半都不到(0.3768 仍显著差)⇒ 不成立。
- **5→20 mm 的分级响应是机理证据,不是调参**:终端段太窄(5 mm ≈ 最后一两步)只回收 20% 的精度差,20 mm(≈ 最后 3–5 步)才回收全部。⇒ 病名的正确写法是**"终端代价的作用区间不够长"**,而不是"缺终端代价"。这也说明 `pre` 的精度损失不是"打分变笨"的随机副作用,而是近终段路径选择被 2 步口径主导的直接后果。
- **两条臂各自的代价(不许只报好的那半)**:门控 20 mm 把 A 类到达打到 **94/128** (控制 96、门控5 也是 96),换来精度归零;门控 5 mm 到达最高 0.5469 且行程比最好(2.4218),但末态误差仍显著变差。⇒ **不存在同时占优的阈值** ,本轮只证明"可解耦",不证明"已找到最优点"。
- **口径纪律**:不改为默认。§9.2 的"时限内"最好读数现在是 **0.3320( pre h=2 / 门控5) ** , "到达"最好读数是 **0.5469(门控5) ** ——两者都还没显著超过控制,所以验收栏仍写控制的 0.5234/0.2656,另注可选口径。
- **下一步(唯一还没做的关键检验)**:门控 20 mm 在 seed=1 复现(控制臂 `round47_ep_s1` 已在盘 ⇒ 只需一条臂)。若 p=0.42 那个"与控制不可分"变成"显著变差",本轮结论降级为"阈值恰好躲过一次复现"。
2026-10-21 01:31:11 +08:00
** 【轮次 50 已做,结果是降级】**:seed=1 上该符号检验是 74 差/51 好 **p=0.049** ,两 seed 合并 **141 差/108 好 p=0.042** ⇒ "与控制不可分"不成立,正确说法是**精度代价被大幅减小但没有消除**;同时时限收益在 seed=1 上从 +6.25 pp 塌到 +0.39 pp。详见下一轮。
2026-10-21 01:24:21 +08:00
2026-10-21 01:11:18 +08:00
## 轮次 48:#30 打分地平线四点曲线——进度收益是剂量-反应关系,而精度代价只集中在 h≤4;h=8 是个坏点
- **设计**: `select=pre` 加 `--pre_h` ( 0=commit_n)。同 seed=0、同配方(`K=8/commit_n=2/fb=2.2/inc_cap=1/cert_batch=1` ),只改打分取 `fut` 的第几步。h=2 与 h=16 两点已在盘(轮次 46 / 45,且控制臂已证跨窗口逐位复现),本轮补 **h=4、h=8** 。
- **曲线(n=256 全部四点)**:
| 打分地平线 | 时限内(≤1.3×老师) | 2 s 误差比 | 到达题末态误差中位 | 到达 | 行程比中位 | 刹停/题 | 执行碰撞 |
|---|---|---|---|---|---|---|---|
| h=16(现 `endpoint` ) | 0.2656 | 0.2792 | 0.2175 mm | 0.5234 | 2.6158 | 19.55 | **0** |
| h=8 | 0.2813 | 0.2661 | 0.2255 mm | 0.5195 | **2.6749** | 20.27 | **0** |
| h=4 | 0.3047 | 0.2350 | 0.3301 mm | 0.5391 | 2.5619 | 20.41 | **0** |
| h=2( =提交窗口) | **0.3320** | **0.1702** | 0.4151 mm | 0.5430 | **2.4449** | 19.84 | **0** |
- **逐题配对(对同一控制)**: `goal_ratio_2s` 符号检验 h=8 **166 好/90 差 p=2.4e− 6** 、h=4 **184/72 p=1.8e− 12** 、h=2 **192/64 p=4.9e− 16** (轮次 46)——三个 h 都显著、显著性随 h 缩短单调增强。到达则全在噪声内:h=8 赢 8 丢 9(净 −1, p=1.0)、h=4 赢 10 丢 6(净 +4, p=0.45)、h=2 赢 15 丢 10(净 +5,p=0.42)。全程末态误差的符号检验 h=8 是 142/114( p=0.091)、h=4 是 130/126( p=0.85)⇒ **末态误差的总体分布没被推动,被推动的是"到达题组内到达那一刻的误差"** 。
- **三条读法(比"哪个 h 最好"有用)**:
1. **进度/时限关于 h 是单调的** (前瞻越短 ⇒ 时限内越多、2 s 时越贴近目标)。这是**剂量-反应关系**,比单点 A/B 强:不是一次涨落,而是整条轴同向。⇒ §9.2 的"到达用时 ≤ 老师×1.3"这一栏的真瓶颈之一确实是**打分地平线长于执行地平线**。
2. **精度代价不是均摊的,几乎全在 h≤4** :h=8 相对控制的末态到达误差只 +3.7%( 0.2175→0.2255),h=4 就 +52%(→0.3301)、h=2 +91%(→0.4151)。⇒ 病因不是"前瞻短",而是**近终段没有前瞻**( MPC 缺 terminal cost 的教科书症状)。正确的形态是**前瞻长度随剩余距离收缩**(#31 ),不是在 h 上挑一个折中值。
3. **h=8 是曲线上的坏点** :时限只 +1.56 pp、到达 −1 题、**行程比反而最差**( 2.6749 > 控制 2.6158)。⇒ "把地平线砍一半"这种渐进方案被自己的中间点否掉了:要么收到提交窗口附近,要么别动。
- **按类别**:h=4 时 A 类回到控制水平(96/128),B +2、C +2; h=2 时 A − 1、B +2、C +3。⇒ 轮次 45 那个"短前瞻在开阔区纯亏"的担忧在 h=4 上消失(`tie` 是另一码事:它换成的是余量而非进度)。
- **判据状态**:四点全部 `collision_rate=0` 、`over_vmax_rate=0` 、`start_fail=0` ; `speed_ratio_p50/p95/max` 与 `accel_ratio_max` **四点的值逐位相同** ( 1.000002/1.000010/1.000010/1.000010)⇒ 收益不是放松安全或超速换来的。成本侧的**实测**(不是推算)证据:`n_plans_mean` 四点都是 **195.0** ,即每颗题的规划次数没变 ⇒ 认证与几何调用的次数不变,改变的只是同一批点里取哪一个来排序。`dls_share` 0.613/0.633/0.629/0.637 不单调,暂不作结论。
- **预注册判读规则的落点**:规则写的是"若 time_ok/2 s 误差比随 h 单调变差 ⇒ 超出提交窗口的前瞻有害,#26 一并作废"。观测正是单调 ⇒ ** #26 (在前缀口径上再加白费惩罚)作废**;改为 ** #31 :门控地平线**(远端用 `pre` 、近终段用整条地平线),一个参数、机制由本曲线直接给出。
- **状态**: `pre_h` 作可选口径入库,默认仍是 `endpoint` 。§9.2 的"时限内"读数最好的一栏从 0.2969( K=16 endpoint)换到 **0.3320( K=8 h=2) ** ,但到达没有显著变化,所以**不换主口径**。
2026-10-21 00:57:08 +08:00
## 轮次 46–47:#29 把候选打分的地平线换成「这一轮真会执行到的位置」——链上第一个正向杠杆,两个 seed 独立复现
- **诊断(不是新想法,是旧负结论给出的原因)**:`select='endpoint'` 按**整条 16 步地平线末端**的终点误差给 K 条候选排序,而每轮只提交 `commit_n=2` 步。对被安全层截断的候选,那个终点**根本到不了**;对满前缀候选,它是 14 步开环外推。轮次 42 判掉 `ep_len/ep_waste` 时写的就是同一件事——"罚的是没被执行的那段地平线"。`select='pre'` 把打分点换成 `fut[:, :, commit_n-1]` (这一轮真正会走到的位置),**同一次 `goal_err` 只换点集,机制上不增加量级**。
- **实现账**:分支 + 文档串 + `--select pre` ;两条可手算的正对照(夹具造一对"前缀好但末端差"/"末端好但前缀差"的候选 ⇒ 两口径必须选**相反**的那条)+ 一条不变式(`commit_n=16` 时 pre 的索引落到地平线末端 ⇒ 必须与 endpoint 选同一条)。49 项测试绿。仪表灵敏度:n=16 冒烟上 `pre` 与 `endpoint` 已给出不同轨迹(刹停 24.94→21.94、行程比 2.43→2.67),不是惰性口径。
- **对照臂的可比性先证再引用**:本轮控制臂 = `docs/experiment_round45_tie0.json` ( `tie=0` 、同配方),它与轮次 42 的 `round42_K8cb1` **22/22 键逐位相同** ⇒ 该配方跨窗口确定性复现,单臂对照成立(这是第一次在新杠杆上省掉控制臂,前提是复现证据已落盘)。
- **seed=0( n=256,同 seed 同批)** 与 **seed=1 独立复现(两臂同窗口背靠背)** :
| 读数 | s0 控制 | s0 `pre` | Δ | s1 控制 | s1 `pre` | Δ |
|---|---|---|---|---|---|---|
| 执行碰撞率 | 0.0 | **0.0** | — | 0.0 | **0.0** | — |
| 到达 | 0.5234 | 0.5430 | +1.95 pp | 0.5313 | 0.5430 | +1.17 pp |
| 时限内(≤1.3×老师) | 0.2656 | **0.3320** | ** +6.64 pp** | 0.2969 | **0.3398** | ** +4.30 pp** |
| 2 s 误差比(中位) | 0.2792 | **0.1702** | − 39% | 0.2750 | **0.2011** | − 27% |
| 行程比中位 | 2.6158 | 2.4449 | − 0.171 | 2.6369 | 2.4661 | ** − 0.171** |
| 超 VMAX 题占比 | 0.0 | 0.0 | — | 0.0 | 0.0 | — |
| 到达题末态误差中位 | 0.2175 | 0.4151 | ** +0.198 mm** | 0.2228 | 0.3425 | ** +0.120 mm** |
- **统计口径(这条线真正的证据在哪)**:
- `goal_ratio_2s` 逐题符号检验:s0 **192 好 / 64 差(p=4.9e− 16) ** , s1 **191 好 / 65 差(p=1.5e− 15) ** 。⇒ 显著、且两个 seed 的计数几乎一样。
- 到达:s0 逐题丢 10 赢 15(净 +5, McNemar **p=0.424** )、s1 丢 10 赢 13(净 +3, **p=0.678**)。⇒ **到达率的提升在两个 seed 上都只是噪声** 。诚实的写法是"时限内到达显著变多、总到达未见显著变化",即它把路上的时间买回来了,没有把通路买回来。
2026-10-21 01:48:46 +08:00
** 【轮次 52 补验】**这句里"时限内显著变多"当时还只是整批读数(0.2656→0.3320),没有逐题配对。补上每题老师用时后:**K8 `pre` 在 1.3× 口径上逐题 22 赢 5 丢,净 +17,精确 p=0.0015**; `K16+pre` 是 27/3、p=8.4e−6。⇒ 那句话现在有据了,而且比原来写的更强。注意 `success` 那道门自带 **2× ** 预算(`limit = max(2·t_exp, 3 s)` ),所以"到达 p=0.42"与"时限内 p=0.0015"是两道不同门的读数,不矛盾。
2026-10-21 00:57:08 +08:00
- 末态误差逐题:s0 130 好 / 126 差(p=0.85)、s1 121/135( p=0.42)⇒ 全程不显著;但**到达题组内**的中位误差两 seed 都涨(0.22→0.42、0.22→0.34 mm)。这是"打分只看 2 步"的必然代价:近目标处不再为最后那几毫米承诺路径。判据仍未违反(到达定义是 `e<1 mm 且 oe<0.5°` ,最差的 0.42 mm 也在壳内),但**这条余量从 4.6 倍缩到 2.4 倍**。
- **按类别(两个 seed 方向一致)**:A 类 − 1, **B 类 +2、C 类 +3/+2**。单个切片在这个分母上都不显著,但方向与轮次 44 的"#27 :候选容量救不了 B/C"**不矛盾**——那条测的是"多给同分布候选",这条改的是"用哪个终点评价候选"。真正的判据留给下一轮的地平线曲线。
- **成本**:两臂墙钟 317.6/319.2 s( s0)与 315.1/314.4 s(s1)——同量级;但**墙钟差不构成成本结论**,要说"零额外开销"得用独占微基准把 `goal_err` 在 `B× K` 个点上的两次调用分开量(记为待办)。
- **状态**:**不改为默认口径**(到达未显著 + 到达精度余量减半),把 `select='pre'` 作为已验证的可选口径入库。下一步 #30 :把打分步长做成参数 `pre_h` ,扫 h∈{2,4,8,16}( 16=现在的 endpoint),量的是"前瞻长度 → 时限内到达 / 末态精度"这条**机理曲线**而不是挑系数;若精度代价随 h 恢复而时限收益不塌,正确的形态是"前瞻长度随剩余距离收缩"。
2026-10-21 00:33:44 +08:00
## 轮次 45:`tie`(等长安全前缀按沿路最小间隙定夺)判掉——它买的是余量,卖的是进度,而且作用在错的人群上
- **做法**: `cert_batch=1` 已经在同一次几何调用里算了 K 条候选各 `2·commit_n` 个点的间隙,但这些信息只用来判通过/拒绝。`--tie 1` 让"前缀最长"的并列集合改由**沿路最小间隙**定夺;零额外几何调用,判据一个字没动(仍是 `gap > gap_margin` )。
- **先测触发率再花钱**(阈值预注册:<1% 直接判掉,≥5% 才跑两臂)。n=64 探针:并列率 `tie_opp_rate=74.8%` 、真的改选率 `tie_changed_rate=7.4%` ⇒ 过线,才投 256 题两臂。
- **两臂 A/B( n=256、同 seed、同窗口背靠背,配方=轮次 42 的 `K8 + cert_batch=1 + inc_cap=1` ) **:
| 读数 | A `tie=0` | B `tie=1` | 差 |
|---|---|---|---|
| 到达 / 无碰撞到达 | 0.5234 | 0.5039 | ** − 1.95 pp** |
| 时限内(≤1.3×老师) | 0.2656 | 0.2773 | +1.17 pp |
| 执行碰撞率 | 0.0 | **0.0** | 判据未放松(硬门槛通过) |
| 刹停/题 | 19.55 | 17.79 | − 9.0% |
| 卡住题占比(刹停>20%) | 23.4% | 20.3% | − 3.1 pp |
| 行程比中位 | 2.6158 | 2.5399 | − 0.076 |
| 到达均值用时 | 2.487 s | 2.359 s | − 0.128 s |
- **统计诚实**:逐题配对**丢 6 题、赢 1 题,净 −5**; McNemar 精确双侧 **p = 0.125** ⇒ 到达差异在这个分母上与零不可分。所以结论不是"它显著变差",而是**没有任何正向证据,且方向为负**;而刹停/行程/用时全部朝"更保守"的方向动,与到达同向恶化是一个自洽的签名,不是噪声。丢的 6 题里 **5 题在 A 类(开阔均匀区)** ,唯一赢的那题在 C 类(贴立柱)。
- **仪表与独立离线数对上了(这条比 A/B 本身更有说服力)**:本轮 256 题的改选率 **5.58%** ,与轮次 44 纯离线量到的"执行点间隙落在 0.2–0.5 mm 的占比 **5.6%** "逐位同量级;并列率 79.0% 对上"满前缀 79.4%"。⇒ **余量能分辨的上界就是"有多少执行点真的贴进 0.5 mm 以内"** ,被宽相位截顶 `gcap = max(0.5, gap_margin+0.5)` 锁死(凡沿途间隙都 >0.5 mm 的候选,`min_gap` 恒等于 0.5,排序上完全并列)。所以 5.6% 是这个家族在 cap=0.5 下的**天花板**,不是实现没调好。
- **机理判读**:并列集合里"余量最大"的那条通常也是"位移最小"的那条。默认口径由选择器分数(终点误差)定夺 = 用进度换余量的风险由策略承担;`tie=1` 把判据整个换成余量 ⇒ 在根本没有障碍的 A 类纯亏进度。正确形态若要保留这条线,只能是"进度 + 余量"的加权,而加权又要一个新的自由系数——在当前 −5 的背景下不值得一轮。
- **结构性发现(否掉的是实现,更是提问方式)**:#24 从提出起就**作用在错的人群**。失败主人群是"全拒(`maxlen=0` ) "——未到达题 22.0% 的规划连第 1 步都不安全;而 `tie` 只在 `maxlen>0` 时触发。全拒人群的杠杆是 `backoff` (轮次 43 已判掉:能救回停步、救不回通路)。⇒ "选哪条活路"这件事,对已经走通的路影响很小,对走不通的路毫无影响。
- **本轮踩到并修掉的实现洞**:tie 分支里我用了局部名 `nmax` ,把主循环的"总步数"顶掉 ⇒ 进度回调 `%d` 收到张量直接炸(第一次 n=64 探针就是这么失败的)。修法是改名 `ntile` ,并补一条守卫单测(tie=1 必须带 `progress` 跑通且 `total` 保持标量);**守卫做过变异检查**——把 `ntile` 换回 `nmax` ,守卫立刻变红。计数器的正对照也可手算:夹具里两条候选永远全安全 ⇒ `tie_opp = tie_changed = n_plans` 、两个比率恒 1。47 项测试全绿。
- **不采纳**。前置条件记为 #28 :先把"数值截顶 `gcap` "与"验收门限 `gap_margin` "解耦(现在 `--gap_margin 1.5` 会同时抬截顶值和门限,动一个必动另一个),再量 cap=0.5/2/5 mm 下的分辨率与几何耗时(`_coarse` 保留 `d ≤ cp_lim + cap` 的胶囊对,成本随壳层体积涨)。**但即使分辨率上来,人群错配也不会被修好**,所以这条只作为"贴边题(C 类)里选哪条活路"的低优先候选保留。
2026-10-21 00:04:32 +08:00
## #27: K=16 的增益**不集中在 B/C**——B 类缺口是策略能力,不是候选容量(轮次 44,逐题 dump)
- K=8 与 K=16(都 `--cert_batch 1 --inc_cap 1` ,同 256 题同 seed)逐题对齐后按类别:
| 类别 | 题数 | K8 到达 | K16 到达 | 差 | K8 刹停/题 | K16 刹停/题 |
|---|---|---|---|---|---|---|
| A 均匀 | 128 | 75% | 78% | +3.1 pp | 7.5 | 4.9 |
| B 直线被挡 | 74 | 27% | **32%** | +5.4 pp | 38.1 | **27.0** |
| C 贴立柱 | 32 | 34% | 38% | +3.1 pp | 33.3 | 24.5 |
| D 不可达 | 13 | 0% | 0% | 0 | 5.2 | 4.8 |
| Dr | 9 | 78% | 89% | +11.1 pp | 10.2 | 6.4 |
逐题翻转:**新救回 12 题(A 6、B 4、C 1、Dr 1),反而丢 2 题(都在 A)**,净 +10 题 = 总体 0.5234 → 0.5625。
- **统计诚实**:分类切片里 1–4 题的变化在这个分母上不构成显著(B 类 +4 题 = +5.4 pp,单看会高估);**稳的只有两条**——总体 +3.9 pp(净 10 题)与刹停整体 − 29%( B 从 38.1 降到 27.0 次/题,是 74 题上的均值移动)。
- **关键读法(决定预算投向)**:候选容量翻倍把 B 的**拒绝次数**砍掉近三成,但 B 的到达只从 27% 到 32%,离 A 类的 78% 还差 46 pp。⇒ ** "少被拒"不等于"会绕"**: B/C 的缺口是策略在这些状态下**根本不产出绕行轨迹**,不是被闸门挡住的。继续在排序/认证口径上打磨救不了 B/C;要动的是数据侧(在受阻状态下采集教师轨迹,即 DAgger 第三轮,需要放行)或明确把 B/C 列为当前能力边界之外。
- 由此更新候选清单:#24 修正版(`tie='gap'` ,等长前缀时按沿路最小间隙定夺)仍然值得测——它影响的是"选了哪条活路",会影响后续拍的存活率;但它**不能**被期待修好 B/C 的 46 pp,那属于训练侧。
2026-10-20 23:51:51 +08:00
## 分层指标上线并被三重交叉验证(轮次 43)
- 对照配方(轮次 33 cap:1 步、`--inc_cap 1` )重跑一次带分层指标的评估:**原有 22 个指标逐位不变**,新增键全部产出(`docs/experiment_round43_control_strat.json` ):
| 新读数 | 值 | 独立离线预测 |
|---|---|---|
| `success_reachable` (排除按定义不可达的 D 类) | **0.5514** | 0.5514(逐题 dump 手算)✓ |
| `by_cat` 到达 | A 96/128=75%、B 20/74=27%、C 11/32=34%、D 0/13、Dr 7/9 | 与离线一致 ✓ |
| `brake_rate` mean / p50 / **p90** | 10.03% / 0.51% / **31.54%** | 均值与手算 19.55/195 一致 ✓ |
| `stuck_share` ( brake_rate>0.2 的题占比) | **23.4%** | 与"最卡前 20% 题占 72.4% 刹停事件"同量级 ✓ |
| `reverse_p50` / `reverse_moving_p50` / `moving_share_p50` | 0.2474 / 0.3258 / 0.9587 | 离线预测 0.247 ✓ |
- 三处独立来源(逐题 dump 手算、轨迹转储离线重算、评估内建指标)在四个数上完全对齐 ⇒ 这批分层读数可以当判据用,不只是看板。
- **为什么现在必须有 p90/stuck_share**:对照口径的均值刹停率 10.03% 看着"差 5 倍",但真相是 **p50 只有 0.51%、p90 高达 31.5%、23.4% 的题踩在卡住线上** 。以前只有均值时,`backoff` 这类"专治尾巴症状"的改动能把判据刷好而行为不变(已实测:brake_rate − 16%、到达 − 0.8 pp)——**没有 p90/stuck_share 就看不出这种背离**,这就是 #25 存在的理由。
2026-10-20 23:42:50 +08:00
## `backoff` 四臂判掉:转化率能买到刹停率,买不到到达——而且它能**绕过 §9.2 的判据**(轮次 43)
- 同一 256 题同 seed、`--inc_cap 1 --cert_batch 1` ,只改缩步档数(`docs/experiment_round38_backoff{0,1,2,3}.json` ):
| 档数 | 到达 | 时限内 | 刹停/题 | 缩步顶上/题 | 全拒事件合计 | 转化率 | `brake_rate` mean |
|---|---|---|---|---|---|---|---|
| 0(对照) | 0.5234 | 0.2656 | 19.55 | 0 | — | — | **10.03%** |
| 1( 1/2) | 0.5273 | 0.2695 | 18.78 | 1.57 | 20.35 | **7.7%** | 9.63% |
| 2( +1/4) | 0.5234 | 0.2617 | 18.12 | 5.00 | 23.11 | 21.6% | 9.29% |
| 3( +1/8) | **0.5156** | **0.2578** | 16.48 | 9.70 | **26.18** | 37.1% | **8.45%** |
- **预注册判读命中低那一支**(转化率 <60%):把全拒变成"慢一拍的动作"确实随档数上升(7.7%→37.1%),但**到达和时限一点没赚**( 0.5234/0.2656 → 0.5156/0.2578,方向还是负的)。⇒ 被全拒的那些状态不是"差一点就能过",而是**这个方向本来就不通**:缩步只是慢一点去撞同一堵墙。
- 更值得警惕的是第二列和最后一列的**背离**:`brake_rate` (§9.2 要 <2% 的那个判据)从 10.03% 一路降到 8.45%, `brakes_mean` 降 16%,**但真实结果没变好**。也就是说**缩步档可以只改善刹停率指标而不改善行为**——判据本身能被绕过。而且"全拒事件合计"反而从 20.35 涨到 26.18:缩步把机械臂带进了更容易被拒的几何里。
⇒ 规则:**任何降低刹停率的改动,必须同时报到达与时限**,只看 `brake_rate` 会奖励错误行为。这条已加进 #25 的分层读数要求。
- 处置:`backoff` 保持默认关、**作为到达率杠杆判掉**;它在"减少原地站住"这件事上确实有效(−16% 刹停),所以留作实机上"不许完全停住"这类需求的安全侧选项,不再投入档位扫描。
- 下一步(链已结束,可以改库):#25 分层指标(可达分母 / 按类别到达率 / `brake_rate_p90` / `stuck_share` )→ 用它重读 K=16( #27 :+3.9 pp 到底买在哪一类)→ 才轮到 #24 (几何信息进打分,直接打 B/C 类"方向不通")。
2026-10-20 23:23:50 +08:00
## 控制臂对表:22/22 键逐位复现 + 仪表预测精确命中(轮次 42)
- `--backoff 0 --cert_batch 1 --inc_cap 1` 重跑轮次 33 cap 配方:**两文件共有的 22 个指标键全部相等,差异集合为空**(第三次确认批量认证分支重写没有改变行为)。
- **仪表互验精确命中**:这个控制臂的 `reverse_p50 = 0.2474` ,而我先前用轮次 33 cap 转储、按 `rollout` 同窗口离线重算的预测值是 **0.247** (那次还给出"到达组 0.265 / 未到达组 0.233")⇒ 线上指标与离线重算在三个小数位上对齐,之前 1.575 那批读数确实只是"未除 6 的旧口径"。
- 控制臂的 §9.2 判据读数(第一次用真分母):**`brake_rate_mean = 10.03%` 、`p50 = 0.51%` 、`n_plans = 195` 、`moving_share = 95.9%` ** ⇒ "<2% 推理周期"在均值上差 5 倍、在中位上已达标,再次是长尾。
- 待读(正在跑):`backoff=1/2/3` 的 `backoff_mean / reject_all_mean` 转化率,按预注册规则判:10–20% ⇒ 缩步只是慢一点撞,到达不动,主攻转向 #24 ; >60% ⇒ 直接吃到那 63/109 的冻住时间。
2026-10-20 23:19:48 +08:00
## "冻住"的真实形态:不是堵死,是每题约 30 次、每次 1.8 步的反复试探(轮次 42,纯读转储)
- 先自纠一次框架:我按"≥10 步连续零运动"找长冻结,结果 B 类 74 题里只有 9 题有这样的段、C 类 32 题只有 3 题。原因很直白:`commit_n=2` 时**一次全拒只站 2 步**,要连成 10 步得连续 5 次全拒。所以"长冻结"这个说法对这份配置基本不成立,改测"停顿事件的累计与分布":
| 类别 | 题数 | 到达率 | 零步占比 | 停顿段数/题 | 平均段长(步) | 刹停/题 |
|---|---|---|---|---|---|---|
| A 均匀 | 128 | 80% | **7.9%** | 9.5 | 0.59 | 7.4 |
| B 直线被挡 | 74 | 34% | **28.7%** | **34.1** | 1.81 | 37.2 |
| C 贴立柱 | 32 | 41% | 25.2% | 29.2 | 1.57 | 33.3 |
| D 不可达 | 13 | 0% | 2.8% | 2.2 | 0.15 | 5.4 |
| Dr | 9 | 78% | 7.5% | 8.1 | 0.47 | 9.7 |
( `ml/runs/round33_base.pt` + 逐题 dump;这是 steps=1、不限幅口径,用于看**形态**不是看成绩)
- **结论**:B/C 的失效不是"走进死路被堵死",而是**反复试探**——每次规划全拒、站约 2 步、下次换个方向再试,一题平均 30 多次,累计把 **29%** 的时间窗花在停走上。它们最终能脱困(段长只有 1.6–1.8 步),只是每次都白站两拍。
- **这条把杠杆的预期钉准了**:
- `backoff` (全拒→缩慢一步)正好打在"每次白站 2 步"上:若 30 多次停顿各省 1–2 步,等于省 30–60 步 ≈ **时限内 20– 30% 的时间** ,但**不会**把"方向本来就不通"的候选变成通路。
- 真正要拿到 B 类到达(34%→A 类那样的 80%),得让**被拒之前的排序**就能避开必然穿模的方向(#24 :把已经算出来的沿路间隙喂进打分),而不是靠事后缩步。
- D 类几乎不停(2.8% 零步、2.2 段),是"直接开去停靠位、永远不满足判据"——再次印证它们不该在到达率分母里。
2026-10-20 23:06:28 +08:00
## 缺口几乎全在"直线被挡 / 贴立柱"两类(轮次 41,按任务类别分层)
- 六个已跑口径(1/2 步 × cap/margin/both,同一 256 题同 seed)的逐题 dump 交叉比对:
- **95 题(37%)在任何口径下都到达**;**106 题(41%)在任何口径下都不到达**;只有 55 题是"口径敏感"的。
- 卡住题集在四个一步口径之间高度重合(Jaccard 0.87– 0.91),换 cap/margin/反馈档**换的不是同一批题**;而 `steps=2` 的卡住集(135 题)**完整包含**一步的 71 题(交集 71=全集)⇒ 多段是"新增"了一批卡住题,而不是换了一批,与候选塌缩的机理一致。
- **按类别的到达率**( `--inc_cap 1` 合法限速口径;类别定义见方案 §采样:A 均匀 45%、B 直线被挡 30%、C 贴立柱 15%、D 目标不可达 10%):
| 类别 | 1 步限幅 | 2 步限幅 |
|---|---|---|
| A 均匀(无障碍) | **75%** (96/128) | 61% |
| B 直线被挡 | **27%** (20/74) | 16% |
| C 贴立柱 | **34%** (11/32) | 16% |
| Dr | 78% (7/9) | 67% |
| D 目标不可达 | 0% (0/13) | 0% |
- **读法**:总到达 52% 的缺口几乎全部来自 **B(30% 的题,只有 27% 做到)与 C( 15% 的题,34%) ** ——无障碍的 A 类已经 75%。⇒ 剩下要拿的分**不是"普遍再准一点",而是"直线被挡住时会绕"**。这与前面所有证据自洽:安全层全拒集中在尾巴题、多段推理因候选塌缩而更拒、K 加倍最赚(多给几条活路)。
- **一处必须纠正的分母口径**:D 类是"目标不可达、标签为停靠"的题,**按定义不可能到达**,却一直留在我的到达率分母里(§9.2 原文要的是"held-out **可达**任务到达率 ≥98%")。去掉 13 道 D 后:一步限幅 0.5234 → **0.5514** 、一步不限幅 0.5742 → 0.6049、两步 0.3945 → 0.4156。差 ** +2.8 pp**,不大但方向是系统性偏高/偏低混合,**以后必须两个数一起报**。历史轮次保留含 D 的分母(那是当初记在文件头的约定),但从下一轮起新增 `success_reachable` 与按类别到达率,别让"98%"和含不可达题的分母对话。
- 待办(链结束后改库):`eval_cl` 补 `success_reachable` (排除 cat=D)、`by_cat` 到达率、`brake_rate_p90` 、`stuck_share` 。这四格是让"对尾巴/对 B 类有效"的杠杆能被看见的前提。
2026-10-20 23:03:51 +08:00
## 刹停是极端长尾:一半题零刹停,两成题占 72% 事件(轮次 41,纯读已落盘逐题数据)
- 轮次 33 base(一步、不限幅)的逐题 dump:256 题共 4928 次全拒,均值 19.25/题。
| 分组 | 刹停均值 | 刹停中位 |
|---|---|---|
| 到达的 147 题 | **1.72** | **0** |
| 未到达的 109 题 | 42.89 | 45 |
分位数:**48.8% 的题一次都不刹**;最卡的前 5% 题占全部刹停事件 **24.5%** ( 92.8 次/题),前 10% 占 **42.9%** ,前 20% 占 **72.4%** ;后 80% 只占 27.6%(均值 6.6)。>30 次的 71 题(27.7%)几乎承担了整条判据缺口。
- **这改变了"怎么评判一条杠杆"**:§9.2 的"刹停 <2% 推理周期"用**均值**报,会被这 71 题拖死(K=16 均值 7.06%、中位 0.0),而大多数题其实早就满足。⇒ 以后每条臂都要**分层报**:`brake_rate_p90` 与"卡住题占比(brake_rate>0.2) "要进指标,否则一条只对尾巴有效的杠杆(#24 、backoff)会在总均值上看起来"没动"。
- 与失败分类完全对上:63/109"走一半被冻住"就是这批题;**它们同时也是到达缺口的全部来源**(可拿的 +25 pp 区间就在这批题里)。所以攻它们不是锦上添花,是主攻方向。
- 待办(等链跑完再改库,避免重犯 14:45 那次事故):给 `eval_cl` 补 `brake_rate_p90` 与 `stuck_share` (判据 `brake_rate > 0.2` 的题占比)。
2026-10-20 23:18:25 +08:00
## `ep_waste` 三臂也是负结论,但给出了原因:罚的是没被执行的那段地平线(轮次 42)
- 同一 256 题同 seed、`--inc_cap 1` ,只改 `select=ep_waste --len_w` (罚 `1 − 同轴净/总` × 当前误差):
| 臂 | 到达 | 时限内 | 行程比 | 刹车/题 | 刹停率 mean / p50 | 换向率 |
|---|---|---|---|---|---|---|
| 对照(endpoint, 1 步限幅) | 0.5234 | 0.2656 | 2.6158 | 19.55 | ≈0.099 / — | 离线 0.247 |
| waste 0.1 | 0.5156 | 0.2695 | 2.6697 | 19.39 | 0.0995 / 0.005 | 0.2527 |
| waste 0.3 | 0.5156 | 0.2656 | **2.5349** | 19.63 | 0.1007 / 0.005 | 0.2511 |
| waste 1.0 | **0.4883** | **0.2383** | 2.7083 | 20.03 | 0.1027 / 0.010 | 0.2490 |
( `docs/experiment_round40_waste{0.1,0.3,1.0}.json` )
- **行程比没有随权重单调下降**( 2.67 → 2.53 → 2.71 vs 对照 2.62):0.3 那一格看着像改善,但两侧都比它差 ⇒ 不是趋势,不能拿单点报"行程降了 0.08"。权重加到 1.0 时到达 − 3.5 pp、时限 − 2.7 pp,纯亏。
- **原因(这条比结论更有用)**:打分用的浪费比例是在**候选的 16 步地平线**上算的,而每拍真正提交只有 `commit_n=2` 步。排序被"后面 14 步会不会来回抖"牵着走,执行的前 2 步基本不变 ⇒ 改了顺序改不了行为。**要影响执行,惩罚必须只算在会被提交的那段前缀上。**
- 与 `ep_len` 三臂合起来看:**选择期的"路径形状类"惩罚(总行程 / 浪费比例)在两个版本上都是负结论**,而选择期的"多给活路"( K=16 +3.9 pp)和"几何信息进打分"( #24 ,待测)才是对的方向。差别在于前者动的是没被执行的那段,后者动的是被拒/被选的那 2 步。
- 内部一致性:`brake_rate_mean` 0.0995/0.1007/0.1027 与 `brakes_mean/n_plans` = 19.4/195 ≈ 0.0995 逐位对得上 ⇒ 刚补的分母口径没接错。
2026-10-20 23:03:06 +08:00
## K=16 串行 vs 批量认证等价 + 第一次真正核算"刹停率"(轮次 41)
- `--K 16 --cert_batch 1` 与 `--K 16` (串行)跑同一 256 题同 seed:`success / time_ok_1p3 / brakes_mean / travel_ratio_median / collision_*` **全部逐位相同** ,差异键只有 7 个、且全是我这几轮新加/改口径的报表键(`reverse_*` 的两种口径、`n_plans` 、`brake_rate` 、`moving_share` )。⇒ **轮次 39 的"试候选数 1/3/8/16 曲线"同样描述批量口径** ,也就是说 K=16 到达 0.5625 这个收益不依赖串行早停这个巧合。
( `docs/experiment_round40_K16cb1.json` vs `docs/experiment_round39_K16.json` )
- **整批墙钟 573 s → 469 s(−18%)**:批量把 K 次小调用并成 1 次大调用,在 B=256 的评估里本来就更快。这只说明趋势,**单次规划的 P99 要用独占微基准另测**(修好的探针排在链尾)。
- **`brake_rate` (刹停 / 规划次数)第一次有读数**:K=16 口径 `mean = 7.06%` ,但 ** `p50 = 0.0` **, `n_plans_mean = 195` , `moving_share_p50 = 98.7%` 。
⇒ §9.2 要"<2% 推理周期",均值差 3.5 倍,但**中位任务一次都不刹**——全部刹停集中在一小撮题上。这与失败分类完全一致(63/109 是"走一半被冻住",而它们就是那撮尾巴)。
**含义** :继续在"普遍少刹"上花力气收益有限,真正的问题是**那批卡住的题里安全层没有可行候选**——正是 K=16(+3.9 pp)与 #24 (把间隙喂进打分)要打的靶子。
- 仪表互验:K=16 批量臂 `reverse_p50 = 0.2625` 与我离线同窗口重算的 K=8 对照 0.247 同量级(K=16 略高,与它到达更多、动得更多一致);`reverse_moving_p50 = 0.3194` > 全步口径 ✓ 方向正确(除掉站住的步之后更抖)。之前那批 1.x 的读数确系修分母前的旧口径。
2026-10-20 22:55:49 +08:00
## #24 的设计定稿:一次几何调用同时供打分与认证(不放松判据、不加成本)
- 表面看有循环依赖:打分要用的"沿路间隙"目前只在安全层里算,而安全层只认证**排完序**的候选。破法是把顺序倒过来——**先对全部 K 条候选算一次 `2·commit_n` 点的间隙矩阵**,然后:
- 打分:`score = − e_end − gap_w · relu(gap_ref − 该候选沿路最小间隙)` (间隙不足的候选先降序,但**不淘汰**它,判据仍是后面的 `gap > 0` );
- 认证:直接用同一份间隙矩阵算 `plen` , **不需要再算第二次**。
- 于是代价是**零额外几何调用**,但口径上要求走批量认证(`cert_batch=1` )——串行那条靠"第一条全安全就早停"省掉后面 K−1 次调用,一旦要按间隙排序就必须先看全部候选。这跟实时性是同一个方向:批量口径本来就是为压最坏情况(轮次 34:80.2→37.1 ms)而做的,所以这条杠杆顺带把部署口径推到批量那侧。
- 读法预设(免得事后挑数):主判据是 `brake_rate` (全拒/规划次数,刚补上的分母)与 `success` /`time_ok_1p3` ; `gap_ref` 取 0.5 mm 起(宽相位截顶值以内,见轮次 33 的口径教训:余量门限高于 cap 会恒假)。
- A/B 脚本 `ml/runs/_gapscore_sweep.sh` ( `gap_w = 0.5 / 2.0 / 8.0` ,三档差一个数量级,看是否有拐点)。等链跑完、库能改之后实现+单测再跑。
2026-10-20 22:55:24 +08:00
## 代价探针的第一版量错了对象(仪表缺陷,已修)
- 第一版 `ml/runs/_kcost_probe.py` 把"整次 `rollout(..., max_sec=0.041)` 调用"当成"一次规划"来量,得到 `K8/cb0 P50 = 144.8 ms` 、`K16/cb0 = 139.6 ms` 这种**比轮次 34 的 33.5 ms/规划大四倍**的数——那里面包含每次调用的固定开销(`tasks_to_tensors` 、生成器、首段同步),2 步的调用只做 1 次规划,所以固定开销占了大头。绝对值完全不可比,我先差点把它当"K 翻倍不花钱"的证据。
- 修法是**用两个长度解出固定开销**:`max_sec` 取 2 步(1 次规划)与 8 步(4 次规划),`每次规划成本 = (T8 − T2)/3` 。这样才与 §9.2 的"每次推理+认证 P99 <20 ms"同一口径。
- 顺带一条**不能混的机理**:串行认证在 B=1 有早停(第一条全安全候选就 `break` ),所以它对 K **不敏感** ——第一版那组 144.8 vs 139.6 其实主要是这个早停在起作用,不是"K 免费";批量认证没有早停,K 从 8 到 16 是真的多算点(第一版里 150.7 → 169.1 ms)。两条口径对 K 的响应相反,报数时必须分开写,否则会把"串行下 K 便宜"错当成"批量下也便宜"。
- 修好的探针排在当前批次结束后单独跑(不改正在被 bash 逐行读取的 `_next_batch.sh` ,只跑独立脚本)。
2026-10-20 22:54:08 +08:00
## 到达率的上限在哪(把 #21 的数读成"还剩多少可拿")
- 两条界都在同一 256 题、`--inc_cap 1` 口径下量得:
- **不要求无碰撞**:纯策略到达 **0.7773** (一步)/ 0.8164(两段)——这是"控制器本身能把活干完"的上限。
- **要求无碰撞**:纯策略只有 **0.3594** (一步)/ 0.3750(两段)——这是"完全没有安全层"时的下限。
- 当前部署口径(开安全层、K=8) = **0.5234** ; K=16 = **0.5625** 。
- 所以可拿的区间是 **0.5234 → 0.7773** (+25.4 pp),而它不是靠放松判据拿:这段全部是"被拒的候选里其实有安全的路"。#24 (间隙进打分)与候选数(#1 )是同一件事的两个方向——前者让排序避开死路,后者多给几条活路。
- 反过来,纯策略无碰撞到达 0.359 也说明**不能靠"少拒一点"来吃这 25 pp**:拒得越少,穿模越多。只有"选得更准"才吃得到,这也是为什么把已有的间隙数喂给打分比再加余量门限更值钱。
2026-10-20 22:53:07 +08:00
## 判别定案(#21):两段动作不是"更危险",是"没有备选";顺带量出安全层值多少到达
- 关安全层(`--safety 0` ,同 256 题、`--inc_cap 1` ,只改段数):
| 口径 | 到达 | **无碰撞到达** | 碰撞率 | 碰撞步/题 | 时限内 | 行程比 |
|---|---|---|---|---|---|---|
| pure steps=1 | 0.7773 | 0.3594 | 0.5859 | 58.34 | 0.5352 | 2.375 |
| pure steps=2 | **0.8164** | **0.3750** | **0.5586** | **45.07** | **0.6836** | **1.594** |
| 开安全层 steps=1(对照) | 0.5234 | 0.5234 | 0 | 0 | 0.2656 | 2.616 |
| 开安全层 steps=2 | 0.3945 | 0.3945 | 0 | 0 | 0.2969 | 1.844 |
( `docs/experiment_round40_safetyoff_steps{1,2}.json` )
- **结论 1(判据 #21 定案)**:关掉安全层以后,两段在**每一格都不更差**——到达更高(+3.9 pp)、时限内高一大截(+14.8 pp)、**碰撞步反而更少**(58.3→45.1)、行程比更接近老师。⇒ "两段动作更危险"被否;两段在开环与纯策略口径都更好,它唯一输的地方是"开安全层时刹车多 4.5 倍"。
- **结论 2(机理)**:这正好是候选塌缩的必然结果——`steps=2` 时 K 条候选的一阶步标准差从 0.852 掉到 0.0245( 35 倍),"塌成一条"以后,那条在采样点上穿模就等于**全拒**;`steps=1` 时候选彼此差得远,总有一条能过。所以"没有备选"是主因,不是"界太保守"(线上只有端点+中点点检,没有位移界)。
- **结论 3(安全层值多少到达,首次定量)**:一步口径下安全层把到达从 0.7773 压到 0.5234( **− 25.4 pp**),换来碰撞从 58.6% 到 0;纯策略的**无碰撞到达只有 0.3594**,比开安全层的 0.5234 低 16.4 pp ⇒ **安全层确实在净收益上是赚的** ,不是白拿到达。
- **对"把一步角点训准"这条训练路线的直接警告**:一步候选的多样性,恰恰来自角点的**偏差/欠缩放**(每条 ε 被削到不同的衰减幅度)。如果训练把一步映射成两段那样的收敛解,候选可能一起塌缩 ⇒ **按当前安全层口径,到达率可能不升反降** (实测就是这个方向:steps=2 开闸 −12.9 pp)。所以任何"修角点"的训练都必须**同时**处理候选多样性(更大 K、或给候选注入受控多样性),否则就是拿开环收益去换闭环到达。
- 顺带修一处历史口径:§9.2 的"策略单独碰撞率 <3%"这一格,现在才有合法读数 **58.6%** (一步)/ **55.9%** (两段)——差距巨大,且以前从没在同一配方下报过。
2026-10-21 01:55:57 +08:00
## §9.2 记分板(2026-10-21 现状,最好的合法口径 = `--inc_cap 1` + K=16 + `select=pre`,轮次 51)
2026-10-20 22:51:30 +08:00
| 判据(§9.2) | 要求 | 当前 | 差距 |
|---|---|---|---|
| 实际执行碰撞 | = 0 | **0** ( `collision_rate 0` 、`collision_free_success` = `success` ) | **达标** |
| 超 VMAX 的题占比 | = 0(本轮新增的硬口径) | **0** ( `over_vmax_rate 0.000` ,开 `--inc_cap 1` 后;不开则 1.000、峰值 1.660× VMAX) | **达标** (代价:到达 − 5.1 pp) |
2026-10-21 01:55:57 +08:00
| held-out 可达任务到达率 | ≥ 98% | **0.5967** (可达分母,K16+`pre` ) / 0.5664(含 D 的整批)/ 0.5234( K8 控制) | 差 **38.3 pp** ;且相对控制净 +11 题只到 **p=0.061 ⇒ 未确立** |
| 到达用时 ≤ 老师×1.3 | 全部到达题 | 达标比例 **0.3594** ( K16+`pre` ) / 0.2969( K16) / 0.2656( K8 控制) | **这一栏是唯一被逐题配对证明买到的** : `pre` 净 +17( s0 p=0.0015) /+11( s1 p=0.035),合并 p=9.0e− 5 |
| 关节行程 ≤ 规划器×1.10 | ≤1.10 | 行程比中位 **2.414** ( K16+`pre` ;控制 2.616) | 超 **1.3 倍** ;罚候选行程/白费比例两条都是负结论,缩短打分地平线顺带降了 0.2 |
2026-10-20 22:51:30 +08:00
| 冷启动 | <10 ms | 未单独测(周期 P50 9.0 ms 是稳态推理,含首段编码) | 待测 |
| 推理 + 安全认证 P99 | <20 ms | 现口径周期 P50 33.5 / P99 64.7 ms;批量认证把最坏 80.2→37.1 ms | 差 **2~3 倍** |
2026-10-21 01:55:57 +08:00
| 刹停 < 2% 推理周期 | <2% | `brake_rate_mean` **7.28%** ( K16+`pre` , 14.20 次/195 规划);p50 **0.0%** 、p90 27.4% | 均值差 **3.6 倍** ,但中位已达标 ⇒ 极端长尾(`stuck_share` 17.2%) |
2026-10-20 22:51:30 +08:00
- 刹停率这一格现在是**手算估算**: `eval` 产物里以前没存每题规划次数。已补 `n_plans` 与 `brake_rate` (并因此踩了 `per['plans']` 键名冲突的坑),当前批次之后的臂会直接给这个数,届时替换估算。
- 记分板脚本 `ml/runs/_scoreboard.py` (读所有产物 + 轮次 33/38 的 GPU 微基准)。**注意它的输出在 GBK 控制台下会因 `⇒` 崩**,要带 `PYTHONIOENCODING=utf-8` 跑——这是我自己的老坑第 N 次复现,脚本以后只打 ASCII。
- 读法:判据之间是相互拉扯的(限速 −5.1 pp 到达、多段推理 +2.4 pp 时限但 −15 pp 到达、放大噪声 −8.2 pp 时限),所以**任何单格变好都要同批报其他格**,这正是记分板存在的理由。
2026-10-20 22:50:41 +08:00
## 多段推理的代价实测(B=1、K=8、逐轮交替、奇数轮反序)
- `docs/experiment_round38_steps_cost.json` (24 轮 × 每轮 40 次,取每档的中位):
| 段数 | 推理 P50 | 相对 1 段增量 |
|---|---|---|
| 1 | 9.02 ms | — |
| 2 | 14.98 ms | ** +5.97 ms** |
| 4 | 26.72 ms | +17.71 ms |
| 8 | 51.07 ms | +42.05 ms |
- 每多一段 ≈ 多一次解码器前向(编码器 `mem` 只算一次),所以增量近似线性;9.02 ms 这一档比轮次 33 报的 7.2 ms 高,是不同会话的时钟/上下文差别,**只用同批内的差值,不用绝对值跨轮比**。
- 合到整周期上:轮次 34 的现口径 P50 ≈ 33.5 ms,两段就是 ≈39.5 ms( 25 Hz),四段 ≈51 ms( 19.6 Hz)——**离 20 ms 预算更远**,所以"靠多段推理把一步的偏差补回来"在部署上不成立,只能作为开环诊断口径。
- 与 K 这条轴叠加会更糟(K=16 认证点翻倍),所以 `K=8/16 × cert_batch=0/1` 的四格周期微基准排在当前批次里(`ml/runs/_kcost_probe.py` ),这是判断"候选数能不能买到部署里的到达率"的关键一列。
2026-10-20 22:48:51 +08:00
## 候选为什么会"塌":两段积分把 K 条候选吸成一条(轮次 39 探针,机理定案)
- `ml/runs/_cand_div.py` (256 题特征、同一批噪声 z、K=8,只改段数):
| steps | 候选间一阶步的标准差 spread | 两两平均距离 pairwise | 第 1 步模长 | ±1 饱和率 |
|---|---|---|---|---|
| 1 | **0.8518** | 5.3647 | 1.1565 | 5.2% |
| 2 | **0.0245** | 0.3024 | 1.0956 | 3.9% |
| 4 | 0.0211 | 0.2861 | 1.0970 | 6.9% |
⇒ **多段积分把 K 条候选的差别抹掉了 35 倍** ( 0.85 → 0.024)。这不是"动作更大更危险"那么简单:安全层是在 K 条**几乎相同**的候选里挑一条能走的前缀,挑无可挑就刹停。
- 这条与轮次 38 的实测严丝合缝:`steps=2/4/8` 到达掉 13–15 pp、刹车 ×4.5,但**开环误差与行程比都更好**——动作质量提升是真的,到达率下降是"没有备选"造成的。
- **但"人为制造多样性"不是解法**(`z_scale=1.5` ,同 K=8):刹车确实砍一半(19.55→10.51),可到到达掉到 0.4961、时限内从 0.2656 崩到 **0.1836** 、行程比恶化到 3.5243、换向升到 0.32。⇒ 放大噪声换来的"能过的候选"是**分布外**的候选:安全层放行它,但它走的是绕、抖、慢的路。**K=16 的收益来自"同分布内更多候选",不是"多样性本身"**——这两个数放在一起才把这条轴的边界说清楚。
- 判据状态:#21 的两个分支现在这样分:**"动作更危险"不是主因,"候选塌缩"是主因**( spread 35 倍 + try/K 单调曲线 + z_scale 反例三条独立证据)。剩下要量的只是成本口径(K=16 在批量认证下贵多少)。
## 事故:我在链式作业排队期间编辑了被 import 的库,两个臂直接没跑
- 时间线:`z15` 于 14:46:38 结束,链接着拉起 `safety=0 steps=1` ( 14:46:38)——而我为了让 `brake_rate` 有分母,正在 14:45:5x 用脚本改 `ml/sim/closed_loop.py` ,一次替换把 `per = {...}` 的字典提前闭合,留下 `IndentationError: unexpected indent` 。**新起的 python 进程 import 到的是半成品文件**,两个 safety-off 臂各 2 秒就退出(日志里 `=== safety=0 steps=1 done 14:46:40 ===` 的"done"只是 bash 循环走到下一行,不代表成功)。修好在 14:46:52,48 项测试全绿。
- **教训(比我原先记的"别改正在跑的脚本"更进一层)**:链式作业会在**未来某个时刻**新起解释器,所以"只要不改正在跑的那一个进程"是不够的。规则改为:**链没结束就不编辑被 import 的库;要编辑,先等通知或先让链跑完**。并且 `=== done ===` 这种循环日志不能当成功凭据——**判成功要看产物文件在不在**(这次 `docs/experiment_round38_safetyoff_steps{1,2}.json` 根本没生成,一看便知)。
- 两个 safety-off 臂与 `ep_waste` /`backoff` /K 代价一起并入下一批重跑(`ml/runs/_next_batch.sh` )。
- 顺带补了验收判据缺的分母:`rollout` 现在记 `n_plans` (每题规划次数)并给 `brake_rate = brakes/n_plans` 、`eval_cl` 报 `brake_rate_p50/mean` 与 `n_plans_mean` ——§9.2 要的是"刹停 <2% **推理周期** ",以前只有绝对次数,**这条判据实际上从来没被真正核算过**。命名上躲开一个坑:`per` 里原本有个 `'plans'` 键是转储用的逐规划字典,新键必须叫 `n_plans` ,否则 `flat` 的过滤 `if k not in ('traj','plans')` 会把它静默吃掉。
2026-10-20 22:43:12 +08:00
## 试候选数的成本-收益曲线(轮次 39,四档齐全,#15 主结果)
- 同一 256 题、同 seed、`--inc_cap 1` 、其余配方(`select=endpoint, replan=empty, commit_n=2, K=8, fb=2.2` )不变,只改**安全层允许试几条候选**:
| 试候选数 | 到达 | 无碰撞到达 | 时限内 | 刹车/题 | 行程比 | reverse_p50 | 整批墙钟 |
|---|---|---|---|---|---|---|---|
| 1 | 0.4023 | 0.4023 | 0.2227 | 60.44 | 2.5107 | 0.1863 | 112 s |
| 3 | 0.4570 | 0.4570 | 0.2383 | 37.75 | 2.5297 | 0.2244 | 170 s |
| 8(对照) | 0.5234 | 0.5234 | 0.2656 | 19.55 | 2.6158 | —(改动前口径) | 329 s |
| 16 | 0.5625 | 0.5625 | 0.2969 | 13.77 | 2.6243 | 1.5750(旧口径,÷6=0.2625) | 573 s |
( `docs/experiment_round39_try{1,3}.json` 、`..._K16.json` 、对照 `docs/experiment_round33_cap.json` )
- **读法**:到达 0.402→0.562( +16 pp)、刹车 60.4→13.8(÷4.4)单调随候选数变好;代价是串行认证下 gaps 调用次数与候选数成正比,整批墙钟 112→573 s(×5.1,与题数无关的部分就是几何调用)。碰撞全程 0、限速照开 ⇒ **这不是放松判据换来的分数** 。
- `reverse_p50` 随"站住更多"而**下降**( try1 的 0.186 < 对照 0.247),是稀释而不是变平滑 ⇒ 这个指标只能和 `moving_share` 一起读(后两个键从 14:41 之后的臂才有)。
- **部署口径的未决项**:上面的墙钟是**串行认证**(`cert_batch=0` )口径;批量认证把 K 条候选并成 1 次调用,理论上能把候选数带来的成本从"线性调用"变成"一次更大的调用"。所以 `K=8/16 × cert_batch=0/1` 的四格 B=1 周期微基准(`ml/runs/_kcost_probe.py` )是这条杠杆能否上线的关键读数——**跨轮次墙钟不算证据**,本表的墙钟只用来说明趋势量级。
2026-10-20 22:42:11 +08:00
## try3 反向档位 + 换向指标的稀释修正(轮次 39 续)
- `--safety_try 3` (只允许安全层试按分数排序的前 3 条候选,其余不变、仍 `--inc_cap 1` ):到达 **0.4570** (对照 0.5234,−6.6 pp)、时限内 0.2383(−2.7 pp)、**刹车 37.75**(对照 19.55, +93%)、行程比 2.530、碰撞仍 0(`docs/experiment_round39_try3.json` )。
- 把"允许试几条候选"这条轴摆开,是**单调**的:
| 试候选数 | 到达 | 时限内 | 刹车/题 |
|---|---|---|---|
| 3 | 0.4570 | 0.2383 | 37.75 |
| 8(对照) | 0.5234 | 0.2656 | 19.55 |
| 16 | 0.5625 | 0.2969 | 13.77 |
⇒ "全拒是没备选而不是真没路"这条假设有**双向**证据(减档更差、加档更好),不只是单点相关。边际收益在递减:3→8 值 +6.6 pp, 8→16 只值 +3.9 pp。
- **但不能当部署结论**:认证点数与候选数成正比(K=8 每次规划 32 个点 → K=16 是 64 个),而 GPU 周期 P50 已经是 33.5 ms、超 20 ms 预算。所以接下来必须先量 `K=8 vs 16` 的 B=1 独占微基准(`ml/runs/_kcost_probe.py` ,已验证调用签名);如果 K=16 把周期推到 45 ms 以上,这条路就只能靠"一次批量调用覆盖全部候选"把常数项压回去(轮次 34 已证批量把最坏 80.2→37.1 ms)。
- **换向指标被刹停稀释,已修**:try3 报 `reverse_p50=0.2244` ,比对照的离线同窗口值 0.247 **还低** ,而它恰恰是站住最多的臂——因为分母 `nact` 把站住的步也算进去了。补了两个口径:`reverse_rate_moving` (只算动过的步)与 `moving_share` (动步占比,=1−站住比例)。
配套写了**可手算的负对照**: `+0.9 → 站一拍 → − 0.9` 这一条轨迹给 1/18(全步口径)vs 1/12(动步口径)、moving_share=2/3 ⇒ 稀释效应是真的,不是猜的。写夹具时又踩一次自己的坑:`commit_n=1` 时每拍都重新规划、永远只执行候选的第 0 步,序列里的 0 与 −0.9 根本没被执行到(末步报 3.24° 而不是 0°)——夹具必须按"一次规划提交 3 步"来构造。测试 42→43 项全绿。
2026-10-20 22:37:40 +08:00
## K16:候选数翻倍是本轮第一个正向结果(轮次 39 续)
- 同一 256 题、同 seed、`--inc_cap 1` 、其余配方不变,只把 `K` 从 8 加到 16( `docs/experiment_round39_K16.json` ):
| 口径 | 到达 | 无碰撞到达 | 时限内 | 刹车/题 | 行程比 |
|---|---|---|---|---|---|
| 对照 cap( K=8) | 0.5234 | 0.5234 | 0.2656 | 19.55 | 2.6158 |
| **K=16** | **0.5625** | **0.5625** | **0.2969** | **13.77** | 2.6243 |
⇒ 到达 ** +3.9 pp**、时限内 ** +3.1 pp**、**刹车 −30%**,碰撞仍为 0,行程比不变。这一条直接支持失败分类的判断:**很多"全拒"不是真没路,而是 8 条候选里没有一条能走**;把候选池翻倍,安全层就找得到可行前缀。这是本轮(36–39)四个杠杆里第一个正向、且不放松任何判据的结果(限速 `inc_cap=1` 照开、间隙判据照旧)。
- **代价没量之前不许上线**:K=16 意味着每次规划的候选点从 32 个(8×2×2)到 64 个,认证与打分都要翻倍——这正好是要用独占微基准量的东西(跨轮次墙钟不算证据:这批整批墙钟 573 s vs 对照 325 s,但同期我在同一台机器跑了 CPU 分析,**不能当成本**)。`steps_cost` 探针之后要补一个 `K=8 vs 16` 的 B=1 周期微基准。
- **仪表对上了**: K16 报 `reverse_p50 = 1.5750` ,是**我修分母之前**的口径(每步换向轴数,0–6),除以 6 = **0.2625** ;离线按 rollout 同窗口算的对照臂预测是 **0.247** ⇒ 差 6%,在"K 更大→走得更顺"的合理方向内。读数规则写死:**产物里的 `reverse_p50` 早于 14:28 的一律先除 6**,之后的才是 [0,1] 的分数。
- 之后三臂(`safety_try 3/1` 、`z_scale 1.5` )在跑:`safety_try` 是**成本方向**的对照(只试前 3/1 条候选会掉多少到达),`z_scale` 是多样性方向。
2026-10-20 22:35:57 +08:00
## 指标链路端到端自证 + 预注册一条判读(轮次 39 续)
- **CPU 冒烟(4 题、`--select ep_waste --len_w 0.3 --cert_batch 1 --backoff 2 --inc_cap 1` ) **:产物里 `reverse_p50 / reverse_mean / backoff_mean / reject_all_mean` 四个新键**都在**( `ml/runs/_smoke_waste.json` )。这是在验证"生产端改了、消费端也要改"那条教训落地——上次 `backoff_mean` 就是这样静默丢掉的。同时证明 `ep_waste` 与 `backoff` 在真实运动学管线上能一起跑,不靠打桩。
- **预注册判读**(读 256 题四臂之前先把解释规则写死,免得事后挑数):这次 4 题小样本给的是 `backoff_mean 11.25 / reject_all_mean 88.25` ⇒ 缩步转化率约 **13%** 。
- 若 256 题也只在 10– 20% 量级:结论是**"冻住"的根因是候选方向本身对着障碍**,缩步只是慢一点撞——那 `backoff` 只留作安全侧兜底(它确实把零运动换成慢运动,但不买到达),到达率这条路要转向"围绕受阻状态重采集数据"(训练侧,需要放行)。
- 若转化率到 60% 以上:`backoff` 直接吃到失败分类里 63/109 那组,值得继续投预算(并与 `ep_waste` 组合再测)。
- 两个分支都要同时报 `brakes_mean` 与到达/时限,不能只报转化率。
2026-10-21 01:55:57 +08:00
## 轮次 39:两条没人碰过的算法杠杆——候选档位与行程惩罚(机制已单测,A/B 排队)
- **为什么是这两条**:轮次 38 的失败分类说清楚了两件事——① 到达率的缺口在"K 条候选全被拒 ⇒ 原地冻住"( 63/109),② §9.2 要"关节行程 ≤ 规划器×1.10",实测行程比中位 **2.4~2.6** ,而现在**没有任何机制在管行程**(选择器只看末态误差,安全层只看间隙)。另外 `--steps` 那组数顺带给了一条线索:多段推理把行程比从 2.62 拉到 1.87,说明行程主要由候选选择/动作形状决定,不是物理必然。
- **杠杆 1:候选档位与多样性(#15 ) **。`ml/eval/eval_cl.py` 补 `--z_scale` (rollout 早就有这个参数,只是评估没接)。四臂对照轮次 33 cap:`K=16` 、`K=8 --safety_try 3` 、`K=8 --safety_try 1` 、`K=8 --z_scale 1.5` 。要回答的是:**全拒是"真没路"还是"没备选"**——若 K=16 或 z_scale 拉大能把到达/刹车买回来,那是候选池的问题;若 `safety_try 1` 几乎不掉到达,那说明第 1 条候选就够,后面试 7 条只是在花几何查询的钱(这对 20 ms 预算直接相关)。
- **杠杆 2:行程惩罚(`select='ep_len'` + `--len_w` ) **。分数从 `-末态误差` 改成 `-末态误差 − len_w·Σ_t Σ_j |Δ_j|/STEP_j` (每轴按自己的满速步长归一,所以 6 轴可比)。
- 机制单测 2 条(`tests/test_eval_cl.py::TravelPenaltySelectTest` ,40 项全过):造两条**末态相同、累计位移相同**的候选,一条来回抖(归一行程 10.8)一条匀速(3.6),`goal_err` 打成常数 ⇒ 只有行程能把它们分开。实测 `len_w=0` 选到抖动那条(第 1 步 1.08°)、`len_w=1.0` 选到匀速那条(第 1 步 0.27°);另有一条**同分零权重必须与 `select='endpoint'` 逐位相同**的回归断言(rtol=atol=0),保证默认行为没被这次改动碰到。
- 待测:`len_w ∈ {0.1, 0.3, 1.0}` 三臂,看行程比能压到多少、到达与时限各付多少。这条杠杆与"到达率"是相互冲突的目标(惩罚行程=主动走慢),所以必须成对汇报,不能只报行程变好。
- 单位口径要说清:`len_w` 的量纲是"mm 误差 / 一个归一 STEP 的累计行程",16 步满速在 3 条轴上大约是 48,所以 0.1~1.0 对应的惩罚是 5~50 mm 当量——这是扫这三个值的原因,不是随手取的。
- 测试 `tests/test_eval_cl.py` 38→40 项、全套 43→45 项(`python -m unittest discover -s tests` ,2.2 s 全绿)。GPU 队列顺序:backoff A/B → `--safety 0` 判别 → 候选档位 → 行程惩罚。
- **等价闸门先过了**: `--backoff 0 --cert_batch 1 --inc_cap 1` 的 256 题与轮次 33 cap( `--cert_batch 0` ) **逐项完全相同**( `docs/experiment_round38_backoff0.json` 对 `docs/experiment_round33_cap.json` ,把两个 metrics 字典做键并集比较,差异集合为空,含 success 0.523438、time_ok 0.265625、brakes 19.55…)⇒ 轮次 36 我把批量认证分支重写(加缩步档那一段)没有改动任何行为。
- **两个我自己的操作失误,如实记在这里**:
1. 新加的 `backoff` 指标一度在产物里根本没有——`ml/eval/eval_cl.py:run()` 的 `out` 是**自己显式列键**的,不是从 `rollout` 返回的字典通抄,所以我往 `res` 加的 `backoff_mean` 被无声丢掉。已改成从逐题 `per['backoff']` 汇总(`backoff_mean` + `reject_all_mean = backoff+brakes` ,后者才是与"原来全拒次数"可比的量)。**教训:加指标要顺着输出链路走到底,别只改生产端。**
2. 停后台 GPU 作业时,`TaskStop` 之后 `bash` 脚本链会活下来并继续拉起下一个 python;而 `nvidia-smi --query-compute-apps` 在这台机器上列不出这些 python(只列 ShellHost/wallpaper32 之类),据此判断"卡已空"会误判。我第一次按 PID 杀子进程后,链条 30 秒后又起了一个新的 eval。第二次我按进程树杀,但**把父子关系读反了**(Windows 的 PPID 在父进程已死时是陈旧值),结果误杀了新链的第一臂。正确做法:重启前用命令行正则列出全量候选、数 python 个数确认单租户,重启后再数一次;杀之前先按 `StartTime` 判新旧。backoff 那一臂因此要补跑。
## 行程惩罚 ep_len 三臂读数:时限变好,但行程比没降(轮次 39 续,负结论)
- 同一 256 题、同 seed、都带 `--inc_cap 1` ,只改 `select=ep_len --len_w` :
| 臂 | 到达 | 时限内(≤1.3×老师) | 行程比(中位) | 刹车/题 | 成功题末态误差 |
|---|---|---|---|---|---|
| 对照(endpoint) | 0.5234 | 0.2656 | 2.6158 | 19.55 | 0.218 mm |
| len_w=0.1 | 0.5117 | 0.2695 | 2.6216 | 19.49 | 0.244 mm |
| len_w=0.3 | 0.5195 | 0.2852 | 2.6548 | 20.00 | 0.219 mm |
| len_w=1.0 | 0.5273 | **0.2891** | 2.6719 | 19.35 | — |
( `docs/experiment_round39_lenw{0.1,0.3,1.0}.json` )
- **两条相反的结论**:① 时限内**单调变好**( 0.2656→0.2891, +2.4 pp = 6 题),到达在噪声内(0.5117/0.5195/0.5273,最大偏离对照 − 1.2/+1.2 pp,n=256 下这就是噪声量级);② **行程比一点没降** ( 2.6216/2.6548/2.6719 vs 对照 2.6158, +0.006/+0.039/+0.056,只有最后一个勉强出噪声、且方向是"变差")。
⇒ "候选地平线内的累计行程"不是"实际执行行程"的好代理:罚它选出的候选在**近端少过冲**(所以收得快、时限内变好),但整段任务要更多次规划才能走完,累计行程不降反升。这条是我原先的假设被打掉,不是被确认;`ep_len` 只值 +2 pp 时限,且对 §9.2 的行程判据无用。
- 顺着这个读数,真正该罚的是**同一轴来回**而不是总长:已实现 `select='ep_waste'` ,罚 `(1 − 同轴净位移/累计行程) × 当前误差` (乘当前误差是为了近端不压死进度项——上一版的形状问题正在这里)。三臂 `len_w=0.1/0.3/1.0` 排在 `ml/runs/_waste_sweep.sh` 。
- 换向率指标 `reverse_p50` 从这一批之后才会出现在产物里(前面的臂是在改动前加载的模块跑的),口径已与离线分解同分母,预期对照臂应复现 **23.5%** 量级——**对不上就要查口径,不能各自报各自的**。
## 换向率进了评估指标(轮次 39 续)
- 分解既然指到"来回抖",每个臂都要直接报这个数,不能每次回头读转储:`rollout` 里按轴记方向,`reverse_rate` = 同轴方向翻转的步数 / 活动步数(站住的步不重置方向,所以"停了再同向走"不算换向);`eval_cl` 报 `reverse_p50` /`reverse_mean` 。
- **正对照**( `tests/test_eval_cl.py` ,42 项全绿):抖动轨迹报 >0.4、匀速轨迹报 ≈0——指标本身要证明有灵敏度,不然等于没测。
- 待交叉验证:新指标在对照臂上应复现转储离线算的 **23.5%** (p50);对不上就是两个口径有一个错。
- 生产端改了、输出端没改=没改:上一次 `backoff_mean` 就是这么丢的,这次加指标同时改了 `closed_loop.per` 与 `eval_cl` 的显式键列表。
## 行程超出的成因分解(轮次 39 续,纯 CPU 读轮次 33 base 转储)
- 口径先对齐:只在"有老师参考且到达"的题上算,自测 **2.425** 与 eval 报的 2.445 同量级(差别在我按 `t_done/DT` 取窗端,eval 逐步累加),后面的数都在这个口径上。
- **超出主要是同一根轴来回抖,不是绕远路**:净位移/总行程中位 **0.445** (完美单调应为 1.0)、各轴最大 excursion/行程 0.507、旧口径换向中位 23.5%( p25 15.7%、p75 30.3%)。
- **撤回一句我自己的假象(并且这条也要再撤回一次,见下一条)**:上面原来写"到达组抖得更厉害(26.1% vs 未到达 14.7%) ", **错在口径**。旧定义 `(dd[t+1]·dd[t] < 0).mean()` 要求相邻两步都非零,遇到"前进→停住→后退"就漏计;而未到达题恰恰大量站住,于是被系统性地少计。
- **用与定义无关的量重算(净位移/总行程,同一转储、同一窗口)**:**到达组 0.478、未到达组 0.352** ⇒ 未到达组白费比例更高(走完 738° 只前进 255°;到达组是 569°/267°)。这条稳。
- **但换向率的组间比较我第二次算错,现纠正**:上一次我用"未到达 24.0% vs 到达 14.4%"来说组间差异,那个算法把**到达题到达之后的冻结步**也算进了分母(`act` 只按 `tn<=limit` ,没排除已到达),把到达组稀释了。按与 `rollout` 完全同语义的窗口(到达题截到 `t_done` )重算,得到的是**两组差不多**:
| 转储(口径) | reverse_p50 全体 | 到达组 | 未到达组 |
|---|---|---|---|
| `round33_cap` ( =轮次33 cap,限幅) | **0.2474** | 0.265 | 0.233 |
| `round33_base` (不限幅) | 0.257 | 0.275 | 0.240 |
( `docs/experiment_round39_reverse_offline.json` )⇒ **换向是全局现象(约 1/4 的(步,轴)对在反向),不是失败题的特征** ;失败题的特征是"白费行程比例高 + 大量站住"。这两件事先前被我混成一句,现在分开。
- **可证伪预测(等 backoff 对照臂回来对表)**:同一配方下 in-eval 的 `reverse_p50` 应当 ≈ **0.247** 。差得多就说明线上实现与离线同语义重算不一致,得先查仪表再谈算法。
- **口径敏感要常驻**:分组/比较类断言之前,先换一种定义把同一份数据再算一遍;两种定义都给同方向才写进日志。分母必须与指标定义一致(`act_ = 未 done 且 在时限内` ),否则"到达题窗短"会系统性稀释任何按步数归一的指标。
- **对得上训练侧的事实**:预训练本来就有 `w_smooth=0.05` 的二阶差分正则,但闭环仍大量换向 ⇒ 训练期的平滑项没管住执行期的抖动。
- **第一条 A/B 读数(`len_w=0.1` , 256 题、`--inc_cap 1` ) **:到达 0.5117(对照 0.5234,−1.2 pp)、时限内 0.2695( +0.4 pp)、**行程比 2.6216 几乎没动**(对照 2.6158)、成功题末态误差 0.2438(对照 0.2175,变差)。
原因是量级不匹配,不是方向错:`0.1 × 累计归一行程` (16 步满速在 3 条轴上约 48)只当量 ~5 mm,而早段末态误差是几百 mm ⇒ 罚不动。等 `len_w=0.3/1.0` 两臂看行程比是否真的开始下降;若仍压不住,惩罚对象应从"总行程"换成**换向/二阶差分**(直接打这个 23.5%)。
## 执行余量与前缀完整性审计(轮次 39 续,纯 CPU 读轮次 33 转储)
- 256 题 × 195 次同步规划、commit_n=2 ⇒ 169,216 个**真正被执行过的**检查点(每步的端点+中点,间隙在 0.5 mm 截顶)。
- **执行点的间隙分布**:≥0.5 mm(=宽裕)占 **91.0%** ; 0.2– 0.5 mm 占 5.6%; <0.1 mm 占 0.84%; <0.02 mm 占 0.25%。每题"最险的那个执行点"的中位数只有 **0.029 mm** 。
⇒ 两件事:① 大多数执行是宽裕的,所以"加 0.5 mm 余量门限"只花 3 题(轮次 33 margin 已实测)是自洽的;② 但每题都会至少一次贴到 **30 µm** 级——这是胶囊模型内部的"贴",真机的运动学与装配误差远大于这个数,**搬到实机时这条是实质风险**,不能当成"我们有余量"。
- **前缀完整性**:满前缀 79.4%、部分前缀 10.8%、全拒 9.9%。分组看全拒率——**到达题 0.88%,未到达题 22.0%**(未到达组因此 44% 的步是零运动,与时间账量的 37% 同量级:那 37% 是"活动窗内",这里是"× commit_n"的换算)。
- **对 `backoff` 的预期与判据**:全拒意味着"连第 1 步的端点或中点已经穿进障碍",缩步能不能救取决于**穿得有多深**(穿 0.1 mm 救得回,穿 3 mm 救不回)。这个数转储里没记(只记被选中那条),所以直接由 `backoff_mean` /`reject_all_mean` 来量:
`reject_all_mean ≈ 原全拒次数` ( =backoff_mean+brakes_mean,与轮次 33 cap 的 19.55 可比),`backoff_mean/(backoff_mean+brakes_mean)` 就是"缩步能救回的比例"。这是补跑(#22 )要读的第一个数。
2026-10-20 21:55:15 +08:00
## 轮次 38:把 `--steps` 打通之后,闭环反而变差——瓶颈从"动作质量"移到了"安全层拒绝率"
2026-10-20 07:56:58 +08:00
2026-10-20 21:59:19 +08:00
2026-10-20 21:55:15 +08:00
- **动机**:E1-b 实测同一个模型的一步输出比它自己的两段采样离老师远 **10 倍** ( 4.33 vs 0.43)。那就先别急着训练——直接把推理段数当自变量,量闭环。`ml/eval/eval_cl.py` 加 `--steps` (默认 1,发布口径不变),同一 256 题、同 seed、同配方只改段数:
2026-10-20 07:56:58 +08:00
2026-10-20 21:55:15 +08:00
| 口径 | 到达 | 时限内(≤1.3×老师) | 刹车/题 | 到点耗时 | 行程比(中位) | 成功题末态误差 | DLS 接管份额 |
|---|---|---|---|---|---|---|---|
| steps=1 cap=0( =轮次33 base) | 0.5742 | 0.3906 | 19.25 | 2.31 s | 2.445 | 0.189 mm | 0.625 |
| steps=2 cap=0 | 0.4258 | 0.3555 | **86.31** | 1.67 s | **1.571** | 0.243 mm | 0.453 |
| steps=1 cap=1( =轮次33 cap) | 0.5234 | 0.2656 | 19.55 | 2.49 s | 2.616 | 0.218 mm | 0.613 |
| steps=2 cap=1 | 0.3945 | 0.2969 | 86.16 | 1.93 s | 1.844 | 0.293 mm | 0.445 |
2026-10-20 21:57:02 +08:00
| steps=4 cap=1 | 0.4062 | 0.3047 | 79.65 | 1.91 s | 1.882 | **0.135 mm** | 0.461 |
2026-10-20 21:59:19 +08:00
| steps=8 cap=1 | 0.4102 | **0.3242** | 79.70 | 1.93 s | 1.870 | 0.253 mm | 0.469 |
2026-10-20 08:42:29 +08:00
2026-10-20 21:59:19 +08:00
( `docs/experiment_round36_steps{2,4,8}_cap1.json` 、`docs/experiment_round36_steps2_cap0.json` )
**段数趋势(都在 `--inc_cap 1` 的合法限速口径)** :到达 0.523 → 0.395 → 0.406 → 0.410(一步之后就先掉再平),时限内 0.266 → 0.297 → 0.305 → **0.324** (单调变好),行程比 2.62 → 1.84 → 1.88 → 1.87(单调变好、贴近老师),刹车 19.6 → 86 → 80 → 80(一步之后翻 4 倍就不再降)。
⇒ 多段推理把"更快、更贴老师、更省行程"这三样都买到了,唯独买不到到达率——那道门的拒绝率把它顶住了。段数从 4 到 8 几乎不再变化,说明瓶颈不在采样精度。
2026-10-20 21:57:02 +08:00
- **失败分类**(不占卡:读轮次 33 base 的 256 题轨迹转储,CPU 重算末态位姿误差,`docs/experiment_round38_fail_taxonomy.json` )。147 到达 / 109 未到,未到题按"末态离目标多远 + 被拒多少次"分桶:
| 桶 | 题数 |
|---|---|
| 位置 >100 mm 且刹车 >30 次(走一半被冻住) | **63** |
| 位置 >100 mm 但刹车 ≤30 次(方向错 / 绕圈) | 23 |
| 位置 20~100 mm | 15 |
| 位置 5~20 mm | 5 |
| 位置 <5 mm 但姿态没到位 | 3 |
| 起步失败 | 0 |
未到组中位数:位置误差 255 mm、姿态误差 11.0°、**活动窗内 37% 的步是零运动**。
⇒ 到达率的缺口不在精度或姿态判据(这两类合计只有 8 题),而在**走一半被冻住**:76% 的失败离目标还 >100 mm,其中多数是安全层反复全拒。这正是 `backoff` (全拒时缩步顶上)对着的那块;也说明 #15 (候选数与安全档位)比"往打分里加剩余时限"更值钱。
2026-10-20 21:55:15 +08:00
- **反直觉但自洽的一组数**:两段推理**开环更贴老师**( E1-b: 0.43 vs 4.33)、**行程比更接近 1**( 1.571 vs 2.445)、**到了的题还更快**( 1.67 vs 2.31 s),但闭环到达掉 14.8 个百分点。逐题对照:108 题两者都到、**39 题只有 1 步能到、只有 1 题是 2 步独有** ⇒ 不是"换了一批题",是同一批题里 1 步原本能做对的那部分被卡住了。
- **卡点在安全层不在策略**:刹车从 19.25 → 86.3/题(4.5 倍),未到达组的刹车中位数从 45 → 176(几乎每步都被拒 ⇒ 原地冻结,末态误差 p50 也从 230 → 406 mm)。也就是说**发布的那 57.4% 是与"一步那套偏置且被削弱过的动作"共同标定出来的**:策略、反馈增益、认证口径、DAgger 采集分布四者都围着它。
- **两种解释必须分开,否则下一步会走错**:
- (A) 两段动作确实更危险(一段更长 ⇒ 真的经过障碍附近);
- (B) 拒绝来自口径而非几何。
**先把我自己写的 (B) 改正一次** :线上安全层里没有"位移界随步长放大"这回事——它只做点检(每步的端点 + 中点,`gaps(...).min(-1) > 0` ,见 `ml/sim/closed_loop.py` 的 `okstep = ok6[:, :commit_n] & ok6[:, commit_n:]` )。确定性界只在我离线做的连续认证里用。所以 (B) 不可能以"界太松/太紧"的形式成立;能以 (B) 解释的只剩两种:**点检欠采样**(那会让它偏松而不是偏严)与**候选多样性塌了**(两段积分把 K 条候选吸到一起,没有备选可退)。
于是判别实验定为三件:`--safety 0` 的 steps=1 vs steps=2 对照(看真实碰撞率差多少 ⇒ (A) 的直接证据)、候选多样性探针、steps 的 B=1 代价实测。脚本 `ml/runs/_safetyoff_ab.sh` ,结果见下面补记。
- **对 K-MF 那条训练路线的直接含义**:把角点"训准"会让动作分布变成现在两段那样 ⇒ 按当前认证口径,到达率可能**先降**。所以训练不是下一步,先做 (A)/(B) 判别;若是 (B),收紧认证(细分/更紧的界)比训模型便宜得多,而且是 50 Hz 也必须的那块。
- **共同标定的第三处证据(回代码确认)**:`ml/dagger/collect.py:48` 调 `rollout` 时也不传 `steps` ⇒ DAgger 采集的状态分布同样是一步走出来的。所以"一步偏置的动作"同时被三处围着标定:策略微调数据、反馈增益、认证口径。改任一处都要另两处跟上,不能指望"只换推理段数"就白拿 10 倍开环增益。
2026-10-20 08:42:29 +08:00
2026-10-20 21:55:15 +08:00
## 轮次 37: K-MF(运动学 MeanFlow)方案核查——先测"一步 vs 多步",结果比论文那条更要命
2026-10-20 08:42:29 +08:00
2026-10-20 21:55:15 +08:00
- **交来的方案里那几条 file:line 断言,逐条回代码核过(都成立)**:`ml/model/meanflow.py:38-39` 是标准 Eq.4 单段自举(`jvp` 切向量 (v,0,1),目标 `v − (t− r)·du/dt` );`ml/train.py:162` 调 `meanflow_loss` 时**没接 ada_p** ⇒ 自适应加权一直是默认 `ada_p=1.0` (配置里改不了,与方案说的一致);`p_neq` 在第 `p_neq_warm=5000` 步从 0 硬切到 0.5; `p_edge=0.1` 把 10% 样本钉在部署角 (r=0,t=1); `policy.sample_k(..., steps=1)` 是默认,`ml/model/policy.py:153` ⇒ **历史发布的所有数字都是一步推理** 。
- **方案里过时的两条要先改掉,否则会拿旧靶子做新实验**:「闭环 0% 到达、79% 碰撞」是 DAgger 之前的状态,现在是 256 题到达 57.4%、实际执行碰撞 0(轮次 30/33);「DAgger 全量是主线,先做」也已完成(`base_dag2_dag1` 就是两轮的产物)。所以 E 系列的判据不能再用"能不能从 0 救起来"。
- **E1 第一版判据是自证的,作废**:我先拿"网络自己的 r≠t 切片走 32 段"当平均速度真值——那正是 MF 损失直接训练的切片,等于用被测公式的收敛解当真值。改成**与损失无关的参考**:平均速度的定义是瞬时场(r=t 切片,由纯流匹配监督)的流图 `u_true = (z_t − Φ_{t→r}(z_t))/(t− r)` ,128 段欧拉;离散化自证:128 段与 512 段的真值差 0.019(相对 **0.18%** )⇒ 参考本身稳。
- **E1 结果(`docs/experiment_round36_kmf_e1.json` , 256 个 val 样本,λ=0.5,‖u_true‖ 均值 10.38)**:目标与真值的距离(越小越好)
2026-10-20 08:42:29 +08:00
2026-10-20 21:55:15 +08:00
| 目标写法 | (r=0,t=1) 部署角 | 最差 ‖du/dt‖ 处 (t=0.05) |
|---|---|---|
| MF(现行 Eq.4) | **3.851** | 2.629 |
| K-MF 按方案抄的 (1−λ)²/λ² | 7.187( 1.87×,更差) | 3.808 |
| K-MF 把平方换成线性权重 (1−λ)/λ | 14.661(更差) | 2.106 |
| 把整条修正移到中点时刻 `du(z_c,r,c)/dc` | **2.364( 0.61×)** | 2.468 |
| 网络现在的一步输出 u(ε,0,1) | 3.906 | — |
2026-10-20 09:41:44 +08:00
2026-10-20 21:55:15 +08:00
- **两条硬结论**:
1. **方案抄来的 Eq.7 系数在收敛解上不自洽** :λ=0.5 时两项系数和 = (1−λ)²+λ² = 0.5,不动点变成 `v − 0.5(t− r)u'` ,不是平均速度;实测也印证——部署角 `‖du(z_t,c,t)/dt‖ = 28.0` 而 `‖du/dt‖ = 4.24` (把 r 槽钉在中点后对 t 的导数大 6.6 倍),组合被这一项主导,所以偏差反而更大。**K-MF 仓库只有 README,论文只能引公式,这条是我们自己的数**:要么抄漏了子区间时长因子,要么 c 的定义不同。判据「K-MF 偏差 ≤ MF 的一半」在这个写法下不成立(1.87×)。
2. **自举污染是真的,而且就在部署角** :网络一步输出与自己的流图差 3.906(相对 38%),而 MF 目标的偏差 3.851 几乎一样 ⇒ 训练把目标的偏差原样灌进了线上那一步。`‖du/dt‖` 在两端炸开(t=0.05 为 156.6、t=0.95 为 64.3,中段只有 1.6– 4.1),与论文 Fig.1a 的形态一致(他们报 76×,我们这里 0.05↔0.4 是 **66× ** )。
- **E1-b( `docs/experiment_round36_kmf_e1b.json` ,512 样本,比的是"离老师多远",归一化动作块 L2)**:一步 **4.326** ;同模型 2 段 **0.434** 、4 段 0.429、32 段 0.601;流图(r=t, 128 段)0.665。**一步比多步差 10 倍**,而 2 段就基本到位(再多段反而偏离老师——那是模型自身场的偏差,不是采样误差)。
- **这一条比 K-MF 本身更要命**:57.4% 的到达是在"线上一步输出偏离自己场 10 倍"的前提下拿到的,安全层/反馈/DAgger 都在替这个角点擦屁股。所以先把 `--steps` 打通,量它对闭环到达的影响,再决定要不要为"把一步训好"付一次训练。
2026-10-20 09:41:44 +08:00
2026-10-20 21:55:15 +08:00
- **不动点判决补一个解析实验**( `tests/test_meanflow_targets.py` , 3 项,CPU/float64,与已训模型无关):1-D 高斯数据 `x~N(0,σ²)` 时 PF-ODE 是线性的,流图 `z_r = z_t·sqrt(s²(r)/s²(t))` 有闭式 ⇒ 平均速度真值有闭式。把**精确场**代进四种写法:
- 仪表自证:Eq.4 代精确场逐位还原真值(绝对偏差 <1e−12,σ=0.5/1/2 三档、(r,t) 三组都过)⇒ 后面的数可信。
- **收敛阶分开"有偏"与"无偏"**(区间长度 0.2→0.1→0.05,σ=2 的相对偏差):`sq` (按方案抄的 (1−λ)²/λ²)0.426→0.133→0.057,比值 ≈0.4 ⇒ **只有线性收敛 = 结构性少修一半** ; `lin` (换成系数和为 1 的线性权重)0.042→0.015→0.004、`mid` (整条修正移到中点)0.147→0.042→0.010,比值 ≈0.25 ⇒ 二次收敛,只剩积分误差。
- 跨整段 (0,1) 时**所有**单点导数写法都不可信(σ=2: sq 1.92、lin 1.84、mid 4.15 倍偏差),跨半段就降到 0.44–0.85 ⇒ 与 E1-b 的实测同向:**一步跨完本身难,两段就便宜一个量级**。这不是训练的毛病,是写法本身的量级。
- 测试 35→38 项(缩步档 3 项)+ 新文件 `tests/test_meanflow_targets.py` 3 项 ⇒ 共 41 项。
- **目标写法开关已落地但默认不启用**(`ml/model/meanflow.py` 新增 `avg_velocity_target(..., target='mf'|'lin'|'sq'|'mid', lam)` , `ml/train.py:162` 从配置读 `mf_target` /`mf_lam` ):
- 默认 `mf` 分支与原实现**逐位相同**(测试用同一批输入把老写法重构出来对拍 `u` 、`u_tgt` 、`z` 三个张量,rtol=atol=0)。
- 接线自证:把解析高斯场做成桩喂进 `avg_velocity_target` ,float32 下三种写法的偏差与 float64 解析值逐位到小数四位一致(sq 0.4262→0.1332→0.0567、lin 0.042→0.0149→0.0038、mid 0.1465→0.0422→0.0104)⇒ z_c、切向量、r 槽换位没接错。
- 加这个开关不是为了训它,是为了"E2 若要训,先有一条不改默认路径的口子"。要不要付这次训练,等 #21 的判别结果(见轮次 38)。
2026-10-20 09:41:44 +08:00
2026-10-20 21:55:15 +08:00
## 时间账:限幅之后 time_ok 的损失在"站住"上,不在巡航速度上(2026-10-20,轮次 36 续)
2026-10-20 09:41:44 +08:00
2026-10-20 21:55:15 +08:00
- **口径**:直接吃轮次 33 的 256 题轨迹转储(`ml/runs/round33_cap.pt` 、`round33_base.pt` ,离线分析 `ml/runs/_time_audit.py` ,产物 `docs/experiment_round36_time_audit.json` ),按每题的活动窗把每一步按「该步最大关节位移 / VMAX·DT」分四档:零运动、<0.5、0.5–0.95、≥0.95。切片时踩了一个自己的坑:`per['traj']` 是 `torch.stack(traj, 1)` 出来的 ** [B,T,6]** 而不是 [T,B,6],按列切成了"同一时刻不同题",比值全是 70~230 的 nonsense;加了 `traj[i][0] == q0` 的断言之后才挡住这类错。
- **实测(占活动窗的比例)**
2026-10-20 10:10:25 +08:00
2026-10-20 21:55:15 +08:00
| 组 | 题数 | 零运动 | <0.5 | 0.5– 0.95 | ≥0.95 | 刹停段/题 | 平均段长 |
|---|---|---|---|---|---|---|---|
| base 到达且按时 | 100 | 1.9% | 4.0% | 19.4% | 74.8% | 1.2 | 1.5 步 |
| base 到达但超时 | 47 | 10.5% | 7.2% | 25.5% | 56.8% | 10.1 | 1.7 步 |
| base 未到达 | 109 | 32.6% | 9.9% | 32.8% | 24.7% | 38.6 | 2.1 步 |
| cap(限幅) 未到达 | 122 | 30.1% | 9.7% | 31.0% | 29.1% | 35.9 | 2.1 步 |
2026-10-20 10:10:25 +08:00
2026-10-20 21:55:15 +08:00
- **判读**:限幅并没有把动作整体拖慢——未到达组的 ≥0.95 档反而从 24.7% 升到 29.1%;真正吃掉时限的是**零运动**(占活动窗 30%,平均每题 1.54 s)和**长刹停段**(最长 41 步 = 0.82 s 原地不动)。所以 #17 不该往"打分里加剩余时限"这种间接方向做,直接打"全拒⇒站住"这一条。
- **改动(默认关,`--backoff` )**:全拒时不再站住,把首选候选按 1/2、1/4、1/8…(档数 = backoff)**并进同一次批量认证**(零额外几何调用),只在原候选连第 1 步都不安全时顶上;缩步候选不参与"前缀更长者优先"的比较,所以正常路径的选择逐位不变。新增 `backoff_mean` 指标记录缩步次数。测试 35→38 项(全拒→慢爬、有安全前缀时插手无效、未开批量认证时报错)。
- **待测**: 256 题 A/B( `--inc_cap 1 --cert_batch 1 --backoff 0/1/2/3` )——GPU 先让给 K-MF E1,这轮排在其后。
2026-10-20 10:10:25 +08:00
2026-10-20 21:55:15 +08:00
## 轮次 36:规划起点队列长度实测——#19(循环内共享 FK)判掉
2026-10-20 10:10:25 +08:00
2026-10-20 21:55:15 +08:00
- **要判的问题**:轮次 35 留下"循环内唯一可省项"是 `qe == q` 时把 features 已算的 `cum_xf` 共享给反馈/打分,实测那份 `cum_xf` 在 B=1 值 **3.631 ms** 。但它只在规划时队列为空(`r = queue.shape[1] == 0` )才成立,而部署口径是 `replan='r3'` 。先量 r 的分布再决定,不靠推测。
- **做法**: `rollout(..., return_traj=True)` 顺带记每次规划的 `r` ( `plans['r']` ,纯诊断,不参与任何判据)。32 题同批、K=8、fb 2.2、dls_safety 1、`docs/experiment_round36_plan_r_hist.json` :
2026-10-20 12:20:31 +08:00
2026-10-20 21:55:15 +08:00
| 口径 | 规划次数 | r 分布 | r==0 占比 | 平摊可省 |
2026-10-20 19:13:40 +08:00
|---|---|---|---|---|
2026-10-20 21:55:15 +08:00
| empty / commit 2 / 不限幅 | 175 | r=0 全部 | 1.000 | 3.631 ms/次 |
| **r3 / commit 3 / 不限幅** | 118 | r=3:116、r=2:1、r=0:1 | **0.0085** | **0.031 ms/次** |
| r3 / commit 3 / inc_cap 1 | 118 | 同上 | 0.0085 | 0.031 ms/次 |
| empty / commit 3 / inc_cap 1 | 117 | r=0 全部 | 1.000 | 3.631 ms/次 |
2026-10-20 19:13:40 +08:00
2026-10-20 21:55:15 +08:00
- **结论(不做)**:部署 r3 稳态每次规划都从队列第 3 步之后开始,`qe` 是前缀末端而不是 `q` ,与 features 的姿态不同 ⇒ 共享率 1.7%,平摊收益 0.03 ms,为它加一条按 r 分支的参数面不值。**评测口径(empty)能省 3.6 ms 这件事不能当成部署收益汇报**——发布的那批 57.4% 数字是在 empty 下跑的,若将来把部署也改成"队列空了才规划",这条要重开。
- **顺带记下的实测**:同一批 32 题上 empty/commit2 到达 0.469、r3/commit3 0.438、加 inc_cap 后 0.406( n=32,只作方向参考,不足以定论;256 题口径见轮次 33)。规划次数差 1.5 倍(175 vs 118)——r3 每次只新增 commit 步却已含 3 步前缀,所以同样墙钟时间内规划得更少,这正是它更贴近部署的原因。
- 测试 35 项仍全过(`plans['r']` 只增不改)。
2026-10-20 19:30:02 +08:00
2026-10-20 21:55:15 +08:00
## 轮次 35:半精度、流水线复用与 float32 认证的实测(exp: `exp/dagger-deploy`,三条路两条被自己否掉)
2026-10-20 19:30:02 +08:00
2026-10-20 21:55:15 +08:00
- **按用户指定的方向先量显卡精度档**( FP32 / FP16 / BF16, `docs/experiment_round34_precision_ab.json` ; B=1、K=8、steps=1, 25 次预热 + 120 次计时):
| 精度 | 推理 P50 | 推理 P99 | 整周期 P50 | 整周期 P99 | 动作最大偏差 |
|---|---|---|---|---|---|
| FP32 | 7.68 ms | 10.63 | 36.51 | 46.57 | — |
| FP16 | 8.31 ms(慢 8%) | 12.03 | 36.16 | **55.60(更差)** | 2.1e− 3 归一化 = **0.0050°** |
| BF16 | 8.58 ms(慢 12%) | 14.17 | — | — | 1.7e− 2 = **0.0377°** |
结论:**这个网络在这个批量下不是算力受限**,半精度换不来时间,还要付动作偏差与更差的尾部 ⇒ 推理保持 FP32。(未测更大 batch,那里的结论不下。)
- **float32 能不能做认证**( `docs/experiment_round34_f32_cert.json` ,48 段 × 9 网格点 × 15 组对,宽相位 cap 2 mm):f32 与 f64 间隙差 p50 **0** 、p99 3.66e− 5、p999 7.44e− 5、**max 1.32e− 4 mm**;有符号误差 max +1.32e− 4(确有 1 例高估)、min − 1.09e−4。同一判据下 f64/f32 都接受 24/48 段,"仅 f32 判安全"= 0、符号翻转 = 0。⇒ f32 不是不能用,但**现用 eps=1e−4 已被实测越界**,要用就得把 eps 抬到 ≥2e−4 mm;且这只量了间隙值误差,没覆盖 f32 下 FK/界自身的误差,因此暂不放宽 dtype 守卫。
- **流水线复用特征间隙——否掉**( `docs/experiment_round35_pipeline_gaps.json` ):想法是"下一次规划的 q 正好是本次认证已算过的末点"。第一版给出 42.1→31.8 ms,但**等价性检查不通过**(缓存行与新算差 3.19 mm)——是我取行索引用错(`full[CN-1]` 取到第 2 条候选的第 1 步,而非第 1 条候选走完 commit 步)。修好后收益只剩 **34.8→31.7 ms(−3.1 ms) ** :复用要求认证调用改用 cap=40 的宽相位(特征所需),省下的被吃回大半;且缓存行与新算**不是逐位相同**(差 6.3e−5 mm,源于不同 batch 下矩阵乘的结合序),会扰动特征输入。⇒ 不为这 3 ms 改口径,放弃。
- **剩下的量级判断**:一个周期 ≈ 推理 7.2 + 特征 13.1(宽相位 8.2 + FK 4.0) + 末态打分 4.3 + DLS 6.5 + 认证 7.4 ≈ 33 ms,其中 **4–5 次调用各自重做同一个宽相位筛选** (67,256 个簇对)。下一步是把一次筛选的半径按位移界(`cert_lever` )扩到整个 commit 地平线,供同周期所有点共用——这才是有量级的候选,而不是再抠精度。
- **再一次自我撤回(方法论)**:为了找"合并几何调用"的收益,我写了三个变体的探测:①两次独立调用 17.62 ms、②共享一次 `cum_xf` 13.32 ms、③合成一次 cap=40 调用 9.51 ms(交错 90 轮,特征行逐位一致)。**②③ 都不成立**:探测里认证点直接取自轨迹、与特征无关,而真实循环的顺序是 特征(q) → 推理 → 候选 → 认证点(q+Δ),认证点在特征算完之前不存在 ⇒ 同一次规划内既不能共享 `cum_xf` ,也不能把两次 `gaps` 合并。只有 ①→轮次 34 已落地的 `gm_groups` 复用 `xf` (同一姿态内部,−3.4 ms)是真的。教训:**效率探测必须按真实数据依赖排布,否则测的是不存在的调用图**。
- **循环内还剩的可复用点**: `replan='empty'` 且队列为空时 `qe == q` ,此时目标反馈 DLS 与末态打分的 FK 和特征用的是同一姿态,可以共享一份 `cum_xf` (部署 `r=3` 时不成立,要按 r 分支)。这条待测(#19 )。
- **守卫补一个**: `gaps()` / `gm_groups()` 现在拒绝行数与 `q` 不符的 `xf` (之前会静默按别的行做宽相位,实测触发 CUDA device-side assert 或给出错间隙),测试 34→35 项;`python -m ml.eval.check_parity` 仍 PASS( 2000 样本,间隙差 2.52e−13 mm、碰撞布尔差 0、特征差 5.96e−08)。
## 轮次 34:GPU 周期的可实现优化——复用 FK 与压认证最坏情况(exp: `exp/dagger-deploy`)
- **起因与一次自我撤回**:轮次 33 记下"合并几何查询看能不能进 20 ms"后,先按 `docs/experiment_round34_fused_cycle.json` 测出"整周期 41.9→24.5 ms"。这个数**作废**,两个独立原因:
1. 第一版的"合并"把 `xf=` 传给了包含 5 行的 `gaps` 调用,而 `gaps` 的 `xf` 是按行对应的 → 只有第 0 行走完宽相位,认证点 4 行全部退回截顶值 40.0 mm,即**少干了活**(表现为认证矩阵差 31.17 mm)。修好后同一 cap 下矩阵逐位一致(差 0.0 mm)。
2. 更根本:真实管线顺序是 特征 → 推理 → 候选 → 认证,**认证点依赖网络输出**,所以"特征用的 q 间隙与认证点间隙合成同一次调用"在实现上做不到。该文件保留作记录,但不能当作可实现收益。
- **只测可实现的口径**( `docs/experiment_round34_geom_opt.json` ; B=1、K=8、commit 2;7 个变体逐轮交替、奇数轮反序,80 轮;等价性两项都 `True` :批量认证矩阵与逐条循环逐位一致、features 复用 xf 前后逐位一致):
| 变体 | 含义 | P50 | P95 | P99 |
2026-10-20 19:30:02 +08:00
|---|---|---|---|---|
2026-10-20 21:55:15 +08:00
| A_today | 现口径 | 33.49 | 46.14 | 64.69 |
| B_xf_reuse | `gm_groups` 复用 features 已算的 `cum_xf` | **30.12** | 42.35 | 66.37 |
| C_batch_cert | K 条候选的认证点并成 1 次 gaps | 38.05 | 50.17 | 59.86 |
| D_both | B + C | 34.87 | 39.81 | 48.26 |
| E_both_cont_n8 | B + C + 连续认证 n=8 | 43.73 | 51.08 | 65.68 |
| F_worst_loop8 | **最坏情况** :所有候选被拒(今天逐条串行 K 次调用) | 80.22 | 88.44 | 89.55 |
| G_worst_batch | 同一最坏情况但并成 1 次调用 | **37.14** | 46.06 | 52.22 |
2026-10-20 19:30:02 +08:00
2026-10-20 21:55:15 +08:00
- **复用 FK 是无条件收益**:省一次 `cum_xf` (约 3.4–3.7 ms),特征输出逐位一致,已直接实现进 `ml/common/kin_torch.py` 的 `gm_groups(..., xf=)` 与 `ml/common/features.py` (默认行为不变,新参数仅在调用方已算过 xf 时传)。
- **批量认证是"典型换尾部"**:常见路径(第一条候选就通过)贵 4.6 ms;但今天一旦前面的候选被拒就要串行调用,实测最坏 **80.2 ms( 12.5 Hz)→ 37.1 ms** , P99 64.7→48.3 ms( D vs A)。硬实时看的是最坏情况,所以这条值得做,但要按"典型略变慢、尾部大幅变稳"来汇报,不能只报 P50。
- **仍未到 20 ms**:即便 D 档 P50 34.9 ms、P99 48.3 ms。连续认证挂在 D 上是 43.7 ms(E)。所以 GPU 侧下一步只能是更结构性的:认证降 float32(需先批量量化 f32/f64 判据差异,不能凭 3 个点下结论)、把宽相位做成可增量复用的核、或 `torch.compile` /CUDA Graph 把碎 kernel 合批。
- **等价性闸门(纯效率改动不许改变任何结果)**:
- 复用 FK:同一 256 题、同 seed、同配方重跑(`docs/experiment_round34_xf_reuse_check.json` ),**22 个指标逐项与轮次 33 base 完全相同**(含 success 0.57421875、time_ok 0.390625、brakes 19.25、speed_ratio_max 1.660003662 等)。整批墙钟 296.3 → 318.0 s,是两次独立运行的差,**不能当作开销结论**:省下的那次 `cum_xf` 只在 B=1 交错实测里量到 −3.4 ms,批量评估里一次调用已覆盖 256 行,摊薄后不足以抵消运行间波动。
- 批量认证(`--cert_batch 1` ,默认 0 不变):同一 256 题重跑 **22 项指标与 base 逐项相同** ( `docs/experiment_round34_cert_batch_check.json` , success 0.57421875、time_ok 0.390625、speed_ratio_max 1.660003662 等全部一致),整批墙钟 296.3 → 306.9 s(批量口径把 8 次串行调用换成 1 次 K×256 点的大调用,均值略涨符合预期,与 B=1 交错实测方向一致)。合成夹具里也断言两条路径选到同一条候选、同一前缀长度、逐位相同的轨迹与证书。
- **测试 32→34 项**: `CertBatchEquivalenceTest` 两条(候选 0 前缀不完整 → 选候选 1;所有候选第 2 步都不安全 → 两条路径都停在第 1 步)。写夹具时踩到一个自己的坑:桩里掩码写成 `q[:, :1]` 再 `[:, None]` 变成 3 维,广播出 (4,4,49) 才报"size 16",是**测试桩错**不是库错——先证形状再改代码。
2026-10-20 19:30:02 +08:00
2026-10-20 19:48:23 +08:00
## 轮次 33:把速度做成可观测的硬约束,再测限幅与余门的代价(exp: `exp/dagger-deploy`)
- **仪表先行**: `rollout()` 现在逐题记录**实际执行**的速度比 `max_j|Δq_j|/STEP` ( STEP=VMAX·DT,所以 1.0 = VMAX)和按控制步的速度变化比;`eval_cl` 汇总 `speed_ratio_p50/p95/max` 、`over_vmax_rate` 、`accel_ratio_p95/max` ,并把逐题值放进 `per` (极值/分位不进按 n 加权的批聚合)。
- **仪表自证**:用第30轮 after 的 trace 独立重算得 max **1.660004× VMAX** 、超速度题占比 **1.0** ,与新指标在同一批上逐位一致(`speed_ratio_max` 1.660003662、`over_vmax_rate` 1.0);这是"先证判据有灵敏度",不是拿新数当结论。
- **默认路径未变**: `--inc_cap 0 --gap_margin 0` (新默认)跑出的每个旧指标与第30轮 after 完全相同——success 0.57421875、无碰撞到达 0.57421875、time_ok 0.390625、碰撞 0、刹停 19.25、行程比 2.4449527263641357、ratio2s 0.20997506380081177、成功题误差 0.18899640440940857、dls_share 0.625( `docs/experiment_round33_base.json` )。整批墙钟 296.3 s 与第30轮 248.8 s 不可比:这期间我在同机跑了 CPU 分析,属自我污染,仪表开销需独占另测,不作为结论。
- **两个新开关**: `inc_cap=1` 在**反馈叠加之后**再按每轴 VMAX·DT 限幅(此前 `inc=clamp(act,±1)·astep` 之后又加 `gain× fb` ,所以 1.66× 是结构性的);`gap_margin>0` 让安全层要求间隙 > 余量而非 >0,并把宽相位 cap 自动抬到 `margin+0.5` ——不抬的话 `gaps(allq, 0.5)` 的截顶值 0.5 会让任何 >0.5 的余量门限恒假。`col` (真实碰撞计数)仍按 `gap≤0` 判,不随余量改变,所以两者不会互相顶替。
- **部署侧同病**(只读核查,未改 JS):`webapp/js/ik-policy.js:355` 也是 `inc[s][j] += fbGain*fbStep[j]` 在 ±1·STEP 之后叠加,所以浏览器控制器同样能超 VMAX;JS 的余量是 `o.margin=5` 的**投影式**护栏(`project()` 每轴 ≤projMax,只处理 gap<margin 的近距对),与本轮的"低于余量就刹停"不是同一机制;`ACC=5.0` 只用于刹停段长度,不是每步加速度上限(§9.2 也没给数值化的加速度门槛,所以 `accel_ratio` 只作变体间比较)。
- **间隙分布的口径坑**:第30轮 `plans['gaps']` 是在 cap=0.5 下记录的,所以"最小间隙 ≥1 mm 的题占 0"是截顶假象。可说的是:逐题最小记录间隙 p5 **0.0005** 、p25 0.0064、中位 **0.046** mm, 57.4% 的题曾低于 0.5 mm——即策略实际贴障碍飞,而查看器护栏是 5 mm。要把 0.5 以上那段分开,必须抬 cap 重算(本轮后续做)。
2026-10-20 20:32:19 +08:00
- **四组单变量对照**(同 256 题、同 seed、其余按第30轮配方):base / `inc_cap=1` / `gap_margin=0.5` / 两者同开。结果见下表。
- **四组单变量对照结果**(同 256 题、同 seed、K=8、commit 2、fb 2.2、fb_block_gain 0.5、dls_safety 1、select endpoint、replan empty、partial 1; `docs/experiment_round33_{base,cap,margin,both}.json` ):
| 变体 | 到达 | 无碰撞到达 | time_ok_1p3 | 真实碰撞 | 刹停/题 | 速度比 p50 | 超 VMAX 题占比 | 2 s 误差比 |
|---|---|---|---|---|---|---|---|---|
| base | 147/256 = 0.5742 | 0.5742 | 0.3906 | 0 | 19.25 | 1.660 | 1.000 | 0.2100 |
| `--inc_cap 1` | 134/256 = 0.5234 | 0.5234 | 0.2656 | 0 | 19.55 | 1.000 | 0.000 | 0.2790 |
| `--gap_margin 0.5` | 144/256 = 0.5625 | 0.5625 | 0.3789 | 0 | 20.05 | 1.660 | 1.000 | 0.1817 |
| 两者同开 | 133/256 = 0.5195 | 0.5195 | 0.2617 | 0 | 19.97 | 1.000 | 0.000 | 0.2870 |
- **速度限幅是有代价的硬约束**:每轴增量限回 VMAX 后到达 − 5.1 pp、time_ok − 12.5 pp、2 s 误差比 0.210→0.279。也就是说 base 的 57.4% 里**有一部分是用超速换来的**:反馈在限幅之外叠加,实际替模型补了速度。不能把 base 当作"满足速度约束的成绩"。
- **机理**: base 速度比 p50=1.660 恰等于 `1+0.3× fb_gain 2.2` ;限幅后刹停几乎不变(19.25→19.55),但 time_ok 掉得比到达更多,说明损失集中在**逼近目标末段被剥夺了超速修正**,不是更容易刹停。所以出路不是调低增益(第29/30轮已测:增益小到达就掉),而是把该由前馈承担的速度还给模型——在限幅后的分布上重采数据(DAgger,需批准),或用不违反速度约束的前馈(#14 的余量投影 + 按时限打分)。
- **0.5 mm 余量门很便宜**:只少 3 题、刹停 +0.8/题,2 s 误差比反而更好(0.182)。但这不等于裕度够用——它只说明"要求 0.5 mm 不明显拖慢"。5 mm(查看器护栏)是否同样便宜,取决于策略能否找到 ≥5 mm 的路径,必须抬 cap 重算真实间隙分布才能回答(第30轮 `plans['gaps']` 在 0.5 mm 截顶,算不出这一条)。
- 四组 `collision_rate` 都是 0,但这仍是端点/中点离散口径;`gap_margin` 不改 `col` 判据(仍 `gap≤0` ),余量与碰撞计数是两条独立的线,不互相顶替。
2026-10-20 19:48:23 +08:00
- **回归**: `python -m unittest tests.test_eval_cl` **30 项通过** (新增 4 项):未限幅时实测速度比确实 =3.4/1.2>1(灵敏度)、限幅后恰为 1.0、0.3 mm 间隙在余量 0 时通过而余量 0.5 时刹停、5 mm 间隙在余量 0.5 时仍通过(证明 cap 抬升生效,否则该测试会恒假)。
2026-10-20 20:32:19 +08:00
- **GPU 上的一个控制周期(按 GPU 口径实测)**:诊断档与逐项分解见 `docs/experiment_round33_gpu_cycle.json` ,真实配方(steps=1)见 `docs/experiment_round33_gpu_cycle_steps1.json` , RTX 3090、B=1、float32 推理 + float64 认证,每项 20 次预热 + 120 次计时并 `cuda.synchronize` 。
- **前提更正(重要)**: `eval_cl` 从不传 `steps` , `rollout` 默认 `steps=1` ,而 `ml/model/policy.py:156` 写明"steps=1 即一步生成,steps>1 是诊断用"。所以第27轮以来的所有评估成绩一直是**单步推理**;本节先用 steps=16 测出的"当前配方 116 ms ≈ 8.6 Hz"是口径错误,已作废并在下面用真实配方重测。
- **真实配方(steps=1, K=8)的分解**:
| 环节 | P50 | P95 | P99 |
|---|---|---|---|
| 推理 `sample_k` steps=1, K=1 / 4 / 8 | 7.11 / 7.08 / 7.19 | 9.45 / 10.17 / 9.95 | 11.91 / 14.00 / 11.34 |
| 特征 83 维(总 / 其中宽相位间隙 / 其中 FK) | 13.11 / 8.18 / 4.00 | 19.57 / 16.57 / 7.51 | 21.17 / 19.43 / 8.47 |
| 目标反馈 DLS 1 步 | 6.53 | 9.32 | 12.62 |
| 现有离散安全层 4 点(cap 1.0) | 7.41 | 11.34 | 13.80 |
| `certify_uniform` 2 根 n=8 / n=16 | 9.70 / 16.07 | 14.40 / 20.95 | 15.75 / 24.42 |
| 组合周期(同一位姿,顺序测;跨行比较受漂移影响,只作量级) | P50 | P95 | P99 |
|---|---|---|---|
| K=8 + 离散安全层(真实配方) | **36.68 → 27.3 Hz** | 43.27 | 49.17 |
| K=4 / K=1 + 离散安全层 | 37.71 / 40.36 | 55.17 / 48.46 | 76.53 / 52.06 |
| K=8 + 连续认证 n=8 | 45.34 → 22.1 Hz | 49.68 | 52.20 |
| K=8 + 连续认证 n=16 | 49.55 → 20.2 Hz | 56.85 | 59.06 |
| (对照)诊断档 steps=16 的同一周期 | 116.5 | 134.5 | 142.6 |
- **归因更正(先证仪表再下结论)**:空算子 P50 0.028 ms、空 `synchronize` 0.005 ms、一次 `encode` 2.27 ms,所以**不是启动/同步地板**。先前口算的"5– 10 ms 是 GPU 启动开销"错了,在此更正:特征 13.1 ms、认证 7.4 ms、DLS 6.5 ms 是 B=1 下真实的小算子工作量——即 **GPU 在单臂批量=1 时利用率极低** ,而不是被框架拖慢。
- **推理不是瓶颈,几何才是**:单步推理 7.2 ms,且候选数几乎免费(K 1→8 不涨);一个周期里几何类工作合计约 27 ms(特征宽相位 8.2 + 特征 FK 4.0 + 认证 7.4 + DLS 6.5),并且这几次调用各自重复做 `cum_xf` 与宽相位筛选。所以 50 Hz 的路径是**合并几何查询**(`features()` 已支持 `gm=` /`xf=` 复用,`gm_groups` 文档保证与整表 `gaps` 数值一致),而不是继续压推理。
- **连续认证的增量成本可接受**:在同一位姿上 n=8 只比现有离散层贵约 8.7 ms(整周期 36.7→45.3 ms),n=16 贵约 12.9 ms。也就是说"段内连续证明"在 GPU 上不是奢侈项,真正卡住 20 ms 的是那 ~27 ms 的重复几何。合并后再看是否进得了 20 ms——这一步正在做交错复测(跨行顺序测的数字受漂移影响,不作最终结论)。
- **50 Hz 结论(当前状态)**:真实配方一个规划周期 **36.7 ms( P99 49.2)≈ 27 Hz** ,仍不满足"P99<20 ms";且必须记住这是在**不限幅**(可超速 1.66×)的策略分布下测的——限幅后的到达率代价见上表,两者不能混着谈。
- f32 与 f64 的间隙在 3 个点上完全相同(最大偏差 0.0 mm、无符号翻转),但 **3 个点不足以支持"认证可以改用 float32"** ,需按真实轨迹批量对比才能下结论。
2026-10-20 21:55:15 +08:00
## 轮次 32:均匀细分认证与确定界的反证(exp: `exp/dagger-deploy`,认证仍进不了 20 ms,但定位到真正的成本杠杆)
2026-10-20 20:53:43 +08:00
2026-10-20 21:55:15 +08:00
- **本轮假设**:第31轮的二分认证把成本花在**多次依赖的 gaps 调用**上(B=1 时每次约 7 ms 起步)。若改成固定层数的一次均匀细分,同样的判据应只付一次调用;同时需要单独证明"这个确定界本身没被低估",否则判据再快也没意义。
- **实现**: `Kin.certify_uniform(a, b, n, eps, cap=None)` ——每根段取 n 个子段、一次 gaps 调用查 n+1 个点,对**每个子段**用与二分版完全相同的判据(子段两端间隙之和 > 子段位移界 + 2eps;界对 Δq 线性,故子段界 = 整段界/n)。没有"未决"状态:证不出就是 `unproven` (拒绝),不存在把未知当安全。未接入 rollout,未改查看器默认。
- **确定界的反证**( `docs/experiment_round32_bound_falsification.json` ):对 48 段每段取 121 个网格点,逐组对比"实测最小间隙"与"预测下限 (ga+gb− bound)/2"。720 项检验**0 违例**;但只有 **61 项有信息量** (预测下限 < 观察 cap 2 mm 才可能被证伪;其余组对的预测下限中位数 15.9 mm、最大 19.96 mm,都被钳制恒等式自动满足)。61 项里最紧的一项仍比预测下限高 **0.035 mm** , p10 高 0.544 mm。因此这是"未能在真实运动上证伪该界",不是"证明了该界";浮点求距误差仍未做形式化上界。
- **接受率曲线**( 48 段单根,`docs/experiment_round32_uniform_validation.json` ):
2026-10-20 20:53:43 +08:00
2026-10-20 21:55:15 +08:00
| 子段数 n | 判安全 | 判碰撞 | 证不出 | 二次加密(2n+1点)反证的误放行 |
2026-10-20 20:53:43 +08:00
|---|---|---|---|---|
2026-10-20 21:55:15 +08:00
| 8 | 26 | 1 | 21 | 0 |
| 16 | 30 | 1 | 17 | 0 |
| 32 | 34 | 1 | 13 | 0 |
| 64 | 36 | 1 | 11 | 0 |
| 128 | 38 | 1 | 9 | 0 |
2026-10-20 20:53:43 +08:00
2026-10-20 21:55:15 +08:00
第180题 1.08– 1.10 s 那段(第30轮加密回放检出 −0.14927 mm、原离散证书 `certified=true` )在**每个 n≥8 都判碰撞**。
- **宽相位 cap 的正确公式**(对第31轮一条负结论的更正):第31轮用 `bound/2 + eps` ,那个值恰好**会把本可通过的子段钳成不可证**,所以既没提速也可能少接受;本轮改成"最小不挡住判定的宽相位"= `最大子段界 + 2eps` , n=4 时是 5.92 mm、n=128 时 0.37 mm。第31轮那句"自适应 cap 无收益"只在旧公式下成立,新公式的实测收益见下表(原记录保留,不回改)。
- **计时 A/B**( `docs/experiment_round32_uniform_latency.json` ; B=2 根=部署 commit2 口径,24 对根逐对按正序/逆序**交替**测全部配置,每配置 3 次预热 + 7 次计时 = 168 次;CUDA float64):
2026-10-20 20:53:43 +08:00
2026-10-20 21:55:15 +08:00
| 配置 | 宽相位 mm | P50 | P90 | P99 | >20 ms 次数 | 安全/碰撞/拒(48根) |
|---|---|---|---|---|---|---|
| 均匀 n=8 auto | 5.92 | **9.68** | 13.03 | 15.16 | 0/168 | 26/1/21 |
| 均匀 n=16 auto | 2.96 | **14.14** | 18.45 | 20.87 | 5/168 | 30/1/17 |
| 均匀 n=32 auto | 1.48 | 20.21 | 27.88 | 32.27 | 87/168 | 34/1/13 |
| 均匀 n=64 auto | 0.74 | 31.43 | 48.75 | 57.70 | 165/168 | 36/1/11 |
| 均匀 n=128 auto | 0.37 | 59.76 | 89.06 | 109.09 | 168/168 | 38/1/9 |
| 均匀 n=8 cap20 | 20 | 13.13 | 16.44 | 20.96 | 3/168 | 26/1/21 |
| 均匀 n=32 cap20 | 20 | 28.41 | 39.58 | 53.02 | 153/168 | 34/1/13 |
| 均匀 n=64 cap20 | 20 | 50.85 | 75.51 | 88.36 | 168/168 | 36/1/11 |
| 均匀 n=128 cap20 | 20 | 98.46 | 139.98 | 167.04 | 168/168 | 38/1/9 |
| 二分 budget32 | 20 | 54.88 | 82.15 | 117.20 | 133/168 | 37/1/10 |
| 二分 budget65 | 20 | 71.83 | 108.56 | 122.53 | 133/168 | 41/1/6 |
2026-10-20 21:01:04 +08:00
2026-10-20 21:55:15 +08:00
- auto 与 cap20 的**决策列完全相同**,只是快 1.36– 1.65×(n=8 13.13→9.68、n=128 98.46→59.76):这次是交错实测的真收益,不是第31轮那种顺序漂移。
- 单次调用的均匀细分在同样接受率下比二分便宜 5 倍以上(n=8 9.68 ms vs 二分 54.88 ms),但二分在同样时间能多证出 11 根——两条路的取舍由下一段的结论决定,不单看耗时。
- **负结论(部署口径)**:只有 n≤16 能把认证本身压进 20 ms( P50 9.68– 14.14 ms),而这档只能证出 48 根里的 26–30 根(54–63%),其余必须刹停;n=32 起 P50 就已经吃满 20 ms,还没算推理。所以**连续段认证按现有几何口径不能同时满足"P99<20 ms"和"不牺牲到达"**。这些数是 CUDA float64 的单次调用,不能外推到浏览器 CPU float32 的 50 Hz 链路。
- **机理定位与下一步**:成本 = 单次调用固定开销 × 由 `log(bound/间隙)` 决定的层数。要同时拿到"证得出"和"证得起",必须把**间隙抬起来**(安全层要求正余量,而不是 `gap>0` )并把**每步位移压回去**(反馈叠加在 ±1 限幅之后,导致第30轮实测最大 1.66×VMAX,界也随之变大)。顺带记下一个坑:安全层现在是 `kin.gaps(allq, 0.5)` ,截顶值 0.5 mm 低于任何 >0.5 mm 的余量门限,直接把余量判据变成恒假——加余量必须同时抬这个 cap。
- **回归与判据灵敏度**: `python -m unittest tests.test_eval_cl` **26 项通过** (新增 3 项均匀细分)。含解析对照:合成恒间隙段(界 1 mm/度、间隙 0.1 mm)在 n=5 必判证不出、n=6 必判安全,且 `cap_required_mm` 等于 `1/n+2eps` ;薄障碍在 n=4/8/64 判碰撞而 n=2 只判证不出(不误放行);`n` 给成张量被类型门拒绝。二次加密反证在 n=8..128 全部 0 误放行。
2026-10-20 21:01:04 +08:00
2026-10-20 21:55:15 +08:00
## 轮次 31:连续段认证的确定界与成本实测(exp: `exp/dagger-deploy`,判据变强,实测进不了 20 ms)
2026-10-20 21:01:04 +08:00
2026-10-20 21:55:15 +08:00
- **假设与判据**:轮次 30 的端点/中点检查漏掉段内碰撞(第180题 1.08– 1.10 s,段内 − 0.14927 mm,端点/中点均正)。若用可证明的全姿态运动界对整段做 Lipschitz 判据,应当(a) 在同一个漏检段上给出碰撞或拒绝,(b) 预算不足时只会拒绝而不会放行,(c) 不放宽 `>0` 判据。判据失败或耗时超预算都算负结论,必须实测不能外推。
- **确定界替代随机采样界**:JS 侧 `leverTable(4000)` /`leverBounds(20000)` 是随机姿态最大值再 ×1.05,不是全姿态上界。本轮按三角不等式给闭式界:组 g 的胶囊端点到关节 k(<g) 的最大位移 = (Σ_{j=k}^{g-2}‖P[j+1]− P[j]‖ + max_e‖e− P[g− 1]‖)·|Δq_k|(k=g−1 时末项换成端点到该轴的垂直距离),组对 (ga,gb) 只累加 ga..gb− 1,取组内最小仍保留 Lipschitz 性质。Python 端 `Kin.cert_lever` ( 15× 6)即此表,未改 `lever` ,也未改 JS。
- **界的量级**( STEP=[1.2,1.2,1.8,1.8,2.4,3.6]°):单整步在各组对上的位移界 **5.93– 48.86 mm** ,0 层通过要求端点间隙之和 > 界,即单端间隙至少 3.0–24.4 mm。实际执行段的间隙普遍只有 0.001–0.5 mm,所以“必须细分”是结构性的,不是实现缺陷。
- **基础求距 bug 与影响范围**:模型里有 1 个退化胶囊(索引 686,组 3)。旧 `seg_seg_dist` 在第二条线段退化成点时固定取该点为第二条起点,没把点投影到第一条线段上——[0,2] 段对点 1 的实测距离旧值 1 mm、反向调用约 1e−9 mm、真值 0。修复后在已有 2000 个对拍姿态的前 64 个姿态上,670 个“退化胶囊作第二条”的细对里 **20661/42880 个距离变小(旧值偏大,最大 86.003 mm)** ,正反调用一致。但这批变化没有进入判定:把轮次 30 修复后 48 段的 7586 个 0.01° 加密点分别用修复前(95da491)与修复后内核重算,**组最小间隙逐位相同(最大差 0.0 mm)、碰撞布尔差 0**;`python -m ml.eval.check_parity` 仍 PASS( 2000 样本,fk 4.55e− 13 mm、间隙 2.52e− 13 mm、特征 5.96e− 08、梯度相对误差 1.85e−06、碰撞布尔差 0)。即这轮修复是正确的,但不解释轮次 30 的漏检,也不改变既有成绩。
- **认证实现**: `Kin.certify_segments` 为 float64 批量前沿二分,每根段独立查询预算,端点间隙用 `min(gap,cap)` 故钳制只会更保守;判据 `ga+gb > bound+2eps` 且两端 >eps,任一子段碰撞即整根判碰撞;超深度、超预算、非有限间隙、越出关节盒一律拒绝(`unresolved` /`outside_box` ),不放行未知。宽相位 cap 可按本层界收到 `bound/2+eps` ( `adaptive_cap` )。**尚未接入 rollout,未改查看器默认。**
- **48 段固定样本**( `docs/experiment_round31_certificates.json` ,沿用轮次 30 的 12 题,每题取首/中/末移动段 + 原证书最小间隙段 + 显式指定 180:54; cap=20、eps=1e− 4、max_depth=12):
| 每根查询预算 | 判安全 | 判碰撞 | 未知拒绝 | 查询数 p50/max |
2026-10-20 21:16:27 +08:00
|---|---|---|---|---|
2026-10-20 21:55:15 +08:00
| 2 | 20 | 0 | 28 | 2 / 2 |
| 8 | 26 | 1 | 21 | 4 / 8 |
| 32 | 37 | 1 | 10 | 4 / 32 |
- 已知漏检段(180 题执行段 54)**判碰撞,仅用 5 次查询**;该段原证书 `certified=true` 、原内部 `col=0` 。48 段里 0.01° 加密采样检出碰撞 1 段,认证接受该类段 **0 段** ;整批与逐根调用结果逐位一致。
- 拒绝不等于安全:预算 2 时 28 段全部落 `unresolved` ,实现不会把未知当通过。
- **成本模型对上实测**( `docs/experiment_round31_cert_cost_model.json` ):按最紧组对的界,所需层数 `L=ceil(log2(bound_pair/(ga+gb)))` 、查询数 `2^L+1` 。37 个判安全段需要 2–17 次(L=0..4),10 个未知段需要 **33 或 65 次** (L=5..6),与预算 32 恰好卡在中间一致;碰撞段因提前撞到负间隙只用 5 次。结论:认证成本由 `bound/间隙` 的对数决定,**降低界或提高间隙余量**才是可行杠杆,加预算只是线性买单。
- **耗时负结论**( CUDA float64、B=1、驻留输入、每段4次预热+9次计时、变体按段交错,`docs/experiment_round31_adaptive_cap.json` ):单段认证 **P50 22.93 ms、P90 58.43 ms、P99 101.57 ms, 432 次里 225 次 > 20 ms** ;自适应 cap 交错重测 P50 23.21 ms、P99 99.10 ms, **决策完全相同、耗时无收益**。先前顺序测得的“1.6×、整批 72→14.8 ms”经交错复测判定为 GPU 时钟/顺序漂移,不作为结论(48 根整批复测 260→212 ms 仍受同一偏差影响,且部署不会出现 48 根同时认证)。因此**连续认证按当前实现不能进 20 ms,更不能宣称 50 Hz**。
- **回归与判据灵敏度**: `python -m unittest tests.test_eval_cl` **23 项通过** (轮次 30 为 14 项)。新增段认证 8 项覆盖:薄障碍段内碰撞被界抓到而清晰段被接受、预算/深度耗尽只拒不放、恒间隙合成段上预算 4/8/9 对应查询 3/5/9(验证细分层数与查询数的解析关系)、批量与逐根及乱序一致、空批与全拒前沿、NaN/±Inf 间隙拒绝、越界拒绝、退化距离对称性与梯度。**变异实测**:把类型门去掉后 `max_depth=torch.tensor(255,dtype=torch.uint8)` 会回绕成 `range(0)` 、整段判据被跳过,真实间隙 −0.05 mm 的段直接返回 `safe=true` ;加门后同一调用报 `certification budgets must be plain ints` 。这是本轮抓到的第二个误放行路径(第一个是轮次 30 的未夹紧认证)。
- **口径与边界**:认证只在 float64 下进行,浮点求距误差没有形式上界(`seg_seg_dist` 距离下限约 1e− 9 mm),eps=1e−4 mm 是工程容差不是证明;48 段取自轮次 30 修复后的执行轨迹,是固定样本不是新策略闭环;连续认证未接入 rollout,实际执行仍走端点/中点离散检查;速度/加速度超限(轮次 30 实测最大 1.66×VMAX)本轮未处理。
- **结论与下一步**:判据确实变强(抓到离散检查漏掉的段内碰撞、未知只拒不放),但成本与 `bound/间隙` 的对数绑定,**当前实现不能部署,也不得把“认证通过”说成零碰撞**。下一步两条:(1) 把逐层依赖的二分改成**一次均匀细分**(固定层数、单个 gaps 调用覆盖全部子段),其实时可行性取决于几何查询成本随批大小是否近似平坦;(2) 把余量要求移到规划/速度侧——实际轨迹贴着 0.001–0.02 mm 间隙走,任何认证方案都会退化成几十次查询,而反馈叠加后的速度约束本来就是未完成项。
2026-10-20 21:16:27 +08:00
2026-10-20 21:55:15 +08:00
## 轮次 30:认证与执行统一逐步限位(exp: `exp/dagger-deploy`,局部修复有效,仍未零碰撞)
2026-10-20 21:16:27 +08:00
2026-10-20 21:55:15 +08:00
- **假设与判据**:安全层认证的是未夹紧累加轨迹,执行器却逐步夹紧 J5,导致认证通过后碰撞。必须同时证明原证书安全、执行点碰撞、记录命令经执行算式能准确重建实际点;修复后保持同任务、同种子、同模型、同增益和同排序,到达不下降,并用不依赖原 `col` 标记的加密回放检验。
- **固定配方**: `python -u -m ml.eval.eval_cl --n 256 --commit 2 --fb 2.2 --partial 1 --replan empty --select endpoint --fb_block_gain 0.5 --dls_safety 1` ; K=8、seed=0、analytic DLS、dag2 checkpoint、fallback=0,其余参数默认;分别附 `--out docs/experiment_round30_before.json --trace ml/runs/round30_before.pt --dump ml/runs/round30_before_rows.json` 和对应的 `after` 路径。未训练、未扩题、未改 JS 默认。
- **可比性**:取证版 before 与轮次29首批256题完整轨迹逐元素完全相同(最大差 0°),ok/col/brakes/err/t_done/first_hit 也完全相同;before/after 配置仅输出路径不同。任务 SHA256=`249bd93457825cda98c59e64d9a096d3473c69aeb3553de1dea6d9e56be71772` , checkpoint SHA256=`f7f686fd8ee92fb6948fbcc4ee954636065ad87bb54f661c4f8f575bc16c2ce1` , kin_fp=`2ebcbf17` 。
- **直接证据**( `docs/experiment_round30_certificates.json` ):旧版7次首撞的原认证端点/中点在 float32 与 float64 均为正间隙,实际执行段均有负间隙;`clamp(previous + recorded_command)` 与实际端点逐位一致。原证书与实际点主要差在 J5,首撞段差 0.340°–4.317°;其他轴仅有最高约 7.6e-6° 的累加舍入差,不足以解释毫米级穿入。全部有效认证步中,5298/34069 步偏差 >0.001°,最大 7.587°。
- **修复范围**: `execution_points` 按执行器相同顺序逐步夹紧,端点和中点都由实际路径计算;整段、部分前缀和近目标 DLS 共用。r3 的旧队列终点和特征前缀改为真实执行结果。fallback 保持实验默认关闭,但两分支统一为“认证一步后补零”,不再把只验过一步的动作重复执行;端点和中点都认证。候选排序和反馈增益未改,0.5 仍只是间隙截顶,正间隙判据没有放宽。
2026-10-20 21:25:47 +08:00
2026-10-20 21:55:15 +08:00
| 指标(同256题) | 修复前 | 修复后 |
|---|---|---|
| 按时到达 | 147/256 = 57.4% | 同147题,57.4% |
| 原端点/中点口径无碰撞到达 | 145/256 = 56.6% | 147/256 = 57.4%(下述加密审计否定其“全程无碰撞”含义) |
| time_ok_1p3 | 39.1% | 39.1% |
| 原端点/中点口径碰撞题 | 7/256 | 0/256 |
| 成功题末端误差中位数 | 0.1951 mm | 0.1890 mm |
| 成功题平均时间 | 2.2993 s | 2.3076 s |
| 2 s 误差比中位数 | 0.2100 | 0.2100 |
| 刹停/题 | 19.2383 | 19.2500 |
| 成功题指令行程比中位数 | 2.4450 | 2.4450 |
| 从实际轨迹重算成功题行程比 | 2.4251 | 2.4251 |
| 整批同步仿真墙钟 | 247.515 s | 248.834 s |
2026-10-20 21:25:47 +08:00
2026-10-20 21:55:15 +08:00
- **执行一致性复核**( `docs/experiment_round30_comparison.json` ):修复后34107个有效认证步,认证端点/中点与实际执行点均逐位一致,最大差 0°;有效时段没有未经认证的移动步。这里“认证”仍仅指离散端点/中点,不能推出连续安全。CPU B=1、commit=2 的预测函数单独测量:100次预热、1000次采样、单线程,P50 0.0388→0.0518 ms, P99 0.0691→0.0939 ms;不是完整规划延迟,不能证明50 Hz。
- **独立加密审计的正反对照**:预先固定12题 `0,21,84,128,145,164,175,180,197,215,224,255` ,其中包含全部7题旧首撞及5题其他任务;不按新版 `col` 过滤。逐题回放至自身时限或到达,含起点,每个插值段最大轴步距≤0.05°并包含中点,float64、每批64点。命令:`python -u -m ml.eval.diag_collision --trace ml/runs/round30_before.pt --dense_indices 0,21,84,128,145,164,175,180,197,215,224,255 --max_step_deg 0.05 --device cuda --out docs/experiment_round30_dense_before.json` , after 同理;串行运行。
- before: 56118点,**7/12题检出碰撞**, 14.870 s;证明探针确实能抓旧碰撞。
- after: 56566点,**仍有1/12题碰撞**, 15.057 s;其余11题采样点间隙为正。这是小样本有限采样,不是完整256题的连续认证。
- 剩余第180题,执行段1.08–1.10 s:上一点/中点/端点 float64 间隙为 **0.5 / 0.11723 / 0.06521 mm** ,都安全,但段内约76.6%处为 ** − 0.14927 mm**;该段0.01°再加密185点仍检出,见 `docs/experiment_round30_missed_segment.json` 。因此这次残余是端点/中点漏检,而非认证与执行错位;它比旧离散首次碰撞1.14 s还早。不得把内部计数0当成修好了;已知真实无碰撞到达至多146/256=57.0%,其余未加密任务仍未知。
- **回归与判据灵敏度**: `python -m unittest tests.test_eval_cl -v` 14项通过。覆盖整段/部分限位拒绝、只保留真实安全前缀、DLS被拒后保留候选、r3旧队列起点和特征前缀及逐点证书、fallback单步/中点拒绝。把预测函数在内存中替回旧算式,限位、DLS和r3测试重新失败。加密探针另有合成正对照:原端点/中点全安全且 `col=0` ,仍检出四分之一处薄障碍;安全负对照、截止后/到达后碰撞排除均通过。
- **新增硬约束证据**: before/after 两组256题实际轨迹都出现超速,最大 **1.660004× VMAX** (来源是动作限幅后叠加0.3×gain2.2反馈)。实际各轴最大速度约 `[99.600,99.600,149.400,149.400,199.200,298.800]°/s` ,并非只看原始指令推测。行程仍约参考2.425倍;速度、加速度和真实控制时延均未达部署验收。历史 `travel` 累积的是指令而非夹紧后位移,本轮已同时列出实际轨迹重算值,不悄悄换分母。
- **结论与下一步**:逐步限位一致性修复有效,未牺牲本批到达率;但加密审计仍检出段内碰撞,**不能部署、不能宣称零碰撞或50 Hz合格**。下一轮先验证更强的段内认证,再单独评估反馈后的速度/加速度约束与真实端到端调度;每次保持小样本单变量对照,继续保留失败证据。
2026-10-20 21:25:47 +08:00
2026-10-20 21:55:15 +08:00
## 轮次 29:安全层全拒后减弱目标反馈(exp: `exp/dagger-deploy`)
2026-10-20 21:25:47 +08:00
2026-10-20 21:55:15 +08:00
- **假设**:目标反馈将绕障候选推向障碍,连续全拒会反复停在同处;仅在上一计划被全拒时减小下一计划反馈,可能保留正常段收敛速度并减少重复刹停。
- **判据**:同任务、同 seed、同 K、同认证下到达和 time_ok 不下降,碰撞不增加;部署门槛仍是零碰撞及真实时延达标。所有实验不重训、不扩大数据。
- **固定配方**: `python -m ml.eval.eval_cl --n 256 --K 8 --commit 2 --fb 2.2 --partial 1 --replan empty --select endpoint --seed 0` ; dag2 checkpoint、几何雅可比。下表仅改列出的参数,默认 `fb_block_gain=1,dls_safety=0` 。512 题按两个 256 批、每批 seed=0,沿用轮次 28 顺序。
2026-10-20 21:38:40 +08:00
2026-10-20 21:55:15 +08:00
| 改动(n=256) | 到达 | time_ok_1p3 | 碰撞 | ratio2s | 刹停/题 |
|---|---|---|---|---|---|
| 原配置复跑 | 52.7% | 37.5% | 2.3% | 0.210 | 34.6 |
| `--dls_safety 1` | 52.7% | 37.5% | 2.0% | 0.210 | 34.6 |
| `--fb_clear 20 --fb_cmin 0.3` | 32.0% | 5.9% | 1.2% | 0.323 | 3.2 |
| `--sub_refresh 1` | 51.6% | 35.5% | 2.0% | 0.279 | 33.8 |
| `--select adapt` | 52.7% | 37.9% | 2.3% | 0.210 | 34.6 |
| `--fb_block_gain 0.3` | 56.2% | 38.7% | 3.1% | 0.178 | 17.2 |
| `--fb_block_gain 0.5` | **57.4%** | **39.1%** | 3.1% | 0.210 | 19.3 |
| `--fb_block_gain 0.7` | 55.5% | 38.3% | 2.3% | 0.189 | 25.0 |
| `--fb_block_gain 0.5 --dls_safety 1` | **57.4%** | **39.1%** | 2.7% | 0.210 | 19.2 |
2026-10-20 21:38:40 +08:00
2026-10-20 21:55:15 +08:00
- **单独减半反馈 n=512**:到达 55.1% / time_ok 36.1% / 碰撞 2.5% / ratio2s 0.251 / 刹停 19.5;相对轮次 28 同规模基线 52.1% / 35.2% / 2.0% / 0.285 / 35.7,到达 +3.0 pp、碰撞也 +0.5 pp,不满足“碰撞不增加”判据。
- **为何不采用其他变体**:所有近障碍状态都衰减反馈会明显拖慢到达;子目标重预测无收益;adapt 全拒后旧计划本来就失效,一致性分数全为 0,实质变成等分选首条而非“继续绕行”。
- **原配置失败分解(n=256)**:135 题按时到达,121 题失败(其中 20 题后来才到,101 题始终没到)。A/B/C/D/Dr 分别 128/74/32/13/9 题,B/C 失败题刹停中位数约 96/93 次;D 留在分母,不用删题提高成绩。
- **碰撞定位**:原配置共 6 题碰撞,只有 224 号首次碰撞紧跟 DLS 接管;另外 5 题首次碰撞早于接管或根本未接管。为 DLS 加端点/中点检查仅减少 1 题,不能解释剩余碰撞。候选认证的未夹紧累加点与执行的逐步夹紧点不同是待验证假设,尚不能断言根因。
- **计时**: n=256 减半反馈+DLS检查整批墙钟 243.6 s,单独减半 n=512 为 443.4 s;这些不是规划时延,不能证明 50 Hz。反馈条件分支未增加几何查询,但其实际延迟收益未测。
- **记录改进**:评估输出完整参数、checkpoint/任务 SHA256、批大小和随机种子规则;增加时限内无碰撞到达率;修正 n_ref、参考时间占比和条件指标的跨批汇总。可保存实际轨迹供不重新采样的回放,NaN 在 JSON 中写为 null,执行进度每 50 步输出。
- **回归检查**: `python -m unittest tests.test_eval_cl -v` 六项通过,覆盖跨批分母、空条件集、非有限数、首撞探针正对照、精修被拒后保留安全候选、只有全拒后才减弱反馈。精修对照在关闭检查时确实碰撞,打开后保留候选,证明门会执行;这是合成测试,不替代真实几何验收。
- **仍未修复的边界**: `fb_fallback=0` 保持关闭;非部分前缀分支仍有“只验一步却重复执行”问题,不能开启部署。速度限制在反馈叠加前而非叠加后,尚未验证速度/加速度符合硬约束。
- **减半反馈 + DLS 检查的 n=512 复核(完整输出 `docs/experiment_round29.json` ) **:到达 **282/512 = 55.1%** 、时限内无碰撞到达 **280/512 = 54.7%** 、time_ok **36.1%** 、碰撞 **9/512 = 1.8%** 、ratio2s **0.251** 、刹停 **19.23/题** 。到达题末端误差中位数 **0.196 mm** ;有参考且到达题的行程比中位数 **2.425** (远高于 1.10 要求)。整批墙钟 **488.4 s** ,非控制延迟。
- 完整命令:`python -u -m ml.eval.eval_cl --n 512 --commit 2 --fb 2.2 --partial 1 --replan empty --select endpoint --fb_block_gain 0.5 --dls_safety 1 --out docs/experiment_round29.json --dump ml/runs/round29_rows.json --trace ml/runs/round29_trace.pt` 。
- 与轮次 28 同规模端点基线相比,到达 +3.0 pp、time_ok +0.9 pp、碰撞少 1 题(10→9),不足以宣称稳定安全改善;n=256 碰撞仍由 6→7 题。
- **首撞回放(`docs/experiment_round29_collisions.json` ) **: `python -m ml.eval.diag_collision --trace ml/runs/round29_trace.pt --out docs/experiment_round29_collisions.json` 。9 题首次碰撞在 CPU float32/float64 均复现,均位于 **J5 限位** ;q0 与首次碰撞前一点均为正间隙,首撞采样点负间隙约 ** − 0.017 至 − 0.936 mm**。这排除了这 9 次碰撞由起点本就碰撞或 float32 单独翻号造成,但还需要记录原认证点才能证明夹紧的因果作用;0.01° 加密仅覆盖首撞段,不是整条轨迹安全审计。
- 双精度运动学/间隙另与已有 JS 2000 个样本对拍:`python -m ml.eval.check_parity` PASS,碰撞布尔差 0、间隙最大差 2.53e−13 mm。首撞回放仍共用碰撞模型,不替代真机或独立连续认证。
- **结论与下一步**:减少连续刹停确有小样本收益,但碰撞、行程和真实时延仍未过门槛;保留为实验选项,不更改查看器默认。下一轮记录原认证点与 J5 夹紧后实际点,修复后用同批同 seed A/B 和独立细采样复核,禁止靠关掉认证提速。
2026-10-20 21:38:40 +08:00
2026-10-20 21:55:15 +08:00
## 轮次 28:端点进度选择——时间效率大幅提升(exp: `exp/dagger-deploy`,新历史最佳)
2026-10-20 21:38:40 +08:00
2026-10-20 21:55:15 +08:00
- **假设**:一致性选择奖励"与上一条计划一致",但失败主因是超时(轮次 13:失败 57% 是超时)。改成直接按候选块末态离目标的距离选(`select='endpoint'` ),应提升时间效率与精度。
- **判据**: time_ok_1p3 显著上升、到达不降、碰撞 ≤3%。
- **配方**: dag2 + 解析 J, gain2.2, commit=2, replan=empty, safety_partial; n=256 → n=512。选择器用 `goal_err(fut[-1])` (只做一次 K 端点 FK,不额外推理)。
- **指标(n=256, commit=2) **:
2026-10-20 21:51:54 +08:00
2026-10-20 21:55:15 +08:00
| 选择器 | 到达 | time_ok_1p3 | 碰撞 | ratio2s | 刹停/题 |
|---|---|---|---|---|---|
| consist(轮次 27) | 52.0% | 29.7% | 1.6% | 0.329 | 35.3 |
| **endpoint** | **52.7%** | **37.5%** | 2.3% | **0.210** | 34.6 |
| mix( consist − 0.1·端点mm) | 50.0% | 30.5% | 2.3% | 0.300 | 35.1 |
2026-10-20 21:51:54 +08:00
2026-10-20 21:55:15 +08:00
- **n=512 复核(endpoint, commit=2) **: **到达 52.1% / time_ok 35.2% / 碰撞 2.0% / ratio2s 0.285 / 刹停 35.7**( consist n=512: 50.8% / 28.9% / 1.4% / 0.343 / 35.9)。
- **节奏曲线(endpoint, n=256) **: commit=1 → **59.4% / 42.6% / 3.9% / 0.133** ; commit=2 → 52.7% / 37.5% / 2.3% / 0.210; commit=3 → 47.7% / 27.0% / 1.2% / 0.245。
- **负结论**:
- `safety_try=1/2` (只认证前 1/2 条候选):41.4% / 44.9%(全 K 52.0%)——候选兜底对到达贡献 ~10 pp,不能省。
- K=4: 47.3%( K=8 52.0%)——少采样同样损失到达。
- DLS 兜底半步(全拒时朝目标走一步并认证):52.3%(基线 52.0%),碰撞 1.6→2.7%,无收益;重复多步版本碰撞 45.7%(第二步未认证),已回退为单步且默认关闭。
- 增益调度(远 2.8/近 2.2):47.3% / time_ok 32.8%,等同 gain2.8 常数;高增益在远处就造成过冲,按距离衰减无效。
- **浏览器同步**: `select='endpoint'` 进 Runner/bench( `--select endpoint` ),冷启动跳过 8 份前瞻(省 ~80 ms P99,冷启动价值评分被端点排序替代)。nc10 bench( --seg 0 --select endpoint):pos ok 4/5 reached、pose ok 2/4,刹车率 32.1%/25.5%( consist 48.1%/31.6%),planP50 31.9/36.5 ms、P99 63.5/67.5 ms。
- **同步 bench 耗时与队列耗尽估算(不是 50 Hz 调度实测)**:Runner 的 `starveTicks = max(0,ceil(planMs/20) − 规划时队列步数)` ,不含真实 tick 时间戳。
2026-10-20 21:51:54 +08:00
2026-10-20 21:55:15 +08:00
| 集合(endpoint, commit=2, --seg 0) | 到达 ok/reached | 刹车率 | planP50/P99 | 估算饥饿 tick/次规划 |
|---|---|---|---|---|
| near_column_pos (10) | 4/5 | 32.7% | 32.0/62.1 ms | 0.87 |
| near_column_pose (10) | 2/3 | 25.6% | 36.8/68.0 ms | 0.78 |
| route40 (20) | 12/13 | 40.4% | 44.3/68.1 ms | 1.26 |
2026-10-20 21:51:54 +08:00
2026-10-20 21:55:15 +08:00
- commit=2 对应 40 ms 队列,route 集 planP50 44 ms 已超过;估算提示可能饥饿,但该 bench 等规划完成才 tick,没有观测实际空转。
- commit=3 对应 60 ms,仍低于上述 P99,不能据此宣称连续 50 Hz。其 Python 同步结果:endpoint n=256 → 47.7% / 27.0% / 1.2% / 0.245; gain2.5 为 45.7% / 24.6%。
- **结论(经轮次 29 更正)**:端点选择 + 解析 J + gain2.2 + commit=2 + safety_partial,在 n=512 同步仿真为 **到达 52.1% / time_ok 35.2% / 碰撞 2.0% / ratio2s 0.285** 。历史 42.2% 使用 commit=1 与 FD,非单变量对照。commit=1 到达 59.4% 但碰撞 3.9%;无论 2.0% 还是 3.9%,开安全层均未通过零碰撞要求,实时性亦未通过。
- **下一步**:先查碰撞来源,保持严格认证和查看器默认;再测真实异步调度及认证成本,不因 Python 收益直接切换部署默认。
## 轮次 27:解析 J 后重扫增益 + 积分/缓存反馈(负结论)+ 浏览器安全层对齐(exp: `exp/dagger-deploy`)
- **目标**:解析雅可比改变了反馈噪声结构,重扫增益;同时修浏览器部署路径的安全层(轮次 25 遗留:bench 刹车 47%、到达 0)。
- **增益重扫(commit=2, empty, analytic, n=256) **:
| gain | 到达 | time_ok_1p3 | 碰撞 | ratio2s | 刹停/题 |
|---|---|---|---|---|---|
| 1.8 | 50.4% | 27.0% | 2.0% | 0.287 | 22.1 |
| **2.2** | **52.0%** | 29.7% | 1.6% | 0.329 | 35.3 |
| 2.5 | 49.6% | 34.4% | 1.2% | 0.334 | 47.9 |
| 2.8 | 47.7% | **34.4%** | 2.0% | 0.362 | 59.8 |
- **n=512 复核 gain 2.2( commit=2) **: **到达 50.8% / time_ok 28.9% / 碰撞 1.4% / ratio2s 0.343 / 刹停 35.9**。**新历史最佳(50 Hz 节奏)= gain 2.2 + commit=2**。
- **负结论**:
- 积分反馈(fb_ki=0.3, decay0.9,限幅0.5·STEP):到达 48.0%( gain2.2 单独 52.0%),−4.0 pp。慢变偏差用积分项补偿会过冲,不采用。
- 反馈隔次复用(fb_every=2,省 ~3.5 ms/次规划):到达 46.9%(−5.1 pp)。误差方向变化比预期快,缓存不成立。
- **浏览器部署修复(有效)**:三个与 Python 仿真不一致的 bug 修掉后(`webapp/js/ik-policy.js` ):
1. `tick` 不夹关节限位(Python `clamp_box` 每步夹)→ q 一旦越限,认证的 `inBox` 永远拒绝所有候选,原地刹停到超时(certWhy.box 2650 次);现执行与候选投影都夹 LIM。
2. 安全层整段拒绝 → 刹停;移植 `safety_partial` :整段不过时依次缩短前缀,执行到第一个不安全步。
3. 新增 `segCert` 开关(默认 true):连续区间认证(距离下界递归)~40 ms/次,是 50 Hz 预算的主要超支项;关闭后改为离散判定「每步端点+中点 collideFree」(与 Python 安全层同口径),默认仍走严格认证,bench 用 `--seg 0` 测部署口径。
- JS bench( nc10, fb2.2, commit2; `node tests/policy_bench.cjs ... --seg 0` ):
| 集合 | 修复前 ok/reached | 修复后 ok/reached | 刹车率 | safety P50 | plan P50 / P99 |
|---|---|---|---|---|---|
| near_column_pos | 0/—(轮次 25) | **5/7** | 79.5→**48.1%** | 41.6→**19.8 ms** | 56.1→**33.5 / 61.1 ms** |
| near_column_pose | 0/— | **3/3** | 80.4→**31.6%** | 43.4→**22.8 ms** | 57.3→**37.6 / 66.3 ms** |
- **结论**:实时配置定为 `dag2 + 解析 J + gain2.2 + commit2 + safety_partial + replan=empty` : n=512 到达 **50.8%** 、碰撞 **1.4%** 。浏览器端从「0 到达 + 47% 刹车」恢复到 nc 集可达,plan P50 33.5/37.6 ms; P99 仍 61– 66 ms, commit=2 的 40 ms 队列会偶发饥饿,需继续压 P99(K/安全候选数/JS 特征)。
- **下一步**:① Python 测 `safety_try=1` (只认证首选候选)对准确率的影响,若无损则 JS 同步(省多次 collideFree);② K=4/6 的准确率-时延权衡;③ JS `gapMatrix` 同步只算 8 组特征;④ commit=2 异步部署的饥饿率实测。
## 轮次 26:解析雅可比 DLS——去掉差分噪声,准确率大幅提升(exp: `exp/dagger-deploy`,新历史最佳)
- **背景**:DLS 目标反馈此前用 6 次批量有限差分(ε=1e-3°)求雅可比。float32 下旋转项信噪比只有 ~1%,位置项 ~3.6%(与 autograd 对拍,见下),相当于每次规划往反馈方向注入 2–4% 的随机扰动。
- **假设**:改用几何雅可比(一次 FK)可同时去噪 + 提速;闭环准确率应不降、延迟应下降。
- **判据**:① 雅可比与 autograd 一致(rel < 1e-4);② n=256 commit=3 到达 ≥ 36.3%(轮次 25 基线,不劣化);③ DLS 单次延迟下降。
- **配方**: `Kin.jac` 几何雅可比(Jv_k = a_k× (p− o_k), Jw_k = a_k,度单位);`dls_steps(analytic=True)` 默认;其余同轮次 25( dag2、K=8、gain1.8、safety_partial、replan=empty)。
- **数值对拍**( `ml/eval/check_dls.py` ):
- 位置项:解析 J 与 autograd 逐项一致(rel 0.00000);有限差分 J 自身 rel 误差 **3.58%** 。
- 姿态项:解析 J 与差分 DLS 输出 max 0.20°/rel 5%(差的部分是 rotvec 的二阶项 Jr(e),非噪声)。
- DLS 输出:pos-only max 0.12°,pos+rot max 0.20°。
- **延迟**( B=1, 3090):n=1 **9.3→7.1 ms** , n=3 **27.7→19.5 ms** (每次 DLS 少 6 次批量 FK)。
- **闭环(replan=empty, analytic, n=256) **:
| commit | 到达 | time_ok_1p3 | 碰撞 | ratio2s | 刹停/题 |
|---|---|---|---|---|---|
| 3(FD 对照,完全复现轮次 25) | 36.3% | 16.4% | 1.6% | 0.277 | 14.3 |
| 3(解析 J) | 46.5% | 16.4% | 1.6% | 0.337 | 13.5 |
| 2(解析 J) | **50.4%** | 27.0% | 2.0% | 0.287 | 22.1 |
| 1(解析 J) | **57.4%** | **31.6%** | 3.1% | 0.251 | 39.1 |
- **n=512 复核(commit=2,解析 J) **:到达 **49.2%** / time_ok **26.2%** / 碰撞 **2.3%** / ratio2s 0.351 / 刹停 21.0( n=256 的 50.4% 在噪声内)。
- **结论**:
- 解析雅可比**既快又准**: commit=3 到达 36.3→46.5%( +10.2 pp),碰撞不变;commit=2 达 **49.2%** (历史最佳 42.2% 是 commit=1 + FD,现在 commit=2 就超过),碰撞 2.3%。
- 机理:DLS 差分雅可比在 float32 下的 2–4% 噪声被慢变误差闭环放大(轮次 4/闭环根因结论:σ>0.02×STEP 即崩);解析 J 去掉噪声后失败题里"能到 50 mm 却到不了"的那批能收敛了(err_fail 中位数 51→217 mm:失败集两极分化,成功集变大)。
- ratio2s 在 commit=3 变差(0.277→0.337)但到达更多:慢收敛题现在"最终到得了",不是"更快"。
- **新历史最佳(50 Hz 目标节奏,commit=2) = 49.2% / 碰撞 2.3% / ratio2s 0.351 / time_ok 26.2%**;非实时上限(commit=1) = 57.4%( n=256,待 n=512 复核)。
- **下一步**:① n=512 复核 commit=1;② 积分反馈(fb_ki,针对慢变偏差)在 commit=2 上叠加;③ 浏览器 JS 端同步解析 J;④ commit=2 的 40 ms 周期实测规划 P99( Python/JS)。
## 轮次 25:实时节奏下的准确率探索 + 推理提速(exp: `exp/dagger-deploy`)
- **目标**:在 50 Hz 可行的节奏(commit=3,60 ms 周期)下提升准确率。
- **效率优化(有效)**:
- `Kin.gm_groups` :特征只算 8 组间隙(数值 diff 0),features 10.4→**7.1 ms**;
- **onnxruntime CPU 推理 3.9 ms**( PyTorch 11.1 ms,部署端本来就是 ONNX);
- 单次规划 ≈ 7.1( features) +3.9(推理)+11( DLS) +8(安全)+2 ≈ **32 ms p50 / ~45 ms p99** ;
- 异步部署下 tick(执行步 + 碰撞检查)2–3 ms → **50 Hz 控制可行** ; commit=3( 60 ms 队列)可覆盖规划 p99。
- **准确率尝试(n=256, commit=3, gain1.8, safety_partial) **:
| 方法 | 到达 | time_ok | 碰撞 | ratio2s | 刹停 |
|---|---|---|---|---|---|
| dag2 + consist(基线) | **36.3%** | 16.4% | 1.6% | 0.277 | 14.3 |
| dag2 + 候选平均(select=average) | 29.7% | 20.3% | 0.4% | 0.432 | 55.9 |
| 冻结编码器模型(dag3_fe) | 34.4% | 14.8% | 2.0% | 0.332 | 15.8 |
| dag2 + commit=4 | 28.9% | 8.2% | 3.5% | 0.339 | 10.5 |
- **结论**:候选平均、冻结编码器、更稀疏规划**均未超过 36.3%**。**50 Hz 节奏下的最佳配置 = dag2 + commit=3 + consist + gain1.8 + safety_partial:到达 36.3% / 碰撞 1.6% / ratio2s 0.277**(相对非实时的 42.2% 差 5.9 pp)。
- **下一步**:若要把实时准确率再拉高,需要把单次规划再压到 ~22 ms 以支持 commit=2( 40 ms 周期,预计 ~39%);或提升模型本身精度(训练侧)。
## 轮次 24:实时性优化与新方法(exp: `exp/dagger-deploy`)
- **目标**:准确率更高 + 效率满足 50 Hz(20 ms 控制步)。
- **① 混合节奏(规划每 3 步 + 执行时每步反馈)——负结论**: plan fb1.8 + exec fb1.8 → 36.3%(与纯规划反馈的 commit_n=3 完全相同);plan fb0 + exec fb1.8 → 仅 1.6%。执行时反馈不带来额外收益(规划时的反馈已是主要贡献),此捷径不成立。
- **② 特征几何优化(有效)**:特征只用 8 组间隙(GP),但原实现算全部 49 组(67256 簇对)。新增 `Kin.gm_groups(q, GP, cap)` :按 7 连杆组对过滤簇对(簇索引 → `cl_g` → 组对 min/max),只算 8 组。
- 数值验证:与 `gaps()['gm'][:, a*7+b]` 逐项一致(diff 0)。
- 延迟:gm 计算 10.4→**7.1 ms**( p50),单次规划省约 3 ms。
- **③ 浏览器部署**:导出 `webapp/models/traj_policy.onnx` ( dag2 best, 19.8 MB,对拍误差 3.1e-6, act_scale 1.0);`ik-policy.js` 加全程目标反馈(`fbGain` ) + `commit` 可配;`ik-policy-glue.js` 支持 `?fb=&commit=` (默认 fb=1.8、commit=3)。
- JS bench( Node, 10 题,fb1.8+commit1):到达 0、**刹车率 47.3%**(每 2 次规划刹停一次)、planP50 43.8 / P99 70.5 ms。JS 安全层(5 mm 护栏 + 距离认证)比 Python(0.5 mm gap)保守,反馈+每步规划被大量拒绝。
- **④ 实时口径的关键认识**:部署形态是**异步规划**(tick 20 ms 只执行队列;`plan()` 后台跑),所以 50 Hz 的约束是「tick < 20 ms + 规划在队列耗尽前完成」,不是「单次规划 < 20 ms」。
- JS 的 tick 只做队列执行 + 投影/碰撞检查(~1.5–3 ms)→ 50 Hz 可行;
- 规划 P99 70 ms → 需要 commit ≥ 4( 80 ms 队列)才不饥饿;commit=3(60 ms)会偶发饥饿。
- 准确率与规划频率的 trade-off: commit1 42.2%(不可 50Hz)、commit3 36.3%、commit6 14.8%。
- **下一步**:① 在 commit=3/4 的实时节奏下找准确率提升(候选平均、dag3_fe 冻结编码器、更高 gain);② 把 gm_groups 同步到 JS( gapMatrix 只算 8 组);③ 降低 JS 安全层拒绝率(margin/认证预算调参)。
## 轮次 23:实时性口径评估(exp: `exp/dagger-deploy`)
- **背景**:870 ms/题是仿真里整条轨迹的总时长(150–300 次规划累加),不是控制延迟。实时口径按 §9.2:每次「推理 + 安全认证」P99 < 20 ms( 50 Hz, DT=0.02 s)。
- **假设**:单次规划延迟可以压到 20 ms 以内。
- **判据**: B=1 单题、单次规划(features + sample_k K=8 + 目标反馈 + 安全层)P99 < 20 ms。
- **优化**:① DLS 目标反馈的 6 次串行有限差分改为一次批量 FK(数值差 ≤0.013°,DLS 25→10–17 ms);② 单题安全层按候选早停(首个全安全候选即停,16 点→2–4 点)。
- **指标(桌面 RTX 3090, B=1, Python; GPU 时钟抖动使 p50 在 40–65 ms 间波动)**:单次规划 **p50 40– 65 ms / p99 70– 80 ms** ;分解:features 10– 17 ms、推理 8– 14 ms、DLS 反馈 10– 17 ms、安全层 10– 17 ms。
- **实时频率扫描(n=256,部署口径,gain1.8 + safety + partial) **:
| 规划节奏 | 控制周期 | 到达 | time_ok_1p3 | 碰撞 | 刹停/题 |
|---|---|---|---|---|---|
| 每步(commit_n=1) | 20 ms | **42.2%( n=512) ** | 29.1% | 2.9% | 37.4 |
| 每 3 步(commit_n=3) | 60 ms | 36.3% | 16.4% | 1.6% | 14.3 |
| 每 6 步(commit_n=6) | 120 ms | 14.8% | 3.9% | 2.0% | 6.1 |
| 每 10 步(commit_n=10) | 200 ms | 2.0% | — | 1.2% | 3.7 |
- **结论**:**当前方案不满足 50 Hz 实时**(单次 40–80 ms,超预算 2–4 倍);42.2% 的成绩依赖每步规划(20 ms 节奏)。实时可行节奏下:每 3 步 → 36.3%(p50 有余量、p99 需继续优化),每 6 步 → 14.8%。**实时性是当前方案的硬约束,不是仿真耗时问题**。
- **下一步(需确认)**:① 浏览器 ONNX 路径实测(推理 P99 历史 10–12 ms;特征/安全层在 JS 端需 `tests/policy_bench.cjs` 实测);② 特征缓存 + 安全层粗筛,目标单次 P99 < 20 ms;③ 或接受「每 3 步规划」的 60 ms 周期(36.3%)。
## 轮次 22:冻结编码器微调(exp: `exp/dagger-deploy`,负结论)
- **假设**:微调导致的分布退化来自表征漂移;冻结编码器(enc + enc_norm)、只调解码器/头,可保留开环精度同时吸收 DAgger-3 的部署分布样本。
- **判据**:部署口径 success > 43.8%( dag2)且 ol_fk 不退化(≤16 mm)。
- **配方**: `train.py --freeze-enc` (优化器只含 requires_grad 参数),数据 = 主数据 + DAgger-3 样本,lr 3e-4、5000 步,从 dag2 best 初始化;n=256 部署口径。
- **对照**: dag2 + gain1.8( 43.8% / 28.9% / 1.6% / 0.216 / 40.0 / 956 ms)。
- **指标**:
| 模型 | gain | 到达 | time_ok_1p3 | 碰撞 | ratio2s | 刹停/题 | 墙钟/题 | ol_fk |
|---|---|---|---|---|---|---|---|---|
| 冻结编码器 | 1.5 | 39.8% | 22.3% | 1.2% | 0.293 | 25.4 | 936 ms | 15.8 mm |
| 冻结编码器 | 1.8 | 41.8% | 26.2% | 2.3% | 0.274 | 41.4 | 940 ms | 15.8 mm |
| dag2(基线) | 1.8 | **43.8%** | **28.9%** | 1.6% | **0.216** | 40.0 | 956 ms | 15.7 mm |
- **结论**:冻结编码器**确实减缓了开环退化**(ol_fk 15.8 vs 全微调 19.5),但部署到达仍比 dag2 低 2.0 pp——**无提升**。至此训练侧四种方法(APG、反馈蒸馏、DAgger-3、冻结编码器)均未超过 dag2 基线(43.8%),训练侧在当前数据/预算下已到平台。
- **下一步(超出小规模范围,需确认)**:更大规模训练(24000 步从头 + 8000× 2 轮 DAgger)或改特征/架构(目标条件化、状态扰动训练需重算特征)。
## 轮次 21:DAgger-3(最终部署配置采集)(exp: `exp/dagger-deploy`,负结论)
- **假设**:用最终部署配置(每步规划 + 部分安全前缀 + 反馈 gain1.8 + 安全层)采集,训练分布与部署完全一致,可继续提升。
- **判据**:部署口径 success > 43.8%( dag2 基线,n=256)。
- **配方**: `collect --fb_gain 1.8 --safety 1 --replan empty --commit_n 1 --safety_partial 1` (500 题、73 起点)→ 老师重规划 → 打包 → 从 dag2 best 微调 15000 步(lr 3e-4,配置 base_dag3)。
- **对照**: dag2 + gain1.8( n=256: 43.8% / 28.9% / 1.6% / 0.216 / 40.0 / 956 ms)。
- **指标(n=256,部署口径)**:
| 模型 | gain | 到达 | time_ok_1p3 | 碰撞 | ratio2s | 刹停/题 | 墙钟/题 |
|---|---|---|---|---|---|---|---|
| dag3 | 1.5 | 39.8% | 16.0% | 1.2% | 0.360 | 14.7 | 912 ms |
| dag3 | 1.8 | 39.5% | 21.1% | 1.2% | 0.320 | 24.5 | 935 ms |
| dag2(基线) | 1.8 | **43.8%** | **28.9%** | 1.6% | **0.216** | 40.0 | 956 ms |
- **结论**: DAgger-3 到达 ** -4.3 pp**( 39.5 vs 43.8),time_ok -7.8 pp;碰撞/刹停略好但主指标下降。开环进一步退化(ol_fk 19.5 mm vs dag2 15.7)。**负结论**:继续微调(15000 步 lr 3e-4)会退化主分布,训练侧收益递减。
- **下一步**:冻结编码器、只微调解码器(假设:微调退化来自表征漂移),用同一份数据与预算验证。
## 轮次 20:反馈蒸馏(exp: `exp/dagger-deploy`,负结论)
- **假设**:用最终部署配置收集 (特征, 复合动作 = 模型输出 + 目标反馈) 样本,微调后模型可内化反馈(部署时降低/去掉反馈仍能到目标)。
- **判据**:部署口径下 `fb_gain=0~0.9` 时 success 接近/超过基线(43.8%, n=256),且 time_ok 不降。
- **配方**: `rollout` 加 collect 钩子(与部署一致:safety、replan='empty'、safety_partial=1、commit_n=1、fb_gain=1.8)收集 500 题 → **17.7 万样本** ; `train.py --config distill.json` ( lr 1e-4、3000 步、w_value=0、w_sub=0、w_fk=0.1、w_smooth=0.01) + 主数据 BC 锚定,从 dag2 best 微调。
- **对照**: dag2 + gain 1.8( n=256: 43.8% / 28.9% / 1.6% / 0.216 / 40.0 / 956 ms)。
- **指标(n=256,部署口径)**:
| 模型 | gain | 到达 | time_ok_1p3 | 碰撞 | ratio2s | 刹停/题 | 墙钟/题 |
|---|---|---|---|---|---|---|---|
| distill | 0.0 | **0.8%** | — | 0.0% | 0.708 | 2.1 | 762 ms |
| distill | 0.9 | 36.7% | 10.5% | 1.2% | 0.421 | 12.4 | 916 ms |
| distill | 1.8 | 43.4% | 27.7% | 2.0% | 0.228 | 47.4 | 925 ms |
| dag2(基线) | 1.8 | 43.8% | 28.9% | 1.6% | 0.216 | 40.0 | 956 ms |
- **结论**: **反馈未内化**——`gain=0` 时到达仅 0.8%(与基线纯策略一样);`gain=1.8` 时与基线持平(43.4 vs 43.8,差约 1 题),碰撞/刹停略差。蒸馏样本占比仅 8.5%、标签仍以主数据增量为主,模型没有学会"看目标修正"。此配方不成立。
- **下一步**:与最终部署配置一致的 DAgger 第 3 轮(采集时已用 safety+fb 1.2,但仍是 3 步提交/全窗口;现在部署是每步规划+部分前缀)。
## 轮次 19:APG 闭环策略梯度试跑(exp: `exp/dagger-deploy`,管线修复但暂不采用)
- **假设**:用闭环目标/碰撞损失直接微调策略(把"朝目标走"内化),减少对执行层反馈的依赖。
- **判据**:纯策略闭环 success 上升、碰撞铰链下降;部署口径(+反馈/安全层)不降。
- **配方**: `ml.apg.apg_finetune --init base_dag2_dag1/best.pt --steps 2` (先冒烟;原计划 500 步)。
- **修复的两个既有 bug**(APG 此前从未实测):
1. `kin_torch._cat_gaps` 的 `p['b'] += s` 是 in-place,而 `b` 被 autograd 索引反向图引用 → backward 报 version 错;改为 `p['b'] = p['b'] + s` 。
2. APG 段边界 `queue.detach()` 让下一段执行的动作无梯度;改为只 detach 状态并重置队列(下一 plan 走 r=0 重新提交)。
- **指标(2 步冒烟)**: EVAL0(纯策略)success 0 / 碰撞 31.8%;第 0 步 col(碰撞铰链均值)**409508**、gnorm 473119(被裁剪)、tgt 206.6、smooth 645; EVAL@2 success 0 / 碰撞 26.0%。
- **结论**:管线已能跑,但**损失尺度失控**(碰撞铰链均值 40 万,远大于 margin 3mm 的合理量级);且 APG 展开是纯策略口径(无反馈/安全层/每步规划),与当前部署形态不一致。**暂不采用**,转「反馈蒸馏」。
- **下一步**:反馈蒸馏——用最终部署配置收集 (特征, 复合动作=模型输出+目标反馈) 样本,微调模型把反馈内化。
## 轮次 18: n=512 复核 gain 1.8(收尾)
- **假设**:轮次 17 的 43.8%( n=256)需更大样本确认。
- **判据**: reach 与 n=256 差异 <5 pp、碰撞 ≤3%。
- **配方**: dag2 best, replan='empty', commit_n=1, safety_partial=1, gain 1.8; n=512。
- **对照**:轮次 17( n=256: 43.8% / 28.9% / 1.6% / 0.216 / 40.0 / 956 ms);轮次 16( gain 1.5 n=512: 40.8% / 25.0% / 2.1% / 0.309 / 25.3 / 852 ms)。
- **指标**:到达 **42.2%** 、time_ok_1p3 **29.1%** 、碰撞 **2.9%** 、ratio2s **0.270** 、刹停 37.4、墙钟 **870 ms/题** 。
- **结论**: gain 1.8 在 n=512 稳定(42.2%),到达/时间效率优于 gain 1.5( +1.4 pp / +4.1 pp),但碰撞 2.1→2.9%(贴近 3% 线)、刹停 25.3→37.4。**历史最佳(到达优先,n=512) = gain 1.8;碰撞优先 = gain 1.5**。
- **下一步**:本轮探索收尾(监控页已回写);进入大规模训练需用户确认 §9.2 锚点。
## 轮次 17:每步规划下的更大增益(exp: `exp/dagger-deploy`)
- **假设**:每步规划下更大的反馈增益可进一步提升到达与时间效率。
- **判据**:time_ok 上升、到达不降、碰撞 ≤3%。
- **配方**: dag2 best, replan='empty', commit_n=1, safety_partial=1, gain ∈ {1.8, 2.2, 3.0}, n=256。
- **对照**:轮次 15( gain 1.5: 41.8% / 21.5% / 2.3% / 0.259 / 26.9 / 967 ms)。
- **指标**:
| gain | 到达 | time_ok_1p3 | 碰撞 | ratio2s | 刹停/题 | 墙钟/题 |
|---|---|---|---|---|---|---|
| **1.8** | **43.8%** | 28.9% | 1.6% | 0.216 | 40.0 | 956 ms |
| 2.2 | 41.0% | **32.4%** | 2.0% | 0.174 | 64.4 | 976 ms |
| 3.0 | 36.3% | 32.8% | 0.8% | **0.153** | **123.2** | 994 ms |
- **结论**: gain 1.8 到达最高(43.8%);2.2/3.0 精度与时间效率更好但到达下降、刹停暴涨(3.0 达 123 次/题,过冲)。**历史最佳按到达优先(碰撞 ≤3%):gain 1.8 = 到达 43.8% / 碰撞 1.6% / ratio2s 0.216 / time_ok 28.9% / 956 ms( n=256) **。保守/时间优先可选 2.2。
- **下一步**: n=512 复核 gain 1.8;随后收尾。
## 轮次 16:n=512 复核每步规划(稳定结论)
- **假设**:轮次 15 的 41.8%( n=256)需更大样本确认。
- **判据**: reach 与 n=256 差异 <5 pp、碰撞 ≤3%。
- **配方**: dag2 best, replan='empty', gain 1.5, safety=True, safety_partial=1, commit_n=1; n=512。
- **对照**:轮次 15( n=256: 41.8% / 21.5% / 2.3% / 0.259 / 967 ms)。
- **指标**:到达 **40.8%** 、time_ok_1p3 **25.0%** 、碰撞 **2.1%** 、ratio2s **0.309** 、刹停 25.3、墙钟 **852 ms/题** 。
- **结论**:稳定。**历史最佳(n=512,部署口径)= 40.8% 到达 / 2.1% 碰撞 / ratio2s 0.309 / time_ok 25.0% / 852 ms/题**;从基线 0% 到达提升 40.8 pp。相对 §9.2(98%、碰撞 0、用时≤老师×1.3)仍有大差距,但机理已成立。
- **下一步**:每步规划下重扫增益(1.8/2.2/3.0),看时间效率是否继续提升;随后收尾。
## 轮次 15:每步规划(commit_n=1)(exp: `exp/dagger-deploy`,新历史最佳)
- **假设**:部分前缀的填充零步仍在消耗时间;每次只提交 1 步、每步重新规划可消除填充、提升时间效率。
- **判据**: time_ok_1p3 显著上升、到达不降、碰撞 ≤3%。
- **配方**: dag2 best, replan='empty', gain 1.5, safety=True, `safety_partial=1, commit_n=1` ; n=256。
- **对照**: commit_n=3 部分前缀(轮次 14: 38.3% / 13.7% / 1.6% / 0.308 / 8.6 / 770 ms)。
- **指标**:
| commit_n | 到达 | time_ok_1p3 | 碰撞 | ratio2s | 刹停/题 | 墙钟/题 |
|---|---|---|---|---|---|---|
| 3 | 38.3% | 13.7% | 1.6% | 0.308 | 8.6 | 770 ms |
| **1** | **41.8%** | **21.5%** | 2.3% | **0.259** | 26.9 | 967 ms |
- **结论**:每步规划把到达推到 **41.8%** 、时间效率 **13.7→21.5%** 、精度 ratio2s **0.259** ;代价:碰撞 1.6→2.3%(仍 <3%)、刹停计数回升(每步都判断)、时延 +26%。**新历史最佳(n=256,部署口径):41.8% / 2.3% / 0.259 / 21.5% / 967 ms**。
- **注**: commit_n=1 的推理频率是 3 倍,真机需核对 §9.2 的 P99 <20 ms 预算(当前桌面 12.58 ms/次)。
- **下一步**:n=512 复核;若稳定则收尾(更新最佳、监控页、分支清理)。
## 轮次 14:部分安全前缀(exp: `exp/dagger-deploy`,刹停大降)
- **假设**:安全层现在要求 3 步全安全才执行,候选只要第 2–3 步有碰撞就全拒刹停;改为「执行到第一个不安全步为止」可减少刹停。
- **判据**:刹停显著下降、到达不降、碰撞 ≤3%。
- **配方**: dag2 best, replan='empty', gain 1.5, safety=True, `safety_partial=1` ; n=256。
- **对照**:全窗口(轮次 11/13: 36.7% / 1.6% / 0.323 / 27.4 / 775 ms)。
- **指标**:
| 安全层 | 到达 | time_ok_1p3 | 碰撞 | ratio2s | 刹停/题 | 墙钟/题 |
|---|---|---|---|---|---|---|
| 3 步全安全 | 36.7% | 13.3% | 1.6% | 0.323 | 27.4 | 775 ms |
| **部分安全前缀** | **38.3%** | 13.7% | 1.6% | **0.308** | **8.6** | 770 ms |
- **结论**:刹停 **27.4→8.6( -69%) ** 、到达 +1.6 pp、碰撞不变——**部分安全前缀有效**(新最佳:38.3% / 1.6% / 0.308 / 8.6 / 770 ms)。但 `time_ok_1p3` 仍 13.7%:说明超时主因不是刹停,而是**执行粒度**——部分前缀的填充零步仍在消耗时间。
- **下一步**: commit_n=1(每次只提交 1 步、每步规划,无填充步),验证时间效率。
## 轮次 13:选择器 / K / 失败模式(exp: `exp/dagger-deploy`)
- **假设**:反馈混合下,候选选择器与候选数 K 会影响到达/时延;失败模式可指导下一步。
- **判据**: reach > 36.7% 或时延显著下降;同时报告 time_ok_1p3。
- **配方**: dag2 best, replan='empty', gain 1.5, safety=True, n=256。
- **对照**:轮次 11/12( consist K=8: 36.7%)。
- **指标**:
| 配置 | 到达 | 碰撞 | ratio2s | 刹停/题 | 墙钟/题 |
|---|---|---|---|---|---|
| consist K=8 | 36.7% | 1.6% | 0.323 | 27.4 | 764 ms |
| value K=8 | 35.9% | 1.6% | 0.334 | 29.4 | 1063 ms |
| first K=8 | 36.3% | 1.2% | 0.338 | 28.1 | 780 ms |
| K=6 | 35.9% | 1.6% | 0.353 | 28.6 | 627 ms |
| K=4 | 31.6% | 1.2% | 0.396 | 32.6 | 482 ms |
- **失败模式(n=256, consist K=8) **:失败 149 题中 **碰撞仅 3 题(1.2%)、超时无碰撞 146 题(57.0%) ** ;失败题终点误差 p50 140 mm;`time_ok_1p3` 仅 **13.3%** ;成功题 t_done p50 2.74 s(时限 p50 3.4 s);刹停 27.4 次/题。
- **结论**:选择器无差别(consist 略优);K=8 到达最佳,K=6 省 18% 时延(到达 -0.8 pp)。**当前真正的瓶颈是时间效率(频繁刹停→超时),不是碰撞**。§9.2 的「用时 ≤ 老师×1.3」当前只有 13.3%。
- **下一步**:每步重规划下,安全层只需认证第 1 步(现在验 3 步,过度保守→全拒→刹停);改 `safety_steps=1` 验证能否在保持低碰撞的同时大幅减少刹停。
## 轮次 12:n=512 复核(稳定结论)
- **假设**: n=256 的 34.8– 36.7% 需在更大样本上确认。
- **判据**: reach 与 n=256 差异 <5 pp、碰撞 ≤3%。
- **配方**: dag2 best, `replan='empty'` , safety=True, gain ∈ {1.2, 1.5}, n=512。
- **对照**:轮次 11( n=256: 34.8 / 36.7%)。
- **指标**:
| gain | n=256 到达 | **n=512 到达** | 碰撞 | ratio2s | 刹停/题 | 墙钟/题 |
|---|---|---|---|---|---|---|
| 1.2 | 34.8% | **32.6%** | 1.0% | 0.435 | 18.6 | 722 ms |
| 1.5 | 36.7% | **33.4%** | 1.0% | 0.399 | 28.1 | 738 ms |
- **结论**: n=512 稳定在 **33% 左右** (n=256 略乐观);**历史最佳(n=512,部署口径)= gain 1.5 + replan=empty:到达 33.4% / 碰撞 1.0% / ratio2s 0.399 / 刹停 28.1 / 738 ms**。保守版 gain 1.2: 32.6% / 1.0% / 0.435 / 18.6 / 722 ms(刹停少 1/3)。
- **监控页回写**: `ml/monitor.py` 新增 `/api/explore` (读 docs/探索日志.md),`ml/monitor.html` 新增「闭环探索日志」卡片;Edge headless 截图确认渲染正常(http://127.0.0.1:8100)。
- **下一步**:候选选择器(consist/value/first)与 K=4 在反馈+每步重规划下是否影响到达/刹停。
## 轮次 11: n=256 复核(发现前 128 题偏难)
- **假设**:轮次 10 的 n=128 差异含样本偏差,需扩大样本复核。
- **判据**:reach 排名与轮次 10 一致、碰撞 ≤3%;若差异大则以 n=256 为准。
- **配方**: dag2 best, `replan='empty'` , safety=True, gain ∈ {1.0, 1.2, 1.5}, n=256。
- **对照**:轮次 10( n=128: 22.7/26.6/28.9%)。
- **指标**:
| gain | n=128 到达 | **n=256 到达** | 碰撞 | ratio2s | 刹停/题 | 墙钟/题 |
|---|---|---|---|---|---|---|
| 1.0 | 22.7% | **31.6%** | 0.8% | 0.428 | 15.0 | 748 ms |
| 1.2 | 26.6% | **34.8%** | 1.2% | 0.392 | 18.6 | 752 ms |
| 1.5 | 28.9% | **36.7%** | 1.6% | 0.323 | 27.4 | 760 ms |
- **结论**:前 128 题显著偏难;n=256 上 **gain 1.5 + replan=empty = 到达 36.7% / 碰撞 1.6% / ratio2s 0.323 / 刹停 27.4 / 760 ms** (新历史最佳)。gain 1.0 更保守(31.6% / 碰撞 0.8% / 刹停 15.0)。排名与 n=128 一致(1.5 > 1.2 > 1.0)。
- **下一步**: n=512 复核 gain 1.2/1.5;随后评估 DAgger 第 3 轮(部署分布采集)与监控页回写。
## 轮次 10: replan=empty( r=0)下的增益重扫(exp: `exp/dagger-deploy`,新历史最佳)
- **假设**:r=0 规划下,最优增益会上移。
- **判据**: reach > 26.6%(轮次 9)且碰撞 ≤1.6%;同时比较刹停/时延。
- **配方**: dag2 best, `replan='empty'` , gain ∈ {0.8, 1.0, 1.2, 1.5, 2.0}, safety=True, n=128。
- **对照**:轮次 9( gain 1.2: 26.6% / 0.8% / 0.453 / 20.6 / 845 ms)。
- **指标**:
| gain | 到达 | 碰撞 | ratio2s | 刹停/题 | 墙钟/题 |
|---|---|---|---|---|---|
| 0.8 | 21.9% | 2.3% | 0.505 | 11.3 | 801 ms |
| 1.0 | 22.7% | **0.0%** | 0.489 | 15.2 | 810 ms |
| 1.2 | 26.6% | 0.8% | 0.453 | 20.6 | 845 ms |
| **1.5** | **28.9%** | 0.8% | **0.411** | 28.5 | 844 ms |
| 2.0 | 28.9% | 0.8% | 0.414 | 44.9 | 914 ms |
- **结论**:到达在 gain 1.5 封顶(28.9%),2.0 无收益且刹停翻倍(44.9)。**按到达优先/碰撞 ≤3%:历史最佳 = gain 1.5 + replan=empty( 28.9% / 0.8% / 0.411 / 28.5 / 844 ms) **;按碰撞优先:gain 1.0( 22.7% / 0.0% / 0.489 / 15.2 / 810 ms)。n=128 的差异约 3– 4 题,需 n=256 复核。
- **下一步**: n=256 复核 gain 1.0 / 1.2 / 1.5;若平台稳定,再决定是否 DAgger 第 3 轮(采集用新部署配置)。
## 轮次 9: replan=empty(队列空时规划、r=0) / K=16 安全候选(exp: `exp/dagger-deploy`,新历史最佳)
- **假设**: replan='empty'(每次队列空时规划、无前缀 r=0)比默认 r=3 更适合反馈混合。K=16 给安全层更多候选、减少全拒。
(更正:replan='empty' 仍是每 3 步规划一次——队列空才规划,commit 3 步;收益来自 r=0 无前缀,不是规划频率。)
- **判据**:部署口径 reach > 23.4% 且碰撞 ≤1.6%、刹停/时延不恶化。
- **配方**: dag2 best; `replan='empty'` (每次 r=0 规划);`K=16` 。n=128, safety=True。
- **对照**:轮次 8( dag2+gain1.2: 22.7% / 1.6% / 0.491 / 25.9 / 922 ms)。
- **指标**:
| 配置 | 到达 | 碰撞 | ratio2s | 刹停/题 | 墙钟/题 |
|---|---|---|---|---|---|
| **gain1.2 + replan=empty** | **26.6%** | **0.8%** | **0.453** | **20.6** | **845 ms** |
| gain1.2 + K=16 | 21.1% | 1.6% | 0.451 | 19.4 | 1629 ms |
| gain1.0 + K=16 | 21.9% | 4.7% | 0.506 | 14.6 | 1588 ms |
- **结论**: **replan=empty( r=0)全面改善**(到达 +3.9 pp、碰撞 1.6→0.8%、刹停 25.9→20.6、时延 922→845 ms),成为**新历史最佳**。K=16 无收益且时延翻倍(1629 ms),淘汰。
- **下一步**: replan=empty 下重扫增益(0.8/1.0/1.5/2.0),找新最优。
## 轮次 8:部署分布 DAgger 第 2 轮(exp: `exp/dagger-deploy`,边际改善)
- **假设**:第 1 轮 DAgger 用纯策略轨迹采集,与部署分布(反馈 + 安全层)不一致;用部署分布采集可让模型学到刹停/反馈下的正确动作。
- **判据**:部署口径 reach > 23.4%(轮次 6)或刹停显著下降且到达不降。
- **配方**: `ml.dagger.collect --fb_gain 1.2 --safety 1` (2000 题 → 637 起点,部署分布)→ 老师重规划 → 打包 → 从 `base_dag1/best.pt` 微调 15000 步(配置 base_dag2, lr 3e-4)。
- **对照**: base_dag1/best.pt(轮次 6 历史最佳);纯策略 eval 见训练日志。
- **指标(部署口径,n=128, safety=True) **:
| 模型 | gain | 到达 | 碰撞 | ratio2s | 刹停/题 | 墙钟/题 |
|---|---|---|---|---|---|---|
| dag2 best | 1.0 | 21.9% | 1.6% | 0.485 | **18.9** | **905 ms** |
| dag2 best | 1.2 | 22.7% | 1.6% | 0.491 | 25.9 | 922 ms |
| dag1 best | 1.0 | 20.3% | 2.3% | 0.480 | 21.9 | 944 ms |
| dag1 best(轮次 6) | 1.2 | **23.4%** | 1.6% | **0.454** | 31.4 | 953 ms |
- **结论**:部署分布 DAgger 把刹停降 18–40%、时延降 ~31 ms,但到达率未突破 23% 平台(-0.7 pp),属边际权衡改善;历史最佳到达仍是 dag1+gain1.2( 23.4%)。
- **下一步**:试 replan=empty(r=0 规划,让反馈逐步生效)与安全层候选 K=16(减少全拒刹停)。
## 轮次 7:距离衰减增益 + 刹停兜底(exp: `feat/fb-mix`,负结论)
- **假设**:贴近目标减弱反馈可减少过冲/刹停;安全层全拒时用「半速朝目标一步」(单点安全认证)可减少原地停滞。
- **判据**: reach > 23.4%(轮次 6)且碰撞 ≤3%、刹停下降。
- **配方**: `fb_scale=100` (>100 mm 全增益,近目标最低 0.2 倍);`fb_fallback=0.5` (全拒时半速 DLS 一步,认证 `qe+fb1` 单点无碰)。n=128, safety=True。
- **对照**:轮次 6(gain 1.2、无衰减、无兜底:23.4% / 1.6% / 0.454 / 31.4 / 973 ms)。
- **指标**:
| 配置 | 到达 | 碰撞 | ratio2s | 刹停/题 | 墙钟/题 |
|---|---|---|---|---|---|
| decay + fallback (gain 1.2) | 7.0% | 57.8% | 0.506 | 45.1 | 1166 ms |
| decay only (gain 1.2) | 9.4% | 1.6% | 0.454 | 29.6 | 1106 ms |
| no-decay + fallback (gain 1.2) | 21.1% | 57.8% | 0.506 | 46.8 | 1063 ms |
| gain 1.0 + decay + fallback | 4.7% | 55.5% | 0.515 | 37.2 | 939 ms |
- **结论**:两个改动都失败。① 衰减使接近目标时的收敛变慢,到达从 23.4% 掉到 9.4%;② 兜底绕过安全层的多候选选择,碰撞从 1.6% 拉到 **57.8%** (仅单点认证、且执行 3 步同向动作,危险),必须清除。保留参数但默认关闭(`fb_scale=0, fb_fallback=0` ),历史最佳配置(轮次 6)可复现。
- **过程 bug(自造)**:衰减代码曾用变量名 `g` 覆盖 rollout 的随机数生成器,导致 `randn` 报错;改名 `gdec` 后正常——记录以免误判为模型问题。
- **下一步**:DAgger 第 2 轮——采集时加入 fb_gain + safety,让训练分布 = 部署分布(1 轮,15000 步微调,约 1 小时)。按目标要求先向用户确认。
## 轮次 6:反馈增益扩展扫描(exp: `feat/fb-mix`,小幅进展)
- **假设**:更大增益能把到达率继续推高。
- **判据**: reach 显著高于 20.3%( >25%)且碰撞 ≤3%、刹停不失控。
- **配方**: `rollout(fb_gain∈{1.2,1.5,2.0}, safety=True)` ,模型同轮次 5, n=128。
- **对照**:轮次 5( gain 1.0: reach 20.3% / 碰撞 2.3% / ratio2s 0.480 / 刹停 21.9)。
- **指标**:
| gain | 到达 | 碰撞 | ratio2s | 刹停/题 | 墙钟/题 |
|---|---|---|---|---|---|
| 1.2 | **23.4%** | 1.6% | **0.454** | 31.4 | 973 ms |
| 1.5 | 21.9% | 2.3% | 0.498 | 43.0 | 1151 ms |
| 2.0 | 23.4% | 0.8% | 0.530 | 57.6 | 1100 ms |
- **结论**:到达率封顶在 ~23%,增益再大只增刹停(31→58 次/题)。当前瓶颈从「到不了目标」变成「安全层频繁刹停 + 近目标过冲」。
- **下一步**:距离衰减增益(远离目标全增益、贴近目标减弱)+ 刹停兜底;目标 reach > 30% 且刹停显著下降。
## 轮次 5:模型前馈 + DLS 目标反馈(exp: `feat/fb-mix`,历史最佳)
- **假设**:模型擅长开环轨迹/避撞,但不指向目标;把 DLS 朝目标的反馈叠加到候选动作上,可把「走偏」拉回目标。
- **判据**:部署口径(+安全层)reach 显著 > 0 且碰撞 < 3%(§9.2 策略单独碰撞线)、刹停可控;否则不成立。
- **配方**: `closed_loop.rollout(fb_gain=...)` : `inc += fb_gain · DLS(qe→T,R, n=1)` (加在所有候选上,安全层评估带反馈的候选)。模型 `ml/runs/base_dag1/best.pt` ( DAgger 轮 4 的 best, 12000 步)。n=128, val。
- **对照**: base/last.pt + 同反馈;DAgger 模型 + 无反馈。
- **指标(n=128) **:
| 配置 | 到达 | 碰撞 | 精度 ratio2s | 刹停/题 | 时延 |
|---|---|---|---|---|---|
| DAgger 模型, gain 0 | 0% | 44.5% | 0.873 | 0 | — |
| DAgger 模型, gain 1.0, 关安全层 | 29.7% | 73.4% | 0.370 | 0 | — |
| **DAgger 模型, gain 1.0, 开安全层** | **20.3%** | **2.3%** | **0.480** | **21.9** | **12.58 ms/次** ( B=64,K=8,桌面 3090) |
| base 模型, gain 1.0, 关安全层 | 0% | 94.5% | 0.554 | 0 | — |
(另测 n=32 复核:gain 1.0 + safety → reach 25.0%、碰撞 6.2%、ratio2s 0.588。)
- **结论**:**反馈混合是首个把到达率从 0 拉到 20%+ 的机理**;安全层把碰撞从 73% 压到 2.3%(部署口径),代价是刹停 21.9 次/题(远超 §9.2 的 <2%/周期)。精度 ratio2s 0.48( 2 s 时误差缩一半),时延 12.58 ms/次接近 §9.2 的 20 ms(推理+认证)门槛。
- **与历史最佳/基线对比**: reach 0→20.3%、碰撞 99.6→2.3%、ratio2s 0.755→0.480;开环精度仍退化(DAgger 微调导致 15.7 mm vs 基线 5.98 mm)。
- **漂移检查**: main = 70654e4(无新提交);工作区仅用户个人 html 未跟踪;数据口径 act_scale=1.0 与 ckpt 一致;`feat/abs-target` 已推送远端;本次实验在独立分支 `feat/fb-mix` 。
- **下一步**:扫更大 gain(1.2–2.0)与增益衰减;目标是把刹停次数降下来、到达率再提升,并测 ONNX/浏览器时延。
## 轮次 4:真实 DAgger 1 轮(main,部分有效)
- **假设**:策略自己走到的状态(离训练集 21.5°)+ 老师重标注,可让模型学会在偏移状态上行动。
- **判据**:reach 是否从 0 抬头;同时看碰撞、开环精度、时延。
- **配方**: `ACT_SCALE=1.0 DAG_ROUNDS=1 DAG_N=2000 bash ml/dagger/run.sh base ml/runs/base/last.pt` (采集 2000 题 → 老师重规划 → 打包 → 微调 15000 步,lr 3e-4;主数据 + DAgger 混合)。
- **对照**: base/last.pt。
- **指标**:碰撞 99.6%→**40.2%**( 8000 步 36.9%, 10000 步 58.8%);到达 **0%** ,仅微调 12000 步时出现 **0.4%( 2/512) ** ;开环退化 6→**15.7 mm**; ratio2s 0.87– 0.92;时延未测。
- **结论**:DAgger 数据确实教会避撞,但微调把主分布带偏(开环退化),到达仍近 0;单独 DAgger 不是终点。
- **下一步**:在 DAgger 模型上加目标反馈(模型前馈 + DLS 反馈)。
## 轮次 3:绝对目标参数化(exp: `feat/abs-target`,负结论)
- **假设**:模型从当前状态外推增量(判别 ρ=1.54),改为绝对目标标签可让输出指向参考位置。
- **判据**:一步采样开环误差需回到 <10 mm,闭环 success > 0;否则参数化不可行。
- **配方**: `ABS_TARGET=1` 重打主数据(201 万样本,Y=16 步绝对目标/180),train/rollout/ckpt 适配;从零训练 9950 步(p_neq 预热 5000)。过程中修复前缀噪声增广把 eps 直接加到绝对目标(≈18° 污染)的 bug。
- **对照**: base/last.pt( ol_fk 5.98 mm、reach 0%)。
- **指标**:一步采样动作误差 **31°** ( 4/8 段 2.3°/2.8°);ol_fk 4000/6000/8000 步 = 74.6/140.4/139.0 mm;闭环 **0% / 100%** ( 1 段与 4 段皆然);时延未测。
- **结论**:绝对目标的一步流匹配在 MeanFlow 头上学不动(过预热后 5000 步无下降趋势);此配方不成立。分支已推送远端 `217a70b` (本地分支可删,远端保留可复现)。
- **下一步**:回归增量口径,上真实 DAgger。
## 轮次 2:合成扰动状态微调(main,负结论)
- **假设**:偏移 1.5° 状态的老师标注可补足闭环状态覆盖。
- **判据**:若 success 仍 0 或开环精度退化,则配方不成立。
- **配方**:2000 个扰动起点(σ 混合 0.5/1/2/4°)→ 老师重规划(2000/2000 到达)→ 36k 样本 → 从 base/last.pt 微调 3000 步(lr 3e-4 / 1e-4 两轮)。
- **对照**: base/last.pt。
- **指标**:碰撞 99.6%→**48.4% / 60.4%**;到达仍 **0%** ;开环 6→**15.3 / 16.4 mm**(退化 2.5×);ratio2s 0.927/0.893。
- **结论**:只学会了「保守避撞」,开环精度被带偏,success 仍 0;此配方不成立。
- **下一步**:改训练标签(绝对目标)或真实 DAgger。
## 轮次 1:数据规模能否救闭环(main,负结论)
- **假设**:训练数据不足导致分布外状态无覆盖。
- **判据**:若闭环状态到训练集最近邻距离大,且密度缩放无法在误差尺度内缩小差距,则加大同类数据无效。
- **配方**:191 万老师状态最近邻分析;6 维密度缩放 d∝N^(−1/6)。
- **对照**:起点(老师分布内)最近邻。
- **指标**:闭环状态最近邻 p50 **21.5°** (起点 13.2°);数据翻 4 倍仅降 ~21%,与 0.02° 误差尺度差三个量级。
- **结论**:加大同类老师数据无效;需要「不同的数据」(闭环状态标注)。
- **下一步**:DAgger 或状态扰动数据。
## 轮次 0:基线(2026-10-18, main)
- **假设**:模型开环已拟合老师(末端 ~6 mm),闭环失败另有原因。
- **判据**: reach = 0 且碰撞 ≈ 100% 即失败;需同时报告碰撞 / 到达 / 精度 / 时延。
- **配方**: `ml/runs/base/last.pt` ( step 14000,旧配方、act_scale=1.0),n=256。
- **对照**:老师回放 reach 1.0 / 碰撞 0; H1_oracle(老师提线走 rollout) reach 1.0、碰撞 0、轨迹偏差 p99 4.6e-4°。
- **指标**:到达 **0%** ;碰撞 **99.6%** ;精度 ol_fk 5.98 mm / ol_best 2.92 mm / ol_div 0.655, 2 s 误差比 0.755;时延未测。
- **结论**:仿真/滚动无误,失败在策略输出。闭环对每步残差极敏感(老师动作加 σ=0.05× STEP 即 reach 1.0→0.218)。
2026-10-20 21:44:50 +08:00
2026-10-20 07:40:16 +08:00
## 分支清理(2026-10-20)
- `feat/fb-mix` (8e5431c):反馈混合方案的中间分支,**已验证是 `exp/dagger-deploy` 的祖先**(所有提交都在后者历史里),本地/远端分支删除,内容保留在 exp/dagger-deploy。
- `feat/abs-target` (217a70b):绝对目标参数化负结论分支(轮次 3);打 tag `archive/abs-target` 保留可复现实体后,删除远端分支(本地此前已删)。
- `backup/pre-deep-squash` 、`backup/pre-squash` :历史备份分支,非实验方案,保留未动。
- 保留:`main` ( 70654e4)、`exp/dagger-deploy` ( 39c870c,历史最佳)。