braindecode.models.MSCFormer#

class braindecode.models.MSCFormer(n_outputs=None, n_chans=None, sfreq=None, chs_info=None, n_times=None, input_window_seconds=None, kernel_sizes=(85, 65, 45), n_filters_time=16, pooling_size=44, cnn_drop_prob=0.5, activation_cnn=<class 'torch.nn.modules.activation.ELU'>, activation_ffn=<class 'torch.nn.modules.activation.GELU'>, num_heads=8, num_layers=5, forward_expansion=4, att_drop_prob=0.5, att_positional_drop_prob=0.1, final_drop_prob=0.25, attention_scale=None)[source]#

MSCFormer from Zhao, W et al (2025) [mscformer].

Convolution Attention/Transformer

Multi-scale convolutional transformer network for motor imagery brain-computer interface.

MSCFormer Architecture

MSCFormer is an end-to-end network for classifying motor imagery (MI) tasks from EEG signals. To handle the individual variability of EEG signals and the limited receptive field of CNNs, the model combines a multi-branch multi-scale convolutional module with a Transformer encoder for global feature integration.

The architecture consists of three main components:

  1. Multi-scale convolutional module:

    • Three parallel branches with temporal convolution kernels of different widths (85, 65, 45) followed by a depth-wise spatial convolution across channels, batch normalization, activation, average pooling and dropout.

    • The branch outputs are concatenated along the feature dimension, giving an embedding size of 3 * n_filters_time.

  2. Transformer encoder module:

    • A learnable class token (BERT-style) is prepended to the embedded patches, followed by a learnable positional encoding.

    • A stack of Transformer encoder blocks with post-norm residual connections captures global dependencies across temporal patches.

  3. Classifier module:

    • The Transformer output at the class-token position is passed through dropout and a fully connected layer producing the classification logits.

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.

  • sfreq (float) – Sampling frequency of the EEG recordings.

  • chs_info (list of dict) – Information about each individual EEG channel. This should be filled with info["chs"]. Refer to mne.Info for more details.

  • n_times (int) – Number of time samples of the input window.

  • input_window_seconds (float) – Length of the input window in seconds.

  • kernel_sizes (tuple[int, int, int]) – Kernel widths of the temporal convolutions in the three multi-scale branches.

  • n_filters_time (int) – Number of temporal filters in each convolutional branch; the total embedding size is n_filters_time * len(kernel_sizes).

  • pooling_size (int) – Average pooling size in the convolutional module. The original implementation uses 44 for BCI IV-2a and 52 for BCI IV-2b.

  • cnn_drop_prob (float) – Dropout probability in the convolutional module. The original implementation uses 0.5 for subject-specific training and 0.25 for cross-subject training.

  • activation_cnn (type[Module]) – Activation function in the convolutional branches.

  • activation_ffn (type[Module]) – Activation function in the Transformer feed-forward blocks.

  • num_heads (int) – Number of attention heads in the Transformer encoder.

  • num_layers (int) – Number of encoder blocks in the Transformer.

  • forward_expansion (int) – Expansion factor of the feed-forward block hidden layer.

  • att_drop_prob (float) – Dropout probability in the attention and feed-forward residual blocks.

  • att_positional_drop_prob (float) – Dropout probability applied after the positional encoding.

  • final_drop_prob (float) – Dropout probability before the final classification layer.

  • attention_scale (float | None) – Multiplier applied to the attention logits before the softmax in braindecode.modules.MultiHeadAttention. When None (default), it reproduces the released source scale embed_dim ** -0.5 (i.e. 1 / sqrt(3 * n_filters_time)), not the more common head_dim ** -0.5: the two only coincide when num_heads == 1. Numerically verified against the original implementation (max abs logit diff < 1e-6 with matched weights); passing head_dim ** -0.5 explicitly instead gives a max abs logit diff of about 0.035 on a random smoke input.

Raises:

ValueError – If some input signal-related parameters are not specified: and can not be inferred.

Notes

This implementation is adapted from the original MSCFormer source code [mscformercode] to comply with Braindecode’s model standards. The multi-head attention is the shared braindecode.modules.MultiHeadAttention, configured through attention_scale to match the original embed_dim ** -0.5 logit scaling by default (see the parameter description above).

References

[mscformer]

Zhao, W., Zhang, B., Zhou, H. et al. Multi-scale convolutional transformer network for motor imagery brain-computer interface. Scientific Reports, 15, 12935 (2025). https://doi.org/10.1038/s41598-025-96611-5

[mscformercode]

Zhao, W. et al. MSCFormer source code: snailpt/MSCFormer

Hugging Face Hub integration

When the optional huggingface_hub package 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 MSCFormer

# Train your model
model = MSCFormer(n_chans=22, n_outputs=4, n_times=1000)
# ... training code ...

# Push to the Hub
model.push_to_hub(
    repo_id="username/my-mscformer-model",
    commit_message="Initial model upload",
)

Loading a model from the Hub:

from braindecode.models import MSCFormer

# Load pretrained model
model = MSCFormer.from_pretrained("username/my-mscformer-model")

# Load with a different number of outputs (head is rebuilt automatically)
model = MSCFormer.from_pretrained("username/my-mscformer-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 = MSCFormer.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)[source]#

Forward pass of the MSCFormer model.

Parameters:

x (Tensor) – Input tensor of shape (batch_size, n_channels, n_times).

Returns:

Output with shape (batch_size, n_outputs).

Return type:

Tensor