Skip to content
AI360Xpert
Beta

Batch Constrained Q-Learning (BCQ)

Instead of letting an agent dream up risky actions no human ever demonstrated, BCQ confines its choices to tracks already in the dataset, tuning them only with a short mathematical leash.

BCQ samples three in data actions from a VAE, perturbs them within 0.05, and picks action 1.04 for a target of 5.585
BCQ samples three in data actions from a VAE, perturbs them within 0.05, and picks action 1.04 for a target of 5.585

Why Does This Exist?

Offline reinforcement learning learns from a fixed log D={(s,a,r,s′)}\mathcal{D} = \{(s, a, r, s')\} with no fresh environment interaction. That is the only option when interaction is slow, costly, or unsafe, and it is exactly where standard off policy methods break. The background on the setting is in offline batch reinforcement learning and the failure pattern is named in distributional shift in offline RL.

The break has a name: extrapolation error. A Bellman backup queries max⁡a′Q(s′,a′)\max_{a'} Q(s', a'), and in continuous control the actor actively hunts for the action with the largest predicted value. For actions far from the logged data, the critic has seen no ground truth, so its output is an accident of function approximation. The actor latches onto the tallest hallucination, the backup bakes that fantasy into earlier states, and the deployed policy drives off the data manifold. Online learning would correct this by visiting the suspect action and observing the truth. Offline learning cannot.

Batch Constrained Q-Learning (Fujimoto, Meger, and Precup, 2019) was the first deep method built to stop this loop. It never asks the critic about arbitrary actions. It samples candidate actions from a generative model of the logged behavior, allows only tiny bounded adjustments, and scores candidates pessimistically. A later, more explicitly pessimistic alternative is conservative Q-learning.

Think of It Like This

Ski tracks after fresh snow

Fresh snow covers a mountainside and you must ski down without hitting rocks. Earlier skiers left visible tracks. You do not know why each turn was chosen, but every track is proof that path was survivable.

Standard off policy RL ignores the tracks and heads for the line its map says is fastest, straight over an unmarked cliff. BCQ skis inside the existing tracks, shifting a few centimeters left or right to find smoother snow, and asks two guides for the safer read on each option before committing.

Where the analogy stops: ski tracks are visible lines on a hill. A behavior distribution over continuous actions is a high dimensional density that must be learned, and the safe sideways shift needs a number, which is the perturbation bound below.

How It Actually Works

BCQ has three coupled parts. GωG_\omega is a conditional variational autoencoder modeling logged actions PD(a∣s)P_{\mathcal{D}}(a \mid s). ξϕ(s,a)\xi_\phi(s, a) is a perturbation network capped by Φ\Phi. Qθ1Q_{\theta_1} and Qθ2Q_{\theta_2} are twin critics. Here s′s' is the next state, aia_i are sampled candidates, a~i\tilde{a}_i are perturbed candidates, rr is the reward, and γ\gamma is the discount factor.

Candidate generation from the behavior model

The C-VAE trains on logged pairs (s,a)(s, a) with an encoder q(z∣s,a)q(z \mid s, a) and decoder D(s,z)D(s, z). At decision time BCQ draws NN latent codes ziz_i from a standard Gaussian and decodes ai=D(s′,zi)a_i = D(s', z_i). Because the decoder only ever learned logged behavior, these candidates sit on the data manifold by construction. Sampling more candidates (commonly N=10N = 10 to 100100) covers multimodal behavior better at the cost of more critic evaluations.

Bounded perturbation

Pure sampling would only clone the logger. BCQ adds a~=a+ξϕ(s,a)\tilde{a} = a + \xi_\phi(s, a) with ξϕ(s,a)=Φtanh⁡(MLPϕ(s,a))\xi_\phi(s, a) = \Phi \tanh(\text{MLP}_\phi(s, a)), so no tweak exceeds ±Φ\pm \Phi in each action dimension. A typical setting is Φ=0.05\Phi = 0.05 times the action range. The perturbation network trains to maximize Qθ1(s,a+ξϕ(s,a))Q_{\theta_1}(s, a + \xi_\phi(s, a)), which is local hill climbing on a short leash: enough to beat a mediocre logger, too short to wander into unsupported regions.

Pessimistic twin critic target

Each perturbed candidate is scored with min⁡jQθj(s′,a~i)\min_j Q_{\theta_j}(s', \tilde{a}_i), the lower of the two critic reads. The policy picks the argmax of that minimum, and the Bellman target mixes min and max with weight λ\lambda in [0.75,1.0][0.75, 1.0]:

y=r+γmax⁡i[λmin⁡jQj′(s′,a~i′)+(1−λ)max⁡jQj′(s′,a~i′)]y = r + \gamma \max_i \left[ \lambda \min_j Q'_j(s', \tilde{a}'_i) + (1 - \lambda) \max_j Q'_j(s', \tilde{a}'_i) \right]

With λ=1.0\lambda = 1.0 the target is the pure minimum, the most conservative choice.

Worked example

Logged actions near state s′s' concentrate in [0.8,1.2][0.8, 1.2]. Fix r=1.5r = 1.5, γ=0.95\gamma = 0.95, λ=1.0\lambda = 1.0, Φ=0.05\Phi = 0.05, and N=3N = 3.

  • The C-VAE samples a1=0.90a_1 = 0.90, a2=1.05a_2 = 1.05, a3=1.15a_3 = 1.15. All three sit inside the logged band.
  • Perturbations: +0.02+0.02, −0.01-0.01, +0.03+0.03, all within ±0.05\pm 0.05. Perturbed actions are a~1=0.92\tilde{a}_1 = 0.92, a~2=1.04\tilde{a}_2 = 1.04, a~3=1.18\tilde{a}_3 = 1.18.
  • Twin critic reads: (3.80,4.00)(3.80, 4.00) for 0.920.92 giving minimum 3.803.80; (4.50,4.30)(4.50, 4.30) for 1.041.04 giving minimum 4.304.30; (4.10,4.20)(4.10, 4.20) for 1.181.18 giving minimum 4.104.10.
  • The policy picks a~2=1.04\tilde{a}_2 = 1.04 with value 4.304.30.
  • The target is y=1.5+0.95×4.30=1.5+4.085=5.585y = 1.5 + 0.95 \times 4.30 = 1.5 + 4.085 = 5.585.

An unconstrained actor would instead query an unseen action such as a=2.50a = 2.50, where one critic hallucinates 8.008.00 and the target inflates to 1.5+0.95×8.0=9.101.5 + 0.95 \times 8.0 = 9.10. BCQ never samples 2.502.50, so the hallucination never enters the update. The diagram draws the three valid candidates, the rejected 2.502.50, and the winning target 5.5855.585.

Code

The snippet replays the same selection and target so you can verify the arithmetic.

def conservative_value(q1: float, q2: float, lam: float = 1.0) -> float:    """BCQ critic mix: lam * min + (1 - lam) * max."""    return lam * min(q1, q2) + (1.0 - lam) * max(q1, q2)

if __name__ == "__main__":    raw = [0.90, 1.05, 1.15]    deltas = [0.02, -0.01, 0.03]    perturbed = [round(a + d, 4) for a, d in zip(raw, deltas)]    reads = [(3.80, 4.00), (4.50, 4.30), (4.10, 4.20)]    scored = [conservative_value(q1, q2) for q1, q2 in reads]    best = max(range(3), key=lambda i: scored[i])    target = 1.5 + 0.95 * scored[best]    print(perturbed)    print(scored)    print(perturbed[best], round(scored[best], 2), round(target, 4))
# -> expected output:[0.92, 1.04, 1.18][3.8, 4.3, 4.1]1.04 4.3 5.585

Watch Out For

Setting the perturbation leash too long or to zero

The symptom tells you which side you are on. With Φ\Phi too large, training reports climbing QQ values while real evaluation collapses, because the actor has slipped back into unsupported actions. With Φ=0\Phi = 0, performance freezes at the logger's average score, because pure sampling can only clone and never improve.

The fix: scale Φ\Phi to the action range, starting near 0.050.05 of it, and watch a held out batch Bellman error alongside training error. If held out error rises while training error falls, shorten the leash or raise NN before touching anything else.

Trusting a single critic on logged but rare actions

The symptom: even inside the data support, rarely seen state action pairs get noisy QQ reads, and the max over candidates keeps picking the noisiest one. Values creep upward for reasons that have nothing to do with better behavior.

The fix: keep both critics and the minimum. If values still drift, raise λ\lambda toward 1.01.0 rather than adding network capacity, and check that the C-VAE actually reconstructs rare actions instead of collapsing onto the majority mode.

The Quick Version

  • BCQ is an offline method that restricts every critic query to actions sampled from a generative model of the logged behavior.
  • A conditional VAE supplies NN in support candidates, so out of distribution hallucinations are never sampled.
  • A perturbation network adds tweaks capped at ±Φ\pm \Phi, giving local improvement without leaving the data manifold.
  • Twin critics score candidates with the minimum, and the policy takes the argmax of that pessimistic read.
  • In the worked example, candidates 0.90, 1.05, and 1.15 become 0.92, 1.04, and 1.18, and the winner 1.04 gives target 5.585.