Learning Latent Dynamics
The agent squeezes camera frames into a small code and imagines futures in that code instead of predicting pixels, so planning runs thousands of rollouts per second.
Why Does This Exist?
A visual agent sees frames, about 12,000 numbers per step. Predicting the next full frame with a deconvolutional decoder at every planning step is slow, and most pixels are distractors like clouds or reflections. Small blur compounds too, so a 50 step pixel rollout melts into gray static.
Model-based RL plans with a learned model instead of the real world. This page covers the compact version of that idea: learn transitions between small latent codes, train with a variational bottleneck, then imagine in latent space only. Dreamer is the full agent that uses this trick to learn behavior inside its own imagination. Planning with learned models shows how those imagined rollouts turn into actions.
The one idea you need first
A latent state is a compressed code that keeps what matters for control and drops the rest. An encoder maps observation to code, a dynamics model maps to next code , and a small head predicts reward . The full treatment of planning with such a model is in model-based RL.
Think of It Like This
Chess in your head, not photos of the board
You play a blindfold chess game. You do not picture wood grain, lamp glare, or your opponent hands. You track a short list: piece squares, whose turn, king safety, open files. You try a line five moves deep inside that list and pick the move that looks best.
Latent dynamics works the same way. The frame is the photo. The latent code is the piece list. The prior is your guess of the next position without looking. The posterior is the updated list after you glance at the board. Imagination is playing lines without touching pieces.
Where it stops: you arrive with a lifetime of knowing what a knight is. The agent starts with zero priors, so a naive compressor can throw away a tiny but vital cue before it learns its value.
How It Actually Works
PlaNet and Dreamer package this as the Recurrent State Space Model, or RSSM. Call the deterministic history kept by a recurrent cell, the stochastic belief about the present, the frame, the action, the encoded frame. The posterior sees the frame. The prior guesses without it.
In words: carries memory, carries uncertainty, is belief with evidence, is belief from memory alone. Training pushes toward so imagination matches reality.
The training objective
Parameters fit the variational lower bound over horizon :
The first two terms force the code to reconstruct frames and rewards. The term is the bottleneck that keeps imagination honest. Once trained, the policy rolls out with only, predicts rewards and values , and never decodes a pixel.
Worked example
Take . Prior without observation:
A frame arrives and the posterior becomes:
Reward head predicts against true .
KL between univariate Gaussians:
That is .
Reward loss with unit variance:
Total to minimize is , so ELBO is . The diagram shows the same split: posterior , prior , KL , reward versus .
Code
This check computes the exact KL and reward terms from the worked example. It uses only the standard library.
import math
def kl_1d(mu_q: float, var_q: float, mu_p: float, var_p: float) -> float: """Closed form KL between univariate Gaussians q and p.""" return 0.5 * ( var_q / var_p + ((mu_q - mu_p) ** 2) / var_p - 1.0 + math.log(var_p / var_q) )
def reward_pred(h: float, s: float) -> float: """Reward head used in the worked example.""" return 1.0 * h + 0.8 * s
if __name__ == "__main__": kl = kl_1d(1.5, 0.64, 1.0, 1.0) rhat = reward_pred(0.8, 1.5) rloss = 0.5 * (rhat - 1.8) ** 2 print(f"KL = {kl:.4f}") # -> KL = 0.1681 print(f"rhat = {rhat:.2f}") # -> rhat = 2.00 print(f"reward loss = {rloss:.4f}") # -> reward loss = 0.0200 print(f"ELBO = {-(rloss + kl):.4f}") # -> ELBO = -0.1881Watch Out For
Compressor drops the cue that matters later
Training on reward alone teaches the encoder to keep only what predicts imminent reward. In sparse tasks a distant hazard gives zero reward for hundreds of steps, so it gets filed as background noise and imagined paths drive straight through it. Symptom: great training curves, collisions in deployment.
Keep an auxiliary image or contrastive loss so the code preserves geometry even when reward is silent. Probe reconstructions for small hazards before you trust the model. If a brake light or pit vanishes in reconstruction, your bottleneck is too tight.
Prior never catches the posterior
If the KL weight is too high early, the posterior collapses to a dull prior and stochastic states carry no information. If it is too low, imagination drifts because the prior never learned to match informed belief. Symptom: KL near zero with blurry predictions, or small training KL but huge imagination error.
Use KL balancing with free bits, meaning a minimum KL per dimension that stops the penalty from crushing useful uncertainty. Hafner style setups keep most gradient on the posterior side until clusters form, then let the prior catch up.
The Quick Version
- Learning latent dynamics compresses frames into a small code and learns transitions between codes, so planning never renders pixels.
- RSSM splits state into deterministic memory from a recurrent cell and stochastic belief for uncertainty.
- The posterior uses the frame while the prior imagines without it, and training pulls them together.
- In the worked 1D check the KL is , reward loss is , and ELBO is .
- Keep a reconstruction loss and free bits, or the code drops rare but vital cues and imagination drifts.