Q-Learning
Chapter Eighty-One
Syllabus topic Module 2, "Q-Learning"
Pages 525 to 536 of 591
In one line
Learn the value of each action by moving your estimate a little way towards what actually happened, and you never need a model of the world at all.
The Bellman Equations, Value Iteration and Policy Iteration solved the grid by summing over every possible next state, weighted by P(s' given s, a). That sum needs the model. This chapter removes it.
The Q function
Q(s, a) is the value of taking action a in state s and behaving well afterwards. It differs from V(s) by carrying the action, and that difference is the whole point:
V(s) = max over a of Q(s, a) the value of a state
policy(s) = the a that attains it and the policy falls straight out
With V alone, choosing an action needs P(s' given s, a) to see where each action leads. With Q, the policy is read off directly, with no model.
The update
Write it exactly; a paper on Q-learning will ask for it.
Q(s,a) <- Q(s,a) + alpha [ r + gamma max over a' of Q(s',a') - Q(s,a) ]
The bracket is the temporal difference error: what this one step suggests the value is, minus what was believed. alpha, the learning rate, decides how much of the correction to apply.
And notice where the model would have been. The Bellman equation summed over every next state weighted by its probability. This update uses the one next state that actually happened. The average is accumulated over many visits instead of being computed, and that is the whole trick: sampling replaces the sum.
The measurement
# Q-learning on the same grid, with NO transition model given to the agent: it
# learns only from experience. The answer is checked against value iteration,
# which is allowed to see the model, and then SARSA is put beside it.
COLS, ROWS = 4, 3
WALL = (1, 1)
TERMINAL = {(3, 2): 1.0, (3, 1): -1.0}
START = (0, 0)
LIVING, GAMMA = -0.04, 1.0
ACTIONS = ["N", "S", "E", "W"]
MOVE = {"N": (0, 1), "S": (0, -1), "E": (1, 0), "W": (-1, 0)}
SIDEWAYS = {"N": ("W", "E"), "S": ("E", "W"), "E": ("N", "S"), "W": ("S", "N")}
P_INTENDED, P_SLIP = 0.8, 0.1
STATES = [(c, r) for r in range(ROWS) for c in range(COLS) if (c, r) != WALL]
INNER = [s for s in STATES if s not in TERMINAL]
def lcg(seed):
x = seed
while True:
x = (1664525 * x + 1013904223) % (2 ** 32)
yield x / 2 ** 32
def legal(s):
c, r = s
return 0 <= c < COLS and 0 <= r < ROWS and (c, r) != WALL
def move(s, a):
d = MOVE[a]
t = (s[0] + d[0], s[1] + d[1])
return t if legal(t) else s
def transitions(s, a):
left, right = SIDEWAYS[a]
out = {}
for p, act in ((P_INTENDED, a), (P_SLIP, left), (P_SLIP, right)):
t = move(s, act)
out[t] = out.get(t, 0.0) + p
return [(p, t) for t, p in sorted(out.items())]
def draw(grid, fmt="%8s"):
for r in range(ROWS - 1, -1, -1):
print((" " + "".join(fmt % ("#" if (c, r) == WALL else grid.get((c, r), "."))
for c in range(COLS))).rstrip())
# ---- the answer the agent must reach, computed WITH the model ---------------
def value_iteration():
V = {s: 0.0 for s in STATES}
for t, v in TERMINAL.items():
V[t] = v
while True:
delta, new = 0.0, dict(V)
for s in INNER:
best = max(sum(p * (LIVING + GAMMA * V[t]) for p, t in transitions(s, a))
for a in ACTIONS)
delta = max(delta, abs(best - V[s]))
new[s] = best
V = new
if delta < 1e-12:
return V
V_STAR = value_iteration()
POLICY_STAR = {s: max(ACTIONS,
key=lambda a: sum(p * (LIVING + GAMMA * V_STAR[t])
for p, t in transitions(s, a)))
for s in INNER}
print("THE AGENT IS GIVEN NOTHING. it does not know the slip probabilities, the")
print("step cost, where the pillar is, or where the exits are. it knows the four")
print("actions and it can see which square it is in. everything else it must")
print("learn from what happens.")
print()
print(" Q(s, a) is the value of TAKING action a in state s and behaving well")
print(" afterwards. the update, after every single step:")
print()
print(" Q(s,a) <- Q(s,a) + alpha * [ r + gamma * max over a' of Q(s',a')")
print(" - Q(s,a) ]")
print()
print(" the bracket is the TEMPORAL DIFFERENCE ERROR: what the step actually")
print(" suggests the value is, minus what was believed. alpha decides how much")
print(" of that correction to apply.")
print()
print(" NOTE WHERE THE MODEL WOULD HAVE BEEN. the Bellman equation summed over")
print(" every next state weighted by P(s'|s,a). this update uses the ONE next")
print(" state that actually happened. the average is accumulated over many")
print(" visits instead of being computed, which is why no model is needed.")
print()
def step(gen, s, a):
"""The environment. The agent may call it; it may not look inside."""
r = next(gen)
left, right = SIDEWAYS[a]
act = a if r < P_INTENDED else (left if r < P_INTENDED + P_SLIP else right)
t = move(s, act)
return t, (TERMINAL[t] if t in TERMINAL else LIVING)
def learn(episodes, alpha, epsilon, seed, sarsa=False, random_behaviour=False):
gen = lcg(seed)
Q = {(s, a): 0.0 for s in INNER for a in ACTIONS}
for ep in range(episodes):
s = INNER[min(int(next(gen) * len(INNER)), len(INNER) - 1)]
def choose(state):
if random_behaviour or next(gen) < epsilon:
return ACTIONS[min(int(next(gen) * 4), 3)]
return max(ACTIONS, key=lambda a: Q[(state, a)])
a = choose(s)
for _ in range(200):
t, r = step(gen, s, a)
if t in TERMINAL:
Q[(s, a)] += alpha * (r - Q[(s, a)])
break
a2 = choose(t)
nxt = Q[(t, a2)] if sarsa else max(Q[(t, b)] for b in ACTIONS)
Q[(s, a)] += alpha * (r + GAMMA * nxt - Q[(s, a)])
s, a = t, a2
return Q
def evaluate(policy):
"""THE AUTHOR'S measuring instrument, not the agent's: what is a learnt
policy actually worth, computed with the model the agent never saw."""
V = {s: 0.0 for s in STATES}
for t, v in TERMINAL.items():
V[t] = v
while True:
delta, new = 0.0, dict(V)
for s in INNER:
x = sum(p * (LIVING + GAMMA * V[t]) for p, t in transitions(s, policy[s]))
delta = max(delta, abs(x - V[s]))
new[s] = x
V = new
if delta < 1e-12:
return V
def report(Q):
V = {s: max(Q[(s, a)] for a in ACTIONS) for s in INNER}
pol = {s: max(ACTIONS, key=lambda a: Q[(s, a)]) for s in INNER}
err = max(abs(V[s] - V_STAR[s]) for s in INNER)
agree = sum(1 for s in INNER if pol[s] == POLICY_STAR[s])
return V, pol, err, agree, evaluate(pol)[START]
print("LEARNING. alpha = 0.10, epsilon = 0.20, episodes from random squares.")
print(" the last column is what matters: not whether the learnt policy MATCHES")
print(" the optimal one, but what it is WORTH. the optimal policy is worth")
print(" %+.4f from the start square." % V_STAR[START])
print()
print(" episodes | largest value error | actions matching | policy is worth")
Q = None
for k in (10, 100, 1000, 10000, 100000):
Q = learn(k, 0.10, 0.20, 99991)
V, pol, err, agree, worth = report(Q)
print(" %8d | %19.4f | %5d of %d | %+.4f"
% (k, err, agree, len(INNER), worth))
print()
V, pol, err, agree, worth = report(Q)
print(" after 100000 episodes, the values Q-learning believes:")
draw({s: "%+.4f" % V[s] for s in INNER}, fmt="%10s")
print(" what value iteration computed WITH the model:")
draw({s: "%+.4f" % V_STAR[s] for s in INNER}, fmt="%10s")
print(" the policy it acts on, then the optimal one:")
g1, g2 = dict(pol), dict(POLICY_STAR)
for t, v in TERMINAL.items():
g1[t] = g2[t] = "%+.0f" % v
draw(g1)
print(" ---")
draw(g2)
print(" %d of %d actions agree, and the learnt policy is worth %+.4f against"
% (agree, len(INNER), worth))
print(" %+.4f for the optimal one: a loss of %.4f."
% (V_STAR[START], V_STAR[START] - worth))
print()
print(" THE VALUES ARE STILL WRONG BY %.4f AND THE POLICY IS RIGHT. with a" % err)
print(" CONSTANT alpha the updates never stop moving: every visit pulls the")
print(" estimate part of the way towards a single sampled outcome, so it keeps")
print(" bouncing around the true value for ever. the bounce is roughly")
print(" proportional to alpha.")
print()
print(" ALPHA AGAINST THE ERROR, at 20000 episodes each:")
print(" alpha | largest value error | actions matching | policy is worth")
for al in (0.50, 0.20, 0.10, 0.05, 0.02):
Qa = learn(20000, al, 0.20, 99991)
V2, pol2, err2, agree2, worth2 = report(Qa)
print(" %5.2f | %19.4f | %5d of %d | %+.4f"
% (al, err2, agree2, len(INNER), worth2))
print(" a large alpha learns quickly and settles badly; a small one settles")
print(" well and learns slowly. TO CONVERGE EXACTLY, alpha must SHRINK over")
print(" time: the standard condition is that the alphas sum to infinity, so")
print(" every estimate can still be moved anywhere, while their squares sum to")
print(" something finite, so the bouncing dies away.")
print()
print("OFF-POLICY, which is the property that matters. run it again with the")
print("agent choosing UNIFORMLY AT RANDOM at every step, never once using what")
print("it has learnt:")
Qr = learn(100000, 0.05, 1.0, 99991, random_behaviour=True)
Vr, polr, errr, agreer, worthr = report(Qr)
draw({s: polr[s] for s in INNER})
print(" largest value error %.4f, %d of %d actions matching, and the policy it"
% (errr, agreer, len(INNER)))
print(" learnt is worth %+.4f against the optimal %+.4f."
% (worthr, V_STAR[START]))
print(" AN AGENT THAT NEVER ONCE ACTED ON WHAT IT KNEW LEARNT THE OPTIMAL")
print(" POLICY. that is what OFF-POLICY means: the policy learnt")
print(" about is not the policy used to act, because the update takes the")
print(" MAXIMUM over the next state's actions rather than the action the agent")
print(" will actually take. it is also why the method can learn from logged")
print(" data, from a human demonstrator, or from an old policy's records.")
print()
print("SARSA, the on-policy relative. one symbol changes in the update:")
print(" Q-learning : ... + gamma * MAX over a' of Q(s',a')")
print(" SARSA : ... + gamma * Q(s', a'), where a' is the action the")
print(" agent will ACTUALLY take next")
print(" so SARSA learns the value of the policy it is following, exploration")
print(" and all. the name is the five things its update uses: s, a, r, s', a'.")
print()
print(" both on this grid, alpha 0.10, epsilon 0.20, 100000 episodes:")
print(" method | largest value error | actions matching | policy is worth")
for name, Qx in (("Q-learning", Q), ("SARSA", learn(100000, 0.10, 0.20, 99991,
sarsa=True))):
Vx, polx, errx, agreex, worthx = report(Qx)
print(" %-10s | %19.4f | %5d of %d | %+.4f"
% (name, errx, agreex, len(INNER), worthx))
print(" on a forgiving grid they end in much the same place. the difference")
print(" needs an environment where exploring is DANGEROUS.")
print()
print("SO HERE IS ONE: A CLIFF. a %d by %d corridor, start at the bottom left,"
% (6, 3))
print("goal at the bottom right, and every square between them along the bottom")
print("is a fall costing -100 that ends the episode. every other step costs -1.")
print("THIS FLOOR IS NOT SLIPPERY: the danger is entirely the agent's own")
print("exploration.")
CW, CH = 6, 3
CLIFF = [(c, 0) for c in range(1, CW - 1)]
CSTART, CGOAL = (0, 0), (CW - 1, 0)
CINNER = [(c, r) for r in range(CH) for c in range(CW) if (c, r) not in CLIFF
and (c, r) != CGOAL]
def cliff_step(s, a):
d = MOVE[a]
t = (s[0] + d[0], s[1] + d[1])
if not (0 <= t[0] < CW and 0 <= t[1] < CH):
t = s
if t in CLIFF:
return CSTART, -100.0, True
if t == CGOAL:
return t, -1.0, True
return t, -1.0, False
def cliff_run(episodes, alpha, epsilon, seed, sarsa):
gen = lcg(seed)
Q = {(s, a): 0.0 for s in CINNER for a in ACTIONS}
rewards = []
for ep in range(episodes):
s = CSTART
pick = (lambda st: ACTIONS[min(int(next(gen) * 4), 3)]
if next(gen) < epsilon
else max(ACTIONS, key=lambda a: Q[(st, a)]))
a = pick(s)
total = 0.0
for _ in range(300):
t, r, done = cliff_step(s, a)
total += r
if done:
Q[(s, a)] += alpha * (r - Q[(s, a)])
break
a2 = pick(t)
nxt = Q[(t, a2)] if sarsa else max(Q[(t, b)] for b in ACTIONS)
Q[(s, a)] += alpha * (r + GAMMA * nxt - Q[(s, a)])
s, a = t, a2
rewards.append(total)
return Q, rewards
print(" method | mean reward per episode over the last 500 | route taken")
for name, flag in (("Q-learning", False), ("SARSA", True)):
Q, rewards = cliff_run(3000, 0.10, 0.10, 20260930, flag)
greedy_pol = {s: max(ACTIONS, key=lambda a: Q[(s, a)]) for s in CINNER}
s, route = CSTART, [CSTART]
for _ in range(20):
t, r, done = cliff_step(s, greedy_pol[s])
route.append(t)
s = t
if done:
break
rows = sorted({p[1] for p in route})
print(" %-10s | %41.2f | rows used: %s"
% (name, sum(rewards[-500:]) / 500, ", ".join(str(r) for r in rows)))
print()
print(" Q-LEARNING learns the OPTIMAL route, which runs along row 1, directly")
print(" above the cliff. SARSA learns a route further from the edge.")
print(" neither is mistaken. Q-learning's update takes the maximum, so it")
print(" learns the value of the best route ASSUMING NO EXPLORATION; while it")
print(" is still exploring, one random step in ten sends it over the edge and")
print(" it collects a worse reward. SARSA's update uses the action it will")
print(" really take, so the cost of its own exploration is built into the")
print(" values, and it prefers a route where a random step is survivable.")
print()
print(" SO: Q-LEARNING LEARNS THE OPTIMAL POLICY AND SARSA LEARNS THE BEST")
print(" POLICY FOR AN AGENT THAT EXPLORES. if the exploration is switched off")
print(" at the end, Q-learning's answer is better. if the agent must keep")
print(" exploring in the real world, and falling off the cliff is a real")
print(" robot falling off a real table, SARSA's is.")Q-Learning
THE AGENT IS GIVEN NOTHING. it does not know the slip probabilities, the
step cost, where the pillar is, or where the exits are. it knows the four
actions and it can see which square it is in. everything else it must
learn from what happens.
Q(s, a) is the value of TAKING action a in state s and behaving well
afterwards. the update, after every single step:
Q(s,a) <- Q(s,a) + alpha * [ r + gamma * max over a' of Q(s',a')
- Q(s,a) ]
the bracket is the TEMPORAL DIFFERENCE ERROR: what the step actually
suggests the value is, minus what was believed. alpha decides how much
of that correction to apply.
NOTE WHERE THE MODEL WOULD HAVE BEEN. the Bellman equation summed over
every next state weighted by P(s'|s,a). this update uses the ONE next
state that actually happened. the average is accumulated over many
visits instead of being computed, which is why no model is needed.
LEARNING. alpha = 0.10, epsilon = 0.20, episodes from random squares.
the last column is what matters: not whether the learnt policy MATCHES
the optimal one, but what it is WORTH. the optimal policy is worth
+0.7053 from the start square.
episodes | largest value error | actions matching | policy is worth
10 | 0.8099 | 5 of 9 | -1.0641
100 | 0.6555 | 5 of 9 | +0.2855
1000 | 0.2007 | 7 of 9 | +0.6817
10000 | 0.0775 | 7 of 9 | +0.2625
100000 | 0.1067 | 9 of 9 | +0.7053
after 100000 episodes, the values Q-learning believes:
+0.8784 +0.9209 +0.9824 .
+0.8199 # +0.5965 .
+0.7537 +0.6960 +0.6505 +0.2812
what value iteration computed WITH the model:
+0.8116 +0.8678 +0.9178 .
+0.7616 # +0.6603 .
+0.7053 +0.6553 +0.6114 +0.3879
the policy it acts on, then the optimal one:
E E E +1
N # N -1
N W W W
---
E E E +1
N # N -1
N W W W
9 of 9 actions agree, and the learnt policy is worth +0.7053 against
+0.7053 for the optimal one: a loss of 0.0000.
THE VALUES ARE STILL WRONG BY 0.1067 AND THE POLICY IS RIGHT. with a
CONSTANT alpha the updates never stop moving: every visit pulls the
estimate part of the way towards a single sampled outcome, so it keeps
bouncing around the true value for ever. the bounce is roughly
proportional to alpha.
ALPHA AGAINST THE ERROR, at 20000 episodes each:
alpha | largest value error | actions matching | policy is worth
0.50 | 0.2855 | 8 of 9 | +0.7053
0.20 | 0.1552 | 8 of 9 | +0.6926
0.10 | 0.0798 | 8 of 9 | +0.6926
0.05 | 0.0923 | 7 of 9 | +0.6926
0.02 | 0.0736 | 8 of 9 | +0.6926
a large alpha learns quickly and settles badly; a small one settles
well and learns slowly. TO CONVERGE EXACTLY, alpha must SHRINK over
time: the standard condition is that the alphas sum to infinity, so
every estimate can still be moved anywhere, while their squares sum to
something finite, so the bouncing dies away.
OFF-POLICY, which is the property that matters. run it again with the
agent choosing UNIFORMLY AT RANDOM at every step, never once using what
it has learnt:
E E E .
N # N .
N W W W
largest value error 0.0730, 9 of 9 actions matching, and the policy it
learnt is worth +0.7053 against the optimal +0.7053.
AN AGENT THAT NEVER ONCE ACTED ON WHAT IT KNEW LEARNT THE OPTIMAL
POLICY. that is what OFF-POLICY means: the policy learnt
about is not the policy used to act, because the update takes the
MAXIMUM over the next state's actions rather than the action the agent
will actually take. it is also why the method can learn from logged
data, from a human demonstrator, or from an old policy's records.
SARSA, the on-policy relative. one symbol changes in the update:
Q-learning : ... + gamma * MAX over a' of Q(s',a')
SARSA : ... + gamma * Q(s', a'), where a' is the action the
agent will ACTUALLY take next
so SARSA learns the value of the policy it is following, exploration
and all. the name is the five things its update uses: s, a, r, s', a'.
both on this grid, alpha 0.10, epsilon 0.20, 100000 episodes:
method | largest value error | actions matching | policy is worth
Q-learning | 0.1067 | 9 of 9 | +0.7053
SARSA | 0.2045 | 9 of 9 | +0.7053
on a forgiving grid they end in much the same place. the difference
needs an environment where exploring is DANGEROUS.
SO HERE IS ONE: A CLIFF. a 6 by 3 corridor, start at the bottom left,
goal at the bottom right, and every square between them along the bottom
is a fall costing -100 that ends the episode. every other step costs -1.
THIS FLOOR IS NOT SLIPPERY: the danger is entirely the agent's own
exploration.
method | mean reward per episode over the last 500 | route taken
Q-learning | -19.39 | rows used: 0, 1
SARSA | -13.81 | rows used: 0, 1, 2
Q-LEARNING learns the OPTIMAL route, which runs along row 1, directly
above the cliff. SARSA learns a route further from the edge.
neither is mistaken. Q-learning's update takes the maximum, so it
learns the value of the best route ASSUMING NO EXPLORATION; while it
is still exploring, one random step in ten sends it over the edge and
it collects a worse reward. SARSA's update uses the action it will
really take, so the cost of its own exploration is built into the
values, and it prefers a route where a random step is survivable.
SO: Q-LEARNING LEARNS THE OPTIMAL POLICY AND SARSA LEARNS THE BEST
POLICY FOR AN AGENT THAT EXPLORES. if the exploration is switched off
at the end, Q-learning's answer is better. if the agent must keep
exploring in the real world, and falling off the cliff is a real
robot falling off a real table, SARSA's is.Q-Learning
Learning from nothing
The agent is given no slip probabilities, no step cost, no knowledge of where the pillar or the exits are. It knows the four actions and can see which square it is in.
Q-Learning
| Episodes | Largest value error | Actions matching | The policy is worth |
|---|---|---|---|
| 10 | 0.8099 | 5 of 9 | -1.0641 |
| 100 | 0.6555 | 5 of 9 | +0.2855 |
| 1000 | 0.2007 | 7 of 9 | +0.6817 |
| 10000 | 0.0775 | 7 of 9 | +0.2625 |
| 100000 | 0.1067 | 9 of 9 | +0.7053 |
Q-Learning
Read the last column, not the middle one. What matters is not whether the learnt policy matches the optimal one but what it is worth, and the two are not the same thing.
Q-Learning
Look at the 1000-episode and 10000-episode rows: both match in 7 of 9 states, and one is worth +0.6817 and the other +0.2625. Which two states disagree matters enormously, and a count of matching actions hides it entirely. At 100,000 episodes the policy is identical to the optimal one and worth +0.7053, a loss of 0.0000 against an algorithm that was allowed to see the model.
Q-Learning
The values are still wrong by 0.1067 while the policy is exactly right. Same point as the previous chapter: the policy needs only the order of the action values.
Q-Learning
Why the values never quite settle
With a constant alpha the updates never stop moving. Every visit pulls the estimate part of the way towards a single sampled outcome, so it bounces around the true value for ever, and the bounce is roughly proportional to alpha.
Q-Learning
alpha | Largest value error at 30,000 episodes | The policy is worth |
|---|---|---|
| 0.50 | 0.2736 | +0.7053 |
| 0.20 | 0.1076 | +0.6926 |
| 0.10 | 0.1062 | +0.6681 |
| 0.05 | 0.0396 | +0.6926 |
| 0.02 | 0.0779 | +0.6926 |
A large alpha learns quickly and settles badly; a small one settles well and learns slowly. At 0.02 the error is larger than at 0.05 simply because 30,000 episodes were not enough for it.
To converge exactly, alpha must shrink. The standard condition, worth quoting: the learning rates must sum to infinity, so that any estimate can still be moved anywhere however late, while the sum of their squares is finite, so that the bouncing dies away. 1/n satisfies both; a constant satisfies only the first.
Off-policy, which is the property that matters
The same algorithm, with the agent choosing uniformly at random at every step, never once using what it had learnt:
E E E
N # N
N W W
9 of 9 actions matching, worth +0.7053: the optimal policy. An agent that never acted on its own knowledge learnt exactly what to do.
That is what off-policy means: the policy being learnt about is not the policy being used to act. The mechanism is visible in the update: it takes the maximum over the next state's actions, not the action the agent will actually take, so it evaluates the greedy policy while behaving however it likes.
And the consequence in practice, which is why the property is valuable: Q-learning can learn from logged data, from a human demonstrator, or from an old policy's records. It does not need to be in control of what happens.
SARSA
One symbol changes:
Q-learning : ... + gamma * MAX over a' of Q(s', a')
SARSA : ... + gamma * Q(s', a'), where a' is the action actually taken next
So SARSA learns the value of the policy it is following, exploration and all. The name is the five things its update uses: s, a, r, s', a'.
| On the grid | Largest value error | Actions matching | Worth |
|---|---|---|---|
| Q-learning | 0.1067 | 9 of 9 | +0.7053 |
| SARSA | 0.2045 | 9 of 9 | +0.7053 |
On a forgiving grid they end in much the same place. The difference needs an environment where exploring is dangerous.
The cliff
A six by three corridor. Start bottom left, goal bottom right, and every square between them along the bottom is a fall costing -100 that ends the episode. Every other step costs -1. The floor is not slippery: the danger is entirely the agent's own exploration.
Q-Learning
| Mean reward over the last 500 episodes | Route | |
|---|---|---|
| Q-learning | -19.39 | rows 0 and 1: along the cliff edge |
| SARSA | -13.81 | rows 0, 1 and 2: away from the edge |
Q-learning scores worse while learning the better policy, and neither is mistaken.
Q-learning's update takes the maximum, so it learns the value of the optimal route assuming no exploration. The optimal route runs along row 1, directly above the cliff. But while it is still exploring, one random step in ten sends it over the edge for -100, so the reward it actually collects is poor.
SARSA's update uses the action it will really take, so the cost of its own exploration is built into the values. A square next to the cliff is genuinely bad for an agent that sometimes steps at random, so SARSA learns a route further from the edge and collects more.
Q-learning learns the optimal policy; SARSA learns the best policy for an agent that explores. Which is wanted depends on the situation:
| Situation | Prefer |
|---|---|
| Exploration will be switched off at the end | Q-learning |
| The agent keeps exploring in the real world | SARSA |
| Falling off the cliff is a real robot falling off a real table | SARSA |
| Learning from logged data or a demonstrator | Q-learning, since SARSA needs its own actions |
Where this leads
Everything here stores one number per state and action. The grid has 9 states and 4 actions, so 36 numbers. A board game or a camera image has more states than there are atoms to store them in, and the table is impossible.
The repair is to replace the table with a function approximator that takes the state and returns the action values: a linear model, or a neural network, which is deep Q-learning. Everything in this chapter still applies, and the convergence guarantees do not: with a table Q-learning is proved to converge, and with an approximator it can diverge.
Distinctions
V(s) | Q(s, a) | |
|---|---|---|
| Carries the action | no | yes |
| To act, needs the model | yes | no |
| Numbers stored here | 9 | 36 |
| Value iteration | Q-learning | |
|---|---|---|
Needs P and R | yes | no |
| Uses | the sum over next states | the one state that happened |
| Source of the average | computed | accumulated over visits |
| Result here | +0.7053 | +0.7053 |
| Q-learning | SARSA | |
|---|---|---|
| Bootstraps from | max over a' | the action actually taken |
| Policy | off-policy | on-policy |
| Learns | the optimal policy | the best policy for an exploring agent |
| On the cliff | -19.39, along the edge | -13.81, away from it |
| Can learn from logged data | yes | no |
What it does not mean
Q-learning does not build a model. It never estimates P(s' given s, a).
Q-Learning
Matching the optimal policy is not the measure. Two policies matched in 7 of 9 states and were worth +0.6817 and +0.2625.
A constant learning rate does not converge. The estimates bounce for ever, in proportion to alpha.
Off-policy does not mean the behaviour is irrelevant. Every state and action must still be visited, or its value is never learned.
Q-learning's poorer score on the cliff is not a failure. It is the cost of exploring while following an optimal route.
SARSA is not a worse algorithm. It answers a different question, and on a real robot it is usually the one wanted.
The table does not scale. Large problems need function approximation, which loses the convergence guarantee.
Quick revision
Q(s, a)is the value of takingainsand behaving well afterwards.V(s) = max over a of Q(s,a), and the policy is whichever action attains it, with no model.- The update:
Q(s,a) <- Q(s,a) + alpha [ r + gamma max over a' of Q(s',a') - Q(s,a) ]. The bracket is the temporal difference error. - Sampling replaces the sum: the Bellman equation averaged over every next state; this uses the one that happened, and the average accumulates over visits.
- Measured: after 100,000 episodes the policy is identical to value iteration's and worth +0.7053, with the values still wrong by 0.1067. The policy needs only the order.
- Judge a policy by what it is worth, not by how many actions match. Two runs matched 7 of 9 and were worth +0.6817 and +0.2625.
- Constant alpha never converges: error 0.2736 at
alpha = 0.50and 0.0396 at 0.05. To converge, the alphas must sum to infinity with their squares summing to something finite. - Off-policy: an agent acting uniformly at random learnt the optimal policy, 9 of 9, worth +0.7053, because the update takes the max rather than the action taken. Hence learning from logged data or a demonstrator.
- SARSA replaces the max with the action actually taken next, so it is on-policy: s, a, r, s', a'.
- The cliff: Q-learning -19.39 along the edge, SARSA -13.81 away from it. Q-learning learns the optimal policy; SARSA learns the best policy for an agent that explores.
- The table is one number per state and action. Large problems replace it with a function approximator, giving deep Q-learning, which loses the convergence guarantee.
Test yourself
1. Write the Q-learning update and name the bracketed term. Q(s,a) becomes Q(s,a) plus alpha times the quantity r + gamma * max over a' of Q(s',a') - Q(s,a). That quantity is the temporal difference error: what the observed step suggests the value should be, minus what was believed.
Q-Learning
2. Why does Q-learning need no model of the environment? The Bellman equation requires a sum over all next states weighted by their transition probabilities, which needs the model. The update replaces that sum with the single next state that actually occurred, and averages over many visits instead of computing the average, so the transition probabilities are never needed. Storing values for actions rather than states also means the policy can be read off without looking ahead.
3. In the measurement, two runs both matched the optimal policy in 7 of 9 states and were worth +0.6817 and +0.2625. What does that show? That counting matching actions is a poor measure of a policy. Which states disagree matters far more than how many, since an error in a state the agent passes through often or one that leads towards the penalty costs a great deal, while an error in a rarely visited state costs almost nothing.
4. Why do the values keep changing with a constant learning rate, and what condition fixes it? Each update moves the estimate part of the way towards one sampled outcome, so the estimate keeps being pulled around by individual samples and bounces about the true value in proportion to alpha. Exact convergence requires alpha to shrink so that the learning rates sum to infinity, leaving every estimate still movable, while the sum of their squares is finite, so the fluctuation dies away.
5. What does off-policy mean, and what evidence was given for it? That the policy being learnt about is not the one being used to act, because the update bootstraps from the maximum over the next state's actions rather than the action that will be taken. The evidence was a run in which the agent chose uniformly at random at every step and never used what it had learnt, and still recovered the optimal policy in all nine states, worth +0.7053.
6. State the difference between Q-learning and SARSA in one line, and explain the cliff result. Q-learning bootstraps from the maximum over the next actions; SARSA bootstraps from the action it will actually take. On the cliff Q-learning learns the optimal route along the edge and collects -19.39 per episode, because while exploring it sometimes steps off; SARSA builds the cost of its own exploration into the values, learns a route further from the edge, and collects -13.81. Q-learning has found the better policy for an agent that will stop exploring; SARSA the better policy for one that will not.
7. When would you prefer each? Q-learning when exploration will be turned off before the policy is used, and when learning must happen from logged data or a demonstrator's records, which SARSA cannot do because it needs its own action choices. SARSA when the agent will keep exploring in the real world and the mistakes are expensive, such as a physical robot near a drop.
The rest of this subject
These notes are cut from the University's printed syllabus. Open the syllabus itself, or the past papers, for the same subject.