Self-play means training a program by letting it play against copies of itself and learning from the results. It produced Go and chess programs far stronger than any human, and it is the cleanest example of a system that improves on data it makes itself. This section shows how self-play works, why it works so well in games, where it breaks, and what is left of it when the game is replaced by language.
This chapter makes one argument, first stated in §26.1. A model can learn from its own outputs only when something tells it which outputs were good, and that something must be more reliable than the model's own guesses. In a game, the rules do this. At the end of every game you know exactly who won.
Here is how far that goes. In 2017 DeepMind trained a Go program, AlphaGo Zero, that started from random moves and was told nothing but the rules (Silver et al. 2017). It never saw a human game. After three days of playing against itself, it played AlphaGo Lee, the earlier program that had beaten Lee Sedol, one of the strongest players in the world. It won 100 games to 0. Its successor, AlphaZero, learned chess and shogi the same way.
Three things made this possible, and we build each one from scratch. First, the rules give an exact reward. Second, a copy of yourself is an opponent of exactly your strength, so you win about half your games and every game teaches something. Third, a search that looks a few moves ahead turns the network's current guess into a better move, and the network then learns to imitate that move.
We build all three on a game small enough to solve by hand. Then we see where the recipe breaks, in games where "better" goes in circles and in superhuman programs that lose to a trick a human player can learn. Last, we follow self-play into language models, which have the opponent but not the rulebook. That answers the question behind the section. Why did self-play produce superhuman Go players but not superhuman essay writers?
A game small enough to solve by hand
Take a pile of stones. Two players take turns, and on each turn the player to move removes 1, 2, or 3 stones. Whoever takes the last stone wins. This is one-pile Nim with a move limit. It is small enough to solve exactly, so every algorithm in the first half of the section can be checked against the true answer.
A position is the number of stones left, n. We score each position for the player about to move, and call the score its value. It is +1 if the player to move wins with best play and −1 if they lose. With 0 stones the player to move has already lost, because the opponent took the last stone, so the value of 0 stones is −1.
The key step is to look at each move from the opponent's side. Whatever position I leave, my opponent moves next. The game is zero-sum, which means one player's win is the other's loss. So a position worth +1 to my opponent is worth −1 to me, and I want to leave them the position with the lowest value.
The same recursion works for every game of this kind.
In plain words, my value is the best I can get, and what I get from a move is minus what my opponent gets from the position it leaves. The name is short for "maximum of the negation". That minus sign is the whole difference between a puzzle, where one player maximizes, and a game, where two players pull in opposite directions. The cell fills in the table for Nim.
Python · cell 1
Chess and Go fit the same definition, so in principle the same table solves them. Working backward from the end of the game like this is called backward induction. It proves that every finite two-player game of perfect information has a value and an optimal strategy for each player, an argument that goes back to Ernst Zermelo in 1913. In practice the table is far too big. Chess has about 5×1044 legal positions and Go about 2×10170. Everything that follows is a way to approximate V⋆ and the best moves without the table.
Tree search looks ahead only where it matters
Monte Carlo tree search (MCTS) looks ahead from the current position without building the whole game tree. It grows a small tree of positions below the current one and estimates how good each move is by averaging the results of many sample walks through that tree, which is what "Monte Carlo" refers to. §18.6 used it to search over the steps of a written solution, where only one player chooses. Here we build the whole algorithm for a two-player game, the version inside AlphaZero.
One walk down the tree is called a simulation. It starts at the root, the current position. At each position it takes the move with the best score. The score adds two things, how well the move did in earlier simulations and a bonus for moves that look plausible but have rarely been tried.
When the walk reaches a position not yet in the tree, it adds that position, asks for an estimate of its value, and carries the estimate back up the path. After many simulations, the moves at the root that were tried most often are the ones that held up best under the most scrutiny. Those visit counts are what the search returns.
Two functions guide the search. A policy gives every legal move a probability, and the search uses one as its priorP(s,a), a first guess at which moves are good. A value functionv(s)∈[−1,1] is a guess at V⋆(s). In AlphaZero both come from one neural network. For now they can be anything, even a uniform prior and a value of zero everywhere.
The selection rule is called PUCT, short for "predictor plus upper confidence bounds applied to trees", where the predictor is the prior. §18.6 wrote its constant as c. We rename it cpuct, because in this chapter c counts correct samples.
In plain words, go where the average outcome has been good, and also where the prior thinks a move is plausible and you have not looked much yet. Look at the bonus term. At a fresh node N(s)=0, so every bonus is zero and the tie rule picks the first move. After that the bonus grows like N(s) for a move you keep skipping and shrinks like 1/N(s,a) for a move you keep choosing. So every move with a positive prior is tried eventually, and as visits pile up, Q decides.
Why the backup flips the sign
The negation in step 3 is the one line that separates search in a game from search in a puzzle. It is also the most common bug in hand-written MCTS.
Proof. The players alternate, so the player to move at sj is the player to move at sL exactly when L−j is even. In a zero-sum game an outcome worth vL to one player is worth −vL to the other. ∎
Forget the negation and every node stores values for the player at the leaf. Both players then maximize the same number, and the search behaves as if the two sides were cooperating. A cell below shows the damage. From 2 stones, "take 2" wins on the spot, yet a search without the flip scores it −1, because it scores the move for the player who just lost.
Four simulations by hand
Let us run the algorithm by hand from 5 stones, where the only winning move is to take 1. The prior is uniform, P=31 for each move, and cpuct=2. The value function is weak but points the right way. It says v(n)=+0.25 if n is not a multiple of 4 and −0.25 if it is. No simulation reaches the end of the game in this short run.
The search did not improve because it found a forced win. It improved because it looked one move ahead and asked the value function, which already knows more than a uniform guess. With more simulations, terminal states enter the tree and their exact values flow back up.
Visit counts become a policy
The root's visit counts are the search's verdict. AlphaZero turns them into a probability distribution with a temperatureτ≥0,
πsearch(a∣s)∝N(s,a)1/τ.
At τ=1 the probabilities are proportional to the visits. As τ→0 all the mass goes to the most-visited move, which is how a program picks its move in a real match. In self-play, AlphaGo Zero used τ=1 for the first 30 moves of each game, so that games start differently, and τ→0 afterward. We write πsearch so that it never collides with the network's own policy πθ.
Warm-up
Policy targets from visit counts
Write search_policy(visits, tau, legal), which turns root visit counts into the training target πsearch∝N1/τ.
visits is a float array of visit counts, and legal is a boolean mask of the same shape. Return a probability vector over the legal moves with exactly zero on the illegal ones.
tau is a temperature of at least 0. At tau == 0, return the argmax, splitting the mass evenly among tied most-visited legal moves.
If no legal move has any visits, return the uniform distribution over the legal moves.
Work in log space. Small temperatures overflow otherwise, since with tau = 0.005 the power 800200 is too large for a float.
Tests, hints, verified solutions, and AI help, with Pro at $7.99 a month.
Next is the interview problem. Labs ask for MCTS on a whiteboard often enough that you should be able to write it without notes, sign flip included.
Interview
MCTS with PUCT for a two-player game
Write mcts(game, root, prior_fn, value_fn, n_sims, c_puct=1.5, eps=0.0, alpha=0.3, seed=0) exactly as the definition box above describes. It returns the root's visit counts N and mean values Q, both arrays of length n_actions. The inputs are these.
game has n_actions, legal(s) (a boolean mask), next_state(s, a), and terminal_value(s). The last returns the exact value of a terminal state for the player to move there, or None if the game goes on.
prior_fn(s) returns nonnegative weights over all actions. Mask them to the legal moves and renormalize.
value_fn(s) returns v(s) for a new non-terminal leaf.
The tests check visit counts down to the last simulation, so follow these rules exactly.
Build a tree with one node per path, not one per state.
Expand the root before the first simulation, and give unvisited edges Q=0.
Break ties with np.argmax, which picks the first legal move.
Never expand a terminal state, and negate the value once per edge on the way up.
If eps > 0, mix random noise into the root's priors only, (1−ε)P+εη, after masking. Here η∼Dir(α) is a random probability vector over the legal moves. Draw it once, as np.random.default_rng(seed).dirichlet([alpha] * k) for the k legal root moves, and place its entries on those moves in order (zero elsewhere). The AlphaZero part of this section explains why the noise is there.
The setup provides Nim (taking the last stone wins), MisereNim (taking the last stone loses), uniform_prior, and zero_value.
import numpy as np
def mcts(game, root, prior_fn, value_fn, n_sims, c_puct=1.5, eps=0.0, alpha=0.3, seed=0):
N = np.zeros(game.n_actions)
Q = np.zeros(game.n_actions)
# TODO: select with PUCT, expand, evaluate, back up with the sign flip
return N, Q
Tests, hints, verified solutions, and AI help, with Pro at $7.99 a month.
Here is our own version, which the rest of the section uses. It prints the root scores of the hand example, and they match the table.
Python · cell 2
What search alone can and cannot see
Python · cell 3
Search alone is excellent near the end of the game and useless far from it. With 300 simulations it puts 94 percent or more of its visits on the winning move up to 7 stones, and 60 percent at 11. From 13 stones on it falls back to about the prior's one third. The winning line there is deeper than the tree grows, and every leaf the search sees says 0.
This blind spot is called the horizon problem, and it is why AlphaZero needs a value network. A value function that is right about positions beyond the tree's reach extends what the search can see. The search, in turn, produces better training targets for the value function. The widget lets you watch both effects.
How does search turn a weak policy into a stronger target to learn from?
Search on one-pile Nim. Take 1, 2, or 3 stones, and whoever takes the last stone wins.
Loading interactive figure…
An interviewer who asks you to write MCTS is checking three things. Do you flip the sign at every level? Does the bonus use the parent's total visits? Can you say why the search needs a value function at all?
Why imitating the search makes the network stronger
AlphaZero trains its network to predict the search's visit counts. Why should that make the network stronger? There is an exact argument for one step and an empirical one for the whole loop.
Start with the exact part. Fix the opponent's strategy. From one player's side the game is then an ordinary Markov decision process, a sequence of states, actions, and rewards in which the next state depends only on the current state and action. §15.2 proved the policy improvement theorem for such processes. Let Qπ(s,a) be the exact action values of a policy π, the expected outcome of playing a in s and following π afterward. The greedy policy π′(s)=argmaxaQπ(s,a) does at least as well as π in every state. It does strictly better somewhere unless π is already optimal.
In plain words, acting greedily on accurate values improves a policy. MCTS estimates those values at the current position, with more look-ahead than the network has. As simulations grow, its visits pile up on the moves with high Q, because a move's bonus shrinks as the move is visited while its Q does not.
How good is the estimate? PUCT descends from UCT, the upper-confidence rule for trees. UCT uses no prior, and its bonus is clnN(s)/N(s,a). For UCT, Kocsis and Szepesvári (2006) proved that the value estimates converge to the true game values as the number of simulations grows. For PUCT with a learned prior and value there is no comparably clean guarantee. That search plus imitation keeps improving the network over millions of games is an empirical finding.
The size of the effect is measured in Elo, the rating scale of chess and Go (§22.7 derives it). A player rated Δ points higher is expected to score a fraction 1/(1+10−Δ/400) of the points. So a 400-point edge means scoring about 10 points for every 1 the opponent scores.
In practice this means two things. A self-play program always plays its real matches with search switched on. And the search's output is a better label than anything the network could produce alone, which is the whole reason to train on it. An interviewer who asks "why does imitating MCTS help?" wants the policy improvement theorem and this gap.
AlphaZero closes the loop
We now have all the pieces. One network reads a position and outputs two things, a prior over moves and a value. MCTS uses the prior to decide where to look and the value to judge new leaves. The program plays games against itself and chooses every move by search. Each position it meets is stored with two labels, the search's move probabilities and the final result of the game. Then the network is trained to predict both labels. A better network makes a better search, which makes better labels.
In plain words, the value head learns to predict who actually won from here. The policy head learns to predict what the search chose here. A little weight decay keeps the weights small. Both labels come from the system itself, and both are better than what the network knew when it played the game. The outcome z is exact, because the rules say who won. The search policy beats p, by the improvement argument above.
Four design choices and their reasons
Interviewers ask about each of these.
Visit counts, not just the best move. A distribution carries more information than one move, the way soft labels carry more than hard ones. It also keeps the search's uncertainty, since a move visited 400 times out of 800 is less certain than one visited 790 times. The Q of a rarely visited move is a noisy average of a few leaves, while the visits already reflect how much the search trusted each estimate. And a one-hot target would collapse the prior. A move with a prior near zero gets almost no bonus in the next search, so it would never be explored again.
Noise at the root. Self-play learns only about moves it plays. If the prior gives a strong move almost no probability, the search rarely visits it, the visits never favor it, and the network never learns it. The fix mixes random noise into the root's prior with weight εdir=0.25. In each search a few random moves, possibly ones the network dislikes, then get a real share of the prior. Meanwhile 75 percent of the prior still comes from the network, so the search can overrule bad noise. The noise is drawn from a Dirichlet distributionDir(α), a distribution over probability vectors. With α below 1 its samples are spiky, with most of their mass on a few random moves. AlphaZero scales αdir inversely with the typical number of legal moves, using 0.3 for chess, 0.15 for shogi, and 0.03 for Go. That keeps αdir times the number of moves near 10, so in every game the noise gives a real boost to a small random set of moves.
A temperature. At τ=1 the move is sampled in proportion to the visits, which varies the openings the network trains on. Later in the game AlphaGo Zero played the most-visited move (τ→0).
No gate. AlphaGo Zero kept a "best player" and replaced it only when a new network won more than 55 percent of 400 evaluation games. AlphaZero dropped this gate and always played with the newest network. That it still worked suggests that in these games the improvements are steady enough that an occasional worse network does little harm.
The loop is one case of a general template called expert iteration, which Anthony, Tian, and Barber (2017) developed independently on the board game Hex. An expert, here search guided by the network, makes better decisions than the apprentice, the network alone. The apprentice is trained to imitate the expert, and the improved apprentice makes the expert stronger. §26.3 shows that STaR and rejection-sampling fine-tuning for language models use the same template, with sampling plus an answer checker as the expert.
The two kinds of compute also trade against each other. Jones (2021) trained AlphaZero-style agents on Hex at many board sizes. On a 9 by 9 board, each additional tenfold of training compute removed the need for about fifteenfold of search compute at play time, with no loss in strength (§9.6 puts this beside test-time compute for language models).
What the loop costs at scale
AlphaZero's hours of training hid a large fleet of chips. Its preprint reports the hardware and the game counts, and those numbers say where a self-play system spends its compute.
The counts in the box are enough to compare the two halves of the loop, playing games and training on them, by the number of network calls each one makes.
Self-play at scale is therefore an inference problem. Three things set its cost. The first is throughput, how many positions the hardware can evaluate per second. The second is latency, because the simulations inside one search run one after another. The third is how well leaf evaluations are batched across many games played in parallel. A design review for a self-play system spends most of its time on the game-playing fleet, not the trainer.
The whole loop on Nim
The PyTorch block below runs the whole loop on Nim, from random weights. Nim has only 16 positions up to 15 stones. So each round evaluates the network on all of them at once, and the search reads from that table, which keeps the run to a few seconds. The network reads a one-hot code of the pile size, so it is a lookup table in disguise, and the point is the loop, not generalization.
Watch the policy head learn the winning move even for 13 to 15 stones, beyond the reach of the pure search above. In this run it gets every winning position right by the sixth round, because the value head extends what a 32-simulation search can see.
🔥 In PyTorchfor a machine with PyTorch
The next step removed the rulebook itself. MuZero (Schrittwieser et al. 2020) learned a model of the game's dynamics from experience and searched inside that learned model. Inside its search it never consulted the rules. The real game supplied only the legal moves at the root, the rewards, and the next real position. The same program mastered Go, chess, shogi, and Atari video games. Learned world models carry this idea to environments with no simulator.
When beating your last self goes in circles
Nim, chess, and Go have a property we have used without saying so. There is one best way to play, and a stronger player beats a weaker one. Many games are not like that. In rock-paper-scissors no strategy is best, and "beats" goes around in a circle. Self-play there can beat its previous version forever without getting anywhere. To say what "getting somewhere" means, we need a little game theory.
Here is the standard example. In rock-paper-scissors, with the actions in the order rock, paper, scissors and a payoff of 1 for a win,
URPS=01−1−1011−10.
Row 2 is paper. It beats rock in column 1 and loses to scissors in column 3. The only equilibrium is for both players to play each action with probability 31, and the expected payoff there is 0.
In plain words, with mixed strategies it does not matter who has to commit first. The left side is what the row player can guarantee by announcing a strategy first. The right side is what the column player can hold them to by announcing first. The left can never exceed the right, and that half is easy. Equality is the deep part. The usual proof uses linear programming duality, and below we prove it a second way, from the fact that a kind of self-play converges.
How far is a pair of strategies from equilibrium? The cleanest measure asks how much each player could gain by switching to a best response.
To see what it measures, add and subtract the payoff actually received, μ⊤Uν,
expl=[μ′maxμ′⊤Uν−μ⊤Uν]+[μ⊤Uν−ν′minμ⊤Uν′].
Each bracket is one player's gain from switching, so each is at least 0. Both are 0 exactly when both strategies are best responses.
Now run the most naive self-play, called iterated best response, in which each new version plays the best response to the previous one. Start with rock. The best response to rock is paper, so the next version plays paper. The best response to paper is scissors, and then comes rock again. Each new version beats the previous one every time, so a dashboard that tracks the win rate against the last checkpoint shows 100 percent at every step. Yet the policy goes around a three-step cycle forever. Its exploitability stays at expl(eR,eR)=2max(0,1,−1)=2, the largest possible in this game.
This is the trap to name in an interview. A rising win rate against your last checkpoint is not evidence of progress unless the game is transitive, meaning that if A beats B and B beats C, then A beats C.
Self-play that converges on average
The fix for cycling is to stop answering only your last self. Fictitious play answers the average of everything the opponent has played so far (Brown 1951, Chapter XXIV). In round t+1 the row player plays a best response to νˉt=t1∑s=1tνs, and the column player plays a best response to μˉt. What converges is the pair of average strategies μˉT and νˉT, not the strategy played in each round.
The rate can be slow. Empirically the exploitability often falls like 1/T, and with adversarial tie-breaking it can fall far more slowly (Daskalakis and Pan 2014).
A second method has a clean rate and a short proof. It is built on regret, how much better you would have done by playing one fixed action all along. A tiny example comes first.
In plain words, play more often the actions you wish you had played more often. An action that would have beaten what you actually did gains regret, and the more regret it has piled up, the more often you play it.
The link between regret and equilibrium is an exact identity, not only a bound.
∂ Proof of the identity, the regret-matching bound, and the minimax theorem
The identity. The payoff is linear in each strategy, so T1∑t(Uνt)i=(UνˉT)i and T1∑t(μt⊤U)j=(μˉT⊤U)j. Substituting into the definitions,
and what is left is the definition of expl(μˉT,νˉT). The average payoff actually received cancels because one player's gain is the other's loss.
The regret-matching bound. Take the row player, and let rt∈Rm be its instantaneous regret vector, rt(i)=(Uνt)i−μt⊤Uνt, so Rt=Rt−1+rt. Two facts do all the work. First, Rt−1+⋅rt=0. Indeed μt=Rt−1+/∥Rt−1+∥1, and with u=Uνt,
(if Rt−1+=0 the product is 0 at once). Second, taking the positive part never increases distance. Coordinate by coordinate, ((x+y)+)2≤(x++y)2, which you can check in the two cases x≥0 and x negative. Hence
since each ∣rt(i)∣≤D. Summing from t=1 to T gives ∥RT+∥2≤TmD2. The largest regret is at most the norm of the positive part, so maxiRT(i)≤DmT, and dividing by T gives RegTμ≤Dm/T.
The minimax theorem. Weak duality, maxμminν≤minνmaxμ, always holds. For the reverse, run regret matching for both players for T rounds and let ϵT=expl(μˉT,νˉT), which is at most D(m1+m2)/T by the two results above. Then
where the middle equality is the definition of exploitability. Letting T→∞ sends ϵT→0 and gives the reverse inequality. ∎
The theorem teaches two things. First, the averages converge, but nothing says the strategies played in each round do, and in rock-paper-scissors they keep circling. Second, the identity makes exploitability something you can compute during training from logged regrets, without ever solving the game. Regret matching extended to games with many decision points and hidden information is called counterfactual regret minimization (Zinkevich et al. 2007). It is the engine inside the poker programs that beat professionals.
The cell runs all three kinds of self-play from rock against rock and plots the exploitability of the average strategy.
Python · cell 4
Look at iterated best response first. In plain rock-paper-scissors its cycle visits each action equally often. So its average lands exactly on the uniform equilibrium every third round, and its line drops to the bottom of the plot. That is luck, not convergence. In the biased game the cycle still spends a third of its time on each action. Its average goes to (31,31,31), which is not the equilibrium, and its exploitability stays near 32.
Fictitious play and regret matching both fall roughly like 1/T in both games, and both find the biased game's (41,21,41). The last strategy played by every method is still exploitable. The widget shows the same dynamics on the triangle of mixed strategies, where the current strategy circles while the average spirals in.
Why can a policy that always beats its previous self still go in circles, and what makes self-play converge?
Rock-paper-scissors played against itself, both players starting on rock. Each corner of the triangle is one pure action.
Loading interactive figure…
Core
Self-play that cycles and self-play that converges
Write three functions for a zero-sum matrix game. The payoff U has shape (m1, m2) and is the row player's payoff.
exploitability(U, mu, nu) returns maxi(Uν)i−minj(μ⊤U)j, the sum of both players' gains from switching. It is 2 for rock against rock.
best_response_dynamics(U, T) is iterated best response. Both players start at action 0. In each of the next T−1 rounds, both switch at once to a pure best response to the other's previous strategy. Return (mus, nus), the strategies of every round including the first, with shapes (T, m1) and (T, m2).
fictitious_play(U, T) has both players play action 0 in round 1. In each later round, each player plays a pure best response to the average of the opponent's past actions, both at once. Return the average strategies (mu_bar, nu_bar) over all T rounds.
Break every tie toward the lowest index (np.argmax, np.argmin).
Tests, hints, verified solutions, and AI help, with Pro at $7.99 a month.
Research
Regret matching and the regret-to-Nash identity
Write regret_matching(U, T), which runs regret matching for both players of a zero-sum matrix game. Return (mu_bar, nu_bar, reg_mu, reg_nu), the average strategies over the T rounds and the two average external regrets RegTμ and RegTν defined above. Each regret is the largest average regret over actions, and it may be negative.
In round 1 both players play action 0 as a pure strategy.
After each round, each player adds its instantaneous regret vector to its cumulative regrets, using expected payoffs against the opponent's mixed strategy. The row player's vector is (Uνt)i−μt⊤Uνt, and the column player's is −(μt⊤U)j+μt⊤Uνt.
Each player then plays its positive regrets normalized to sum to 1, or uniform if none is positive.
The tests check the identity expl(μˉT,νˉT)=RegTμ+RegTν and the bound Dm/T.
import numpy as np
def regret_matching(U, T):
raise NotImplementedError
Tests, hints, verified solutions, and AI help, with Pro at $7.99 a month.
Populations of past selves stand in for the average
Fictitious play needs the average of all past strategies. That is easy for a vector of three numbers and hard for a neural network, because averaging the weights of two networks does not average how they play. Large systems keep a population of past networks instead and play mixtures of them.
Lanctot et al. (2017) put the options into one algorithm, Policy-Space Response Oracles (PSRO). It repeats three steps.
Play every pair of policies in the population against each other. The results form a payoff table, a small matrix game whose actions are whole policies, called the meta-game.
Choose a mixture over the population with a rule called the meta-solver.
Train a new policy by reinforcement learning to beat that mixture, and add it to the population.
The meta-solver decides which classical method you get. All weight on the newest policy gives iterated best response. A uniform mixture gives fictitious play. The meta-game's Nash equilibrium gives the double oracle method (McMahan, Gordon, and Blum 2003).
In a finite game double oracle stops after finitely many steps. Each step either adds a strategy not yet in the population, or finds that the small game's equilibrium is already an equilibrium of the full game. In rock-paper-scissors, starting from rock, it adds paper (the best response to rock) and then scissors (the best response to paper, which is the equilibrium of the rock-paper game). The equilibrium of all three is the uniform mixture. Every action earns the same against it, so there is nothing left to add.
AlphaStar (Vinyals et al. 2019) built the largest league of this kind for a game, the real-time strategy game StarCraft II. It began from networks trained on human replays, so it did not start from scratch, and then trained three kinds of agents.
Main agents train against themselves and the whole league, meeting past opponents more often the more they lose to them.
Main exploiters train only against the current main agents, to expose their weaknesses.
League exploiters train against the whole league, to find strategies that no one handles.
Frozen copies join the league over time, so every weakness found stays in the pool of opponents.
In practice, a population is how you get the benefit of fictitious play with neural networks. The cost is a growing payoff table and many training runs in parallel, and the reward is a policy that does not lose to strategies it has already met.
Superhuman is not unexploitable
AlphaZero-style Go programs became so strong that people treated them as nearly perfect. In 2022 and 2023 a research group showed that they are not.
The lesson for anyone evaluating a self-play system is that two numbers answer two different questions. Elo against past versions and against humans measures the transitive part of strength, which can be enormous. Exploitability asks how well the best possible counter-strategy does. Self-play covers the positions that self-play visits, and an optimizer aimed squarely at the system finds the ones it never visits. Computing a best response in a large game is as hard as training, so in practice exploitability is estimated by training exploiters, which is what AlphaStar's league builds in.
The same lesson applies to every learned judge in this book. A reward model is a network trained to score answers the way people would. A policy trained by reinforcement learning against a frozen reward model is an adversarial policy against that model. The result is reward hacking, answers that score high and are not good (§16.5). It is also the central risk of the loops in §26.4, where a model judges its own outputs.
Language models have the opponent but not the referee
Back to the opening question. Why does self-play make superhuman Go players but not superhuman essay writers? Go supplies three things, and open-ended language tasks lack the most important one.
An exact reward. The rules of Go say who won. Nothing says which of two essays is better except a person, or a model trained to imitate people.
An opponent of matching strength. This one transfers, since a model can always play a copy of itself.
Search with a reliable value. Tree search over text is possible (§18.6), but the value of a half-written argument is far harder to learn than the value of a Go position.
Every self-play method for language models is a way to supply the first ingredient. Some play real games whose rules decide the winner. Some make the training data the referee. Some use a judge or a reward model. And some invent problems whose answers a program can check. The table sorts the main methods by what decides the winner, and that column predicts how far each can go.
The most direct approach keeps a real game and plays it in words, with the rules as the referee. The rewards are then exact, but they reward skill at the game, and how much of that skill carries over to math and code is a question only experiments can answer. The box gives the two main results.
Self-play against your previous self
Self-play fine-tuning (SPIN, Chen et al. 2024) plays a game whose referee is a supervised dataset of prompts and target answers. The targets may be written by people or, as in the paper's experiments, by a stronger model. Call them the data answers. SPIN starts from a model already fine-tuned on that data, at the point where more supervised training no longer helps.
Each iteration plays one round of a game. The previous model writes its own answer to each prompt. The new model is trained to tell the data answer from the previous model's answer. The previous model is the opponent, trying to make the two indistinguishable.
One trick turns this game into a single loss. Score each answer with the new model itself, by how much more likely the new model finds it than the previous model did. Raising the score of data answers and lowering the score of the model's own answers is then a preference loss. It is the loss of direct preference optimization (DPO), which trains on pairs of a preferred and a rejected answer and raises the first's log-probability relative to a fixed reference model while lowering the second's (§17.2 derived it).
In plain words, this is the DPO loss with the data answer y always chosen, the model's own answer y′ always rejected, and the previous model as the reference. No preference labels are needed, only the supervised data.
What does each iteration do to the model? The exact answer fits in one line, and a tiny example shows it first.
The geometric mean in the example is not a coincidence of the numbers. The theorem below gives the update for any data and any λspin, shows that the data distribution is where the iterations stop, and says for which λspin they get there.
∂ Proof of the update and of the convergence condition
Fix a prompt and drop x. Write πt=πθt and g(y)=λspinlog(π(y)/πt(y)) for the candidate π. The loss is ∑a,bpdata(a)πt(b)ℓ(g(a)−g(b)). Group each pair a=b with its mirror image b,a, and let wab=pdata(a)πt(b)>0. The pair contributes h(d)=wablog(1+e−d)+wbalog(1+ed) with d=g(a)−g(b). This is strictly convex in d, and h′(d)=−wabσ(−d)+wbaσ(d), which vanishes when σ(d)=wab/(wab+wba), that is at d⋆=log(wab/wba). The diagonal terms a=b contribute the constant ℓ(0).
Now take g(y)=log(pdata(y)/πt(y))+C for any constant C. Then for every pair g(a)−g(b)=logpdata(b)πt(a)pdata(a)πt(b)=d⋆, so this single g minimizes every term at once and therefore the sum. By strict convexity any minimizer must give every pair the same differences, so the minimizing g is unique up to C. Solving λspinlog(π/πt)=log(pdata/πt)+C gives π=πt(pdata/πt)1/λspineC/λspin, and normalization fixes C. This is (b). If πt=pdata, the update returns πt, which is (a) for the logistic loss (the paper proves it for every convex decreasing ℓ).
Taking logs of (b), logπt+1=(1−1/λspin)logπt+(1/λspin)logpdata+Ct. Subtract logpdata from both sides to get et+1=(1−1/λspin)et+Ct. The constant cannot change the shape of the distribution, so measure the error after removing it, e~t=et−meanyet, which obeys e~t+1=(1−1/λspin)e~t exactly. If e~t=0, then πt=pdataec for a constant c, and since both sum to 1, c=0. So πt→pdata exactly when ∣1−1/λspin∣<1, which for λspin>0 means λspin>21. The factor is 0 at λspin=1, in (0,1) above 1, in (−1,0) between 21 and 1, exactly −1 at 21, and below −1 under 21. ∎
The cell runs the exact update from the tiny example for several values of λspin. It then checks part (b) against the loss itself.
Python · cell 5
The theorem explains SPIN's results and its limit at the same time. The fixed point is pdata, so SPIN cannot exceed the quality of its supervised data. It can only pull a model that has not fully absorbed the data closer to it. In practice that makes SPIN a way to squeeze more out of a supervised dataset after ordinary fine-tuning has stalled, and never a way past it.
Core
SPIN in a table
Simulate SPIN exactly on a finite set of K answers.
spin_tabular(p0, p_data, lam, iters) applies the exact update pt+1∝pt(pdata/pt)1/λ for iters iterations. Return the whole trajectory as an array of shape (iters + 1, K), starting with p0.
Work in log space and subtract the maximum before exponentiating, so that tiny probabilities and small λ cannot overflow. Carry the log-probabilities from one iteration to the next instead of taking the log of the previous row again. Below λ=21 some entries underflow to exactly 0, and the log of 0 would turn the next row into nan.
spin_rate(lam) returns the factor ∣1−1/λ∣ by which the centered log-ratio error shrinks or grows each iteration.
import numpy as np
def spin_tabular(p0, p_data, lam, iters):
traj = [np.asarray(p0, float)]
for _ in range(iters):
p = traj[-1]
q = p * (p_data / p) ** (1 / lam)
traj.append(q / q.sum())
Tests, hints, verified solutions, and AI help, with Pro at $7.99 a month.
Debate, and games with a learned referee
§19.5 introduced debate as a way to supervise answers a judge cannot check directly. Two models argue for different answers, and a weaker judge decides who won. The hope is that the truth is easier to defend than a lie. Training the debaters to win is self-play with the judge's verdict as the reward. This is not the cooperative debate of §24.7, where several agents revise toward one answer and a vote decides. Here the two sides argue against each other and a third party judges.
Arnesen, Rein, and Michael (2024) trained Llama-3-8B debaters this way on QuALITY-HARD, hard multiple-choice questions about long stories. The judge was a fine-tuned GPT-4-Turbo that saw only the debate, not the story. The judge was 4 percentage points more accurate on debates between the fully trained debaters than on debates between the starting ones (p<10−6).
The authors also trained consultancy, where one model argues for an assigned answer with no opponent, and found no such gain. Across checkpoints the judge was right 77 percent of the time on debates and 68 percent on single consultancies.
Why does the opponent help? The authors checked the obvious story, that each debater refutes the other's misleading claims. It explained little. A judge shown two separate consultancies side by side, one for each answer, was right 75 percent of the time, close to debate's 77, though neither side ever answered the other. Most of the gain came from the judge seeing the best evidence for both answers. The trained consultant, by contrast, quoted less evidence and repeated itself more. Its habits persuaded the judge it was trained against far more than they persuaded a different, untrained judge model.
Language Self-Play (Kuba et al. 2025) shows the other side of a learned referee. One model plays two roles. The challenger writes queries meant to be hard, and the solver answers them. A reward model scores the answers, and a KL penalty toward the starting model keeps the challenger's queries meaningful. The full method adds a quality score that the starting model, prompted as a judge, gives each query and answer.
The authors started from Llama-3.2-3B-Instruct and used no training data. They measured win rates on AlpacaEval, a standard set of instruction prompts, against the starting model, with Llama-4-Maverick as the judge. On this scale the starting model itself scores 26.5 percent. The full method reached 36.4 percent and the version without the quality score 32.0 percent, while GRPO trained on real instruction data reached 38.8 percent.
The quality score fixes a failure the authors saw early on. With a different reward model in their first experiments, the game degenerated. The solver learned to answer most queries in Python, which that reward model liked and people do not. Self-play against a learned referee is an optimizer aimed at the referee.
Curricula that write their own problems
An opponent can also be a teacher that writes the solver's problems. One role proposes tasks and another solves them. Reward the proposer for tasks that are hard but not impossible for the solver. Then the pair builds its own curriculum, a sequence of tasks whose difficulty rises with the solver's skill.
With language models, the two roles are played by one network (Absolute Zero) or by two copies trained from the same base model (R-Zero). The question is always what makes a proposed task worth solving.
Why tasks of middling difficulty? Because that is where learning happens. Recall GRPO, the reinforcement learning method of §18.4. It samples a group of attempts at each task and scores each attempt by how much better it did than the group's average, a score called its advantage.
The general statement has three parts, all from earlier chapters. For a task solved with probability p, the reward R∈{0,1} has variance p(1−p). If the solver's log-odds of success on the task are a parameter ϕ, so that p=σ(ϕ), then the gradient of success is dp/dϕ=p(1−p). And a group of G attempts is mixed with probability 1−pG−(1−p)G. All three vanish at p=0 and p=1 and are largest in between.
The two rewards aim at different points of that range. R-Zero's reward peaks at exactly p^=21, like p(1−p). Absolute Zero's reward peaks at the hardest task that is solved at least once, rˉsolve=1/G, a deliberate push toward the edge of what the solver can do. The cell draws all four curves.
Python · cell 6
The pattern across the four is the chapter's argument again. The loops grounded in a program (an executor, tests, a proof checker) kept improving, and the loop grounded in its own votes degraded as it pushed. When you design a proposer-solver loop, the first question is what checks the answers, and the second is whether that check stays reliable as the tasks get harder.
Core
Learnability rewards for a proposer
Write two functions that score proposed tasks.
proposer_rewards(outcomes) takes an integer array of shape (n_tasks, G) of 0 or 1 solver results. It returns four arrays of shape (n_tasks,), in this order. They are the success rates rˉsolve, Absolute Zero's reward rprop, the uncertainty reward 1−2∣rˉ−21∣, and the reward variance rˉ(1−rˉ).
majority_agreement(answers) takes an integer array of shape (n_tasks, m) of the solver's final answers, given as answer ids. It returns the pseudo-labels (the most frequent answer per task, with ties going to the smallest id) and the agreement rates p^ (the fraction of answers equal to the pseudo-label).
import numpy as np
def proposer_rewards(outcomes):
r = outcomes.sum(axis=1)
azr = 1 - r
rzero = 1 - 2 * (r - 0.5)
return r, azr, rzero, r * (1 - r)
Tests, hints, verified solutions, and AI help, with Pro at $7.99 a month.
Choosing a self-play scheme
The schemes differ in what converges, what you ship, and what each step costs.
scheme
converges in two-player zero-sum games
what you deploy
cost per step
where it is used
best response to the last self
no, it can cycle forever
the newest policy
one best response
naive baselines; fine in transitive games
AlphaZero-style self-play with search
empirically, in perfect-information games with a strong value function
the newest network plus search
many games, each with hundreds of simulations per move
regret matching and counterfactual regret minimization
yes, the averages, within O(1/T)
the average policy
a regret update per decision point
poker
PSRO with a Nash meta-solver (double oracle)
yes, in finitely many steps in finite games
a mixture over the population
a reinforcement learning best response plus a growing payoff table
research on general games
leagues with exploiters
no guarantee, built to reduce exploitability
the main agent
many agents trained in parallel
AlphaStar
Read more
Silver et al. (2017). Mastering the game of Go without human knowledge. AlphaGo Zero, with the full search algorithm, the training pipeline, and the raw-network-versus-search Elo comparison in the Methods.
🎬 RL Course by David Silver - Lecture 10: Classic Games · Google DeepMindDavid Silver covers minimax search, Nash equilibria, and self-play reinforcement learning in classic games. It is the lecture-length background for both halves of this section.🎬 Self-Play by Noam Brown · Cooperative AI FoundationThe co-creator of Libratus, Pluribus, and CICERO explains why self-play converges in two-player zero-sum games and why it breaks in general-sum games played with people.🎬 FAR Research: Adversarial Policies Beat Superhuman Go AIs · FAR.AIThe authors show how an adversarial policy beats KataGo at superhuman settings. It makes the gap between strength and exploitability concrete.🎬 AlphaGo - The Movie | Full award-winning documentary · Google DeepMindThe story of the 2016 Lee Sedol match, including move 37, which shows what search plus a learned policy and value network looks like from the board.