Fly XOX
Weights for a tic-tac-toe player that runs on the MaleCNS fruit fly connectome. The whole wiring diagram stays in (166,700 neurons, 25.6M connections), and the only trained part is three values per neuron. The browser game loads the webgpu/ folder.
Play it: https://fly.n4ze3m.com
Files
webgpu/ is the browser model, exported from training/best.pt: seven arrays split into 16 MiB chunks, 224,749,428 bytes in total. manifest.json lists each chunk with its SHA256, and the app checks every chunk before copying it to the GPU. Trained gains are already multiplied into weight and encoder. golden.json holds 12 test boards with their PyTorch logits, and webgpu-verification.json has the result of running the shaders on them. brainmap.json and brainmap.bin hold a 2D position and an annotation group for every neuron, used by the game's activity panel.
training/ is the shipped game model, run game-1: best.pt (step 2,300, optimizer state included), last.pt, untrained.pt, results.json and history.json. training/v1/ keeps the original research pilot the first version of the game used.
graph/ is the filtered connectome as a scipy sparse matrix (connectome.npz), plus MaleCNS body IDs (ids.npy), the sensory neurons (sensory.npy), the fixed board input projection (encoder.npy), and manifest.json with the source URLs and SHA256 hashes of the original downloads.
controls/ has results and histories for every other run: research runs with both recipes on real and shuffled wiring (fly-*, shuffled-*, fly-v2-*, shuffled-v2-*), the other game-model seeds (game-*), and how the shuffle was done.
analysis/ has compare.json and compare-v2.json (real vs. shuffled for each recipe), regions.json (response by annotation group and step for the shipped model), and browser-policy.json (exact game results for the page's move picker).
How it works
- The board becomes 27 one-hot values (empty, mine or theirs for each square).
- A fixed random projection feeds them into the 17,937 sensory neurons.
- Four softsign rate updates run across the full graph, starting from zero each move.
- A fixed random readout from 2,048 non-sensory neurons gives 9 move scores. Taken squares are masked.
Edge weights are synapse counts normalized per receiving neuron. GABA and glutamate neurons count as inhibitory and everything else as excitatory. Each neuron gets a trained input gain, offset and leak, 500,100 parameters in total. The two projections stay fixed.
Neurons are kept if they have a superclass in the annotations and aren't glia. Every connection between kept neurons is included, with no synapse threshold.
Research runs vs. the game model
Research runs train on 80% of positions and are scored on a held-out 10%. Rotations and mirror images of a board always fall in the same split, and any move minimax rates as best counts as correct.
The game model uses the same model and a game-aware sampling recipe, but trains on all 4,520 positions and is picked on exact game results. It has no held-out score. It exists because research models could lose every game to perfect play after opening in a corner: the position they failed to block sits in the validation split.
Real vs. shuffled wiring (research runs)
The shuffled graph keeps every neuron's in-degree, out-degree, transmitter sign and normalized input weights, and randomizes which neuron each connection comes from. Three runs per graph and recipe, same 468 test positions:
| Recipe | Graph | Test runs | Mean |
|---|---|---|---|
| Original | Real wiring | 91.2%, 91.7%, 94.0% | 92.3% |
| Original | Shuffled | 82.7%, 83.5%, 87.8% | 84.7% |
| Game-aware | Real wiring | 90.2%, 92.1%, 93.6% | 92.0% |
| Game-aware | Shuffled | 84.4%, 85.5%, 85.7% | 85.2% |
Before training, the same model picks a best move 62.8% of the time on real wiring and 55.8% on shuffled. A random legal move gets 56.9%.
Game model results
All three game-model seeds never lose to perfect play from any opening or side. The shipped seed also never loses to a random player. The page samples the opening from the network's scores softened 5x (about 42% center, 8โ13% per corner, 3โ5% per edge) and lets later moves pick any square within 85% of the best score. Exact outcomes for that picker, over every possible game:
| Win | Draw | Loss | |
|---|---|---|---|
| Fly first vs perfect player | 0% | 100% | 0% |
| Fly second vs perfect player | 0% | 100% | 0% |
| Fly first vs random player | 97.7% | 2.3% | 0% |
| Fly second vs random player | 85.0% | 15.0% | 0% |
Where the signal goes
Averaged over all boards, the biggest response outside the sensory neurons is in antennal lobe projection neurons (0.087 at the last step), and it drops off quickly after that. The mushroom body and central complex barely respond. 1,755 of the 2,048 readout neurons are in the optic lobe, 1,261 of them lamina cells L1 to L3 right behind the photoreceptors. That comes from where the input lands, not from any kind of vision: the input projection treats photoreceptors like every other sensory neuron. Full numbers are in analysis/regions.json.
Limitations
- One shuffle and three runs per graph and recipe. There's no plain MLP baseline.
- The shipped model trained on every position, so its accuracy isn't a generalization number. Use the research runs for that.
- It's a rate model with rough transmitter signs. Nothing spikes, there's no real timing, and backprop is nothing like how flies learn.
- The shaders were checked against PyTorch with wgpu-native on a CPU Vulkan driver: same moves, logits within 1.2e-5.
- Running it needs WebGPU, a 225 MB download, and storage buffers of at least ~102 MB.
License
Derived from MaleCNS v1.0 by HHMI Janelia/FlyEM, the University of Cambridge, MRC LMB, Google Research and collaborators (https://male-cns.janelia.org/), which is CC BY 4.0. These files use the same license. The training and game code is MIT.