What’s new#

Current 1.8.1 (2026-08-31)#

Enhancements#

  • braindecode.models.BrainBERT, EpiNT, Brant, PopulationTransformer, BaRISTA, DIVER1 and MVPFormer accept a ch_mask of real channels, as returned by braindecode.datasets.pad_channels_collate(), so one batch can mix recordings with different channel counts; PopT’s ch_mask replaces key_padding_mask. Add the shared helpers braindecode.functional.check_ch_mask(), pack_channels(), unpack_channels(), masked_mean() and masked_group_norm() (#1487 by Julien Gadonneix).

  • CI: test_forward_in_dtype no longer runs the models in float16 on the CPU; torch’s CPU float16 kernels killed the test worker without a traceback in about one run in seven (the hangs of the last days), and bfloat16 covers the same dtype checks (#1474 by Bruno Aristimunha).

  • CI: a test that stops answering fails after 10 minutes with a traceback (pytest-timeout), instead of the job waiting until its own timeout; twice an xdist worker went silent during test_forward_in_dtype and the run idled for 40 minutes to 5 hours (#1473 by Bruno Aristimunha).

  • CI: the shared model tests build a 2-layer ZUNA and a narrow BENDR instead of the released 172M- and 157M-parameter configurations, which took 5.6 GB per test worker to script and serialize and killed CI runners; the registry entry of a model may now carry architecture arguments next to its signal parameters. The released configurations stay covered by test_pretrained_compat (#1472 by Bruno Aristimunha).

  • CI: test_core_dependencies_are_imported parsed the whole package once per installed distribution (215 s, the last test to finish); it parses once. The test job stops after 60 minutes instead of 6 hours when a worker hangs (#1471 by Bruno Aristimunha).

  • braindecode.functional.sinusoidal_positional_encoding() takes a base (longest wavelength); PopulationTransformer and SignalJEPA build their tables with it, unchanged (#1458 by Bruno Aristimunha).

  • Remove 59 model tests (950 lines) that only asserted output shapes or that a forward ran, every line of which the shared model suites already cover; coverage of braindecode is unchanged (#1467 by Bruno Aristimunha).

  • Add braindecode.modules.PreNormTransformerBlock (EEGConformer, MIRepNet) and PostNormTransformerBlock (CTNet, MSCFormer), replacing four pairs of private encoder classes; parameters and outputs unchanged (#1464 by Bruno Aristimunha).

  • Add braindecode.modules.LearnedPositionalEncoding (CTNet, MSCFormer) and SinusoidalPositionalEncoding (BIOT, MEDFormer); the four models’ parameters, buffers and outputs are unchanged (#1463 by Bruno Aristimunha).

  • Add braindecode.modules.PreNormBlock, the pre-norm transformer block with timm’s parameter names (norm1/attn/norm2/mlp, optional gamma_1/gamma_2 layer scale); EEGPT, EEGDINO, LUNA, NeuroRVQ and NeuroRVQTokenizer build their encoders with it, parameters and outputs unchanged (#1461 by Bruno Aristimunha).

  • Add braindecode.modules.TimmAttention, multi-head self-attention with timm’s parameter names (qkv/proj, BEiT’s q_bias/v_bias); EEGPT and EEGDINO use it with parameters and outputs unchanged (#1460 by Bruno Aristimunha).

  • Add braindecode.functional.scaled_dot_product_attention() (the shared SDPA helper, now public, with scale and an exact op-order mode); ATCNet, AttnSleep, EEGDINO, TCFormer and TMSA-Net compute their attention through it with outputs, losses and gradients unchanged bit for bit (#1457 by Bruno Aristimunha).

  • Add braindecode.functional.rotary_frequencies(), rotary_angles(), apply_rotary() and rotate_half(); BaRISTA, BrainOmni, DIVER-1, EpiNT, LUNA and TCFormer build and apply their rotary embeddings with them (parameters and outputs unchanged), and EEGPT loses a rotary code path it never used (#1456 by Bruno Aristimunha).

  • Add a test that lists every private copy of a standard block (attention, transformer block, MLP, positional encoding, norm, patch embedding, residual) in braindecode.models, so a new copy fails CI unless it is listed with a reason; the new-model checklist asks for the shared blocks (#1455 by Bruno Aristimunha).

  • Add a test that lists every private copy of a standard block (attention, transformer block, MLP, positional encoding, norm, patch embedding, residual) in braindecode.models, so a new copy fails CI unless it is listed with a reason; the new-model checklist asks for the shared blocks (#1455 by Bruno Aristimunha).

  • Add braindecode.functional.patch_count() and pad_or_crop_to_patches() (the patch-tiling helpers nine models and PatchTokenizer already used privately), now public in braindecode.functional.patches (#1459 by Bruno Aristimunha).

  • braindecode.models.ZUNA takes registers (default True, the published encoder, unchanged). registers=False drops the learned register before each patch, so the encoder runs on the patch tokens alone (half the tokens), each patch keeps its rotary position, and the head reads the patch outputs. Pretrained weights load unchanged; the register parameter is then unused and frozen (#1468 by Bruno Aristimunha).

  • braindecode.models.ZUNA runs its rotary embedding on HPU through the Gaudi bridge’s fused pairwise RoPE kernel, as a custom op whose backward is the kernel at the opposite angle: identical outputs, gradients rounded to bfloat16 once instead of once per term (within one bfloat16 ulp), and one node inside torch.compile. Gaudi2 train step at 21 channels x 1280 samples, batch 64: 2.61 -> 1.96 s eager, 1.78 -> 1.25-1.42 s with the transformer block compiled; CPU and other devices unchanged (#1461 by Bruno Aristimunha).

  • braindecode.models.ZUNA runs its rotary embedding in HPU eager mode and inside compiled regions through the Gaudi bridge’s fused pairwise RoPE kernel (lazy mode keeps the formula, which its graph compiler fuses), as a custom op whose backward is the kernel at the opposite angle: identical outputs, gradients rounded to bfloat16 once instead of once per term (within one bfloat16 ulp), and one node inside torch.compile. Gaudi2 train step at 21 channels x 1280 samples, batch 64: 2.61 -> 1.96 s eager, 1.78 -> 1.25-1.42 s with the transformer block compiled; CPU and other devices unchanged (#1461 by Bruno Aristimunha).

  • braindecode.models.ZUNA takes registers (default True, the published encoder, unchanged). registers=False drops the learned register before each patch, so the encoder runs on the patch tokens alone (half the tokens), each patch keeps its rotary position, and the head reads the patch outputs. Pretrained weights load unchanged; the register parameter is then unused and frozen (#1468 by Bruno Aristimunha).

  • Add braindecode.modules.TimmMlp, the timm-style MLP (fc1/fc2 parameter names) that EEGPT and LUNA each defined privately; their parameters and outputs are unchanged (#1454 by Bruno Aristimunha).

  • Every model has reset_parameters(), which draws new initial weights with the model’s own scheme: the layers’ PyTorch defaults, then the model’s initialization (_init_parameters), which the constructor also runs. Initial weights at construction are unchanged for every model. A new test checks, for all registered models, that seeded construction is reproducible and finite, that reset_parameters matches the constructor’s initialization, and that a model’s own initialization is not a no-op (#1452 by Bruno Aristimunha).

  • Add braindecode.modules.Residual and braindecode.modules.PostNormResidual, the residual connections that EEGConformer, MIRepNet, STEEGFormer, CTNet and MSCFormer each defined privately; their parameter names and outputs are unchanged (#1449 by Bruno Aristimunha).

  • Add braindecode.functional.init_weights_(), a per-layer-type weight initialization applied with model.apply. The 24 models that each wrote their own initialization loop (BaRISTA, BENDR, BrainOmni, CBraMod, CSBrain, DANCE, DuIN, EEGPT, LaBraM, LUNA, MAPA, MEDFormer, MVPFormer, NeuroPose, NeuroRVQ, PBT, SensingDynamics, SPARCNet, STEEGFormer, TCFormer, VEMG2Pose, …) now declare their rule with it; the initial weights of every model are unchanged (#1448 by Bruno Aristimunha).

  • braindecode.models.ZUNA: a channel without a location takes the standard 10-05 position of its name (with a warning) instead of raising, and ZUNA warns when sfreq is not its pretraining 256 Hz or when the coordinates are not in metres (they were silently clipped); channels with locations give the same model and output (#1437 by Bruno Aristimunha).

  • braindecode.models.BrainBERT takes on_non_divisible (default "pad"): a window too short for the centre-frame pooling (n_times < 1401 with the defaults) gets the missing STFT frames as zeros, half before and half after the window, with a warning, instead of raising ("crop"/"error" keep raising). braindecode.models.MAPA takes an input at another integer sampling rate and resamples it to 2048 Hz inside the model with torchaudio.transforms.Resample, with a warning (normalization="session" still needs its 32 Hz spectrogram). Long enough BrainBERT windows and 2048 Hz MAPA inputs give the same model and output as before (#1434 by Bruno Aristimunha).

  • braindecode.models.ZUNA accepts windows longer than max_seqlen patches (the release’s 8192 samples): the rotary table is extended to the window instead of raising; shorter windows are unchanged (#1433 by Bruno Aristimunha).

  • The DANCE event-detection tutorial evaluates the published checkpoint and explains that its reported subject-3 score was used for epoch selection, not independent testing (#1406 by Bruno Aristimunha).

  • braindecode.models.NeuroRVQ takes an input at another integer sampling rate and resamples it to the modality’s rate (EEG 200 Hz) inside the model with torchaudio.transforms.Resample, with a warning, instead of raising; and on_missing="drop" leaves out input channels with no pretrained slot (default "error"). At 200 Hz with known channels the model and its output are unchanged. braindecode.models.EEGCLIP keeps its BatchNorm layers on running statistics for a single-example batch in train mode, as the other BatchNorm models do (#1402 by Bruno Aristimunha).

  • braindecode.models.NeuroRVQTokenizer takes on_missing as braindecode.models.NeuroRVQ does: "drop" leaves out input channels with no pretrained slot, and the target, reconstruction and codes cover the kept channels; the default "error" keeps the previous behaviour (#1435 by Bruno Aristimunha).

  • Add braindecode.modules.resolve_channel_positions(): places channels in a name -> position bank by name (case, EEG/-REF, T3-T6 aliases, montage-qualified names such as biosemi128_A1) or as the midpoint of a bipolar A-B; on_missing raises, drops, or takes the bank entry nearest the channel’s loc. braindecode.models.REVE uses it (montage, on_missing); exact bank names give the same positions as before (#1400 by Bruno Aristimunha).

  • Add braindecode.augmentation.LabelSmoothing and braindecode.augmentation.functional.label_smoothing(), which replace class-index targets, or existing target distributions, with their convex combination with the uniform distribution over the classes; the signals are unchanged and the smoothed targets train with any distribution-accepting loss (#1401 by Li Qing).

  • braindecode.augmentation.CutMix pastes a random time region of a shuffled example into each example of the batch (Yun et al., 2019) and, like braindecode.augmentation.Mixup, returns targets for braindecode.training.mixup_criterion() (#1372 by Li Qing).

  • braindecode.models.EEGCLIP.contrastive_loss() takes distributed=True to use every DDP rank’s pairs as negatives, with the gradient of the loss on the concatenated batch even for uneven per-rank batches; the default local-batch loss is unchanged (#1320 by lindicaphxag-tech).

  • braindecode.functional.fft_conv1d() on CPU computes its per-frequency channel product as one real matmul whose output columns are the (real, imaginary) pairs of the result, read as a complex tensor without a copy: the backward no longer allocates four zero-filled copies of the product. CPU train step of braindecode.models.EEGNeX 2.6x faster on 60-s windows at 100 Hz, batch 64, 24 threads (0.47x of 1.8.1; it had become 1.17x slower) and 2.5x on 4-s windows at 250 Hz, batch 32, 2 threads; braindecode.models.TIDNet 2.0-2.7x, braindecode.models.EEGInceptionMI 1.15-1.6x; EEGNeX train-step peak memory halved. Forward-only calls with fewer rows than twice the input channels keep the previous product. Outputs and gradients change by float rounding only (#1362 by Bruno Aristimunha).

  • braindecode.models.AXON runs its unmasked attention (the spatial attention of every block) through the shared SDPA helper, so HPU eager mode uses the Gaudi bridge’s fused SDPA kernel instead of torch’s op-by-op SDPA: Gaudi eager train step 1.09x faster (21 channels x 6000 samples, batch 64); CPU, CUDA and Gaudi lazy mode run the same call as before; Gaudi eager outputs and gradients within master’s own float32 error except single gate-bias gradients of 1e-11 to 1e-9 (up to 5x their few-ulp yardstick) (#1360 by Bruno Aristimunha).

  • braindecode.models.AXON computes its banded and full temporal attention from one score matrix: both softmaxes share the query-key product, and one product with the values and one temporal_out projection serve their scale-gated mixture (the gate weights sum to one). Gaudi train step 1.10x faster in lazy mode and 1.17x in eager mode, CPU 1.05x (21 channels x 6000 samples, batch 64); outputs and gradients differ from before by float rounding of the new summation order, up to 1.6x master’s own float32-vs-float64 difference on the outputs (more on the ~1e-9 gate-bias gradients), argmax unchanged; the attention-dropout and no-band paths are unchanged (#1359 by Bruno Aristimunha).

  • braindecode.models.EEGInceptionMI takes the channels-last copy for its max pooling only on CPU: on Intel Gaudi (HPU) the layout copies made the eager train step 2.6x slower than in 1.8.1 (now back to 1.8.1’s time); CPU unchanged (#1344 by Bruno Aristimunha).

  • braindecode.models.SignalJEPA, braindecode.models.SignalJEPA_Contextual, braindecode.models.SignalJEPA_PreLocal and braindecode.models.SignalJEPA_PostLocal compute the group norm of their feature encoder from mean and variance in HPU eager mode on Intel Gaudi: torch’s group norm costs 120-190 ms per forward and backward there whatever the shape. Gaudi eager train step 0.10x (PreLocal) and 0.17x (PostLocal) at 21 channels x 6000 samples, 0.34x for SignalJEPA at 22 x 1000; same code as before on CPU, CUDA and in HPU lazy mode (#1364 by Bruno Aristimunha).

  • braindecode.models.EEGSym runs its temporal (1, k, 1) convolutions on Intel Gaudi (HPU) as conv1d on a time-last copy of the input: Gaudi’s conv3d along time, which is not the innermost axis of EEGSym’s 5-D activations, is 10-50x slower than that conv1d. Gaudi train step 0.47x in eager and 0.57x in lazy mode at 21 channels x 6000 samples; same code as before on CPU and CUDA, same state dict (#1375 by Bruno Aristimunha).

  • braindecode.functional.fft_conv1d() runs on Intel Gaudi (HPU) as overlap-save blocks with the DFT as real matmuls instead of a host FFT, and braindecode.functional.prefer_fft_conv() picks it there from 8 input channels and batch_size * n_times * kernel_size >= 8e6: Gaudi eager train step of braindecode.models.EEGInceptionMI 1.4-2.3x faster and braindecode.models.EEGNeX 2.1x faster on 60-s windows at 100 Hz, batch 64; CPU unchanged; Gaudi outputs and gradients change by float rounding only (#1341 by Bruno Aristimunha).

  • braindecode.models.EEGNeX keeps its long temporal convolution direct on Intel Gaudi (HPU) when no gradient is computed: the FFT path pays off only through the backward, so evaluation and inference on Gaudi were 1.8x (eager) and 2.2x (lazy) slower than in 1.8.1 on 60-s windows at 100 Hz, batch 64; now back to 1.8.1’s time; training, CPU and GPU unchanged; Gaudi outputs change by float rounding only (#1363 by Bruno Aristimunha).

  • braindecode.models.SignalJEPA and braindecode.models.SignalJEPA_Contextual run their transformer encoder in training with the attention through the shared SDPA helper (no _safe_softmax pass of torch’s math path, #1361), the layers otherwise op for op as torch’s: Gaudi eager train step 0.86x at 21 channels x 6000 samples; bit-identical on CPU, same dropout draws; eval, HPU lazy mode and TorchScript unchanged (#1365 by Bruno Aristimunha).

  • braindecode.models.CTNet computes the depthwise spatial convolution of its patch embedding as a matmul over the channel axis: same forward values on CPU (bit-identical outputs and batch-norm statistics), a faster backward than the grouped-convolution kernels. Train step 0.90x on CPU and 0.92x (eager) / 0.81x (lazy) on Intel Gaudi at 21 channels x 6000 samples, batch 64; 0.85x on CPU at 22 x 1000, batch 32; parameters and state dict unchanged, gradients change by float rounding (#1374 by Bruno Aristimunha).

  • braindecode.models.CSBrain runs its region embedding and the region means of every encoder layer for all regions at once (a 0/1 neighbour-selection matmul and one batched matmul per kernel; one index_add_) instead of one convolution and one mean per region: about half the operators per forward, CPU forward and train step 1.14-1.17x faster, Gaudi forward 1.30-1.45x and train step 1.36-1.56x faster; outputs change by float rounding only (#1335 by Bruno Aristimunha).

  • braindecode.models.EEGSym runs its batch norms on Intel Gaudi (HPU) on the (batch, filters, -1) view of its 5-D activations: Gaudi’s 5-D batch norm backward with the 12 electrodes innermost is 2-7x slower than the 3-D one. Gaudi eager train step 0.75x on top of #1375 at 21 channels x 6000 samples (lazy 0.95x); same batch_norm call as before on CPU and CUDA, same state dict (#1376 by Bruno Aristimunha).

  • braindecode.models.DIVER1 computes the amplitude spectrum of its spectral embedding on the device on accelerators without complex tensors (Intel Gaudi / HPU) instead of a host FFT round trip: Gaudi forward 1.02-1.12x and train step 1.02-1.10x faster; CPU unchanged (#1334 by Bruno Aristimunha).

  • braindecode.models.DIVER1 builds and overlap-adds its STCPE sliding windows with one gather and one index_add instead of unfold/fold: Gaudi forward 1.25-1.36x and train step 1.13-1.32x faster, CPU 0-1 % faster; outputs and released-checkpoint outputs unchanged, gradients change by float rounding only (#1333 by Bruno Aristimunha).

  • braindecode.models.EEGConformer runs the temporal and the spatial convolution of its patch embedding as one convolution over the channels with the composed weight and bias (the two are linear with nothing in between): no (batch, filters, channels, time) intermediate and 3.4x fewer stem FLOPs per train step. Train step 0.58x on CPU and 0.68x (eager) / 0.74x (lazy) on Intel Gaudi at 21 channels x 6000 samples, batch 64; 0.41x on CPU at 22 x 1000, batch 32; parameters and state dict unchanged, outputs change by float rounding (#1373 by Bruno Aristimunha).

  • braindecode.models.MIRepNet runs the temporal and the spatial convolution of its patch embedding as one convolution over the channels with the composed weight and bias (the two are linear with nothing in between): no (batch, filters, channels, time) intermediate and 4.3x fewer stem FLOPs per train step. Train step 0.65x on CPU and 0.63x (eager) / 0.54x (lazy) on Intel Gaudi at 21 channels x 6000 samples, batch 64; 0.60x on CPU at 22 x 1000, batch 32; parameters and state dict unchanged, outputs change by float rounding (#1377 by Bruno Aristimunha).

  • braindecode.models.LUNA computes the three group norms of its patch embedding from mean and variance in HPU eager mode on Intel Gaudi, with the group norm of braindecode.models.SignalJEPA (#1364): torch’s group-norm backward was about half of each eager train step there. Gaudi eager train step 0.53x at 21 channels x 6000 samples (batch 64) and 0.31x at 22 x 1000 (batch 32); CPU, CUDA and Gaudi lazy mode run the same group_norm call as before (bit-identical on CPU), same state dict (#1379 by Bruno Aristimunha).

  • braindecode.models.MIRepNet makes the tokens of its patch embedding contiguous. The transposed view carried through every residual add of the encoder (a sum takes the memory layout of its first operand), so each add and layer norm read strided memory. Gaudi eager train step 0.92x at 21 channels x 6000 samples, batch 64 (CPU 0.98x, lazy unchanged); outputs change by float rounding (#1378 by Bruno Aristimunha).

  • braindecode.models.NeuroRVQ and braindecode.models.NeuroRVQTokenizer compute the group norms of their multi-scale patch embedding from mean and variance in HPU eager mode on Intel Gaudi, as braindecode.models.SignalJEPA does (#1364): the backward of torch’s group norm compiled new graphs at every call there (8 per train step, about 70 ms each). Gaudi eager train step 0.22x (NeuroRVQ) and 0.39x (NeuroRVQTokenizer) at 21 channels x 800 samples, batch 64; same code as before on CPU, CUDA and in HPU lazy mode (#1382 by Bruno Aristimunha).

  • braindecode.models.REVE computes the 4-D position embedding of its default channel positions once per forward and broadcasts it over the batch instead of computing it for one identical copy per example: 3 ms instead of 10-12 ms of each Gaudi train step (21 channels x 6000 samples, batch 64; step 1.01x); explicit pos inputs are unchanged (#1347 by Bruno Aristimunha).

  • braindecode.models.ContraWR computes its STFT magnitude on the device on accelerators without complex tensors (Intel Gaudi / HPU) instead of a host STFT and a host-to-device copy of the spectrogram: Gaudi forward 4.2-7.1x and train step 2.4-5.2x faster; CPU unchanged (#1332 by Bruno Aristimunha).

  • braindecode.models.NeuroRVQTokenizer sums the per-code counts and vectors of its EMA codebook update with index_add_ instead of a dense one-hot matrix and GEMM: CPU train step 1.3x faster (22 channels, batch 32, 2 threads), Gaudi unchanged; outputs, gradients and token ids unchanged, the updated codebooks change by float rounding only (#1308 by Bruno Aristimunha).

  • braindecode.models.REVE computes the two halves of its GEGLU feed-forward as two matrix products on the row halves of the same weight instead of slicing one product, so the activation reads contiguous tensors (HPU copied the strided halves in both passes). Same parameters and state dict; train step 1.11x faster on Gaudi eager and 1.06x on CPU (21 channels x 6000 samples, batch 64), float32 rounding differences only (#1346 by Bruno Aristimunha).

  • braindecode.modules.EMACodebook sums its training EMA statistics per code with index_add_ instead of a dense one-hot matrix and GEMM: braindecode.models.TFMTokenizer CPU train step 5 % faster and braindecode.models.BrainTokenizer 1-3 % (22 channels, batch 32, 2 threads); outputs, gradients and token ids unchanged, the EMA buffers change by float rounding only (#1306 by Bruno Aristimunha).

  • The TUH datasets read the _date.txt file kept beside each EDF with json.load() instead of pandas.read_json(): 2.9 s -> 0.04 s for the 2993 TUAB date files; descriptions unchanged (#1300 by Bruno Aristimunha).

  • Add braindecode.models.Guetschel2026, the encoder shared by the 58 MAE and JEPA checkpoints of the EEG masking-geometry study (Guetschel et al., 2026). The checkpoints load with from_pretrained from the original Hugging Face repositories, with backbone features identical to the reference implementation, and hub_repo_id() builds their names. The head is a flatten and a linear layer, with an optional fixed Gaussian random projection in between (random_projection, as in the OpenEEGBench probe) (#1260 by Pierre Guetschel).

  • Add braindecode.models.DuIN (Du-IN, Zheng et al., NeurIPS 2024), an sEEG speech decoder that fuses the channels of a brain region into one token per 100 ms patch before a Transformer encoder. The authors’ per-subject Du-IN checkpoints (MAE and VQ-VAE stages, 12 subjects) are on the Hub at braindecode/duin-pretrained and match the upstream encoder to float precision. braindecode.modules.MultiHeadAttention gains head_dim and qk_norm for it (#1269 by Adam Mounir).

  • braindecode.models.MetaNeuromotorHand sums the cross-spectral bins of each frequency band with one einsum instead of a broadcast product and a sum: CPU forward and train step 3-7 % faster, Gaudi 2-10 % faster; outputs and gradients differ from before by more than float32 rounding (up to 1.6x master’s own float32-vs-float64 difference, amplified by the eigendecomposition), argmax unchanged (#1330 by Bruno Aristimunha).

  • braindecode.models.MetaNeuromotorHand rotates and half-vectorizes the MPF matrices with one precomputed index_select instead of three rolls, a stack and a permute copy: CPU train step about 2 % faster, Gaudi neutral; outputs, gradients and state dict unchanged bit for bit (#1292 by Bruno Aristimunha).

  • braindecode.models.MetaNeuromotorHand solves the eigendecompositions of its matrix logarithm in chunks on all CPU threads instead of one matrix after another on one thread (torch’s CPU eigh): train step 2.5x faster at 24 threads (21 channels x 32,000 samples, batch 64), 11-15 % at 2 threads (batch 32), 1.5x on Gaudi (the featurizer runs on the host CPU); bit-identical outputs and gradients (#1336 by Bruno Aristimunha).

  • Add braindecode.modules.layers.RMSNorm, a drop-in torch.nn.RMSNorm (same parameters and state dict) that runs the Gaudi bridge’s fused RMSNorm kernel on HPU instead of torch’s op-by-op square, mean, rsqrt and products (float32 or bfloat16 input with a weight over the last dimension; other devices unchanged). braindecode.models.REVE uses it: Gaudi train step 1.05x faster in eager mode and 1.03x in lazy mode (21 channels x 6000 samples, batch 64), differences within the Gaudi float32 error (#1348 by Bruno Aristimunha).

  • braindecode.models.CodeBrain skips the attention scores in eval mode on CPU at the default swa_window_size=1, where the window keeps only the diagonal and the attention reduces to its value projection: CPU eval forward 1.25x faster at 19 x 6000 (batch 32); training unchanged; outputs unchanged bit for bit (#1293 by Bruno Aristimunha).

  • braindecode.models.CodeBrain takes the same one-wide-window shortcut in training on CPU: the attention weights are exactly one-hot, so the block multiplies the value projection by the diagonal of the dropout mask that torch.nn.MultiheadAttention draws (same RNG stream) instead of computing all scores, their softmax, dropout and product: train step 1.2x faster at 21 x 6000 (batch 64, 24 threads) and 1.3x at 19 x 6000 (batch 32, 2 threads); outputs, gradients and dropout masks unchanged bit for bit (#1339 by Bruno Aristimunha).

  • braindecode.models.CodeBrain computes its bidirectional long convolution as a linear convolution at a 5-smooth FFT length instead of a circular one of length 2 * seq_len: Gaudi forward 2.1x and train step 1.4x faster (19 channels x 6000 samples, batch 32), CPU forward 1-16 % faster, CPU train step unchanged to 6 % faster; outputs and gradients differ from before by more than float32 rounding (up to 1.9x master’s own float32-vs-float64 difference on the released checkpoint’s logits), argmax unchanged (#1329 by Bruno Aristimunha).

  • braindecode.models.MAPA folds the (batch, array) axes before its within-array attention, so CPU attention runs as one fused 4-D torch.nn.functional.scaled_dot_product_attention() call instead of the 5-D math fallback: CPU forward 1.16x and train step 1.03x faster at 22 contacts (batch 32), 4.2 GB less peak memory in training; Gaudi unchanged; outputs and gradients change by float rounding only (relative differences below 1e-6) (#1294 by Bruno Aristimunha).

  • braindecode.modules.MultiHeadAttention (EEGConformer, CTNet, MSCFormer, MIRepNet, STEEGFormer) and braindecode.models.ZUNA run attention through the Gaudi bridge’s fused SDPA kernel in HPU eager mode, where torch’s SDPA runs op by op through the full score matrix (without a mask or dropout; lazy mode, CPU and other devices unchanged): Gaudi eager train step STEEGFormer 2.2x and ZUNA 1.7x faster (21 channels x 6000 samples), forward 1.2-2x for the other models; differences within the Gaudi float32 error (#1338 by Bruno Aristimunha).

  • braindecode.models.ZUNA rotates the rotary position pairs with one flip, the sign kept in the sine table, instead of a negated strided slice and a stack: bit-identical, Gaudi eager train step 11 % faster at 21 channels x 6,000 samples, lazy mode 2.5 % slower (#1349 by Bruno Aristimunha)

  • braindecode.models.ZUNA builds its RMS norms from braindecode.modules.layers.RMSNorm instead of torch.nn.RMSNorm (same parameters and state dict), so on HPU they run the Gaudi bridge’s fused kernel: Gaudi train step 1.07x faster in eager mode and 1.03x in lazy mode (21 channels x 6000 samples, batch 2); CPU unchanged (bit-identical), Gaudi differences within the Gaudi float32 error (#1354 by Bruno Aristimunha).

  • braindecode.models.MEDFormer computes its patch embedding, a kernel spanning all n_times rows over non-overlapping patches, as one GEMM of the patch-reshaped input with the kernel instead of a conv1d with n_times input channels (same parameters and state dict): CPU train step 1.12-1.18x faster (21 channels x 1000 samples, batch 64, 24 threads), Gaudi unchanged; float32 outputs are 3-8x closer to the float64 result than before and differ from before by up to 1.15x the model’s own float32-vs-float64 difference (#1357 by Bruno Aristimunha).

  • braindecode.models.PBT runs its attention through the shared SDPA helper of braindecode.modules.MultiHeadAttention, so in HPU eager mode attention without dropout (eval mode, drop_prob=0) uses the Gaudi bridge’s fused SDPA kernel instead of the op-by-op path through the full score matrix: Gaudi eager forward 2.0x faster (21 channels x 6000 samples, batch 64); training with attention dropout, lazy mode, CPU and other devices unchanged (outputs, gradients and dropout draws identical); eval outputs within the Gaudi float32 error (#1350 by Bruno Aristimunha).

  • braindecode.models.DANCE skips the taps of its dilated convolutions that only ever read the zero padding (kernel offset at or beyond the input length): CPU train step 0.92x and Gaudi eager 0.97x (21 channels x 6000 samples, batch 64); outputs change by float rounding only (#1343 by Bruno Aristimunha).

  • braindecode.modules.ChannelMerger (DANCE, BrainModule(use_merger=True)) computes its channel mix as (x^T @ weights^T)^T on HPU, where Gaudi’s lazy-mode graph compiler failed on weights @ x feeding a convolution’s backward: DANCE now trains in Gaudi lazy mode (train step 622 ms vs 844 ms in eager mode, 21 channels x 6000 samples, batch 64); other devices run the same code as before (#1351 by Bruno Aristimunha).

  • braindecode.models.BrainModule computes its GLU gates as a * sigmoid(b) in Intel Gaudi (HPU) lazy mode, where the graph compiler failed on aten.glu after the gate’s convolution: BrainModule now trains in Gaudi lazy mode (train step 306 ms vs 554 ms in eager mode, 21 channels x 6000 samples, batch 64); eager mode and other devices run the same code as before (#1371 by Bruno Aristimunha).

  • braindecode.models.MSCFormer runs the temporal and the depthwise spatial convolution of each patch-embedding branch as one convolution over the channels with the composed weight and bias (the two are linear with nothing in between): no (batch, filters, channels, time) intermediate. Train step 0.63x on CPU and 0.63x (eager) / 0.66x (lazy) on Intel Gaudi at 21 channels x 6000 samples, batch 64; 0.60x on CPU at 22 x 1000 (batch 32); outputs and gradients change by float rounding (#1381 by Bruno Aristimunha).

  • braindecode.models.CodeBrain aggregates its residual skip connections as one torch.stack(skips).sum(0) reduction in Intel Gaudi (HPU) lazy mode, where the graph compiler failed on the backward of the sequential sum (a skip-convolution weight-gradient node landed in two pipeline bundles): CodeBrain now trains in Gaudi lazy mode (train step 3498 ms vs 3691 ms in eager mode, 21 channels x 6000 samples, batch 64); eager mode and other devices run the same code as before (#1387 by Bruno Aristimunha).

  • braindecode.models.CodeBrain computes its bidirectional long convolution on Intel Gaudi (HPU) as a real-valued DFT (device matmuls against a cached cosine/sine basis) instead of a host torch.fft round trip: Gaudi lazy TUEG batch 64 now trains (~3.5 s/step, previously synStatus 26); CPU and CUDA keep the torch.fft path (bit-identical), TorchScript and state dict unchanged (#1390 by Bruno Aristimunha).

  • braindecode.models.MSVTNet computes the depthwise spatial convolution of each branch as a matmul over the channel axis when gradients are computed (and on CPU): same values, a faster backward than the grouped convolution’s. Gaudi train step 0.86x in eager and 0.87x in lazy mode, CPU 0.88x at 22 channels x 1000 samples (batch 32) and 0.98x at 21 x 6000 (batch 64); evaluation on Gaudi keeps the grouped convolution; outputs and batch-norm statistics unchanged on CPU, gradients change by float rounding (#1380 by Bruno Aristimunha).

  • braindecode.models.MSVTNet with large inputs (when a branch’s (batch, filters, channels, times) activation would reach 2**26 elements, e.g. 21 channels x 6000 samples at batch 64) applies each branch’s spatial weights to the input first and runs each filter’s temporal kernel on its projections, with the first batch norm’s statistics computed from the input’s autocorrelation, so that activation is never built: same function and state dict, numerical differences only. Train step at 21 x 6000, batch 64: Intel Gaudi 0.57x in eager mode and 0.78x in lazy mode, CPU 0.23x (#1384 by Bruno Aristimunha).

  • braindecode.models.TFMTokenizer computes the group norms of its frequency- and temporal-path convolutional blocks from mean and variance on Intel Gaudi (HPU), where the graph compiler failed on the native group-norm backward at the TUEG batch size (“SRAM capping too big”): TFMTokenizer now trains on Gaudi (train step about 1.5 s in eager and 8 s in lazy mode, 21 channels x 6000 samples, batch 64); CPU, CUDA and TorchScript run the same group_norm call as before (bit-identical on CPU), same state dict (#1386 by Bruno Aristimunha).

  • braindecode.models.Labram and braindecode.models.BaRISTA run attention through the Gaudi bridge’s fused SDPA kernel in HPU eager mode (without a mask or attention dropout; lazy mode, CPU and other devices unchanged): Gaudi eager train step Labram 8 % and BaRISTA 5 % faster (21 channels x 6000 samples), differences within the Gaudi float32 error (#1342 by Bruno Aristimunha).

  • braindecode.models.DANCE runs its Perceiver attention through the same Gaudi fused SDPA path in HPU eager mode (torch’s SDPA there computes the full score matrix op by op, which made the DANCE Gaudi eager train step 8 % slower than in 1.8.1): Gaudi eager train step 848 -> 763 ms (21 channels x 6000 samples, batch 64); CPU and Gaudi lazy mode unchanged (#1340 by Bruno Aristimunha).

  • braindecode.models.REVE runs its attention through the same helper, so HPU eager mode uses the Gaudi bridge’s fused SDPA kernel instead of torch’s op-by-op SDPA through the full score matrix (lazy mode, CPU and other devices unchanged): Gaudi eager train step 1.42x faster (21 channels x 6000 samples, batch 64); differences within the Gaudi float32 error (#1345 by Bruno Aristimunha).

  • braindecode.models.REVE also uses the fused SDPA kernel in HPU lazy mode, through a new opt-in fused_in_lazy flag of the shared helper (default off: on long sequences such as ZUNA’s the graph compiler’s own SDPA fusion is faster): Gaudi lazy train step 1.04x faster for REVE’s ~700-token sequences (21 channels x 6000 samples, batch 64); differences within the Gaudi float32 error (#1353 by Bruno Aristimunha).

  • braindecode.models.EEGPT and braindecode.models.LUNA split their fused query/key/value projection with unbind instead of three index selects, whose backward wrote a zero-filled copy of the whole projection gradient per select and summed them: EEGPT train step 1.09x faster on CPU and 1.02-1.03x on Gaudi (21 channels x 6000 samples, batch 64); outputs and gradients unchanged bit for bit (#1352 by Bruno Aristimunha).

  • braindecode.models.EEGPT runs its attention through the shared SDPA helper with fused_in_lazy=True, so on HPU it uses the Gaudi bridge’s fused SDPA kernel in eager and lazy mode instead of torch’s SDPA (op by op through the full score matrix in eager mode); causal attention keeps torch’s call: Gaudi train step 1.21x faster in eager mode and 1.03x in lazy mode (21 channels x 6000 samples, batch 64; lazy mode up to 3 % slower on 256-sample inputs); CPU and other devices unchanged (bit-identical), Gaudi differences within the Gaudi float32 error (#1355 by Bruno Aristimunha).

  • The shared SDPA helper of braindecode.modules.MultiHeadAttention (EEGConformer, CTNet, MSCFormer, MIRepNet, STEEGFormer) and braindecode.models.PBT runs attention with dropout on CPU and in HPU eager mode as torch’s math path op for op, without the pass of _safe_softmax that zeroes fully masked rows (there are none without a mask): train step PBT 16 % faster in Gaudi eager mode and 9 % on CPU, EEGConformer 3 % / 6 %, MIRepNet 5 % / 3 % (21 channels x 6000 samples, batch 64); outputs, gradients and dropout draws identical on CPU and for PBT on Gaudi, within Gaudi’s own run-to-run variation for the other models; lazy mode, masks, other devices and attention without dropout unchanged (#1361 by Bruno Aristimunha).

  • braindecode.models.NeuroRVQ and braindecode.models.NeuroRVQTokenizer run their four temporal scales through the shared transformer blocks as one stacked batch on accelerators (CPU, and training with dropout, keep the per-scale loop): Gaudi train step 1.7-2.6x and forward 1.8-3.1x faster; CPU unchanged; outputs and token ids unchanged on CPU, within float rounding on Gaudi (#1312 by Bruno Aristimunha).

  • braindecode.datasets.TUH, braindecode.datasets.TUHAbnormal and braindecode.datasets.TUHEvents build the standard_1005 montage once per process instead of twice per recording for rename_channels / set_montage: 2993 TUAB recordings, rename_channels + set_montage 37.5 s -> 14.5 s (2.6x), 23 s less per TUHAbnormal indexing with n_jobs=1; channel names, types, positions and descriptions unchanged (#1299 by Bruno Aristimunha).

  • The attention of braindecode.models.Labram (shared by braindecode.models.NeuroRVQ and braindecode.models.NeuroRVQTokenizer) runs through torch.nn.functional.scaled_dot_product_attention() with the relative position bias as attn_mask off HPU (the manual path stays on HPU, with return_attention=True and with attention dropout in training): Labram CPU forward 1.2-1.3x and train step 1.06-1.14x faster, NeuroRVQ / NeuroRVQTokenizer CPU up to 6 % faster, Gaudi unchanged; outputs and gradients differ from before by more than float32 rounding (up to 2.5x master’s own float32-vs-float64 difference on the released Labram checkpoint’s gradients), token ids unchanged in single forward passes (#1328 by Bruno Aristimunha).

  • braindecode.models.LUNA computes its rotary self-attention with torch.nn.functional.scaled_dot_product_attention(): CPU forward 1-4 % faster, train step neutral to 2.4 % faster; outputs and gradients change by float rounding only, within master’s own float32-vs-float64 difference, also with the released PulpBio/LUNA weights (#1282 by Bruno Aristimunha).

  • braindecode.models.DANCE computes the Perceiver and decoder attention with torch.nn.functional.scaled_dot_product_attention() instead of an explicit softmax: eval forward 0.7 % faster on CPU and 1.4 % on Gaudi (22 channels, 32 s, batch 32), train step unchanged; outputs and gradients change by float rounding only, within master’s own float32-vs-float64 difference (#1291 by Bruno Aristimunha).

  • braindecode.functional.prefer_fft_conv() picks the FFT for a float32 convolution only if also in_channels * kernel_size >= 120: with one or two input channels the direct convolution is up to 2.5x cheaper on CPU; braindecode.models.EEGInceptionMI decisions and outputs unchanged (#1283 by Bruno Aristimunha).

  • braindecode.models.TIDNet and braindecode.models.EEGNeX compute their long temporal convolutions with braindecode.functional.fft_conv1d() on CPU where braindecode.functional.prefer_fft_conv() expects it to be faster (TIDNet in float64): train step 1.8x (TIDNet) and 1.3x (EEGNeX) faster at 22 channels, batch 32 (2 threads); small batches, GPUs and Gaudi keep the direct convolution; outputs and gradients change by float rounding only, as close to the float64 result as master (#1305 by Bruno Aristimunha).

  • braindecode.preprocessing.preprocess() with save_dir preprocesses a copy of each recording, so with n_jobs=1 the input datasets are no longer loaded and held in memory until the saved copies are reloaded: peak memory on 64 TUAB recordings 1.8 GB -> 0.6 GB (it grew by ~22 MB per recording, ~65 GB for the whole corpus); saved files and returned datasets unchanged (#1301 by Bruno Aristimunha).

  • braindecode.models.BIOT computes the spectrograms of all channels with one STFT instead of one per channel: Gaudi forward 1.6x and train step 1.35x faster (22 channels, batch 32), CPU registry forward 3 % faster; outputs and gradients unchanged bit for bit, also with the released weights (#1284 by Bruno Aristimunha).

  • braindecode.models.MVPFormer builds its attention masks and channel-shift index once per forward instead of in every layer: forward 19-25 % faster on Gaudi and 2-12 % on CPU, outputs and gradients unchanged bit for bit (#1280 by Bruno Aristimunha).

  • braindecode.models.AttnSleep, braindecode.models.Brant, braindecode.models.MSVTNet and braindecode.models.PBT no longer compute tensors their forward discards (AttnSleep’s first attention product, Brant’s reconstruction projection, MSVTNet’s branch heads without return_features, PBT’s class-token index); outputs and gradients unchanged bit for bit (#1281 by Bruno Aristimunha).

  • braindecode.models.NeuroRVQTokenizer accumulates the -2 * vectors @ codes.T term of its code distances inside the GEMM (one addmm_) instead of a separate product and subtraction: CPU forward 8 % and train step 3 % faster (22 channels, batch 32, 2 threads); distances and token ids unchanged bit for bit (#1315 by Bruno Aristimunha).

  • braindecode.preprocessing.preprocess() with save_dir reloads the saved recordings with its n_jobs instead of one at a time: TUAB (2993 recordings, n_jobs=16) preprocess 626.8 s -> 386.4 s, the final reload 260.1 s -> 65.4 s; saved files and returned datasets unchanged (#1302 by Bruno Aristimunha).

  • braindecode.models.CSBrain copies each region’s mean feature into its electrodes with one slice assignment per region instead of one per electrode: train step about 10 % and forward 7 % faster on Gaudi (22 channels, batch 32), unchanged on CPU; outputs are unchanged and gradients change by float rounding only, within master’s own float32-vs-float64 difference (#1285 by Bruno Aristimunha).

  • braindecode.models.AXON runs one temporal attention per block instead of two when the window has at most temporal_window + 1 patches (every window up to 5.5 s at the defaults), where the restricted and full temporal branches are identical: train step 7 % faster on CPU and 12 % on Gaudi (22 channels, 5 s, batch 32); outputs are unchanged and gradients change by float rounding only, within master’s own float32-vs-float64 difference (#1286 by Bruno Aristimunha).

  • braindecode.modules.FilterBankLayer broadcasts each FIR band filter over the channels instead of repeating it, so its FFT is computed once per band: braindecode.models.FBCNet, braindecode.models.FBMSNet, braindecode.models.FBLightConvNet and braindecode.models.IFNet steps 1-10 % faster on CPU and 8-29 % on Gaudi at batch 2, 0-3 % at batch 32; outputs and gradients change by float rounding only at 22 channels, within master’s own float32-vs-float64 difference, and not at all at 3 channels (#1278 by Bruno Aristimunha).

  • braindecode.modules.FilterBankLayer computes the FFT of the input once for consecutive FIR bands with the same filter length (and moves an HPU input to the CPU and back once for the whole bank instead of once per band); each band is still torchaudio’s fftconvolve at its own FFT length, so outputs are unchanged bit for bit: braindecode.models.FBCNet, braindecode.models.FBMSNet and braindecode.models.FBLightConvNet Gaudi forward 12-20 % and train step 8-18 % faster, CPU forward 1-7 % faster; braindecode.models.IFNet Gaudi 1-5 % faster, CPU unchanged (#1324 by Bruno Aristimunha).

  • braindecode.modules.FilterBankLayer filters all FIR bands with one FFT of the input at a 5-smooth length on CPU (each filter shifted to a common window) and with one direct conv1d on HPU instead of host FFTs: braindecode.models.FBCNet, braindecode.models.FBMSNet, braindecode.models.FBLightConvNet and braindecode.models.IFNet Gaudi train step 1.1-28x faster, CPU train step 3-41 % faster (21 channels x 6000 samples and 22 x 800); outputs and gradients differ from before by more than float32 rounding (up to 3.6x master’s own float32-vs-float64 difference on CPU, 4.7x on Gaudi), argmax unchanged (#1327 by Bruno Aristimunha).

  • The SEANet convolutions of braindecode.models.BrainTokenizer (and the tokenizer of braindecode.models.BrainOmni) skip the padding calls that only copy their input (the 1x1 convolutions pad nothing, and the zero extension is empty unless the signal is shorter than the padding): BrainTokenizer CPU forward 6-11 % and train step 5-8 % faster, Gaudi (eager) train step 2-4 % faster, BrainOmni CPU 1-5 % faster; outputs, gradients, token ids and released-checkpoint outputs unchanged bit for bit (#1326 by Bruno Aristimunha).

  • The SELU of braindecode.models.BrainOmni and braindecode.models.BrainTokenizer is computed as an ELU times a positive-side factor instead of a where of two branches, so its backward has no zero-filled branch gradients: BrainOmni CPU train step 7-9 % faster (22 channels, batch 32, 2 threads), Gaudi unchanged; outputs, gradients and token ids unchanged bit for bit, still trainable on Gaudi (#1316 by Bruno Aristimunha).

  • braindecode.preprocessing.create_fixed_length_windows() runs its per-recording calls in threads when n_jobs > 1, instead of pickling every recording to worker processes and back: TUAB (2993 recordings) with n_jobs=8 52.3 s -> 5.5 s (n_jobs=1: 1.8 s, unchanged); windows unchanged (#1303 by Bruno Aristimunha).

  • braindecode.models.MEDFormer adds its channel embedding once instead of once per granularity, and runs its layer norms and kernel-1 feed-forward convolutions once on all granularities (dropout stays per granularity, same masks): train step 3-7 % faster on CPU and 6-7 % on Gaudi; outputs change by float rounding only (#1288 by Bruno Aristimunha).

  • braindecode.models.MEDFormer computes its attention scores and outputs as batched matrix products on (batch, heads, length, features) operands instead of two torch.einsum() calls, and the query, key and value projections of its self-attention as one GEMM on their concatenated weights (same parameters and state dict): torch.compile() with Gaudi’s hpu_backend now compiles and trains MEDFormer (graph compilation failed at the einsum’s reshape before; the compiled Gaudi eager train step is 1.9x faster than the uncompiled one), Gaudi train step 1.15-1.18x faster in lazy mode and 1.06-1.10x in eager mode, CPU 1.05x (21 channels x 1000 samples, batch 64); outputs and gradients change by float rounding only, within the model’s own float32 error (#1356 by Bruno Aristimunha).

  • braindecode.functional.plv_time() copies the real and imaginary phasor parts once instead of in every matmul for each batch matrix: braindecode.models.EEGMiner CPU forward 1.5x and train step 1.4x faster (22 channels, batch 32, 2 threads); outputs and gradients change by float rounding only, within master’s own float32-vs-float64 difference (#1277 by Bruno Aristimunha).

  • braindecode.modules.EMACodebook builds its one-hot code matrix only in training, where the EMA update reads it: eval forward of braindecode.models.TFMTokenizer 5 % faster on CPU (22 channels, batch 32; 208 MB less temporary memory) and of braindecode.models.BrainTokenizer / braindecode.models.BrainOmni 0.5-2 %; outputs, gradients, buffers and token ids unchanged bit for bit (#1290 by Bruno Aristimunha).

  • braindecode.datasets.BaseConcatDataset.save() with an offset no longer lists and stats every entry of the target directory (and no longer warns with that listing): braindecode.preprocessing.preprocess() saves each recording at its offset into one directory, which made the scan quadratic; 2993 TUAB recordings 223 s -> 15 s of save calls and 2992 -> 0 warnings (33 MB); saved files unchanged (#1304 by Bruno Aristimunha).

  • braindecode.datasets.EEGWindowsDataset reads a window of a lazily loaded FIF recording (what preprocess(..., save_dir=...) and braindecode.datautil.load_concat_dataset() produce) from one slice of the memory-mapped file instead of one 1-s FIF buffer at a time through a 4 MB read buffer: one epoch of 60-s TUAB windows 1.3-1.4x faster from a cold page cache and 1.5-2.1x faster from a warm one (num_workers 0-8), windows unchanged (#1318 by Bruno Aristimunha).

  • braindecode.datautil.load_concat_dataset() keeps the FIF data-buffer tags of each lazily loaded recording (one mne Tag object per 1-s buffer) as one int64 array: 2.9x less memory per 20-min recording (446 -> 153 KiB), 2.8-3.4x less copy-on-write memory per DataLoader worker over an epoch (8 workers, 10,000 recordings: 14.0 -> 4.6 GiB for the whole process tree), reload about 8 % faster with n_jobs=1 and 1.7-2x faster with n_jobs=8, gc.collect() 2-2.2x faster; windows, batches and mne’s own reads unchanged (#1325 by Bruno Aristimunha).

  • braindecode.datasets.BaseConcatDataset gives a DataLoader each batch through __getitems__, which first asks the operating system to start reading every lazily loaded FIF window of the batch (posix_fadvise(POSIX_FADV_WILLNEED)) and then reads them as before, so a worker’s reads of a batch overlap instead of running one after another: from cold files on a network file system, one shuffled epoch of 60-s windows 1.3-2.6x faster (num_workers 4-16) and 3.4-7.7x faster when every window comes from a different file; batches unchanged; no hint where posix_fadvise does not exist (Windows, macOS) (#1337 by Bruno Aristimunha).

  • braindecode.models.EEGInceptionMI runs its max pooling in channels-last layout and pads even kernels once per inception module: CPU forward 1.1-1.25x faster, outputs, gradients and state dict unchanged (#1267 by Bruno Aristimunha).

  • braindecode.models.EEGInceptionMI computes its temporal convolutions with an FFT on CPU when the input is float16/bfloat16 or batch_size * largest_kernel >= 600 (new fft_conv argument; None by default, False keeps the direct convolution bit for bit): float32 CPU steps 1.5-8.8x faster from batch 8 (2 threads), float16/bfloat16 17-117x; outputs change by float rounding (<= 3.6e-7 relative) (#1268 by Bruno Aristimunha).

  • braindecode.models.EEGInceptionMI takes its FFT convolution from the new braindecode.functional.fft_conv1d() (automatic choice in braindecode.functional.prefer_fft_conv()) and uses plain padding="same" convolutions again: direct-path outputs, gradients and state dict unchanged bit for bit, CPU steps 0.98-1.45x master’s (FFT path faster from batch 8) (#1274 by Bruno Aristimunha).

  • Add braindecode.models.TFMTokenizer, the time-frequency motif tokenizer for single-channel EEG of Pradeepkumar et al. (ICLR 2026) (#1202 by lindicaphxag-tech).

  • Add braindecode.models.EEGCLIP, a dual encoder that aligns EEG windows and text descriptions with a symmetric contrastive objective; the text encoder is optional and user-supplied (#1200 by lindicaphxag-tech).

  • Add braindecode.models.EpiNT, a port of the EpiNT epilepsy foundation model for scalp and intracranial EEG (Zhang et al., 2025): a channel-independent transformer with rotary attention over 256-sample patches of a 3072-sample window. The authors’ released representations.bin loads with load_state_dict(strict=False) (#1266 by Julien Gadonneix).

  • Add braindecode.augmentation.TrivialAugment, which applies to each example one transform and strength sampled from a label-preserving pool; also list braindecode.augmentation.BandRotation in the API docs (#1255 by Li Qing).

  • The pretrained-compatibility test now covers every model class with released weights (NeuroRVQ, MAPA, BrainOmni, BrainTokenizer and the SignalJEPA heads added), checks that the list is complete, and runs REVE’s cases without network access (#1252 by Bruno Aristimunha)

  • braindecode.models.NeuroRVQ now reuses the LaBraM attention block instead of a private copy, and the K-means codebook initialisation in braindecode.modules.quantization uses torch.cdist (about 6x faster, lower peak memory, identical codebooks). Outputs and state-dict keys are unchanged. (by Bruno Aristimunha)

  • The K-means codebook initialisation in braindecode.modules.quantization searches the nearest center once per distinct sampled row: a first batch smaller than the 4096 drawn vectors is sampled with replacement, and the first forward of a fresh braindecode.models.BrainOmni or braindecode.models.BrainTokenizer took about 10 s on CPU. Codebooks are unchanged (#1265 by Bruno Aristimunha).

  • Add braindecode.models.MAPA, a masked-autoencoder foundation model for intracranial EEG that describes an electrode only by its atlas region and its number along the array it was implanted on, never by its coordinates, so that one pretrained encoder reads a subject it has never seen: three magnitude-spectrogram bands on a shared frame clock are tokenized per contact, offset by a learned region embedding, and mixed by a transformer whose attention stays inside one array and carries a two-axis rotary encoding on the contact number and on time. One instance encodes recordings from different subjects, by passing each one’s electrode metadata to forward, and normalization="session" takes a spectrogram normalized over the whole recording, which reproduces the reference inputs (#1178 by Julien Gadonneix).

  • braindecode.models.MAPA loads the released mapa_vits384 with MAPA.from_pretrained("braindecode/mapa-pretrained", ...); the key mapping for the original checkpoint is removed (by Bruno Aristimunha).

  • Add test/unit_tests/models/test_pretrained_compat.py: every model with released weights is built on a grid of input geometries (canonical montage, permuted order, a 64-channel montage outside the 10-20 vocabulary, coordinates-only channels, names without coordinates, 1 s / 30 s / non-divisible windows) and must forward or raise the error its declared channel strategy implies; unhandled cells are strict xfail markers (#1228 by Bruno Aristimunha).

  • Add channel_strategy ("exact", "zero", "nearest", "idw", "spline", "field", "source", "region", "wiener", "latent"; default "native") and channel_strategy_kwargs to the 19 pretrained models, saved in the config. A braindecode.modules.ChannelLayer (one matrix per montage) maps any montage onto the channels the backbone consumes, also per call with model(x, chs_info=...). "native" keeps every released checkpoint bit-identical with the same state_dict. It replaces the unreleased ChannelTokenizer; BENDR adapts a non-canonical montage with an MNE spline and SignalJEPA no longer returns NaN for names without coordinates. See Channel strategies: any montage in (#1227, #1241 by Bruno Aristimunha).

  • Add registry-wide model contract tests that automatically cover every registered model, checking eval-mode input/state purity, finite batched outputs, batch-permutation equivariance, and get_config + state_dict reconstruction (#1208 by lindicaphxag-tech).

  • Add braindecode.models.NeuroRVQ, a channel-aware EEG foundation model with four-scale temporal patch embedding and a pretrained masked-token encoder. The port preserves the released architecture and identifies its CC BY-NC 4.0 license and 200 Hz preprocessing requirements (#1090 by lindicaphxag-tech).

  • Generate a version-scoped llms.txt and selected Markdown documentation entry points with source-commit attribution and critical-page coverage checks.

  • Add braindecode.models.NeuroRVQTokenizer, the released NeuroRVQ EEG tokenizer: reconstruction and discrete codes (#1223 by lindicaphxag-tech).

  • Add braindecode.models.AXON, an axis-factorized EEG foundation model whose layers mix a temporal and a spatial attention path with a per-token gate, with pretrained weights on the Hugging Face Hub (#1182 by Mahir Jain).

  • braindecode.models.BIOT, braindecode.models.BrainBERT, braindecode.models.EEGDINO, braindecode.models.SleepFM, braindecode.models.SleepFMStager, braindecode.models.BrainTokenizer and braindecode.models.BrainOmni warn about a sampling rate that differs from the pretrained one through the shared braindecode.models.util.warn_if_sfreq_differs; the warning fires in the same cases as before (up to a 1e-6 Hz tolerance), with one wording (#1261 by Bruno Aristimunha).

  • braindecode.models.NeuroRVQ and braindecode.models.NeuroRVQTokenizer take modality ("eeg", "ecg", "emg", "ppg"), the settings of the authors’ four released packages; the seven released checkpoints load with from_pretrained from braindecode/neurorvq-{eeg,ecg,emg}-pretrained and braindecode/neurorvq-tokenizer-{eeg,ecg,emg,ppg}-pretrained (load_pretrained_weights is removed). The tokenizer reconstruction now equals the authors’ code (it differed by up to 6e-8); statistic_code_usage=True reproduces their eval-time code-usage EMA. Builds on #1090 and #1223 by lindicaphxag-tech (#1254 by Bruno Aristimunha).

  • Add braindecode.models.TMSANet, the motor-imagery convolution and local/global attention model of Zhao and Zhu (2025) (#1209 by lindicaphxag-tech).

  • Add braindecode.models.SeizureTransformer, the U-shaped convolution and Transformer seizure detector of Wu et al. (2025) that won the 2025 SzCORE seizure detection challenge. It predicts a logit for every time sample. With the authors’ released weights it reproduces their challenge scores on braindecode.datasets.SIENA (event F1 0.706) (#1236 by Raghav Rathi).

  • Restore acceptance tests on supported Python versions as seeded decoding checks on BNCI2014_001 (held-out accuracy thresholds, a shuffled-label control and a replicability check), run by a dedicated CI job (#1159 by Bruno Aristimunha).

  • Clarify decoder temporal embedding indexing in braindecode.models.Labram and cover its one-token-per-temporal-patch behavior (#1155 by Bruno Aristimunha).

  • Add braindecode.models.SleepFM, a channel-agnostic multimodal PSG foundation encoder, and braindecode.models.SleepFMStager, its patch-wise sleep-staging model, with the released weights; CC BY-NC 4.0 (#1106 by Fashad Ahmed)

  • Add braindecode.models.CSBrain, the cross-scale spatiotemporal brain foundation model from Zhou et al. (NeurIPS 2025 Spotlight): multi-scale temporal and per-region embeddings with structured sparse (inter-window and inter-region) attention, channel names mapped to five anatomical regions or an explicit brain_regions layout, verified bit-exact against the authors’ released pretrained checkpoint (#1196 by Li Qing).

  • braindecode.models.CSBrain reuses the patch embedding of braindecode.models.CBraMod instead of a copy of it; state-dict keys, outputs with loaded weights and same-seed initial weights are unchanged (#1240 by Bruno Aristimunha).

  • Add head_drop_prob to braindecode.models.CSBrain, the task-head dropout of the reference fine-tuning models (default: drop_prob, so existing models are unchanged), and document the checkpoint key names (#1247 by Bruno Aristimunha).

  • Add braindecode.models.DIVER1, an any-variate EEG/iEEG foundation model with pretrained encoders and support for varying montages through braindecode.models.diver1.channel_metadata_from_chs_info() (#1170 by Julien Gadonneix).

  • braindecode.models.ZUNA accepts an n_times that is not a multiple of fine_time_pts through the new on_non_divisible option ("pad" or "crop"), forwarded to the shared braindecode.modules.PatchTokenizer; the default "error" keeps the previous behaviour (#1190 by Bruno Aristimunha).

  • Add braindecode.models.MSCFormer, a multi-scale convolutional transformer network for motor imagery decoding from Zhao et al. (2025), adapted from the reference implementation to reuse braindecode’s shared attention and feed-forward blocks. The default attention logit scale reproduces the released source’s embed_dim ** -0.5 (numerically verified against the original code, max abs logit diff < 1e-6) and is configurable via attention_scale (#1186 by Li Qing).

  • Add braindecode.models.BaRISTA, an intracranial EEG foundation model whose spatial encoding scale is a free choice: electrodes are tokenized channel-wise and space enters as a single learned embedding selected by the electrode coordinate, its atlas parcel or its lobe, before a joint space-time transformer encoder with rotary temporal embeddings (#1173 by Julien Gadonneix).

  • Add braindecode.models.Brant, a braindecode-native port of the Brant foundation model for intracranial (sEEG/iEEG) signals (Zhang et al., NeurIPS 2023), including in-model spectral features and the shared configuration, feature-return, and head-reset APIs. The official pretrained weights load from braindecode/brant-pretrained (all tensors verified identical to the official release) (#1100 by Adam Mounir).

  • Add braindecode.models.BrainTokenizer, the EEG/MEG VQ-VAE tokenizer of BrainOmni (NeurIPS 2025), with the released weights converted to braindecode/braintokenizer-pretrained (#1043 by Bruno Aristimunha).

  • Add braindecode.models.PopulationTransformer (PopT, Chau et al. 2024), an iEEG population model over per-electrode features and coordinates, with pretrained weights at braindecode/popt-pretrained (#1105 by Adam Mounir).

  • Add braindecode.models.BrainOmni, the BrainOmni downstream classifier on a frozen braindecode.models.BrainTokenizer, with the released tiny and base weights converted to braindecode/brainomni-tiny-pretrained and braindecode/brainomni-base-pretrained (#1043 by Bruno Aristimunha).

  • Add braindecode.models.VEMG2Pose, braindecode.models.NeuroPose, and braindecode.models.SensingDynamics for dense hand-pose regression from surface EMG (#1132 by Bruno Aristimunha).

  • Add a bounded SAE intervention tutorial on a frozen pretrained REVE with BNCI2014_001 using optional SAE Lens, without adding an SAE implementation to Braindecode (#1120 by Vandit Shah and Bruno Aristimunha)

  • Improve CI test scheduling and run documentation examples with bounded parallelism, preserving the test cases and gallery training workloads (#1161 by Bruno Aristimunha).

  • CI: torch threads per pytest-xdist worker so that threads times workers equal the runner’s vCPUs (one per worker on macOS); test_model_compiled runs only in the Linux job that restores the TorchInductor cache; a pull request’s docs build executes only the gallery examples it changes (the full gallery runs on master, tags, release/* branches and a weekly schedule), and only non-PR docs runs save the MNE and Hugging Face caches (#1263 by Bruno Aristimunha).

  • Add a bounded SAE activation analysis tutorial on BCI IV 2a (BNCI2014_001) using optional SAE Lens, without adding an SAE implementation to Braindecode (#1152 by Vandit Shah and Bruno Aristimunha)

  • Add braindecode.models.BrainBERT, a self-supervised foundation model for intracranial (sEEG/iEEG) signals from Wang et al. (ICLR 2023), with pretrained weights (#1104 by Adam Mounir).

  • Add pull request templates, including an exhaustive checklist for new model contributions covering implementation conventions, registration, documentation, and benchmarking (#1169 by Li Qing).

  • torch.jit.script() compiles models whose weights are parametrized (max-norm constraints, weight_norm): ATCNet, BDTCN, EEGITNet, EEGNeX, EEGNet, EEGTCNet, FBCNet, FBMSNet, IFNet and TIDNet now script and give the eager output, and so do models built with an int sfreq or input_window_seconds (as in Hub configs) (#1256 by Bruno Aristimunha).

  • torch.jit.script() compiles MetaNeuromotorHand, NeuroRVQTokenizer, REVE, SleepFM and SleepFMStager and gives the eager output (einops calls written as reshape/permute, NeuroRVQTokenizer’s four scales without a computed-name getattr). Scripted REVE leaves out the autocast-off block around its Fourier features (TorchScript needs a constant autocast device). Eager outputs and state-dict keys are unchanged (#1271 by Bruno Aristimunha).

  • torch.jit.script() compiles MVPFormer and gives the eager output: its einops calls are written as the reshapes and expands einops ran, and dwt_max_level() finds the level in integers instead of with math.log2. Eager outputs and state-dict keys are unchanged (#1272 by Bruno Aristimunha).

  • Shrink the slowest unit tests, keeping what each one checks: EEGInceptionMI’s 500 Hz case on 2 windows instead of 64; 1 s DANCE and ZUNA and 5-patch CodeBrain windows in the shared model test geometry; one EEGClassifier fit per model instead of two; 8 BIOT shape cases instead of 240; 3 spawned processes instead of 14 in the distributed sampler tests (#1264 by Bruno Aristimunha).

  • torch.jit.script() compiles 17 more models and gives the eager output: BENDR, BrainModule, CBraMod, CodeBrain, CSBrain, EEGDINO, LUNA, MIRepNet, MSVTNet, NeuroRVQ, SSTDPN, STEEGFormer, TCFormer and the four SignalJEPA variants. einops calls in forward are written as reshape/permute, forward declares its dict or tuple return, BrainModule no longer keeps None in a ModuleList (TorchScript dropped it), NeuroRVQ’s branches no longer use a computed-name getattr and LUNA’s reconstruction head stays eager-only. Eager outputs and state-dict keys are unchanged (#1262 by Bruno Aristimunha).

  • torch.jit.script() compiles BrainOmni, BrainTokenizer, DANCE, EEGPT and Labram and gives the eager output: the shared EMA codebook (braindecode.modules.quantization), DANCE’s Fourier position embedding and Perceiver, and EEGPT no longer use einops functions, **kwargs or @torch.no_grad() methods in forward, and Labram’s ch_names is no longer keyword-only. A scripted BrainOmni needs its tokenizer in eval mode. Eager outputs and state-dict keys are unchanged (#1270 by Bruno Aristimunha).

  • torch.jit.script() compiles BIOT and TFMTokenizer and gives the eager output. They now run braindecode.modules.linear_attention, the part of linear_attention_transformer they used (global linear attention, MIT), whose forward takes no **kwargs; parameter names are unchanged, so released checkpoints load as before (#1273 by Bruno Aristimunha).

  • torch.jit.script() compiles MAPA and gives the eager output, both for the montage given at construction and for another recording’s sensor_indices passed to forward, so every braindecode model now scripts. The token layout is a tuple of named buffers and the band and region tables are module constants. Eager outputs and state-dict keys are unchanged (#1276 by Bruno Aristimunha).

  • Add braindecode.models.GCNsNet, a graph convolutional neural network for decoding time-resolved EEG motor imagery signals, from Hou et al. (2022) (#1331 by Seáic Mac Murchadha).

  • braindecode.modules.EMACodebook reuses its distance-matrix storage during nearest-code lookup, avoiding two full-sized arithmetic temporaries without changing distance evaluation order (#1404 by Bruno Aristimunha).

API and behavior changes#

  • braindecode.datasets.BaseConcatDataset.get_metadata() returns an i_dataset column with the position of the dataset each window comes from, and raises a ValueError if a description or the window metadata already has that key. The samplers in braindecode.samplers take each dataset as one recording; pass the metadata without i_dataset to group the one-trial datasets of braindecode.datasets.create_from_X_y() or braindecode.datasets.create_from_mne_epochs() by subject, session and run as before. The samplers’ info gets a recording index level after subject, session and run (#1369 by Raghav Rathi).

  • braindecode.models.Labram, braindecode.models.CBraMod and braindecode.models.LUNA tokenize the time axis with the shared braindecode.modules.PatchTokenizer and accept a window that is not a multiple of patch_size by right zero-padding the last patch (with a warning), through a new on_non_divisible={"pad", "crop", "error"} argument; previously such windows raised a reshape error. braindecode.models.ZUNA now defaults to on_non_divisible="pad" as well (it was "error"). Outputs and state-dict keys are unchanged for divisible windows, so released checkpoints load as before (#1226 by Bruno Aristimunha).

  • Every patch-based model takes on_non_divisible={"pad", "crop", "error"}, default "pad": a window that patches do not tile is zero-padded instead of cropped (STEEGFormer, Brant, BaRISTA, SleepFM, REVE) or rejected (NeuroRVQ, DuIN, CSBrain). Tiled windows are unchanged; configs saved without the key load as before (subclasses whose __init__ does not take it are left alone) (#1399 by Bruno Aristimunha).

  • braindecode.models.Labram defaults to use_mean_pooling=True again, the documented value and the readout of the original fine-tuning (fc_norm of the mean patch token). #931 had made the [CLS] output, which the pretraining loss never uses, the default so that the pretraining checkpoint loaded strictly. That checkpoint, such as the released weights, now loads into the mean-pooling model as in the original fine-tuning script (norm unused, fc_norm initialized). Pass use_mean_pooling=False to keep the [CLS] readout, for instance to load a checkpoint fine-tuned with it, which no longer loads into the default model (#1155 by Bruno Aristimunha).

  • Remove InterpolatedBENDR, InterpolatedBIOT, InterpolatedEEGPT, InterpolatedLaBraM, InterpolatedSignalJEPA, InterpolatedModel, ChannelInterpolationLayer and interpolated_models_dict: use BENDR(chs_info=..., channel_strategy="spline") instead (#1241 by Bruno Aristimunha).

Requirements#

  • linear_attention_transformer is no longer a dependency: since #1273 braindecode ships the part BIOT and TFMTokenizer use. einops, which arrived only through it, is now declared directly (#1443 by Bruno Aristimunha).

  • Add sphinx-markdown-builder==0.6.11 and pytest<9.1 to the docs extra for version-scoped Markdown exports and their offline contract tests.

  • Require PyTorch and TorchAudio >= 2.4 and remove obsolete attention fallbacks. REVE and ZUNA now import PyTorch’s RMSNorm layer directly, preserving their explicit epsilon values. Intel macOS is no longer supported because PyTorch stopped providing its binary packages after 2.2. (#1174 by Bruno Aristimunha)

Bug fixes#

Current 1.8.0 (2026-08-31)#

Enhancements#

API and behavior changes#

  • Deprecate drop_last_window in braindecode.preprocessing.create_windows_from_events() and braindecode.preprocessing.create_fixed_length_windows(); it will be removed in version 2.0. The keyword-only replacement, on_last_window, accepts 'overlap' or 'drop'. Explicit legacy False maps to 'overlap' and explicit legacy True maps to 'drop'; either legacy spelling emits a DeprecationWarning. When no explicit window size or stride is supplied to fixed-length windowing, the policy is immaterial and normalizes to the existing single full-recording window; this also replaces the internal assertion formerly reached by explicit legacy True. (#1058 by Michele Romani)

Requirements#

Bug fixes#

Code health#

  • None yet

Current 1.7.0 (2026-08-01)#

Enhancements#

  • Add braindecode.models.ZUNA, a position-aware EEG foundation model from Warner et al. (2026), ported from the public Zyphra/ZUNA1.1 encoder with a Braindecode classification head, shared patch tokenization, and construction-time spatial positions compatible with TorchScript and torch.compile (#1020 by Jon Huml)

  • Add braindecode.models.util.interpolated_models_dict, a dedicated registry for the interpolated (channel-adapting) models, keeping them separate from braindecode.models.util.models_dict (#1093 by Bruno Aristimunha)

API and behavior changes#

  • The stride_factor parameter of braindecode.models.FBLightConvNet is deprecated and will be removed in a future release. The model never read it, its temporal segmentation is set by win_len, and the reference implementation has no such parameter. Passing it now emits a DeprecationWarning and keeps being ignored. By Sarthak Tayal.

  • Interpolated models (e.g. InterpolatedBIOT, InterpolatedLaBraM) are no longer included in braindecode.models.util.models_dict; they now live in the separate braindecode.models.util.interpolated_models_dict registry. They remain fully usable and resolvable by name in the skorch wrappers and pydantic configs (#1093 by Bruno Aristimunha)

Requirements#

  • None yet

Bug fixes#

  • Fix braindecode.EEGClassifier.predict_trials(), braindecode.EEGRegressor.predict_trials() and braindecode.training.scoring.CroppedTrialEpochScoring on the training set raising AttributeError or TypeError when the module was passed as a model name or as an uninstantiated class. Those paths read the module constructor argument instead of the initialized module_ attribute, so they only worked when an already instantiated module was passed, which the documentation discourages. By Sarthak Tayal.

  • Raise a clear ValueError in braindecode.models.FBLightConvNet when n_times is shorter than win_len. The temporal attention kernel is sized as n_times // win_len, so a short window produced an empty kernel and the constructor died with a ZeroDivisionError coming from the weight initialisation. The docstring now also documents win_len and reports the correct n_bands default of 9. By Sarthak Tayal.

  • Use nn.Dropout1d instead of nn.Dropout2d for the channel-wise dropout inside braindecode.models.BDTCN, braindecode.models.TCN and braindecode.models.BENDR. Those layers receive (batch, channels, times) activations, which nn.Dropout2d only handles through a deprecated fallback that warns on every forward pass and is scheduled to be reinterpreted as unbatched input, masking batch items rather than channels. The masking behaviour is unchanged. By Sarthak Tayal.

  • Clarify that braindecode.training.scoring.predict_trials(), braindecode.EEGClassifier.predict_trials(), and braindecode.EEGRegressor.predict_trials() return ground-truth dataset targets alongside predictions. By Sarthak Tayal.

  • Make braindecode.models.EEGMiner compatible with TorchScript across magnitude, correlation, and phase-locking-value feature modes by replacing runtime callable dispatch with a scriptable feature module. (#1101 by Sarthak Tayal)

  • Make the braindecode.models.REVE position bank robust on offline / limited-network nodes: it is now cached in the writable MNE data directory (resolved via the REVE_POSITIONS_PATH config key, defaulting under ~/mne_data) instead of the package folder, so a prefetched reve_positions.json there is used without any download (#1098 by Bruno Aristimunha)

Code health#

  • None yet

Current 1.6.1 (2026-07-01)#

Enhancements#

  • Pin the %pip install braindecode cell in generated notebooks to the version used to build them (braindecode==X.Y.Z for stable releases, git+https://github.com/braindecode/braindecode.git for dev builds), so notebooks can be reproduced with a matching installation. (#1080 by Fashad Ahmed)

  • Add braindecode.functional.sinusoidal_positional_encoding(), a shared sine/cosine positional-encoding primitive (handling odd dimensions), and reuse it in braindecode.models.BIOT, braindecode.models.MEDFormer, and braindecode.models.STEEGFormer instead of re-deriving the table in each. Encodings are bit-identical, so model behavior is unchanged. Also add braindecode.modules.GatedLinearUnit, a configurable GLU-family gate (GEGLU with the default nn.GELU, SwiGLU with nn.SiLU; torch.nn.GLU is hard-wired to the sigmoid) for building gated transformer feed-forwards. (#1078 by Bruno Aristimunha)

  • Add braindecode.models.DANCE, an event detection-and-classification model (CNN encoder + Perceiver bottleneck + DETR-style decoder) that detects a set of (start, end, class) events from long, unaligned EEG windows, with a braindecode.training.DanceLoss criterion, an f1_event detection metric, and a runnable tutorial. The re-implemented spatial merger / Perceiver / conv stack are numerically parity-verified against the upstream reference. (#1075 by Bruno Aristimunha)

  • Add an optional spatial Fourier braindecode.modules.ChannelMerger (with braindecode.modules.FourierEmb) to braindecode.models.BrainModule via use_merger=True, implementing the montage-agnostic spatial attention its docstring described. Also fixes a latent crash for non-integer dilation_growth and sizes the channel accounting in forward order so subject_layers/STFT combinations work. Default-off, so existing behavior is unchanged. (#1076 by Bruno Aristimunha)

  • Add opt-in electrode positions in the batch via braindecode.datasets.BaseConcatDataset.set_return_ch_pos() and a cached ch_pos accessor on windowed datasets, plus braindecode.datasets.pad_channels_collate() to make collections with heterogeneous montages (different channel sets) batchable. Positions and a channel mask are routed into the model’s forward under braindecode.EEGClassifier. Default-off, so the (X, y, crop_inds) contract is unchanged. (#1066 by Bruno Aristimunha)

  • Add a revision keyword argument to braindecode.datasets.BaseConcatDataset.pull_from_hub() so callers can pin dataset downloads to a specific branch, tag, or commit on the Hugging Face Hub.

  • Clarify the model summary table’s Type column by using Prediction for supervised heads instead of describing them as classification-only. By Sarthak Tayal.

  • Add a Modality column (EEG, MEG, sEMG, …) to the model summary table so models can be filtered by the bio-signal they target, and validate it against a controlled vocabulary. By Bhargav Kowshik.

  • Add braindecode.models.InterpolatedEEGPT, a channel-interpolation variant of braindecode.models.EEGPT built with InterpolatedModel(). By Pierre Guetschel.

  • Add braindecode.models.EEGDINO, the EEG-DINO self-distillation foundation model (Small/Medium/Large) with pretrained S/M weights. By Bruno Aristimunha.

  • Add braindecode.models.MVPFormer, the multi-variate parallel attention (MVPA) foundation model for heterogeneous multi-variate iEEG, with a db4-wavelet signal encoder computed from first principles (no new dependency). By Bruno Aristimunha.

  • Add braindecode.models.STEEGFormer, a ViT-based EEG foundation model pre-trained with a masked-autoencoder objective, from Yang et al. (ICLR 2026). By Adam Mounir.

  • Add separate EEGNet and TCN dropout rates to braindecode.models.EEGTCNet via the new drop_prob_eeg and drop_prob_tcn arguments, enabling the source/paper configuration (p_eeg=0.2, p_tcn=0.3). Both default to drop_prob, so existing behavior is unchanged. (#1060 by Bruno Aristimunha)

  • Add an opt-in conv_max_norm_const argument and a source_optimizer_param_groups() helper to braindecode.models.ATCNet, exposing the official implementation’s convolution/TCN max-norm constraint (0.6) and L2 weight-decay groups (conv/TCN 0.009, dense 0.5). Defaults preserve current behavior. (#1061 by Bruno Aristimunha)

  • Add causal forward filtering support to braindecode.modules.FilterBankLayer for IIR and FIR filter banks via phase="forward"/phase="causal". Existing zero-phase filtering remains the default. By Bruno Aristimunha.

  • Add braindecode.models.TCFormer, the Temporal Convolutional Transformer for EEG motor-imagery decoding: a multi-kernel CNN front-end, a grouped-query attention Transformer with rotary positional embeddings, and a grouped temporal convolutional network head. (#1065 by Bruno Aristimunha)

  • Add a return_features option to braindecode.models.FBMSNet: when enabled, forward() returns (logits, features) where features is the flattened pre-classifier vector (shape (batch, out_channels_spatial * stride_factor)), enabling center-loss training without subclassing. (#1083 by Bruno Aristimunha)

  • Add an n_augmentation argument to braindecode.augmentation.AugmentedDataLoader for fixed set-expansion: each batch keeps its clean originals and appends n_augmentation independently transformed copies (e.g. the EEG-Inception 6x training set with n_augmentation=5); the default 0 preserves the current in-place behavior. The collate is now a picklable callable, so the loader supports num_workers > 0, and several augmentation transforms were vectorized for speed. (#1070 by Bruno Aristimunha)

API and behavior changes#

Requirements#

  • Cap the test dependency to pytest<9.1 in the tests extra. pytest 9.1.0 changed the IdMaker constructor signature, which breaks pytest_cases 3.10.1 and makes the whole test suite crash at collection time. The cap can be lifted once pytest_cases supports pytest>=9.1. By Adam Mounir.

Bug fixes#

Code health#

  • Silence the new “training set smaller than batch_size” warning (#1053) in the test_eegneuralnet signal-argument tests, which intentionally fit tiny mock data to check argument propagation rather than to train. Keeps the warning meaningful by not emitting it on every CI run. (#1056 by Adam Mounir)

  • Install CPU-only PyTorch wheels in the tests and docs CI workflows via UV_TORCH_BACKEND=cpu. GitHub runners have no GPU, so the default CUDA build pulled ~1.8 GiB of unused nvidia-* wheels and contributed to a disk-exhaustion crash. (#1054 by Bhargav Kowshik)

  • Add a monthly scheduled workflow that cuts a stable PyPI release on the 1st of every month, complementing the existing per-push .devN pipeline. (#1030 by Bruno Aristimunha)

  • Make the monthly release workflow push only the release tag and open a pull request for the version bump, so it never needs to push to the protected master branch. (#1031 by Bruno Aristimunha)

Current 1.5.1 (stable)#

Enhancements#

  • Add braindecode.augmentation.BandRotation and braindecode.augmentation.functional.band_rotation(): per-band circular roll along the channel axis plus inter-band temporal jitter, for surface-EMG inputs shaped (B, num_bands * electrodes_per_band, T). Models small wristband rotation between sessions and relative timing noise between two arms, from the emg2qwerty paper (Sivakumar et al., NeurIPS 2024). (#1013 by Bruno Aristimunha)

  • Build SpecAugment (Park et al., Interspeech 2019) into braindecode.models.EMG2QwertyNet as a parameter-free submodule gated by a new spec_augment constructor flag (default False). When enabled, applies up to n_time_masks × time_mask_param time bands and n_freq_masks × freq_mask_param frequency bands on the log-spectrogram during train() only, with masks sampled IID per (sample × band × electrode) triple — same recipe as the upstream emg2qwerty.transforms.SpecAugment dataset transform. The mask fill value stays a 0-D on-device tensor (spec.mean()) so the forward pass adds no host round-trip on GPU. Also adds a return_features runtime flag to braindecode.models.EMG2QwertyNet.forward() (returns {"features": (B, T_out, num_features), "cls_token": None}, BIOT / signal-JEPA convention) and a matching return_feature constructor flag (returns (emissions, features) tuple, BIOT-style legacy path) so downstream wrappers — such as neuroai’s DownstreamWrapperModel — can pick up the encoder representation via model_output_key="features" (dict) or model_output_key=1 (tuple) without changes to their call site. (#1015 by Bruno Aristimunha)

API and behavior changes#

  • Restore the per-batch ch_names keyword argument on braindecode.models.Labram.forward() that was removed in 1.5.0 (#993). ch_names is now keyword-only and, when provided, case-insensitively matches each name to braindecode.models.labram.LABRAM_CHANNEL_ORDER and indexes into the canonical position-embedding bank, so callers can forward an arbitrary subset of canonical channels without going through braindecode.models.InterpolatedLaBraM. The strict ValueError raised in 1.5.0 when chs_info did not match LABRAM_CHANNEL_ORDER is downgraded to a UserWarning so that downstream wrappers (e.g. neuroai’s _LabramChannelWrapper) can build the inner braindecode.models.Labram with their union channel set and resolve the subset per batch via ch_names.

Bug fixes#

Current 1.5.0 (stable)#

Enhancements#

  • Add braindecode.datasets.BaseConcatDataset.set_target() to swap any per-window metadata column or per-record description field (e.g. a BIDS entity, a participants.tsv extra) into the dataset’s target y in one call, replacing the manual for ds in concat.datasets: ds.metadata.loc[:, 'target'] = ...; ds.y = ... loop. Dispatches on the subdataset type: writes metadata['target'] / ds.y for windowed records, and points target_name at the chosen description field for raw records. By Bruno Aristimunha.

  • Redesign the documentation landing page (docs/index.rst) in a pyhealth.dev-style layout: animated brain → EEG → net hero, fact strip highlighting MOABB / EEGDash interoperability, interactive model-zoo browser sourced from braindecode/models/summary.csv, Hugging Face Hub integration row, and a tutorial-thumbnail carousel. Adds sphinxext-opengraph to docs extras and a SoftwareApplication JSON-LD block. (#1007 by Bruno Aristimunha)

  • Tutorials now train for a few epochs then load pretrained weights from Hugging Face Hub to show full training curves and metrics. All 9 tutorial checkpoints published to huggingface.co/braindecode/. The offline training script used to produce the checkpoints is available as a gist: https://gist.github.com/bruAristimunha/27d74c8410fe9d0db258a03f42efa7c6. (#985 by Bruno Aristimunha)

  • Use F.scaled_dot_product_attention in braindecode.modules.MultiHeadAttention, enabling optimized attention kernels (flash-attention on CUDA, memory-efficient backends on other devices). By Léo Burgund and Bruno Aristimunha. (#902)

  • Add experimental channel interpolation feature: new braindecode.modules.ChannelInterpolationLayer plus the braindecode.models.InterpolatedModel() class factory project arbitrary user channel sets to a model’s canonical set via an MNE-backed (frozen by default) interpolation matrix. Ship pre-built variants braindecode.models.InterpolatedLaBraM, braindecode.models.InterpolatedSignalJEPA, and braindecode.models.InterpolatedBIOT for the corresponding pre-trained models. (#993 by Pierre Guetschel)

  • Add a tutorial walking through the experimental Interpolated* family (Running a Pretrained Model on Any Channel Set with the Channel Layer): failure mode of the vanilla backbones on non-canonical channel sets, one-line fix via braindecode.models.InterpolatedLaBraM / braindecode.models.InterpolatedBIOT / braindecode.models.InterpolatedSignalJEPA, side-by-side visualisation of the name_match vs always interpolation matrices, and the trainable=True flag. (#994 by Pierre Guetschel)

  • Mark deterministic index buffers (braindecode.models.BIOT encoder’s index and braindecode.models.REVE’s position embedding bank) as non-persistent. They are rebuilt from __init__ arguments on every instantiation, so keeping them in state_dict only bloated checkpoints and caused spurious mismatches when n_chans (or the position-bank config) differed between save and load. (#993 by Pierre Guetschel)

  • Add braindecode.visualization interpretability utilities, all built on plain PyTorch autograd with no extra dependencies: saliency(), input_x_gradient(), integrated_gradients(), layer_grad_cam(), project_to_topomap() (thin wrapper around mne.viz.plot_topomap()), and compute_metrics() for quantitative attribution comparison. A new tutorial, Interpretability of EEG Decoders, walks through the full pipeline.

  • Add braindecode.models.MetaNeuromotorHand, a port of the handwriting decoder from Meta / CTRL-labs’ generic neuromotor interface (Kaifosh, Reardon et al., Nature 2025). The model takes raw 16-channel surface EMG from the wristband at 2 kHz and produces per-token scores for CTC decoding of handwritten text. The pipeline is a fixed multivariate power frequency (MPF) featurizer (channel-wise STFT, cross-spectral density, frequency-band averaging, and SPD matrix logarithm) followed by a circular rotation-invariant MLP and a 15-block causal conformer encoder. Meta’s pretrained checkpoint loads directly via load_state_dict (after stripping the network. prefix); the port is bit-exact to the upstream reference implementation on real sEMG. Distributed under CC BY-NC 4.0 to match the upstream repository; see the class docstring for the license warning and the pretrained-checkpoint loading recipe. By Bruno Aristimunha.

  • Add braindecode.models.EMG2QwertyNet, a port of the TDS-Conv-CTC touch-typing decoder from facebookresearch/emg2qwerty (Sivakumar et al., NeurIPS 2024). The model takes raw 32-channel surface EMG (two 16-electrode wristbands at 2 kHz) and emits per-frame scores over a 99-class typing vocabulary (98 keys + CTC blank); pass log_softmax=True to get log-probabilities directly consumable by CTCLoss. The pipeline is a parameter-free log-spectrogram front-end, per-electrode-per-band BatchNorm, a circular rotation-invariant MLP (one per band), and a stack of Time-Depth-Separable convolutional blocks (Hannun et al., 2019) without temporal padding. The encoder nn.Sequential mirrors upstream’s TDSConvCTCModule.model indices for parameter-bearing children, so upstream emg2qwerty checkpoints load directly via load_state_dict (after stripping the PyTorch-Lightning network. prefix); the class-level mapping only remaps the head from model.4.{weight,bias} to final_layer.{weight,bias}. Distributed under CC BY-NC 4.0 to match the upstream repository; see the class docstring for the license warning and the pretrained-checkpoint loading recipe. By Bruno Aristimunha.

API and behavior changes#

  • braindecode.modules.MultiHeadAttention now follows PyTorch’s SDPA mask convention: boolean masks use True to ignore a position (previously True meant keep). The scaling factor is now 1/sqrt(head_dim) instead of 1/sqrt(emb_size). (#902)

  • braindecode.models.BENDR: remove the n_chans_pretrained / chan_proj_max_norm parameters and the channel_projection layer; hard-code the 20 pre-training channels as _BENDR_TARGET_CHS_TUPLES. The official braindecode/braindecode-bendr checkpoint has been re-uploaded flat so from_pretrained now loads its 99 weights (previously 0 of 99 matched silently). Also ships braindecode.models.InterpolatedBENDR, the InterpolatedModel() wrapper that accepts arbitrary user chs_info and projects to the canonical 20 BENDR channels (the SCALE target has no physical position, so its interpolation row is a spatial spline of the user’s EEG — not the dn3 amplitude statistic). (#992 by Pierre Guetschel)

  • braindecode.models.Labram now requires chs_info to match LABRAM_CHANNEL_ORDER exactly (128 channels, canonical order). The on_unknown_chs parameter and the forward-time ch_names argument are removed. Users with arbitrary channel sets should migrate to braindecode.models.InterpolatedLaBraM. (#993 by Pierre Guetschel)

Bug fixes#

  • Fix braindecode.models.SyncNet swapped parameter initialization where phi_ini (phase shift) was using beta_init_values and beta (decay) was using phase_init_values, replaced incorrect .view() reshape with .permute() for proper conv2d filter weight layout, and fixed duplicate default values in docstring (by Sarthak Tayal)

  • Fix braindecode.models.AttentionBaseNet redundant super().__init__() call that ran the parent nn.Module.__init__ twice (by Sarthak Tayal)

  • Fix incomplete author email in braindecode.models.TSception header (by Sarthak Tayal)

  • Fix a time-of-check-time-of-use race in braindecode.datasets.base._zarr_to_memmap() that caused concurrent workers to repeatedly rename-replace the published .npy cache, producing wasted I/O on local filesystems and .nfsXXXX silly-rename files plus SIGBUS crashes on NFSv3. The published file is now created exactly once via os.link and is never replaced, making the cache safe under arbitrary concurrent access on local POSIX, NFSv3, Lustre and SMB (#986 by Pierre Guetschel)

  • Register braindecode.models.BIOT encoder index as a non-trainable buffer instead of a parameter (torch.long), so it is treated as module state rather than trainable weights (#988 by Pierre Guetschel)

  • Fix TypeError: type 'Any' is not subscriptable when importing braindecode.models.config without numpydantic installed on Python 3.12+ (#871 by Sarthak Tayal)

  • Fix braindecode.preprocessing.create_fixed_length_windows() crashing when only window_size_samples is provided without window_stride_samples, stride now defaults to window size as documented (#990 by Sarthak Tayal)

  • Add channel_embedding parameter to braindecode.models.SignalJEPA and braindecode.models.SignalJEPA_Contextual to load pre-trained channel embedding weights when fine-tuning on a subset of the pre-training channels. Two new HuggingFace checkpoints are published: braindecode/signal-jepa and braindecode/signal-jepa_without-chans (#991 by Pierre Guetschel)

  • Bump openneuro-py to >=2026.4.0 so the docs build picks up upstream PR #308 (DatasetFile.key → id). The previous <2026.4 pin (#1000) avoided a libc double-free seen with newer releases but broke examples/datasets_io/plot_bids_dataset_example.py against the live OpenNeuro 5.0.0 GraphQL schema (Cannot query field "key" on type "DatasetFile") (#1002 by Bruno Aristimunha)

  • Retry transient TLS failures from physionet.org when fetching braindecode.datasets.SleepPhysionet (by Bruno Aristimunha)

Current 1.4.0 (stable)#

Enhancements#

API changes#

  • Add braindecode.models.base.EEGModuleMixin.get_config() and braindecode.models.base.EEGModuleMixin.from_config() to all models, enabling full JSON round-trip serialization and reconstruction of any model including all __init__ parameters (by Bruno Aristimunha)

  • push_to_hub() now saves all model parameters to config.json (previously only 6 EEG-specific parameters were saved; model-specific parameters like F1, D, drop_prob were lost on reload) (by Bruno Aristimunha)

  • Add braindecode.modules.Square activation module and update braindecode.models.ShallowFBCSPNet to use type[nn.Module] for conv_nonlin (backward-compatible with callable) (by Bruno Aristimunha)

  • Replace LazyLinear with Linear in braindecode.models.CBraMod when input dimensions are known, improving Hub round-trip compatibility (by Bruno Aristimunha)

Requirements#

  • Relaxed PyTorch requirement to >=2.0 to support Intel-based Macs (by GalAshkenazi1)

Bugs#

  • Improve the error message when from_pretrained() or push_to_hub() are called without the optional huggingface_hub dependency installed. Users now get a clear ImportError with installation instructions (pip install 'braindecode[hub]') instead of an AttributeError. (#1024 by @copilot)

  • Replace the vague license: unknown field in the auto-generated Hugging Face Hub dataset card with an inferred license (when consistent across all recordings’ descriptions) or a please-specify placeholder with a reminder comment for the user to fill in the dataset’s license. (#1014 by Fashad Ahmed)

  • Fix the documentation header “Cite Braindecode” announcement link: it used a bare cite.html URL, which browsers resolve relative to the current page path and led to 404s (for example from install/install.html). The link is now built with Sphinx’s pathto() for each page so it always targets the cite page correctly.

  • Fix braindecode.models.EEGITNet state dict mapping that pointed bias to the weight key and referenced a nonexistent submodule path, and fix third inception branch using the wrong variable for kernel length (by Sarthak Tayal)

  • Fix braindecode.models.EEGInceptionMI state dict mapping typo where the old key was tc.bias instead of fc.bias (by Sarthak Tayal)

  • Fix multi-target channel windowing in braindecode.preprocessing.windowers.create_windows_from_target_channels() to use the union of valid target positions across all misc channels instead of only the first channel (by Sarthak Tayal)

  • Fix braindecode.preprocessing.preprocess.filterbank() to preserve info fields (description, line_freq, device_info, etc.) when creating filtered copies, avoiding merge conflicts in MNE when adding channels (#928 by Bruno Aristimunha)

  • [Outdated:] Restrict to ``pandas>=3.0`` due to incompatibility with ``wfdb`` (#919 by Pierre Guetschel)

  • Fix multiple bugs in Labram positional encoding. Now the braindecode implementation is aligned with the original one (#931 by Pierre Guetschel )

  • Fix Zenodo citation: update to global concept DOI and add BibTeX/APA citation formats in docs/cite.rst, README.rst, CITATION.cff, and docs/conf.py (#937 by Bruno Aristimunha)

  • Fix channel reduction in braindecode.modules.SqueezeAndExcitation to avoid runtime shape mismatches when the reduced channel count differs from the reduction rate (#889 by Sarthak Tayal)

  • Push large datasets to HuggingFace Hub using huggingface_hub.upload_large_folder() to avoid limitations, and allow resuming downloads (#945 and #953 by Pierre Guetschel)

  • Fix braindecode.models.LUNA channel location embeddings repeated along batch dimension instead of patch dimension in prepare_tokens, and include pretrained weight typo mapping in self.mapping (#887 by Sarthak Tayal)

  • Fix temporal generalization tutorial producing degraded results (peak AUC dropped from ~0.9 to ~0.75): MEG data in SI units (T/m) has variances ~1e-23, so BatchNorm1d’s eps=1e-5 dominated the normalization denominator. Now uses epochs.get_data(units="fT/cm") to bring data to a reasonable scale, and removes the misleading “importance of normalization” section whose conclusions were an artifact of the data scale issue (by Bruno Aristimunha)

  • Fix braindecode.augmentation.BandstopFilter notch center frequency range using bandwidth/2 instead of 2*bandwidth to match docstring (#548 by Sarthak Tayal)

  • Fix braindecode.models.DeepSleepNet hardcoded linear layer size that caused a shape mismatch when using input shapes other than the default 1 channel, 3000 timepoints. The FC and BiLSTM input dimensions are now computed dynamically from the CNN output (#755 by Sarthak Tayal)

  • Fix model docstring inheritance: track_model_init_kwargs wrapped __init__ with @wraps before the NumpyDocstringInheritanceInitMeta metaclass ran, causing inspect.unwrap() to bypass the wrapper and read __doc__=None. This replaced every model’s description with the parent mixin’s and marked all model-specific parameters as “The description is missing” when DOCSTRING_INHERITANCE_ENABLE=1 was set during documentation builds (#971 by Bruno Aristimunha)

  • Expose max_nbytes directly on braindecode.preprocessing.preprocess.preprocess() and turn the cryptic mmap can't resize a readonly failure (raised when joblib memory-maps a preloaded array that a preprocessor later tries to resize) into an actionable error explaining how to fix it: pass max_nbytes=None to disable memory mapping, or supply a save_dir so data is reloaded with preload=False (#325 by Sarthak Tayal)

Code health#

  • Reorder model categories in documentation to follow the progression: Convolution, Filterbank, Interpretability, Recurrent, Attention/Transformer, SPD, Graph Neural Network, Channel, and Foundation Model (#962 by Bruno Aristimunha)

  • Fix documentation build warnings and errors: correct numpydoc section underlines in braindecode.models.EEGSym and braindecode.models.SSTDPN, strip upstream .. rubric:: directives from MNE and MOABB docstrings that caused Sphinx errors, fix RST title levels in whats_new.rst, correct bibtex key for EEGPT, and ensure conf.py prioritises the local package on sys.path (by Bruno Aristimunha)

  • Remove deprecated torch.irfft fallback in braindecode.visualization.gradients.compute_amplitude_gradients_for_X(), now uses torch.fft.irfft directly since braindecode requires torch>=2.2 (by Sarthak Tayal)

Current 1.3.2 (stable)#

Enhancements#

API changes#

  • BIDS and Hub modules moved to braindecode.datasets.bids subpackage: braindecode.datasets.bids.hub, braindecode.datasets.bids.hub_format, braindecode.datasets.bids.datasets, braindecode.datasets.bids.hub_validation (#871 by Bruno Aristimunha)

  • Deprecating the old naming of MOABB Dataset name (#826 by Bruno Aristimunha)

  • Exposing the braindecode.datautil.infer_signal_properties() utility function (#856 by Pierre Guetschel)

  • Deprecating the old naming of MOABB Dataset name #826 by Bruno Aristimunha

  • Drop support for Python 3.10 and increase support to Python 3.13 and python 3.14 (#840 by Bruno Aristimunha)

    • Model config helpers now soft-import pydantic/numpydantic; if the optional dependencies are missing the module skips config generation and warns to install pip install braindecode[pydantic].

Bugs#

Current 1.2#

Enhancements#

API changes#

  • Using the name from the original name and deprecation models that we create for no reason, models #775 by Bruno Aristimunha

  • Deprecated the version name in braindecode.models.EEGNetv4 in favour of braindecode.models.EEGNetv.

  • Deprecated the version name in braindecode.models.SleepStagerEldele2021 in favour of braindecode.models.AttnSleep.

  • Deprecated the version name in braindecode.models.TSceptionV1 in favour of braindecode.models.TSception.

Version 1.1.1#

Enhancements#

  • Massive refactor of the model webpage

Bugs#

Version 1.0#

Enhancements#

Bugs#

API changes#

Version 0.8 (11-2022)#

Enhancements#

Bugs#

API changes#

Version 0.7 (10-2022)#

Enhancements#

Bugs#

API changes#

  • Renaming the method get_params to get_augmentation_params in augmentation classes. This makes the Transform module compatible with scikit-learn cloning mechanism (#388 by Bruno Aristimunha and Alex Gramfort)

  • Delaying the deprecation of the preprocessing scale function braindecode.preprocessing.scale() and updates tutorials where the function were used. (#413 by Bruno Aristimunha)

  • Removing deprecated functions and classes braindecode.preprocessing.zscore(), braindecode.datautil.MNEPreproc and braindecode.datautil.NumpyPreproc (#415 by Bruno Aristimunha)

  • Setting iterator_train__drop_last=True by default for braindecode.EEGClassifier and braindecode.EEGRegressor (#411 by Robin Tibor Schirrmeister)

Version 0.6 (2021-12-06)#

Enhancements#

Bugs#

API changes#

Version 0.5.1 (2021-07-14)#

Enhancements#

Bugs#

API changes#

  • Preprocessor classes braindecode.datautil.MNEPreproc and braindecode.datautil.NumpyPreproc are deprecated in favor of braindecode.datautil.Preprocessor (#197 by Hubert Banville)

  • Parameter stop_offset_samples of braindecode.datautil.create_fixed_length_windows() must now be set to None instead of 0 to indicate the end of the recording (#152 by Hubert Banville)

Authors#