Behavioral cloning and distribution shift
Behavioral cloning is supervised fine-tuning where the model's outputs feed back into its inputs through physics. Derive why errors compound quadratically with horizon, what DAgger really costs on hardware, and design the WidowX baseline whose failures will teach you the taxonomy every later lesson depends on.
- State the i.i.d. assumption behavioral cloning inherits from supervised learning and point to the exact arrow in the control loop that breaks it.
- Derive the quadratic-in-horizon compounding-error bound and explain why DAgger-style online labeling restores linear growth.
- Specify a state-only BC baseline for a WidowX pick task — inputs, outputs, normalization, architecture, dataset size — and defend each choice.
- Label a failed rollout as perception, coverage, compounding drift, or hardware failure using log signatures rather than intuition.
Behavioral cloning is the technique you already know best, wearing a lab coat. Take a dataset of expert demonstrations, treat every observation-action pair as a labeled example, and minimize prediction loss with SGD — it is supervised fine-tuning where the tokens are motor commands. The entire modern VLA stack, π₀ and OpenPI (opens in a new tab) included, is behavioral cloning at heart: expressive architectures, but the loss is still “match what the demonstrator did.” Familiar — so why open the learning phase with it? Because closing the loop breaks the one assumption supervised learning stands on, and the way it breaks — quadratically in episode horizon — is arguably the single most important fact about robot learning. You have met this failure before, under the name exposure bias.
Foundations: Defining the Control Abstractions
Before deriving error bounds, we must rigorously define the control-theoretic abstractions that the lesson relies on. The first is the state-only policy. In this context, a state-only policy is a mapping where the input vector consists exclusively of numerical proprioceptive and external sensor data—specifically joint angles, joint velocities, and object pose in the base frame. Crucially, this excludes raw pixel data. This abstraction exists to isolate control logic from perception errors. If the policy fails, we can attribute the failure to the control law rather than a vision backbone misinterpreting a shadow. This separation is essential for the failure taxonomy discussed later.
The second abstraction is teacher forcing in a continuous control context. In standard supervised learning, the model is trained on a fixed dataset. In control, this means the policy is trained on states generated by the expert policy . During training, the policy never sees its own errors; every input state is the result of the expert's action . This contrasts with free-running deployment, where the policy's output becomes part of the next input through the physics of the environment. The mismatch between these two regimes is the root cause of distribution shift.
To quantify this shift, we define the tube of states. Let be the nominal trajectory generated by the expert. The tube is the set of all states reachable by the expert policy within a small deviation from . The policy is only guaranteed to perform well within this tube. If the policy's action deviates from the expert's action by more than a threshold, the state may exit the tube, and the training guarantee no longer applies. We define as the probability that the policy's action deviates from the expert's action by more than on the expert's state distribution. This is a discrete error probability, not a continuous error magnitude.
The third abstraction is action chunking. Instead of predicting a single action , the policy predicts a sequence of actions at once. This reduces the effective horizon in the error compounding formula to . By reducing the number of decision points, action chunking reduces the quadratic term in the regret bound. It also matches how humans demonstrate, as teleop actions encode intent over a short horizon rather than just the current frame.
Worked Example: Deriving the Quadratic Bound
Consider a WidowX pick task with steps and a per-step error probability . We want to derive the quadratic bound on the total regret. The key step is to bound the probability of being off-distribution at step . By the union bound, the probability of making an error at any previous step is at most . If an error occurs, the state exits the tube, and the worst-case cost is 1.
Plugging in the numbers: and . The bound is . The maximum possible cost for the task is . Since the bound (311.25) exceeds the maximum possible cost (250), the bound is vacuous. This means the theory provides no useful information about actual performance; the policy is likely to fail completely. If DAgger reduces the effective error to , the bound becomes , which is well within the maximum cost, indicating a high probability of success.
| Failure Type | Log Signature | Physical Cause |
|---|---|---|
| Actuator Lag | Commanded vs. measured position error grows linearly with time | Insufficient torque or bandwidth in the joint controller |
| Communication Latency | Jitter in command timestamps; sporadic large errors | Network congestion or USB bus contention |
Why is the quadratic bound for and considered vacuous?
Imitation as supervised learning — and the assumption it quietly breaks
Set up the notation for the rest of this phase. You teleoperate the WidowX through a task — pick a block, drop it in a bin — logging observation-action pairs at the policy rate. Call the expert (you) and the logged dataset . Behavioral cloning fits a policy by empirical risk minimization, exactly as if this were regression:
Supervised learning's generalization guarantees assume train and test inputs drawn i.i.d. from one distribution — plausible in classification, where inputs are exogenous: nothing the classifier predicts changes which image arrives next. A control loop violates this by construction: the observation at tick is physics applied to the command at tick . Write for the distribution of states visited when closes the loop. Training measured your loss under ; deployment evaluates you under — a distribution your own errors generate:
Make it concrete with your hardware. A pick episode on the WidowX runs about 25 seconds with the policy ticking at 10 Hz: sequential decisions, each conditioning the next input through the arm's dynamics. Suppose held-out validation says the policy matches your demonstrations 99% of the time — a number measured on states you steered into. The first 1% event — the gripper 2 cm left of any demonstrated approach — puts the policy somewhere it has never been graded, and the validation number no longer applies. What happens next is the most cited argument in imitation learning.
Compounding error: deriving the quadratic bound
The classic argument, due to Ross and Bagnell, formalizes the snowball. Use the simplest cost model that captures it: at each step the policy matches the expert or makes a mistake; training got the mistake probability down to on the expert's distribution; off that distribution we assume nothing, and each wrong step can incur cost up to 1. The derivation is three lines, each worth internalizing:
Had training states come from the learner's own distribution instead, the per-step guarantee would hold at every visited step and total regret would be — a factor of better. Plug in your numbers: , gives on-distribution versus for BC, past the maximum possible cost of 250. With 1% per-step error the guarantee goes vacuous around step — your episode lives 150 steps beyond the edge of the theory. The bound is also tight: Ross and Bagnell exhibit a cliff-walking problem, where one mistake leaves the recoverable region, that realizes the quadratic. Real manipulation sits in between: a closing gripper funnels nearby states into the same grasp, but once the block is knocked over, no demonstrated state resembles the current one.
Autoregressive LLMs have exactly this train/deploy mismatch — teacher forcing during training, self-conditioning during generation — and the community named the resulting drift exposure bias a decade ago. Why do LLMs mostly get away with what breaks robots? Coverage: trillion-token pretraining means the model's own outputs rarely leave the training distribution's support; your 12,500-transition WidowX dataset has no such luxury. Recoverability: a weak token can be semantically absorbed downstream, but physics has no attention mechanism that reinterprets a bad torque. On-policy fine-tuning: RLHF and its variants explicitly train on model-generated states — precisely the fix imitation learning proposed first. That fix has a name.
You evaluate your BC policy on held-out expert states and it disagrees with the expert on only 1% of them. On the robot, 25-second episodes at 10 Hz (T = 250) fail more than half the time. What best explains the gap?
DAgger: fix the distribution, not the model
DAgger — Dataset Aggregation, from Ross, Gordon, and Bagnell, 2011 (opens in a new tab) — attacks the subscript directly: if training states come from while deployment visits , then collect labels on the learner's own states:
- Train an initial policy with plain BC on the expert demos.
- Roll out the current policy on the robot and record every state it visits — including the awkward ones it steered itself into.
- Ask the expert to label those visited states: for each recorded , what action would have taken?
- Aggregate the new pairs into the dataset () and retrain on everything.
- Repeat. Under a no-regret analysis, the best iterate satisfies — linear, not quadratic.
In simulation, where the “expert” is an oracle controller queryable in microseconds, DAgger works exactly as advertised. On a real robot with a human teleoperator, step 3 collides with human factors. Post-hoc labeling means staring at a frozen mid-failure frame and answering “what exact 7-dim command would you have issued here?” — humans give continuous corrections in context, not calibrated per-state actions out of it, so the labels come back noisy and biased. Real-time labeling means the expert supervises every rollout, hand hovering over the controller — erasing the labor savings that motivated learning, each takeover a safety event on a physical arm. And each outer-loop iteration costs hours of lab time at 25 wall-clock seconds plus a manual reset per rollout. So the field keeps DAgger's idea while approximating its mechanics:
| Strategy | How off-distribution states get labels | Teleop burden | What you give up |
|---|---|---|---|
| Textbook DAgger | Expert labels every state the learner visited, after the fact | Brutal: thousands of out-of-context per-frame queries per iteration | Humans are unreliable at post-hoc per-state action labeling |
| Expert-gated takeover | Human watches each rollout and grabs the controller when the policy misbehaves; corrections are logged | Full attention on every rollout, plus a safe handoff mechanism | Labels concentrate near the takeover boundary, not deep in failure states |
| Noise-injected demos | Noise injected during demonstration makes the demos themselves contain error states plus the expert's natural corrections | None beyond normal demonstration | Coverage only of a tube around expert behavior, tuned by noise scale |
| Recovery clips | Episodes start from deliberately perturbed or failure states and the expert demonstrates the fix | Extra collection sessions, modest | You must guess in advance which failure states will matter |
On the WidowX, the last two rows are your workhorses. Recovery collection is cheap: nudge the block 3–5 cm after reset, or start the arm just off the demonstrated approach corridor, then teleoperate the correction. A common practitioner heuristic makes roughly 10–20% of a dataset recovery-flavored — enough that the policy has seen the direction home from the states its own drift will produce. This is DAgger with the human predicting the learner's mistakes instead of observing them, and it is the cheapest robustness lever you have.
Why modern BC works anyway
Given a quadratic lower bound, why do BC-trained systems — up to and including π₀-class VLAs — manipulate objects successfully for minutes at a time? Four levers, all pulled in this phase. First, action chunking. Predict a chunk of future actions and execute them before re-observing. The compounding argument counts decisions, not timesteps: a 250-step episode with makes only 13 decisions. Chunking also matches how humans demonstrate — teleop actions encode intent over the next second, not just the current frame, so chunk targets are cleaner labels than per-step Markov ones. This is the core of ACT, lesson 3 — and the exact structure whose latency behavior your capstone will study.
Second, expressive policy classes. Demonstrations are multimodal: confronted with a tall obstacle between gripper and bin, you route left on some demos and right on others, both correct. A deterministic network trained with MSE cannot represent “left or right” — the loss forces it to the conditional mean:
Half of your demonstrations route the gripper left around a tall obstacle and half route right. You train a deterministic MLP with MSE loss. At the decision point, what does the trained policy most likely command?
Third, viewpoint choices that shrink the shifted distribution. A wrist-mounted RealSense-class camera makes observations approximately relative — the block looks the same in wrist-cam pixels anywhere in the workspace — so a single demo covers a family of absolute configurations, and the learner's drifted states more often look like training data. Fourth, and dominating everything: coverage. The result repeated across recent large-scale imitation efforts is that data diversity — initial poses, lighting, distractors, recovery segments — moves success rates more than architecture choices do. The quadratic bound never stops being true; broad data makes small on a wider distribution, so the first mistake arrives later and lands somewhere still covered. Remember this hierarchy when tempted by a bigger model in week 8.
The Phase 03 baseline — and the failure taxonomy it exists to expose
Now design the artifact this lesson exists to produce: the deliberately simple baseline you train first and keep forever as an experimental control. The task is a fixed-scene pick: one block, a bin, scripted resets, object pose from a fiducial tag seen by your RealSense-class camera and transformed into the base frame with your Phase 01 calibration. The baseline is state-only on purpose — no images enter the network — which removes the perception confound: when it fails, a vision backbone misreading a shadow is not a suspect. Image-conditioned policies arrive with ACT in lesson 3, and you will want a policy beneath them whose failures you already understand.
The interface: observations are 17 dimensions — 7 joint positions (6 arm joints plus gripper), 7 joint velocities, 3 for object position in the base frame. Actions are 7 absolute joint-position targets at 10 Hz — absolute rather than deltas, because delta policies accumulate integration error along the very drift dimension you want to study. Normalize both sides with per-dimension z-scores computed on the training split only: joint angles span radians while gripper width spans centimeters, and unnormalized MSE silently downweights the gripper — the dimension that decides whether the grasp closes. The network is a 3-layer MLP, 17 → 256 → 256 → 7, about 72k parameters; it converges in under a minute on your RTX workstation from 50 demonstrations (roughly 12,500 pairs). That is the point: iteration speed on the data is worth more than capacity in the model, and a small MLP on clean state goes far further than vision-model intuition suggests.
import numpy as np
OBS_DIM = 17 # 7 joint pos + 7 joint vel + 3 object xyz in base frame
ACT_DIM = 7 # 6 arm joints + 1 gripper, absolute position targets
# WidowX AI published joint limits (rad; gripper in m) -- confirm against your driver config.
JOINT_LOW = np.array([-3.14, 0.00, 0.00, -1.57, -1.57, -3.14, 0.0])
JOINT_HIGH = np.array([3.14, 3.14, 2.36, 1.57, 1.57, 3.14, 0.04])
MAX_STEP = 0.06 # rad per 10 Hz tick: never command a larger jump
def split_by_episode(episodes, val_frac=0.1, seed=0):
"""Split whole episodes, never transitions: adjacent frames are
nearly identical, so a transition-level split leaks train into val."""
rng = np.random.default_rng(seed)
order = rng.permutation(len(episodes))
n_val = max(1, int(len(episodes) * val_frac))
val = [episodes[i] for i in order[:n_val]]
train = [episodes[i] for i in order[n_val:]]
return train, val
def fit_normalizer(train_episodes):
"""Per-dimension z-score stats from the training split only."""
obs = np.concatenate([ep["obs"] for ep in train_episodes])
act = np.concatenate([ep["act"] for ep in train_episodes])
return {
"obs_mu": obs.mean(0), "obs_sig": obs.std(0) + 1e-6,
"act_mu": act.mean(0), "act_sig": act.std(0) + 1e-6,
}
class Deployer:
"""Wraps the trained net for the 10 Hz control loop."""
def __init__(self, net, stats):
self.net = net # 17 -> 256 -> 256 -> 7 MLP, ~72k params
self.s = stats
def act(self, obs, qpos_now):
z = (obs - self.s["obs_mu"]) / self.s["obs_sig"]
a = self.net(z) * self.s["act_sig"] + self.s["act_mu"]
a = np.clip(a, JOINT_LOW, JOINT_HIGH) # joint limits
delta = np.clip(a - qpos_now, -MAX_STEP, MAX_STEP)
return qpos_now + delta # rate-limited commandYour baseline will fail — plan on 40–70% success from 50 demos — and the failures are the curriculum, but only if you can tell them apart: the fix for a coverage gap (collect demos there) is the opposite of the fix for a perception fault (leave the policy alone). From the first evaluation session, every failed episode gets one primary label from this taxonomy plus a sentence of evidence, written at reset time. This habit is the raw material for lesson 2's data-quality work and lesson 6's statistics.
| Failure class | Signature in the rollout | Telltale in the logs | First fix |
|---|---|---|---|
| Perception / state estimation | Confident, smooth motion — toward the wrong place; behavior would be correct if the state were true | Object pose jumps, freezes, or disagrees with a ruler check; tag dropout frames | Fix the estimator and calibration; the policy is innocent |
| Coverage gap | Policy stalls, dithers, or emits an averaged, incoherent motion in a scene condition no demo contained | Nearest-neighbor distance to the training set jumps at a specific event, with no prior ramp | Collect demonstrations in exactly that condition |
| Compounding drift | Starts on-path; a small early deviation grows smoothly until the grasp misses by centimeters | Nearest-neighbor distance ramps monotonically over tens of steps from the first deviation | Recovery clips near the drift corridor; consider chunking |
| Hardware / controller | Motion disagrees with the commands: sag, overshoot, gripper slip, mid-episode stop | Commanded-vs-measured joint error grows; driver fault flags; effort or comms faults | Retune, repair, or re-torque; retraining cannot help |
Notice how much weight one probe carries: the per-timestep distance from visited states to the nearest training-set state, computed in normalized state space. A step change says coverage; a slow monotonic ramp says drift; an in-band curve during a miss says perception; none of the above with bad tracking error says hardware. It is a crude density estimate, but cheap at 17 dimensions and 12,500 reference points, and it turns “out of distribution” into a number per tick — exactly the instrumentation this course keeps insisting on.
Measure the drift before it owns you
Using 10 logged rollouts of your BC baseline plus the training dataset (before the policy exists, use a scripted controller and perturbed replays): (1) z-score all states with the training-split statistics; (2) for every rollout timestep, compute the Euclidean distance to the nearest training-set state; (3) plot nearest-neighbor distance versus timestep for successes, failures, and held-out expert episodes on one figure; (4) give each failed episode one taxonomy label supported by its curve plus the video.
Need a hint?
A KD-tree (scipy.spatial.cKDTree) over 12,500 states in 17 dimensions answers thousands of queries in milliseconds — build it once from the normalized training states. Held-out expert episodes are your calibration band: any rollout inside it is unremarkable to this probe. Separate drift from coverage by onset shape — gradual ramp versus step change — not by final magnitude.
Where this goes next: the previous lesson, Linear systems, LQR, and feedback — the EE refresher, gave you policies derived from a model, with stability margins computable before touching the arm. Behavioral cloning trades the model for data and the guarantee for a distribution match that deployment immediately violates — this lesson gave you the theory of that violation and the baseline that will exhibit it. Next, Demonstration data: collection, quality, and splits turns the 50-demo dataset sketched here into a designed artifact: coverage plans, recovery-clip budgets, and the episode-level splits your evaluation will stand on.