Files
hand-motion-pipeline/scripts/check_spider_dynamics_replay.py
liyang ae28d55f81 Update to 2026-09-17 pipeline snapshot; add weights, L20 assets and recording via Git LFS
Source: RGB-D -> Dyn-HaMR -> L20 retargeting -> FoundationPose -> reference repair -> SPIDER,
documented in docs/PIPELINE_LATEST.md and docs/SETUP_AND_WEIGHTS.md. Adds FoundationPose and
nvdiffrast upstream snapshots, requirements/pipeline_venv.txt and the FoundationPose weight
manifest/downloader.

Assets (Git LFS): weights/ (WiLoR detector, HandFlow denoiser, UniDepth-L), FoundationPose
checkpoints, HaMeR checkpoint, Dyn-HaMR HMP model and BMC constraints, L20 URDF/meshes, the
20260915_171525 D405 recording and the two box CADs. MANO models are not redistributed
(third_party/hamer/_DATA/data/mano/README.txt). Environments, caches and run outputs excluded.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-09-17 11:43:37 +08:00

20 lines
2.3 KiB
Python

"""Compare saved controls in fresh GPU worlds and CPU, without optimization."""
import os,json
from pathlib import Path
ROOT=Path(__file__).resolve().parents[1]
os.environ['WARP_CACHE_PATH']=str(ROOT/'.spider_cache/warp');os.environ['OMP_NUM_THREADS']='4'
import numpy as np,mujoco,mujoco_warp as mw,warp as wp
O=Path(os.environ.get('SPIDER_TASK_OUT',str(ROOT/'output/spider_dynamics_fix_20260915')));T=O/'datasets/processed/current/l20/bimanual/boxes'
a=np.load(T/'0/trajectory_mjwp_act.npz');r=np.load(T/'0/trajectory_kinematic_act.npz');rq,rv,rc=(r[k] for k in ['qpos','qvel','ctrl']);u=a['ctrl'].reshape(-1,56);expected=a['qpos'].reshape(-1,66)
m=mujoco.MjModel.from_xml_path(str(T/'scene_act.xml'));settings=json.loads((O/'physics_parameters.json').read_text());m.opt.iterations=settings['solver_iterations'];m.opt.ls_iterations=settings['ls_iterations'];m.opt.timestep=.0025;m.opt.integrator=mujoco.mjtIntegrator.mjINT_IMPLICITFAST;m.opt.o_solref[:]=[.02,1];m.opt.o_solimp[:]=[0,.95,.03,.5,2]
assert not m.actuator_gainprm[-12:].any() and not m.actuator_biasprm[-12:].any()
d=mujoco.MjData(m);d.qpos[:]=rq[0].astype(np.float32);d.qvel[:]=rv[0].astype(np.float32);d.ctrl[:]=rc[0].astype(np.float32);mujoco.mj_step(m,d)
wp.init();gpu=[];cpu=[]
with wp.ScopedDevice('cuda:0'):
wm=mw.put_model(m);wd=mw.put_data(m,d,nworld=64,nconmax=1024,njmax=3072)
with wp.ScopedCapture() as capture:mw.step(wm,wd)
for i,ctrl in enumerate(u):
wd.ctrl.assign(np.tile(ctrl.astype(np.float32),(64,1)));wp.capture_launch(capture.graph);wp.synchronize();gpu.append(wd.qpos.numpy()[0].copy());d.ctrl[:]=ctrl;mujoco.mj_step(m,d);cpu.append(d.qpos.copy())
gpu=np.array(gpu);cpu=np.array(cpu);diff=np.abs(gpu-expected);reports={'steps':len(u),'all_finite':bool(np.isfinite(gpu).all() and np.isfinite(cpu).all()),'zero_object_assistance':True,'gpu_first_step_max_qpos_difference':float(diff[0].max()),'gpu_max_qpos_difference':float(diff.max()),'cpu_gpu_max_qpos_difference':float(np.abs(cpu-gpu).max()),'note':'qpos differences mix meters and radians; 64 fresh duplicate worlds, same model/initial state/controls'}
np.savez_compressed(O/'control_replay.npz',gpu=gpu,cpu=cpu,expected=expected,ctrl=u,time=a['time'].ravel());(O/'control_replay.json').write_text(json.dumps(reports,indent=2));print(json.dumps(reports,indent=2))