Official codebase for BEEMO as presented in "Scaling Neural Motor Decoding via Decoupled Behavioral Pretraining"
BEEMO learns a behavior prior across many sessions and reuses it when decoding behavior from spikes on a new recording. The prior can be learned together with the neural data, or decoupled from it and learned on behavior alone, with a neural encoder attached afterwards.
This repository supports two neural encoders: POYO, a latent-bottleneck transformer with spike tokenization, and NDT, which uses binned tokenization.
This project has been developed on Python3.11, with environment management using uv. To setup the environment, do:
source utils/venv_setup.shThis also installs xformers, which needs a CUDA GPU. Runs use precision=bf16 or fp16; fp32 is not supported by the attention kernels.
Follow the steps below to pretrain and finetune your own BEEMO model.
To preprocess datasets, run brainsets prepare on each pipeline in preprocess/:
brainsets prepare preprocess/perich_miller_population_2018 --local --raw-dir ../data/raw --processed-dir ../data/processed --cores 8
brainsets prepare preprocess/gallego_carracedo_lfp_2022 --local --raw-dir ../data/raw --processed-dir ../data/processed --cores 8
brainsets prepare preprocess/ma_miller_adversarial_bci_2023 --local --raw-dir ../data/raw --processed-dir ../data/processed --cores 8
brainsets prepare preprocess/churchland_shenoy_neural_2012 --local --raw-dir ../data/raw --processed-dir ../data/processed --cores 8- Pretraining uses the first three. Churchland is only needed for the Jenkins finetuning recordings.
- Gallego and Ma-Miller are downloaded from Dryad, which needs API credentials. Create them at datadryad.org (My account → API) and set
DRYAD_APP_IDandDRYAD_APP_SECRETbefore running.
To pretrain on behavior and neural data together:
python train.py ckpt.enable=trueTo pretrain on behavior alone, which is the first stage of the decoupled route:
python train.py --config-name beemo_behavior_only_pretrain ckpt.enable=trueTo pretrain on neural data alone, without behavioral pretraining:
python train.py --config-name base_pretrain ckpt.enable=true- We use Hydra for managing configs.
- Options for
model=can be found inconfigs/model/*.yaml. E.g.model=beemo_ndt - The data would be read from
../data/processedby default. - The checkpoints would be stored in
../ckptby default. - Other available configurations can be found in
configs/base.yamlandconfigs/beemo_pretrain.yaml
The training script would print a "run_id" for the corresponding run. Use this to finetune the checkpoint on each held-out recording:
python utils/run_finetune.py --ckpt ../ckpt/<run_id>/epoch_99.ptFor the decoupled route, use a behavior-only checkpoint and train a fresh neural encoder on top of it:
python utils/run_neural_finetune.py --ckpt ../ckpt/<run_id>/epoch_99.pt --encoder poyo- Both scripts loop over all 27 recordings. Pass
--recordingsto run a subset, and--dry-runto print the commands without running them. --unfreeze-at-epochcontrols gradual unfreezing.-1unfreezes everything immediately.run_finetune.py --few-shotswitches to the few-shot split.run_neural_finetune.py --encoder ndtuses the NDT encoder.
To finetune on a single recording:
python train.py --config-name finetune \
ckpt.load_from=../ckpt/<run_id>/epoch_99.pt \
data=perich_miller_ft data.args.recording_ids="['t_20130820_random_target_reaching']" \
finetuning.enable=true finetuning.unfreeze_at_epoch=-1To train one recording from scratch:
python train.py --config-name single_session data.args.recording_ids="['t_20130819_center_out_reaching']"To sweep hyperparameters per recording with Optuna:
python utils/run_sweep.py --model poyo- Options for
--modelarepoyo,ndt,linear,mlpandgru. - Ray runs locally.
--gpu-reqand--cpu-reqset the per-trial resource share, and--num-samplesthe number of trials per recording. - Each model defines its own search space as
create_search_spaceandprocess_tunable_params.
To pretrain BEEMO with your own neural encoder, replace the POYO or NDT encoder in src/model/beemo_poyo.py or src/model/beemo_ndt.py with your custom encoder.
If you find this repository useful in your research, please consider giving a star ⭐ and a citation
TODONote
This project utilizes code from and was influenced by nuclr by Vinam Arora. The baselines code was adapted from ibl-bwb by Alexandre Andre and Shivashriganesh Mahato.
