diag: F 段——MeanFlow 一步采样残留噪声(开环 1/2/4/8 段与零噪声的幅度/抖动/残差-噪声相关;闭环 4 段、零噪声);sample_k 加 steps、rollout 加 steps/z_scale;删 E 段;本机执行清单更新
This commit is contained in:
+31
-54
@@ -8,8 +8,7 @@
|
||||
B. 同一噪声下,用两份特征得到的动作差(16 步末端关节差,度)——A 有差但 B 很小说明差异无害;
|
||||
C. 闭环失败形态:首次碰撞时刻分布、碰撞步数、首次碰撞的组对、全程最小目标误差、目标误差进度比;
|
||||
以及同一批题开安全层(safety=True,近似部署)的到达率 / 刹停次数。
|
||||
E. 速度:开环动作幅度 / 老师幅度、抹掉 dq 后的幅度(是否「抄上一帧速度」);
|
||||
从老师轨迹中段起步的闭环,带老师速度 vs 静止起步(是否只坏在起步)。
|
||||
F. 一步采样残留噪声:开环比较 1/2/4/8 段采样与零噪声的幅度、抖动、残差与噪声相关;闭环用 4 段采样、零噪声各跑一遍。
|
||||
用法(仓库根目录):
|
||||
PYTHONUTF8=1 python -m ml.eval.diag_cl --ckpt ml/runs/base/last.pt --n 256 --out ml/runs/diag_cl.json
|
||||
"""
|
||||
@@ -124,65 +123,43 @@ def main():
|
||||
'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 = 在靠近目标
|
||||
|
||||
# ---------- E:速度与「抄速度」(2026-10-19 加) ----------
|
||||
# 上一轮 D 段:不用子目标 / 用老师真实途经点,结果与基线完全一样(0% / 99.6%),子目标排除。
|
||||
# C 段 2 s 只把目标误差缩小 18.5%:方向对、但走得极慢。开环(数据集里的老师状态)却几乎精确。
|
||||
# 嫌疑:特征里的 dq(上一帧速度)在老师数据里总是满速,模型学会「照上一帧速度往下走」;
|
||||
# 闭环从静止起步 dq=0,模型就给小动作,小动作又喂回 dq,一直慢,慢慢挤进自碰撞。
|
||||
# ---------- F:一步采样残留噪声(2026-10-19 加) ----------
|
||||
# 前几轮:子目标、抄速度、起步都已排除;但动作幅度在开环、起点、闭环三处一致是老师的 1.4–1.6 倍,
|
||||
# 而开环 16 步末端 FK 误差只有 ~6 mm。幅度大、终点却准 = 每步动作里叠着来回抵消的抖动。
|
||||
# 嫌疑:MeanFlow 一步生成 x = z − u(z,0,1) 没把噪声 z 去干净(只有 25% 样本学区间平均速度、14k 步),
|
||||
# 闭环每次只执行前 3 步,抖动不抵消,表现为「动得多、走得少」,再挤进碰撞。
|
||||
# F0:开环 val 随机 4096 行,比较 1/2/4/8 段采样和零噪声(z=0):幅度比、抖动比、残差与 z 的相关、前 3 步与 16 步末关节误差
|
||||
# F1:同一批闭环题,用 4 段采样、零噪声各跑一遍,对比 C 的基线
|
||||
stepv = torch.tensor(STEP, device=dev)
|
||||
gen = torch.Generator(device=dev).manual_seed(11)
|
||||
# E0:开环,val 全部时刻随机 4096 行。动作幅度 / 老师幅度;把 dq 抹成 0 后幅度与 16 步末端差
|
||||
ri = torch.randperm(vd.X.shape[0], generator=torch.Generator().manual_seed(3))[:4096].to(dev)
|
||||
Xr, Yr = vd.X[ri].float(), vd.Y[ri].float()
|
||||
zr = torch.randn(len(ri), 1, H, 6, device=dev, generator=gen)
|
||||
def amp(X):
|
||||
with torch.no_grad(): ac, _, _ = model.sample_k(X, 1, zr)
|
||||
return ac[:, 0].clamp(-1, 1)
|
||||
a_full = amp(Xr); X0dq = Xr.clone(); X0dq[:, 15:21] = 0; a_0dq = amp(X0dq)
|
||||
ymag = Yr.abs().mean().item()
|
||||
moving = Xr[:, 15:21].abs().max(-1).values > 0.3 # 老师此刻在动(|dq| > 30% 满速)
|
||||
out['E0_openloop'] = {'n': len(ri), 'teacher_amp': ymag, 'policy_amp_ratio': a_full.abs().mean().item() / ymag,
|
||||
'dq_zeroed_amp_ratio': a_0dq.abs().mean().item() / ymag,
|
||||
'dq_zeroed_amp_ratio_on_moving_rows': a_0dq[moving].abs().mean().item() / max(1e-6, Yr[moving].abs().mean().item()),
|
||||
'dq_zeroed_end_diff_deg_p50': pct(((a_full - a_0dq) * stepv).sum(1).abs().max(-1).values.tolist(), .5),
|
||||
'start_rows_amp_ratio': None}
|
||||
st = first.nonzero().flatten()[:4096]
|
||||
with torch.no_grad(): a_st, _, _ = model.sample_k(vd.X[st].float(), 1, torch.randn(len(st), 1, H, 6, device=dev, generator=gen))
|
||||
out['E0_openloop']['start_rows_amp_ratio'] = a_st.clamp(-1, 1).abs().mean().item() / max(1e-6, vd.Y[st].float().abs().mean().item())
|
||||
# E1:从老师轨迹中段(每题第 30% 行)起步闭环,带老师上一帧速度 vs 静止起步,同一批题同一噪声
|
||||
tid_all = vd.TID.long(); starts = first.nonzero().flatten().tolist() + [len(tid_all)]
|
||||
mid_rows = []
|
||||
for s0, s1 in zip(starts[:-1], starts[1:]):
|
||||
if int(tid_all[s0]) in by_tid and s1 - s0 >= 4: mid_rows.append(s0 + int(0.3 * (s1 - s0)))
|
||||
mid_rows = mid_rows[:a.n]
|
||||
Xm = vd.X[mid_rows].float()
|
||||
qm = torch.atan2(Xm[:, 0:12:2], Xm[:, 1:12:2]) * 180 / torch.pi
|
||||
qm = torch.where(kin.cont, qm, kin.clamp_box(qm))
|
||||
qpm = qm - Xm[:, 15:21] * stepv
|
||||
mtasks = []
|
||||
for r_, q_ in zip(mid_rows, qm.tolist()):
|
||||
t = dict(by_tid[int(tid_all[r_])]); t['q0'] = q_; t['exec_s'] = float(vd.V[r_]) * 5; mtasks.append(t)
|
||||
rem = [t['exec_s'] for t in mtasks]
|
||||
ym = vd.Y[mid_rows].float().abs().mean().item()
|
||||
for tag, use_v in (('E1_mid_teacher_vel', True), ('E1_mid_zero_vel', False)):
|
||||
rc = cc_ = 0; ratio1 = []; spd = []
|
||||
for i in range(0, len(mtasks), a.bs):
|
||||
ch = mtasks[i:i + a.bs]
|
||||
zr = torch.randn(len(ri), 1, H, 6, device=dev, generator=torch.Generator(device=dev).manual_seed(11))
|
||||
ymag = Yr.abs().mean().item(); yjit = (Yr[:, 1:] - Yr[:, :-1]).abs().mean().item()
|
||||
f0 = {'teacher_amp': ymag, 'teacher_jitter': yjit}
|
||||
for tag, steps, zs in (('1step', 1, 1.0), ('2step', 2, 1.0), ('4step', 4, 1.0), ('8step', 8, 1.0), ('1step_z0', 1, 0.0)):
|
||||
with torch.no_grad(): ac, _, _ = model.sample_k(Xr, 1, zr * zs, steps=steps)
|
||||
ac = ac[:, 0]; acc = ac.clamp(-1, 1); res = ac - Yr
|
||||
zc = zr[:, 0] - zr[:, 0].mean(); rc_ = res - res.mean()
|
||||
corr = ((zc * rc_).sum() / (zc.pow(2).sum().sqrt() * rc_.pow(2).sum().sqrt()).clamp(min=1e-9)).item() if zs > 0 else None
|
||||
e3 = ((acc[:, :3] - Yr[:, :3]) * stepv).sum(1).abs().max(-1).values
|
||||
e16 = ((acc - Yr) * stepv).sum(1).abs().max(-1).values
|
||||
f0[tag] = {'amp_ratio': acc.abs().mean().item() / ymag, 'jitter_ratio': (acc[:, 1:] - acc[:, :-1]).abs().mean().item() / yjit,
|
||||
'resid_corr_z': corr, 'first3_err_deg_p50': pct(e3.tolist(), .5), 'end16_err_deg_p50': pct(e16.tolist(), .5)}
|
||||
out['F0_openloop_sampler'] = f0
|
||||
for tag, kw in (('F1_4step', {'steps': 4}), ('F1_z0', {'z_scale': 0.0})):
|
||||
rc = cc_ = 0; me = []; r2 = []
|
||||
for i in range(0, len(tasks), a.bs):
|
||||
ch = tasks[i:i + a.bs]
|
||||
with torch.no_grad():
|
||||
_, pp = rollout(model, kin, ch, dev, K=8, safety=False, seed=i, return_traj=True,
|
||||
qp0=qpm[i:i + a.bs] if use_v else None)
|
||||
_, pp = rollout(model, kin, ch, dev, K=8, safety=False, seed=i, return_traj=True, **kw)
|
||||
tr = pp['traj'].to(dev); B, Tn, _ = tr.shape
|
||||
k1 = min(Tn - 1, int(round(1.0 / DT)))
|
||||
k2 = min(Tn - 1, int(round(2.0 / DT)))
|
||||
Tt = torch.tensor([t['T'] for t in ch], dtype=torch.float32, device=dev)
|
||||
Rt = torch.tensor([t['R'] if t.get('R') else [0.] * 9 for t in ch], dtype=torch.float32, device=dev)
|
||||
e0, _ = goal_err(kin, tr[:, 0], Tt, Rt); e1, _ = goal_err(kin, tr[:, k1], Tt, Rt)
|
||||
ratio1 += (e1 / e0.clamp(min=1e-3)).tolist()
|
||||
dd = (tr[:, 1:k1 + 1] - tr[:, :k1]) / stepv
|
||||
spd.append(dd.abs().mean().item())
|
||||
rc += int(pp['done'].sum()); cc_ += int((pp['col'] > 0).sum())
|
||||
nm = len(mtasks)
|
||||
out[tag] = {'n': nm, 'teacher_remaining_s_p50': pct(rem, .5), 'reach': rc / nm, 'collided': cc_ / nm,
|
||||
'goal_err_ratio_1s_p50': pct(ratio1, .5), 'speed_ratio_first_1s': sum(spd) / len(spd) / max(1e-6, ym)}
|
||||
e0, _ = goal_err(kin, tr[:, 0], Tt, Rt); e2, _ = goal_err(kin, tr[:, k2], Tt, Rt)
|
||||
r2 += (e2 / e0.clamp(min=1e-3)).tolist()
|
||||
rc += int(pp['done'].sum()); cc_ += int((pp['col'] > 0).sum()); me += pp['err'].tolist()
|
||||
out[tag] = {'reach': rc / n, 'collided': cc_ / n, 'goal_err_ratio_2s_p50': pct(r2, .5), 'end_goal_err_mm_p50': pct(me, .5)}
|
||||
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