Linear Methods in RL
Linear methods compute value estimates as a simple weighted sum of handcrafted features, guaranteeing that the mathematical error surface is a clean bowl with a single global optimum.
Why Does This Exist?
In realistic reinforcement learning applications—such as robotics, game playing, and resource allocation—the state space is vast or continuous. Tabular representations, where a separate memory cell is allocated for every single state , collapse under memory limitations and fail completely to generalize: experiencing state tells a tabular agent nothing about a virtually identical state .
To generalize across states, practitioners use function approximation. However, complex non-linear function approximators like deep neural networks introduce thorny theoretical and practical headaches: non-convex loss landscapes, local minima, saddle points, sensitivity to hyperparameter tuning, and catastrophic divergence when paired with bootstrapping and off-policy sampling (the notorious "deadly triad").
Linear methods represent the premier, theoretically sound workhorse of function approximation. By parameterizing the value function strictly as an inner product of a learnable weight vector and a feature vector, linear methods transform the value-error objective into a strictly convex quadratic bowl. There are no local minima traps, gradients compute in time, and on-policy TD algorithms are mathematically guaranteed to converge to a bounded global fixed point.
Think of It Like This
The Weighted Grading Rubric
Imagine a university professor calculating a student's final course score using a syllabus rubric:
- The Feature Vector : The student's raw performance across different categories:
- Homework assignments completed:
- Midterm exam score:
- Final exam score:
- Class attendance:
- The Weight Vector : The syllabus percentage allocated to each category:
To find the final course score , the professor does not run the data through a convoluted, non-linear multi-layer network. She simply computes the weighted sum (inner product):
If the professor wants to adjust the final score upward by points, the adjustment needed for each weight is directly proportional to how much that assignment contributed ().
Where the analogy stops: A grading rubric is fixed beforehand by a human instructor. In reinforcement learning, the weights are dynamic parameters learned through gradient descent, adjusting continuously on each observed state transition until prediction errors reach their mathematical minimum.
How It Actually Works
The Linear Function Approximator and the Gradient Property
In linear methods, any environmental state is mapped into a -dimensional feature vector:
The approximate state-value function is the linear combination (inner product) of the feature vector and a learnable parameter vector :
The mathematical elegance of linear approximation stems from its gradient with respect to the weights . Taking the partial derivative with respect to any weight :
In vector notation:
The gradient of a linear function approximator is simply the feature vector itself. This identity drastically simplifies implementation: there is no backpropagation pass or chain-rule recursion—the direction of steepest value increase is already given directly by the input representation.
Strictly Convex Error Surfaces: No Local Minima
When evaluating the quality of approximation across a state distribution , practitioners measure the Mean Squared Value Error:
Expanding this objective yields a quadratic form in :
where is the feature covariance matrix. Because is positive semi-definite, forms a strictly convex paraboloid (a single bowl) in weight space:
- There are no local minima traps.
- There are no saddle points.
- Any gradient descent process that converges is guaranteed to land at the unique global optimum .
Linear Stochastic Gradient Descent vs. Semi-Gradient TD(0)
1. Linear Monte Carlo SGD
When trained with unbiased full-return targets (Monte Carlo), the standard SGD update rule is:
Because , this update is an unbiased sample gradient of , ensuring asymptotic convergence to the best possible linear approximation .
2. Linear Semi-Gradient TD(0)
In temporal difference learning, the true return is replaced by the bootstrapped one-step TD target:
The TD error is:
The semi-gradient update treats the target as independent of :
Convergence Guarantees and the TD Fixed-Point Bound
Unlike non-linear neural networks, which can diverge during semi-gradient bootstrapping, linear semi-gradient TD(0) is proven to converge on-policy to a unique weight vector called the TD fixed point (Tsitsiklis and Van Roy, 1997).
Furthermore, the error at the TD fixed point is strictly bounded relative to the global theoretical minimum:
For , the final approximation error is at most the best achievable linear projection; for small discount factors, the solution is virtually identical to the optimal projection.
Worked numerical example
Consider a 2-dimensional feature representation for state :
1. Forward Prediction
2. Target Observation
Suppose the agent observes an episode target return . The prediction error is:
3. Weight Vector Update
Using the gradient identity :
4. New Prediction Verification
Notice that the prediction shifted toward the target by exactly:
The prediction changed cleanly by a fraction determined by step size and feature magnitude .
Code
import mathfrom typing import List, Tuple
class LinearValueApproximator: """Linear value function approximator v_hat(s, w) = w^T x(s)."""
def __init__(self, num_features: int, initial_weights: List[float]): assert len(initial_weights) == num_features self.num_features = num_features self.w = list(initial_weights)
def predict(self, x: List[float]) -> float: """Compute inner product between weights and features.""" assert len(x) == self.num_features return sum(w_i * x_i for w_i, x_i in zip(self.w, x))
def update_sgd(self, x: List[float], target: float, alpha: float) -> float: """Update weights via linear SGD: w <- w + alpha * (target - v_hat) * x.""" v_hat = self.predict(x) error = target - v_hat for i in range(self.num_features): self.w[i] += alpha * error * x[i] return error
def update_semi_gradient_td( self, x: List[float], reward: float, x_next: List[float], gamma: float, alpha: float, ) -> float: """Update weights via Semi-Gradient TD(0): delta = R + gamma * v(s') - v(s).""" v_current = self.predict(x) v_next = self.predict(x_next) td_target = reward + gamma * v_next td_error = td_target - v_current
for i in range(self.num_features): self.w[i] += alpha * td_error * x[i] return td_error
if __name__ == "__main__": # State features: x(S) = [1.0, 0.5] features_s = [1.0, 0.5] init_w = [2.0, 1.0] approximator = LinearValueApproximator( num_features=2, initial_weights=init_w )
# 1. Forward Prediction Check v_init = approximator.predict(features_s) print(f"Initial Value Prediction: {v_init:.3f}") assert math.isclose(v_init, 2.5), f"Expected 2.5, got {v_init}"
# 2. Monte Carlo SGD Update towards target U = 4.0 with alpha = 0.2 target_return = 4.0 err = approximator.update_sgd(features_s, target=target_return, alpha=0.2) v_updated = approximator.predict(features_s)
print(f"Error: {err:.3f} | Updated Weights: {approximator.w}") print(f"Updated Value Prediction: {v_updated:.3f}")
assert math.isclose( approximator.w[0], 2.30 ), f"Expected w[0] = 2.30, got {approximator.w[0]}" assert math.isclose( approximator.w[1], 1.15 ), f"Expected w[1] = 1.15, got {approximator.w[1]}" assert math.isclose( v_updated, 2.875 ), f"Expected v_updated = 2.875, got {v_updated}"
# 3. Semi-Gradient TD(0) Update Step features_next = [0.8, 0.4] reward = 1.0 gamma = 0.9 td_err = approximator.update_semi_gradient_td( x=features_s, reward=reward, x_next=features_next, gamma=gamma, alpha=0.1, )
print(f"TD Error: {td_err:.3f} | Weights after TD update: {approximator.w}") print("\nAll linear method assertions passed successfully.")
# Expected Output:# Initial Value Prediction: 2.500# Error: 1.500 | Updated Weights: [2.3, 1.15]# Updated Value Prediction: 2.875# TD Error: 0.195 | Weights after TD update: [2.3195, 1.15975]## All linear method assertions passed successfully.Watch Out For
Feature Scale Imbalance and Ill-Conditioned Curvature
A common failure mode in linear methods is using unnormalized features whose numerical scales differ by orders of magnitude (for instance, combining a vehicle velocity feature in with an obstacle distance feature in ).
When features have disparate scales:
- The covariance matrix becomes ill-conditioned, elongating the quadratic error bowl into an extremely sharp, narrow elliptical canyon.
- Gradient updates oscillate wildly perpendicular to the steep walls rather than progressing smoothly toward the minimum along the flat floor.
- A single global learning rate either causes divergence along the high-magnitude feature or painfully sluggish learning along the low-magnitude feature.
The Fix:
- Feature Normalization: Standardize all feature dimensions to zero mean and unit variance (), or rescale strictly into .
- Dimension-Specific Step Sizes: Scale individual learning rates inversely with feature magnitude: .
- Normalized Feature Representations: Use tile coding, radial basis functions (RBFs), or Fourier bases where feature vector norms are naturally bounded: .
The Quick Version
- Inner product formulation: Linear methods estimate state values as , combining handcrafted feature representations with learnable weights.
- Gradient equals the feature: Because , updates simplify to without backpropagation or chain-rule complexity.
- Unimodal convex landscape: The Value Error is a quadratic paraboloid with a unique global optimum; there are zero local minima traps or saddle points.
- Guaranteed TD fixed point: Linear semi-gradient TD(0) converges reliably on-policy to a bounded fixed point whose error is within of the best theoretical linear projection.