Gradient Monte Carlo Algorithm
Gradient Monte Carlo updates parameterized value functions toward full-episode returns, achieving true gradient descent without bootstrapping bias.
Why Does This Exist?
When state spaces grow too large for lookup tables—such as continuous robotic joint spaces or high-dimensional board positions—reinforcement learning agents must approximate the state-value function using parameterized models, .
Tabular Monte Carlo simply averages observed returns per state. However, once function approximation is introduced, modifying the value of one state inevitably changes the values of neighboring states. To generalize correctly across unseen states, updates must minimize a formal global error metric, specifically the Mean Squared Value Error ().
Many function approximation methods rely on temporal-difference bootstrapping (such as Semi-Gradient TD), replacing future returns with the estimate . Because the bootstrap target itself depends on the parameter vector , TD ignores the derivative of the target with respect to . This turns TD into a semi-gradient method, stripping away conventional stochastic gradient descent (SGD) convergence guarantees.
Gradient Monte Carlo exists as the foundational baseline of true gradient methods in RL. By waiting until the episode terminates and using the complete empirical return as the target, the supervision signal is completely independent of the parameter vector . Because , every weight update follows the true negative gradient of the squared error in expectation, guaranteeing convergence to a global or local optimum.
Think of It Like This
End-of-Semester Student Evaluations
Imagine a university professor trying to evaluate and refine the clarity rating of each lecture module in a 15-week curriculum.
If the professor used bootstrapping (Temporal Difference learning), they would gauge the success of Lecture 3 by asking students how confident they feel about Lecture 4 immediately after Lecture 3 ends. If a student holds a misconception in Lecture 4, that biased self-assessment instantly corrupts the rating of Lecture 3.
Instead, Gradient Monte Carlo acts like comprehensive end-of-semester course evaluations and final exams. The professor delivers the entire syllabus from Week 1 through Week 15 without altering their baseline lecture ratings. Only after students complete their final cumulative exams does the professor inspect the total outcome (). If a student struggled on questions linked to concepts introduced in Lecture 3, the professor retroactively attributes that outcome and adjusts their teaching model's weights for those lecture topics.
Every final grade represents a concrete, uncorrupted realization of student comprehension. An individual student's exam score may fluctuate due to lack of sleep or personal distractions (high sample variance), but averaged across hundreds of students, the evaluation signal is completely unbiased.
Where the analogy stops: In reinforcement learning, the agent can adjust its decision policy across episodes based on these calibrated value weights, whereas a professor typically waits until the following academic year to modify their curriculum.
How It Actually Works
Mathematical Formulation and Objective Function
In on-policy value prediction with function approximation, we measure approximation quality using the Mean Squared Value Error, weighted by the on-policy state distribution :
Where:
- is the parameter weight vector.
- is the differentiable parameterized value function approximation.
- is the fraction of time steps spent in state under policy ().
- is the true underlying value of state .
To minimize via stochastic gradient descent, the ideal parameter update for an observed state is proportional to the negative gradient of the squared error:
In practice, the true value is unknown. Gradient Monte Carlo substitutes the complete empirical discounted return for :
Yielding the Gradient Monte Carlo update rule:
Where:
- is the learning rate step-size parameter.
- is the discount factor.
- is the terminal time step of the episode.
- is the column vector of partial derivatives with respect to the components of .
Because is an unbiased estimator of () and does not depend on , the expected update vector is the exact negative gradient of . Under standard Robbins-Monro step-size conditions (), the algorithm is guaranteed to converge to a local optimum (and the unique global optimum under linear representations).
For linear function approximation, the value function is the inner product of the weight vector and a state feature vector :
The gradient reduces directly to the feature vector: . The linear Gradient Monte Carlo update is:
Worked Numerical Example
Consider an episodic environment with 6 states, , partitioned into two coarse state-aggregation groups:
- Group 1 (): represented by feature vector .
- Group 2 (): represented by feature vector .
Parameters:
- Learning rate:
- Discount factor: (undiscounted)
- Initial weight vector:
The agent generates an episode of length :
- (Group 1), takes action, receives reward , transitions to .
- (Group 2), takes action, receives reward , transitions to .
- (Group 2), takes action, receives reward , transitions to terminal state.
Step 1: Backward Return Computation
At episode termination, the agent computes returns recursively from down to :
Step 2: Sequential Weight Updates
Now the agent iterates through the trajectory to perform gradient updates.
Update for (, ):
- Feature vector:
- Prediction:
- Error:
- Gradient update:
Update for (, ):
- Feature vector:
- Prediction:
- Error:
- Gradient update:
Update for (, ):
- Feature vector:
- Prediction:
- Error:
- Gradient update:
Final Value Estimates after 1 Episode:
- Group 1 states ():
- Group 2 states ():
Notice how the second visit to Group 2 at benefited from the update made at , reducing the error from down to .
Code
from typing import List, Tuple, Sequence
class LinearGradientMonteCarlo: """Gradient Monte Carlo for episodic value prediction with linear function approximation."""
def __init__(self, num_features: int, alpha: float = 0.01, gamma: float = 1.0) -> None: self.num_features = num_features self.alpha = alpha self.gamma = gamma self.weights: List[float] = [0.0] * num_features
def predict(self, features: Sequence[float]) -> float: """Compute estimated state value: v_hat(s, w) = w^T * x(s).""" return sum(w * x for w, x in zip(self.weights, features))
def update_episode( self, trajectory: List[Tuple[Sequence[float], float]], ) -> List[float]: """Update weights using full-episode trajectory of (state_features, reward).
Args: trajectory: List of (feature_vector, reward_received) pairs for t = 0 .. T-1. Returns: Updated weight vector. """ if not trajectory: return list(self.weights)
t_steps = len(trajectory) returns = [0.0] * t_steps
# Backward pass: compute empirical return G_t = R_{t+1} + gamma * G_{t+1} running_g = 0.0 for t in reversed(range(t_steps)): reward = trajectory[t][1] running_g = reward + self.gamma * running_g returns[t] = running_g
# Forward pass: stochastic gradient descent updates for t in range(t_steps): features = trajectory[t][0] target_g = returns[t] prediction = self.predict(features) error = target_g - prediction
# Gradient for linear model is the feature vector x(s) for i in range(self.num_features): self.weights[i] += self.alpha * error * features[i]
return list(self.weights)
# Demonstrate on the worked exampleif __name__ == "__main__": # State aggregation: 2 feature dimensions (Group 1: [1, 0], Group 2: [0, 1]) agent = LinearGradientMonteCarlo(num_features=2, alpha=0.5, gamma=1.0)
# Trajectory: # S0=2 (Group 1) -> R1=1.0 -> S1=4 (Group 2) -> R2=0.0 -> S2=5 (Group 2) -> R3=3.0 -> Terminal episode_trajectory = [ ([1.0, 0.0], 1.0), # (features_S0, R1) ([0.0, 1.0], 0.0), # (features_S1, R2) ([0.0, 1.0], 3.0), # (features_S2, R3) ]
final_weights = agent.update_episode(episode_trajectory)
print(f"Final Weights: [w1={final_weights[0]:.4f}, w2={final_weights[1]:.4f}]") print(f"Value Estimate Group 1: {agent.predict([1.0, 0.0]):.4f}") print(f"Value Estimate Group 2: {agent.predict([0.0, 1.0]):.4f}")# Expected Output:# Final Weights: [w1=2.0000, w2=2.2500]# Value Estimate Group 1: 2.0000# Value Estimate Group 2: 2.2500Watch Out For
High Variance and Episodic Horizon Latency
Because Gradient Monte Carlo constructs targets from un-bootstrapped sample trajectories, accumulates the stochastic transitions and reward noise across all future steps until termination:
In environments with long horizons or high action stochasticity, this variance causes updates to fluctuate wildly, requiring extremely small learning rates and thousands of episodes to converge.
Furthermore, Gradient Monte Carlo cannot perform online updates during an ongoing episode. In tasks with very long or non-terminating (continuing) horizons (), the algorithm is entirely unusable because cannot be computed.
The Fix: When sample efficiency or online adaptation is required, transition to n-step Semi-Gradient TD or eligibility traces (). If retaining un-bootstrapped gradient guarantees is essential, apply variance-reduction techniques such as baseline subtraction, feature normalization, or learning rate schedules satisfying Robbins-Monro conditions.
The Quick Version
- True Gradient Guarantee: Because complete returns do not depend on the parameter vector , Gradient Monte Carlo follows the true negative gradient of the Mean Squared Value Error ().
- Zero Bootstrapping Bias: Targets represent unbiased real-world trajectory returns, eliminating the self-referential estimation bias inherent to TD methods.
- High Sample Variance: Accumulating stochastic rewards across entire trajectories introduces high variance, requiring smaller learning rates and more training episodes.
- Strictly Episodic: Updates require trajectory completion and cannot be computed online mid-episode or applied to infinite-horizon continuing tasks.