fix(kin/diag): kin.gaps 粗筛段也按点分块(COARSE_ENTRIES=3e7,≤446 点/块;实测上一版粗筛 4096 点仍 9.3 GiB);diag_cl 加 D 段(子目标头精度 / 不用子目标 / 老师真实途经点)与目标误差进度比;rollout 加 use_sub、sub_override;本机执行清单更新
This commit is contained in:
@@ -27,6 +27,9 @@ GROUPS = [('sincos', 0, 12), ('joint_norm', 12, 15), ('dq', 15, 21), ('p', 21, 2
|
||||
('sub', 68, 74), ('sub_flag', 74, 75), ('gaps', 75, 83)]
|
||||
|
||||
|
||||
PROG_T = (0.5, 1.0, 2.0) # 目标误差 / 起点误差 的取样时刻(s)
|
||||
|
||||
|
||||
def pct(v, p):
|
||||
v = sorted(v)
|
||||
return v[min(len(v) - 1, int(len(v) * p))] if v else None
|
||||
@@ -81,6 +84,7 @@ def main():
|
||||
|
||||
# ---------- C:闭环失败形态 ----------
|
||||
first_t, col_steps, pairs, min_err, reach = [], [], {}, [], 0
|
||||
prog = {ts: [] for ts in PROG_T}
|
||||
reach_s, brakes_s, col_s = 0, [], 0
|
||||
for i in range(0, len(tasks), a.bs):
|
||||
ch = tasks[i:i + a.bs]
|
||||
@@ -95,6 +99,9 @@ def main():
|
||||
Rt = torch.tensor([t['R'] if t.get('R') else [0.] * 9 for t in ch], dtype=torch.float32, device=dev)
|
||||
e, _ = goal_err(kin, tr.reshape(-1, 6), Tt.repeat_interleave(Tn, 0), Rt.repeat_interleave(Tn, 0))
|
||||
e = e.view(B, Tn)
|
||||
for b in range(B):
|
||||
for ts in PROG_T:
|
||||
k = min(Tn - 1, int(round(ts / DT))); prog[ts].append((e[b, k] / e[b, 0].clamp(min=1e-3)).item())
|
||||
# 到达后轨迹被冻结(d=0),之后不再计
|
||||
for b in range(B):
|
||||
if per['done'][b]: reach += 1
|
||||
@@ -113,6 +120,38 @@ def main():
|
||||
'first_hit_pair(group a-b)': dict(sorted(pairs.items(), key=lambda kv: -kv[1])[:8]),
|
||||
'min_goal_err_mm': {'p10': pct(min_err, .1), 'p50': pct(min_err, .5), 'p90': pct(min_err, .9)},
|
||||
'safety_on': {'reach': reach_s / n, 'collided': col_s / n, 'brakes_p50': pct(brakes_s, .5)}}
|
||||
out['C']['goal_err_ratio_p50'] = {'%.1fs' % ts: pct(v, .5) for ts, v in prog.items()} # <1 = 在靠近目标
|
||||
|
||||
# ---------- D:子目标是不是元凶(2026-10-19 加:C 显示全程最小目标误差中位 254 mm,策略根本没朝目标走) ----------
|
||||
# 训练时特征里的子目标是老师真实途经点(80% 概率给),闭环里却换成子目标头自己的预测;预测偏了,策略就会忠实地朝错的方向走。
|
||||
sg_by_tid = {}
|
||||
for i, t in zip(idx, tk):
|
||||
qrow = torch.atan2(vd.X[i, 0:12:2].float(), vd.X[i, 1:12:2].float()) * 180 / torch.pi
|
||||
sgr = vd.SG[i].float()
|
||||
sg_by_tid[t['tid']] = (qrow[None] + sgr[:12].view(2, 6) * 180, bool(sgr[12] > 0.5))
|
||||
# D0:冷启动子目标头精度(起点特征里抹掉数据集的真子目标,与闭环冷启动同口径)
|
||||
Xs = X0.clone(); Xs[:, 68:75] = 0
|
||||
with torch.no_grad(): _, sp = model.heads(model.encode(Xs))
|
||||
lab = torch.stack([vd.SG[i].float() for i in idx])
|
||||
need_l = lab[:, 12] > 0.5; need_p = sp[:, 12] > 0.5
|
||||
via_err = ((sp[:, :6] - lab[:, :6]) * 180).abs().max(-1).values
|
||||
out['D0_subhead'] = {'n': len(idx), 'need_label_rate': need_l.float().mean().item(), 'need_acc': (need_l == need_p).float().mean().item(),
|
||||
'via1_maxjoint_err_deg_p50': pct(via_err[need_l].tolist(), .5), 'via1_maxjoint_err_deg_p90': pct(via_err[need_l].tolist(), .9)}
|
||||
# D1 不用子目标、D2 用老师真实途经点(oracle),同一批题、同一随机种子,对比 C 的基线
|
||||
def run(tag, **kw):
|
||||
rc = cc_ = 0; me = []
|
||||
for i in range(0, len(tasks), a.bs):
|
||||
ch = tasks[i:i + a.bs]; extra = dict(kw)
|
||||
if kw.get('sub_override') == 'oracle':
|
||||
subs = torch.stack([sg_by_tid[t['tid']][0] if t['tid'] in sg_by_tid else torch.zeros(2, 6, device=dev) for t in ch])
|
||||
need = torch.tensor([sg_by_tid[t['tid']][1] if t['tid'] in sg_by_tid else False for t in ch], device=dev)
|
||||
extra['sub_override'] = (subs, need)
|
||||
with torch.no_grad():
|
||||
_, pp = rollout(model, kin, ch, dev, K=8, safety=False, seed=i, **extra)
|
||||
rc += int(pp['done'].sum()); cc_ += int((pp['col'] > 0).sum()); me += pp['err'].tolist()
|
||||
out[tag] = {'reach': rc / n, 'collided': cc_ / n, 'end_goal_err_mm_p50': pct(me, .5)}
|
||||
run('D1_no_sub', use_sub=False)
|
||||
run('D2_oracle_sub', sub_override='oracle')
|
||||
s = json.dumps(out, indent=1, ensure_ascii=False); print(s)
|
||||
os.makedirs(os.path.dirname(a.out) or '.', exist_ok=True)
|
||||
open(a.out, 'w', encoding='utf-8').write(s)
|
||||
|
||||
Reference in New Issue
Block a user