release 6e71f00 · 8 sessions · DANDI:000021

cortexflow

how it was measured

The protocol in brief. The full text is in the paper and in the repository’s research record; every rule below is enforced in code and most are pinned by a test.

the split

Each natural movie is shown in two blocks per session, tens of minutes apart. One epoch boundary per session is set at the start of the earliest late block. Segments before it train (first 80%) and validate (last 20%); segments after it are test, in full; segments straddling it are discarded. The test period is therefore strictly in the future and shows the same stimulus the model trained on — which removes the confound between elapsed time and a change of stimulus that a plain chronological split would have on this dataset.

Primary resolution 0.05 s, fixed before any comparison. Context 40 bins (2 s). Multi-step horizons 1, 5, 10, 25, 50 bins.

the score

Metrics are computed on spike counts after mapping predictions back from the normalised space. The headline skill is R² against each unit’s training-period mean rate: referencing the test mean would credit a model with information it does not have. Every metric is per unit, reported as a distribution and as a rate-weighted mean.

Uncertainty resamples whole sessions, never individual bins, because adjacent 50 ms bins are strongly dependent. Model comparisons are paired. When a family’s best entrant is needed it is chosen by validation score.

leakage, and what stops it

RiskControlTest
Shuffled time binsSplits are assigned by recording segment on the session clock, never by row.test_train_val_test_are_chronologically_ordered
A window straddling two splitsA window is admissible only if every bin it reads or predicts carries its own split's code.test_no_window_straddles_a_split_boundary
Train and validation windows sharing binsAn embargo of one context length between them.test_embargo_separates_train_and_val_windows
A window across a segment joinWindow indices are per segment.test_no_window_crosses_a_segment_boundary
Test statistics in normalisationThe normaliser is fitted on training bins only.test_normalizer_uses_only_training_statistics
Smoothing that mixes in the futureOnly one-sided kernels exist in the code; none is on by default.test_causal_boxcar_never_looks_forward
An architecture that peeks aheadCausal masks, and the encoders are probed directly.test_convolutional_and_attention_encoders_do_not_look_ahead
An empty split making checks vacuousThe split validator refuses any plan with an empty split.test_validator_rejects_a_shuffled_plan
Flagged recording intervalsProbe flags drop that probe's units; session flags mask the bins.test_masked_bins_are_never_touched_by_any_window
A biased inverse transformRetransformation bias is added back from training residuals.test_sqrt_inversion_is_biased_without_correction_and_unbiased_with_it

tuning, and its limits

Classical models tune lag, ridge penalty and latent dimension per session on validation. Each neural architecture was offered four capacity and regularisation settings, scored on the validation periods of two sessions. Every architecture chose the largest setting on the grid, which means the neural models may sit below their ceiling; a separate capacity sweep measures how much a wider network would have helped.

Neural configuration chosen on validation
ArchitectureHiddenDropoutWeight decay
rnn2560.30.001
gru2560.30.001
lstm2560.30.001
tcn2560.30.001
transformer2560.30.001
Completed runs per experiment arm
ArmRuns
primary126
covariates80
binwidth30
scaling32
capacity18
latent8
generalization1
filtering36

reproduce it

make setup
make train-smoke      # synthetic, no network, < 1 min
make preprocess       # stream 8 sessions from DANDI
make train            # tune on validation, then the benchmark
make ablations generalization latent robustness
make evaluate analyze figures paper site
make test