Skip to content
AI360XpertBeta

Advantages of TD over MC and DP

TD updates from every step by bootstrapping off its own estimates, while Monte Carlo waits for the final score. That makes TD online and low variance at the price of early bias.

TD updates the start value to 1.30 after one step while Monte Carlo waits for the full return 7.58 and lands at 1.52
TD updates the start value to 1.30 after one step while Monte Carlo waits for the full return 7.58 and lands at 1.52

Why Does This Exist?

Estimating a state's value means predicting the rewards still to come. The two classical answers each demand something you often lack.

Dynamic programming computes values from a perfect model: transition probabilities and reward tables for every outcome. Hand it the model and it sweeps the state space with zero sampling noise. Refuse it the model, which is the normal case in robotics and games, and it cannot start. Big spaces make the sweeps costly too.

Monte Carlo methods drop the model and learn from real episodes. Honest prices. You must finish the episode before any update, so continuing tasks that never terminate get nothing. Worse, the target sums noise from every future step, so variance balloons and data demands explode.

Temporal-difference learning takes the workable half of each. Like Monte Carlo it learns model-free from sampled transitions. Like dynamic programming it bootstraps from successor estimates after a single step. You get online updates, continuing-task support, and low-variance targets, paying with bias that fades as the table improves.

Think of It Like This

Calling your arrival time mid-drive

You leave work expecting a 45 minute drive home.

The dynamic programming driver pre-simulates the whole city before turning the key: every light, every merge, every pedestrian. Perfect with a perfect simulator. Useless without one.

The Monte Carlo driver refuses to revise until parked in the driveway. Fifteen minutes in, gridlock doubles the remaining time, and still no update. At minute 90 the driver finally revises the 5 PM estimate. On a road trip with no destination, the revision never comes.

The TD driver revises at the first jam. Remaining time jumps from 30 to 60 minutes, so the departure estimate jumps from 45 to 75 on the spot. One local change, immediate lesson, no waiting for the driveway.

Where it stops: early estimates can mislead. If your guess of the remaining drive is wrong, the revised total inherits that error until the downstream guesses improve.

How It Actually Works

Symbols for this page: V(s)V(s) is the estimated value of state ss, Rt+1R_{t+1} the next reward, γ\gamma the discount, α\alpha the step size, GtG_t the full Monte Carlo return, and δt\delta_t the TD error. Two ideas split the three methods: sampling (model or experience) and bootstrapping (estimates or full returns).

Dynamic programming backs up a full expectation one step deep. It needs the model p(s′,r∣s,a)p(s', r \mid s, a) and the current successor values, computes with zero variance, and sweeps offline. Monte Carlo backs up one sampled episode at full depth. It needs no model, uses only realized rewards, carries zero bias since the expected return equals the true value, and pays with high variance plus end-of-episode timing. TD with one-step depth backs up one sampled transition:

V(St)←V(St)+α [Rt+1+γV(St+1)−V(St)]V(S_t) \leftarrow V(S_t) + \alpha\,[R_{t+1} + \gamma V(S_{t+1}) - V(S_t)]

The bracket is the TD error δt\delta_t, and Rt+1+γV(St+1)R_{t+1} + \gamma V(S_{t+1}) is the TD target. Model-free like Monte Carlo, bootstrapping like dynamic programming, constant work per step, usable mid-episode and in continuing tasks.

Three properties side by side

Model needed: dynamic programming wants the full transition model, while Monte Carlo and TD learn from experience alone. Bootstrapping: dynamic programming and TD bootstrap at depth 1, Monte Carlo never bootstraps. Update timing: dynamic programming sweeps offline in batches, Monte Carlo waits for termination, TD updates after every transition. Variance runs from zero to high to low across the three. Bias runs from zero with a true model, to none for Monte Carlo, to early bias for TD that vanishes as values converge.

Worked example with target 6.50 against return 7.58

A three-state chain pays +2+2, then −1-1, then +8+8 before terminating. Discount γ=0.9\gamma = 0.9, step size α=0.2\alpha = 0.2, values V(S0)=0.0V(S_0) = 0.0, V(S1)=5.0V(S_1) = 5.0, V(S2)=10.0V(S_2) = 10.0, terminal 0.00.0.

TD acts after the first transition (S0→S1,R1=2.0)(S_0 \to S_1, R_1 = 2.0):

TD target=2.0+0.9×5.0=6.50\text{TD target} = 2.0 + 0.9 \times 5.0 = 6.50 δ0=6.50−0.0=6.50,V(S0)←0.0+0.2×6.50=1.30\delta_0 = 6.50 - 0.0 = 6.50, \quad V(S_0) \leftarrow 0.0 + 0.2 \times 6.50 = 1.30

State S0S_0 improves at step one. Nothing downstream needed.

Monte Carlo must walk the whole chain first, then discounts all three rewards:

G0=2.0+0.9×(−1.0)+0.81×8.0=2.0−0.90+6.48=7.58G_0 = 2.0 + 0.9 \times (-1.0) + 0.81 \times 8.0 = 2.0 - 0.90 + 6.48 = 7.58 V(S0)←0.0+0.2×7.58=1.516≈1.52V(S_0) \leftarrow 0.0 + 0.2 \times 7.58 = 1.516 \approx 1.52

Same start, two lessons. TD learns sooner and insulates S0S_0 from late-trajectory noise by substituting the smooth V(S1)V(S_1) for the whole tail. Monte Carlo sees the true +8+8 but imports every wobble along the way. If that last reward flipped between +20+20 and −4-4 across episodes, the TD update would barely move while the Monte Carlo target swung wildly.

Code

A short check of the two updates above, with type hints throughout:

from typing import List

def td_update(v0: float, reward: float, v_next: float, gamma: float, alpha: float) -> float:    target = reward + gamma * v_next    return v0 + alpha * (target - v0), target

def mc_return(rewards: List[float], gamma: float) -> float:    total = 0.0    for k, r in enumerate(rewards):        total += (gamma ** k) * r    return total

gamma = 0.9alpha = 0.2
v_td, td_target = td_update(0.0, 2.0, 5.0, gamma, alpha)print([round(td_target, 2), round(v_td, 2)])# -> [6.5, 1.3]
g0 = mc_return([2.0, -1.0, 8.0], gamma)print([round(g0, 2), round(alpha * g0, 2)])# -> [7.58, 1.52]
# -> expected output:[6.5, 1.3][7.58, 1.52]

Watch Out For

Trusting bootstraps while the table is still crude

TD targets contain your own guesses, so early errors recycle into new updates. In tables this washes out with standard decaying step sizes. With neural networks plus off-policy data it can spiral: approximation, bootstrapping and off-policy updates form the deadly triad, and values diverge instead of settling.

Keep step sizes modest in tables, and in deep setups split the target from the weights being trained with target networks. If values oscillate or explode, suspect the bootstrap before the reward design.

The Quick Version

  • Dynamic programming needs a model and sweeps offline, Monte Carlo needs finished episodes and pays high variance, TD needs neither.
  • The TD update V(St)+α[Rt+1+γV(St+1)−V(St)]V(S_t) + \alpha[R_{t+1} + \gamma V(S_{t+1}) - V(S_t)] learns after every transition, including in continuing tasks.
  • Bootstrapping cuts variance by replacing the noisy tail with a smooth estimate, at the price of early bias that fades with convergence.
  • On rewards [2.0,−1.0,8.0][2.0, -1.0, 8.0] with γ=0.9\gamma = 0.9, the TD target is 6.506.50 giving 1.301.30, while the Monte Carlo return is 7.587.58 giving 1.521.52.
  • With function approximation plus off-policy data, bootstrapping can diverge, so use target networks and modest step sizes.