Offline RL: when imitation is not enough
Offline RL promises what no imitator can — a policy better than the demonstrator, from logged data alone — but distribution shift relocates into the value function, where a max operator turns noise into divergence. Learn the pathology, the CQL/IQL fixes, and the honest decision table for a real arm.
- Derive why maximizing a learned Q-function over out-of-distribution actions produces overestimation that diverges offline but self-corrects online.
- Explain CQL's conservative penalty and IQL's expectile-regression trick precisely enough to implement either from its paper.
- Decide from a dataset's composition and reward availability whether offline RL or the BC family is the better bet, defending the call with the stitching and coverage arguments.
- Specify a sparse-reward labeling scheme for a WidowX tabletop task, including hindsight relabeling and its labeling cost.
Every policy in this phase shares a ceiling. Behavioral cloning, ACT, and Diffusion Policy are — under three different losses — the demonstrator, compressed. If your teleoperated grasps succeed 85% of the time, a faithful imitator succeeds about 85% of the time: the fumbles are in the training distribution, and a density model reproduces them. Offline RL is the field's standing offer to break that ceiling: from the same logged episodes, plus a reward label, learn a policy better than the one that collected the data — with zero exploratory actions on the physical arm. If you have watched RLHF turn a frozen preference dataset into a better model, the offer sounds plausible. The catch: the distribution shift you mapped in the behavioral-cloning lesson does not disappear when you add a value function. It relocates into the value function, where it compounds faster and hides better.
Foundations: Support, Error Decomposition, and the Geometry of Optimization
Before deriving the divergence of offline value estimation, we must rigorously define the geometric and statistical objects that make the failure possible. The core issue is not merely that the data is finite, but that the data is localized. In a continuous state-action space, the dataset does not cover the entire space uniformly; it occupies a specific region. We define the support of the dataset, denoted , as the set of state-action pairs where the behavior policy has non-negligible probability density. Formally, for a threshold , if . Points outside this region are off-support. The critical distinction is that off-support points are not merely 'unseen'; they are regions where the approximator has no gradient signal from the data, allowing its output to be determined entirely by the inductive bias of the architecture and the initialization of its weights.
To understand why the max operator fails, we must decompose the error of the learned Q-function into two distinct components. Let be the true optimal Q-function. The error can be split into estimation error and extrapolation error . Estimation error arises from the finite number of samples within the support; it is a variance term that decreases as . Extrapolation error arises from the model class's inability to constrain its output outside the support; it is a bias term that depends on the distance from the support and the complexity of the approximator. A common misconception is that collecting more data fixes offline RL. This is false: increasing reduces but does not reduce . If the behavior policy is narrow, the support remains narrow regardless of , and the extrapolation error at the boundary of the action space remains unbounded.
The distinction between estimation and extrapolation error is crucial for diagnosing failure. If a critic diverges, checking the loss on the training set is insufficient. A low training loss only guarantees small on-support. It says nothing about off-support. To diagnose extrapolation failure, one must evaluate the critic on a held-out set of actions that are off-support but physically valid. If the Q-values on these actions are wildly different from the true values (or from the Q-values on nearby on-support actions), the critic is extrapolating. This is the 'extrapolation gap.' In practice, this gap is the primary driver of the bias in the Bellman backup, not the variance of the on-support fit.
| Error Type | Source | Depends on Sample Size N? | Depends on Support Width? | Behavior as N increases |
|---|---|---|---|---|
| Estimation Error () | Finite samples within support | Yes (decreases as ) | No | Decreases |
| Extrapolation Error () | Model class bias outside support | No | Yes (increases with distance) | Constant or Increases |
| Total Error () | Sum of both | Yes (initially) | Yes | Plateaus at |
This decomposition explains why 'more data' is not a panacea. If the behavior policy is a Gaussian with standard deviation , the support is effectively . Doubling the dataset size does not change ; it only makes the fit within tighter. The extrapolation error at (if ) remains determined by the architecture's inductive bias. For a neural network with ReLU activations, the function is piecewise linear. In regions with no data, the weights are not updated by the data loss, so they remain at their initialization or drift due to regularization. This drift is uncontrolled and can lead to large, arbitrary Q-values. The 'divergence' is not a smooth explosion but a random walk in the weight space that projects to large values in the off-support region.
Worked Example: Divergence in a 1-D Cart-Pole
Consider a simplified 1-D Cart-Pole task. The state is the cart position and the action is the cart velocity . The true Q-function is , which is maximized at with value 0. The behavior policy is a Gaussian with , so the support is effectively . We have a dataset of 1000 transitions. We fit a 2-layer MLP with 32 hidden units to estimate . The noise in the returns is .
Step 1: Fit the critic. Within the support , the MLP fits the data well. The estimation error is small, approximately 0.05. Outside this range, the MLP extrapolates. Due to the ReLU activation, the function becomes piecewise linear. In regions with no data, the gradient of the loss is zero, so the weights remain at their initialization or drift due to regularization. Suppose that at (off-support), the MLP outputs , while the true value is . The extrapolation error here is . This is a large positive error, caused by the random initialization of the weights in the off-support region.
Step 2: Gradient ascent on the actor. The actor starts at . It performs gradient ascent on . Initially, the actor is in the support, where is accurate. The gradient points toward . However, as the actor moves, it eventually reaches the boundary of the support. At , the actor is still in the support. At , the actor is off-support. The gradient at is determined by the noise field. Suppose the noise gradient points toward . The actor moves to . At , the MLP outputs , while the true value is . The extrapolation error is now . The actor continues to move toward higher , eventually converging to , where and the true value is . The actor has converged to a point where the critic's hallucination is largest.
Step 3: The fix with IQL. IQL avoids this by never evaluating off-support. It computes using expectile regression on dataset actions only. For , the dataset actions are in . The best dataset action is with . The expectile approximates this best in-sample value, say . The advantage is computed only for dataset actions. For , . For (not in dataset), is not computed. The AWR policy weights highly, and the actor stays near . The extrapolation channel is closed.
In the 1-D Cart-Pole example, why does the actor converge to instead of ?
The promise: improvement without exploration
Fix notation. You have a dataset logged by some behavior policy — teleop sessions, scripted rollouts, old evaluations. On your rig: 200 episodes at 10 Hz for 25 s is about 50,000 transitions of RealSense frames, 7-dim joint states (six joints plus gripper), commanded actions, and (new in this lesson) a reward. The goal: a policy that outperforms , trained entirely from . What makes improvement conceivable is dynamic programming — back returns up through the Bellman equation.
Two properties make this backup more than BC-with-extra-steps. It is off-policy by construction — the target does not care which policy produced a transition, so failed episodes become usable signal rather than contamination. And it composes across trajectories: a value function fit on episode 12's reach and episode 47's grasp can rank a combination neither episode executed. That composition, stitching, is how the learner can beat every individual demonstration. But look at the max: in a 7-dim continuous action space it is an actor network or sampling optimizer doing gradient ascent on , and nothing constrains its proposals to lie near the data. That one unguarded operator is where the field's entire difficulty lives.
The pathology: maximizing over a liar
Your Q-network is a function approximator, so its estimate is the truth plus an error field: . On-support, is small and roughly zero-mean — standard generalization. Off-support it is whatever the architecture extrapolates, with no data to pull it back. Now push a max through that noise:
Plug in your numbers: noise on returns normalized to , an actor that effectively screens candidate actions (so ), and . The fixed-point bias is at least — an eighteen-fold overestimate of the best possible return, from 5% noise and one max operator. And the bound is optimistic — it holds fixed: the actor's gradient ascent on migrates toward the largest positive extrapolation errors, so at the argmax grows without bound. The actor is an adversarial-example generator pointed at your own critic.
What separates offline from online RL here is a feedback-control argument. Online, the agent executes the overestimated action, the environment returns the true reward and next state, and the next regression step pushes back down: overestimation triggers exactly the data that corrects it — negative feedback. Offline, that wire is cut. The optimizer inflates at actions nobody took, contradicting evidence can never arrive, and the recursion runs open-loop until the value function is fiction. BC's distribution shift compounded through physics over one episode; offline RL's compounds through bootstrapping over the whole training run, with as its gain.
import numpy as np
rng = np.random.default_rng(0)
# Normalized 1-D action (think: one joint-velocity channel in [-1, 1]).
# The behavior policy only ever explored the slice [-0.2, 0.2].
actions = rng.uniform(-0.2, 0.2, size=400)
def q_true(a):
return -2.0 * (a - 0.1) ** 2 # true optimum inside the data
returns = q_true(actions) + rng.normal(0.0, 0.05, size=actions.shape)
# Fit Q with a degree-5 polynomial: any smooth approximator extrapolates.
X = np.vander(actions, N=6, increasing=True)
w, *_ = np.linalg.lstsq(X, returns, rcond=None)
grid = np.linspace(-1.0, 1.0, 2001) # the FULL actuator range
q_hat = np.vander(grid, N=6, increasing=True) @ w
in_support = np.abs(grid) <= 0.2
print("true max (inside data): ", round(q_true(0.1), 3))
print("Q-hat max, inside support: ", round(float(q_hat[in_support].max()), 3))
print("Q-hat max, full range: ", round(float(q_hat.max()), 3))
print("argmax action: ", round(float(grid[q_hat.argmax()]), 3))Run it. Inside the data slice the fit is excellent: estimated max against a true max of . Over the full range the same polynomial reports a max of 212.9, at action — the edge of the range, as far from the data as the optimizer can travel. No pathology was injected: unbiased noise, 400 clean samples, a reasonable model class. The lie is not in the fit; it is in where you asked. Now picture this across 7 action dimensions and a learned state embedding, each iteration regressing the inflated max into the next target.
You train a SAC-style actor-critic on a frozen 50k-transition WidowX buffer. Critic loss steadily decreases, yet logged Q-values climb to 4,000 on a task whose maximum return is 1. The same code run online in simulation keeps Q near 1. What breaks offline?
Two escape routes: penalize the answer, or never ask the question
Every practical offline RL algorithm answers one design question: how do you use a max operator over a function you can only trust on-support? The conservative family keeps querying arbitrary actions but rigs the critic so off-support answers come back pessimistic. CQL (opens in a new tab) (Conservative Q-Learning, Kumar et al. 2020) is the canonical member: alongside the Bellman error, it adds a term pushing Q down wherever the optimized policy finds high values, and up on dataset actions.
The price is a live hyperparameter, : too small and the exploit survives; too large and the critic is so pessimistic the policy collapses onto the behavior policy — you paid for RL machinery and bought a worse BC. The second family never asks off-support questions at all. IQL (opens in a new tab) (Implicit Q-Learning, Kostrikov, Nair, and Levine 2021) replaces the max over the action space with a statistic computed only on actions in the dataset, using expectile regression — an expectile is to the mean what a quantile is to the median, an asymmetrically weighted version:
import numpy as np
rng = np.random.default_rng(1)
# Q-values of actions the DATASET actually took in one state bucket:
# 20 mediocre grasp approaches and 3 good ones. Nothing else exists.
q_samples = np.concatenate([
rng.normal(0.20, 0.05, size=20),
rng.normal(0.90, 0.02, size=3),
])
def fit_expectile(samples, tau, steps=4000, lr=0.05):
v = samples.mean()
for _ in range(steps):
diff = samples - v
grad = -2.0 * np.mean(np.where(diff > 0, tau, 1.0 - tau) * diff)
v -= lr * grad
return v
for tau in (0.5, 0.7, 0.9, 0.99):
print("tau =", tau, "-> V =", round(float(fit_expectile(q_samples, tau)), 3))
print("best in-sample Q:", round(float(q_samples.max()), 3))The output walks from the mean to the best in-sample action: gives (the behavior policy's mediocre average), gives , and gives against a best in-sample Q of . IQL alternates two such regressions — fit as a high expectile of over dataset actions, then fit by TD against , which needs no action query at $s'$ at all. No network is ever evaluated outside : the extrapolation channel is closed by construction, not by a tuned penalty.
IQL trains value functions but no policy. Extraction is a separate, simple step — advantage-weighted regression (AWR (opens in a new tab), Peng et al. 2019). Ask for the best policy that stays close to the behavior policy, and the answer falls out of two lines of variational calculus:
Read the final line as an engineer: it is behavioral cloning with per-transition sample weights . Above-average transitions get up-weighted; below-average ones fade toward zero. Every piece of BC infrastructure from this phase — dataloaders, normalization, the ACT or Diffusion Policy backbone — is reusable; offline RL enters as one extra column in the batch. That is how the field mostly uses it on manipulators: not an alien algorithm family, a principled reweighting of imitation.
In IQL with tau = 0.9, the learned V(s) is best described as approximating which quantity?
When offline RL beats BC on a real robot — and when it cannot
Now the decision you face with your own 200-episode dataset. Say 120 episodes are clean successes, 45 pair a flawless reach with a botched grasp, and 35 recover a clumsy reach into a clean grasp. Diffusion Policy, a faithful density model, learns all of it — including a mode that fumbles grasps. A value function sees the same data differently: the good reach and good grasp segments each carry high-advantage transitions, and dynamic programming can rank the composite — clean reach stitched to clean grasp — above every complete episode. Stitching is the mechanism behind every legitimate claim that offline RL beat BC: the improvement already existed as segments; the value function is the composition operator.
Stitching has preconditions — the terms of the decision table. You need a reward signal to define advantage — without one, BC is the only option. You need diversity with overlap — segments compose only where trajectories pass through similar states; 50 near-identical expert demos offer nothing to stitch. And you need enough data to fit a Q-function, a harder estimation problem than fitting a policy. The empirical record (Levine et al.'s offline RL tutorial (opens in a new tab)) is consistent: on narrow, near-expert data, well-tuned BC matches or beats offline RL; offline RL pulls ahead when data is large, mixed-quality, and reward-labeled.
| Your dataset looks like… | Reward signal | Better bet | Why |
|---|---|---|---|
| 150–300 near-expert teleop episodes, one operator, consistent style | None | BC family (ACT / Diffusion Policy) | The demonstrator's ceiling is high; value estimation adds variance with no signal to exploit |
| Mixed-quality logs: ~40% failures, good segments inside bad episodes | Sparse success labels | Offline RL (IQL + AWR extraction) | Stitching composes partial successes; advantage weights filter bad segments instead of imitating them |
| Multi-task play data, many goals reachable from overlapping states | Hindsight-relabeled goals | Offline RL, goal-conditioned | Relabeling manufactures dense supervision; shared structure across goals is exactly what DP exploits |
| 50 demos of one precise insertion, minutes of total data | None or sparse | BC family | Far too little data to fit a Q-function; value-estimation error would dwarf the imitation gap |
| Thousands of autonomous eval rollouts from your own policy, auto-labeled | Binary per episode | Offline RL fine-tuning on a BC initialization | Learner-distribution coverage plus reward: the regime where the machinery pays for itself |
What is a reward, on a tabletop?
The table's second column hides the real cost. In simulation, reward is a free function call; on your bench it is a labeling pipeline. The practical baseline for manipulation is the sparse success label: everywhere except on success. It is cheap — about two seconds per episode from the final wrist-camera frame, so 400 episodes cost under fifteen minutes — and honest, encoding the task definition and nothing else. Dense shaping (distance terms, grasp bonuses) looks like free signal but breeds reward hacking: a distance-shaped reach reward will happily park the gripper 5 mm from the block forever, never risking the grasp. The catch with sparsity is horizon: one terminal bit must propagate backward through the whole episode.
Two tools soften the sparsity. Hindsight relabeling, for goal-conditioned policies: a failed pick that knocked the block to the table's left edge is a perfect demonstration of reaching the left edge — relabel the episode with the outcome it achieved, and the failure becomes a success for a different goal. Your 45 botched-grasp episodes turn into supervision with zero robot or human time. Automated success detection, once any policy is running: a small classifier on the final RealSense frame (block in bin: yes or no) labels episodes as they happen — making the table's last row realistic rather than hypothetical.
The verdict for this course
Where does this leave the capstone? The BC family carries it. The OpenPI (opens in a new tab) stack you will fine-tune next phase is flow-matching imitation — π₀ matches demonstrations rather than maximizing reward — and latency-aware chunking modifies when and how actions execute, orthogonal to training. Offline RL enters your work twice. As literacy: a growing slice of the VLA literature is offline-RL-shaped (value-guided action selection, advantage-weighted fine-tuning, RL on BC initializations), unreadable without the overestimation story and the CQL/IQL distinction. And as the failure-driven tool: once your logs hold diverse, reward-labeled, learner-distribution data — the table's last row, reached by default — advantage-weighted methods are a cheap upgrade. Until then, offline RL is a solution to a problem you do not have yet.
Watch fitted Q-iteration diverge, then contain it
Build a divergence lab in numpy, no robot required. Environment: 1-D gripper offset m, action (normalized velocity), dynamics , reward 1 when m else 0, . Dataset: 500 transitions from a noisy proportional controller whose actions stay within . Implement fitted Q-iteration with a small feature map on , taking the backup max over a dense action grid on , for 100 iterations in three variants: (a) naive; (b) CQL-style — subtract times (mean over grid actions minus mean over dataset actions); (c) in-sample — restrict the backup max to dataset-supported actions. Deliver a plot of max versus iteration for all three, plus three sentences: where the naive argmax migrated, why the bound certifies hallucination, and which variant you would trust for policy extraction.
Need a hint?
Keep the feature dimension modest — a degree 4–5 polynomial is plenty; richer features just diverge faster. If the naive run refuses to diverge, widen the backup grid relative to the data support; divergence needs the argmax to escape the data. Track the argmax action alongside max Q each iteration: watching it march to the grid boundary and pin there is the lesson.
Where this goes next: Diffusion Policy: actions as denoising gave you the strongest imitator in this phase; this lesson told you when imitation itself is the bottleneck — and what the exit costs. But every load-bearing claim here was an evaluation claim: “beats BC,” “85% versus 92%,” “stitching pays off.” On hardware you will test such claims with maybe 20 rollouts per policy, where a 7-point success-rate difference is statistically invisible. Evaluating policies: statistics you can defend closes the phase by making sure that when you choose between an imitator and a value-based upgrade, the number you point to means something.