← All tutorials

Value-Based RL

Learn a score for every move, then play the best one.

On this page

1 Where value-based methods fit 2 What each family stores 3 Value-based methods 4 On-policy and off-policy 5 Deep Q-networks 6 Choosing a method 7 References

1 Where value-based methods fit

Value-based methods are one of four RL families. Every family runs the reinforcement learning loop; what differs is what the agent learns to pick its move. A value is an estimate of how much future reward to expect; a policy is the rule that picks the move. Methods that learn, or are handed, a model predicting each move’s result plan with it (model-based); the rest are model-free. Actor-critic methods learn both a policy, the actor, and a value, the critic.

Reinforcement learningmodel-freemodel-basedvalue-basedQ-learningSARSADQNmy runDouble DQNDueling DQNpolicy-basedREINFORCEactor-criticA2C, A3CPPOused for RLHFDDPGmy runTD3SACplans with a modelDynaWorld ModelsDreamerAlphaZerogiven rulesMuZerolearned model Reinforcement learningmodel-freevalue-basedQ-learningSARSADQNmy runDouble DQNDueling DQNpolicy-basedREINFORCEactor-criticA2C, A3CTD3PPOused for RLHFDDPGmy runSACmodel-basedplans with a modelDynaWorld ModelsDreamerAlphaZerogiven rulesMuZerolearned model
Figure 1. Each name links the page that teaches it; DQN and DDPG link my runs.

2 What each family stores

Given one state, a value-based agent outputs a score per move, a policy-based one move probabilities, and an actor-critic probabilities plus the critic’s score of the state.

statevalue netbiggest4 scoresstatepolicy net4 chances, sum 1statecritic1 number
Figure 2. Same state in, three different things out.
What the agent stores

Tap a square to start there.

Figure 3. Goal +1, pit −1, one wall. All three stored forms pick the same dashed route.

3 Value-based methods

A value-based agent keeps a score, a Q-value, for every move in every state: the future reward it expects from that move and good play after. It mostly plays the highest score, explores with a small chance ε (ε-greedy) and updates as in RL Basics. Q-learning (Watkins and Dayan 1992) keeps these scores in a table, one row per state.

In the cliff walk of Sutton and Barto’s RL textbook (2018, chapter 6), a 4 × 12 grid, an episode runs from start S to goal G, the two ends of the bottom row, past the cliff between them. Every step costs −1; the cliff costs −100 and a return to S. One step right along the cliff edge costs −1 and lands two moves from the goal (Figure 4).

cliffGss′r = −1−2best−4−4−113−113: cliff−100, then 13steps from Starget −1 + (−2) = −3guess −5 moves to −4
Figure 4. One step along the edge: its cost plus the best move from where it lands.

The same pull between a short risky route and a safe one faces a robot that learns while it explores next to a drop.

This is the Q-learning update, the card of RL Basics on a table. The move’s score moves halfway toward what the step just paid plus the best still possible from where it landed.
target = r + γ · max Q(s′, a′)
r is what the step paid, −1 in Figure 4. The discount γ, from 0 to 1 (the discount plot in RL Basics), is 1 here: every episode ends, so the sum stays finite. max Q(s′, a′) is the best score over the moves a′ in the square s′ the move led to, right’s −2. Together: the Bellman target of RL Basics for one real step, −3 here.
Q(s, a) ← Q(s, a)
+ α · (target − Q(s, a))
target − Q(s, a) is the TD error δ of RL Basics, +2 here. α, the learning rate, is 0.5 in the book’s cliff code, so each update closes half the gap and the guess −5 becomes −4; the arrow means replace with. Builds on the update card of RL Basics; SARSA, next, changes one term of the target, and DQN in Section 5 computes it with a frozen copy.

The code runs tabular Q-learning on gymnasium’s CliffWalking.

import random
import numpy as np
import gymnasium as gym

alpha, gamma, eps = 0.5, 1.0, 0.1   # values from the book's cliff code
env = gym.make("CliffWalking-v1")
Q = np.zeros((48, 4))   # 48 squares, 4 moves

def epsilon_greedy(Q, s):
    if random.random() < eps:
        return random.randrange(4)
    return int(Q[s].argmax())

for episode in range(500):
    s, info = env.reset()
    done = False
    while not done:
        a = epsilon_greedy(Q, s)
        s_next, r, terminated, truncated, info = env.step(a)
        best_next = 0.0 if terminated else Q[s_next].max()
        Q[s, a] += alpha * (r + gamma * best_next - Q[s, a])
        s, done = s_next, terminated or truncated
  1. 1Sets α, γ and ε and an all-zero Q-table for the 48-square cliff.
  2. 2Defines ε-greedy move choice.
  3. 3Starts an episode, picks a move and steps the environment.
  4. 4Target and update, eq card in Section 3, lines 1 and 2.
  5. 5Moves on to the next state.

4 On-policy and off-policy

An off-policy method learns about a policy other than the one making its moves. Q-learning is off-policy because its target scores the best move in s′, whatever the agent plays next, so it learns best-move values while exploring. SARSA, named for the five things one update uses (State, Action, Reward, next State, next Action), changes that one term (the RL textbook, chapter 6). SARSA scores the same step with the move the agent really plays next, slips included (Figure 5).

Q-learningSARSAs′−2s′0.9250.0250.0250.025−1 + (−2) = −3slip: −113−4−4−2−1 + average −4.875= −5.875
Figure 5. The same step scored by the best next move and by the move ε-greedy plays.
This is the SARSA update: it scores the move it will really play next, not the best one. Squares where one random slip costs −100 score worse, so its route keeps one row further out (Figure 7).
targetSARSA = r + γ · Q(s′, a′next)
a′next is the move ε-greedy really picks in s′ (RL Basics, section 6), slips included: right with chance 0.925 and each other move 0.025 at ε 0.1, as in Figure 5. Q(s′, a′next) replaces max Q(s′, a′); everything else is the Q-learning target. Figure 4’s numbers are shortest-route values; the values SARSA itself settles on near the cliff are lower, because its own slips count. Together: the target values the policy that is running, so SARSA is on-policy, while Q-learning values best play. Builds on the Q-learning update; Figure 7 shows the route difference, and the on-policy learners in Policy Gradients: REINFORCE, Actor-Critic and PPO learn from the moves really played, as SARSA does.

The SARSA loop picks a_next first and reuses Section 3’s env, Q and epsilon_greedy.

for episode in range(500):
    s, info = env.reset()
    a = epsilon_greedy(Q, s)
    done = False
    while not done:
        s_next, r, terminated, truncated, info = env.step(a)
        a_next = epsilon_greedy(Q, s_next)   # really played
        q_next = 0.0 if terminated else Q[s_next, a_next]
        Q[s, a] += alpha * (r + gamma * q_next - Q[s, a])
        s, a = s_next, a_next
        done = terminated or truncated
  1. 1Starts an episode and picks the first move.
  2. 2Steps, then picks a′next, the move the agent will really play.
  3. 3SARSA target, eq card in Section 4, line 1, then the update from Section 3, line 2.
  4. 4Carries the next state and move into the next step.
on-policycurrentpolicyfreshstepsupdateeach batch used, then thrown awayoff-policyany policyreplaybufferupdateold steps drawn again and again
Figure 6. Off-policy can reuse old steps; on-policy needs fresh ones after each update.
Learning rule

Figure 7. Q-learning walks the shaded cliff edge; SARSA keeps one row further out.

4.1 Q-learning and SARSA in practice

Runsonce after every real step
Carriesthe table Q, 48 squares × 4 moves here
Costone table read and one write per step
αshare of the gap each update closes; higher learns faster but noisier, 0 never learns, 1 keeps only the latest target; 0.5 in the book’s cliff code
γweights the next score in the target; lower favors sooner reward, 0 sees one step, 1 counts all future reward alike; 1 on the cliff, where every episode ends
εchance of a random move; higher explores more and falls more, 0 never tries anything new, 1 is a random walk; 0.1, over 500 episodes
Codecliff_walking.py, the book’s figures in Python
Gotchasno future after terminated, but keep it after truncated, a time limit (CliffWalking itself never truncates)

5 Deep Q-networks

DQN, deep Q-network (Mnih et al. 2015), replaces the table with a neural network that outputs one score per move. Two fixes keep it from oscillating or diverging:

Among noisy scores the highest is usually one that came out too high, so the max makes Q-learning and DQN overestimate (van Hasselt et al. 2016). Double DQN fixes the target. In the banana arena, a square with nothing in reach is worth 0 for every move, yet the guesses are noisy (Figure 8).

forwardbackleftrightQ0.3−0.20.1−0.4Q⁻−0.10.2−0.30.1Double DQNQ picks forward,Q⁻ scores ittarget −0.099DQNmax of Q⁻: backtarget 0.198too high
Figure 8. Toy guesses where every move is worth 0 (dashed): their max is not.

The step pays r = 0 and γ is 0.99; Q− is the target network, the frozen copy.

This is the DQN target and the Double DQN target. The max of noisy guesses picks one that came out too high; letting one network pick and the other value the pick breaks that link. One draw can miss either way; Figure 9 shows that on average the max runs high.
targetDQN = r + γ · max Q−⁠(s′, a′)
The Q-learning target with the frozen copy Q− in place of Q. The same scores both pick the best move and value it, so a score that came out too high is the one picked and used: back’s 0.2 in Figure 8 gives a target of 0.198 where the truth is 0.
a* = argmax Q(s′, a′)
The learning network Q picks the move. argmax returns which move scores highest, forward in Figure 8, not the score itself.
targetDouble = r + γ · Q−⁠(s′, a*)
The frozen copy values that move, −0.1 for forward, so the target is −0.099. A score inflated in one network is less often inflated in the other. Together: the same Bellman target, inflated less often; the Double DQN paper measured this upward bias on Atari games. Builds on the Q-learning target; the dueling split next changes how this network’s Q is built, and the two critics of TD3 carry the same caution.

Figure 9. The noisy max runs high; the frozen copy’s score of the pick does not.

Dueling DQN (Wang et al. 2016) changes the network instead, splitting it into two streams. With a banana ten steps ahead, every move scores about 0.9; the moves differ by less than 0.02 (Figure 10).

V 0.900.914A +0.014forwardV 0.900.895A −0.005turn leftV 0.900.895A −0.005turn rightV 0.900.895A −0.005back
Figure 10. Toy Q-values: a shared V plus a small advantage per move.

Here γ is 0.99. The dueling paper reports the gain on Atari games, where in many frames the moves score about the same.

This is the dueling split. A Q-value is how good the square is plus how much better this move is than the average move here; the network learns the two parts in separate streams.
Q(s, a) = V(s) + A(s, a)
− meana′ A(s, a′)
V(s) plays the role of the value of RL Basics; with the mean subtracted it is exactly the plain average of the four Q-values, 0.90 in Figure 10. A(s, a), the advantage, is the move’s edge over that average, +0.014 for forward. The mean advantage over all moves a′ is subtracted so the advantages average to zero, which picks one split (the dueling paper, eq. 9); otherwise any amount could shift between V and A. Together: the same Q-values built from a part every step trains (V) and a small part per move (A), which helps when many moves score about the same. Builds on the network Q above and the V of RL Basics; the actor-critic uses the same A = Q − V.

My banana agent uses both; Deep Q-Networks (DQN) draws its two streams.

One DQN update; for Double DQN, pick the next move with q_net and score it with target_net.

import random
import torch
import torch.nn.functional as F

gamma, batch_size, C = 0.99, 32, 10_000   # DQN paper

def dqn_update(q_net, target_net, optimizer, buffer, n_updates):
    batch = random.sample(buffer, batch_size)
    s, a, r, s_next, done = map(torch.tensor, zip(*batch))
    with torch.no_grad():
        best_next = target_net(s_next).max(1).values
        target = r + gamma * best_next * (1 - done.float())
    q_sa = q_net(s).gather(1, a.unsqueeze(1)).squeeze(1)
    loss = F.smooth_l1_loss(q_sa, target)   # Huber
    optimizer.zero_grad()
    loss.backward()
    optimizer.step()
    if n_updates % C == 0:
        target_net.load_state_dict(q_net.state_dict())
  1. 1Samples 32 stored steps from the replay buffer.
  2. 2Target from the target network Q−, first eq card in Section 5, line 1.
  3. 3Huber loss (squared for small errors, linear for large) between Q(s, a) and the target, then one gradient step.
  4. 4Copies the network into Q− every C updates.

5.1 DQN in practice

Runsone update every 4 actions, once the buffer holds 50,000 steps
Carriesa buffer of the last 1,000,000 steps, the target network, ε
Costone pass on 32 steps per update; the buffer dominates memory
Cupdates between target copies; larger keeps targets steadier but staler, 1 means no frozen copy; 10,000 (the DQN paper)
Bufferhow far back replay reaches; larger mixes more old policies, very small brings back look-alike batches; 1,000,000
Minibatchsteps per update; larger is less noisy but costs more compute; 32
Learning ratestep size of RMSProp, an optimizer like Adam; higher learns faster but can diverge, 0 never learns; 0.00025
CodeCleanRL dqn.py, whose CartPole (pole balancing) defaults are smaller (buffer 10,000, batch 128)
Gotchasthe paper clips the error to [−1, 1], which is what the Huber loss in the code does

6 Choosing a method

Two facts usually decide: whether actions are a short list (discrete) or real numbers, and what a real step costs.

PPO and A2C are taught in Policy Gradients: REINFORCE, Actor-Critic and PPO; TD3 and SAC in Continuous-Action Actor-Critic: TD3 and SAC; AlphaZero, MuZero, Dyna and Dreamer in Model-Based RL: Dyna, AlphaZero and MuZero.

WhenReach forBecause
Few states, fits in a tableQ-learning, or SARSA if exploring mistakes are costlySARSA keeps clear of its own slips
Short list of moves, many numbers or pixels inDQN with Double and DuelingOff-policy, so replay reuses every step
Continuous actions, real steps costlyTD3 or SACOff-policy with replay, and steadier than DDPG
Many cheap copies of a simulatorPPO or A2COn-policy updates from fresh data; PPO’s clip keeps each small
Tuning a language model from human preferencesPPOReinforcement learning from human feedback (RLHF) in Aligning Language Models with RL
Rules known and exactly simulatedAlphaZero-style searchLooks ahead with the real rules
Rules unknown, real steps costlyDreamer or DynaA learned model gives imagined practice
Rules unknown, look-ahead mattersMuZeroSearches with a learned model

A score per move needs a max over a list of moves. What does an agent learn when it outputs the move itself? Policy Gradients: REINFORCE, Actor-Critic and PPO takes up that question, and Continuous-Action Actor-Critic: TD3 and SAC carries it to real-number moves such as a joint torque.

6.1 What breaks and how to fix it

What breaksWhat you seeFix and where
Max over noisy scoresPredicted values climb above the returns earnedDouble DQN, TD3’s twin critics
Targets chase their own updatesScores oscillate or blow upTarget network
Whole-episode returnsVery noisy learning curveBaseline, critic
Policy too certain too earlyEntropy, the spread of the move probabilities, falls toward zero and reward stallsEntropy bonus, SAC
Too many steps on one batchReward collapses right after an updatePPO clipping
Agent exploits a learned model’s flawsHigh reward inside the learned model, low in the real worldCheck real-world returns; add randomness to the model, as World Models, a learned model of the world (Model-Based RL, section 3), did

7 References

  1. Sutton, R. S., and Barto, A. G. (2018). Reinforcement Learning: An Introduction (2nd ed.). MIT Press. Book site.
  2. Watkins, C. J. C. H., and Dayan, P. (1992). Q-learning. Machine Learning, 8, 279-292.
  3. Mnih, V., et al. (2015). Human-level control through deep reinforcement learning. Nature, 518, 529-533.
  4. van Hasselt, H., et al. (2016). Deep Reinforcement Learning with Double Q-learning. AAAI. arXiv:1509.06461.
  5. Wang, Z., et al. (2016). Dueling Network Architectures for Deep Reinforcement Learning. ICML. arXiv:1511.06581.