Autoresearch · Othello

Training a model to play Othello with Autoresearch

Autoresearch lets an AI agent run its own machine-learning experiments: editing the code, training, checking results, and trying again, hundreds of times. I pointed it at a small model and asked it to learn Othello from nothing but lists of moves. It learned to play legal games, then to actually win them. And when I looked inside, the model had built a picture of the board.

↓ scroll to see how it went
A layered Othello board with flipping discs and a lattice revealing the model’s internal board representation
What Autoresearch is

The AI runs the experiments

Improving an AI model normally means a slow human loop: change some code, train the model, check whether it got better, try again, over and over. Autoresearch, a project by Andrej Karpathy, hands that entire loop to an AI agent so it can run on its own, hundreds of times.

I gave it a concrete job with a clear scorecard: train a small model to play Othello. The catch is that the model is never told the rules. It only ever sees finished games written out as lists of moves, like d3 c5 f6 …, the way you might pick up a game by watching thousands of them.

Othello is a good test because you can simply check whether the moves the model makes are legal. No opinion required.

How it worked

A five-minute experiment, on repeat

The AI agent ran the same loop over and over, unsupervised, on a graphics chip I rented by the hour:

1
Tweak the training recipe
→
2
Train the model for exactly 5 minutes
→
3
Measure whether it improved
→
4
Keep the change if better, undo it if not
↻ then do it again: a fresh idea every few minutes, all night

Everything was fair game for the AI to change: the size of the model, how fast it learned, the shape of its internal wiring. My only job was to decide what counts as "better", the goal it optimizes toward. That choice turned out to matter more than I expected.

The first run  · 91 experiments · about 10 hours

First, I asked it to be a good guesser

For the first run, "better" meant one thing: get better at predicting the next move in a game. The bet is that if the model can reliably guess what comes next, it must be picking up something real about how Othello works.

Under the hood: how it learns to guess

The model reads the moves so far and, for every square it could play next, outputs a probability. Training rewards it for putting high probability on the move that actually came next. The penalty at each step is the surprise of the real move, and the model is nudged to make that average as small as possible:

loss = − 1N ∑ ln p(next move) the average surprise across every move in the training games. Lower means it guessed better.

To grade it fairly on games it had never seen, that surprise is turned into bits per byte, a standard way to measure how tightly a model can compress data:

val_bpb = total surprise (nats)ln 2 × total bytes lower is better. This is the single number the agent drove down, run after run.

Here is why the bet pays off: the model is far too small to memorize games, so the only way to keep predicting well is to internally track the board and work out which moves are even legal. Learning to guess quietly forces it to learn the game.

It worked. Over about ten hours, the AI kept finding small improvements. Each dot below is one experiment; the line tracks its best result so far.

How well it predicted the next move (lower is better)

Here's the surprising part. I never asked the model to follow the rules, only to predict moves. But as it got better at guessing, it started actually playing legal Othello on its own. Watch the difference between its early attempts and its best moment in this run:

Hour one
Hour seven
Left: a partly-trained model plays some real moves, then slips onto an illegal square (✕). Right: a later model plays a clean game start to finish.
Then it found a loophole

Partway through, the AI discovered a clever data trick: it multiplied its training games eightfold by rotating and mirroring the board, which is symmetric (a move known as dihedral, or 8x, data augmentation). That nudged its prediction score higher but quietly made its actual play worse. It was optimizing the thing I measured, not the thing I wanted. That gap between a proxy and the real goal is a classic trap, sometimes called Goodhart's law: when a measure becomes the target, it stops being a good measure.

So I changed the question.

The second run  · 39 experiments · about 5 hours

Then I asked it to actually play

This time "better" meant the thing I really cared about: play a complete, fully legal game, start to finish, with no illegal moves at all. A much harder bar, and one the loophole from before couldn't fake.

Under the hood: a harder test

The first score was teacher-forced: at every step the model was shown the real game history and judged only on the single next move. That measures prediction, not play. "Actually play" swaps in a different test. The model now generates a whole game by itself, feeding its own moves back in as it goes, and we check what fraction of those games stay legal from the first move to the last:

complete-game rate = fully legal gamesgames played a game counts only if it stays legal from the first move to the last. Measured over a fixed batch of 512 self-play games at a set randomness, so the agent cannot cheat the number.

This is much harder. A single illegal move anywhere ruins the whole game, and because the model is now running on its own output with no teacher to correct it, small mistakes compound. It is exactly the test the earlier prediction loophole could not fake, so pushing on it drove the model toward genuinely legal play.

It climbed fast, and this run knew when to quit. I'd set it to stop automatically once it stopped improving, so it wrapped itself up after about five hours instead of running until the money ran out.

Share of games played legally start to finish (higher is better)

By the end, the model had genuinely learned the game, from nothing but lists of moves:

–
of its games are legal from start to finish
of individual moves are legal
–
win rate against random play

The two goals really do pull apart. This model plays far better, yet it is much worse at the first run's test of raw next-move prediction: about 4.2 bits per byte against 0.72 for the earlier champion, where lower is better. And when the AI reached for that same board-symmetry trick again here, it threw it away, because under this goal it lowered legal play instead of lifting the score. The same idea, opposite verdict, once the target changed.

The trained model playing itself: real games, filling the board.
The third run  · 35 experiments · about 4 hours

Then I asked it to win

Playing by the rules is a low bar. A model can make only legal moves and still play badly, handing the game away move after move. So for the third run I raised the stakes to the thing I'd wanted all along: win the game, not just finish it legally.

Under the hood: keeping score of skill

To measure skill you need opponents. So I built a fixed ladder of four, from easy to hard: a player that moves at random, a greedy one that grabs the most pieces every turn, and two that think ahead, searching one and two moves into the future. The model plays a set batch of games against each, and its score is simple:

strength = wins + ½ · drawsgames played averaged across the four fixed opponents. 0.5 against an opponent is an even match; above 0.5 it wins more than it loses.

The opponents, the number of games, and the starting positions are all locked down, so the agent can't cheat the number with a lucky streak. And "play" means just what it sounds like: the model looks at the game so far and, of the moves that are actually legal, makes the one it rates highest. No search, no rulebook, no looking ahead, only the instincts it built from watching finished games.

Same loop as before: a fresh idea, five minutes of training, keep it only if the score clearly rose. Each dot is one experiment; the line tracks its best score so far.

Its score against the opponent ladder (0.5 is an even match; higher is better)

It climbed from barely above a coin-flip to genuinely skilled play. Graded afterward on a larger, fully deterministic set of games, the final model wins convincingly against the easier opponents:

88%
of games won against random play
76%
won against a greedy piece-grabber
90%
won against a one-move-lookahead search

That is real skill, learned from nothing but lists of moves, with no rules given and no searching ahead when it plays. It meets its match against an opponent that looks two moves ahead, and a deeper search still beats it, since the model never learned to plan that far. But reaching the level of a searching player on instinct alone is a lot for so small a network.

Two changes drove most of the gains, and both were about restraint. The agent made the model smaller, trimming it to four layers, and added dropout, which forces it not to lean too hard on any single detail. With so few training games to learn from, a bigger model just memorized them; a leaner one had to pick up the general shape of good play instead. The champion ended up at about 3.5 million parameters, a twelfth the size of the second run's model, yet a far stronger player.

And the single biggest jump? An old friend. That same board-symmetry trick from the first run, the one the second run threw away, paid off again here, the largest single win of the night. The first run embraced it, the second discarded it, the third welcomed it back. The same idea, a third verdict, decided each time by nothing but the goal I had set.

Looking inside

But does it actually "get" the board?

Here's what nagged me. The model only ever saw move lists, never a board. So is it really tracking the game, or just parroting patterns it has seen? There's a way to check, using a technique called mechanistic interpretability, which studies a model's inner workings to understand how it reaches its answers. You peek inside the model's internal activity as it reads a game and ask whether the current board is written down in there somewhere.

Under the hood: how we looked

As the model reads a game, every layer turns the moves so far into a long list of numbers: its internal working state at that moment. To see whether the board is written into those numbers, we freeze the finished model so it can no longer change, feed it thousands of positions, and record that internal state at each step.

Then we train a deliberately simple reader, a single linear layer that looks only at those numbers and tries to name the contents of every square. It never sees the board or the rules, only the model's internal state:

guess(square) = argmax( W · h + b ) h is the model's internal state; W and b are all the reader learns. It picks whichever of mine, yours, or empty scores highest. "Linear" means it can only take a weighted sum of the numbers, nothing cleverer.

That simplicity is the whole point. A more powerful reader could reconstruct the board by replaying the moves itself, which would prove nothing about the model. A plain linear one can only surface what the model has already written down clearly. So if it can name the squares, the board really is sitting inside the model, in a form simple enough to read straight off.

It turns out the board really is in there. Reading the model's internal activity, we can reconstruct what's on each square in the model's own frame (mine, yours, or empty, which reads far more cleanly than black versus white) with 92.8% accuracy, far above the roughly 33% you'd get by guessing. The picture also sharpens with depth, climbing from about 80% in the model's middle layers to 93% in its later ones. The further a square moves from paper toward ink below, the more reliably the board shows up in the model's internal activity:

–
–

We can even watch it happen. On the left is the board the model has reconstructed internally as it reads a game; on the right is the real board. They track each other closely: the model is holding the game in its head, move by move:

what the model pictures
the real board

One more check. The model above learned to play legally; the one from the third run learned to win, and it is far smaller, just four layers. So I looked inside that one too. The board is right there again, readable from its internal activity at about 90% accuracy, and it takes only those four layers to get there. A tiny network that both plays a strong game and clearly pictures the board it was never shown.

This mirrors a well-known result called "Othello-GPT," where researchers found the same thing in a larger model: evidence that models trained only to predict can build genuine internal models of the world they're predicting. (The original paper; a follow-up showed the board is held as a simple linear pattern in "mine versus yours" terms, the same framing used here.)

In short

Running on its own, Autoresearch trained a small model to play legal Othello, then to genuinely win, working around a pitfall it found along the way and ending with models that had quietly built a map of the board they were never shown.

All told: about 165 experiments across the three runs, close to 20 hours of compute on rented GPUs, for under $100. Every run is in the logs.