Skip to content
AI360XpertBeta

Reward Function

The reward function turns each step into one number, and the agent climbs the total. Get that number wrong and the agent learns the wrong job perfectly.

One transition in, one number out, and four steps with three minus ones plus ten sum to a discounted return of 4.58
One transition in, one number out, and four steps with three minus ones plus ten sum to a discounted return of 4.58

Why Does This Exist?

No one tells a reinforcement learning agent which action was correct. It tries, watches the world change, and gets one number back. Without that number there is no learning signal at all, only random wandering through thousands of steps that all look the same.

The reward function is that number. It maps a single transition to a scalar, and everything else in RL is commentary on those scalars. A delivery robot that reaches the charger in 40 steps gets 40 numbers. If the numbers reward arrival and punish dawdling, the robot learns short routes. If they reward wheel speed, it learns to spin in place very fast.

This page covers the mapping itself: what it takes in, what it returns, and how a short chain of rewards adds to a return you can check. The rulebook around it lives in MDP foundations. What those rewards predict over the long run lives in value functions. How to add helpful hints without changing the goal lives in reward shaping.

The one idea you need first is the return. Write the rewards after time tt as Rt+1,Rt+2,…R_{t+1}, R_{t+2}, \dots and pick a discount γ\gamma (gamma) between 0 and 1. The return is Gt=Rt+1+γRt+2+γ2Rt+3+…G_t = R_{t+1} + \gamma R_{t+2} + \gamma^2 R_{t+3} + \dots. Here each RR is one immediate reward and γ\gamma says how much you care about later rewards relative to now. A γ\gamma of 0.9 keeps the future relevant without letting far away steps dominate.

Think of It Like This

A taxi meter that never steers

You ride across town and watch the meter. Each block adds a fixed fare, waiting in traffic subtracts idle time, and a clean on time arrival adds a tip. The meter never touches the wheel. It only converts what just happened into one number, then adds those numbers into a shift total.

That maps part for part. The block is the transition (s,a,s′)(s, a, s^\prime), with ss the corner you left, aa the turn you took, and s′s^\prime the corner you reached. The fare increment is the immediate reward RR. The shift total is the return GG. The driver who chases the meter learns routes that earn, exactly as a policy chases return.

Where it stops: a real meter is honest by construction, while a designed reward can lie. Pay for wheel speed and the meter praises spinning in place. The fix is never a smarter driver. It is a better meter.

How It Actually Works

The general form takes the full transition. With ss the current state, aa the action, and s′s^\prime the next state:

R(s,a,s′)∈RR(s, a, s^\prime) \in \mathbb{R}

In plain words: ss is where you are, aa is what you do, s′s^\prime is where you land, and RR is the single score for that triple. Simpler forms exist. R(s,a)R(s, a) averages over possible landings, and R(s′)R(s^\prime) scores only the landing zone, such as plus 10 inside the goal and minus 1 elsewhere. All three are the same idea with fewer arguments.

The reward hypothesis behind all of RL says every goal can be expressed as maximizing the expected discounted sum of these scalars. That is a strong claim and it explains why reward design feels so high stakes. You do not get to tell the agent to be careful, quick, and gentle in separate channels. You get one number per step, so careful, quick, and gentle must all live inside it.

Sparse versus dense

A sparse reward pays only at the goal, such as plus 1 on arrival and 0 elsewhere. It never lies but it rarely speaks, so random exploration may never find it in a large room. A dense reward speaks every step, such as minus 1 per step plus 10 at the goal. It teaches fast but it can be gamed, because any step signal is a proxy and proxies have loopholes. The practical rule: start with the true sparse goal, then add dense terms you can defend, and test that the fastest way to earn is still the task you wanted.

Worked example

A chain has states s0s_0 to s3s_3 plus a goal. The reward is minus 1.0 on every non goal step and plus 10.0 on entering the goal. Discount γ\gamma is 0.9. The direct path takes four steps:

s0→s1→s2→s3→sgoals_0 \to s_1 \to s_2 \to s_3 \to s_{goal}

Rewards are R1=−1.0R_1 = -1.0, R2=−1.0R_2 = -1.0, R3=−1.0R_3 = -1.0, R4=10.0R_4 = 10.0. The return from the start is:

G0=R1+γR2+γ2R3+γ3R4G_0 = R_1 + \gamma R_2 + \gamma^2 R_3 + \gamma^3 R_4

G0=−1.0+0.9×(−1.0)+0.81×(−1.0)+0.729×10.0G_0 = -1.0 + 0.9 \times (-1.0) + 0.81 \times (-1.0) + 0.729 \times 10.0

G0=−1.0−0.90−0.81+7.29=4.58G_0 = -1.0 - 0.90 - 0.81 + 7.29 = 4.58

That 4.58 is the number the diagram draws. A five step wander that stalls once earns 3.12 under the same rule, so the step penalty plus discount ranks the short path first by 1.46. If a designer instead pays plus 2.0 for every right move and 0.0 for every left move, a two state loop earns 10.53 forever without ever reaching the goal, which beats 4.58 and teaches the agent to loop. That contrast is why the dense terms need a step cost.

Code

This snippet computes the same 4.58 from the same four rewards, so you can check the arithmetic in one run:

from typing import List

def discounted_return(rewards: List[float], gamma: float = 0.9) -> float:    """Return G0 for one reward list. rewards[0] is R1."""    total = 0.0    for r in reversed(rewards):        total = r + gamma * total    return total

if __name__ == "__main__":    direct = [-1.0, -1.0, -1.0, 10.0]    print(round(discounted_return(direct, gamma=0.9), 3))    # -> 4.58    stall = [-1.0, -1.0, -1.0, -1.0, 10.0]    print(round(discounted_return(stall, gamma=0.9), 3))    # -> 3.122

The second line is the stalling path at 3.122. Same rule, one extra minus one step, lower return. That gap is the step penalty doing its job.

Watch Out For

Paying for progress without charging for retreat

The symptom is a policy whose return climbs while the task never completes. Logs look great, the robot never arrives. The usual cause is a one sided proxy, such as plus 2.0 for moving right and 0.0 for moving left. The agent finds the two state loop and harvests plus 2.0 every other step forever.

Fix it before tuning anything else. Charge every step with a small negative, score arrivals with a terminal bonus, and define extra hints as potential differences so loops sum to zero. Then evaluate on the true goal rate, not on the shaped total. If goal rate is flat while shaped return rises, the shaping is the bug.

Letting reward scale fight the optimizer

The symptom is learning that is either frozen or violent with no middle ground. Tiny rewards next to a default step size produce tiny gradients and nothing moves. Huge rewards produce huge updates and the policy jumps apart on the first good episode.

Fix it by keeping rewards near unit scale and by checking the first batches. Aim for typical non zero step rewards around magnitude 1, with terminal bonuses no more than about ten times that. If you rescale rewards, retune the step size or normalize advantages, because the optimizer only ever sees their product.

The Quick Version

  • The reward function maps one transition (s,a,s′)(s, a, s^\prime) to one scalar score.
  • The agent never sees the goal directly. It sees the discounted sum GtG_t of those scalars.
  • Sparse rewards tell the truth rarely. Dense rewards teach fast and can be gamed.
  • Four steps of minus 1, minus 1, minus 1, plus 10 at gamma 0.9 return 4.58.
  • Charge steps, bonus the goal, and test on goal rate rather than shaped return.
  • Keep step rewards near unit scale so the optimizer sees stable updates.