No result paragraph for this entry was found in the log.
EXPERIMENTS.md · lines 1260–1325E27 — The fly could not learn, because its odour code was not sparse
Date 2026-09-12 · Question The environment is built; can the fly search it? ·
Provenance forager/mushroom.py, tests/test_mushroom.py,
…/{fly_build,fly_diag,fly_why,fly_learn}.py
Method. Mushroom body extracted with its olfactory input (type regex
^(KC|MBON|PAM|PPL|APL)|PN): 5,311 cells, 1,066,603 edges - 4,064 Kenyon cells, 97
output neurons, 316 PAM, 24 PPL1, 2 APL, 595 projection neurons, 61,210 plastic
KC->MBON synapses. A composition enters as an odour, one element per channel. Reward
is the free energy from E25. Trained online over 200 compositions, scored on 60 held
out, against ridge regression on the composition vector.
First result: the circuit was deaf. Every composition scored the same to within
0.0001, and the compartments disagreed identically about all of them. Three measurements
found why:
- The odour arrived at the Kenyon cells as a current of 0.0040 against a random bias
of 0.048 - twelve times larger. The cells were responding to their own noise.
- 97.8% of Kenyon cells were active for every composition. The 9.7% "sparse code"
reported by the sparsity measure was the tail of that bias noise.
- With a dense code every update touches all 61,210 synapses alike, so learning one
composition overwrites every other. Measured directly: after 40 strong updates the
weights moved 18% and the spread of scores went down, 2.39e-4 to 1.77e-4. It was
unlearning.
Three causes, all in what was left unspecified rather than in the anatomy.
- Two scales had no measured value and were never set. Contact counts are not
conductances, so the gain from an odour to the Kenyon cells is arbitrary; a Kenyon
cell's threshold is not in a connectome at all. Left at 1 and at random noise, the
odour lands below the noise. Both are now fixed by properties of real flies - an
odour drives the Kenyon cells, and the code it evokes is a few percent sparse.
- tanh does not rectify. Raising a threshold under tanh does not silence a cell, it
drives it strongly negative - and a cell that votes while silent leaves the code
dense. Kenyon cells now rectify, as a firing rate must. Sparsity 97.8% -> 4.0%.
- Dopamine was global. One teaching signal was applied to all 97 output neurons
though 40 are appetitive and 57 aversive, so the two halves cancelled. Each plastic
synapse now carries the valence of the compartment it ends in.
Second result: it learns, and it is not good enough. With the sparse code, training
moves the ranking reliably - Spearman -0.226 -> +0.151 on held-out compositions, and
the same swing at every sparsity target tried (-0.302 -> +0.143 at 3%, -0.134 -> +0.147
at 10%). Before the fix, training moved it the wrong way or not at all.
The circuit learns about a quarter of what a linear model gets from the composition
alone. That is the honest position, and it matches the earlier finding on a different
task (0.755 against 0.948). The mechanisms are now right; the performance is not.
What is now in place: a genuinely sparse odour code, compartment-specific dopamine,
calibrated gain and threshold, and evaluate() returning the spread across compartments
- the circuit's own uncertainty, from anatomy rather than an ensemble bolted beside it.
The module had no tests at all; it now has six, on a synthetic connectome so they
check mechanism rather than one asset's numbers.
Not yet done. The search loop itself - proposing under a budget and measuring regret
against random - is not worth running until the ranking is better than a linear model's.
The next thing to test is the APL feedback inhibition, which is in the circuit (2 cells)
and is what actually normalises the code in a fly; here sparsity is imposed by a fitted
threshold instead, which is a stand-in for it.