File size: 7,557 Bytes
5a19a36 6d736b4 5a19a36 6d736b4 5a19a36 | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 | ---
license: mit
library_name: braindecode
tags:
- braindecode
- pytorch
- safetensors
- meg
- bbl
- self-supervised
- foundation-model
datasets:
- CamCAN
---
# BBL (pretrained, CamCAN)
Weights of the MEG encoder of *The Brain's Bitter Lesson* (Jayalath et al., ICML 2025),
pretrained on CamCAN with the band, phase and amplitude pretext tasks, for
[`braindecode.models.BBL`](https://braindecode.org/stable/generated/braindecode.models.BBL.html),
converted from the authors' checkpoint to braindecode's parameter names. The class is
added by [braindecode#1553](https://github.com/braindecode/braindecode/pull/1553)
(braindecode 2.1).
```python
from braindecode.models import BBL
model = BBL.from_pretrained("braindecode/bbl-pretrained", n_outputs=2)
features = model(x, return_features=True)["features"] # (batch, 528)
```
The linear head (`final_layer`, `n_outputs=2` in `config.json`) is not part of the
release: it is PyTorch's default init under `torch.manual_seed(0)`. Passing `n_outputs` to
`from_pretrained` replaces it. Fine-tune or linear-probe before use.
<!-- braindecode:training-data -->
## Training data
The data that shaped these weights. The ids are the `datasets:` field of this card,
which braindecode reads into `model.card_data.datasets` when you call
`from_pretrained` (MOABB class names for MOABB datasets, OpenNeuro / NEMAR
accessions, Hub ids otherwise). `nm`/`on` ids are datasets on [NEMAR](https://nemar.org)
(`on` = NEMAR's copy of the OpenNeuro dataset with the same number). Rows marked
`private:` are data the authors did not release; they are not in `datasets:`.
| `datasets:` id | Dataset | Stage | Modality |
|---|---|---|---|
| `CamCAN` | [Cambridge Centre for Ageing and Neuroscience (Cam-CAN) MEG data, Shafto et al. 2014 / Taylor et al. 2017](https://cam-can.mrc-cbu.cam.ac.uk/dataset/) | pretraining | MEG |
- self-supervised band/phase/amplitude pretext tasks; 583 Cam-CAN subject rows trained (train split; rows with non-zero Adam state)
- Sources: https://github.com/neural-processing-lab/the-brains-bitter-lesson/blob/3965a2be11677d9c2b9cecb88109a0af6bf19d1c/README.md; checkpoint hyper_parameters (inspected 2026-11-06, meg-ports-20261106/bbl/weights/CHECKPOINT.md and evidence/parity.log); arXiv:2406.04328 Sec. 4 Datasets.
## Intended input
- MEG, `(batch, n_chans, 125)`: CamCAN's 306 Elekta `MEG*` channels in FIF order (the
projector is indexed by position; inputs with fewer channels are zero-padded to 306, as
the reference collator does). `dataset_index` defaults to slot 0 (CamCAN).
- Preprocessed as in the authors' `data/preprocess.py` and `data/utils.py`: band-pass
0.1-125 Hz with 50 and 100 Hz notches, resampled to 250 Hz, 0.5 s windows (125 samples);
each channel scaled by the median and interquartile range fitted on its recording,
clipped to `[-5, 5]`, and the mean of the first 0.5 s subtracted. `forward` only does
the zero-padding.
- `subject_index` row `d * 1024 + s` for subject `s` of dataset slot `d`. Only CamCAN
subject rows are trained; the `trained_subjects` buffer flags those 583 rows and drives
the mean-subject fallback used when no `subject_index` is given.
## Source
- Paper: D. Jayalath, G. Landau, B. Shillingford, M. Woolrich, O. Parker Jones. *The
Brain's Bitter Lesson: Scaling Speech Decoding With Self-Supervised Learning.* ICML 2025.
[arXiv:2406.04328](https://arxiv.org/abs/2406.04328)
- Code: [neural-processing-lab/the-brains-bitter-lesson @ `3965a2be11677d9c2b9cecb88109a0af6bf19d1c`](https://github.com/neural-processing-lab/the-brains-bitter-lesson/tree/3965a2be11677d9c2b9cecb88109a0af6bf19d1c) (MIT)
- Weights: the checkpoint "pretrained with CamCAN" linked from the README of that
repository ("Pre-trained checkpoints"), hosted on Google Drive (file id
`1cYdKDYoIupjoMfq5cEWgB-W74XhztWEw`), downloaded 2026-11-06: 509,226,678 bytes, sha256
`94a35ca9bb8ca00941ce355d1b5cd97e4984b689209317a4eb18a3560a8e940b`. A PyTorch Lightning
2.5.0.post0 `Pretrainer` checkpoint (original name
`camcan_preproc_full_cont-best-epoch=02-val_loss=1.26.ckpt`; epoch 2, global step 60507;
`input_dim=306, model_dim=512, subject_embedding_dim=16, projector_dim=1024`, tasks band,
phase, amp).
## Conversion
`convert.py` (in this repository) was run with braindecode at
`bruAristimunha/braindecode@388ac6cb96361c2df3d5b530172ed6662b9e6a65` (branch `feat/meg-bbl`, PR #1553):
```
python convert.py bbl.ckpt <out_dir>
```
It keeps the `backbone.*` tensors, renames them to braindecode's keys (the old-style
`weight_g`/`weight_v` weight norm maps to `parametrizations.weight.original0/1`, which
computes the same `torch._weight_norm`), fills the `trained_subjects` buffer with the
subject rows the optimizer updated (non-zero Adam second moment; the original keeps that set
in a Python attribute that is not saved), loads everything into
`BBL(n_chans=306, n_outputs=2, n_times=125, sfreq=250.0)` and calls `save_pretrained`.
Tensor values are copied unchanged.
Dropped (training only): the SSL projector, the band/amplitude/phase pretext classifiers,
and the Lightning/optimizer state.
| file | sha256 |
|---|---|
| `model.safetensors` | `3f5022d2564762917d5b9d0df35060b8f0dd4f09128cc9cb076d5fd6aed193c3` |
| `pytorch_model.bin` | `7d0da29ad7d4404917bfa70cf6b4b3c692dcbc10501eec9ec100fb5c785679bb` |
| `config.json` | `71ba8c6efac12d7595f0723522c090400017a9b41255a8f620847a1313699f7f` |
| `convert.py` | `c3388e146017e55aa439dfba995ea8e5a06efe3e4d77acd3f97b98112b950581` |
## Verification
`BBL.from_pretrained(<this repo>, strict=True)` (loaded tensors equal `convert.py` applied
to the original checkpoint) against the original `Backbone` with the same weights and
inputs, CPU float32, eval mode, 4 windows of 0.5 s: features, logits, loss, input
gradients and the gradients of all 55 backbone parameters and of the head are equal
(max-abs difference 0.0) with 306 sensors; with 204 sensors (zero-padded to 306) the
features are equal. The mean-subject fallback (batch 1) differs by 3.7e-8 in the
16 subject-embedding features (the mean is taken in another order); the encoder part is
equal.
## License and provenance
`license: mit` follows the repository that distributes the checkpoint. The code of
[the-brains-bitter-lesson](https://github.com/neural-processing-lab/the-brains-bitter-lesson)
is MIT ([licence](https://github.com/neural-processing-lab/the-brains-bitter-lesson/blob/main/LICENSE),
Copyright (c) 2025 Dulhan Jayalath). The weights are distributed by the authors through
that repository's README (Google Drive link) without a separate weight licence. They are
re-hosted here unmodified in converted form (renamed keys, training-only parts dropped),
with attribution to the authors. Authors or rights holders who want this copy changed or
removed: please open an issue at https://github.com/braindecode/braindecode/issues and it
will be taken down.
## Citation
```bibtex
@inproceedings{jayalath2025bbl,
title = {{The Brain's Bitter Lesson: Scaling Speech Decoding With Self-Supervised Learning}},
author = {Jayalath, Dulhan and Landau, Gilad and Shillingford, Brendan and Woolrich, Mark and Parker Jones, Oiwi},
booktitle = {Forty-second International Conference on Machine Learning (ICML)},
year = {2025},
organization = {PMLR}
}
@article{aristimunha2025braindecode,
title = {Braindecode: a deep learning library for raw electrophysiological data},
author = {Aristimunha, Bruno and others},
journal = {Zenodo},
year = {2025},
doi = {10.5281/zenodo.17699192},
}
```
|