TD-MPC-Glass, Part 24: Does the Planner Earn Its Keep? A Self-Contained Account
This post is meant to be read on its own. It assumes you know what reinforcement learning is and nothing else about this project. Every term is defined where it first appears, every number has its seed count, and the last section answers the objections we expect. If you only read one thing about this work, read this.
0. The question in one paragraph
TD-MPC2 is a model-based RL agent. At every environment step it does two things that cost time: it trains a world model, and it plans with that model by simulating hundreds of candidate action sequences before choosing one. Planning is roughly a third of the wall-clock. We asked a simple engineering question — can we switch the planner off and get the same result faster? — and the answer turned out to be: sometimes completely free, sometimes catastrophic, and which one it is depends on the task in a way that is not obvious in advance.
1. Vocabulary
Skip this if the terms are familiar.
World model. A learned simulator. Instead of predicting pixels, TD-MPC2 learns a latent
dynamics model: given a compressed state z and an action a, predict the next compressed state
z', plus the reward and the value. “Latent” just means the model works in its own internal
coordinates rather than in raw observations.
Policy prior (π). A small neural network that maps a state directly to an action, exactly
like a model-free actor. TD-MPC2 trains one alongside the world model.
MPPI planning. At decision time the agent does not simply ask the policy prior for an action. It samples many candidate action sequences, rolls each one forward through the learned world model, scores them by predicted reward-plus-value, and takes a weighted average of the best ones. TD-MPC2’s defaults: 512 sampled sequences, horizon 3, 6 refinement iterations, 64 elites — so roughly 18 sequential rounds of model evaluation per environment step. This is the expensive part.
The ablation. TD-MPC2 exposes a config flag, mpc. With mpc=true the agent plans as above.
With mpc=false it acts straight from the policy prior. The world model is still trained either
way — we are removing the planner, not the model.
A “gate”. Rather than planning always or never, switch it partway through training. We use two:
WMP_MPC_OFF_AT=N— plan until step N, then stop.WMP_MPC_ON_AT=N— act from the policy prior until step N, then start planning.
A gate is the practical object here. If the planner is only useful under some conditions, then “detect the condition and switch” is the design, and the gate is the simplest possible version of that detector — a fixed step count.
Return. Sum of rewards over an episode. DMControl tasks are scaled so 1000 is roughly perfect and 0 is failure. Seed. One training run with a given random initialisation; RL results vary a lot between seeds, which is most of what this post is about.
2. The premise was wrong, and checking cost nothing
The original proposal was “remove the world model when it isn’t necessary, to save time”. Before spending any GPU-hours we checked the premise against throughput telemetry already on disk:
| what you remove | throughput | saving |
|---|---|---|
the world-model loss (consistency_coef 20 → 0) |
31.45 vs 31.54 steps/s (n≈4700 snapshots each) | none |
| the planner (MPPI on → off) | 43.3 → 66.6 steps/s | ~35% of runtime |
Turning off the world-model loss saves nothing measurable, because the latent rollout still happens — reward and value prediction need it whether or not a consistency term reads it. All of the available saving is in the planner. So the experiment became “switch off planning”, not “switch off the world model”.
Correction from an earlier draft: we first reported these as 25.26 vs 24.89 steps/s over ~365 snapshots. That aggregation keyed on a field name the records do not contain, so it silently sampled about 2% of the rows. The conclusion did not change; the numbers above are the corrected ones.
3. The main experiment
Setup. Official nicklashansen/tdmpc2 @e9f5932 — not our own re-implementation, which is a
distinction that has bitten this project before. State observations (not pixels), model_size=5,
400,000 environment steps, evaluation every 25k or 50k steps over 10 episodes. Two arms:
- planning throughout — stock TD-MPC2,
mpc=true - never planning —
mpc=falsefrom step 0, everything else identical
Table 1 — final return at 400k steps
| task | planning throughout | never planning | Δ | verdict |
|---|---|---|---|---|
| cup-catch | 982.8 (n=1) | 981.5 (n=1) | −1.3 | tie, uninformative |
| finger-spin | 985.0 (n=1) | 984.7 (n=1) | −0.3 | tie, uninformative |
| cheetah-run | 855.9 ±120.2 (n=5) | 882.0 ±49.0 (n=4) | +26.1 | not separable |
| walker-run | 809.9 ±11.7 (n=3) | 690.6 ±64.2 (n=3) | −119.3 | planning wins |
| acrobot-swingup | 417.2 (n=3) | 305.0 (n=3) | −112.2 | planning wins |
| hopper-hop | 364.2 ±76.6 (n=5) | 103.3 ±55.7 (n=5) | −261.0 | planning wins, p=0.004 |
Per-seed values, because means hide everything that matters here:
| task | planning throughout | never planning |
|---|---|---|
| cheetah-run | 640.9, 903.6, 908.4, 910.9, 915.6 | 808.7, 901.2, 907.7, 910.4 |
| walker-run | 799.1, 808.4, 822.3 | 622.5, 699.2, 750.2 |
| hopper-hop | 319.1, 319.6, 333.4, 349.6, 499.4 | 42.8, 45.6, 120.0, 153.0, 154.9 |
| acrobot-swingup | 192.1, 504.9, 554.6 | 24.3, 409.2, 481.5 |
walker-run is the statistically cleanest cell. Every planning seed beats every never-planning seed. Under exchangeability that arrangement has probability 1/C(6,3) = 0.05 exactly — an exact rank test, not a t-test, because at n=3 per arm a t-test assumes more than we know.
hopper-hop is the largest effect, and it is not a degradation. 103.3 against 364.2 means the agent barely learns to hop at all. Removing the planner there does not cost some performance; it costs most of the task. At n=5 per arm every planning seed beats every never-planning seed (319.1 is the worst planning run, 154.9 the best never-planning run), which is an exact rank test at p = 1/C(10,5) = 0.004.
This cell was first reported at n=3 as 394.1 vs 69.5, a 5.7× ratio. At n=5 it is 364.2 vs 103.3, a 3.5× ratio. The direction did not move and the evidence got stronger — but the magnitude fell by a third when two seeds per arm were added, which is the honest measure of how well an effect size is pinned down at n=3 on this benchmark.
Two of the six tasks were wasted compute. cup-catch and finger-spin both sit at ~982–985 against a ceiling near 1000. When both arms are at the ceiling the comparison cannot distinguish “the planner is unnecessary” from “this task is too easy to show a difference”. We flagged them as uninformative before they finished, which mattered, because —
they finished first. Easy tasks train fastest. Had we stopped when the first two results arrived, we would have shipped “removing the planner is free” with two confirmations behind it.
4. What happens inside a run
The final numbers hide the interesting part. On hopper-hop, the two arms are indistinguishable for the first 150,000 steps and then diverge sharply.
Table 2 — hopper-hop, matched-step returns
| step | never planning (s1) | never planning (s2) | planning throughout |
|---|---|---|---|
| 50,000 | 7.4 | 7.6 | 0.0 |
| 100,000 | 42.5 | 76.5 | 59.5 |
| 150,000 | 97.0 | 77.8 | 101.5 |
| 200,000 | 81.4 | 109.0 | 258.1 |
| 250,000 | 104.2 | 68.9 | 315.5 |
The reading: a planner is worth nothing until the model is good enough to plan through. Early on, rolling out a bad model gives bad action sequences, so MPPI is no better than the policy prior — and you are paying 35% more wall-clock for it. Once the model crosses some quality threshold the planner starts extracting real value from it, and the no-planning arm flattens out and stays flat.
This also explains an earlier oddity. When we first tried the opposite gate — plan early, then switch planning off at 200k — that arm did worse than never planning at all. It removes the component exactly when it has started to pay.
5. The gate
If the planner is useless before ~150k and valuable after, the obvious design is to switch it on at 150k rather than paying for it from the start.
Table 3 — hopper-hop, three schedules
| arm | return at 400k | wall-clock | seeds |
|---|---|---|---|
| planning throughout | 394.1 ±91.5 | 2h47m | 333.4, 349.6, 499.4 |
| gate: plan from 150k | 250.4 ±109.0 | 2h26m | 69.1, 230.0, 304.1, 310.5, 338.6 |
| never planning | 69.5 ±43.8 | 1h49m | 42.8, 45.6, 120.0 |
The gate recovers 56% of the gap between never-planning and planning-throughout, for 13.0% less wall-clock. It is a genuine Pareto point — better return than never planning, less time than always planning — and not a free recovery.
The saving is predictable, which is the part we care about. Planner overhead is 34.7% of runtime; the gate skips planning for 150k/400k = 37.5% of training; 34.7% × 37.5% = 13.0% predicted, and 13.0% observed. Because the arithmetic closes, the knob is understood: a later gate, or one triggered by a model-quality probe instead of a fixed step, moves along a known curve rather than being a guess.
Correction: at n=2 we reported this gate as recovering “essentially all” of the benefit, from seeds scoring 310.5 and 338.5. Seeds 4 and 5 came in at 230.0 and 69.1. The corrected 56% then held when a further seed was added, which the original figure had not.
One seed (69.1) never learned at all, flat near zero from step 0, before the gate could fire. hopper-hop is bimodal in that way — a fraction of runs simply never get off the ground. It is included in the mean because dropping it would need a rule stated in advance, and we did not have one.
Update 2 — this section has now been wrong twice, in opposite directions. Read this part, not the earlier versions.
The honest history, because it is the most instructive thing here:
- Mid-flight, one walker gate seed tracked below both extremes. We wrote that a badly timed gate “may be worse than not gating at all”.
- The second walker seed came in at 811.2 and we corrected the section to say the gate recovers 100% of the gap on walker and 56% on hopper — and drew a conclusion from that ordering.
- The third walker seed (687.8) and the sixth hopper seed (541.9) arrived. The ordering reversed again.
Final figures at n=3 (walker) and n=6 (hopper):
| task | never plan | plan throughout | gate at 150k | gate recovers |
|---|---|---|---|---|
| walker-run | 690.6 (n=3) | 809.9 (n=3) | 687.1 (n=3: 562.2, 687.8, 811.2) | ~0% |
| hopper-hop | 69.5 (n=3) | 394.1 (n=3) | 299.0 (n=6: 69.1, 230.0, 304.1, 310.5, 338.6, 541.9) | 71% (mean), 86% (median) |
On walker the gate lands on top of the never-planning arm (687.1 vs 690.6) — the 811.2 seed we built the “100%” claim on is the top of a very wide distribution spanning 562–811, not a representative value. On hopper the gate recovers most of the gap, and one of its six seeds (541.9) exceeds every planning-throughout seed.
What survives. The gate is worth something on hopper-hop and nothing on walker-run. The wall-clock saving still matches prediction in every configuration measured (13.0/13.0, 12.6/12.8, 4.2/4.2) — that part was a timing measurement and has never moved. What is not established is any rule for when a gate recovers, and both mechanisms we proposed for it are now dead: “gates work where the un-gated arm is useless” was contradicted at n=2, and its replacement “recovery tracks pre-gate policy quality” is contradicted at n=3/6.
What this cost, and the actual lesson. Nothing was spent but compute, because every version was published with its seed count attached. But the sequence — n=1 wrong, n=2 wrong in the opposite direction, n=3/6 different again — is the clearest evidence in this whole campaign that these gate cells are too noisy to compare at the sample sizes we were reporting at. The walker gate spans 562–811 across three seeds of one configuration. Our stated rule was “n≥3 before any cross-arm comparison”, and the 100% claim broke it at n=2 within hours of the rule being written down.
The correct treatment for a cell like this is a failure-rate plus a conditional distribution, not a mean, and not a headline. We are reporting it here rather than quietly fixing the number because the error pattern is more useful to a reader than the result.
6. The result does not generalise beyond TD-MPC2 — and that is the interesting part
DreamerV3 is another world-model agent. It has no planner at all: it trains a policy inside an imagined rollout of its world model and acts from that policy directly. If “you need a planner for hard control” were true, Dreamer should fail on hopper-hop.
Table 4 — hopper-hop across agents
| agent | hopper-hop | env steps |
|---|---|---|
| DreamerV3 (no planner) | 209.0 (n=3: 187.6, 214.6, 224.9) | ~500k |
| TD-MPC2, planning throughout | 394.1 (n=3) | 400k |
| TD-MPC2, gate at 150k | 250.4 (n=5) | 400k |
| TD-MPC2, never planning | 69.5 (n=3) | 400k |
A planner-free agent reaches ~209 where TD-MPC2-without-its-planner reaches ~103 — on more environment steps, so if anything the comparison flatters TD-MPC2.
So the correct claim is narrower than “planning is necessary”:
In TD-MPC2, MPPI planning is load-bearing on walker-run, hopper-hop and acrobot, and free to remove where the policy prior already solves the task. The collapse without planning is a property of this agent’s policy prior, not evidence that model-based control requires a planner.
That is a better research question than the one we started with: what does DreamerV3’s prior have that TD-MPC2’s lacks? Candidates — a much higher replay ratio, a different actor objective, a generative rather than value-equivalent model — are all testable.
The probe came back, and it answers the question. Removing DreamerV3’s dynamics loss
(dyn=0, so the world model is no longer trained) collapses it:
| DreamerV3, hopper-hop | seeds | mean |
|---|---|---|
dyn=1.0 — model trained |
187.6, 214.6, 224.9 | 209.0 (n=3) |
dyn=0.0 — model not trained |
0.0, 65.5, 81.5, 110.1 | 64.3 (n=4) |
Complete separation — every model-trained seed beats every model-untrained seed — exact rank test p = 1/C(7,3) = 0.029.
Line the four configurations up on the same task:
| configuration | hopper-hop |
|---|---|
| TD-MPC2, planning | 364.2 (n=5) |
| DreamerV3, model trained | 209.0 (n=3) |
| TD-MPC2, no planner | 103.3 (n=5) |
| DreamerV3, model not trained | 64.3 (n=4) |
Both agents fall into the same 60–105 band once the world model stops being exploited, by whichever route that agent uses — TD-MPC2 by planning at decision time, DreamerV3 by training its policy inside imagined rollouts. Dreamer’s advantage is therefore not a better actor-critic.
That points at a more unifying statement than “planning is load-bearing”: what matters is whether the world model is exploited at all, not the particular mechanism by which it is exploited. It is also the only cell in this campaign where adding seeds did not move the verdict — n=2 and n=4 agree.
Limits: the two ablations are not exact analogues (dyn=0 removes the model’s training signal,
mpc=false removes its use at decision time), the agents differ in many other ways, and the
budgets differ (500k vs 400k). This is the strongest lead for the next paper, not a settled result.
Correction: we earlier reported Dreamer at 125.3 and said it “lands with the never-plan arm”. That was one run read at 256k steps and compared against 400k results. Trained to ~500k it reaches 206.3 and sits with the gate arm instead. The comparison reversed.
7. What went wrong three times in one day
This is the part we would most like feedback on.
Table 5 — claims that decayed under replication
| claim | first reading | after replication | outcome |
|---|---|---|---|
| removing the planner is free, 1.87× faster | cheetah-run only, n=1–2 | fails on 3 of 4 informative tasks | falsified |
| never-planning is 33× more reliable on cheetah | sd 157.2 vs 4.7 (n=3 each) | 2.5× (n=5/4) | withdrawn |
| the gate recovers the full benefit | 310.5, 338.5 (n=2) | 56% of the gap (n=5) | corrected |
| DreamerV3 corroborates “planner-free fails” | 125.3 at 256k (n=1) | 209.0 at 500k (n=3) | reversed |
All four have the same shape: a claim formed from the runs that finished first, and the runs that finish first are not a random sample. Three distinct mechanisms produced that, and the second is specific to this kind of study:
- Easy tasks finish first. cup-catch and finger-spin are fast and uninformative.
- The cheaper arm finishes first. Never-planning runs 1.9× faster, so its seeds arrive earlier, so any early comparison is weighted toward whatever the cheap arm happens to show. This is a hazard in any speed-versus-quality ablation.
- Partial checkpoints exist first. The Dreamer error was reading a 256k checkpoint against 400k results.
A fourth, unrelated trap worth recording: “same seed” is not “same draw”. Changing eval_freq
from 50,000 to 25,000 perturbs the RNG stream enough that seed 1 under one schedule diverged
completely from seed 1 under the other (1.61 vs 97.0 at 150k, nominally identical configuration).
Anything that consumes randomness — including evaluation — breaks seed pairing.
What kept the cost at roughly six GPU-hours rather than a retracted paper: the first write-up was published as a hypothesis with named falsifiers before the data existed — “acrobot-swingup and hopper-hop are the tasks I expect to break it”. Both broke it. Nothing had to be retracted from a paper, only from a note that had already said it might be wrong. Every correction above is in the git history rather than silently edited.
Rule adopted: no cross-arm comparison is reported until every cell is at matched budget and n ≥ 3.
8. Objections we expect, and our answers
“n=3 is too few.” Agreed, and it is why we report exact rank tests and per-seed values rather than t-tests, and why the cheetah cell is reported as not separable rather than as a win for either arm. Where n=3 is enough is when the arms do not overlap at all — walker-run, where every planning seed beats every never-planning seed, p=0.05 exactly. Where it is not enough, we say so.
“You only tested six tasks, and two were useless.” True. The two ceiling-limited tasks were a planning error on our part — we should have screened for headroom first. The three informative tasks all point the same way, and the one that does not (cheetah) is reported as null rather than quietly dropped.
“Isn’t this just saying TD-MPC2’s planner is good? That’s already known.” The novel parts are (a) that it is worthless for the first ~150k steps on hard tasks, which is not in the paper; (b) that this makes a schedule a real design axis with a predictable cost curve; and (c) that a planner-free agent does not collapse the same way, so the failure is about TD-MPC2’s prior rather than about planning.
“The wall-clock numbers depend on your hardware.” Yes. All wall-clock comparisons in this post are within a single machine, because environment stepping is CPU-bound and our boxes differ. Returns are hardware-independent and are pooled across boxes; timings are not. We excluded one gate seed from the timing table for exactly this reason.
“Your cheetah control has a seed at 640.9 and another at 915.6. Is your setup broken?” No — that cell genuinely has that spread. Pooled with an earlier five-seed baseline, planning-throughout on cheetah-run spans 640.9–915.6 across eight seeds. Establishing that before running single-seed comparisons on that task would have saved us the withdrawn reliability claim.
“Why should I believe the gate result when one seed scored 69?” You should believe it as far as n=5 with a bimodal task allows, which is not very far. It is reported with the degenerate seed included, the mean and spread shown, and the walker counter-example flagged as provisional and possibly negative. It is a direction, not a result.
“What would change your mind?” For the main claim: a task where the policy prior clearly cannot solve the task alone, yet never-planning matches planning at matched steps and n≥3. For the gate: walker-run’s 50k-gate arm failing as well as its 150k arm, which would mean the disruption is intrinsic to switching mid-run rather than a matter of timing.
8b. Two questions this answers about our own earlier work
Does the AAAI paper still stand?
That paper ablated the consistency loss (consistency_coef 20 → 0) and described the result as
“TD-MPC2 versus TD-MPC2 without the world model”. Three things we now know bear on it.
The ablation is weaker than its description. With consistency_coef=0 the world model is still
trained — reward and value prediction roll the latent forward regardless — and the planner still
plans through it. Nothing about the model’s use changes. Consistent with that, the ablation costs
no wall-clock at all (31.45 vs 31.54 steps/s): you are not removing a component, you are removing one
training signal from a component that keeps running. “Without the world model” overstates what was
tested.
The headline magnitude was a re-implementation artifact. The paper’s ~9.2× cheetah gap came from our own JAX port. On official TD-MPC2 the same comparison is 1.04× under ordinary training and 3.55× under the paper’s own matched-data control. The direction is real; the number is not.
The conclusion survives, and this work supports it. The paper’s actual claim — world-model benefit is real, strongly task-dependent, and not cheaply predictable in advance — is exactly what the planner experiments found independently, with a different ablation and larger effects. If anything it is now better supported than when it was written.
So: not wrong, but mis-scoped in its central experiment. The honest revision is to describe
consistency_coef=0 as removing a training signal, keep the task-dependence claim, drop the 9.2×,
and note that the stronger ablation — removing the planner — was run afterwards and gives cleaner
separation (hopper-hop 364.2 vs 103.3, p=0.004).
Why did TD-MPC2 beat PPO by a huge margin only on hopper-hop — and why did that survive the consistency ablation?
This was an open puzzle from earlier in the campaign. Both halves now have the same answer.
| task | planning | no planning | planning’s contribution |
|---|---|---|---|
| hopper-hop | 364.2 | 103.3 | +260.9 (3.53×) |
| walker-run | 809.9 | 690.6 | +119.3 (1.17×) |
| acrobot-swingup | 417.2 | 305.0 | +112.2 (1.37×) |
| cup-catch | 982.8 | 981.5 | +1.3 (1.00×) |
| finger-spin | 985.0 | 984.7 | +0.3 (1.00×) |
| cheetah-run | 855.9 | 882.0 | −26.1 (0.97×) |
Planning contributes 3.5× on hopper-hop and essentially nothing anywhere else. PPO has no planner. So TD-MPC2’s margin over PPO should be largest precisely where planning contributes most — and hopper-hop is that task by a wide margin. The “TD-MPC2 only really beats PPO on hopper-hop” observation is the planning-contribution column, read through a different comparison.
And the second half falls out immediately: the consistency ablation left the planner running.
Turning off consistency_coef does not touch the component responsible for the advantage, so the
advantage survives. That was not a puzzling result; it was the ablation missing its target.
This makes a testable prediction we have not run: TD-MPC2 with mpc=false should lose most of its
advantage over PPO on hopper-hop specifically, and lose little of it elsewhere. If that fails, this
explanation is wrong.
9. What this is for
Two threads come out of it.
An efficiency paper. Not “world models are slow, here is a fast one”, but measure which component is load-bearing per task, then remove what is not. The planner is the only component with a real wall-clock price; its value is task-conditional and phase-conditional; and the saving from a schedule is predictable from two measurable quantities. A gate triggered by a model-quality probe — rather than a fixed step — is the concrete next build, and it connects directly to the probe-then-prune idea from the earlier diagnostic work.
A design question. DreamerV3’s prior survives without a planner where TD-MPC2’s does not. If we can identify why, that is a statement about what makes a policy prior robust in a model-based agent — which is a better paper than anything in this post.
Reproducibility
Every number here has per-seed values committed in data/ in
SuuTTT/world-model-paper@claude-opus-4-8/world-model-paper, alongside the reports the tables were
built from. The planner gate is a ~20-line patch that adds WMP_MPC_OFF_AT / WMP_MPC_ON_AT to
TD-MPC2’s trainer; it is additive-only (zero deleted lines against the stock file) and inert unless
the environment variable is set, so the reference path stays the arbiter. Figures are generated by
docs/assets/make_part24_figs.py, stdlib only.
Total compute for everything in this post: three 4×RTX-3060 boxes at roughly $0.67/hour, about $15.