braindecode.models.DuIN#
- class braindecode.models.DuIN(n_outputs=None, n_chans=None, chs_info=None, n_times=None, input_window_seconds=None, sfreq=None, *, patch_size=100, on_non_divisible='pad', n_neural=16, n_filters=(128, 128, 16), kernel_sizes=(19, 3, 3), strides=(10, 1, 1), n_layers=8, n_heads=8, head_dim=64, ffn_dim=320, head_hidden_dim=128, activation=<class 'torch.nn.modules.activation.ReLU'>, attn_drop_prob=0.2, drop_prob=0.2, channel_strategy='native', channel_strategy_kwargs=None)[source]#
Du-IN from Zheng et al. (2024) [DuIN2024].
Foundation Model Convolution Attention/Transformer
Architecture Overview
Du-IN decodes speech from intracranial (sEEG) signals with region-level tokens: instead of one token per channel, the few channels recorded in a language-related region (ventral sensorimotor cortex, superior temporal gyrus) are fused into a single token per 100 ms patch [DuIN2024].
Project the channels linearly into a small hidden “neural” space.
Cut the signal into non-overlapping patches and encode each patch with a stack of strided 1D convolutions into one patch embedding.
Add fixed sinusoidal temporal embeddings and run a Transformer encoder over the patch sequence.
Flatten the encoded sequence and classify it with a one-hidden-layer MLP.
Macro Components
DuIN.spatial_projectionOperations. A linear layer from the
n_chansinput channels ton_neuralhidden channels, applied at every time sample.Role. Fuses the channels of the region into a common neural space. Its weights give the per-channel contribution scores used by the authors to select about 10 channels per subject.
DuIN.spatial_encoderOperations. Each patch of
patch_sizesamples goes throughConv1d+BatchNorm1dblocks (n_filters,kernel_sizes,strides); the output, time-major, is flattened into oneembed_dim-dimensional patch embedding.Role. Turns a patch of raw signal into a region-level token.
DuIN.encoderOperations. Post-norm Transformer layers whose attention applies layer normalisation to the queries and keys of each head (as LaBraM), followed by a ReLU feed-forward block.
Role. Models the dynamics across the patch sequence.
DuIN.head_hiddenandDuIN.final_layerOperations. The encoded
(n_patches, embed_dim)sequence is flattened, mapped tohead_hidden_dimunits with a ReLU, then ton_outputsby a linear layer.Role. The upstream “label prediction head” of the Du-IN CLS model.
Pretraining
Du-IN is pretrained per subject in two stages: a VQ-VAE learns a discrete codebook of patch embeddings, then a masked model (Du-IN MAE) predicts the codebook indices of 50% masked patches. Fine-tuning (“Du-IN (mae)”, 62.70% top-1 accuracy over the 61 words, averaged over 12 subjects) loads the encoder of the MAE and trains it with the head above. Only the classification model is ported here: the VQ-VAE, the codebook and the MAE token head are not.
Differences from the reference
The upstream head ends with a sigmoid and is trained with
F.cross_entropy(torch.sigmoid(logits), target). The port returns the logits, as every braindecode classifier. Train with that loss to reproduce the paper: fine-tuning the released MAE checkpoints on the 61-word task (12 subjects x 6 seeds) gives 60.2% top-1 with it and 55.6% with the cross-entropy on the logits.The upstream subject layer maps a one-hot subject id to a channel-to-neural matrix. The released checkpoints are single-subject, so it is a plain linear layer (
spatial_projection) here; the multi-subject variant (“Du-IN (poms)”) is not ported.The paper describes the patch convolutions as depthwise; the released code and checkpoints use full
Conv1dlayers, which the port follows.The temporal embedding table is rebuilt from
n_timesand not stored in the state dict (it has no parameters).
Important
Pre-trained weights. The authors release one Du-IN checkpoint per subject (001 to 012) and pretraining stage (
mae, the paper’s Du-IN, andvqvae) of their 61-word dataset (CC BY 4.0). They are converted to this class on the Hugging Face Hub atbraindecode/duin-pretrained(subj-<subject>/<stage>/ model.safetensors; the rootmodel.safetensorsissubj-001/mae). Each was trained on that subject’s 10 selected channels at 1000 Hz, so it only fits that subject’s montage. The head is not pretrained:model = DuIN.from_pretrained( "braindecode/duin-pretrained", filename="subj-002/mae/model.safetensors", )
The encoder matches the upstream
duin_clsmodel to float precision on identical inputs.load_state_dictalso accepts the original upstream checkpoints (liulab-repository/Du-IN,pretrains/duin/ <subject>/<stage>/model/checkpoint-399.pth) withstrict=False.Added in version 1.8.2.
- 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. Default 100 (100 ms at 1000 Hz), as the released model.on_non_divisible (
str) – HowPatchTokenizertreats a time axis that is not a multiple ofpatch_size(right zero-pad, crop, or raise). The input window is padded or cropped before the spatial projection. The reference implementation requires a multiple ("error"); all three give the same model and output whenn_timesis a multiple ofpatch_size.n_neural (
int) – Number of hidden channels ofspatial_projection. Default 16.n_filters (
tuple[int,...]) – Output channels of each patch convolution. Default(128, 128, 16).kernel_sizes (
tuple[int,...]) – Kernel size of each patch convolution. Default(19, 3, 3).strides (
tuple[int,...]) – Stride of each patch convolution. Default(10, 1, 1). Their product must dividepatch_size.n_layers (
int) – Number of Transformer layers. Default 8.n_heads (
int) – Number of attention heads. Default 8.head_dim (
int) – Dimension of each attention head. Default 64 (so the attention width, 512, is larger thanembed_dim, as upstream).ffn_dim (
int) – Inner dimension of the feed-forward blocks. Default 320.head_hidden_dim (
int) – Hidden units of the classification head. Default 128.0gives a single linear layer on the flattened sequence.activation (
type[Module]) – Activation of the feed-forward blocks and of the head. DefaultReLU, as upstream.attn_drop_prob (
float) – Dropout on the attention weights. Default 0.2.drop_prob (
float) – Dropout after the first feed-forward layer. Default 0.2.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
[DuIN2024] (1,2)Zheng, H., Wang, H.-T., Jiang, W.-B., Chen, Z.-T., He, L., Lin, P.-Y., Wei, P.-H., Zhao, G.-G., & Liu, Y.-Z. (2024). Du-IN: Discrete units-guided mask modeling for decoding speech from intracranial neural signals. Advances in Neural Information Processing Systems 37 (NeurIPS 2024). arXiv:2405.11459. Code: https://github.com/liulab-repository/Du-IN (MIT).
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 DuIN # Train your model model = DuIN(n_chans=22, n_outputs=4, n_times=1000) # ... training code ... # Push to the Hub model.push_to_hub( repo_id="username/my-duin-model", commit_message="Initial model upload", )
Loading a model from the Hub:
from braindecode.models import DuIN # Load pretrained model model = DuIN.from_pretrained("username/my-duin-model") # Load with a different number of outputs (head is rebuilt automatically) model = DuIN.from_pretrained("username/my-duin-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 = DuIN.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)[source]#
Decode a batch of signals.
- Parameters:
x (
Tensor) – Input of shape(batch, n_chans, n_times).return_features (
bool) – IfTrue, return the flattened encoded sequence the head consumes,(batch, n_patches * embed_dim), as{"features": features, "cls_token": None}(braindecode foundation-model convention; Du-IN has no class token). A TorchScript-compiled model returns the logits instead.
- Returns:
Class logits of shape
(batch, n_outputs), or the feature dict whenreturn_featuresis set.- Return type:
torch.Tensor or dict
- load_state_dict(state_dict, *args, **kwargs)[source]#
Also accept an upstream Du-IN checkpoint (
duin_mae/duin_cls).Upstream keys are renamed to this implementation. The pretraining parts (
mask_emb, the VQ codebook, the MAE token head), the fixed temporal table and the upstream classification head are dropped, so load such a checkpoint withstrict=False.- Parameters:
state_dict – The description is missing.
*args – The description is missing.
**kwargs – The description is missing.