exp: 轮次36——规划起点 r 分布实测,循环内共享 FK(#19) 在部署 r3 口径只值 0.03 ms/次,判掉

This commit is contained in:
cbb
2026-10-20 21:16:27 +08:00
parent ee7fe829ac
commit f23f6fc93f
3 changed files with 69 additions and 2 deletions
+50
View File
@@ -0,0 +1,50 @@
{
"empty/commit2/inc_cap0": {
"plans": 175,
"r_hist": {
"0": 175
},
"frac_r0": 1.0,
"save_ms_per_plan_avg": 3.631,
"success": 0.46875,
"brakes_mean": 24.0625,
"wall_s": 54.74565179999627
},
"r3/commit3/inc_cap0": {
"plans": 118,
"r_hist": {
"0": 1,
"2": 1,
"3": 116
},
"frac_r0": 0.00847457627118644,
"save_ms_per_plan_avg": 0.030771186440677965,
"success": 0.4375,
"brakes_mean": 18.03125,
"wall_s": 49.8360657000012
},
"r3/commit3/inc_cap1": {
"plans": 118,
"r_hist": {
"0": 1,
"2": 1,
"3": 116
},
"frac_r0": 0.00847457627118644,
"save_ms_per_plan_avg": 0.030771186440677965,
"success": 0.40625,
"brakes_mean": 16.9375,
"wall_s": 49.97621490000165
},
"empty/commit3/inc_cap1": {
"plans": 117,
"r_hist": {
"0": 117
},
"frac_r0": 1.0,
"save_ms_per_plan_avg": 3.631,
"success": 0.4375,
"brakes_mean": 15.0625,
"wall_s": 43.831084999997984
}
}
+16
View File
@@ -738,6 +738,22 @@
- **循环内还剩的可复用点**:`replan='empty'` 且队列为空时 `qe == q`,此时目标反馈 DLS 与末态打分的 FK 和特征用的是同一姿态,可以共享一份 `cum_xf`(部署 `r=3` 时不成立,要按 r 分支)。这条待测(#19)。 - **循环内还剩的可复用点**:`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)。 - **守卫补一个**:`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)。
## 轮次 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']` 只增不改)。
## 分支清理(2026-10-20) ## 分支清理(2026-10-20)
- `feat/fb-mix`(8e5431c):反馈混合方案的中间分支,**已验证是 `exp/dagger-deploy` 的祖先**(所有提交都在后者历史里),本地/远端分支删除,内容保留在 exp/dagger-deploy。 - `feat/fb-mix`(8e5431c):反馈混合方案的中间分支,**已验证是 `exp/dagger-deploy` 的祖先**(所有提交都在后者历史里),本地/远端分支删除,内容保留在 exp/dagger-deploy。
+3 -2
View File
@@ -197,7 +197,7 @@ def rollout(model, kin, tasks, device, K=8, safety=False, seed=0, max_sec=None,
# 2026-10-20(轮次33):速度/加速度按「实际执行位移」算,不看指令——第30轮证明反馈是在限幅之后叠加的 # 2026-10-20(轮次33):速度/加速度按「实际执行位移」算,不看指令——第30轮证明反馈是在限幅之后叠加的
vratio = torch.zeros(B, device=device); aratio = torch.zeros(B, device=device); prev_exec = torch.zeros(B, 6, device=device) vratio = torch.zeros(B, device=device); aratio = torch.zeros(B, device=device); prev_exec = torch.zeros(B, 6, device=device)
traj = [q.clone()] if return_traj else None traj = [q.clone()] if return_traj else None
plans = {k: [] for k in ('it', 'qe', 'commit', 'points', 'midpoints', 'gaps', 'certified')} if return_traj else None plans = {k: [] for k in ('it', 'r', 'qe', 'commit', 'points', 'midpoints', 'gaps', 'certified')} if return_traj else None
n_start = int(round(0.5 / DT)); moved_start = None # R2 起步失败:0.5 s 内关节总行程 < 1° n_start = int(round(0.5 / DT)); moved_start = None # R2 起步失败:0.5 s 内关节总行程 < 1°
k2s = int(round(2.0 / DT)); e2 = None k2s = int(round(2.0 / DT)); e2 = None
e0, _ = goal_err(kin, q0, T, R) e0, _ = goal_err(kin, q0, T, R)
@@ -422,6 +422,7 @@ def rollout(model, kin, tasks, device, K=8, safety=False, seed=0, max_sec=None,
last = torch.cat([qe[:, None], fut[ar, pick]], 1); last_ok = committed; last_brake = braked last = torch.cat([qe[:, None], fut[ar, pick]], 1); last_ok = committed; last_brake = braked
if return_traj: if return_traj:
plans['it'].append(it + r) plans['it'].append(it + r)
plans['r'].append(r)
for key, value in (('qe', qe), ('commit', commit), ('points', cert_pts), ('midpoints', cert_mids), ('gaps', cert_gaps), ('certified', certified)): for key, value in (('qe', qe), ('commit', commit), ('points', cert_pts), ('midpoints', cert_mids), ('gaps', cert_gaps), ('certified', certified)):
plans[key].append(value) plans[key].append(value)
queue = torch.cat([queue, commit], 1) queue = torch.cat([queue, commit], 1)
@@ -476,7 +477,7 @@ def rollout(model, kin, tasks, device, K=8, safety=False, seed=0, max_sec=None,
'goal_ratio_2s': ratio2.cpu(), 'speed_ratio': vratio.cpu(), 'accel_ratio': aratio.cpu()} 'goal_ratio_2s': ratio2.cpu(), 'speed_ratio': vratio.cpu(), 'accel_ratio': aratio.cpu()}
if return_traj: if return_traj:
per['traj'] = torch.stack(traj, 1).cpu() per['traj'] = torch.stack(traj, 1).cpu()
per['plans'] = {k: torch.tensor(v) if k == 'it' else torch.stack(v, 1).cpu() for k, v in plans.items()} per['plans'] = {k: torch.tensor(v) if k in ('it', 'r') else torch.stack(v, 1).cpu() for k, v in plans.items()}
return res, per return res, per