UR10e Linear Gripper β€” Jig / Bottom Enclosure β€” SimDist World Model

Latent world model pretrained in simulation with Simulation Distillation (SimDist) (arXiv:2603.15759, RSS 2026; code CLeARoboticsLab/simdist, MIT).

Status: trained. 24,797,184 simulated steps, 90,000 updates. Weights, optimizer state, configs and logs are in this repo.

What it is

A planning-oriented latent world model that predicts future latent states, rewards and values from raw (non-privileged) observations, so that a sampling-based planner can rank candidate action sequences.

z_t              = E(o_t)                       latent encoder, newest observation only
h_t              = C(o_{t-H:t-1}, a_{t-H:t-1})  history encoder β€” proprio + actions only, no images
αΊ‘_{t+1:t+T}      = f(z_t, a_{t:t+T-1}, h_t)     causal transformer, whole horizon in one pass
rΜ‚_{t:t+T-1}      = R(αΊ‘, a)                      sequence-to-sequence transformer head
vΜ‚_{t+1:t+T}      = V(αΊ‘)                         sequence-to-sequence transformer head
Γ’_{t:t+H}        = Ο€(z_t, h_t)                  base policy, action chunks to warm-start planning

Keeping images out of the history encoder is the paper's Minimal History Representation; it is what makes planning affordable. Predicting the horizon in a single forward pass, rather than unrolling, is what makes sampling thousands of candidate trajectories tractable.

Architecture

Paper Table II. Embedding dimension 64; all transformer MLPs hidden 256; dynamics 3 layers / 4 heads; reward 1 / 1; value 1 / 1; base policy 4 layers / 8 heads. Horizons H = T = 5.

The encoder passes each of three camera views through an ImageNet-pretrained ResNet-18 (shared trunk by default, 11.18 M parameters against 33.53 M for separate trunks) to 3×512, concatenates with the 20-d proprioceptive observation, and projects to the 64-d latent. The torchvision→Flax NNX weight conversion is exact: max absolute deviation 1.9e-06.

Training objective

Four terms, weighted 1 / 1 / 1 / 4:

  • latent dynamics β€” MSE against stop_grad(E(o_{t+i+1}))
  • reward β€” MSE
  • value β€” MSE against the expert critic's V
  • behaviour cloning β€” MSE, masked by the cumulative expert flag so it stops contributing the moment an environment leaves the expert

There is deliberately no pixel-reconstruction loss. The paper's ablation shows adding one drops manipulation success from 0.90 to 0.32 β€” reconstruction pressures the latent to encode randomised texture and lighting that are irrelevant to the task.

Read this before using the numbers

No success rate is reported here, and none of these numbers is comparable to the paper's Table I. Table I reports task success, which requires closed-loop rollouts under the MPPI planner. The planner exists in the port (simdist/control/mppi.py, task agnostic) but the manipulation closed-loop harness does not β€” only the locomotion one (scripts/simulate_go2.py). Everything below is a training-side proxy: latent dynamics error, head regression quality, and a value-ranking AUC.

Results at step 90,000

metric value reference
test/latent_dynamics 0.0278 paper reports 0.076 / 0.019
train/latent_dynamics 0.0343
eval/latent_rollout_error h1β†’h5 0.0164, 0.0228, 0.0283, 0.0344, 0.0385 mean 0.0281, no knee
eval/value_pearson_r 0.9510 data critic ceiling +0.953
eval/value_r2 0.9040
eval/reward_pearson_r 0.9300
eval/reward_r2 0.8641
eval/bc_action_mse 0.1188
eval/value_auc_success 0.7344 see caveat below
eval/latent_variance encoder / predicted 0.3695 / 0.3482 matched β€” no collapse, no runaway

The value head is the informative one. It regresses the data-generating critic's output, so that critic's own correlation (r = +0.953 against bootstrapped return-to-go) is a ceiling it cannot meaningfully exceed. At 0.951 it has essentially reached it.

The AUC is optimistic. eval.episodes.holdout is 0, so the train/test split is at the chunk level and no episode is fully unseen β€” the AUC has a step-level leak. eval/value_auc_holdout_episodewise: 0 records that regime. It is also computed over only 32 episodes.

Stability across training

Early rows were transcribed from live reads during the run; auto-park pulled only the log tail, so the shipped logs/train_metrics.txt starts at step 77500.

step latent_dynamics encoder variance lr value AUC
2500 0.424 0.309 5.0e-5 0.766
5000 0.080 0.243 1.0e-4 0.684
7500 0.084 0.245 1.5e-4 0.731
10000 0.076 0.336 2.0e-4 (peak) 0.773
90000 0.034 0.369 1.0e-4 0.734

Encoder variance staying flat through and past peak LR is the load-bearing observation β€” see the divergence section.

The divergence, and the deviation it forced

The first attempt at this run diverged and had to be thrown away. latent_dynamics went 9.37 β†’ 8.62 β†’ 3.0e20 over steps 2500/5000/7500 and settled near 1e28, while reward, value and action losses stayed bounded at 0.5–2.7 the whole time. latent_variance/encoder tracked it exactly: 0.97 β†’ 2.88 β†’ 3.1e13 β†’ 1.6e25.

The cause is a degenerate direction in the latent objective. The dynamics target is stop_gradient(encode_latent(...)), but it is produced by the same online encoder β€” an encoder that grows also grows its own target. stop_gradient bounds the gradient path, not the magnitude. Nothing in the loss penalises β€–zβ€–, and the encoder's latent_mlp ends in a free linear map, so β€–zβ€– is free to run away. The optimizer was bare optax.adam, with global_norm computed for logging and never applied, so nothing bounded the rate either.

Two fixes were probed at peak LR 2e-4 held for 4000 steps (warmup compressed to 1000):

configuration latent_dynamics encoder variance value AUC
gradient clipping only 5.4 β†’ 9.4e6 0.99 β†’ 1.1e4 0.80 β†’ 0.57
clipping + latent LayerNorm 0.63 β†’ 0.063 pinned 0.12–0.45 ~0.70–0.80

Clipping alone only bounds how fast the run travels the degenerate direction. The LayerNorm removes it. This model therefore uses a LayerNorm on the encoder latent, which the paper does not describe β€” an explicit deviation, exposed as model.encoder.latent_norm (default false, the paper's architecture) rather than hardcoded. Whether this is an undocumented detail of the reference implementation or a mis-port has not been checked against the reference code.

Deviations from the paper

  • Latent LayerNorm β€” added, as above. The substantive one.
  • Gradient clipping at global norm 1.0. The paper logs grad_norm and does not apply it.
  • 90,000 updates, roughly 1.06 epochs, against the paper's ~194.5 k / 2 epochs. A budget decision: per Table I, data scale dominates and epochs are secondary, so the full dataset with fewer passes is the better trade under a cap.
  • H = T = 5, not the paper's 25. Deliberate and documented in the port: this policy runs at 10 Hz, so 5 steps is 0.5 s of history and prediction β€” the timescale an insertion evolves on. 25 would be 2.5 s.
  • No pixel-reconstruction loss and no image decoder, matching the paper (Table I: adding reconstruction as an objective is 0.90 β†’ 0.32).

Training

python scripts/train_model.py \
  model=manipulator_world_model system=omnireset_ur10e \
  data.dataset_name=simdist_merged data.num_train_workers=32 data.num_test_workers=4 \
  training.batch_size=256 training.max_steps=90000 training.warmup_steps=10000 \
  training.decay_steps=90000 training.eval_interval=2500 \
  training.grad_clip_norm=1.0 model.encoder.latent_norm=true \
  checkpoint.enabled=True checkpoint.max_to_keep=5 \
  run_name=simdist_ur10e_24m_v2

Adam, cosine 2e-4 β†’ 1e-4 with 10 k warmup. Loss weights 1/1/1/4 (latent dynamics / reward / value / behaviour cloning, the last masked by the cumulative expert flag). One RTX 5090, 2.26 updates/s, 11.9 h, GPU util 97 %, dataloader_wait_frac 0.015.

Contents: checkpoint/ is an orbax checkpoint including optimizer state (resumable); config/ holds the model, system and training configs; logs/ and metrics.json hold the eval history that survived.

Data

24,797,184 steps, 155,370 episodes, 843 shards merged from 116 independent generation runs (37.2 h on one RTX 5090, 174 rows/s). Three RGB views at 160Γ—120 (front, side, wrist), JPEG q90, plus 20-d proprioception and 7-d relative Cartesian OSC actions. expert_prob 0.5, sub-optimal actions drawn from a 37-checkpoint ladder, visual and physics domain randomisation on.

The dataset is not published. It lived on rented storage that was released at the end of the campaign; only the model and its logs were retained.

Known data defects

Both are recorded because they affect anyone reproducing this, and neither caused the divergence above (reward and value losses stayed bounded throughout):

  • Value outliers. 0.116 % of rows have value < βˆ’20, p0.01 = βˆ’94.97, against mean 8.87 and std 4.00 β€” a βˆ’28Οƒ target after scaling. This matches an MDP-mismatch signature seen earlier in the project (V^e βˆ’98 vs +8.95).
  • Action outliers. ee_delta_* are expected to be order ~1, but per-dimension absolute maxima reach 3788 while p99.9 is only 12–37, inflating actions.std to 7.2–13.7.

A further note for reproducers: episode_ids from the generator is a per-environment counter that restarts at 0 in every process, so merging N generation runs puts N distinct episodes under (env 0, episode 0). They must be namespaced per source run before processing, or the episode stitcher will refuse the merged set.

Intended use

Sim-only evaluation: held-out prediction losses, latent rollout error against horizon, reward and value calibration, and MPPI planning in simulation. Real-world deployment and dynamics finetuning (SimDist stages 4a/4b) are out of scope for this release and have not been validated.

Licence

MIT, following upstream SimDist.

Downloads last month

-

Downloads are not tracked for this model. How to track
Video Preview
loading

Paper for RubetekRobotics/UR10e-LinearGripper-Jig-SimDist-WorldModel