FlyLab · brain playground

Run a trained fruit-fly brain

Each of the seven skills below is a separate 642-weight neural network, trained with Evolution Strategies and checked in NeuroMechFly v2 physics. Here it runs in your browser on the calibrated surrogate body: walking speeds and turn rates measured from the MuJoCo fly at 49 drive settings. Full physics is too heavy for a browser, so each brain's physics film and its held-out physics score are shown next to it.

What it senses (inputs, after 0.1 s smoothing)

32 hidden neurons click one to silence it

Descending drives (brain → legs)

Lesions

Silencing an antenna or eye reads that side as zero. Flies with one antenna removed tend to turn toward the intact side; see whether this brain does.

Test it on many arenas

Runs the current brain, with your lesions and silenced neurons, on random arenas from the same distribution it was trained on, with training noise on. Takes a second or two.

The same brain in MuJoCo physics

Model card

Architecture

17 inputs (10 senses + a one-hot task cue) → 32 tanh units → 2 outputs. Output d = 0.35 + 0.85·tanh(o), then a motor gate: |d| < 0.02 is exactly 0, fading to full strength by 0.10. 642 float64 weights. One network per skill.

Training

OpenAI-style Evolution Strategies (32 antithetic candidates, 16 arenas per generation, common random numbers, centered ranks, Adam), 100 generations per round in the surrogate. After every round the candidate is validated in MuJoCo; a brain is only replaced if it does better in physics. Mastery goes in three levels (6, 12, 24 validation arenas). The quoted test score uses 8–32 arenas that are never used to choose a brain.

Known limits

Odor and light are smooth analytic fields, not turbulent plumes or rendered vision. The brain is learned, not wired from the connectome. This page runs the surrogate body, which matches physics closely for steady walking but not every transient.

Downloads

    Use a brain in Python

    import numpy as np
    theta = np.load("odor_seek.npy")          # 642 float64
    W1, b1 = theta[:544].reshape(17, 32), theta[544:576]
    W2, b2 = theta[576:640].reshape(32, 2), theta[640:]
    
    def act(senses, task_index):
        """senses: the 10 values world.sense() returns; task_index: 0-6."""
        x = np.concatenate([senses, np.eye(7)[task_index]])
        d = 0.35 + 0.85 * np.tanh(np.tanh(x @ W1 + b1) @ W2 + b2)
        return d * np.clip((np.abs(d) - 0.02) / 0.08, 0, 1)   # [left, right]

    Task order: walk_forward, turn, goto, odor_seek, odor_avoid, light_seek, light_avoid. The senses come from world.py. This page's engine (flybrain.js) matches the Python code to 1e-11 on every brain (parity test).