braindecode.models.CORTEG#
- class braindecode.models.CORTEG(n_outputs=None, n_chans=None, chs_info=None, n_times=None, input_window_seconds=None, sfreq=None, patch_size=16, hi_patch_size=25, embed_dim=512, depth=8, num_heads=8, mlp_ratio=4, drop_prob=0.0, drop_path=0.1, activation=<class 'torch.nn.modules.activation.GELU'>, n_chans_pos=145, merge_strategy='average', n_merge_blocks=4, knn_k=8, adapter_hidden=128, n_fourier_freqs=32, fourier_max_freq=50.0, gate_bottleneck=16, on_non_divisible='pad')[source]#
CORTEG from Yang et al. (2026) [Yang2026b].
Attention/Transformer Foundation Model Channel
CORTEG overview, reproduced from the official repository (
LiuyinYang1101/CORTEG).#Added in version 2.1.
Architecture Overview
A scalp-EEG foundation model,
STEEGFormer, adapted to intracranial (ECoG) recordings. The transformer stays the pretrained one; around it, a spatial adapter places each electrode by its 3D position, and a second token stream carries the high-gamma activity the scalp model was never trained on. The paper trains only the spatial adapter, the high-gamma patch embedding, LoRA on the lastn_merge_blocksblocks with their LayerNorms, and the head (about 297 K parameters for the small backbone); this module builds the network, and LoRA and freezing are left to the training code.Macro Components
Dual-stream tokenizer (
CORTEG.patch_embed,CORTEG.patch_embed_hi). Operations: the low-frequency streamxis cut into patches ofpatch_sizesamples, the high-gamma streamx_hiinto patches ofhi_patch_size, each linearly embedded and the high-gamma tokens average-pooled to the low-frequency count. The high-gamma embedding starts from the pretrained low-frequency one, linearly interpolated to its patch size.KNNSoftFourier spatial adapter (
CORTEG.channel_adapter). Operations: a soft branch maps each electrode position to softmax weights over the 142 positioned slots of the pretrained channel embedding (CORTEG.channel_pos, kept frozen) and returns their weighted sum; the last bias starts from a Gaussianknn_k-nearest- neighbour kernel over the slots’ scalp positions, so the soft branch starts as a nearest-electrode interpolation. A Fourier residual (n_fourier_freqslog-spaced frequencies per axis, up tofourier_max_freq, zero-initialized output) adds a position-specific correction. Role: replace the scalp channel embedding, which knows no intracranial electrode.Transformer encoder (
CORTEG.encoder). Operations: thedepthpretrained pre-norm ViT blocks of ST-EEGFormer, over a CLS token and the (time-patch, channel) tokens of the low-frequency stream.Late fusion (
merge_strategy). Operations:"average"replaces the low-frequency tokens by their mean with the high-gamma tokens before the lastn_merge_blocksblocks;"layerwise_gate"adds the high-gamma tokens after every block, scaled per block and per sample by a small gate network that starts at zero.Read-out (
CORTEG.norm,CORTEG.final_layer). Operations: layer norm, mean over all tokens (CLS included), linear head.
Inputs
The paper decomposes the raw signal into two streams, both z-scored per channel with training-set statistics:
x: the low-frequency stream, resampled to 128 Hz (the 16-sample patches of the pretrained model then span 125 ms);x_hi: the 70-200 Hz Hilbert envelope at 200 Hz, so that its 25-sample patches line up with those ofx.
With MNE,
raw.copy().filter(70, 200).apply_hilbert(envelope=True) .resample(200)givesx_hi. Withoutx_hithe model readsxalone, as the paper’s low-frequency-only ablation.Electrode positions are 3D coordinates in metres (the paper’s MNI coordinates), passed as
posor read fromchs_info.Pre-trained weights
The ST-EEGFormer small backbone, with the high-gamma embedding warm-started from its low-frequency one, loads from the re-hosted checkpoint; the adapter, gate and head keep their initialization:
model = CORTEG.from_pretrained( "braindecode/corteg-small-pretrained", n_outputs=5, n_times=128, chs_info=chs_info, )
The authors’ Stanford model (finger flexion, nine patients pooled) is re-hosted with its LoRA factors folded in:
model = CORTEG.from_pretrained( "braindecode/corteg-stanford-pooled", chs_info=chs_info )
Note
The outputs match the reference implementation for the same weights and inputs, for both merge strategies.
ch_maskis an addition: the reference batches one patient at a time.- 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) – Patch size of the low-frequency stream (16 for the released backbones).hi_patch_size (
int) – Patch size of the high-gamma stream.embed_dim (
int) – Token embedding dimension (512 for the small backbone).depth (
int) – Number of Transformer encoder blocks.num_heads (
int) – Number of attention heads.mlp_ratio (
int) – Hidden-to-embedding ratio of the MLP blocks.drop_prob (
float) – Dropout rate.drop_path (
float) – Stochastic-depth rate (max of a linear schedule overdepth).activation (
type[Module]) – Activation layer class of the feed-forward blocks and of the MLPs of the spatial adapter and the gate.n_chans_pos (
int) – Size of the pretrained channel vocabulary (145 for small/base/large).merge_strategy (
str) – Fusion of the high-gamma stream: the paper’s default mean before the lastn_merge_blocksblocks (the released Stanford adapter), or the layer-wise gate (its BrainTreebank results).n_merge_blocks (
int) – Number of blocks after the"average"fusion.knn_k (
int) – Number of nearest scalp slots of the soft branch’s initial kernel.adapter_hidden (
int) – Hidden width of the spatial adapter’s MLPs.n_fourier_freqs (
int) – Number of Fourier frequencies per axis of the residual branch.fourier_max_freq (
float) – Highest of those frequencies, log-spaced from 1, in radians per metre.gate_bottleneck (
int) – Hidden width of the layer-wise gate.on_non_divisible (
str) – How a stream whose length is not a multiple of its patch size is handled (right zero-pad, crop, or raise); the reference crops.
- 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
[Yang2026b]Yang, L., Sun, Q., Van Dyck, B., Calvo Merino, E. & Van Hulle, M. M. (2026). CORTEG: Foundation models enable cross-modality representation transfer from scalp to intracranial brain recordings. Advances in Neural Information Processing Systems (NeurIPS 2026). https://arxiv.org/abs/2605.10337
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 CORTEG # Train your model model = CORTEG(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-corteg-model", commit_message="Initial model upload", model_card_kwargs={"datasets": ["BNCI2014_001"]}, )
Loading a model from the Hub:
from braindecode.models import CORTEG # Load pretrained model model = CORTEG.from_pretrained("username/my-corteg-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 = CORTEG.from_pretrained("username/my-corteg-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 = CORTEG.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, x_hi=None, pos=None, ch_mask=None, return_features=False)[source]#
Encode a batch of intracranial recordings.
- Parameters:
x (
Tensor) – Low-frequency stream,(batch, n_chans, n_times).x_hi (
Optional[Tensor]) – High-gamma stream of the same channels,(batch, n_chans, n_times_hi). Without it the model readsxalone.pos (
Optional[Tensor]) – Electrode positions in metres,(batch, n_chans, 3)or(n_chans, 3); by default those ofchs_info.ch_mask (
Optional[Tensor]) –(batch, n_chans)mask of real channels, seecheck_ch_mask(). Padded channels take part in no attention and no pooling.return_features (
bool) – IfTrue, return{"features", "cls_token", "tokens"}: the layer-normalized patch tokens(batch, n_patches * n_chans, embed_dim), the CLS token, and the patch tokens as(batch, n_chans, n_patches, embed_dim); padded channels’ tokens are zero.
- Returns:
Outputs
(batch, n_outputs), or the feature dict.- Return type:
- reset_head(n_outputs)[source]#
Replace the linear head for a new
n_outputs.- 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.