Skip to content
AI360XpertBeta

Multi-Agent DDPG (MADDPG)

Each agent acts alone from its own view, but training gives each critic the full scene plus all actions, which steadies learning in continuous team play.

Centralized critic sees joint actions and builds target 5.6 with error 0.60 while the actor uses only its local view to climb with gradient 1.20
Centralized critic sees joint actions and builds target 5.6 with error 0.60 while the actor uses only its local view to climb with gradient 1.20

Why Does This Exist?

Independent learners chase a moving target. When agent 1 learns, agent 2 changes too, so transition P(s′∣s,a1)P(s' \mid s, a_1) shifts under your feet. Replay turns stale, Q updates wobble, and continuous control rarely converges.

A single joint controller fixes stationarity but needs global talk at runtime, which robots and game clients cannot afford, and its action space blows up with team size. Multi-agent RL frames the problem. This page covers the CTDE fix for continuous actions: train with global context, deploy with local views only. For the PPO cousin see MAPPO. For factored team values see value decomposition.

The one idea you need first

An actor μ(o)\mu(o) maps a local view oo to an action aa. A critic Q(x,a)Q(x, a) scores a global state xx plus actions. DDPG trains a deterministic actor by climbing the critic slope ∇aQ\nabla_a Q. MADDPG keeps that climb but gives each critic the joint actions.

Think of It Like This

Film room versus live game

Your basketball team studies overhead drone film. The coach sees all ten players and tells you that when your teammate set a high screen you should have cut backdoor. The note is sharp because it uses full context.

In the live game the film room is gone. You play from eye level on your local view o1o_1 only. You still cut at the right time because practice wired the pattern in. Training was centralized, execution is local.

Where it stops: a human coach can still shout from the sideline. In MADDPG the critic is deleted at deployment. Zero talk, full autonomy.

How It Actually Works

With NN agents, call oio_i the local view, aia_i the continuous action, xx the global state, a=(a1,…,aN)a = (a_1, \dots, a_N) the joint action. Agent ii owns actor μi(oi)\mu_i(o_i) and critic Qi(x,a)Q_i(x, a).

Conditioning on aa restores stationarity because P(x′∣x,a)P(x' \mid x, a) does not shift when policies change. Only the action distribution shifts, which replay handles.

Critic target

Critic ii minimizes Bellman square error with target actors μj′\mu'_j and target critic Qi′Q'_i:

yi=ri+γQi′(x′,a1′,…,aN′)y_i = r_i + \gamma Q'_i(x', a'_1, \dots, a'_N)

aj′=μj′(oj′)a'_j = \mu'_j(o'_j)

L=(Qi(x,a)−yi)2\mathcal{L} = (Q_i(x, a) - y_i)^2

Rewards rir_i stay individual, so cooperative, competitive, and mixed motives all fit.

Actor climb

The actor climbs through its own critic slope only:

∇J=E[∇θμi(oi)⋅∇aiQi(x,a)]\nabla J = \mathbb{E}[\nabla_\theta \mu_i(o_i) \cdot \nabla_{a_i} Q_i(x, a)]

Peer actions enter as fixed context. You do not differentiate through them.

Worked example

Two agents, γ=0.90\gamma = 0.90. State x=[1.0,2.0]x = [1.0, 2.0], views o1=1.0o_1 = 1.0 and o2=2.0o_2 = 2.0, actions a1=0.50a_1 = 0.50 and a2=−0.50a_2 = -0.50, reward r1=2.0r_1 = 2.0, next x′=[1.2,1.8]x' = [1.2, 1.8].

Target actions a1′=0.60a'_1 = 0.60 and a2′=−0.40a'_2 = -0.40. Target critic Q1′(x′,a′)=4.00Q'_1(x', a') = 4.00.

y1=2.0+0.90×4.00=5.60y_1 = 2.0 + 0.90 \times 4.00 = 5.60

Current critic Q1(x,a)=5.00Q_1(x, a) = 5.00.

δ1=5.60−5.00=0.60\delta_1 = 5.60 - 5.00 = 0.60

L=0.602=0.36\mathcal{L} = 0.60^2 = 0.36

Critic slope ∇a1Q1=1.50\nabla_{a_1} Q_1 = 1.50 and actor sensitivity ∇θμ1=0.80\nabla_\theta \mu_1 = 0.80.

∇J=0.80×1.50=1.20\nabla J = 0.80 \times 1.50 = 1.20

Actor weights move up by rate times 1.201.20. The diagram shows 5.605.60, 0.600.60, and 1.201.20 on the same path.

Code

This replays the critic and actor arithmetic from the worked example.

def bellman_target(r: float, gamma: float, q_next: float) -> float:    """y = r + gamma * Q next."""    return r + gamma * q_next

def policy_gradient(dmu_dtheta: float, dq_da: float) -> float:    """Chain rule through own action only."""    return dmu_dtheta * dq_da

if __name__ == "__main__":    y1 = bellman_target(2.0, 0.90, 4.0)    print(f"y1 = {y1:.2f}")  # -> y1 = 5.60    delta = y1 - 5.00    print(f"delta = {delta:.2f}")  # -> delta = 0.60    print(f"loss = {delta**2:.4f}")  # -> loss = 0.3600    g = policy_gradient(0.80, 1.50)    print(f"grad = {g:.2f}")  # -> grad = 1.20

Watch Out For

Critic input blows up with team size

Each critic takes all actions, so with 10 plus agents the input grows and credit assignment blurs. Symptom: sample hunger spikes and actor gradients swing wildly as team size grows.

Attend to neighbors instead of concatenating everyone, as in attention critics, or switch to factored team values in pure cooperative tasks. Do not just widen the critic and hope. The joint space is the bottleneck.

Leaking global state into the actor

It is tempting to pass xx or peer actions to the actor because training looks faster. Symptom: lab scores shine, deployment fails because those inputs are missing and the policy never learned a local mapping.

Keep the actor signature strictly μi(oi)\mu_i(o_i). Test with global inputs masked before you report results. If performance collapses under masking, the actor cheated.

The Quick Version

  • MADDPG trains centralized critics on global state plus joint actions but deploys actors on local views only.
  • Joint conditioning restores stationarity because P(x′∣x,a)P(x' \mid x, a) stays fixed while policies change.
  • In the worked step target y1=5.60y_1 = 5.60, error is 0.600.60, loss is 0.360.36, and actor gradient is 1.201.20.
  • Each actor climbs only its own critic slope ∇aiQi\nabla_{a_i} Q_i, with peer actions as fixed context.
  • Individual rewards support cooperative, competitive, and mixed play, but large teams need attention or factored critics.