braindecode.models.Brant#
- class braindecode.models.Brant(n_outputs=None, n_chans=None, chs_info=None, n_times=None, input_window_seconds=None, sfreq=None, *, patch_size=250, on_non_divisible='pad', embed_dim=256, ffn_dim=384, temporal_n_layers=4, spatial_n_layers=2, n_heads=8, n_freq_bands=8, band_power_sfreq=256.0, drop_prob=0.1, channel_strategy='native', channel_strategy_kwargs=None)[source]#
Brant from Zhang et al. (2023) [Brant2023].
Foundation Model Attention/Transformer
Architecture Overview
Brant models intracranial neural signals (sEEG/iEEG) in four stages [Brant2023]:
Split every channel into non-overlapping temporal patches.
Combine a linear patch projection with learned temporal positions and a spectral-power embedding.
Apply a temporal Transformer within each channel, followed by a spatial Transformer across channels at each patch index.
Mean-pool the channel-patch representation and classify it with a Braindecode downstream head.
Macro Components
Brant.patch_tokenizerOperations. Crops an incomplete tail and reshapes the signal into non-overlapping patches of
patch_sizesamples.Role. Preserves the raw samples consumed by both the linear patch projection and the spectral-power calculation.
Brant.band_powerandBrant.temporal_encoderOperations. A periodogram is summed over the eight rhythmic bands in
BRANT_FREQ_BANDS. Their log powers softmax-weight learned band embeddings, which are added to projected patches and temporal positions before self-attention within each channel.Role. Fuse time- and frequency-domain information while capturing long-range dependencies between consecutive patches.
Brant.spatial_encoderOperations. Self-attention is applied across all channels sharing a patch index.
Role. Capture spatial correlations without a fixed channel vocabulary or channel-specific parameters.
Brant.final_layerOperations. Mean-pool the encoded channel-patch grid, then apply a single linear layer.
Role. Adapt the upstream encoder to Braindecode classification. This pooling and head are not part of the masked-reconstruction pretraining objective.
Temporal, Spatial, and Spectral Encoding
Temporal: learned patch positions and the temporal Transformer preserve patch order and model long-range activity within each channel.
Spatial: the spatial Transformer attends across the channels at every temporal patch index.
Spectral: log power in theta, alpha, beta, and five gamma bands weights eight learned frequency embeddings.
Additional Mechanisms
The upstream reconstruction projection is retained in
Brant.spatial_encoderas part of the source architecture, although classification does not consume its output. Brant has no class token, soreturn_features=Truereturnscls_token=None. The learned temporal positions require the runtime signal length to equal the configuredn_times. As no parameter is channel-specific, the number of channels may differ from the configuredn_chans, between batches and within one batch when the recordings are padded to a common count andch_mask(seeforward()) flags the real ones. A window that is not a multiple ofpatch_sizeis right zero-padded toceil(n_times / patch_size)patches by default (on_non_divisible).The upstream model operates on signals down-sampled to 250 Hz, but its band-power features are computed at a fixed 256 Hz (upstream
pre_utils.py:54andutils.py:36), whatever the true rate; seeband_power_sfreqbelow. At a different rate the band edges shift and the pretrained embeddings change (by up to 0.55 in our checks).The defaults are a modest, ready-to-run configuration. The paper’s large architecture uses
patch_size=1500(6 s),embed_dim=2048,ffn_dim=3072,temporal_n_layers=12,spatial_n_layers=5,n_heads=16, andn_times=22500(15 patches, 90 s).Important
Pretrained weights.
braindecode/brant-pretrainedholds the official weights converted to this implementation. All 210 shared tensors of the official checkpoint load unchanged; the encoder outputs of the port match the official code within 1e-5 on identical inputs. It uses the large configuration above; the classification head is braindecode’s and is not pretrained:model = Brant.from_pretrained( "braindecode/brant-pretrained", n_outputs=2 )
Added in version 2.0.
- 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.
patch_size (
int) – Number of time samples per patch fed to the encoders. Default 250 (1 s at 250 Hz). The paper’s large architecture uses 1500 (see above).on_non_divisible (
str) – HowPatchTokenizertreats a time axis that is not a multiple ofpatch_size(right zero-pad, crop, or raise). The reference implementation crops ("crop"); both give the same model and output whenn_timesis a multiple ofpatch_size.embed_dim (
int) – Model widthD(patch embedding size). Default 256.ffn_dim (
int) – Inner dimension of the Transformer feed-forward blocks. Default 384.temporal_n_layers (
int) – Number of layers in the temporal Transformer encoder. Default 4.spatial_n_layers (
int) – Number of layers in the spatial Transformer encoder. Default 2.n_heads (
int) – Number of attention heads in both encoders. Default 8.n_freq_bands (
int) – Number of frequency bands used by the frequency encoding. Default 8 (must matchlen(BRANT_FREQ_BANDS)).band_power_sfreq (
float) – Sampling rate the upstream code assumes when it computes the eight band powers: 256 Hz, although the data are 250 Hz (Brant_src/utils.py:36). Keep the default to load the released weights faithfully;sfreqdescribes the data and is not used by the band-power features.drop_prob (
float) – Dropout probability. Default 0.1.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
If some input signal-related parameters are not specified, there will be an attempt to infer them from the other parameters.
References
[Brant2023] (1,2)Zhang, D., Yuan, Z., Yang, Y., Chen, J., Wang, J. and Li, Y., 2023. Brant: Foundation Model for Intracranial Neural Signal. In Thirty-seventh Conference on Neural Information Processing Systems, NeurIPS. Code: yzz673/Brant (Apache-2.0).
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 Brant # Train your model model = Brant(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-brant-model", commit_message="Initial model upload", model_card_kwargs={"datasets": ["BNCI2014_001"]}, )
Loading a model from the Hub:
from braindecode.models import Brant # Load pretrained model model = Brant.from_pretrained("username/my-brant-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 = Brant.from_pretrained("username/my-brant-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 = Brant.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 (
Tensor) – Input of shape(batch, n_chans, n_times);n_chansmay differ from the construction one.return_features (
bool) – IfTrue, return the pooled encoder embedding instead of the class logits, as{"features": pooled, "cls_token": None}(braindecode foundation-model convention). Brant pools over channels and patches and has no class token, hencecls_tokenisNone. A TorchScript-compiled model returns the logits instead.ch_mask (
Tensor|None) –(batch, n_chans)mask of real channels, seecheck_ch_mask(). Padded channels affect no output.
- Returns:
Class logits of shape
(batch, n_outputs), or the feature dict{"features", "cls_token"}whenreturn_featuresis set.- Return type:
torch.Tensor or dict