xwm.dynamics¶
(z, a) → z', the centre of the library. Every family consumes a dynamics model from here; every planner consumes nothing else.
Action-conditioned latent dynamics -- the heart of a robotics world model.
(z, a) -> z' in latent space, shared by every family: JEPA's V-JEPA 2-AC
stage, TD-MPC2's consistency loss, and MuZero's recurrent unroll all consume a
model from here. Which one you pick is a compute/expressivity trade, not an
algorithmic commitment:
ActionConditionedPredictor-- a transformer over the token grid. Expressive, and the right choice when the latent is a sequence of patch tokens.MLPDynamics-- a residual MLP on a pooled latent. Far cheaper, and what TD-MPC2 and MuZero actually use, because they run it thousands of times inside a planner.
Modules:
| Name | Description |
|---|---|
action_conditioned |
Action-conditioned latent dynamics. |
action_embed |
Action encoders. |
mlp_dynamics |
A residual MLP latent dynamics model. |
Classes:
| Name | Description |
|---|---|
ActionConditionedPredictor |
|
ContinuousActionEmbed |
Embed a continuous action vector with a small MLP. |
DiscreteActionEmbed |
Embed a discrete action index with a lookup table. |
PoseActionEmbed |
Embed a rigid-body pose delta, splitting translation from rotation. |
MLPDynamics |
|
ActionConditionedPredictor
¶
ActionConditionedPredictor(grid: tuple[int, ...], embed_dim: int, action_embed: ActionEmbed, *, pred_dim: int, depth: int, num_heads: int, key: PRNGKey | None = None, conditioning: Conditioning = 'both', residual: bool = True, pos: Literal['sincos', 'learned', 'none'] = 'sincos', mlp_ratio: float = 4.0, dropout: float = 0.0, drop_path: float = 0.0, layer_scale: float | None = None, remat: bool = False)
Bases: Module
(z, a) -> z' over a token grid, satisfying LatentDynamics.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
grid
|
tuple[int, ...]
|
token grid of the latent state. |
required |
embed_dim
|
int
|
encoder width (input and output). |
required |
action_embed
|
ActionEmbed
|
how the action becomes a vector. |
required |
pred_dim
|
int
|
internal width. |
required |
depth, num_heads
|
transformer size. |
required | |
conditioning
|
Conditioning
|
how the action reaches the tokens.
|
'both'
|
residual
|
bool
|
predict the change in latent state rather than the next
state outright. On by default: consecutive latents are nearly
identical, so starting close to the identity map is a far better
prior than starting from noise. The output projection is scaled down
by |
True
|
pos
|
Literal['sincos', 'learned', 'none']
|
positional scheme (additive only -- the action token has no grid position, so rotary embeddings do not apply here). |
'sincos'
|
Source code in xwm/dynamics/action_conditioned.py
75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 | |
ContinuousActionEmbed
¶
ContinuousActionEmbed(action_dim: int, embed_dim: int, *, key: PRNGKey | None = None, hidden_dim: int | None = None, scale: float = 1.0)
Bases: Module
Embed a continuous action vector with a small MLP.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
action_dim
|
int
|
dimensionality of the raw action. |
required |
embed_dim
|
int
|
output width. |
required |
scale
|
float
|
divide the action by this before embedding. Set it to the action's typical magnitude; an unnormalised action of magnitude 100 will otherwise dominate the conditioning signal. |
1.0
|
Source code in xwm/dynamics/action_embed.py
DiscreteActionEmbed
¶
Bases: Module
Embed a discrete action index with a lookup table.
Source code in xwm/dynamics/action_embed.py
PoseActionEmbed
¶
PoseActionEmbed(embed_dim: int, *, key: PRNGKey | None = None, translation_dim: int = 3, rotation_dim: int = 3, extra_dim: int = 0)
Bases: Module
Embed a rigid-body pose delta, splitting translation from rotation.
End-effector actions mix units -- metres and radians -- and a single linear layer has to learn to rescale them. Embedding the parts separately removes that burden, which matters when translations are centimetre-scale.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
translation_dim
|
int
|
usually 3. |
3
|
rotation_dim
|
int
|
3 for axis-angle / Euler, 4 for a quaternion, 6 for the continuous 6-D rotation parameterisation. |
3
|
extra_dim
|
int
|
remaining scalars, e.g. a gripper command. |
0
|
Source code in xwm/dynamics/action_embed.py
MLPDynamics
¶
MLPDynamics(latent_dim: int, action_dim: int, *, key: PRNGKey | None = None, hidden_dim: int = 512, depth: int = 2, residual: bool = True, normalize: Normalization = 'simnorm', simnorm_groups: int = 8)
Bases: Module
(z, a) -> z' as a residual MLP on a flat latent.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
latent_dim
|
int
|
width of the latent vector. |
required |
action_dim
|
int
|
width of the action vector (continuous), or the embedding width if you embed a discrete action before calling. |
required |
hidden_dim
|
int
|
MLP width. |
512
|
depth
|
int
|
number of hidden layers. |
2
|
residual
|
bool
|
predict the change rather than the next state. Consecutive latents are nearly identical, so starting near the identity is a far better prior than starting from noise. |
True
|
normalize
|
Normalization
|
what to apply to the output latent.
|
'simnorm'
|
simnorm_groups
|
int
|
group size for SimNorm; |
8
|