CrossQ¶
Intuition¶
CrossQ is a drop-in SAC upgrade for continuous control that removes the target networks entirely. Stability instead comes from Batch Renormalization in the critics plus a joint forward pass: \(Q(s,a)\) and \(Q(s',a')\) are computed together in one batch so BatchNorm statistics stay consistent between the value being trained and its bootstrap. This matches SAC's sample efficiency at an update-to-data ratio of 1, without target networks or critic ensembles.
Key Equations¶
Bootstrap target (the next-state half of the joint pass, detached):
Crucially, both halves are computed with the critic in train mode (batch statistics) -- the same normalisation regime the critic is trained under, which is why no target network is needed. Critic loss:
The actor and automatic-entropy losses are identical to SAC.
Pseudocode¶
initialize BatchRenorm critics Q_phi1, Q_phi2 (NO target nets), actor pi
for step:
sample batch (s,a,r,d,s') from replay
a' ~ pi(s')
# joint forward pass, critics in train() -> consistent batch stats:
Q_both = Q([s ; s'], [a ; a']); split -> Q(s,a), Q(s',a')
y = ( r + gamma(1-d)(min Q(s',a') - alpha*logpi(a'|s')) ).detach()
minimize sum_i (Q_i(s,a) - y)^2
every policy_delay steps: SAC actor update + alpha update
Usage¶
from rlox import Trainer
trainer = Trainer("crossq", env="Pendulum-v1")
trainer.train(total_timesteps=20_000)
Status¶
Experimental. Continuous action spaces only. Uses Adam betas=(0.5, 0.999)
-- β1 = 0.5 is load-bearing (the torch default 0.9 is unstable with
BatchNorm). Solves Pendulum-v1 reliably (greedy eval −134 ± 0.5 across 4
seeds); full MuJoCo sample-efficiency parity is a tracked follow-up.
Paper: Bhatt, Palenicek et al., CrossQ: Batch Normalization in Deep RL for Greater Sample Efficiency and Simplicity (ICLR 2024, arXiv:1902.05605).