munotes®

Q-Learning

Get access to whole semester resourcesSemester Pass

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.")
munotes.in525

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.
munotes.in526

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.

munotes.in527

Q-Learning

EpisodesLargest value errorActions matchingThe policy is worth
100.80995 of 9-1.0641
1000.65555 of 9+0.2855
10000.20077 of 9+0.6817
100000.07757 of 9+0.2625
1000000.10679 of 9+0.7053
munotes.in528

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.

munotes.in529

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.

munotes.in530

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.

munotes.in531

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.

munotes.in532

Q-Learning

alphaLargest value error at 30,000 episodesThe policy is worth
0.500.2736+0.7053
0.200.1076+0.6926
0.100.1062+0.6681
0.050.0396+0.6926
0.020.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 gridLargest value errorActions matchingWorth
Q-learning0.10679 of 9+0.7053
SARSA0.20459 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.

munotes.in533

Q-Learning

Mean reward over the last 500 episodesRoute
Q-learning-19.39rows 0 and 1: along the cliff edge
SARSA-13.81rows 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:

SituationPrefer
Exploration will be switched off at the endQ-learning
The agent keeps exploring in the real worldSARSA
Falling off the cliff is a real robot falling off a real tableSARSA
Learning from logged data or a demonstratorQ-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 actionnoyes
To act, needs the modelyesno
Numbers stored here936
Value iterationQ-learning
Needs P and Ryesno
Usesthe sum over next statesthe one state that happened
Source of the averagecomputedaccumulated over visits
Result here+0.7053+0.7053
Q-learningSARSA
Bootstraps frommax over a'the action actually taken
Policyoff-policyon-policy
Learnsthe optimal policythe best policy for an exploring agent
On the cliff-19.39, along the edge-13.81, away from it
Can learn from logged datayesno

What it does not mean

Q-learning does not build a model. It never estimates P(s' given s, a).

munotes.in534

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 taking a in s and 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.50 and 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.

munotes.in535

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.

munotes.in536

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.

Issue
Done!