Planning, Control, and Policy Evaluation › Task Return and Sample Efficiency

Michael BrenndoerferAugust 3, 202613 min read
World Models HandbookAll chapters
Part 11 of 12Evaluation and Understanding
Chapter 64Planning, Control, and Policy Evaluation › Task Return and Sample Efficiency
Reading section 3 of 9 · Task Return and Sample Efficiency · 13 minSection 3 of 9 · 13 min

Book contents

Section 3 of 9 · 13 min read

Planning, Control, and Policy Evaluation › Task Return and Sample EfficiencyOne section · Sections in this chapter3 / 9 ↓
Reading tools Definitions & inline links

Choose your expertise level to adjust how many terms are explained. Beginners see more tooltips, experts see fewer to maintain reading flow. Hover over underlined terms for instant definitions.

Article links

Make inline references clickable

Task return is the sum of rewards earned by a policy in an episode of finite length TT, G(π,s0)=∑t=0T−1γt r(st,at)G(\pi, s_0) = \sum_{t=0}^{T-1} \gamma^{t}\, r(s_t, a_t) with s0∼μs_0 \sim \mu, where:

  • G(π,s0)G(\pi, s_0): the total discounted reward accumulated over the episode starting from initial state s0s_0
  • s0∼μs_0 \sim \mu: the initial state is drawn from the stated initial-state distribution μ\mu
  • TT: the finite episode horizon (number of steps)
  • γ∈(0,1]\gamma \in (0, 1]: the discount factor (here we set γ=1\gamma = 1, giving an undiscounted finite-horizon objective)
  • r(st,at)r(s_t, a_t): the scalar reward received at step tt in state sts_t under action ata_t
  • at=π(st)a_t = \pi(s_t) for a deterministic policy: randomized MPC additionally depends on its planner stream ω\omega
  • st+1=f(st,at)s_{t+1} = f(s_t, a_t): the next state produced by the true environment transition dynamics

The discount factor and episode horizon belong to the task definition. Here γ=1\gamma=1 and T=30T=30, so the code sums 30 unweighted rewards with no terminal reward. Changing discount or horizon can change policy rankings, but different reward timing does not force a ranking reversal. Comparisons should use the same objective, or explicitly present the different objectives as different tasks.

For a randomized controller, write the expected evaluation return as J(π)=Es0∼μ, ω[G(π,s0;ω)]J(\pi)=\mathbb{E}_{s_0\sim\mu,\,\omega}[G(\pi,s_0;\omega)], where ω\omega contains the planner's random draws. A stochastic environment would add transition randomness to that expectation. The deterministic PD controller needs no ω\omega; random-shooting MPC does. Our finite estimates use 20 held-out initial states and one prescribed stream per case, seeded 110+i110+i for case ii. Reconstructing those streams pairs comparisons. These estimates do not average over independent training runs or repeated planner streams at each state, and geometric state coverage alone does not establish estimation precision.

An expected-return claim must state its initial-state distribution μ\mu and any other randomness being averaged. Other legitimate policy claims concern success probability, tail risk, safety, or latency and require their own defined quantities. Different initial-state distributions answer different return questions unless the comparison explicitly accounts for them.

Initial states influence the trajectories and model queries a policy generates. Starting near the origin does not guarantee that a controller stays there, nor does a farther starting state guarantee worse return. Measure visitation and return if those mechanisms are the claim. Here a fixed uniform sample on [−1,1]2[-1,1]^2 defines the held-out cases for all source controllers and the paired target experiment.

Sample efficiency describes performance as a function of real-environment interaction budget, not a raw ratio J/NJ/N. That ratio is especially unhelpful for negative rewards, where its ordering can change simply by changing the reward offset. A learning curve evaluates systems at several disclosed interaction budgets, using either cumulative online learning or separate fits. Independent seeds and uncertainty estimates are needed to characterize variability; their number should be justified by the precision of the comparison. Track these interaction buckets separately:

  • Source pretraining interactions: data used before the target adaptation experiment. Source and target can share an environment; the domains must be stated.
  • Target adaptation interactions. Real trajectories collected in the deployment environment and used to update any parameter (model, policy, value, planner hyperparameter).
  • Validation rollouts. Interactions used to select among hyperparameters or checkpoints. This is not free: those rollouts also consumed actions.
  • Test rollouts. Interactions used to report the metric, with no update or selection step consuming their outcomes.

Separating the counters prevents two accounting errors: treating synthetic model transitions as newly collected environment data, and omitting interactions used for selection. Report each bucket so readers can compare the resources their deployment constrains.

Synthetic transitions generated by f^\hat f are compute, not real samples. A planner that rolls the model K⋅HK \cdot H times per decision did not collect K⋅HK \cdot H real environment steps. It spent K⋅HK \cdot H model evaluations. Both quantities matter, but they belong to different budgets. Real interactions may constrain a deployment when collecting data is expensive or dangerous; model evaluations may constrain it when inference is slow or costly. A method can be sample-efficient and compute-inefficient, or the reverse. Report both budgets against the deployment's actual limits.

What a Learning Curve Is Not

A sweep of planning horizon HH or candidate count KK with one fixed model is a search-configuration sensitivity test, not a sample-efficiency curve. A learning curve varies the real-interaction budget and reports the learning procedure used at each point. Use multiple independent runs when estimating variability, with the run count justified by uncertainty or power rather than a universal three-seed threshold. Chapter 65 develops that experimental-design question.

A horizon sweep can mix longer lookahead, fewer candidates, and longer model rollouts. A candidate-count sweep changes search adequacy at a fixed model. Neither alone establishes a data-efficiency advantage. To measure that advantage, vary the real-interaction budget and evaluate the resulting learner or checkpoint under a consistent test protocol.

The remaining experiments use a deterministic damped double integrator with two state variables and a known nonlinear transition. This keeps return and resource accounting inspectable. The same evaluation questions apply when studying ensemble methods, imagination-based policies, or value-equivalent models, but those methods need their own implementations and protocols; this notebook does not benchmark them.

The testbed is a deterministic point mass with position and velocity state, damped dynamics, and nonlinear quadratic drag. Its reference transition is a known formula, so we can substitute it into the same planner without claiming to solve control optimally. A neural surrogate would not remove that reference formula; an unknown physical plant would make exact-dynamics substitution unavailable.

The system is a 1D damped point mass with quadratic drag. The state is s=(p,v)∈R2s=(p,v)\in\mathbb{R}^2, the action is a scalar bounded acceleration a∈[−1,1]a\in[-1,1], and its discrete source transition is vt+1=(1−d)vt+Δt g at−cdragvt∣vt∣v_{t+1}=(1-d)v_t+\Delta t\,g\,a_t-c_{\mathrm{drag}}v_t|v_t|, followed by pt+1=pt+Δt vt+1p_{t+1}=p_t+\Delta t\,v_{t+1}. These are the toy's discrete update rules, not an exact continuous-time solution.

where:

  • vtv_t: velocity at time tt
  • ptp_t: position at time tt
  • ata_t: scalar bounded acceleration applied at time tt
  • Δt\Delta t: integration timestep, 0.10.1
  • dd: linear damping coefficient, 0.050.05
  • cdragc_{\mathrm{drag}}: quadratic drag coefficient in the discrete velocity update, 0.10.1; it is distinct from the return discount γ\gamma
  • gg: actuator gain, set to a source value of 1.01.0 and (for transfer) a target value of 0.70.7
  • ∣vt∣|v_t|: absolute velocity, capturing the sign-symmetric drag effect

The first line updates velocity from linear damping, the scaled control input, and quadratic drag. The second line updates position by semi-implicit (post-update velocity) Euler integration. The reward is a quadratic tracking-and-control penalty to the origin, r(s,a)=−(p2+0.05 v2+0.01 a2)r(s, a) = -\bigl( p^2 + 0.05\, v^2 + 0.01\, a^2 \bigr), where:

  • p2p^2: position penalty, driving the state toward the origin
  • 0.05 v20.05\, v^2: velocity penalty, discouraging high speed
  • 0.01 a20.01\, a^2: control effort penalty, discouraging large actions
  • the overall negative sign: penalizes deviations rather than rewarding them, so higher return means staying closer to the origin with less effort

The quadratic term cdragv∣v∣c_{\mathrm{drag}}v|v| makes the true transition nonlinear, while the learned surrogate is affine in state and action. Least squares solves the empirical fitting problem within that class. This is a deliberate class mismatch, not an injected corruption of the fitted coefficients.

Empirical least-squares optimality does not rule out overfitting or finite-sample estimator variation. There is no transition or observation noise here, but the sampled training trajectories still affect the fitted coefficients. The affine class also cannot represent the quadratic drag everywhere. Held-out errors and control tests measure the consequences of that fit; they do not decompose all error into a single bias term.

In[3]:
Code
import numpy as np

DT = 0.1
DAMP = 0.05
DRAG = 0.1
ACTION_MIN, ACTION_MAX = -1.0, 1.0
GAIN_SOURCE = 1.0
GAIN_TARGET = 0.7
EPISODE_HORIZON = 30


def true_step_batch(S, A, gain=GAIN_SOURCE):
    S = np.atleast_2d(S).astype(float)
    A = np.atleast_1d(A).astype(float)
    A = np.clip(A, ACTION_MIN, ACTION_MAX)
    p, v = S[:, 0], S[:, 1]
    v_next = (1.0 - DAMP) * v + DT * gain * A - DRAG * v * np.abs(v)
    p_next = p + DT * v_next
    return np.stack([p_next, v_next], axis=1)


def reward_batch(S, A):
    S = np.atleast_2d(S).astype(float)
    A = np.atleast_1d(A).astype(float)
    A = np.clip(A, ACTION_MIN, ACTION_MAX)
    p, v = S[:, 0], S[:, 1]
    return -(p * p + 0.05 * v * v + 0.01 * A * A)

We collect source training transitions with a PD behavior policy plus action noise, initialized in a narrow region. This creates a restricted collection regime; whether its errors cause exploitation must be tested rather than assumed.

In[4]:
Code
def behavior_action(S, rng):
    p, v = S[:, 0], S[:, 1]
    a = -3.0 * p - 2.0 * v + 0.3 * rng.standard_normal(len(S))
    return np.clip(a, ACTION_MIN, ACTION_MAX)


def collect_transitions(
    n_episodes, horizon, s0_low, s0_high, rng, gain=GAIN_SOURCE
):
    Ss, As, Sns = [], [], []
    for _ in range(n_episodes):
        s = rng.uniform(s0_low, s0_high, size=(1, 2))
        for _ in range(horizon):
            a = behavior_action(s, rng)
            s_next = true_step_batch(s, a, gain=gain)
            Ss.append(s[0])
            As.append(a[0])
            Sns.append(s_next[0])
            s = s_next
    return np.array(Ss), np.array(As), np.array(Sns)


train_rng = np.random.default_rng(0)
S_train, A_train, S_next_train = collect_transitions(
    n_episodes=100,
    horizon=30,
    s0_low=-0.5,
    s0_high=0.5,
    rng=train_rng,
)
PRETRAIN_INTERACTIONS = int(len(S_train))

PRETRAIN_INTERACTIONS records the 3000 source training transitions. The later learned-model comparisons share that source fit, and the final accounting separates these records from adaptation, evaluation transitions, and model-search compute.

Fitting a linear model is a two-line least-squares problem. The design matrix concatenates the two state components, the scalar action, and a bias column so the model can absorb any constant offset.

In[5]:
Code
X_train = np.column_stack([S_train, A_train, np.ones(len(S_train))])
W_lin, *_rest = np.linalg.lstsq(X_train, S_next_train, rcond=None)


def learned_step_batch(S, A, W=W_lin):
    S = np.atleast_2d(S).astype(float)
    A = np.atleast_1d(A).astype(float)
    X = np.column_stack([S, A, np.ones(len(S))])
    return X @ W

Before trusting this model for planning, we look at its one-step error on held-out transitions drawn from a wider region than training. This is the teacher-forced protocol from Chapter 61: it measures error on these sampled trajectories, not the globally weakest region or every state a planner might visit.

Out[6]:
Console
Training transitions:  3000
Held-out transitions:  600
Mean one-step error at state norm < 0.5:   0.0015
Mean one-step error at state norm >= 0.5:  0.0118
Overall one-step MSE:                      0.00005

The held-out errors tend to be larger away from the central region. This is consistent with region-dependent model accuracy, but this plot does not measure planner visitation or establish that the planner seeks high-error states. The later decision tests ask whether these prediction errors matter for the policies evaluated.

The near and far averages summarize two groups of held-out transitions. A scatterplot also shows their within-group variation.

The figure below plots prediction-error magnitude against the Euclidean norm of the numerical state coordinates. Position and velocity have different physical units, so this norm is a declared toy-coordinate diagnostic, not a unit-invariant distance. The split at 0.50.5 does not define the boundary of training support, and the figure does not measure planner visitation.

Out[7]:
Visualization
One-step error versus state distance from origin, near and far regions.
Held-out one-step prediction error against state distance from the origin. The near and far groups use a stated distance threshold; larger errors are more common farther from the origin in this dataset. Distance mixes position and velocity in the toy's chosen units and is not a measure of training density. This figure does not measure planner visitation or show that a planner prefers high-error states.

The farther group has a larger mean one-step error in this dataset. Similar group means would not prove uniformly accurate predictions, and different means do not establish optimism or exploitation. Error magnitude does not reveal the sign of a return error.

A planner could favor poorly supported trajectories if their predicted rewards are spuriously high, but this plot does not show that mechanism. The decision tests below measure actual return and return-prediction discrepancies; this particular run does not demonstrate optimistic exploitation.

A fixed PD feedback controller is our no-model comparator. It supplies a concrete return benchmark without consuming model-fitting data.

PD does not consult the learned model, so it cannot select actions because that model predicts them favorably. That does not identify why a learned-model controller might lose to PD: exploitation, poor search, horizon choice, or other effects can all matter. Beating this PD controller is the chosen return benchmark for the toy, not a universal condition for a world model to be useful.

In[8]:
Code
def make_pd_policy(kp, kd):
    def policy(s):
        p, v = s
        a = -kp * p - kd * v
        return float(np.clip(a, ACTION_MIN, ACTION_MAX))

    return policy


def closed_loop_return(env_step_batch, policy, s0, horizon=EPISODE_HORIZON):
    s = np.asarray(s0, dtype=float).reshape(1, 2)
    total = 0.0
    for _ in range(horizon):
        a = float(np.clip(policy(s[0]), ACTION_MIN, ACTION_MAX))
        assert ACTION_MIN <= a <= ACTION_MAX
        r = float(reward_batch(s, np.array([a]))[0])
        total += r
        s = env_step_batch(s, np.array([a]))
        assert s.shape == (1, 2) and np.all(np.isfinite(s))
    return total


def evaluate_policy(
    env_step_batch,
    policy_factory,
    S0_array,
    horizon=EPISODE_HORIZON,
    planner_seed=110,
):
    """Fresh policy per case; identical case seeds pair candidate streams."""
    returns = np.array(
        [
            closed_loop_return(
                env_step_batch, policy_factory(planner_seed + i), s0, horizon
            )
            for i, s0 in enumerate(S0_array)
        ]
    )
    assert np.all(np.isfinite(returns))
    return returns

We fix a held-out evaluation set of initial states and compute the PD baseline in both the true environment and the learned model. The pair of numbers is the first instance of a pattern we will repeat throughout.

In[9]:
Code
eval_rng = np.random.default_rng(7)
S0_eval = eval_rng.uniform(-1.0, 1.0, size=(20, 2))

pd_policy = lambda _seed: make_pd_policy(kp=4.0, kd=3.0)
pd_returns_true = evaluate_policy(true_step_batch, pd_policy, S0_eval)
pd_returns_model = evaluate_policy(learned_step_batch, pd_policy, S0_eval)
Out[10]:
Console
PD baseline (kp=4.0, kd=3.0), 20 held-out initial states
  actual return in true env: mean=  -3.588  std= 4.697
  model-predicted return:    mean=  -3.704  std= 4.753
  real interactions used to report this number: 600
  (reporting: 0 model rollouts counted as real interactions)

Even for a simple PD controller whose behavior is not chosen by the model, the model's prediction of PD's return differs from reality. In this run the model predicts a lower return, so its error is pessimistic rather than optimistic. Replacing PD with a model-driven planner can change the gap, but neither its sign nor its cause follows from the PD comparison alone.

This is fixed-budget accounting, not a sample-efficiency learning curve. The model fit uses 3000 source transitions. The fixed PD gains require no fitting transitions, but evaluating PD costs 20 episodes of 30 steps, or 600 environment transitions. Compare both performance and disclosed costs; do not call these 600 transitions 600 rollouts or divide the negative return by a sample count.