150 KiB
探索日志: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 起,用户要求:打开就看到最近一轮)。
评测约定:val 任务、部署节奏(r = 3 重规划、1 段采样、K=8);「纯策略」= 关安全层;「部署」= 开安全层。时延:桌面 RTX 3090 上 sample_k(B=64, K=8) 墙钟均值(均值,非 P99);浏览器 ONNX P99 以 §9.2 R4 的独立测量为准。
口径更正(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 仅是可选实验。
轮次统计
- 连续无实质进展轮数: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 重跑。
- 但这组数含超速:
- 实时性(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_uniformn≥8、二分 5 次查询),但它进不了实时预算(轮次 31–32)。 - 失败结构(轮次 38,147 到达 / 109 未到):63 题是走一半被冻住(离目标 >100 mm 且刹车 >30 次)、23 题方向错、位置差 20
100 mm 15 题、差 520 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)
| 序 | 候选 | 支撑证据 | 状态 |
|---|---|---|---|
| 0 | 把"沿路最小间隙"接进候选打分(#24) | 安全层的拒绝是真实几何(端点/中点穿模),而 cert_batch=1 已经在同一次 gaps 调用里算了 K 条候选各 2·commit_n 个点的间隙——这些信息目前只用来判通过/拒绝,没进打分。做法:score = −e_end − w·relu(gap_ref − min_gap_path),让"会穿模"的候选在排序阶段就出局,而不是等安全层全拒。代价为零(同一批数),判据完全不放松 |
待实现(链跑完后动库) |
| 1 | 候选数翻倍 K=8→16 | 轮次 39 实测:到达 +3.9 pp、时限内 +3.1 pp、刹车 −30%(19.55→13.77)、碰撞仍 0、行程比不变 ⇒ 很多"全拒"是没备选而不是真没路 | 正向;认证/打分成本要用独占微基准量完才能谈部署 |
| 2 | 全拒时缩步顶上(--backoff:首选候选按 1/2、1/4、1/8 并进同一次认证,只在原候选连第 1 步都不安全时启用) |
失败分类 63/109 是"被冻住"、未到组 37% 步为零运动;但 4 题 CPU 冒烟提示转化率只 ~13% | 代码与单测已落,256 题四臂待补跑(判读规则已预注册) |
| 3 | 白费比例惩罚(select=ep_waste --len_w,罚 1−同轴净/总 × 当前误差) |
换向是全局现象(~1/4 的(步,轴)对在反向,到达/未到达两组差不多);净位移只占总行程 0.445 | 已实现+正对照单测(可手算 2/18);三臂排队 |
| 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 且扰动特征 | 已判掉 |
轮次 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.11.0 对应的惩罚是 550 mm 当量——这是扫这三个值的原因,不是随手取的。
- 机制单测 2 条(
- 测试
tests/test_eval_cl.py38→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 我把批量认证分支重写(加缩步档那一段)没有改动任何行为。 - 两个我自己的操作失误,如实记在这里:
- 新加的
backoff指标一度在产物里根本没有——ml/eval/eval_cl.py:run()的out是自己显式列键的,不是从rollout返回的字典通抄,所以我往res加的backoff_mean被无声丢掉。已改成从逐题per['backoff']汇总(backoff_mean+reject_all_mean = backoff+brakes,后者才是与"原来全拒次数"可比的量)。教训:加指标要顺着输出链路走到底,别只改生产端。 - 停后台 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)要读的第一个数。
控制臂对表: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 的冻住时间。
"冻住"的真实形态:不是堵死,是每题约 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 段),是"直接开去停靠位、永远不满足判据"——再次印证它们不该在到达率分母里。
缺口几乎全在"直线被挡 / 贴立柱"两类(轮次 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 类有效"的杠杆能被看见的前提。
刹停是极端长尾:一半题零刹停,两成题占 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的题占比)。
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_mean0.0995/0.1007/0.1027 与brakes_mean/n_plans= 19.4/195 ≈ 0.0995 逐位对得上 ⇒ 刚补的分母口径没接错。
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.jsonvsdocs/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 的读数确系修分母前的旧口径。
#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,三档差一个数量级,看是否有拐点)。等链跑完、库能改之后实现+单测再跑。
代价探针的第一版量错了对象(仪表缺陷,已修)
- 第一版
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,只跑独立脚本)。
到达率的上限在哪(把 #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:拒得越少,穿模越多。只有"选得更准"才吃得到,这也是为什么把已有的间隙数喂给打分比再加余量门限更值钱。
判别定案(#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%(两段)——差距巨大,且以前从没在同一配方下报过。
§9.2 记分板(2026-10-20 现状,最好的合法口径 = --inc_cap 1 + K=16)
| 判据(§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) |
| held-out 可达任务到达率 | ≥ 98% | 0.5625(K=16)/ 0.5234(K=8) | 差 41.8 pp |
| 到达用时 ≤ 老师×1.3 | 全部到达题 | 达标比例 0.2969(K=16)/ 0.2656(K=8) | 到达题里也只有约三成按时 |
| 关节行程 ≤ 规划器×1.10 | ≤1.10 | 行程比中位 2.62 | 超 1.4 倍,且罚候选行程是负结论(见上) |
| 冷启动 | <10 ms | 未单独测(周期 P50 9.0 ms 是稳态推理,含首段编码) | 待测 |
| 推理 + 安全认证 P99 | <20 ms | 现口径周期 P50 33.5 / P99 64.7 ms;批量认证把最坏 80.2→37.1 ms | 差 2~3 倍 |
| 刹停 < 2% 推理周期 | <2% | 估算 ≈9.9%(19.25 次全拒 ÷ 195 次规划;K=16 时 13.77/195 ≈ 7.1%) | 差 3.5~5 倍 |
- 刹停率这一格现在是手算估算:
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 时限),所以任何单格变好都要同批报其他格,这正是记分板存在的理由。
多段推理的代价实测(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),这是判断"候选数能不能买到部署里的到达率"的关键一列。
候选为什么会"塌":两段积分把 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')会把它静默吃掉。
试候选数的成本-收益曲线(轮次 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)是这条杠杆能否上线的关键读数——跨轮次墙钟不算证据,本表的墙钟只用来说明趋势量级。
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 项全绿。
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是多样性方向。
指标链路端到端自证 + 预注册一条判读(轮次 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与到达/时限,不能只报转化率。
- 若 256 题也只在 10–20% 量级:结论是**"冻住"的根因是候选方向本身对着障碍**,缩步只是慢一点撞——那
轮次 38:把 --steps 打通之后,闭环反而变差——瓶颈从"动作质量"移到了"安全层拒绝率"
-
动机:E1-b 实测同一个模型的一步输出比它自己的两段采样离老师远 10 倍(4.33 vs 0.43)。那就先别急着训练——直接把推理段数当自变量,量闭环。
ml/eval/eval_cl.py加--steps(默认 1,发布口径不变),同一 256 题、同 seed、同配方只改段数:口径 到达 时限内(≤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 steps=4 cap=1 0.4062 0.3047 79.65 1.91 s 1.882 0.135 mm 0.461 steps=8 cap=1 0.4102 0.3242 79.70 1.93 s 1.870 0.253 mm 0.469 (
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 几乎不再变化,说明瓶颈不在采样精度。 -
失败分类(不占卡:读轮次 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(候选数与安全档位)比"往打分里加剩余时限"更值钱。 -
反直觉但自洽的一组数:两段推理开环更贴老师(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 倍开环增益。
轮次 37:K-MF(运动学 MeanFlow)方案核查——先测"一步 vs 多步",结果比论文那条更要命
-
交来的方案里那几条 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):目标与真值的距离(越小越好)目标写法 (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)/dc2.364(0.61×) 2.468 网络现在的一步输出 u(ε,0,1) 3.906 — -
两条硬结论:
- 方案抄来的 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×)。 - 自举污染是真的,而且就在部署角:网络一步输出与自己的流图差 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×)。
- 方案抄来的 Eq.7 系数在收敛解上不自洽:λ=0.5 时两项系数和 = (1−λ)²+λ² = 0.5,不动点变成
-
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打通,量它对闭环到达的影响,再决定要不要为"把一步训好"付一次训练。 -
不动点判决补一个解析实验(
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.py3 项 ⇒ 共 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)。
- 默认
时间账:限幅之后 time_ok 的损失在"站住"上,不在巡航速度上(2026-10-20,轮次 36 续)
-
口径:直接吃轮次 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的断言之后才挡住这类错。 -
实测(占活动窗的比例)
组 题数 零运动 <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 步 -
判读:限幅并没有把动作整体拖慢——未到达组的 ≥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,这轮排在其后。
轮次 36:规划起点队列长度实测——#19(循环内共享 FK)判掉
-
要判的问题:轮次 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:口径 规划次数 r 分布 r==0 占比 平摊可省 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/次 -
结论(不做):部署 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']只增不改)。
轮次 35:半精度、流水线复用与 float32 认证的实测(exp: exp/dagger-deploy,三条路两条被自己否掉)
-
按用户指定的方向先量显卡精度档(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_xf13.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"。这个数作废,两个独立原因:- 第一版的"合并"把
xf=传给了包含 5 行的gaps调用,而gaps的xf是按行对应的 → 只有第 0 行走完宽相位,认证点 4 行全部退回截顶值 40.0 mm,即少干了活(表现为认证矩阵差 31.17 mm)。修好后同一 cap 下矩阵逐位一致(差 0.0 mm)。 - 更根本:真实管线顺序是 特征 → 推理 → 候选 → 认证,认证点依赖网络输出,所以"特征用的 q 间隙与认证点间隙合成同一次调用"在实现上做不到。该文件保留作记录,但不能当作可实现收益。
- 第一版的"合并"把
-
只测可实现的口径(
docs/experiment_round34_geom_opt.json;B=1、K=8、commit 2;7 个变体逐轮交替、奇数轮反序,80 轮;等价性两项都True:批量认证矩阵与逐条循环逐位一致、features 复用 xf 前后逐位一致):变体 含义 P50 P95 P99 A_today 现口径 33.49 46.14 64.69 B_xf_reuse gm_groups复用 features 已算的cum_xf30.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 - 复用 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 是无条件收益:省一次
-
等价性闸门(纯效率改动不许改变任何结果):
- 复用 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 交错实测方向一致)。合成夹具里也断言两条路径选到同一条候选、同一前缀长度、逐位相同的轨迹与证书。
- 复用 FK:同一 256 题、同 seed、同配方重跑(
-
测试 32→34 项:
CertBatchEquivalenceTest两条(候选 0 前缀不完整 → 选候选 1;所有候选第 2 步都不安全 → 两条路径都停在第 1 步)。写夹具时踩到一个自己的坑:桩里掩码写成q[:, :1]再[:, None]变成 3 维,广播出 (4,4,49) 才报"size 16",是测试桩错不是库错——先证形状再改代码。
轮次 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_max1.660003662、over_vmax_rate1.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 重算(本轮后续做)。 -
四组单变量对照(同 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 1134/256 = 0.5234 0.5234 0.2656 0 19.55 1.000 0.000 0.2790 --gap_margin 0.5144/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),余量与碰撞计数是两条独立的线,不互相顶替。
-
回归:
python -m unittest tests.test_eval_cl30 项通过(新增 4 项):未限幅时实测速度比确实 =3.4/1.2>1(灵敏度)、限幅后恰为 1.0、0.3 mm 间隙在余量 0 时通过而余量 0.5 时刹停、5 mm 间隙在余量 0.5 时仍通过(证明 cap 抬升生效,否则该测试会恒假)。 -
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_ksteps=1,K=1 / 4 / 87.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_uniform2 根 n=8 / n=169.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、空
synchronize0.005 ms、一次encode2.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",需按真实轨迹批量对比才能下结论。
- 前提更正(重要):
轮次 32:均匀细分认证与确定界的反证(exp: exp/dagger-deploy,认证仍进不了 20 ms,但定位到真正的成本杠杆)
-
本轮假设:第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):子段数 n 判安全 判碰撞 证不出 二次加密(2n+1点)反证的误放行 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 第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):配置 宽相位 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 - 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_cl26 项通过(新增 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 误放行。
轮次 31:连续段认证的确定界与成本实测(exp: exp/dagger-deploy,判据变强,实测进不了 20 ms)
- 假设与判据:轮次 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 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,实现不会把未知当通过。
- 已知漏检段(180 题执行段 54)判碰撞,仅用 5 次查询;该段原证书
- 成本模型对上实测(
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_cl23 项通过(轮次 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 间隙走,任何认证方案都会退化成几十次查询,而反馈叠加后的速度约束本来就是未完成项。
轮次 30:认证与执行统一逐步限位(exp: exp/dagger-deploy,局部修复有效,仍未零碰撞)
- 假设与判据:安全层认证的是未夹紧累加轨迹,执行器却逐步夹紧 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 仍只是间隙截顶,正间隙判据没有放宽。
| 指标(同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 |
- 执行一致性复核(
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 -v14项通过。覆盖整段/部分限位拒绝、只保留真实安全前缀、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合格。下一轮先验证更强的段内认证,再单独评估反馈后的速度/加速度约束与真实端到端调度;每次保持小样本单变量对照,继续保留失败证据。
轮次 29:安全层全拒后减弱目标反馈(exp: exp/dagger-deploy)
- 假设:目标反馈将绕障候选推向障碍,连续全拒会反复停在同处;仅在上一计划被全拒时减小下一计划反馈,可能保留正常段收敛速度并减少重复刹停。
- 判据:同任务、同 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 顺序。
| 改动(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 |
- 单独减半反馈 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_parityPASS,碰撞布尔差 0、间隙最大差 2.53e−13 mm。首撞回放仍共用碰撞模型,不替代真机或独立连续认证。
- 双精度运动学/间隙另与已有 JS 2000 个样本对拍:
- 结论与下一步:减少连续刹停确有小样本收益,但碰撞、行程和真实时延仍未过门槛;保留为实验选项,不更改查看器默认。下一轮记录原认证点与 J5 夹紧后实际点,修复后用同批同 seed A/B 和独立细采样复核,禁止靠关掉认证提速。
轮次 28:端点进度选择——时间效率大幅提升(exp: exp/dagger-deploy,新历史最佳)
- 假设:一致性选择奖励"与上一条计划一致",但失败主因是超时(轮次 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):
| 选择器 | 到达 | 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 |
- 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 时间戳。
| 集合(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 |
- 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):tick不夹关节限位(Pythonclamp_box每步夹)→ q 一旦越限,认证的inBox永远拒绝所有候选,原地刹停到超时(certWhy.box 2650 次);现执行与候选投影都夹 LIM。- 安全层整段拒绝 → 刹停;移植
safety_partial:整段不过时依次缩短前缀,执行到第一个不安全步。 - 新增
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 的准确率-时延权衡;③ JSgapMatrix同步只算 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 此前从未实测):
kin_torch._cat_gaps的p['b'] += s是 in-place,而b被 autograd 索引反向图引用 → backward 报 version 错;改为p['b'] = p['b'] + s。- 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)
feat/fb-mix(8e5431c):反馈混合方案的中间分支,已验证是exp/dagger-deploy的祖先(所有提交都在后者历史里),本地/远端分支删除,内容保留在 exp/dagger-deploy。feat/abs-target(217a70b):绝对目标参数化负结论分支(轮次 3);打 tagarchive/abs-target保留可复现实体后,删除远端分支(本地此前已删)。backup/pre-deep-squash、backup/pre-squash:历史备份分支,非实验方案,保留未动。- 保留:
main(70654e4)、exp/dagger-deploy(39c870c,历史最佳)。