perf+exp(closed_loop): 解析雅可比 DLS(消除 float32 差分数值噪声)——commit3 到达 36.3→46.5%,commit2 49.2%(n=512),DLS n1 9.3→7.1ms
- Kin.jac 几何雅可比,与 autograd 逐项一致(FD 自身 rel 误差 3.58%) - dls_steps(analytic=True) 默认;每步少 6 次批量 FK - 新增 ml/eval/eval_cl.py(部署口径小规模评估)与 check_dls.py(对拍+延迟) - 积分反馈 fb_ki 脚手架(默认 0,未启用)
This commit is contained in:
@@ -0,0 +1,54 @@
|
||||
"""DLS 解析雅可比对拍 + 延迟(python -m ml.eval.check_dls)"""
|
||||
import time
|
||||
import torch
|
||||
|
||||
from ml.common.kin_torch import Kin
|
||||
from ml.sim.closed_loop import dls_steps
|
||||
|
||||
|
||||
def main():
|
||||
dev = 'cuda' if torch.cuda.is_available() else 'cpu'
|
||||
kin = Kin(device=dev)
|
||||
g = torch.Generator(device=dev); g.manual_seed(0)
|
||||
B = 64
|
||||
lo, hi = kin.lo + 20, kin.hi - 20
|
||||
q = lo + (hi - lo) * torch.rand(B, 6, device=dev, generator=g)
|
||||
xf = kin.cum_xf(q)
|
||||
p = kin.fk(q, xf)
|
||||
T = p + 6 * torch.randn(B, 3, device=dev, generator=g)
|
||||
R = torch.zeros(B, 9, device=dev)
|
||||
a = dls_steps(kin, q, T, R, n=3, analytic=True)
|
||||
b = dls_steps(kin, q, T, R, n=3, analytic=False)
|
||||
d = (a - b).abs()
|
||||
print('pos-only max|Δdq| %.6f° mean %.6f° rel %.4f' % (d.max().item(), d.mean().item(), (d.norm() / b.norm()).item()))
|
||||
# 带姿态目标:绕随机轴 ±8°
|
||||
axis = torch.randn(B, 3, device=dev, generator=g); axis = axis / axis.norm(dim=-1, keepdim=True)
|
||||
ang = (torch.rand(B, 1, device=dev, generator=g) * 16 - 8) * torch.pi / 180
|
||||
Kx = torch.zeros(B, 3, 3, device=dev)
|
||||
Kx[:, 0, 1] = -axis[:, 2]; Kx[:, 0, 2] = axis[:, 1]; Kx[:, 1, 0] = axis[:, 2]
|
||||
Kx[:, 1, 2] = -axis[:, 0]; Kx[:, 2, 0] = -axis[:, 1]; Kx[:, 2, 1] = axis[:, 0]
|
||||
I = torch.eye(3, device=dev)
|
||||
Rd = I + torch.sin(ang)[..., None] * Kx + (1 - torch.cos(ang))[..., None] * (Kx @ Kx)
|
||||
Rt = kin.orient(q, xf) @ Rd
|
||||
R9 = Rt.reshape(B, 9)
|
||||
a = dls_steps(kin, q, T, R9, n=3, analytic=True)
|
||||
b = dls_steps(kin, q, T, R9, n=3, analytic=False)
|
||||
d = (a - b).abs()
|
||||
print('pos+rot max|Δdq| %.6f° mean %.6f° rel %.4f' % (d.max().item(), d.mean().item(), (d.norm() / b.norm()).item()))
|
||||
|
||||
for n_ in (1, 3):
|
||||
for Bn in (1, 256):
|
||||
qq = q[:Bn]; TT = T[:Bn]; RR = R9[:Bn]
|
||||
for an in (False, True):
|
||||
for _ in range(3):
|
||||
dls_steps(kin, qq, TT, RR, n=n_, analytic=an)
|
||||
torch.cuda.synchronize() if dev == 'cuda' else None
|
||||
t0 = time.perf_counter()
|
||||
for _ in range(20):
|
||||
dls_steps(kin, qq, TT, RR, n=n_, analytic=an)
|
||||
torch.cuda.synchronize() if dev == 'cuda' else None
|
||||
print('n=%d B=%3d analytic=%d %.2f ms' % (n_, Bn, an, (time.perf_counter() - t0) / 20 * 1e3))
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
||||
@@ -0,0 +1,75 @@
|
||||
"""小规模闭环评估(部署口径):
|
||||
python -m ml.eval.eval_cl --n 256 --commit 3 --fb 1.8 --partial [--ki 0.1 --select consist]
|
||||
输出:到达 / 碰撞 / ratio2s / 刹停 / 精修接管 / 墙钟。直接调 rollout,参数与部署一致。"""
|
||||
import argparse, functools, json, time
|
||||
import torch
|
||||
|
||||
from ml.common.ckpt import load_policy
|
||||
from ml.common.kin_torch import Kin
|
||||
from ml.data import load_tasks
|
||||
from ml.sim.closed_loop import rollout
|
||||
import ml.sim.closed_loop as clmod
|
||||
|
||||
|
||||
def run(model, kin, tasks, device, bs=256, **kw):
|
||||
agg, per = {}, []
|
||||
for i in range(0, len(tasks), bs):
|
||||
r, p = rollout(model, kin, tasks[i:i + bs], device, **kw)
|
||||
per.append((r, p, len(tasks[i:i + bs])))
|
||||
n = sum(w for _, _, w in per)
|
||||
for r, _, w in per:
|
||||
for k, v in r.items():
|
||||
if k in ('n', 'time_budget') or v is None: continue
|
||||
agg[k] = agg.get(k, 0.0) + v * w
|
||||
out = {k: v / n for k, v in agg.items()}; out['n'] = n
|
||||
out['goal_ratio_2s'] = torch.cat([p['goal_ratio_2s'] for _, p, _ in per]).median().item()
|
||||
out['err_fail_med'] = torch.cat([p['err'] for _, p, _ in per])[~torch.cat([p['ok'] for _, p, _ in per])].median().item()
|
||||
out['dls_share'] = torch.cat([p['dls_it'] for _, p, _ in per]).ge(0).float().mean().item()
|
||||
out['time_budget'] = per[0][0]['time_budget']
|
||||
return out
|
||||
|
||||
|
||||
def main():
|
||||
ap = argparse.ArgumentParser()
|
||||
ap.add_argument('--ckpt', default='ml/runs/base_dag2_dag1/best.pt')
|
||||
ap.add_argument('--samples', default='ml/data/samples')
|
||||
ap.add_argument('--tasks', default=None)
|
||||
ap.add_argument('--split', default='val')
|
||||
ap.add_argument('--n', type=int, default=256)
|
||||
ap.add_argument('--K', type=int, default=8)
|
||||
ap.add_argument('--commit', type=int, default=3)
|
||||
ap.add_argument('--fb', type=float, default=1.8)
|
||||
ap.add_argument('--ki', type=float, default=0.0)
|
||||
ap.add_argument('--kdecay', type=float, default=0.9)
|
||||
ap.add_argument('--kimax', type=float, default=0.5)
|
||||
ap.add_argument('--select', default='consist')
|
||||
ap.add_argument('--replan', default='r3')
|
||||
ap.add_argument('--safety', type=int, default=1, help='1=安全层+部分前缀;0=关')
|
||||
ap.add_argument('--partial', type=int, default=1)
|
||||
ap.add_argument('--max_sec', type=float, default=None)
|
||||
ap.add_argument('--seed', type=int, default=0)
|
||||
ap.add_argument('--dls', default='analytic', choices=['analytic', 'fd'])
|
||||
ap.add_argument('--device', default='cuda' if torch.cuda.is_available() else 'cpu')
|
||||
a = ap.parse_args()
|
||||
if a.dls == 'fd':
|
||||
clmod.dls_steps = functools.partial(clmod.dls_steps, analytic=False)
|
||||
model, ck = load_policy(a.ckpt, a.device)
|
||||
kin = Kin(device=a.device)
|
||||
assert ck.get('fp') in (None, kin.fp)
|
||||
tasks = ([json.loads(l) for l in open(a.tasks, encoding='utf-8') if l.strip()] if a.tasks
|
||||
else [t for t in load_tasks([a.samples]) if t['split'] == a.split])
|
||||
tasks = tasks[:a.n]
|
||||
t0 = time.perf_counter()
|
||||
r = run(model, kin, tasks, a.device, K=a.K, safety=bool(a.safety), seed=a.seed, max_sec=a.max_sec,
|
||||
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_ki=a.ki, fb_decay=a.kdecay, fb_imax=a.kimax)
|
||||
wall = time.perf_counter() - t0
|
||||
print('ckpt=%s n=%d K=%d commit=%d fb=%.2f ki=%.2f select=%s replan=%s safety=%d' %
|
||||
(a.ckpt, r['n'], a.K, a.commit, a.fb, a.ki, a.select, a.replan, a.safety))
|
||||
print('success %.3f time_ok_1p3 %.3f coll %.3f ratio2s %.3f brakes %.1f dls_share %.3f err_fail %.2f wall %.1fs (%.0f ms/题)'
|
||||
% (r['success'], r['time_ok_1p3'] or 0, r['collision_rate'], r['goal_ratio_2s'], r['brakes_mean'],
|
||||
r['dls_share'], r['err_fail_med'], wall, wall / max(1, len(tasks)) * 1000))
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
||||
Reference in New Issue
Block a user