exp: 轮次45——tie(等长安全前缀按沿路最小间隙定夺)判掉

两臂 n=256 同 seed 背靠背(配方=轮次42 K8+cert_batch=1+inc_cap=1):到达 0.5234→0.5039
(-1.95pp,逐题配对丢6赢1净-5,McNemar 精确 p=0.125 与零不可分),时限内 +1.17pp、
刹停 -9%、行程比 -0.076、执行碰撞仍为 0(判据未放松)。丢的 6 题 5 题在 A 类(开阔区)
=买余量卖进度的签名。

仪表与离线数交叉验证:改选率 5.58% 对上轮次44 独立测得的"执行点间隙落在 0.2–0.5mm 占
5.6%",并列率 79.0% 对上"满前缀 79.4%" ⇒ 分辨率上界被宽相位截顶 gcap=max(0.5,margin+0.5)
锁死,5.6% 是这个家族在 cap=0.5 下的天花板,不是实现没调好。

结构性发现:#24 作用在错的人群——tie 只在 maxlen>0 触发,而失败主人群是全拒(maxlen=0,
未到达题 22% 的规划);全拒那条已由 backoff(轮次43)判掉。前置条件记为 #28(gcap 与
gap_margin 解耦)。

实现账:新增 tie 与触发计数器(生产端 per 数组+dump 键、消费端汇总 tie_* 同批改完,
tie=0 时 22/22 老键逐位复现);修掉 tie 分支局部名 nmax 顶掉主循环总步数的遮蔽 bug,
守卫单测做过变异检查;计数器正对照可手算(tie_opp=tie_changed=n_plans)。47 项测试绿。
This commit is contained in:
cbb
2026-10-21 00:33:44 +08:00
parent 350f386c02
commit 72c8835229
8 changed files with 564 additions and 5 deletions
+8 -2
View File
@@ -68,6 +68,10 @@ def run(model, kin, tasks, device, bs=256, **kw):
if 'backoff' in flat and flat['backoff'].any(): # backoff=缩步顶上的次数;brakes 现在只记连最小档都不安全的
out['backoff_mean'] = flat['backoff'].mean().item() # ⇒ 原来的"全拒"事件数 = 两者之和
out['reject_all_mean'] = (flat['backoff'] + flat['brakes']).mean().item()
if 'tie_opp' in flat and flat['tie_opp'].any(): # tie=1 的自检:钩子可用率/真的改选率,分母与 brake_rate 同为规划次数
out.update({'tie_opp_rate_mean': flat['tie_opp_rate'].mean().item(),
'tie_changed_rate_mean': flat['tie_changed_rate'].mean().item(),
'tie_opp_task_share': (flat['tie_opp'] > 0).float().mean().item()})
return out, per
@@ -115,6 +119,7 @@ def main():
ap.add_argument('--steps', type=int, default=1, help='MeanFlow 采样段数;1=线上一口径(历史发布数字全是 1)')
ap.add_argument('--z_scale', type=float, default=1.0, help='候选噪声缩放:>1 让 K 条候选更分散(测"全拒是没有备选"还是"真的没路")')
ap.add_argument('--len_w', type=float, default=0.0, help="ep_len=罚累计归一行程;ep_waste=罚(1−净/总)×当前误差;0 与 endpoint 逐位相同")
ap.add_argument('--tie', type=int, default=0, help='1=等长安全前缀时按沿路最小间隙定夺(需 --cert_batch 1)')
ap.add_argument('--backoff', type=int, default=0, help='全拒时把首选候选按 1/2、1/4…缩步重试的档数(需 --cert_batch 1)')
ap.add_argument('--max_sec', type=float, default=None)
ap.add_argument('--seed', type=int, default=0)
@@ -142,7 +147,7 @@ def main():
safety_partial=(a.commit if (a.safety and a.partial) else 0), commit_n=a.commit,
select=a.select, replan=a.replan, fb_gain=a.fb, fb_scale=a.fb_scale, fb_near=a.fb_near, fb_fallback=a.fb_fallback, fb_ki=a.ki, fb_decay=a.kdecay, fb_imax=a.kimax,
fb_every=a.fb_every, safety_try=a.safety_try, sel_w=a.sel_w, dls_safety=a.dls_safety, fb_clear=a.fb_clear, fb_cmin=a.fb_cmin, sub_refresh=a.sub_refresh, fb_block_gain=a.fb_block_gain,
inc_cap=a.inc_cap, gap_margin=a.gap_margin, cert_batch=a.cert_batch, backoff=a.backoff, len_w=a.len_w, return_traj=bool(a.trace))
inc_cap=a.inc_cap, gap_margin=a.gap_margin, cert_batch=a.cert_batch, backoff=a.backoff, len_w=a.len_w, tie=a.tie, return_traj=bool(a.trace))
wall = time.perf_counter() - t0
result = {**meta, 'metrics': r, 'simulation_wall_s': wall}
print(json.dumps(json_finite(result), ensure_ascii=False, allow_nan=False), flush=True)
@@ -150,7 +155,8 @@ def main():
Path(a.out).write_text(json.dumps(json_finite(result), indent=2, ensure_ascii=False, allow_nan=False) + '\n', encoding='utf-8')
if a.dump:
rows = []
keys = ['done', 'ok', 't_done', 'limit', 'col', 'brakes', 'err', 'first_hit', 'dls_it', 'goal_ratio_2s', 'brake_rate', 'n_plans']
keys = ['done', 'ok', 't_done', 'limit', 'col', 'brakes', 'err', 'first_hit', 'dls_it', 'goal_ratio_2s', 'brake_rate', 'n_plans',
'tie_opp', 'tie_changed', 'tie_opp_rate', 'tie_changed_rate']
flat = {k: torch.cat([p[k] for _, p, _ in pers]).tolist() for k in keys}
for i, t in enumerate(tasks):
rows.append({**t, 'i': i, **{k: flat[k][i] for k in keys}})