braindecode.models.MVPFormer#
- class braindecode.models.MVPFormer(n_outputs=None, n_chans=None, chs_info=None, n_times=None, input_window_seconds=None, sfreq=None, *, segment_len=2560, d_model=256, n_layers=4, n_heads=8, n_head_kv=4, d_inner=512, local_window=10, global_att=True, max_segments=110, max_channels=128, drop_prob=0.1, activation=<class 'torch.nn.modules.activation.SiLU'>, pooling='mean', channel_strategy='native', channel_strategy_kwargs=None)[source]#
MVPFormer from Carzaniga et al. (2026) [Carzaniga2026].
Foundation Model Attention/Transformer
MVPFormer model overview from [Carzaniga2026].#
Multi-variate parallel attention (MVPA) from [Carzaniga2026].#
Added in version 1.6.1.
A foundation model with multi-variate parallel attention for heterogeneous multi-variate iEEG. The raw signal is tokenised channel-wise into continuous wavelet embeddings and processed by a decoder-only (Llama2-style) transformer whose self-attention is decomposed into content, time-relative and channel-relative terms over a
(segment, channel)token grid [Carzaniga2026].Architecture Overview
MVPFormer combines three ideas to model heterogeneous multi-variate iEEG [Carzaniga2026]:
Continuous wavelet tokenization. A db4 wavelet encoder maps each fixed-length signal segment (per channel) to a continuous embedding, rather than a discrete vocabulary, preserving fine signal structure.
Multi-variate parallel attention (MVPA). Self-attention over the 2D
(segment, channel)token grid is decomposed into three additive terms – content, time-relative and channel-relative – so the temporal and spatial axes are modelled jointly at the attention level.Llama2-style decoder. Parallel attention and MLP blocks, grouped-query attention and causal masking in time, trained to predict the next-in-time embedding (generative pre-training).
Macro Components
MVPFormer.patch_tokenizer+MVPFormer.patch_embed(Wavelet encoder)Operations.
PatchTokenizersplits the raw signal \(\mathbf{x} \in \mathbb{R}^{C \times T}\) into non-overlapping segments ofsegment_lensamples. Each segment passes independently through a fixed db4 discrete wavelet decomposition, is RMS-normalised, and is linearly projected to a continuous embedding \(\mathbf{e}_{c,t} \in \mathbb{R}^{d}\) (_WaveletPatchEmbed). The wavelet transform has no learnable parameters; only the norm and projection are trained. Role. Turns the heterogeneous raw signal into a(segment, channel)grid of continuous tokens whose frequency content is exposed by the wavelet sub-bands.MVPFormer.blocks(MVPA decoder stack)Operations. A stack of
_MVPABlockmodules in the parallel attention/MLP configuration \(\mathbf{o} = \mathbf{o} + \text{attn}(\text{ln}(\mathbf{o})) + \text{mlp}(\text{ln}(\mathbf{o}))\) (Megatron-LM style) with RMSNorm and a SwiGLU MLP. Each block computes multi-variate parallel attention (_MVPAttention) between tokens at grid positions \((c,t)\) and \((c',t')\) as a sum of three terms:\[\begin{split}\mathbf{a}^{\text{MVPA}}_{c,t,c',t'} &= \mathbf{x}_{c,t}^\top W_q^\top W_{k_e}\,\mathbf{x}_{c',t'} + \mathbf{u}^\top W_{k_e}\,\mathbf{x}_{c',t'} && \text{(content)} \\ &\;+ \mathbf{x}_{c,t}^\top W_q^\top W_{k_t}\,\mathcal{T}_{t-t'} + \mathbf{v}^\top W_{k_t}\,\mathcal{T}_{t-t'} && \text{(time-relative)} \\ &\;+ \mathbf{x}_{c,t}^\top W_q^\top W_{k_c}\,\mathcal{C}_{c-c'} + \mathbf{w}^\top W_{k_c}\,\mathcal{C}_{c-c'} && \text{(channel-relative)}\end{split}\]where \(\mathcal{T}\) and \(\mathcal{C}\) are learnable time and channel positional codebooks and \(\mathbf{u}, \mathbf{v}, \mathbf{w}\) are learnable bias terms. Attention is causal in time and uses grouped-query attention. Role. Models content, temporal and spatial dependencies jointly, producing one output embedding per input segment.
MVPFormer.final_layer(Classification head)Operations. The last time-segment of the decoder output is pooled over channels (
pooling="mean"or"concat") and passed through a linear layer. Role. Maps the pooled representation ton_outputsclass logits.
Temporal, Spatial, and Spectral Encoding
Temporal: Time is the first grid axis. The time-relative attention term encodes the signed distance \(t-t'\) between segments (shared across channels) in Transformer-XL fashion, and attention is causally masked so a segment only attends to the past. Content attention is restricted to a local window of
local_windowsegments while the relative term still spans the full context.Spatial: Channels are the second grid axis. The channel-relative attention term encodes the relative distance \(c-c'\) between channels (shared across time); being relative, it is montage-agnostic and can recover a connectivity map from random initialisation, independent of the absolute electrode layout.
Spectral: Frequency content is captured at tokenization: the db4 discrete wavelet decomposition of each segment yields multi-resolution sub-band coefficients before projection, so spectral structure is embedded in every token rather than learned by explicit band-pass filters.
Additional Mechanisms
Grouped-query attention.
n_head_kvkey/value heads are shared acrossn_headsquery heads to reduce memory and compute.Relative terms and content window. The time- and channel-relative terms are quadratic in one axis and constant in the other (computed once and broadcast), and a relative-shift trick yields all relative offsets in one pass. The local content window bounds each query’s effective context, but this reference implementation still materialises the full
(segment*channel)-squared content-attention matrix before masking; the TritonFlashMVPAkernel that avoids that cost is not ported, so memory scales quadratically with the total number of tokens.Variable channel counts. With
ch_maskandpooling="mean", one batch can mix channel counts; each sample gives its unpadded output.Generative pre-training (reference only). Upstream, MVPFormer is pre-trained to predict the next-in-time embedding with a contrastive loss and fine-tuned with LoRA. This braindecode implementation provides the architecture; the Triton
FlashMVPAkernel and the contrastive pre-training loop are not included.
- Parameters:
n_outputs (int) – Number of outputs of the model. This is the number of classes in the case of classification.
n_chans (int) – Number of EEG channels.
chs_info (list of dict) – Information about each individual EEG channel. This should be filled with
info["chs"]. Refer tomne.Infofor more details.n_times (int) – Number of time samples of the input window.
input_window_seconds (float) – Length of the input window in seconds.
sfreq (float) – Sampling frequency of the EEG recordings.
segment_len (
int) – Length of each temporal segment in samples.d_model (
int) – Token embedding dimension.n_layers (
int) – Number of decoder blocks.n_heads (
int) – Number of attention (query) heads.n_head_kv (
int) – Number of key/value heads (grouped-query attention).d_inner (
int) – Hidden dimension of the SwiGLU MLP.local_window (
int) – Size, in segments, of the causal local content-attention lookback window.global_att (
bool) – Whether to use the global content-attention term.max_segments (
int) – Size of the segment (time) embedding table; must be >= number of segments produced from the input.max_channels (
int) – Size of the channel embedding table; must be >=n_chans.drop_prob (
float) – Dropout rate (embedding, attention and residual).activation (
type[Module]) – Activation class used in the SwiGLU MLP (defaulttorch.nn.SiLU).pooling (
str) – How to pool the last segment over channels before the head."mean"(default, as used for seizure detection) is montage-agnostic;"concat"flattens channels and ties the head ton_chans.channel_strategy (
str) – How any montage reaches the backbone (pretrained models only; see Channel strategies: any montage in)."native"keeps the model as it is."exact","zero","nearest","idw","spline","field","source","region","wiener"(callmodel.channel_layer.fitfirst) or"latent"map the montage ofchs_info(or of thechs_infogiven toforward) onto the backbone’s channels with aChannelLayer. Saved in the config.model(x)andmodel.forward(x)both apply the layer.channel_strategy_kwargs (
dict|None) – Options of the strategy (e.g.{"reg": 1e-2}for"spline").
- Raises:
ValueError – If some input signal-related parameters are not specified: and can not be inferred.
Notes
The defaults are a small, CI-friendly configuration. The published model sizes are MVPFormer-S (75M,
d_model=768, n_layers=12, n_heads=12, n_head_kv=4, d_inner=1728) and MVPFormer-M (1.2B,d_model=2048, n_layers=24, n_heads=16, n_head_kv=8, d_inner=5632); both use 5-second segments at 512 Hz, i.e.segment_len=2560.References
[Carzaniga2026] (1,2,3,4,5)Carzaniga, F. S., Hersche, M., Sebastian, A., Schindler, K., & Rahimi, A. (2026). A foundation model with multi-variate parallel attention to generate neuronal activity. In The Fourteenth International Conference on Learning Representations. https://openreview.net/forum?id=5M1YOW3bRq
Hugging Face Hub integration
When the optional
huggingface_hubpackage is installed, all models automatically gain the ability to be pushed to and loaded from the Hugging Face Hub. Install with:pip install braindecode[hub]
Pushing a model to the Hub:
from braindecode.models import MVPFormer # Train your model model = MVPFormer(n_chans=22, n_outputs=4, n_times=1000) # ... training code ... # Push to the Hub; ``datasets`` and ``base_model`` go to the card model.push_to_hub( repo_id="username/my-mvpformer-model", commit_message="Initial model upload", model_card_kwargs={"datasets": ["BNCI2014_001"]}, )
Loading a model from the Hub:
from braindecode.models import MVPFormer # Load pretrained model model = MVPFormer.from_pretrained("username/my-mvpformer-model") # Data the weights were trained on, from the Hub model card print(model.card_data.datasets if model.card_data else None) # Load with a different number of outputs (head is rebuilt automatically) model = MVPFormer.from_pretrained("username/my-mvpformer-model", n_outputs=4)
Extracting features and replacing the head:
import torch x = torch.randn(1, model.n_chans, model.n_times) # Extract encoder features (consistent dict across all models) out = model(x, return_features=True) features = out["features"] # Replace the classification head model.reset_head(n_outputs=10)
Saving and restoring full configuration:
import json config = model.get_config() # all __init__ params with open("config.json", "w") as f: json.dump(config, f) model2 = MVPFormer.from_config(config) # reconstruct (no weights)
All model parameters (both EEG-specific and model-specific such as dropout rates, activation functions, number of filters) are automatically saved to the Hub and restored when loading.
See Loading and Adapting Pretrained Foundation Models for a complete tutorial.
Methods
- forward(x, return_features=False, ch_mask=None)[source]#
Decode a batch of signals.
- Parameters:
x (torch.Tensor) – Input of shape
(batch, n_chans, n_times). Samples with fewer channels are padded along the channel axis and flagged bych_mask.return_features (
bool) – IfTrue, return the pooled last-segment embedding instead of the class logits, as{"features": pooled, "cls_token": None}(braindecode foundation-model convention). MVPFormer has no class token, hencecls_tokenisNone.ch_mask (
Optional[Tensor]) –(batch, n_chans)mask of real channels, seecheck_ch_mask(). Each sample is processed as if unpadded. Needspooling="mean".
- Returns:
Class logits of shape
(batch, n_outputs), or the feature dict{"features", "cls_token"}whenreturn_featuresis set.- Return type:
- reset_head(n_outputs)[source]#
Replace the classification head for a new number of outputs.
This is called automatically by
from_pretrained()when the user passes ann_outputsthat differs from the saved config. Override in subclasses that need a model-specific head structure. Implementations keep changed constructor arguments in sync withself._update_init_kwargs, so that a saved model can be loaded back. Implementations requiring positive outputs can also useself._set_n_outputsto validate and record the new value.- Parameters:
n_outputs (int) – New number of output classes.
Examples
>>> from braindecode.models import BENDR >>> model = BENDR(n_chans=22, n_times=1000, n_outputs=4) >>> model.reset_head(10) >>> model.n_outputs 10
Added in version 1.4.