Multi-Agent PPO (MAPPO)
One shared policy controls every agent from local views, while one central critic judges the team from full state. Clipped updates keep the team moving together.
Why Does This Exist?
Independent policy gradients fail on teams. Each agent treats teammates as noise, so from any one agent view the world keeps shifting as peers change. Advantage estimates swing, and small steps by many agents compound into a large joint jump.
MAPPO answers with centralization at train time and independence at run time. Training sees full state through one critic. Execution uses only local views through one shared actor. Clipping bounds each step. Yu and coauthors showed in 2022 that this plain recipe matches far more complex off policy team methods on StarCraft unit tasks, football, and Hanabi.
This page covers the team PPO loop. Single agent clipping lives in trust region and proximal methods. Team framing lives in multi-agent RL. Value factorization alternatives live in value decomposition networks.
The one idea you need first
A policy gradient raises the chance of actions that beat baseline. PPO keeps the new policy near the old one by clipping the probability ratio to . With the ratio can move only between and . That bound is the whole stabilizer MAPPO reuses per agent.
Think of It Like This
One playbook, many players, one coach with the full field view
A youth football squad shares one playbook. Each child on the pitch sees only nearby players and the ball. That is the local view . Each child decides alone, with no time to ask the bench. That is the decentralized actor.
One coach stands on a tower and sees all 22 players. The coach does not shout moves during play. After the match the coach grades each choice against the full field picture. That grade is the central critic . Practice changes are small by rule, at most one small tweak per drill, so the team keeps shape. That is clipping.
Where it stops: children differ in speed and skill. MAPPO agents with shared weights are identical copies told apart only by an identity tag in the input.
How It Actually Works
There are agents. Agent sees local view plus a one hot tag for its identity. One actor with weights serves all agents. One critic with weights reads full state during training only. is shared team reward, discounts the future, trades bias for variance in advantage estimation.
Rollouts collect times more steps per tick than one agent, because every teammate writes into the same buffer. Advantages come from the central critic with generalized advantage estimation. Actors update with the clipped PPO loss averaged over agents and time. The critic fits return targets with its own clipped loss.
Central advantage from full state
Define the one step residual from the central critic:
In words: reward plus discounted next value minus current value. Positive means the team did better than the critic thought. The advantage aggregates residuals:
Because sees and not just , peer moves are in the baseline instead of appearing as noise.
Clipped team update
Let be new chance divided by old chance for the taken action:
The per sample loss keeps the smaller of plain and clipped:
With the update raises action chance but stops paying once the ratio hits . With it lowers chance but stops penalizing past .
Worked example
Use , , . The critic says and . Team reward is .
Residual:
One step advantage . The action helped.
Old chance is . Candidate new chance gives ratio:
Surrogate values:
Clipped ratio stays , so clipped value is also . Loss is .
Now try an aggressive jump to . Ratio is . Plain value is . Clipped ratio snaps back to , clipped value stays . Loss is . The extra push earns nothing, so the gradient for pushing further is zero. That cap is what the diagram draws.
Code
This snippet recomputes the worked numbers with plain Python. It has no dependencies and prints the advantage plus both clipped cases.
def td_residual(r: float, v: float, v_next: float, gamma: float) -> float: return r + gamma * v_next - v
def clipped_loss(ratio: float, adv: float, eps: float = 0.20) -> float: lo = 1.0 - eps hi = 1.0 + eps clipped = min(max(ratio, lo), hi) return min(ratio * adv, clipped * adv)
adv = td_residual(2.00, 4.00, 5.00, 0.95)print(round(adv, 2)) # -> 2.75print(round(0.48 / 0.40, 2)) # -> 1.2print(round(clipped_loss(0.48 / 0.40, adv), 2)) # -> 3.3print(round(0.52 / 0.40, 2)) # -> 1.3print(round(clipped_loss(0.52 / 0.40, adv), 2)) # -> 3.3The prints match the hand calculation: advantage , moderate ratio with loss , aggressive ratio still capped at .
Watch Out For
Feeding the critic a concat of every view
Stacking all local views into the critic sounds thorough and trains poorly past a handful of agents. Input width grows with team size, noise repeats, and the critic fits sensor quirks instead of team state. Returns then swing and advantages follow.
Fix it with a compact global state: positions, health, counts, map flags. Keep views for actors only. Normalize value targets with a running mean and scale so early team return spikes do not throw huge critic gradients.
Running too many PPO epochs on stale team data
Single agent PPO often uses 10 to 20 passes per batch. MAPPO with 10 plus passes on the same joint batch drifts because peers moved while the data sat still. Policy ratios leave the trust band and the next rollout starts from a worse joint policy.
Use 5 to 10 epochs, watch the fraction of clipped ratios, and stop early when half the batch clips. Fresh team rollouts beat extra passes on old ones.
The Quick Version
- MAPPO is PPO for teams: one shared actor per agent plus one central critic on full state.
- The central critic removes teammate noise from advantages by conditioning on instead of .
- Parameter sharing pools agent streams into one buffer, so data grows with team size.
- Clipping at caps joint jumps. Ratio with advantage still pays only .
- Keep critic inputs compact, normalize value targets, and hold PPO to few epochs per batch.