PlaNet#
PlaNet (Deep Planning Network) is a latent-dynamics model that learns a compact state-space representation from image observations and uses online planning rather than a separately trained actor-critic policy. At each step, PlaNet runs a cross-entropy method (CEM) planner inside the learned dynamics model to select the best action.
PlaNet introduced the RSSM (Recurrent State-Space Model) that later became the backbone of Dreamer and other latent-dynamics agents.
Architecture#
PlaNet’s learned world model has four components:
Component |
Description |
|---|---|
CNN Encoder |
4-layer conv net ( |
RSSM |
GRU-based recurrent state-space model with deterministic state |
CNN Decoder |
4-layer transposed-conv decoder (reconstructs image from |
Reward predictor |
3-layer MLP that predicts reward from |
RSSM latent dynamics#
The RSSM maintains two state variables:
Deterministic state
h_t— a GRU hidden state that captures temporal context across the full sequence.Stochastic latent
s_t— a diagonal GaussianN(μ_t, σ_t)representing the uncertainty about the current observation.
At each timestep the model:
Encodes the observation:
e_t = enc(o_t)Updates the deterministic state:
h_t = GRU(h_{t-1}, s_{t-1}, a_{t-1})Computes the prior:
p(s_t | h_t)— predicts the latent without seeing the observationComputes the posterior:
q(s_t | h_t, e_t)— infers the latent after seeing the observation
During planning, the prior is used to roll out imagined trajectories. The posterior is only used during training to provide a target.
Planning with CEM#
PlaNet does not train a separate policy network. Instead it uses the cross-entropy method at every environment step:
Sample
Kcandidate action sequences from a diagonal Gaussian.Roll out each candidate through the RSSM prior for
Hsteps.Score each rollout by the sum of predicted rewards.
Refit the Gaussian to the top
Ncandidates.Repeat for
Iiterations, then execute the first action of the best sequence.
Parameter |
Default |
Description |
|---|---|---|
|
20 |
Number of imagined steps per candidate |
|
1000 |
Candidate action sequences sampled per iteration |
|
10 |
CEM re-fitting iterations |
|
100 |
Elite candidates kept for re-fitting |
Loss function#
PlaNet uses the standard variational bound (single-step predictions):
Term |
Description |
|---|---|
KL divergence |
Regularizes the posterior toward the prior, with free nats = 3.0 |
Reconstruction (MSE) |
Pixel-level image reconstruction loss |
Reward prediction (MSE) |
Learns to predict rewards from the latent state |
The KL term uses free_nats = 3.0 — the KL is clamped so that once the
posterior and prior are within 3 nats, no further gradient pressure is applied.
Memory#
PlaNet stores complete episodes rather than individual transitions:
from torchwm import Memory, Episode
memory = Memory(size=100) # keep at most 100 episodes
episode = Episode()
episode.append(obs, action, reward, done)
episode.terminate(final_obs)
memory.append([episode])
# Sample random subsequences for training
sequences, lengths = memory.sample(batch_size=32, tracelen=50)
Feature |
Detail |
|---|---|
Storage unit |
Complete episodes (not individual transitions) |
Sampling |
Randomly select episodes, then contiguous subsequences |
Eviction |
FIFO per-episode (deque-based) |
Time-major |
Optional via |
Usage in TorchWM#
Direct construction#
import torchwm
agent = torchwm.create_model("planet", env="CartPole-v1")
agent.train(epochs=100, steps_per_epoch=150)
PlaNet takes parameters directly in its constructor (no separate config class):
from torchwm import Planet
agent = Planet(
env="CartPole-v1",
bit_depth=5, # image bit depth for preprocessing
state_size=200, # deterministic GRU state dimension
latent_size=30, # stochastic latent dimension
embedding_size=1024, # encoder output dimension
memory_size=100, # number of episodes to keep
action_repeats=1,
max_episode_steps=1000,
headless=False, # set True for headless servers
)
Training options#
results_dir = agent.train(
epochs=100,
steps_per_epoch=150,
batch_size=32,
H=50, # sequence length for training
beta=1.0, # KL weight
save_every=25,
record_grads=False,
scheduler_type="step", # LR scheduler: "step", "cosine", "exponential", "plateau", None
scheduler_kwargs={"step_size": 50, "gamma": 0.5},
)
Warmup#
Collect random episodes before training starts:
agent.warmup(n_episodes=5, random_policy=True)
If not called explicitly, one warmup episode is collected automatically at the
start of train().
CEM Planner#
The CEM planner is embedded inside the Planet agent and configured through the
policy_cfg dict:
agent = Planet(
env="CartPole-v1",
policy_cfg={
"planning_horizon": 20,
"num_candidates": 1000,
"num_iterations": 10,
"top_candidates": 100,
},
)
Preprocessing operator#
from torchwm import get_operator, PlaNetOperator
op = get_operator("planet", state_dim=32, action_dim=4)
# Or directly:
op = PlaNetOperator(state_dim=32, action_dim=4)
result = op.process({
"obs": torch.randn(32),
"action": [0.1, 0.2, 0.3, 0.4],
"reward": 1.0,
"done": False,
})
print(result["obs"].shape) # (1, 32)
print(result["action"].shape) # (1, 4)
See Also#
Dreamer: Model-Based RL with Latent Dynamics — successor to PlaNet; replaces CEM with a trained actor-critic
IRIS: Transformers for Sample-Efficient World Models — discrete world model that also uses the CEM-style planning
Memory & Replay Buffers — PlaNet Memory and Episode in detail
World Models Study Guide — conceptual overview of latent-dynamics models
Vision Components — CNNEncoder and CNNDecoder used by PlaNet