← All tutorials

RL Basics

No answers, just a score. The agent figures out the rest.

On this page

1 The reinforcement learning loop 2 The banana collector environment 3 Why copying an expert is not enough 4 Why RL is hard 5 Scoring each move with Q-values 6 Explore early, exploit late 7 One RL step on a toy banana field 8 The trained banana agent 9 Reward hacking 10 Three algorithms, one loop 11 References

Reinforcement learning trains an agent’s strategy for picking moves to collect as much total reward as it can. There are no labels and no examples of correct behavior, just a world, a few possible moves and a reward; the agent tries things, the world returns rewards, and the strategy slowly shifts toward the moves that earn them.

Whenever the right move is unknown but the score is clear, RL is the tool.

1The reinforcementlearning loop2The banana collectorenvironment3Why copying anexpert is not enough4Why RL is hard5Scoring moveswith Q-values6Explore early,exploit late7One RL step on atoy banana field8The trained bananaagent9Rewardhacking10Three algorithms,one loop
Figure 1. Tap a box to jump there.

1 The reinforcement learning loop

Each turn the agent sees the state, what it senses right now. Its policy, the strategy being learned (often a neural network), picks an action. The world answers with a reward, the score for what just happened, and the next state, the world after the action lands. The goal is the most total reward over time.

Agent (the policy)Python side, picks a moveWorldUnity arena, steps and checks bananasaction1 of 4 movesnext state37 numbersreward+1, −1 or 0
Figure 2. One turn: a move goes out, the next state and a reward come back.

2 The banana collector environment

Walk the loop with the banana collector, a Unity ML-Agents environment from my Value-based-methods repo. ML-Agents is the toolkit that connects a Unity game world to training code. Each step the Python side sends one of four moves; Unity steps the physics and sends back 37 numbers, the next state, plus a reward: +1 for a yellow banana, −1 for a blue one, 0 otherwise.

The actions are a list of four, not a continuous range: forward, back, left, right.

yellowbluewallnothingeach ray says how far, and what it hitplus its own velocity, 37 numbers
Figure 3. The network gets 37 numbers from rays and velocity, never the picture.

This snippet plays one episode, one game from reset until the world reports done, with a random policy that learns nothing. Each pass of the while loop is one turn, and env.step returns the next state and the reward.

import random
from unityagents import UnityEnvironment

env = UnityEnvironment(file_name="Banana.app")
brain = env.brain_names[0]
info = env.reset(train_mode=True)[brain]
state = info.vector_observations[0]   # 37 numbers
score = 0
while True:
    action = random.randrange(4)      # random policy
    info = env.step(action)[brain]
    state = info.vector_observations[0]
    reward = info.rewards[0]          # +1, -1 or 0
    score += reward
    if info.local_done[0]:
        break
print("score", score)
  1. 1Starts an episode by resetting the banana world and reading the first state, the 37 numbers in Figure 3.
  2. 2One turn of the loop in Figure 2, a random move and its reward.
  3. 3Ends the episode when the world reports done, then prints the score.

3 Why copying an expert is not enough

The obvious alternative is behavior cloning: train a network to copy an expert’s moves. It is stage 1 of RLHF (reinforcement learning from human feedback) in Aligning Language Models with RL. The clone only saw perfect play, so once it drifts where the expert never went, its mistakes compound. RL learns from its own failures.

startgoalexperta small slipclonenever seen here, so lost
Figure 4. One slip puts the clone where the expert never went; each step drifts further.

4 Why RL is hard

Three things make RL hard. First, credit assignment. The agent turns left at step 40, drifts forward, and eats the banana at step 57. The +1 lands at 57, but the decision that mattered was the turn at 40. The discount gives earlier steps a share of that reward, smaller for each step of delay. Sparse rewards, long stretches that pay nothing, make every credit trail longer.

One banana at step 57 is worth less the further back you stand (Figure 5).

step 400.19…step 54step 55step 56step 57+10.810.91reward× 0.9× 0.9
Figure 5. Each step’s return is its reward plus 0.9 times the next step’s return.
This is the return: everything the agent will still collect, each later reward counted a bit less. Each step’s return is its own reward plus the discount (0.9 in Figure 5) times the next step’s return.
Gt = rt+1 + γ rt+2 + γ2 rt+3 + …
Gt is the return from step t. rt+1, the next reward, counts in full; γrt+2, the reward after it, is shrunk once by the discount γ, a number between 0 and 1; each further step shrinks once more, and … runs to the episode’s end. Together: one number for how good the future from step t turned out.
Gt = rt+1 + γ Gt+1
The return, one step at a time. rt+1 is the next reward; γGt+1 is everything after it, already summed one step later and shrunk once. Together: the same total read one step at a time, the 1, 0.9 and 0.81 of Figure 5; every later equation on this page uses it.
1 + γ + γ2 + … = 11 − γ
A reward of +1 at every step, forever, adds up to this sum (Sutton and Barto 2018). As a rule of thumb the agent looks about that many steps ahead, 10 at γ 0.9 and 100 at γ 0.99. Builds on the rewards of the loop (Section 1); the value card in Section 5 averages Gt, and line 2 is what its Bellman line rests on.

Figure 6. Each bar is the +1 at step 57 as seen from an earlier step.

Second, exploration. You cannot learn what you never try, and trying costs blue bananas, so the agent explores most early on (Section 6).

Third, sample inefficiency. Learning from scratch takes many tries. My banana run played 1,600 episodes for a task with four moves (Value-based-methods repo).

5 Scoring each move with Q-values

A Q-value, Q for quality, is the agent’s guess of the return from one move in one state. This agent plays forward 5 times in 8 and each other move 1 time in 8 (the ε-greedy rule of Section 6 at ε 0.5); the returns of single plays vary, so it keeps averages (Figure 7).

V = 0.9this squareforward · 5 in 8returns 1.4right · 1 in 8returns −0.6left · 1 in 8returns 0.4back · 1 in 8returns 0.4
Figure 7. Each move’s chance and its average return (toy numbers).
This is the value and the Q-value. The value of a square is what a play from it returns on average for this agent; the Q-value is the same average when the first move is fixed.
V(s) = E[ Gt | st = s ]
E[…] is the expected value: the average over everything chance decides (which move the agent plays, what the world does), each outcome weighted by its chance. The bar | reads “given that”, and st = s says the play starts in square s. Gt is the return of Section 4. Together: V(s) is the return this agent can expect from square s, the 0.9 at the centre of Figure 7.
Q(s, a) = E[ Gt | st = s, at = a ]
at = a adds “and its first move is a”. Line 2 differs from line 1 only by fixing the first move, so averaging the four Q-values, each weighted by how often the agent plays its move, gives V back: the four labels of Figure 7 average to its centre. These averages depend on how the agent plays afterwards; the Q it learns, next, assumes the best move at every later step. Builds on the return of Section 4, which it averages; the Bellman line in the next card writes the best-play Q with the return’s one-step line.

Training aims at a different Q: the return when every later move is the best one. Its guesses sit in a table, and the table’s guess for forward is 0.82; one real step says more (Figure 8).

forwardbackleftrightstateblue dead ahead−0.40………after theyellow bananabest Q 0.50yellowish ahead0.82………reward +1target 1.495TD error 0.675new guess 0.89the policy playseach row's best
Figure 8. Toy Q-table: the guess 0.82 and one step’s evidence 1.495.

The step earns reward +1 and uses γ 0.99, my DQN agent’s setting. The best Q in the next square is 0.50, so best play afterwards is worth 0.99 × 0.50 = 0.495, more than this agent’s own 0.4 in Figure 7, and the target is 1 + 0.495 = 1.495.

This is the Bellman equation and the update built on it. The best you can expect from a move is the reward it pays now plus the discounted best you can expect from where it lands. The agent cannot compute that average, so it uses the one step it just lived and moves its guess part of the way.
Q(s, a) = E[ r
+ γ · max Q(s′, a′) ]
The Bellman equation. Here Q(s, a) is the best-play Q, the return when every later move is the best one; from here on, Q means the best-play Q. E[ ] averages over what the world does after the move, and r is the reward. max Q(s′, a′) is the best Q-value in the next square s′: max picks the largest over the moves a′, and primes mark “next”. It stands in for Gt+1 of the return’s one-step line, because best play from there earns that much on average, and γ shrinks it for one step. Together: the one-step return with the rest of the future replaced by the best guess of it.
target = r + γ · max Q(s′, a′)
The Bellman target: the same right side without E[ ], built from the one step just seen. In Figure 8 it is 1.495.
δ = target − Q(s, a)
The TD error δ (temporal difference: two guesses one step apart) is how much the step surprised the agent; positive means better than the guess. It is the 0.675 on the marker in Figure 8.
Q(s, a) ← Q(s, a) + α · δ
The Q-learning update. The arrow means replace with; α, the learning rate, is a share between 0 and 1, so the guess moves a share α of the surprise. α is 0.1 here, so 0.82 + 0.1 × 0.675 = 0.89 in Figure 8. Repeated over many steps the guesses settle where δ averages zero, which is line 1 holding: a guess already at 1.495 gets δ = 0 and stays. Builds on the return’s one-step line and the value card above; Section 10’s first line plays the move this Q scores, Section 8’s code computes line 2 with a target network, and Value-Based RL starts from this card. Figure 11 walks one update.

A table needs one row per state, and 37 continuous numbers never repeat, so a network replaces the table.

one row per state,endless rows37 in,4 scores out
Figure 9. A deep Q-network, DQN, maps 37 numbers to one Q-value per move.

6 Explore early, exploit late

The agent’s Q-values say forward has been the best move so far. Always stepping forward means never learning that right might be better; picking at random every turn means never using what it knows.

The standard fix is ε-greedy: with chance ε (epsilon, eps in code) play a random move, otherwise the move with the highest Q-value. With ε 0.5 forward is played half the time plus a quarter of the random half, 5 times in 8, the chances in Figure 7.

import random
import numpy as np

N_MOVES = 4
EPS_FLOOR, EPS_DECAY = 0.01, 0.998   # as in my run
eps = 1.0

def epsilon_greedy(q_values, eps):
    if random.random() < eps:
        return random.randrange(N_MOVES)   # explore
    return int(np.argmax(q_values))       # exploit

q_values = np.array([0.82, 0.10, -0.40, 0.05])
action = epsilon_greedy(q_values, eps)
eps = max(EPS_FLOOR, eps * EPS_DECAY)  # after each episode
  1. 1Sets ε to start at 1 and decay to a floor of 0.01, the curve in Figure 10.
  2. 2A random move with probability ε, else the move with the top Q-value.
  3. 3Picks one move from toy Q-values, then shrinks ε once per episode.
10ε08001,600episodemostly randommostly best moveabout 0.04 after1,600 episodesfloor 0.01
Figure 10. ε shrinks ×0.998 per episode and never reaches the floor (DQN page).

7 One RL step on a toy banana field

Q-value of each move, Q(s, a)
One turn of the loop, in five steps

Agent A in the ringed square, one step from a +1 and a −1 banana.

Figure 11. Toy Q-values. Steps 1 to 4 act; step 5 updates the Q-value (Section 5).

8 The trained banana agent

My agent is a Dueling Double DQN (Deep Q-networks in Value-Based RL): dueling splits each score into how good the state is plus how much better each move is. It trains on batches drawn from replay memory, a store of past steps. For the Section 5 target, the learning network picks the next move and the target network, a slowly updated copy, scores it. Double stops the max from picking scores that came out too high (Value-Based RL, section 5).

import torch
import torch.nn.functional as F

GAMMA, TAU = 0.99, 1e-3   # values in my agent.py

def learn(q_local, q_target, optimizer, batch):
    s, a, r, s_next, done = batch   # 64 replayed steps
    with torch.no_grad():
        a_star = q_local(s_next).argmax(1, keepdim=True)   # learning net picks
        best_next = q_target(s_next).gather(1, a_star)     # target net scores
        target = r + GAMMA * best_next * (1 - done)
    q_sa = q_local(s).gather(1, a)   # Q(s, a) of moves played
    loss = F.mse_loss(q_sa, target)
    optimizer.zero_grad()
    loss.backward()
    optimizer.step()
    for p, p_t in zip(q_local.parameters(), q_target.parameters()):
        p_t.data.copy_(TAU * p.data + (1 - TAU) * p_t.data)
  1. 1Double DQN target for 64 replayed steps, eq card in Section 5, line 2, with the best next move picked by the learning network.
  2. 2Compares Q(s, a) with the target, the TD error, line 3.
  3. 3Takes one gradient step on that loss.
  4. 4Moves the target network a fraction τ toward the learning network.
Runsevery 4 moves, once the memory holds more than 64 steps; updating more often learns more per move played at more compute, 1 updates after every move
Carriesreplay memory, the target network, ε
Costone forward and backward pass on 64 states per update
γweights the next best score; lower favors sooner bananas, 0 sees one step, near 1 looks far ahead (Figure 6); 0.99
εchance of a random move; 1 never uses what it learned, 0 never explores; a decay nearer 1 explores longer, lower stops sooner; 1.0, ×0.998 per episode, floor 0.01
Batchsteps replayed per update; larger gives a less noisy gradient at more compute, 1 learns from single noisy steps; 64
Memorypast steps; random draws break the link between neighboring steps, larger reaches further back, too small replays only recent moves; 100,000
Learning ratethe network’s α: higher learns faster but can diverge, 0 never learns; Adam 0.0005
τshare the target network moves toward the learning network per update; larger tracks faster but steadies less, 1 copies outright; 0.001
Codeagent.py, or CleanRL dqn.py
Gotchaszero the future at an episode's end; decay ε per episode, not per move

The training code (env.py) stops early once the 100-episode average score reaches 17.0. The run never hit that bar, so all 1,600 episodes ran (the DQN page).

Figure 12. The trained network collecting yellow bananas in the Unity arena.

9 Reward hacking

The agent does not learn what you meant. It learns what you rewarded. Reward hacking is an agent raising its reward in a way the designer did not intend. An OpenAI agent playing the boat-racing game CoastRunners learned to circle a lagoon knocking over three respawning targets, kept catching fire, and still outscored human players by about 20 percent instead of finishing the race (Clark and Amodei 2016).

So before training, ask "what is the easiest way to score high without doing the task?"

Reward shaping, extra pay for getting closer, carries the same risk (an agent can approach and back away forever), and so do learned rewards, where it is called reward over-optimization in RLHF.

Watch what the agent actually does, then fix the reward, not the agent.

An agent that sits in a corner for 600 steps eats nothing: 0 by the banana count, 60 at 0.10 per step alive (Figure 13).

Two rewards for one world: the same arena scored by bananas or by steps survived.
scorereal = yellows − blues
The real banana reward pays +1 per yellow banana eaten and −1 per blue.
scorealive = 0.10 × steps alive
Pays 0.10 for every step alive, the same whether the agent eats or not, so standing still in a corner scores as well as any banana hunt. Builds on the return of Section 4, which adds up whichever reward is chosen, and the update of Section 5, which chases it; the reward model in Aligning Language Models with RL learns the reward from people instead.
Steps-alive pay for one 600-step run in the corner (one dot = up to 20 bananas)

Banana score
illustrative toy
0score (0 eaten)
Steps-alive score
illustrative toy
0.0score (0 eaten)

Both agents wait at their start rings.

Figure 13. Same world, two rewards, opposite agents: the reward defines the task.

10 Three algorithms, one loop

Three agents built on this loop live in my Value-based-methods, RF-DDPG and TennisGym repos. The banana agent picks from four moves; a robot arm and a pair of tennis rackets must output real numbers (Figure 14).

a0.82forward0.11back0.20left0.35rightargmaxplaysforwardb33 numbersμ4 torques, toy0.60, −0.20,0.35, 0.10Qgrades the paircA: own 24B: own 24μ(scoot, jump)A (0.8, 0.1)B (−0.3, 0.9)
Figure 14. Three ways to pick the move: a scored list, an actor, one shared actor.
Three ways to pick the move. With a short list of moves, score each and play the best; with real-number moves, a network outputs the move itself; with two players, each runs the same network on what it alone sees.
a = argmaxa Q(s, a)
a is the move played and Q(s, a) its score from the Section 5 update. argmax returns the move whose score is largest, not the score itself: forward, not 0.82, in panel a of Figure 14. Together: play the best-scored move, which needs the whole list scored.
a = μ(s)
μ is the actor, a network, and s is the arm’s 33 numbers. Its output a is the four torques directly, so there is no list to search; Q(s, a) only grades the pair while training, as the critic (panel b). Together: the network outputs the move instead of scoring a list (Deep Deterministic Policy Gradient, section 2).
ai = μ(oi)
i names the racket, A or B, and oi is that racket’s own 24 numbers (3 snapshots of 8). The same μ drives both, so one actor learns from both sides (self-play), and ai is that racket’s scoot and jump (panel c). Together: one actor, two players, each seeing only its own side (Multi-Agent Reinforcement Learning, section 2, which also shows how MADDPG differs). Builds on Section 5, since line 1 is its Q in use; the DDPG page’s critic and actor updates use line 2 and the multi-agent page uses line 3.

The DDPG page shows the actor and critic code.

These three agents are one value-based and two actor-critic methods. What other families are there, and how do value-based methods learn? Value-Based RL maps them all, teaches the value-based ones and ends with a guide to choosing a method.

11 References

  1. Sutton, R. S., and Barto, A. G. (2018). Reinforcement Learning: An Introduction (2nd ed.). MIT Press. Book site.
  2. Unity ML-Agents Toolkit, GitHub.
  3. Value-based-methods, my banana DQN repo (env.py runs up to 1,600 episodes and stops early at a 100-episode average of 17.0).
  4. TennisGym, my tennis repo (one shared actor-critic for both rackets).
  5. RF-DDPG, my DDPG repo (solves the 20-arm Reacher task).
  6. Clark, J., and Amodei, D. (2016). Faulty reward functions in the wild. OpenAI. https://openai.com/index/faulty-reward-functions/