Kinematic trajectory recording + post-hoc video replay (#296) - #297
Open
sibocw wants to merge 11 commits into
Open
Kinematic trajectory recording + post-hoc video replay (#296)#297sibocw wants to merge 11 commits into
sibocw wants to merge 11 commits into
Conversation
Decouple how many worlds are *simulated* from how many are *rendered*: a recorder stores only qpos (plus mocap poses) at the render cadence instead of rasterizing frames, and the trajectory is replayed to video later on CPU or GPU. This lets e.g. thousands of GPU-simulated worlds be sub-selected and rendered with a small batch, sidestepping the full RGB-tensor buffering that is hopeless at scale. Recording: - RecordedTrajectory: backend-agnostic dataclass (qpos + mocap + replay metadata); RecordedTrajectory.save/.load are one self-describing .npz each. - TrajectoryRecorder(Renderer): CPU single-world recorder. - WarpTrajectoryRecorder(_BaseWarpRenderer): GPU multi-world recorder, one RecordedTrajectory per selected world; same format as the CPU recorder. - Simulation/GPUSimulation.set_renderer(..., record_trajectory_only=True) swaps in the recorder (a recorder is a kind of renderer). Replay (model supplied by the caller, persisted separately via save_xml_with_assets): - flygym.rendering.render_trajectories(mj_model, trajectories, ...) — CPU. - flygym.warp.rendering.render_trajectories_gpu(mj_model, trajectories, ...) — GPU batch replay; bin-packs (trajectory, frame) work into mjw.Data batches of worlds_per_batch. - Both set qpos and run position-only kinematics (mj_kinematics + mj_camlight) rather than a full forward step. Serialization: save_trajectories/load_trajectories read/write a folder of individual traj_XXXX.npz files; the model is not stored with the trajectory. Refactor rendering.py and warp/rendering.py into packages, each split into live_rendering and recorded_trajectory submodules, with backward-compatible re-exports. Tests cover CPU/GPU recording, npz round-trip, CPU and GPU replay, and cross-backend kinematics identity. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
modify_world_for_batch_rendering warns as it adds overhead lights / strips textures. The GPU replay test calls it deliberately, so wrap it in warnings.catch_warnings() like the existing test_rendering.py does. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
scripts/record_replay_trajectories_gpu.py mirrors replay_behavior_gpu.py's GPU-resident captured loop but swaps the live batch renderer for a WarpTrajectoryRecorder: it simulates many worlds, records qpos for a small subset, saves the trajectories and model to disk as independent artifacts, then reloads and renders them post-hoc on GPU (and optionally CPU). This exercises the full decoupled record -> save -> replay pipeline end to end. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Record a trajectory for every simulated world (drop the recorded-subset flag / `worlds=` selection) and render all of them post-hoc in GPU batches of --worlds-per-batch (default 10) -- highlighting that the render batch size is decoupled from the simulated world count. Lower the default --n-worlds to 50 since every world is now rendered. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…ethods Now that the model is no longer saved alongside trajectories, the free functions earned their keep only as thin folder loops. Replace them with RecordedTrajectory.save() and RecordedTrajectory.from_file() (classmethod); each trajectory is one self-describing .npz. Callers that want a folder of many just loop. Updates the package re-exports, the GPU recorder error messages/docstrings, the demo script, and the tests accordingly. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Closes #296.
Decouples how many worlds are simulated from how many are rendered. Instead of rasterizing frames during simulation, a recorder stores only generalized coordinates (
qpos, plus mocap poses) at the render cadence. The trajectory is replayed to video later — on CPU or GPU. This sidesteps buffering full(n_worlds, n_cams, H, W, 3)RGB tensors, which is hopeless at thousands of worlds: simulate many in parallel, then sub-select and render a few.Architecture
Recording —
record_trajectory_only=Trueonset_rendererswaps in a recorder (a recorder is just a renderer whose per-frame output is aqposslice, not pixels):RecordedTrajectory— backend-agnostic dataclass (qpos+ optional mocap + replay metadata)..save()/.load()are one self-describing.npzeach.TrajectoryRecorder(Renderer)— CPU single-world (Simulation).WarpTrajectoryRecorder(_BaseWarpRenderer)— GPU multi-world (GPUSimulation), oneRecordedTrajectoryper selected world, identical format to the CPU recorder.Replay — set
qpos, run position-only kinematics (mj_kinematics+mj_camlight, not a full forward step), rasterize:flygym.rendering.render_trajectories(mj_model, trajectories, ...)— CPU.flygym.warp.rendering.render_trajectories_gpu(mj_model, trajectories, ...)— GPU batch replay; bin-packs(trajectory, frame)work intomjw.Databatches ofworlds_per_batch.A trajectory recorded on either backend replays on either backend (all four combinations), because it carries no trace of how it was produced.
Serialization —
save_trajectories/load_trajectorieswrite/read a folder of individualtraj_XXXX.npzfiles.Deviations from the design notes in #296
The implementation intentionally diverges from the serialization design sketched in the issue thread; see the issue comment for the full rationale. In short:
world.save_xml_with_assets(...)) and passes a compiledMjModelinto the replay functions. This is the headline signature change vs. the issue'ssave_trajectories(trajectories, mj_model, dir)/render_trajectories(source, ...).nq/nmocapshape check guards mismatches instead (robust across both).render_trajectoriesvsrender_trajectories_gpu) rather than one function with ause_gpuflag — matching theflygym/flygym.warpsplit elsewhere.render_trajectories_gpuexpects a batch-ready model (modify_world_for_batch_rendering, now exported fromflygym.warp); ause_gpu_batch_rendering=TrueGPUSimulationalready provides one.n_workersCPU multiprocessing was dropped (untested, and re-introduced a model-transport pathway); easy to restore if wanted.Refactor
rendering.pyandwarp/rendering.pybecome packages, each split intolive_renderingandrecorded_trajectorysubmodules, with backward-compatible re-exports (from flygym.rendering import Rendereretc. unchanged).docs/SUMMARY.mdupdated for the new module layout.Tests
tests/core/test_trajectory.pyandtests/warp/test_trajectory.py: CPU/GPU recording, npz round-trip, CPU and GPU replay, incompatible-model guard, and a cross-backend kinematics-identity check (geom_xposfrom CPUmj_kinematicsvs GPUmjw.kinematics). The CPU replay test asserts a bit-exact match against a qpos-consistent inline render. Full suite: 647 passed, 1 skipped; ruff clean.🤖 Generated with Claude Code