Notes, essays, and fragments from the edge of understanding.

my notes on RL

July 14, 2026

bellman equations

No. think of a ball in space, if you only give that state and not the previous state how would the model know if the ball is going up or down. I know you are thinking you can just give velocity as state too and that’s right.

but now think about poker, in the immediate state, you only have your cards and the cards on table so you do not know what cards your opponent have and that matters a lot so if you had all previous states you would have been able to tell from how the players played what kind of cards do they have.

is a neural network always a deterministic policy?

if we always pick the answer with highest policy then yes it is deterministic but if we sample then it becomes non deterministic

both of these equations are equivalent

this means all possible combination of sum of these rewards and probability of its coming, sometimes you will not know all possible values, so you have to use Monte-Carlo to get these R values

Concept Description Notation State Value Formula
Expectation Following a specific policy and finding V values for various state.
we can vectorize to solve this all at once
π






Optimality Finding the perfect policy but finding the optimum V values
because of the max there, it can not be vectorized
*







is this like always valid?

if we know the values of P for every state then we do not need to do Reinforcement learning, we can just use the equations above.


many people confuse what P really is, its not the probablity of choosing an action. it is the probablity that the action will indeed happen after choosing it. it’s the physics not the choice.

there are cases when we exactly know the p value, for example in chess you know when you move a peice from position A to position B it is 100% gonna move that way but when moving a robot the real physics kicks in and we are not sure


Grid World Problem

the question setup

world: a 5x5 grid.

start: (1,1). goal: (5,5).

rewards:

  • step reward = 0 for all steps.

  • goal reward = +100 (when transitioning into the goal).

  • discount factor γ = 0.9.

physics (noisy robot):

  • intended direction: 80% chance (0.8).

  • slip 90° clockwise: 10% chance (0.1).

  • slip 90° counter-clockwise: 10% chance (0.1).

  • if slip leads into a wall, robot bounces back to current square.


initialization (iteration 0)

at the very beginning, the agent knows nothing.

v(s) = 0 for every single square on the board.

iteration 1 (the first update)

We will focus on square (4,5) — the square immediately above the goal.

Step A: Calculate Q-Values

We must calculate the score for every button the robot can press: down, up, left, right.

The Formula:


Action: TRY DOWN

  • Physics: 0.8 to Goal, 0.1 to Wall (Stay), 0.1 to (4,4).

Step 1: Calculate Expected Reward R(s,a)

R_down = (0.8×100) + (0.1×0) + (0.1×0) = 80

Step 2: Calculate Expected Future ∑PV

∑PV = (0.8×0) + (0.1×0) + (0.1×0) = 0

(Note: All V are currently 0).

Step 3: Combine

Q_down = 80 + 0.9(0) = 80

Q_down = 80


Action: TRY LEFT

  • Physics: 0.8 to (4,4), 0.1 to (3,5), 0.1 to Goal (Lucky Slip).

Step 1: Calculate Expected Reward R(s,a)

R_left = (0.8×0) + (0.1×0) + (0.1×100) = 10

Step 2: Calculate Expected Future ∑PV

∑PV = (0.8×0) + (0.1×0) + (0.1×0) = 0

Step 3: Combine

Q_left = 10 + 0.9(0) = 10

Q_left = 10


Action: TRY UP

  • Physics: 0.8 to (3,5), 0.1 to Wall, 0.1 to (4,4).

Step 1: Calculate Expected Reward R(s,a)

R_up = (0.8×0) + (0.1×0) + (0.1×0) = 0

Step 2: Calculate Expected Future ∑PV

∑PV = 0

Step 3: Combine

Q_up = 0 + 0.9(0) = 0

Q_up = 0


Action: TRY RIGHT

  • Physics: 0.8 to Wall, 0.1 to Goal (Lucky Slip), 0.1 to (3,5).

Step 1: Calculate Expected Reward R(s,a)

R_right = (0.8×0) + (0.1×100) + (0.1×0) = 10

Step 2: Calculate Expected Future ∑PV

∑PV = 0

Step 3: Combine

Q_right = 10 + 0.9(0) = 10

Q_right = 10


Step B: Find V (The Max)

The agent looks at the list of q-values: 80, 10, 0, 10.

It picks the winner:

V(4,5) = max(Q_down, Q_left, Q_up, Q_right)

V(4,5) = max(80, 10, 0, 10)

V(4,5) = 80

Update: We erase the 0 on square (4,5) and write 80.

now you can do this same for 4,4 or 5,4 or 3,5

suppose you calculated for 3,5 and all the other remaining state one by one

this was iteration one, now because of the changed V of 3,5 the V of 4,5 will also change so we will do iteration two calculating the V of all the States agian, and then repeat agian

how would we know where to stop?

Convergence Algorithm

  • Set a threshold: e.g., θ = 0.001 (your "good enough" stopping criterion)

  • Start a sweep: iterate through all 25 squares

  • Calculate change: for each square, compute |v_new - v_old|

  • Track maximum change (δ):

    • If square (4,5) changed by 0.6, then δ = 0.6

    • If square (3,5) changed by 0.8, then δ = 0.8

  • Check convergence: at end of sweep, is δ < θ?

    • If no (e.g., 0.8 < 0.001? no) → repeat the sweep

    • If yes (e.g., sweep 50: δ = 0.00004 < 0.001) → stop

Policy Evaluation Using Vectorized Equation

We are building the equation:

We need to build two giant objects:

  1. Vector : A column of 25 numbers.

  2. Matrix : A 25×25 grid of probabilities.


The Setup (Indices)

To make this "Vectorized," we must flatten the grid.

  • Row 1 is States 1-5.

  • ...

  • Row 4 is States 16-20. State 20 is (4,5).

  • Row 5 is States 21-25. State 24 is (5,4). State 25 is (5,5) [Goal].


Part 1: Calculating Vector (Expected Reward)

The Formula:

We need to calculate this for State 20 (Coordinate 4,5).

Neighbors:

  • Down: Goal (State 25).

  • Right: Wall (Bounces back to State 20).

  • Left: Empty (State 19).

  • Up: Empty (State 15).

We sum the expected cash from all 4 buttons (0.25 chance each).

1. Action: TRY DOWN (Intention: Goal)

  • Success (0.8): Enters Goal. Reward = 100.

  • Slip Right (0.1): Hits Wall (State 20). Reward = 0.

  • Slip Left (0.1): Goes Left (State 19). Reward = 0.

2. Action: TRY RIGHT (Intention: Wall)

  • Success (0.8): Hits Wall. Reward = 0.

  • Slip "Right" (0.1): Relative right is Down → Enters Goal. Reward = 100.

  • Slip "Left" (0.1): Relative left is Up. Reward = 0.

3. Action: TRY LEFT (Intention: Empty)

  • Success (0.8): Goes Left. Reward = 0.

  • Slip "Right" (0.1): Relative right is Up. Reward = 0.

  • Slip "Left" (0.1): Relative left is Down → Enters Goal. Reward = 100.

4. Action: TRY UP (Intention: Empty)

  • Success (0.8): Goes Up. Reward = 0.

  • Slips (0.1/0.1): Go Left/Right. Reward = 0.

Total Expected Reward for State 20

R(20) = 20 + 2.5 + 2.5 + 0 = 25

(We would repeat this exact math for State 24 (5,4) and get 25. All other states are 0).

The Final Vector R:


Part 2: Calculating Matrix P_π (Transitions)

The Formula:

We need to fill Row 20 (State 4,5) of the matrix. This row tells us: "If I start at (4,5), what is the probability I land in X?"

We calculate the probability for each possible destination.

Destination A: The Goal (State 25)

Which actions can take us to the Goal (Down)?

  1. Try Down (0.25): Success chance is 0.8 → (0.25 × 0.8) = 0.2

  2. Try Left (0.25): Slip "Left" (which is Down) chance is 0.1 → (0.25 × 0.1) = 0.025

  3. Try Right (0.25): Slip "Right" (which is Down) chance is 0.1 → (0.25 × 0.1) = 0.025

  4. Try Up (0.25): Cannot reach Goal.

Total Prob to Goal:

Destination B: The Wall/Self (State 20)

Which actions leave us at State 20? (Hitting the wall to the Right).

  1. Try Right (0.25): Success (Hit wall) chance is 0.8 → (0.25 × 0.8) = 0.2

  2. Try Up (0.25): Slip "Right" (Hit wall) chance is 0.1 → (0.25 × 0.1) = 0.025

  3. Try Down (0.25): Slip "Right" (Hit wall) chance is 0.1 → (0.25 × 0.1) = 0.025

  4. Try Left (0.25): Cannot hit Right wall.

Total Prob to Self:

Destination C: Left (State 19)

Which actions take us Left?

  1. Try Left (0.25): Success 0.8 → 0.2

  2. Try Up (0.25): Slip Left 0.1 → 0.025

  3. Try Down (0.25): Slip Right (relative to Down is Left on map) 0.1 → 0.025

Total Prob to State 19:

Destination D: Up (State 15)

(Same logic as above)

Total Prob to State 15:


Part 3: The Final Matrix Equation

Now we have our ingredients.

  1. R: A vector with 25s at indices 20 and 24.

  2. P: A matrix where Row 20 has 0.25 at indices [15, 19, 20, 25].

Now we solve:

tic-tac-toe with bellman equations

To use the Bellman equation, we must force tic-tac-toe to fit into the tuple .

In the grid world, this was easy:

  • State: Where am I? (square 1–25)

  • Physics: The wind

In tic-tac-toe, it is harder. We are player X. The opponent is player O.

1. The State

In grid world, a state was a coordinate .

In tic-tac-toe, a state is the board configuration.

Imagine a list of 9 numbers representing the 3×3 grid:

  • 0 = empty

  • 1 = X (us)

  • 2 = O (opponent)

Example state: .

This is a specific "square" on our massive mental map.

2. The Action

Definition: Placing an X in an empty spot.

Constraint: You cannot play in a spot that is already 1 or 2.

3. The Reward

We need to define the motivation.

Grid world: step = 0, goal = +100.

Tic-tac-toe:

  • We win (3 Xs):

  • We lose (3 Os): (this is new; grid world did not have death)

  • Draw (full board, no winner): (or maybe to discourage boring games, but we will stick to 0)

  • Ongoing game:

4. The Discount Factor

Let .

Why? If we can win in 1 move, we want that more than winning in 3 moves. Discounting creates urgency.

The Big Logical Hurdle: The Physics

This is the most critical concept to understand.

In grid world, when we chose "action down," the environment (physics) calculated the result:

  • Agent moves

  • Wind blows

  • New state

In tic-tac-toe, the environment includes the opponent.

Steps:

  1. We choose a move (place X)

  2. The environment processes our move, but the state is not "ours" yet. It is not our turn again yet

  3. The opponent places an O

  4. New state: it is our turn again

Crucial logic:

From the perspective of the Bellman equation, we do not see the opponent moving. The opponent is just a force of nature, like the wind.

We make a move, we close our eyes, the "wind" (opponent) blows, and we open our eyes to see a new board setup with an extra O on it.

Therefore, depends entirely on how the opponent plays.

We have two choices for designing our "physics":

  • The drunk opponent: The opponent plays randomly (environment is stochastic / noisy)

  • The god opponent: The opponent plays perfectly (environment is adversarial)

Decision: To learn the logic of MDPs, we will build the AI to crush a random opponent (the drunk opponent).

This fits our previous math perfectly: is the probability distribution of the opponent's random moves.


Module 2: The Map (The State Space)

We need to list every possible situation the agent could ever find itself in.

1. The Coordinate System

In grid world, a state was .

In tic-tac-toe, a state is a tuple of 9 numbers .

Start state: .

This is our "state " equivalent. The journey begins here.

2. The Size of the World

How big is our matrix going to be?

Mathematically: There are 3 options per square and 9 squares.

Calculation: combinations.

But most of these are impossible:

  • You cannot have a board with 9 Xs and 0 Os

  • You cannot have a board where both X and O have won simultaneously

The "turn" logic:

Since we defined the transition as "I move, then opponent moves," our agent only gets to make decisions when it is X's turn.

This means we only care about states where .

(Because X goes first. At the start: 0 vs 0. After round 1: 1 vs 1.)

If we filter out the impossible states, the number of valid states drops to roughly 5,000.

Conclusion: 5,000 is tiny. A computer can solve a matrix in milliseconds. We are safe to use the exact Bellman equations.

3. The Terminal States (The Cliffs and Goals)

In grid world, we had the goal (+100) and the rest were normal.

In tic-tac-toe, the game can end in three ways. We need to identify these terminal states because for these states is fixed. We do not calculate them; we assign them.

We classify every state into 4 categories:

  • X won (e.g., 3 Xs in a row)Value: Status: terminal, game over

  • O won (e.g., 3 Os in a row)Value: Status: terminal, game over

  • Draw (board full, no winner)Value: Status: terminal, game over

  • In progress (none of the above)Value: unknown. This is what we need to calculate.


Module 3: The Physics (The Opponent)

We need to define a function that returns a list of possible outcomes and their probabilities.

The Inputs

  • : the current board (e.g., )

  • : the index where we place our X (e.g., index 2)

The Logic Flow

Phase 1: My Move (Deterministic)

  • Take the board state

  • Place a 1 (X) at the action index

  • Call this

Phase 2: Check for Instant Win

  • Did we just make 3 Xs in a row?

  • If yes: the transition is complete

    • Outcome:

    • Probability:

    • Reward:

    • Stop here. The opponent does not get to move.

Phase 3: Check for Draw

  • Is full (and X did not win)?

  • If yes: the transition is complete

    • Outcome:

    • Probability:

    • Reward:

Phase 4: The Opponent's Turn (Probabilistic)

If the game is not over, the opponent moves.

  • Identify all 0s (empty spots) remaining on

  • Suppose there are 4 empty spots left

  • Since the opponent is random, they have a chance of picking each spot

Phase 5: Generate Next States

For each of the 4 empty spots:

  • Create a copy of

  • Place a 2 (O) in that spot

  • This new board is a possible

Probability:

Reward:

  • If this new board is an "O winner": reward =

  • If not: reward =

Example Trace (The Mental Model)

Current state :

We have 2 Xs and 1 O. It is our turn.

My action : place X at top-middle (index 1).

Phase 1 (my move):

Board becomes:

Phase 2/3 (check): Did we win? No. Draw? No.

Phase 4 (opponent):

There are 5 empty spots left.

Opponent has chance for each.

Phase 5 (outcomes):

  • Outcome 1: opponent plays at position (1, 0) New board : Probability: . Reward:

  • Outcome 2: opponent plays at (1, 2)New board : ...Probability: . Reward:

  • ...

  • Outcome 5: opponent plays at (2, 2)Probability: . Reward:

Conclusion: For this specific state–action pair , our physics tells us there are 5 possible futures, each with probability .

When we calculate the value , we will average the values of these 5 futures.


Module 4: The Solution (Value Iteration Logic)

We need a dictionary called .

  • Key: the board state (tuple)

  • Value: the score (float)

Step 0: Initialization

  • Generate all valid legal states (where )

  • Set for everything

Identify the terminal states inside this list (game-over states) and permanently lock their values:

  • If X won:

  • If O won:

  • If draw:

Step 1: The Loop (Repeat Until Convergence)

Loop through every non-terminal state in the list.

Step 2: The "Max" Calculation (Inside the Loop)

For a specific state :

  1. Identify all empty spots (possible actions )

  2. For each action :

  • Call the physics function (Module 3)

  • Get the list of futures:

  • Calculate the Q-value:

  1. Find the best action:

  2. Update the dictionary:

Step 3: Check Convergence

  • Did any value in the dictionary change by more than ?

    • Yes: repeat the loop

    • No: done. Tic-tac-toe is solved.


The Final Product: The Optimal Policy

Once the loop finishes, we have a dictionary filled with numbers.

  • might be roughly 60 (meaning "we can probably win")

  • might be (meaning "we are almost doomed")

How to play:

  1. Look at the real board

  2. Look at every possible move

  3. For each move, peek into the future using the physics to see the resulting

  4. Check for those futures

  5. Pick the move that leads to the highest value

model based vs model free

if the agent knows the rewards and transition probabilities then it is model based else it is model free. I always get confused in this.

one good example is Atari games. if we only give it the screenshots then it is model free but if we give it the source code of what exactly would happen if it would press the up button then it is model based

sometimes the ps matrix gets too large to fit in computer ram in those cases also we consider model free approaches

montie carlo

The Update Rule

The incremental Monte Carlo (MC) prediction rule is:

This moves the value estimate toward the observed return , where is a step size (often to compute a running average).

Episode 1: Every-Visit MC Updates

Initial state:

,

Episode trajectory:

Returns:

note : these are G not R.

we visited 5 states but got only 4 rewards why?

time (t) | state (S_t) | return (G_t) | notes t = 1 | S_1 | G_1 = -4 | t = 2 | S_2 | G_2 = -3 | first visit to S_2 t = 3 | S_3 | G_3 = -2 | t = 4 | S_2 | G_4 = -1 | second visit to S_2

here is the breakdown of your specific trajectory (): start at S_1 (you haven't done anything yet, so no reward yet). move : you get reward 1. move : you get reward 2. move : you get reward 3. move : you get reward 4.

The sample-average version uses after incrementing the counter:

Backward update loop:

  • State (from ):

  • State (from ):

  • State (from ):

  • State (from ):

After episode 1:

Are These Values Optimal?

No. These are estimates of the value function for the policy being followed, i.e., , not the optimal value function .

Monte Carlo policy evaluation answers: "How good is my current strategy on average?" because it only averages returns generated while following .

How to Get Optimal Values (MC Control, GPI)

To get (or more commonly in model-free control), Monte Carlo must be combined with policy improvement inside the Generalized Policy Iteration (GPI) loop: evaluate the current policy, then improve it, then repeat.

Policy improvement is done by moving the policy toward a greedy one with respect to the current value estimates. In practice, this usually means using an -greedy policy with respect to to keep exploring.

but you told that in model free we do not get rewards!

no! we do get rewards, but from the environment directly the agent does not have the source code

TD Learning

TD(0) Learning

Update Rule:

MC Target (): (sum of all actual future rewards)

TD Target: (actual reward for next step + estimated value of landing state)

Example Episode

Episode: (terminal)

Rewards: -1, -1, -1, -1, 0

Parameters: ,

Initial state:

Step-by-Step Updates

Step 1: Agent in , moves to

  • Reward: -1

  • Current estimate:

  • TD target:

  • Update:

  • Note: In MC, nothing would be updated yet!

Step 2: Agent in , moves to

  • Reward: -1

  • TD target:

  • Update:

Step 3: Agent in , moves to

  • Reward: -1

  • Current estimate: (from previous step!)

  • TD target:

  • Update:

Step 4: Agent in (again), moves to (terminal)

  • Reward: -1

  • TD target:

  • Update:


2-Step TD Update

Initial state:

Time t=1: Agent in , takes action, receives (, )

  • Cannot perform 2-step update yet (need to see )

Time t=2: Agent in , takes action, receives (, )

  • Now can perform 2-step update for (state at t=1)

  • (reward )

  • (reward )

  • ,

  • 2-step return:

  • Update:

Time t=3: Agent in , takes action, receives (, )

  • Now can perform 2-step update for (state at t=2)

  • (reward )

  • (reward )

  • (terminal state)

  • 2-step return:

  • Update:

End of episode: Episode over, no more 2-step updates

Final V-table:

  • (never target of 2-step update)

The 2-step update is less biased than 1-step: it correctly learned that is worse than because it's further from the goal.


n-Step Returns

Since for terminal states:

Key Insight: The "infinity-step" return is just the Monte Carlo return! TD(0) and MC are two extremes of the same spectrum of n-step returns.


TD(λ) - Weighted Average

Example with :

  • Weight for 1-step:

  • Weight for 2-step:

  • Weight for 3-step:

  • ...and so on

The -return is an exponentially decaying average of n-step returns. It says: "I mostly trust short-term returns (1-step, 2-step), but give a little weight to long-term returns in case they have useful information."

But computing this requires the whole episode (like MC). To avoid that, we use the backward view with eligibility traces.


Eligibility Traces (Backward View)

TD(λ) Backward View Update Formulas:

(TD error)

(eligibility trace update)

(value update for all states)

Initial state:

(eligibility traces)

Time t=1: Agent at S₀, moves to S₁

  • Trace decay: All traces decay by (still zeros)

  • Trace increment: Visiting , so

  • TD error:

  • Update all states:

  • ,

After step 1: ,

Time t=2: Agent at S₁, moves to S₂ (terminal)

  • Trace decay:

  • Trace increment: Visiting , so

  • TD error:

  • Update all states:

Final V-table after one episode:

, ,


Intuition: Credit Flow

At time , the agent is surprised:

This "surprise" needs to propagate backward to update past states.

Eligibility trace : Tracks "how responsible" state is for the current situation.

  • When we visit state :

  • At every step, all eligibility decay:

Update rule: When surprise happens at time , update every state according to its eligibility:

Q learning

Why V-Values Need a Model

So far, we've only learned how to evaluate a strategy. But to find the best policy using V-values, you need a model of the environment.

You have to look at your neighboring states and ask: "If I take action 'right', what's the probability I land in that high-value state?" Without the transition probability matrix , you're stuck.

The Hallway Problem

Imagine you're a robot standing in a hallway . There are two doors in front of you: Door 1 and Door 2.

You have a perfect V-table:

  • (delicious cake)

  • (scary monster)

The Decision:

You want to act greedily—you want to go to the kitchen. Which door do you open?

You don't know.

Knowing that the kitchen is valuable is useless unless you know which action connects the hallway to the kitchen.

  • Does Door 1 → kitchen?

  • Does Door 2 → kitchen?

You need the transition matrix to tell you:

Without that model, having V-values is like having a map of treasure but no compass. You know where you want to be, but not how to move there.

The Q-Value Solution (Model-Free Control)

Now imagine you have a Q-table instead:

The Decision:

Which door do you open? Door 1.

You don't need to know where it leads. You don't need to know it leads to the kitchen. You just need to know that opening Door 1 is worth 100 points.

  • V-values: Require a model to convert state-values into actions

  • Q-values: Do not require a model—the value is attached directly to the action


Q-Learning Update Rule

Let's break down the target. It's almost identical to the TD(0) target, but with one crucial difference.

TD(0) Target

(immediate reward) + (gamma × the value of the state you landed in)

Q-Learning Target

(immediate reward) + (gamma × the value of the best possible action you can take from where you landed)


The Q-Learning Algorithm

Initialize

Create a Q-table (dictionary or matrix) with for every state-action pair.

Loop for Many Episodes

  1. Start in state

  2. Loop for each step of the episode:

  • Choose action: Select action from state using ε-greedy policy

  • Take action: Execute , observe reward and next state

  • Update: Apply the Q-learning update rule

    • Find best Q-value for next state:

    • Calculate TD target:

    • Update Q-value:

  • Move: Update state

  • If is terminal, end episode


SARSA(λ) Algorithm

At each time , the agent does the following:

  1. Take action , observe and

  2. Choose next action from using ε-greedy policy

  3. Calculate 1-step TD error:

  4. Decay all traces:

  5. Increment trace for action just taken:

  6. Update every Q-value:

Value Estimation

The Problem: Dimensionality

In tabular RL, we assumed we could maintain a uniquely addressable memory cell for every state .

v[s] ← ...

This works for tic-tac-toe ().

This fails for a robotic arm with 7 joints, where each joint angle is a continuous number:

Even if we discretize the angles, if the state space is defined by variables, the number of states grows exponentially with . This is the curse of dimensionality. We cannot store the value; we must estimate it.

Module 2: Parameterization

We replace the lookup table with a function approximator .

  • : the input state (vector)

  • : a vector of weights (parameters)

  • : a differentiable function (e.g., linear combination, neural network)

Module 3: The Objective Function (Minimizing Error)

In supervised learning, we minimize the error between a prediction and a known label. In RL, we minimize the error between our approximate value and the true value .

We define the mean squared value error :

  • : the true value of state (the oracle's answer)

  • : our current estimate given weights

  • : the state distribution. This tells us how often we visit state . We care more about minimizing error in states we visit frequently than in states we never see.

Goal: Find the weight vector that minimizes this error.

Module 4: Stochastic Gradient Descent (SGD)

Since we cannot know the true for all states, we cannot solve this analytically. We use gradient descent.

We want to move in the direction that reduces the error. The gradient of the squared error with respect to weights is:

is the gradient vector of the function approximator. It tells us: "If I increase weight , how much does the value prediction for state increase?"

Module 5: The "Target" Substitution

There is a problem in the equation above: we do not know the true value .

This is where your previous knowledge comes in. We substitute with the target provided by our RL algorithms (MC or TD).

Case A: Monte Carlo Function Approximation

Substitute (the actual return) for .

Case B: Temporal-Difference (TD) Function Approximation (Semi-Gradient)

Substitute for .

The Algorithm

  1. Initialize weights arbitrarily (usually random small numbers)

  2. Loop for each episode:

  • Initialize

  • Loop for each step of the episode:

    1. Act: Choose action according to policy (e.g., random or greedy)

    2. Observe: Take action , observe reward and next state

    3. Forward pass (prediction): Feed into the network to get

    4. Forward pass (target): Feed into the network to get

    Crucial: We do not calculate gradients for this pass. We treat this value as a fixed number (a constant).

    1. Calculate TD target: (if is terminal, )

    2. Calculate TD error (delta):

    3. Backpropagation (the gradient step): Calculate the gradient

    4. Update weights:

    5. Transition:

    6. If is terminal, break loop

Extension to Q-Learning: How to Handle Actions?

Question: This can only be used for policy evaluation right? For policy control we will have to replace by but how will we differentiate between and as they are both inputs to neural networks?

Architecture 1: The "Naive" Way (State + Action In)

This fits your mental model. We treat the state and the action as two inputs combined together.

  • Input: Concatenate the state vector and the action vector (e.g., one-hot encoded).

  • The network: Processes them together

  • Output: A single number:

Architecture 2: The "DQN" Way (Only State In)

This is the industry standard for discrete actions (like Atari, grid world, etc).

  • Input: Only the state

  • The network: A "brain" that processes the situation

  • Output: A vector of values, one for each possible action Output node 0: Output node 1: ...

The Benefit:

  • You run the network once

  • To act: you just take

  • To calculate target: you just take

The Modified Algorithm for Control (DQN)

Here is how the update logic works with Architecture 2.

Forward Pass (Prediction):

Feed into the network.

Output:

Select: Since we actually took action 2 (), our "prediction" is specifically .

Forward Pass (Target):

Feed into the network.

Output:

Select max: We want the best future.

The Loss Calculation:

Stabel DQN

Problem 1: Non-IID Data (The Correlation Problem)

The Assumption: Neural networks assume data is i.i.d. (independent and identically distributed).

In supervised learning (e.g., cats vs dogs), the order of images is random. Picture 1 (cat) has nothing to do with picture 2 (dog).

The RL Reality: RL data is sequential.

  • State is almost identical to

  • If the robot is in the kitchen, the next 100 frames are all in the kitchen

The Crash:

If you train the network on the live stream of data:

  1. The robot is in the kitchen. It adjusts all its weights to maximize rewards in the kitchen

  2. In doing so, it overwrites the weights that knew how to navigate the living room

  3. It enters the living room, fails immediately (catastrophic forgetting), and spirals out of control

The Hero: Experience Replay (The Memory)

We stop the agent from learning from "right now." Instead, we force it to learn from "memories."

The Component: The Replay Buffer

  • This is a massive circular list (usually size 1,000,000)

  • It stores "experiences" or "transitions":

The Logic:

  1. Collect: As the agent plays, we do not train. We just push tuples into the buffer

  2. Sample: When we are ready to train (e.g., every step), we pause. We reach into the buffer and grab a random batch (e.g., 32 scenarios)

  • Sample 1: from 5 minutes ago (kitchen)

  • Sample 2: from 2 hours ago (bathroom)

  • Sample 3: from 10 seconds ago (garden)

  1. Train: We calculate the loss on this randomized batch

Problem 2: The Moving Target

The Assumption: Neural networks assume the target (the label) is fixed.

In supervised learning: this image is a cat. That label will never change.

The RL Reality: The target is self-generated.

Recall the Q-learning target:

Notice that the weights are inside the target calculation!

The Crash:

  1. The network thinks should be higher

  2. Gradient descent increases the weights

  3. Side effect: Increasing also increases (because and look similar)

  4. Result: The target moves up!

The Loop: The network takes a step toward the target, but the target takes a step away. The dog chases its tail forever. The values spiral to infinity.

The Hero: Target Networks (The Anchor)

We split the brain into two parts.

  • This is the actor. It selects actions

  • It is updated every single step

  • This is a clone of the main network

  • It is frozen. It is not updated every step

  • It is used only to calculate the target number

The Logic:

We modify the loss function to use the frozen weights for the future guess:

The Sync:

  • Step 1 to 9,999: We update (main) constantly. (target) stays stone cold. The target stays fixed. The network can finally converge to it

  • Step 10,000: Hard update. We copy the weights from main to target: . The target jumps to the new, better location, and freezes again

Data Collection: How the Main Network is Used

Phase 1: The "Warm-Up" (Filling the Buffer)

When you first start the script, the replay buffer is empty. You cannot sample a batch of 32 if the buffer has 0 items.

  • Logic: We usually run the agent for 1,000 to 10,000 steps without training at all

  • Network: We use the main network (or pure random actions) to generate these steps

  • Goal: Just fill the tank with diverse data so the first training step isn't biased towards the start state

Phase 2: The "Steady State" (Interleaved)

Once the buffer is full enough (e.g., items), we enter the main loop.

The standard DQN implementation (like the one DeepMind used for Atari) actually does not do "many steps" in a row before training. It usually follows a 1-to-1 or 4-to-1 ratio.

  1. Step 1: main net acts store in buffer

  2. Step 2: main net acts store in buffer

  3. Step 3: main net acts store in buffer

  4. Step 4: main net acts store in buffer

  5. Train: sample one batch from buffer update main net weights one time

Why don't we do 1,000 steps then 1,000 training updates?

If you run the main network for 1,000 steps without updating it, you are collecting data using an old, stale policy. You want the agent to learn from its improving behavior as fast as possible.

Reinforce

Why REINFORCE? The Continuous Action Problem

DQN is great for Atari (joystick: up, down, left, right).

DQN is impossible for a physical robot arm.

The Problem:

A robot arm has 7 motors. Each motor takes a continuous voltage between -1.0 and +1.0.

Action space: a vector of 7 continuous numbers.

Total actions: infinite.

In DQN, to pick an action, we do argmax(Q(s, a)).

You cannot calculate the max of a function over infinite inputs efficiently. You can't check every possible voltage combination.

The Solution:

Instead of learning "how good is this specific voltage?", we act like a human. We learn a probability distribution.

  • Input: state (camera feed)

  • Output: "mean: 0.5 volts, standard deviation: 0.1"

  • Action: sample from that distribution

The REINFORCE Loop:

  1. Initialize policy network arbitrarily

  2. Loop forever:

  • Generate episode: run the current policy until the game ends. Store the history:

  • Calculate returns: go backwards from the end. Calculate for every step:

  • Update weights: for every step in the episode:

Calculate the "direction":

Update:

  • Discard episode: throw away the data (this is on-policy; we can't reuse old data because the probabilities change when changes)

What is ?

Discrete Example: Rock, Paper, Scissors

  1. The network output (the distribution) The neural network takes the state as input and outputs a softmax probability distribution over the 3 actions.Output: [rock: 0.1, paper: 0.7, scissors: 0.2]

  2. The action ()The agent samples from this distribution. Let's say, by chance, it picked rock.Action index: 0.

  3. The probability We look at the probability the network assigned to the action we actually took. We picked rock. The probability of rock was 0.1. Therefore:

  4. The logWe simply take the natural logarithm (ln) of that number.

Continuous Example: Gaussian Policy (Robot Force)

  1. The network output (the parameters)Input: state (robot sees a target).Network output:
  • Mean () = 2.0 (the robot thinks it should apply 2.0 newtons of force)

  • Std dev () = 1.0 (it's exploring with some noise)

  1. The action ()The agent samples from this bell curve distribution .Let's say the random sample comes out as action = 2.0 (exactly on the mean).

  2. Calculating the "probability" We plug our action (2.0) into the Gaussian probability density function formula: Plug in , , . The exponent part becomes . The math simplifies to: So, the single number is 0.3989. This number represents the "likelihood" of picking 2.0 given that specific curve. Likelihood of 2.0: 0.3989 (high, because it's the center).

  3. The log probJust like in the discrete case, we take the log of this number.

Reinforce Proof

In our study of reinforcement learning, we began with Value-Based Methods (like Q-Learning). The goal was to solve a prediction problem: "What is the expected future reward from this state/action?" We framed this as minimizing a loss function, typically the Mean Squared Error between our prediction and a target.

Minimize Loss: (V_target − V_prediction)²

We now shift to a fundamentally different approach: Policy-Based Methods. Here, we directly parameterize the policy itself with a neural network, π(a|s;θ). We do not have a "target policy" to match. Our goal is simply to find the weights θ that produce the highest possible score.


Chapter 1: The Foundation - The Policy Gradient Theorem (REINFORCE)

1.1 The Objective Function

Let be the objective function we want to maximize. It represents the total expected reward for a policy with weights .

Here, represents a single trajectory (or episode), which is a sequence of states and actions: . The notation means "the average score, averaged over all possible trajectories that our policy might generate."

1.2 The Goal: Gradient Ascent

To maximize , we must calculate its gradient with respect to the weights, , and take a small step in that direction.

The central challenge is calculating this gradient.

1.3 Derivation of the Policy Gradient

Step 1: Express the Expectation as a Sum

The expectation is the sum of the reward for each possible trajectory, weighted by the probability of that trajectory occurring. The probability of a trajectory, , is the product of the agent's action probabilities and the environment's transition probabilities (physics).

The objective function can thus be written as:

Step 2: Move the Gradient Inside the Sum

Since the sum is a linear operator, we can move the gradient inside.

Step 3: Apply the Product Rule (and a key insight)

A common point of confusion is why the gradient doesn't apply to the reward term, . The gradient we are calculating is , the rate of change with respect to our policy's weights. The reward function is a property of the environment, not our agent. The rule "you get +1 for winning" is fixed. Therefore, with respect to , is a constant, and its derivative is zero.

Applying the product rule for derivatives :

This simplifies to:

Step 4: The Log-Derivative Trick

This is the core mathematical device that makes policy gradients tractable. Recall from calculus that . Rearranging gives us . Applying this to our gradient:

Substituting this back into our equation:

Step 5: Convert Back to an Expectation

This step can be confusing. Let's be precise. The definition of an expectation is . Here, our "outcome" is a trajectory .

  • The probability of the outcome is .

  • The "value" of that outcome (the random variable we are averaging) is the entire term .

So, the sum above is, by definition, the expectation of that value:

Step 6: Simplify the Log-Probability of a Trajectory

The gradient only affects terms that depend on . Looking at the formula for , only the policy terms depend on . Since , the gradient of the log-probability of the trajectory simplifies to the sum of the gradients of the log-probabilities of the actions:

This gives the Policy Gradient Theorem:

1.4 From Theory to a Practical Algorithm (REINFORCE)

The formula above is still theoretical. We now make two practical simplifications.

Simplification 1: Causality (Using )

The formula weights every action in an episode by the total reward for the whole episode. This doesn't make sense: an action at time t cannot influence rewards that came before it. It can be proven that in expectation, we can replace the total reward (which is ) with the return from that step onward, . This doesn't change the expected gradient but dramatically reduces its variance.

full explanation

the original theorem says: "sum up all the gradients for the whole game, then multiply that total by the total score."

where:

  • is shorthand for

  • is the total reward R(τ)

  1. the expansion (foil method on steroids) if we multiply everything out (every term times every term), we get:

gradient = +

now apply: actions cannot affect past rewards, so terms of the form with k < t have zero expectation.

cross out:

remaining:

gradient ≈

the regrouping (finding ) define return-to-go:

then:

  1. the final formula so we can rewrite:

or in summation notation:

Simplification 2: Stochastic Approximation (From to a single sample)

We cannot average over an infinite number of episodes. Instead, we play one episode and use its result as a noisy but unbiased sample of the gradient. We drop the .

The Final Update Rule and the "On-Policy" Constraint:

This leads to a subtle but important implementation detail. The total update for the episode, , is a step in the direction of this summed gradient:

By the distributive property, we can think of this total update as the sum of contributions from each timestep:

, where .

You are asking: "If I update at step , then changes. When I get to step , isn't the data now 'old' because it was generated by the previous ?"

The answer is Yes, technically you are right.

There are two ways to implement REINFORCE. One is mathematically pure, and one is a "lazy" approximation that works because of small step sizes.

If we follow the derivation strictly, the gradient is the sum over the whole episode.

In a pure implementation, you would do this:

  1. Play Episode.

  2. Initialize total_gradient = 0.

  3. Loop t=0 to T:

  • Calculate gradient for step t: .

  • Add to total: total_gradient += g_t.

  • DO NOT update yet.

  1. After the loop finishes:
  • Update ONCE: .

Why this satisfies the proof:

Because stays constant during the calculation, every single term in the sum is calculated using the exact same policy that generated the data. The "On-Policy" condition is perfectly satisfied.

This is a version very common in practice (e.g., typical SGD implementations).

  1. Loop t=0 to T:
  • Calculate gradient for step t.

  • Update immediately.

Why is this allowed if it violates the math?

It works because of the Learning Rate ().

In RL, is usually very small (e.g., 0.0003).

  • At , we update . The weights change by a tiny amount.

  • At , we use the new weights.

  • The Assumption: Because the change was so tiny, is roughly 99.99% identical to . The error introduced by this slight drift is negligible compared to the noise in the rewards themselves.

Explanation of how summation was removed

we are just moving parentheses

total (end-of-episode) update:

where

example: 3 steps (t = 0,1,2)

incremental (step-by-step) update:

Actor Critic

Welcome to Actor-Critic. This is the architecture that runs the modern world of RL.

You identified the problem with REINFORCE: high variance. is a noisy mess.

The Solution:

Instead of waiting until the end of the episode to see how much reward we got (), let's train a second neural network to predict how much reward we will get.

We replace the actual return (Monte Carlo) with an estimated return (TD learning).

Module 1: The Two Brains

In Actor-Critic, the agent is split into two distinct neural networks (or two heads on one body):

  • Job: Takes the state, outputs action probabilities.

  • Goal: Learn to play the game (policy optimization).

  • Analogy: The athlete. They perform the moves.

  • Job: Takes the state, outputs a scalar value .

  • Goal: Learn to guess the score (value estimation).

  • Analogy: The coach. They watch the athlete and yell, "that was a good move!" or "that was terrible!"

Module 2: The Math (The Advantage Function)

In REINFORCE, the update was:

In Actor-Critic, we don't use . We use the advantage ().

The advantage asks: "How much better was this action than what I usually expect?"

  • The expectation: The critic's current prediction for the state, .

  • The reality: The immediate reward plus the value of the next state: (this is the TD target!).

So the advantage is simply the TD error ():

AtA_tAt (Advantage) is not the same number as GtG_tGt (Return).

You can subtract any value from as long as that value does NOT depend on the action you just took. This value is called a Baseline.

Key idea: Subtracting a baseline does not change the expected policy gradient (the direction the weights move). It only changes the variance (how noisy / shaky the learning signal is).

Policy gradient with a baseline:

If we choose the baseline b(s) to be the value function V(s) (i.e., the expected return from state s):

Then the learning signal becomes:

So, advantage can be written as:

The Updates:

stability issues like in DQN with Actor critic?

REINFORCE (Monte Carlo Policy Gradient)

The Correlation Problem?

Yes, the data is correlated within an episode.

Can we use Experience Replay?

No.

Why: REINFORCE is an on-policy algorithm. The math assumes that the data was generated by the current neural network.

If you use a replay buffer, you are training on data generated by an old version of the network (an old policy). The math breaks down immediately. You cannot use old memories to calculate the gradient for a new policy without complex math corrections (importance sampling).

The Moving Target Problem?

No.

Why: REINFORCE uses the Monte Carlo return () as the target.

  • is the actual sum of rewards calculated at the end of the episode.

  • comes from the environment (ground truth), not from the neural network's own prediction.

Therefore, the target is stable. You do not need a target network for REINFORCE.


Actor-Critic (A2C / A3C)

This is where it gets interesting.

The Correlation Problem?

Yes, data is sequential.

Can we use Experience Replay?

No (usually).

Like REINFORCE, standard Actor-Critic is on-policy. It needs fresh data from the current actor.

Instead of a replay buffer, we make 16 agents play the game at the same time in parallel.

  • Agent 1 is in the kitchen. Agent 2 is in the garden. Agent 3 is jumping...

We collect the data from all 16 and average the update.

Result: The data is decorrelated because the 16 agents are in different places, but the data is still "fresh" (on-policy).

The Moving Target Problem?

Yes.

The actor is safe (no bootstrapping), but the critic is learning values ().

The critic's target is .

comes from the critic itself! The critic is chasing its own tail, just like in DQN.

  • In simple A2C: We often ignore it. Because the updates are smoother than DQN, it sometimes just works without a target network.

  • In advanced Actor-Critic (DDPG, SAC, PPO): Yes, we use target networks. For the critic to be stable in complex games, we absolutely need to freeze the target weights () just like we did in DQN.

PPO

The Problem with Standard Policy Gradients (REINFORCE)

In algorithms like REINFORCE and A2C (standard Actor-Critic), we follow a strict and inefficient cycle:

  1. Collect data with the current policy, .

  2. Perform one gradient update to get a new policy, .

  3. Throw away the data.

The data becomes "stale" immediately because it was generated by an old, obsolete policy. The mathematical justification for Policy Gradients relies on the expectation being taken over samples from the same policy being optimized. This is incredibly inefficient. We spent 2048 steps collecting data, and we only used it for a single update. It's like reading a textbook chapter for one second and then burning the book.

The Goal

We want to reuse the old data to perform multiple updates on our new policy. This requires a mathematical bridge to justify using data sampled from to calculate the gradient for .


2. Importance Sampling: The Mathematical Bridge

We cannot simply plug old data into the new policy's gradient.

  • The Goal (What we want): Maximize the expected reward under the New Policy.

  • The Constraint (What we have): Data (trajectories ) sampled from the Old Policy.

Your Doubt: "I am reading as 'improve the new policy'. What does this mean?"

Resolution:

  • does not mean "improve". It means "Calculate the Average using data generated by the new policy."

  • does not mean "from the old data." It means "Calculate the gradient direction for the old policy weights."

If we naively estimate the gradient using old samples without correction, we are calculating , which is biased and mathematically incorrect for optimizing . It is like driving a Tesla and using data from a Ford Model T to tune it.

Derivation of the Importance Sampling Ratio

To fix this, we use the Importance Sampling Identity:

Let's apply this to our RL objective step-by-step.

Step 1: Write the Goal as a Summation

Step 2: The "Multiply by 1" Trick

Multiply and divide the term inside the sum by the Old Probability . This is valid (algebraic identity):

Step 3: Rearrange terms to match the Old Policy

We want the summation to look like an Expectation over the Old Policy. To do that, we group to the front:

Step 4: Convert back to Expectation

We have solved the mismatch. The expectation is over (matching our data), but the term inside allows us to optimize . The bridge is the fraction , which is the Importance Sampling Ratio.

Simplifying the Ratio (Canceling the Physics)

The ratio looks scary because it involves the probability of the entire trajectory (Agent + Environment).

  • The start state prob cancels out.

  • The environment physics cancel out (since physics don't depend on ).

We are left with just the ratio of the Agent's Policies:

The Surrogate Objective

This leads to the objective function we actually optimize in PPO, using the Advantage instead of raw Reward to reduce variance (proven below):


3. The Policy Gradient Theorem & Advantage

Why Replace Reward with Advantage ?

In the derivation above, we swapped for . Are they mathematically equal? No.

However, replacing with yields the exact same gradient direction while significantly reducing variance. This is due to the Baseline Property.

Proof:

  1. Definition: .

  2. Gradient with Advantage:

  3. Split the terms:

  4. Analyze the second term (The Baseline Term). Since does not depend on action : Using the log-derivative trick (): Since probabilities sum to 1, and the derivative of 1 is 0:

The term cancels out. Therefore, optimizing for Advantage is mathematically equivalent to optimizing for Reward, but with lower variance.

Calculating Advantage (Definition vs. Code)

  • Mathematical Definition: .

  • In Code (Estimation): We don't have . We use the Bellman estimate . This is exactly the TD Error ().



4. Implementing PPO: Algorithm & Memory

The "Old Policy" Dilemma (Do we store 1000 networks?)

To compute the ratio , it looks like we need to keep a copy of the old neural network in memory.

  • Your Question: "But to use this we will have to always store the old neural network and after suppose 1000 policy updates will we be storing 1000 neural networks with us?"

  • The Answer: No. We absolutely do not store 1000 neural networks. We store one old copy, and we update it frequently.

The Conceptual Cycle:

  1. Start: We have our main network, policy_new.

  2. Snapshot: At step 0, we make a copy: policy_old = policy_new.clone(). (Now we have 2 networks in memory).

  3. Data Collection: Play 2048 steps using policy_old.

  4. Training: Train policy_new for 10 epochs. Calculate the ratio using the live network vs the snapshot.

  5. Overwrite: Delete policy_old. Overwrite it with policy_new.

The "Log-Prob" Optimization (The Engineering Trick)

  • Your Insight: "If you like really really see we do not need to store the whole neural net just the pie ( at , s ) values for those 2048 steps."

  • The Optimization: You are absolutely correct. This is the standard optimization used in every professional implementation. We do NOT need to keep a copy of the old network weights in memory.

Since never changes during the training phase (the 10 epochs), its output for the specific states and actions we collected is constant.

The Optimized Algorithm:

  1. Rollout (Data Collection):
  • Run the current network (policy).

  • It outputs an action and a probability calculation.

  • We save the number log_prob_old into our data buffer.

  • Crucial: We detach this number from the computation graph. It is just a float (e.g., 0.693).

  1. Training Loop:
  • We load the batch: states, actions, and the saved numbers log_probs_old.

  • We run the current network (policy) on states to get log_probs_new.

  • We calculate the ratio: ratio = exp(log_probs_new - log_probs_old).

  1. Result:
  • log_probs_new has a gradient. log_probs_old is just a constant number.

  • Memory Cost: We store 2048 floating-point numbers instead of duplicating a 10-Gigabyte Neural Network.


Throwing Away Data (The On-Policy Constraint)

  • Your Question: "But this means we are throwing away those 2048 examples? If we are deleting the old policy we will never be able to use those examples again?"

  • The Answer: YES. You are absolutely correct. We throw them away.

Once we have squeezed the juice out of those 2048 examples (by training on them for roughly 10 epochs), we delete them forever. This is exactly why PPO is still considered an On-Policy algorithm (or "Near On-Policy"), whereas algorithms like DQN and SAC are Off-Policy.

The Logic for Deletion:

  1. The Limits of Importance Sampling: The math trick () is mathematically valid for any two distributions. However, the Variance of this estimate depends heavily on how different the two distributions are.
  • If is close to : The ratio is near 1.0 (e.g., 0.9 or 1.1). The variance is low. The update is safe.

  • If is far from : The ratio becomes wild (e.g., 0.001 or 1000.0). The variance explodes. The gradient becomes garbage.

  1. The Timeline of Decay:
  • Cycle 1: We collect data with Network_Version_1. We train Network_Version_2 on it. The difference is small. Math works.

  • Cycle 2: We create Network_Version_3. If we tried to use the data from Network_Version_1... the difference between Version 3 and Version 1 is now huge. The Trust Region is broken. The math collapses.

  1. The Efficiency Trade-off Table:
Algorithm Data Usage Sample Efficiency Stability
REINFORCE Use once, delete. Very Low Low
PPO Use ~10-80 times, delete. Medium High
DQN / SAC Store in Replay Buffer (1M capacity), reuse forever. High Lower (Harder to tune)

Why PPO is popular despite deleting data: It hits the "Sweet Spot." It reuses data enough to be much faster than REINFORCE, but it deletes the data before it becomes "toxic" (too old to be useful), which keeps the training incredibly stable. If you want to keep data forever, you have to leave PPO and study SAC, which uses fancy math to make old data safe again.

but what if the old state is never visited under the new policy

we do not need to visit the state physically to calculate the ratio

data collection (the past):

  • the agent was in state s_123 (a specific observation: image / coordinates).

  • it took action a_123.

  • we saved that exact state tensor s_123 (and action a_123, and usually logπ_old(a_123 | s_123)) into the buffer.

training loop (the present):

  • we take the saved state tensor s_123 and feed it into the current policy network π_new.

  • we compute the probability (or log-probability) of the same stored action a_123 under the new policy: π_new(a_123 | s_123).

ratio (importance sampling):

so the ratio is computed purely from logged (s, a) and policy evaluation


5. Variance Reduction: Generalized Advantage Estimation (GAE)

We need to calculate the input to our Objective Function: The Advantage ().

We have a Critic network that gives us . But we don't have . We have to estimate it using the rewards we collected.

The Problem of Estimation

We have two bad options:

Option A: The Monte Carlo Estimate We use the actual full return as our estimate for .

  • Pros: Unbiased. It uses real reality.

  • Cons: High Variance. If the game is long/random, bounces around wildly. The training will be unstable.

Option B: The TD(0) Estimate We use the one-step lookahead.

  • Pros: Low Variance. Very stable.

  • Cons: High Bias. It relies heavily on , which is just a guess made by the Critic. If the Critic is dumb (early in training), this estimate is garbage.

The Solution: We need the TD() slider we discussed earlier. We want to mix these two.

Sparse Reward Problem

in text generation, rewards are often sparse/delayed: many steps get 0 reward, and a final outcome (e.g., at ) provides most of the signal. [web:275]

example trajectory (token-by-token): step 1: "The" (reward: 0) step 2: "cat" (reward: 0) step 3: "sat" (reward: 0) ... step 20: "" (reward: +10)

why 1-step advantage can fail here if we use a simple 1-step TD-style advantage:

at step 1 ("The"):

  • immediate reward = 0

  • so the advantage becomes:

this relies entirely on the critic/value function V(·) to predict long-term reward from very early states, via bootstrapping.

if the critic is weak early on (often ~0 everywhere at the start), then: V("The") ≈ 0 and V("The cat") ≈ 0 => ≈ 0

result: the actor gets ~no learning signal for the early token "The" (credit assignment is difficult when rewards are sparse/delayed).


The Magic of the TD Error ()

Let's define the TD Error for a single step. This is the difference between "What happened + What I expect next" and "What I expected now."

Now, watch what happens if we sum up these errors over time.

The 1-Step Advantage: (This is just Option B above).

The 2-Step Advantage: What if we add the next error () to the current one? Let's expand this to prove a point: Notice the terms cancel out! This is exactly the 2-step return minus the value!

The k-Step Advantage: If we sum errors, the intermediate Value predictions cancel out telescopically, and we get the k-step return.


The GAE Formula

Just like in TD(), we don't want to pick a specific "k". We want an exponentially weighted average of ALL of them. We introduce the parameter (Lambda).

  • High : Trust the real rewards (Monte Carlo).

  • Low : Trust the Critic (TD).

The Generalized Advantage Estimator is defined as the sum of discounted TD errors:

geometric series identity (for |λ| < 1):

gae as an exponentially-weighted mixture: A_GAE = (1 − λ) [ A^(1) + λ A^(2) + λ^2 A^(3) + … ]


Recursive Calculation (The Backwards Loop)

We do not calculate that infinite sum for every step. That would be . We can calculate it in Reverse in .

Look at the relationship between step and step :

So the recursive formula is:

Your Doubt: "If , where do we get from? We start from , so we need , but we don't have it."

The Solution: This is exactly why we loop backwards.

Let's trace it on a short episode of 3 steps ().

Data We Have:

  • . (Calculated from rewards and values).

Goal:

  • Calculate .

Step 1: Start at the End () The episode ends after step 2. What is the "Future Advantage" ()? It is 0. There is no future. So, for the last step: Now we have .

Step 2: Step Back () We need . The formula requires . We just calculated in the previous step! Now we have .

Step 3: Step Back () We need . The formula requires . We just calculated . Now we have . We are done.

6. Continuous Control: Gaussian Heads

In Atari games (DQN/A2C), the output is a Softmax over discrete buttons (Left, Right, Jump). In Robotics (MuJoCo, PyBullet), the action is a Vector of Continuous Numbers (Torque, Voltage, Velocity). We cannot use Softmax. We must use a Probability Distribution Function (PDF).

The Gaussian Policy

We assume that for any state , the optimal action follows a Gaussian (Normal) Distribution:

Our Neural Network (Actor) needs to output two things for every motor joint:

  1. Mean (): The "ideal" action (The center of the bell curve).

  2. Standard Deviation (, or "Scale"): How "unsure" or "random" we should be (The width of the bell curve).

The Architecture:

  • Input: State Vector (e.g., Robot Joint Angles).

  • Hidden Layers: Dense layers with ReLU.

  • Output Head 1: A linear layer outputting Mean ().

  • Output Head 2: A linear layer outputting Log-Std ().


Why log_std instead of std? (The Optimization Dynamics)

We need to enforce the constraint that Standard Deviation must be positive (). Why don't we just use abs(output) or ReLU(output)?

  1. The Gradient Scale Problem
  • Option A: Absolute Value () If the network outputs , and we need to change from (High Noise) to (High Precision): The network weights must push the output linearly from down to . This requires a massive change in weights relative to the target precision.

  • Option B: Log Space () If the network outputs , and we need to change from to :

    • To get , output .

    • To get , output .

    • The Benefit: The neural network can move across massive orders of magnitude (from huge noise to tiny noise) just by moving the output linearly from to . This is much easier for an optimizer to handle.

  1. The Zero-Crossing Problem
  • The Trap of abs(x): Imagine the network outputs , so . The agent realizes it needs less noise. It pushes toward 0. If it pushes too far (e.g., from -0.1 to +0.1), the goes from . The noise collapsed to zero and then bounced back up.

  • The Stability of exp(x): can range from to . This entire range maps to a valid, strictly positive . There is no "boundary" at zero. You can keep decreasing forever to get smaller and smaller without ever hitting a wall or bouncing back.


State-Dependent vs. State-Independent Noise

We need to decide how to generate the .

Option A: State-Dependent (The Network Output) In this setup, the Neural Network takes the State as input and outputs both and .

  • Meaning: The agent can choose to be precise () in some states and random () in others.

Option B: State-Independent (The Parameter) In this setup, the Neural Network takes the State and outputs only . The is not calculated by the network layers. It is a separate list of trainable numbers (a tensor) that stands alone.

  • Math:

  • Meaning: The agent has a fixed "randomness level" for every state.

Your Doubt: "The optimizer updates this directly? How?" The Explanation:

  1. Define Parameter: We create a variable log_sigma_param = 0.0. We tell the optimizer: "Please optimize this number."

  2. Forward Pass: Network predicts . We grab log_sigma_param. We calculate probability: log_prob = Gaussian(mu, exp(log_sigma_param)).log_prob(action).

  3. Backward Pass: When we call loss.backward(), PyTorch sees that log_sigma_param was used in the math. It calculates the derivative and updates the number directly, just like a bias term in a neuron.


The Entropy Tug-of-War (Auto-Tuning Exploration)

How does the agent decide whether to increase or decrease this noise parameter? It is determined by two forces fighting in the Loss Function:

Force 1: The Policy Loss (Exploitation)

  • If we found a winning action (), we want to maximize its probability density.

  • In a Gaussian, how do you make the peak higher? You make the bell curve skinnier.

  • Result: Maximizing probability pushes .

Force 2: The Entropy Bonus (Exploration)

  • We subtract . To minimize this, we must maximize .

  • Result: This force constantly pushes . It wants the agent to be as random as possible.

The Resulting Behavior:

  • Success: If the agent gets huge rewards ( is big), Force 1 becomes massive ("I found gold! Be precise!"). It overpowers Force 2. shrinks.

  • Failure: If the agent gets no rewards (), Force 1 is weak ("I don't know what I'm doing"). Force 2 is still there, pushing constantly. It overpowers Force 1. grows.

So, when the agent "fails" (doesn't find a strong signal), the Entropy Bonus takes over and inflates the noise to help it search.


Calculating Log-Probabilities

In Discrete PPO, the network outputs [0.1, 0.8, 0.1]. If we took action 2, the probability is just the number 0.8. In Continuous PPO, we don't have a list. We have the formula for the Gaussian curve. We need to calculate the Probability Density of the specific action value that we sampled.

The Gaussian Formula:

The Log-Prob Formula:

In PyTorch: You do not need to type this formula.

  1. You give PyTorch the and from your network.

  2. You give PyTorch the specific action you took.

  3. PyTorch plugs , , and into the equation above and returns the number.

7. The Loss Function & Updates

The Combined Loss Equation

We define a single scalar number that represents everything we want the network to achieve: (Note: We minimize this total loss).


Adding Losses (The "Illegal" Math)

Your Doubt: "I never understood the maths of this. How can you add losses and then propagate gradients? Mathematically aren't you supposed to do them individually and separately?"

The Answer: This relies on the Linearity of Differentiation. It is not a hack; it is valid calculus.

Scenario: Imagine we have two completely separate neural networks:

  1. Actor Network (Parameters ): Produces loss .

  2. Critic Network (Parameters ): Produces loss .

We define a combined loss: .

When we run L_total.backward(), we want PyTorch to calculate the gradients for both and . Let's solve for them manually using partial derivatives.

  1. The Actor Gradient () Using the Sum Rule: Here is the key: Does the Critic's loss depend on the Actor's weights? No. They are separate networks. Therefore, . Conclusion: Differentiating the Sum with respect to gives exactly the same result as differentiating only the Actor Loss.

  2. The Shared Weights Case (The Multi-Head Body) In many implementations, the Actor and Critic share the first few layers (the "Body") to process the image (), and then split into two "Heads." This is exactly what we want. The gradients from both objectives simply add up (accumulate) at the shared weights. The weights are pushed in a direction that satisfies both tasks simultaneously.


Batching: How One Number Updates 64 Items

Your Doubt: "We sum the loss for 64 items and do a single backprop. How does that work?"

The Math: Derivative of an Average Let's say we have a batch of 3 items with losses . The Total Batch Loss is the average:

When we call backward(), we calculate the derivative:

The Magic: The Gradient of the Average is the Average of the Gradients. By backpropagating from that single summed number, PyTorch automatically calculates the individual gradient for Sample 1, Sample 2, and Sample 3, and adds them all up inside the weight's .grad attribute.

The Intuition: The "Tug of War" (Compromise) Imagine a single weight in the network.

  • Sample 1 says: "To predict correctly for me, this weight needs to go UP (+1.0)."

  • Sample 2 says: "To predict correctly for me, this weight needs to go DOWN (-0.5)."

  • Sample 3 says: "I don't care, this weight doesn't affect me (0.0)."

When we do the single backprop on the average, we get:

The Update: The weight moves up slightly.

  • This makes Sample 1 happier.

  • This makes Sample 2 slightly unhappier.

  • But on average, the total error of the batch decreases. The network finds a compromise.


Batching vs. Sequential Updates

Your Doubt: "Is averaging the loss for 64 items same as doing 64 sequential updates?"

The Answer: NO. They are mathematically different.

  1. The Sequential Way (True SGD)

  2. Calculate gradient for Sample 1 using weights . Update weights to .

  3. Calculate gradient for Sample 2 using new weights .

  4. Update weights to .

  5. The Batch Way (PyTorch Default)

  6. Calculate gradient for Sample 1 using weights .

  7. Calculate gradient for Sample 2 using weights (NOT . The weights are "stale").

  8. Sum them up and update once.

Why we use Method 2 (Batching) despite the error:

Reason 1: The "Drunk Walk" (Stability) Sequential updates are incredibly noisy.

  • Sample 1 says "Go Left". You go Left.

  • Sample 2 says "Go Right". You go Right. The weights jitter around wildly. This "drunk walk" makes convergence hard. By averaging 64 samples, the noise cancels out, and the update step moves smoothly in the true downhill direction.

Reason 2: GPU Speed (The Engineering Reality) This is 99% of the reason.

  • Sequential: You have to do the math Update -> Write -> Read -> Update 64 times. This is serial processing.

  • Batch: You stack the 64 items into a matrix. You do one massive matrix multiplication. The GPU calculates all 64 gradients in parallel instantly.

  • Result: Batching is roughly 50x to 100x faster.

Reason 3: The Approximation In Deep Learning, the Learning Rate is usually very small (e.g., 0.0003). Because is tiny, is almost identical to . Therefore, the gradient at is almost identical to the gradient at . The error introduced by batching is negligible.

8. PPO Update Logic & Engineering Details

The Actor Update (Trust Region via "Internal Ratio Clipping")

Our theoretical goal is to constrain the KL Divergence . Calculating KL is computationally expensive. PPO approximates this constraint by Clipping the Probability Ratio. This is often called "Internal Clipping" because it happens inside the mathematical definition of the Loss Function itself.

The Probability Ratio (): First, we calculate how much the policy has changed for a specific action:

The Objective Function:

Let's trace the logic for a Good Action (). We want to increase the probability ().

  1. Scenario A: Small Change (Safe). The ratio moves from 1.0 to 1.1. This is inside the safe zone [0.8, 1.2] (assuming ).
  • The clip function does nothing.

  • The min operator selects the first term ().

  • Result: The gradient flows normally. The optimizer pushes the weights to increase the probability further.

  1. Scenario B: Huge Change (Dangerous / Clipped). The optimizer tries to be aggressive. It changes the weights so that is much higher than , pushing the ratio to 1.5.
  • The clip function activates. It truncates the ratio to the limit: 1.2.

  • The min operator sees two values: and . It chooses the smaller one: .

  • The Magic: To the optimizer (differentiation engine), the term looks like a constant. The derivative of a constant is 0.

  • Result: The gradient becomes zero. The update stops for that specific sample. This "Internal Clipping" acts as a logical gate that shuts off learning if the policy strays too far.


The Critic Update (Clipped Value Loss)

This is a detail often missed in basic tutorials. Just like the Actor, we don't want the Critic to change too fast, because a jumping Critic destabilizes the Advantage estimate for the Actor.

Definitions:

  • : The value predicted by the network before the training epochs started (frozen).

  • : The current prediction of the network we are training.

The Logic:

  1. Calculate Unclipped Loss: . (Standard MSE).

  2. Calculate Clipped Value: We force the new prediction to stay within of the old prediction.

  3. Calculate Clipped Loss: .

  4. The Final Loss: We take the Maximum of the two errors.

The Update Rule: If the update tries to move too far (outside the bound) to chase a noisy return, the gradient becomes 0 (because looks like a constant). This forces the Critic to learn slowly and stably.


Engineering Tricks (The "Hidden" Code)

You can have the math 100% correct, but without these engineering details, PPO often fails to learn.

  1. Observation Normalization (Running Mean Std)
  • The Problem: In games, pixels are 0-255. In robotics, velocity might be 0-5, but position might be -100 to +100. Neural networks hate unscaled data.

  • The Fix: We calculate a Running Mean and Variance of every state the agent has ever seen. We normalize inputs:

  • Result: The agent sees a "whitened" world where inputs are roughly Mean 0, Variance 1.

  1. Advantage Normalization
  • The Problem: In Level 1, rewards might be +10. In Level 10, rewards might be +1000. This messes up the step size. A "good" advantage of +5 becomes irrelevant later.

  • The Fix: Inside each training batch (e.g., 2048 items), we normalize the Advantages so they form a standard bell curve.

  • Result: Roughly half the actions are considered "Good" () and half are "Bad" (). This keeps the learning signal consistent regardless of the reward scale.

  1. Orthogonal Initialization
  • The Problem: Standard weight initialization (Xavier/Glorot) is designed for image classifiers. In RL, bad initialization leads to vanishing gradients immediately.

  • The Fix: We initialize weights such that the matrix is orthogonal (). This preserves the magnitude of the signal as it passes through deep networks.

  • Critical Detail: For the final output layer of the Actor, we initialize weights to be tiny (0.01). This ensures the initial probabilities are almost perfectly random, preventing the agent from starting with a strong bias (e.g., "Always move Left").

  1. Gradient Clipping (External / Global Clipping)
  • The Distinction: This is NOT the PPO Ratio Clipping we discussed above.

    • PPO Ratio Clipping (Internal): Happens inside the Loss Function math. It sets the gradient to 0 if the policy changes too much.

    • Gradient Clipping (External): Happens after loss.backward() and before optimizer.step().

  • The Problem: Even with PPO Clipping, sometimes the data is weird, and the gradient calculation results in massive numbers that crash the floating-point math (NaNs).

  • The Fix: We clip the Global Norm of the gradient vector.

torch.nn.utils.clip_grad_norm_(agent.parameters(), max_norm=0.5)

  • Meaning: If the gradient vector is too long (length ), we shrink it to length 0.5, keeping the direction the same. This is a safety fuse for the optimizer.er.

RLHF


Phase 1: Supervised Fine-Tuning (SFT)

The Problem: The "Blank Slate" Model

If we start with a raw, randomly initialized neural network and try to apply PPO, the model will fail. It has no concept of language, grammar, or facts. It would generate random, incoherent noise (e.g., "gaga goo goo").

In a simple RL environment like a Grid World, random exploration is sufficient to eventually stumble upon a reward. In the vast space of language, the probability of a random sequence of tokens forming a coherent, reward-worthy sentence is practically zero. The agent would never receive a learning signal.

Therefore, before we can use RL, the model must first learn to speak a human language and follow basic instructions.

The Goal of SFT

The goal is to teach a pre-trained base model (like LLaMA, GPT-3, etc.) to act like a helpful assistant. We want to refine its behavior to be more aligned with the "instruction-following" style we expect from a chatbot. We are essentially cloning the behavior of expert human labelers.

The Data: High-Quality Demonstrations

The dataset for this phase consists of high-quality (Prompt, Response) pairs curated and written by expert humans. This is a critical and expensive part of the process.

  • Example Prompt: "Explain the concept of quantum physics to a five-year-old in simple terms."

  • Example Response (written by a human expert): "Imagine a tiny, tiny ball that can be both red and blue at the same exact time, until you look at it. When you look, it has to choose to be just red or just blue. Isn't that silly?"

The Training Method: Standard Supervised Learning

This phase does not involve any reinforcement learning. It is a standard supervised learning task, identical to how models like GPT are trained.

We use Next Token Prediction with a Cross-Entropy Loss (also known as Negative Log-Likelihood).

The Process:

  1. We take a (Prompt, Response) pair.

  2. We concatenate them into a single sequence.

  3. We feed the sequence into the model one token at a time.

  4. At each step, we train the model to predict the very next token in the sequence.

Example Trace:

  • Input to Model: [<start>, "Explain", "quantum", "physics", ..., "Imagine", "a", "ball", "that", "can", "be"]

  • Model's Task: Predict the probability distribution for the next token.

  • Correct Answer (Target): The token "red".

  • Loss Calculation: The model's loss is the negative logarithm of the probability it assigned to the correct word, "red". We use backpropagation to adjust the weights to make the probability of "red" higher in this context next time.

The Result: The Model

After training on thousands of these demonstrations, we get a model we will call (The Supervised Fine-Tuned Model).

This model is good, but not great.

  • It is proficient: It can follow instructions and generate coherent, grammatically correct text.

  • It is an "Averager": Its responses are a statistical average of the responses it saw in the training data. It may lack creativity, fail to generalize to novel prompts, or produce safe but unhelpful answers.

  • It is the Foundation: This model serves as the crucial starting point for the PPO agent in Phase 3. It also acts as the "Grammarian" or the "Anchor" in the KL Penalty, ensuring our RL agent doesn't forget how to speak English.


Chapter 2: The Reward Model (RM)

The Goal: Learn a Scoring Function

The goal of this phase is to train a model, which we'll call , that takes a (Prompt, Response) pair and outputs a single scalar number representing its quality (e.g., +5.2 for a good answer, -3.1 for a bad one). This model will act as the "Environment" for our PPO agent in the next phase.

The Data Problem: Human Inconsistency

A naive approach would be to ask human labelers to score responses on a scale of 1 to 10. This fails in practice for two reasons:

  1. Noise: What one person considers a "7/10" another might call a "9/10". The scores are not well-calibrated between different people.

  2. Difficulty: It is much harder for a human to assign a consistent, absolute score than it is to make a relative judgment.

The Solution: Pairwise Comparison (Ranking)

Instead of asking "How good is this?", we ask "Which one is better?". Humans are exceptionally good at making relative judgments.

The Data Collection Process:

  1. Take a Prompt: "Write a short story about a friendly robot."

  2. Generate Multiple Responses: Run our SFT model () several times with the same prompt to get different outputs (e.g., Output A, B, C, D).

  3. Human Labeling: Show a human labeler a random pair of these responses (e.g., A and B).

  4. Record the Preference: The human chooses which response is better. The data point we save is a triplet: (prompt, chosen_response, rejected_response).

This creates a high-quality dataset of human preferences.


The Training Math: The Bradley-Terry Model

We now have a dataset of (prompt, winner, loser). We need a loss function that teaches our Reward Model ( ) to assign a higher score to the winner.

The standard approach is based on the Bradley-Terry model, which connects pairwise probabilities to an underlying score.

The Logic: The probability that a human prefers the winning response ( ) over the losing response ( ) is modeled as a sigmoid of the difference in their scores.

  • x is the prompt.

  • is the scalar score our Reward Model gives to a (prompt, response) pair.

  • is the sigmoid function.

Visualizing the Math: Let's trace a single training step to understand how this works.

  1. The Setup: We have a winning response Input A and a losing response Input B. We feed both into the same Reward Model network.

  2. The Scores: The network, currently with random weights, outputs a random scalar score for each.

  • Score(Winner) = 0.5

  • Score(Loser) = 0.8 (This is incorrect; the loser has a higher score).

  1. The Difference: We calculate the difference in scores.
  • Diff = Score(Winner) - Score(Loser) = 0.5 - 0.8 = -0.3.
  1. The Probability: We want this difference to be a large positive number. We feed it into a sigmoid to see what the model currently "believes".
  • P(Winner is better) = sigmoid(-0.3) ≈ 0.42 (42%).
  1. The Loss: We want this probability to be 1.0 (100%). We use the Negative Log-Likelihood as our loss function.
  • Loss = -log(0.42) ≈ 0.86. This is a high error, signaling that the model's prediction was very wrong.
  1. The Update (Backpropagation): The gradient descent process will now adjust the weights of to fix this error. It will simultaneously:
  • Push Up: Nudge the weights to increase the score for the winning response.

  • Pull Down: Nudge the weights to decrease the score for the losing response.

  • The goal is to maximize the gap between the winner's score and the loser's score.

The final loss function we minimize is:

The Result: The Model (The Judge)

After training on hundreds of thousands of human preference pairs, we have a frozen, reliable Reward Model. This model has learned to internalize human preferences. It can now look at a new, unseen response and assign it a high score if it's good (helpful, harmless, well-written) and a low score if it's bad (inaccurate, unsafe, gibberish).

This model is the "Environment" our PPO agent will interact with in the final, most complex phase.


Chapter 3: PPO Optimization (Unabridged & Complete)

The Goal: Maximize the Reward Model's Score

The primary objective is to adjust the weights ( ) of our language model, let's call it , to generate responses that get the highest possible score from our frozen Reward Model, .

The "Per-Token" RL Loop

A standard PPO loop involves a sequence: State -> Action -> Reward -> Next State. To apply this to text generation, we treat the process as a multi-step episode.

  • The Episode: The entire process of writing one response to one prompt.

  • A Timestep ( t ): The generation of a single token (word).

Let's trace the generation for the prompt "Write a poem".

Time t=0:

  • State ( ): The initial prompt tokens: ["Write", "a", "poem"].

  • Action ( ): The Actor network ( ) samples the token "Upon".

  • Reward ( ): We don't get a score yet. The reward is 0.

  • Next State ( ): ["Write", "a", "poem", "Upon"].

...This continues until the model generates an End-of-Sentence <EOS> token.

Final Timestep (e.g., t=20):

  • State ( ): The full poem generated so far.

  • Action ( ): The Actor samples <EOS>.

  • Reward ( ): The episode is now over. We take the complete text and feed it to the Reward Model.

    • = (, ) = +7.5 .

    • This is the only non-zero reward from the Reward Model. The reward sequence is sparse: [0, 0, ..., +7.5].


The Full PPO Loop (LLM Version)

Now, let's look at how all our PPO machinery plugs into this "per-token" view.

  1. The Rollout: We generate a batch of, say, 16 prompts. For each prompt, we do a full rollout, collecting data at each token step:
t State ( S_t ) Action ( A_t ) LogProb (Old) V(S_t) Reward ( R_{total} )
0 ["Write", "poem"] "Roses" -1.2 3.5 -0.002
1 [..., "Roses"] "are" -0.8 3.8 -0.004
2 [..., "are"] "red" -0.9 4.1 -0.001
3 [..., "red"] <EOS> -1.5 4.5 +4.997
  • LogProb (Old): The log probability of the action, calculated from the policy_old (the frozen policy that is generating this data).

  • V(): The Critic's prediction of the final score, given the sentence so far. Notice it goes up as the sentence gets better.

  • Reward ( ): The reward for this token, which is the (usually zero) Reward Model score plus the KL penalty for this step.

  1. The GAE Calculation: We now have a sequence of rewards, for example: [-0.002, -0.004, -0.001, +4.997]. We can run our backwards GAE loop exactly as we learned to calculate the Advantage for each token.
  • Delta for "red" (t=2): .

  • Advantage for "red": .

  • Delta for "are" (t=1): .

  • Advantage for "are": .

The GAE math automatically propagates the final reward backwards to credit the earlier words that led to it.

  1. The PPO Update: Now we have our (State, Action, LogProb_Old, Advantage) tuples for every single token. We feed these into the PPO Loss function and update the network. The network learns: "When the state was [..., 'are'], picking red had a large positive advantage. I should increase its probability."

obviously we are calculating pie new the updating and then again calculating pie new in loop for 1-4 epoch and yes for the first iteration pie new and old would be the same


The Hidden Trap: The "Reward Hack" (Goodhart's Law)

If we let PPO run wild just to maximize the score from , it will find and exploit flaws in our Judge.

  • Scenario: The Reward Model learned an implicit bias: Longer text = Higher score.

  • The Hack: The PPO agent discovers this. It learns to generate rambling, repetitive, nonsensical text because this maximizes its score from the flawed Judge.

  • The Result: The model's output becomes unhelpful to a human, even though it is "winning the game." This is Over-Optimization.


The Solution: The KL Penalty (The "Anchor")

To prevent the agent from straying too far into "alien" text, we must anchor it to the original, human-like distribution of the SFT model. We modify the reward function.

The Per-Token Reward Function:

one doubt I had was how will we calculate this during the rollout phase? because I thought this pie RL is pie RL new no, its pie RL old itself. pie SFT is the OG sft policy we started with


The Four Models in Memory

To execute this complex loop, you actually need four separate models loaded into memory simultaneously, which is why RLHF is so resource-intensive.

  1. The Actor ( ): The main LLM we are actively training with PPO.

  2. The Critic ( ): The value function network that predicts the expected score. Often, this shares the "body" of the Actor model but has a separate linear "head" on top.

  3. The Reward Model ( ): A frozen, separate LLM that acts as the "Judge" and provides the final reward.

  4. The SFT Reference Model ( ): A frozen, separate copy of the original Supervised Fine-Tuned model. This is used for two things:

  • The denominator of the PPO ratio ( ): This is the "Old Policy" that collected the data for the current training batch.

  • The KL Penalty Anchor: This is the pi_SFT in the KL(pi_RL || pi_SFT) calculation.

GRPO

Deep Reinforcement Learning: Group Relative Policy Optimization (GRPO)

Chapter 1: The Motivation (The Memory Wall)

To understand why GRPO exists, we must look at the computational cost of PPO when applied to massive models (70B+ parameters).

The PPO Memory Bottleneck

In the standard PPO-RLHF setup, we need to load four distinct models into GPU memory:

  1. The Actor ( ): The model being trained (e.g., 70B params).
  • Memory Cost: Parameters + Gradients + Optimizer States (Adam).
  1. The Critic ( ): The value function.
  • Memory Cost: Parameters + Gradients + Optimizer States.

  • Crucial Detail: In PPO, the Critic usually needs to be as large as the Actor to effectively understand the nuance of the text. So, another 70B params.

  1. The Reference Model ( ): Frozen copy for KL penalty.

  2. The Reward Model ( R ): Frozen judge.

The Total Cost: The Optimizer States for the Actor and Critic take up massive amounts of VRAM. Having a trainable Critic effectively doubles the training memory requirements compared to just fine-tuning the model.

The GRPO Hypothesis

If we delete the Critic:

  1. We save 50% of the training memory (no Critic weights, no Critic optimizer states).

  2. We remove the complexity of training a Value Function (no more loss).

  3. We remove the need for GAE (Generalized Advantage Estimation).

The Problem: The Critic's job was to provide a Baseline ( V(s) ) to reduce variance ( A = Q - V ). Without V(s) , how do we calculate the Advantage?

The Solution: Instead of learning a neural network to predict the baseline, we can empirically estimate the baseline by sampling a Group of outputs for the same prompt.


Chapter 2: The GRPO Mechanism

GRPO modifies Phase 3 (The Optimization Phase). It changes how we collect data and how we calculate the Advantage.

Step 1: Group Sampling

In PPO, we usually sample one output per prompt. In GRPO, for every prompt query q , we sample a Group of G outputs.

  • G : The group size (e.g., 64).

  • q : The input prompt (e.g., "Solve this math problem").

  • : The i -th generated output text.

Step 2: Scoring

We run the Reward Model on all G outputs to get a scalar reward for each.

Step 3: The Relative Advantage

This is the core innovation. Instead of asking a Critic "How good is compared to the average?", we compare to the other outputs in the group.

We calculate the Mean and Standard Deviation of the rewards within this specific group.

The Advantage for output i is its Z-Score within the group:

Why this works (The "Math Test" Analogy):

  • Prompt: A very hard calculus question.

  • GRPO Approach: The model generates 8 answers. Since the question is hard, all 8 answers are bad. Scores: [0.1, 0.2, 0.1, 0.5, 0.1, 0.2, 0.1, 0.1].

  • The Mean is .

  • That answer with score 0.5? It is terrible objectively, but it is amazing compared to the group.

  • The Advantage for the 0.5 answer becomes huge positive. The model learns: "Even though I failed, this was the best path."

Using the Group Mean as the baseline automatically adjusts for the difficulty of the prompt.


Chapter 3: The Notation and Hierarchy

Before writing the loss function, we must clarify the indices to avoid confusion between "Responses" and "Tokens."

The Hierarchy of Data:

  1. The Prompt ( q ): The input question.

  2. The Group ( i ): We generate G different responses to that one prompt.

  • .

  • represents the complete response.

  1. The Token ( t ): Inside one specific response o_i , there is a sequence of words.
  • .

  • is the t -th token of the i -th response.

Key Definition: The Advantage ( )

  • A_i is a single scalar number calculated for the entire response .

  • Crucial Detail: We broadcast this value. Every single token in sentence i ("The", "answer", "is", "4") gets assigned the same advantage .

Key Definition: The Probability Ratio ( )

  • This is calculated per token.

  • .


Chapter 4: The Objective Function

The GRPO Loss Function (from the DeepSeekMath paper) averages over the Group and sums over the Tokens.

Term A: The Reward Objective (PPO Clip)

  • Logic: This is the standard PPO "Trust Region" logic.

  • Constraint: It ensures the new policy ( ) does not drift too far from the old policy ( ) that generated the data within the current training batch.

Term B: The KL Regularization (Your Doubt)

Your Doubt: "The KL term had to be in the reward, right? What is it doing there in the loss? We are already using clipping."

The Answer:

  1. Placement: In Standard PPO, we put KL in the Reward. In GRPO (DeepSeek), they explicitly put it in the Loss. Mathematically, maximizing Reward - KL is similar to minimizing Loss + KL. However, putting it in the loss allows for per-token precise control without messing up the Group Normalization of the rewards.

  2. Why do we need it if we have Clipping?

  • PPO Clipping (Term A): Constraints pi_new vs pi_old. It ensures Optimization Stability (don't trip while learning). It does not stop long-term drift.

  • KL Regularization (Term B): Compares pi_new vs pi_ref (The SFT Model). It ensures Behavioral Stability (don't forget how to speak English). Even after 1,000 updates, this anchors the model to the original SFT distribution.

We need both. One for the math to work (Clip), one for the language to stay coherent (KL).


Chapter 5: Update Mechanics (Batch vs. Token)

Your Doubt: "Due to the way loss is calculated weights can only be updated once for a full prompt with many responses, right?"

The Answer: Yes. You are correct. Neither PPO nor GRPO updates weights "per token."

1. The Summation Symbols

The symbols in the loss function mean "Sum up the error." They do not mean "Update weights inside the loop."

The Execution Flow:

  1. Loss Calculation: We calculate the GRPO loss for every token in all 64 responses. (e.g., 6,400 individual numbers).

  2. Aggregation: We average them all into One Scalar Loss.

  3. Update: We run loss.backward() and optimizer.step() ONCE for that entire group/batch.

2. Granularity of the Signal (PPO vs. GRPO)

While the update frequency is the same, the signal is different.

  • PPO (Dense Signal): Because of the Critic, Token 5 might have A=+0.8 and Token 6 might have A=-0.2 . The gradient pushes tokens in different directions within the same sentence.

  • GRPO (Sparse Signal): Because we use the Group Outcome, the entire sentence gets one score. If A_i = +2.0 , the gradient pushes every single token in that response UP.

3. Engineering Reality (Gradient Accumulation)

With 70B models, we cannot fit 64 sequences in memory to do the sum at once.

  • Method: We load 1 sequence, calculate gradients, and accumulate them (add to a bucket). We repeat this 64 times. Then we update the weights once using the bucket. This achieves the mathematical equivalent of the batch update.

DPO

The Current State (RLHF via PPO)

Think about the pipeline we just built for PPO. It is an engineering nightmare.

To align a model, we need:

  1. Step 1: Train a Supervised Model ( ).

  2. Step 2: Train a Reward Model ( ) on comparison data (Winner, Loser).

  3. Step 3: Load 4 Models into memory (Actor, Critic, Ref, Reward).

  4. Step 4: Run a complex, unstable loop:

  • Generate text (slow).

  • Estimate Values.

  • Calculate Advantages.

  • Clip gradients.

  • Hope it doesn't crash.

The DPO Insight

The creators of DPO (Rafael Rafailov et al., 2023) looked at Step 2 (Reward Model training).

  • Data: We have pairs (Winner > Loser).

  • Standard Way: Train a Reward Model to understand this data, then use RL to teach the Language Model.

  • DPO Way: Why the middleman? Can we define a loss function that looks at (Winner, Loser) and updates the Language Model directly?

If this works, we can delete the Reward Model. We can delete the Critic. We can delete the PPO loop. We essentially turn RLHF back into a simple Supervised Learning problem.


Chapter 2: The Mathematical Magic Trick

This chapter contains the derivation. It relies on algebra, not calculus.

Step 1: The RLHF Objective

Recall the equation we maximize in PPO (using the KL penalty in the reward):

  • R(x, y) : The true reward for prompt x and response y .

  • : The penalty strength.

  • : The reference SFT model.

Step 2: The "Closed Form" Solution

This is the hardest concept to accept intuitively, but it is a proven mathematical fact.

If you have a specific Reward Function R and a Reference , there is an exact mathematical formula for the Optimal Policy ( ) that maximizes that objective. You don't need gradient descent to find the formula, you can just write it down.

The Optimal Policy is given by:

  • Translation: The perfect policy is just the Reference Policy, scaled up by the exponentiated Reward.

  • Z(x) : This is a "Partition Function." It’s just a normalization constant (a number) to make sure the probabilities sum to 1. It does not depend on the specific response y .

Step 3: The Algebra (The Inversion)

Now, the magic. We have an equation relating the Optimal Policy to the Reward.

Let's do some algebra to rearrange this equation. We want to solve for R.

  1. Take the logarithm of both sides:

  2. Move terms around to isolate R(x,y) :

  3. Simplify the logs ( ):

  4. Multiply by :

What have we done? We have expressed the Reward entirely in terms of the Optimal Policy, the Reference Policy, and a constant Z(x) .

We no longer need a separate Reward Network . The policy itself defines the reward.


Step 4: The Substitution

Now, recall how we trained the Reward Model in Phase 2 (Bradley-Terry Model). We wanted to maximize the likelihood that the Reward of the Winner ( ) is higher than the Reward of the Loser ( ).

Let's plug in our formula for R from Step 3 into this equation.

Look what happens: The term appears in both rewards. Since we are subtracting, it cancels out! We don't need to know Z(x) .

The difference becomes:

Step 5: The DPO Loss Function

We replace the theoretical "Optimal Policy " with our "Trainable Network ".

The DPO Loss is just the standard Bradley-Terry loss, but using this "Implied Reward" difference:

Conclusion of the Derivation:

  • We started with the RLHF objective (Reward - KL).

  • We solved for the optimal policy.

  • We inverted it to define Reward in terms of Policy.

  • We plugged that into the preference ranking loss.

  • Result: A loss function that optimizes the Policy using only the reference model and the data pairs. No Reward Model network required.

This derivation proves that optimizing this loss is mathematically equivalent to optimizing the RLHF objective.

Are you comfortable with this "Inversion" logic? It is the foundation of DPO.

Original Notion page