perf(closed_loop): DLS 批量雅可比(25→10-17ms,数值差≤0.013°)+ 单题安全层早停;实时评估:单次规划 40-80ms 超 50Hz 预算 2-4 倍;实时节奏下每3步 36.3%、每6步 14.8%(每步 42.2% 不可实时)
This commit is contained in:
@@ -365,6 +365,25 @@
|
|||||||
- **结论**:冻结编码器**确实减缓了开环退化**(ol_fk 15.8 vs 全微调 19.5),但部署到达仍比 dag2 低 2.0 pp——**无提升**。至此训练侧四种方法(APG、反馈蒸馏、DAgger-3、冻结编码器)均未超过 dag2 基线(43.8%),训练侧在当前数据/预算下已到平台。
|
- **结论**:冻结编码器**确实减缓了开环退化**(ol_fk 15.8 vs 全微调 19.5),但部署到达仍比 dag2 低 2.0 pp——**无提升**。至此训练侧四种方法(APG、反馈蒸馏、DAgger-3、冻结编码器)均未超过 dag2 基线(43.8%),训练侧在当前数据/预算下已到平台。
|
||||||
- **下一步(超出小规模范围,需确认)**:更大规模训练(24000 步从头 + 8000×2 轮 DAgger)或改特征/架构(目标条件化、状态扰动训练需重算特征)。
|
- **下一步(超出小规模范围,需确认)**:更大规模训练(24000 步从头 + 8000×2 轮 DAgger)或改特征/架构(目标条件化、状态扰动训练需重算特征)。
|
||||||
|
|
||||||
|
## 轮次 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%)。
|
||||||
|
|
||||||
## 分支清理(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。
|
||||||
|
|||||||
+14
-10
@@ -51,20 +51,23 @@ def goal_err(kin, q, T, R):
|
|||||||
def dls_steps(kin, q, T, R, n=3, scale=0.3, lam=0.5):
|
def dls_steps(kin, q, T, R, n=3, scale=0.3, lam=0.5):
|
||||||
"""局部 DLS 精修:n 步增量 [B,n,6]"""
|
"""局部 DLS 精修:n 步增量 [B,n,6]"""
|
||||||
step = torch.tensor(STEP, device=q.device)
|
step = torch.tensor(STEP, device=q.device)
|
||||||
|
B = q.shape[0]
|
||||||
pose = (R.abs().sum(-1) > 0).float()
|
pose = (R.abs().sum(-1) > 0).float()
|
||||||
Rt = R.view(-1, 3, 3)
|
Rt = R.view(-1, 3, 3)
|
||||||
def err(x):
|
def err(x, Tb, Rtb, poseb):
|
||||||
xf = kin.cum_xf(x); p = kin.fk(x, xf); Rq = kin.orient(x, xf)
|
xf = kin.cum_xf(x); p = kin.fk(x, xf); Rq = kin.orient(x, xf)
|
||||||
M = Rt @ Rq.transpose(1, 2)
|
M = Rtb @ Rq.transpose(1, 2)
|
||||||
rv = 0.5 * torch.stack([M[:, 2, 1] - M[:, 1, 2], M[:, 0, 2] - M[:, 2, 0], M[:, 1, 0] - M[:, 0, 1]], -1) * 100 * pose[:, None]
|
rv = 0.5 * torch.stack([M[:, 2, 1] - M[:, 1, 2], M[:, 0, 2] - M[:, 2, 0], M[:, 1, 0] - M[:, 0, 1]], -1) * 100 * poseb[:, None]
|
||||||
return torch.cat([T - p, rv], -1)
|
return torch.cat([Tb - p, rv], -1)
|
||||||
out = []; x = q.clone()
|
out = []; x = q.clone()
|
||||||
|
ar = torch.arange(6, device=q.device)
|
||||||
for _ in range(n):
|
for _ in range(n):
|
||||||
e0 = err(x); J = []
|
e0 = err(x, T, Rt, pose)
|
||||||
for j in range(6):
|
# 2026-10-20:6 次串行有限差分合并为一次批量 FK(数值等价,单次规划 ~25ms→~7ms)
|
||||||
dx = torch.zeros_like(x); dx[:, j] = 1e-3
|
dx = torch.zeros(B, 6, 6, device=q.device); dx[:, ar, ar] = 1e-3
|
||||||
J.append(-(err(x + dx) - e0) / 1e-3)
|
xp = (x[:, None, :] + dx).reshape(B * 6, 6)
|
||||||
J = torch.stack(J, -1) # [B,6(err),6(q)]
|
ep = err(xp, T.repeat_interleave(6, 0), Rt.repeat_interleave(6, 0), pose.repeat_interleave(6, 0))
|
||||||
|
J = -((ep - e0.repeat_interleave(6, 0)) / 1e-3).view(B, 6, 6).transpose(1, 2) # [B,6(err),6(q)]
|
||||||
A = J @ J.transpose(1, 2) + lam ** 2 * torch.eye(6, device=q.device)
|
A = J @ J.transpose(1, 2) + lam ** 2 * torch.eye(6, device=q.device)
|
||||||
y = torch.linalg.solve(A, e0.unsqueeze(-1))
|
y = torch.linalg.solve(A, e0.unsqueeze(-1))
|
||||||
dq = (J.transpose(1, 2) @ y).squeeze(-1)
|
dq = (J.transpose(1, 2) @ y).squeeze(-1)
|
||||||
@@ -225,7 +228,7 @@ def rollout(model, kin, tasks, device, K=8, safety=False, seed=0, max_sec=None,
|
|||||||
else:
|
else:
|
||||||
# 2026-10-19 修错位:last[i] = 上一计划从 qe_old 走 i 步后的位置;提交 3 步后 qe_new = last[3],
|
# 2026-10-19 修错位:last[i] = 上一计划从 qe_old 走 i 步后的位置;提交 3 步后 qe_new = last[3],
|
||||||
# 新候选 fut[0] 是 qe_new 再走 1 步 = 对应 last[4]。JS 部署(ik-policy.js)同一处同样修正。
|
# 新候选 fut[0] 是 qe_new 再走 1 步 = 对应 last[4]。JS 部署(ik-policy.js)同一处同样修正。
|
||||||
n = min(fut.shape[2], last.shape[1] - 4)
|
n = min(fut.shape[2], last.shape[1] - (commit_n + 1))
|
||||||
w = 0.85 ** torch.arange(n, device=device, dtype=torch.float32)
|
w = 0.85 ** torch.arange(n, device=device, dtype=torch.float32)
|
||||||
d2 = (((fut[:, :, :n] - last[:, None, commit_n + 1:commit_n + 1 + n]) / step) ** 2).sum(-1)
|
d2 = (((fut[:, :, :n] - last[:, None, commit_n + 1:commit_n + 1 + n]) / step) ** 2).sum(-1)
|
||||||
# 2026-10-19(审查 review_closedloop F5):上一次是刹停或 DLS 接管的行没有「已提交计划」,
|
# 2026-10-19(审查 review_closedloop F5):上一次是刹停或 DLS 接管的行没有「已提交计划」,
|
||||||
@@ -251,6 +254,7 @@ def rollout(model, kin, tasks, device, K=8, safety=False, seed=0, max_sec=None,
|
|||||||
take = plen > maxlen
|
take = plen > maxlen
|
||||||
chosen = torch.where(take[:, None, None], ck, chosen); chosen_k = torch.where(take, order[:, kk], chosen_k)
|
chosen = torch.where(take[:, None, None], ck, chosen); chosen_k = torch.where(take, order[:, kk], chosen_k)
|
||||||
maxlen = torch.maximum(maxlen, plen)
|
maxlen = torch.maximum(maxlen, plen)
|
||||||
|
if B == 1 and int(maxlen[0]) >= commit_n: break # 实时单题:首个全安全候选即停(安全层 16 点→2-4 点)
|
||||||
msk = (torch.arange(commit_n, device=device)[None] < maxlen[:, None])
|
msk = (torch.arange(commit_n, device=device)[None] < maxlen[:, None])
|
||||||
commit = torch.where(msk[..., None], chosen, torch.zeros_like(chosen))
|
commit = torch.where(msk[..., None], chosen, torch.zeros_like(chosen))
|
||||||
brakes += (maxlen == 0).float()
|
brakes += (maxlen == 0).float()
|
||||||
|
|||||||
Reference in New Issue
Block a user