Braindecode 1.8.1.dev181543327__tar.gz → 1.8.1.dev181710643__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {braindecode-1.8.1.dev181543327 → braindecode-1.8.1.dev181710643}/NOTICE.txt +1 -0
- {braindecode-1.8.1.dev181543327/braindecode.egg-info → braindecode-1.8.1.dev181710643}/PKG-INFO +1 -1
- {braindecode-1.8.1.dev181543327 → braindecode-1.8.1.dev181710643}/braindecode/augmentation/functional.py +6 -2
- {braindecode-1.8.1.dev181543327 → braindecode-1.8.1.dev181710643}/braindecode/datasets/base.py +4 -1
- {braindecode-1.8.1.dev181543327 → braindecode-1.8.1.dev181710643}/braindecode/datasets/tuh.py +12 -9
- {braindecode-1.8.1.dev181543327 → braindecode-1.8.1.dev181710643}/braindecode/functional/__init__.py +4 -0
- {braindecode-1.8.1.dev181543327 → braindecode-1.8.1.dev181710643}/braindecode/functional/functions.py +100 -4
- {braindecode-1.8.1.dev181543327 → braindecode-1.8.1.dev181710643}/braindecode/models/__init__.py +2 -0
- {braindecode-1.8.1.dev181543327 → braindecode-1.8.1.dev181710643}/braindecode/models/attn_sleep.py +5 -11
- {braindecode-1.8.1.dev181543327 → braindecode-1.8.1.dev181710643}/braindecode/models/axon.py +15 -8
- {braindecode-1.8.1.dev181543327 → braindecode-1.8.1.dev181710643}/braindecode/models/biot.py +7 -2
- {braindecode-1.8.1.dev181543327 → braindecode-1.8.1.dev181710643}/braindecode/models/brant.py +5 -4
- {braindecode-1.8.1.dev181543327 → braindecode-1.8.1.dev181710643}/braindecode/models/codebrain.py +29 -4
- {braindecode-1.8.1.dev181543327 → braindecode-1.8.1.dev181710643}/braindecode/models/csbrain.py +1 -2
- {braindecode-1.8.1.dev181543327 → braindecode-1.8.1.dev181710643}/braindecode/models/eeginception_mi.py +25 -94
- {braindecode-1.8.1.dev181543327 → braindecode-1.8.1.dev181710643}/braindecode/models/eegsym.py +17 -1
- braindecode-1.8.1.dev181710643/braindecode/models/guetschel2026.py +775 -0
- {braindecode-1.8.1.dev181543327 → braindecode-1.8.1.dev181710643}/braindecode/models/luna.py +7 -12
- {braindecode-1.8.1.dev181543327 → braindecode-1.8.1.dev181710643}/braindecode/models/mapa.py +116 -73
- {braindecode-1.8.1.dev181543327 → braindecode-1.8.1.dev181710643}/braindecode/models/medformer.py +24 -19
- {braindecode-1.8.1.dev181543327 → braindecode-1.8.1.dev181710643}/braindecode/models/meta_neuromotor.py +22 -24
- {braindecode-1.8.1.dev181543327 → braindecode-1.8.1.dev181710643}/braindecode/models/msvtnet.py +3 -4
- {braindecode-1.8.1.dev181543327 → braindecode-1.8.1.dev181710643}/braindecode/models/mvpformer.py +46 -56
- {braindecode-1.8.1.dev181543327 → braindecode-1.8.1.dev181710643}/braindecode/models/patchedtransformer.py +0 -1
- {braindecode-1.8.1.dev181543327 → braindecode-1.8.1.dev181710643}/braindecode/models/summary.csv +1 -0
- {braindecode-1.8.1.dev181543327 → braindecode-1.8.1.dev181710643}/braindecode/models/util.py +139 -33
- {braindecode-1.8.1.dev181543327 → braindecode-1.8.1.dev181710643}/braindecode/modules/dance_modules.py +8 -9
- {braindecode-1.8.1.dev181543327 → braindecode-1.8.1.dev181710643}/braindecode/modules/filter.py +3 -14
- {braindecode-1.8.1.dev181543327 → braindecode-1.8.1.dev181710643}/braindecode/modules/quantization.py +5 -5
- {braindecode-1.8.1.dev181543327 → braindecode-1.8.1.dev181710643}/braindecode/preprocessing/preprocess.py +11 -0
- {braindecode-1.8.1.dev181543327 → braindecode-1.8.1.dev181710643}/braindecode/preprocessing/windowers.py +5 -4
- braindecode-1.8.1.dev181710643/braindecode/version.py +1 -0
- {braindecode-1.8.1.dev181543327 → braindecode-1.8.1.dev181710643/braindecode.egg-info}/PKG-INFO +1 -1
- {braindecode-1.8.1.dev181543327 → braindecode-1.8.1.dev181710643}/braindecode.egg-info/SOURCES.txt +1 -0
- {braindecode-1.8.1.dev181543327 → braindecode-1.8.1.dev181710643}/docs/api.rst +5 -0
- {braindecode-1.8.1.dev181543327 → braindecode-1.8.1.dev181710643}/docs/user_guide/channel_strategies.rst +1 -1
- {braindecode-1.8.1.dev181543327 → braindecode-1.8.1.dev181710643}/docs/whats_new.rst +43 -0
- braindecode-1.8.1.dev181543327/braindecode/version.py +0 -1
- {braindecode-1.8.1.dev181543327 → braindecode-1.8.1.dev181710643}/LICENSE.txt +0 -0
- {braindecode-1.8.1.dev181543327 → braindecode-1.8.1.dev181710643}/MANIFEST.in +0 -0
- {braindecode-1.8.1.dev181543327 → braindecode-1.8.1.dev181710643}/README.rst +0 -0
- {braindecode-1.8.1.dev181543327 → braindecode-1.8.1.dev181710643}/braindecode/__init__.py +0 -0
- {braindecode-1.8.1.dev181543327 → braindecode-1.8.1.dev181710643}/braindecode/augmentation/__init__.py +0 -0
- {braindecode-1.8.1.dev181543327 → braindecode-1.8.1.dev181710643}/braindecode/augmentation/base.py +0 -0
- {braindecode-1.8.1.dev181543327 → braindecode-1.8.1.dev181710643}/braindecode/augmentation/transforms.py +0 -0
- {braindecode-1.8.1.dev181543327 → braindecode-1.8.1.dev181710643}/braindecode/classifier.py +0 -0
- {braindecode-1.8.1.dev181543327 → braindecode-1.8.1.dev181710643}/braindecode/datasets/__init__.py +0 -0
- {braindecode-1.8.1.dev181543327 → braindecode-1.8.1.dev181710643}/braindecode/datasets/_notebook_viewer.py +0 -0
- {braindecode-1.8.1.dev181543327 → braindecode-1.8.1.dev181710643}/braindecode/datasets/bbci.py +0 -0
- {braindecode-1.8.1.dev181543327 → braindecode-1.8.1.dev181710643}/braindecode/datasets/bcicomp.py +0 -0
- {braindecode-1.8.1.dev181543327 → braindecode-1.8.1.dev181710643}/braindecode/datasets/bids/__init__.py +0 -0
- {braindecode-1.8.1.dev181543327 → braindecode-1.8.1.dev181710643}/braindecode/datasets/bids/datasets.py +0 -0
- {braindecode-1.8.1.dev181543327 → braindecode-1.8.1.dev181710643}/braindecode/datasets/bids/format.py +0 -0
- {braindecode-1.8.1.dev181543327 → braindecode-1.8.1.dev181710643}/braindecode/datasets/bids/hub.py +0 -0
- {braindecode-1.8.1.dev181543327 → braindecode-1.8.1.dev181710643}/braindecode/datasets/bids/hub_format.py +0 -0
- {braindecode-1.8.1.dev181543327 → braindecode-1.8.1.dev181710643}/braindecode/datasets/bids/hub_io.py +0 -0
- {braindecode-1.8.1.dev181543327 → braindecode-1.8.1.dev181710643}/braindecode/datasets/bids/hub_validation.py +0 -0
- {braindecode-1.8.1.dev181543327 → braindecode-1.8.1.dev181710643}/braindecode/datasets/bids/iterable.py +0 -0
- {braindecode-1.8.1.dev181543327 → braindecode-1.8.1.dev181710643}/braindecode/datasets/chb_mit.py +0 -0
- {braindecode-1.8.1.dev181543327 → braindecode-1.8.1.dev181710643}/braindecode/datasets/collate.py +0 -0
- {braindecode-1.8.1.dev181543327 → braindecode-1.8.1.dev181710643}/braindecode/datasets/mne.py +0 -0
- {braindecode-1.8.1.dev181543327 → braindecode-1.8.1.dev181710643}/braindecode/datasets/moabb.py +0 -0
- {braindecode-1.8.1.dev181543327 → braindecode-1.8.1.dev181710643}/braindecode/datasets/nmt.py +0 -0
- {braindecode-1.8.1.dev181543327 → braindecode-1.8.1.dev181710643}/braindecode/datasets/registry.py +0 -0
- {braindecode-1.8.1.dev181543327 → braindecode-1.8.1.dev181710643}/braindecode/datasets/siena.py +0 -0
- {braindecode-1.8.1.dev181543327 → braindecode-1.8.1.dev181710643}/braindecode/datasets/sleep_physio_challe_18.py +0 -0
- {braindecode-1.8.1.dev181543327 → braindecode-1.8.1.dev181710643}/braindecode/datasets/sleep_physionet.py +0 -0
- {braindecode-1.8.1.dev181543327 → braindecode-1.8.1.dev181710643}/braindecode/datasets/utils.py +0 -0
- {braindecode-1.8.1.dev181543327 → braindecode-1.8.1.dev181710643}/braindecode/datasets/xy.py +0 -0
- {braindecode-1.8.1.dev181543327 → braindecode-1.8.1.dev181710643}/braindecode/datautil/__init__.py +0 -0
- {braindecode-1.8.1.dev181543327 → braindecode-1.8.1.dev181710643}/braindecode/datautil/channel_utils.py +0 -0
- {braindecode-1.8.1.dev181543327 → braindecode-1.8.1.dev181710643}/braindecode/datautil/hub_formats.py +0 -0
- {braindecode-1.8.1.dev181543327 → braindecode-1.8.1.dev181710643}/braindecode/datautil/serialization.py +0 -0
- {braindecode-1.8.1.dev181543327 → braindecode-1.8.1.dev181710643}/braindecode/datautil/util.py +0 -0
- {braindecode-1.8.1.dev181543327 → braindecode-1.8.1.dev181710643}/braindecode/eegneuralnet.py +0 -0
- {braindecode-1.8.1.dev181543327 → braindecode-1.8.1.dev181710643}/braindecode/functional/_real_dft.py +0 -0
- {braindecode-1.8.1.dev181543327 → braindecode-1.8.1.dev181710643}/braindecode/functional/initialization.py +0 -0
- {braindecode-1.8.1.dev181543327 → braindecode-1.8.1.dev181710643}/braindecode/models/atcnet.py +0 -0
- {braindecode-1.8.1.dev181543327 → braindecode-1.8.1.dev181710643}/braindecode/models/attentionbasenet.py +0 -0
- {braindecode-1.8.1.dev181543327 → braindecode-1.8.1.dev181710643}/braindecode/models/barista.py +0 -0
- {braindecode-1.8.1.dev181543327 → braindecode-1.8.1.dev181710643}/braindecode/models/base.py +0 -0
- {braindecode-1.8.1.dev181543327 → braindecode-1.8.1.dev181710643}/braindecode/models/bendr.py +0 -0
- {braindecode-1.8.1.dev181543327 → braindecode-1.8.1.dev181710643}/braindecode/models/brainbert.py +0 -0
- {braindecode-1.8.1.dev181543327 → braindecode-1.8.1.dev181710643}/braindecode/models/brainmodule.py +0 -0
- {braindecode-1.8.1.dev181543327 → braindecode-1.8.1.dev181710643}/braindecode/models/brainomni.py +0 -0
- {braindecode-1.8.1.dev181543327 → braindecode-1.8.1.dev181710643}/braindecode/models/cbramod.py +0 -0
- {braindecode-1.8.1.dev181543327 → braindecode-1.8.1.dev181710643}/braindecode/models/config.py +0 -0
- {braindecode-1.8.1.dev181543327 → braindecode-1.8.1.dev181710643}/braindecode/models/contrawr.py +0 -0
- {braindecode-1.8.1.dev181543327 → braindecode-1.8.1.dev181710643}/braindecode/models/ctnet.py +0 -0
- {braindecode-1.8.1.dev181543327 → braindecode-1.8.1.dev181710643}/braindecode/models/dance.py +0 -0
- {braindecode-1.8.1.dev181543327 → braindecode-1.8.1.dev181710643}/braindecode/models/deep4.py +0 -0
- {braindecode-1.8.1.dev181543327 → braindecode-1.8.1.dev181710643}/braindecode/models/deepsleepnet.py +0 -0
- {braindecode-1.8.1.dev181543327 → braindecode-1.8.1.dev181710643}/braindecode/models/dgcnn.py +0 -0
- {braindecode-1.8.1.dev181543327 → braindecode-1.8.1.dev181710643}/braindecode/models/diver1.py +0 -0
- {braindecode-1.8.1.dev181543327 → braindecode-1.8.1.dev181710643}/braindecode/models/eeg_clip.py +0 -0
- {braindecode-1.8.1.dev181543327 → braindecode-1.8.1.dev181710643}/braindecode/models/eegconformer.py +0 -0
- {braindecode-1.8.1.dev181543327 → braindecode-1.8.1.dev181710643}/braindecode/models/eegdino.py +0 -0
- {braindecode-1.8.1.dev181543327 → braindecode-1.8.1.dev181710643}/braindecode/models/eeginception_erp.py +0 -0
- {braindecode-1.8.1.dev181543327 → braindecode-1.8.1.dev181710643}/braindecode/models/eegitnet.py +0 -0
- {braindecode-1.8.1.dev181543327 → braindecode-1.8.1.dev181710643}/braindecode/models/eegminer.py +0 -0
- {braindecode-1.8.1.dev181543327 → braindecode-1.8.1.dev181710643}/braindecode/models/eegnet.py +0 -0
- {braindecode-1.8.1.dev181543327 → braindecode-1.8.1.dev181710643}/braindecode/models/eegnex.py +0 -0
- {braindecode-1.8.1.dev181543327 → braindecode-1.8.1.dev181710643}/braindecode/models/eegpt.py +0 -0
- {braindecode-1.8.1.dev181543327 → braindecode-1.8.1.dev181710643}/braindecode/models/eegsimpleconv.py +0 -0
- {braindecode-1.8.1.dev181543327 → braindecode-1.8.1.dev181710643}/braindecode/models/eegtcnet.py +0 -0
- {braindecode-1.8.1.dev181543327 → braindecode-1.8.1.dev181710643}/braindecode/models/emg2qwerty.py +0 -0
- {braindecode-1.8.1.dev181543327 → braindecode-1.8.1.dev181710643}/braindecode/models/fbcnet.py +0 -0
- {braindecode-1.8.1.dev181543327 → braindecode-1.8.1.dev181710643}/braindecode/models/fblightconvnet.py +0 -0
- {braindecode-1.8.1.dev181543327 → braindecode-1.8.1.dev181710643}/braindecode/models/fbmsnet.py +0 -0
- {braindecode-1.8.1.dev181543327 → braindecode-1.8.1.dev181710643}/braindecode/models/hybrid.py +0 -0
- {braindecode-1.8.1.dev181543327 → braindecode-1.8.1.dev181710643}/braindecode/models/ifnet.py +0 -0
- {braindecode-1.8.1.dev181543327 → braindecode-1.8.1.dev181710643}/braindecode/models/labram.py +0 -0
- {braindecode-1.8.1.dev181543327 → braindecode-1.8.1.dev181710643}/braindecode/models/mirepnet.py +0 -0
- {braindecode-1.8.1.dev181543327 → braindecode-1.8.1.dev181710643}/braindecode/models/mscformer.py +0 -0
- {braindecode-1.8.1.dev181543327 → braindecode-1.8.1.dev181710643}/braindecode/models/neuropose.py +0 -0
- {braindecode-1.8.1.dev181543327 → braindecode-1.8.1.dev181710643}/braindecode/models/neurorvq.py +0 -0
- {braindecode-1.8.1.dev181543327 → braindecode-1.8.1.dev181710643}/braindecode/models/neurorvq_tokenizer.py +0 -0
- {braindecode-1.8.1.dev181543327 → braindecode-1.8.1.dev181710643}/braindecode/models/popt.py +0 -0
- {braindecode-1.8.1.dev181543327 → braindecode-1.8.1.dev181710643}/braindecode/models/reve.py +0 -0
- {braindecode-1.8.1.dev181543327 → braindecode-1.8.1.dev181710643}/braindecode/models/sccnet.py +0 -0
- {braindecode-1.8.1.dev181543327 → braindecode-1.8.1.dev181710643}/braindecode/models/seizure_transformer.py +0 -0
- {braindecode-1.8.1.dev181543327 → braindecode-1.8.1.dev181710643}/braindecode/models/sensingdynamics.py +0 -0
- {braindecode-1.8.1.dev181543327 → braindecode-1.8.1.dev181710643}/braindecode/models/shallow_fbcsp.py +0 -0
- {braindecode-1.8.1.dev181543327 → braindecode-1.8.1.dev181710643}/braindecode/models/signal_jepa.py +0 -0
- {braindecode-1.8.1.dev181543327 → braindecode-1.8.1.dev181710643}/braindecode/models/sinc_shallow.py +0 -0
- {braindecode-1.8.1.dev181543327 → braindecode-1.8.1.dev181710643}/braindecode/models/sleep_stager_blanco_2020.py +0 -0
- {braindecode-1.8.1.dev181543327 → braindecode-1.8.1.dev181710643}/braindecode/models/sleep_stager_chambon_2018.py +0 -0
- {braindecode-1.8.1.dev181543327 → braindecode-1.8.1.dev181710643}/braindecode/models/sleepfm.py +0 -0
- {braindecode-1.8.1.dev181543327 → braindecode-1.8.1.dev181710643}/braindecode/models/sparcnet.py +0 -0
- {braindecode-1.8.1.dev181543327 → braindecode-1.8.1.dev181710643}/braindecode/models/sstdpn.py +0 -0
- {braindecode-1.8.1.dev181543327 → braindecode-1.8.1.dev181710643}/braindecode/models/steegformer.py +0 -0
- {braindecode-1.8.1.dev181543327 → braindecode-1.8.1.dev181710643}/braindecode/models/syncnet.py +0 -0
- {braindecode-1.8.1.dev181543327 → braindecode-1.8.1.dev181710643}/braindecode/models/tcformer.py +0 -0
- {braindecode-1.8.1.dev181543327 → braindecode-1.8.1.dev181710643}/braindecode/models/tcn.py +0 -0
- {braindecode-1.8.1.dev181543327 → braindecode-1.8.1.dev181710643}/braindecode/models/tfm_tokenizer.py +0 -0
- {braindecode-1.8.1.dev181543327 → braindecode-1.8.1.dev181710643}/braindecode/models/tidnet.py +0 -0
- {braindecode-1.8.1.dev181543327 → braindecode-1.8.1.dev181710643}/braindecode/models/tmsanet.py +0 -0
- {braindecode-1.8.1.dev181543327 → braindecode-1.8.1.dev181710643}/braindecode/models/tsinception.py +0 -0
- {braindecode-1.8.1.dev181543327 → braindecode-1.8.1.dev181710643}/braindecode/models/usleep.py +0 -0
- {braindecode-1.8.1.dev181543327 → braindecode-1.8.1.dev181710643}/braindecode/models/vemg2pose.py +0 -0
- {braindecode-1.8.1.dev181543327 → braindecode-1.8.1.dev181710643}/braindecode/models/zuna.py +0 -0
- {braindecode-1.8.1.dev181543327 → braindecode-1.8.1.dev181710643}/braindecode/modules/__init__.py +0 -0
- {braindecode-1.8.1.dev181543327 → braindecode-1.8.1.dev181710643}/braindecode/modules/activation.py +0 -0
- {braindecode-1.8.1.dev181543327 → braindecode-1.8.1.dev181710643}/braindecode/modules/attention.py +0 -0
- {braindecode-1.8.1.dev181543327 → braindecode-1.8.1.dev181710643}/braindecode/modules/blocks.py +0 -0
- {braindecode-1.8.1.dev181543327 → braindecode-1.8.1.dev181710643}/braindecode/modules/channels.py +0 -0
- {braindecode-1.8.1.dev181543327 → braindecode-1.8.1.dev181710643}/braindecode/modules/convolution.py +0 -0
- {braindecode-1.8.1.dev181543327 → braindecode-1.8.1.dev181710643}/braindecode/modules/layers.py +0 -0
- {braindecode-1.8.1.dev181543327 → braindecode-1.8.1.dev181710643}/braindecode/modules/linear.py +0 -0
- {braindecode-1.8.1.dev181543327 → braindecode-1.8.1.dev181710643}/braindecode/modules/linear_attention.py +0 -0
- {braindecode-1.8.1.dev181543327 → braindecode-1.8.1.dev181710643}/braindecode/modules/parametrization.py +0 -0
- {braindecode-1.8.1.dev181543327 → braindecode-1.8.1.dev181710643}/braindecode/modules/popt_modules.py +0 -0
- {braindecode-1.8.1.dev181543327 → braindecode-1.8.1.dev181710643}/braindecode/modules/stats.py +0 -0
- {braindecode-1.8.1.dev181543327 → braindecode-1.8.1.dev181710643}/braindecode/modules/util.py +0 -0
- {braindecode-1.8.1.dev181543327 → braindecode-1.8.1.dev181710643}/braindecode/modules/wrapper.py +0 -0
- {braindecode-1.8.1.dev181543327 → braindecode-1.8.1.dev181710643}/braindecode/preprocessing/__init__.py +0 -0
- {braindecode-1.8.1.dev181543327 → braindecode-1.8.1.dev181710643}/braindecode/preprocessing/eegprep_preprocess.py +0 -0
- {braindecode-1.8.1.dev181543327 → braindecode-1.8.1.dev181710643}/braindecode/preprocessing/mne_preprocess.py +0 -0
- {braindecode-1.8.1.dev181543327 → braindecode-1.8.1.dev181710643}/braindecode/preprocessing/util.py +0 -0
- {braindecode-1.8.1.dev181543327 → braindecode-1.8.1.dev181710643}/braindecode/regressor.py +0 -0
- {braindecode-1.8.1.dev181543327 → braindecode-1.8.1.dev181710643}/braindecode/samplers/__init__.py +0 -0
- {braindecode-1.8.1.dev181543327 → braindecode-1.8.1.dev181710643}/braindecode/samplers/base.py +0 -0
- {braindecode-1.8.1.dev181543327 → braindecode-1.8.1.dev181710643}/braindecode/samplers/ssl.py +0 -0
- {braindecode-1.8.1.dev181543327 → braindecode-1.8.1.dev181710643}/braindecode/training/__init__.py +0 -0
- {braindecode-1.8.1.dev181543327 → braindecode-1.8.1.dev181710643}/braindecode/training/callbacks.py +0 -0
- {braindecode-1.8.1.dev181543327 → braindecode-1.8.1.dev181710643}/braindecode/training/losses.py +0 -0
- {braindecode-1.8.1.dev181543327 → braindecode-1.8.1.dev181710643}/braindecode/training/scoring.py +0 -0
- {braindecode-1.8.1.dev181543327 → braindecode-1.8.1.dev181710643}/braindecode/util.py +0 -0
- {braindecode-1.8.1.dev181543327 → braindecode-1.8.1.dev181710643}/braindecode/visualization/__init__.py +0 -0
- {braindecode-1.8.1.dev181543327 → braindecode-1.8.1.dev181710643}/braindecode/visualization/activations.py +0 -0
- {braindecode-1.8.1.dev181543327 → braindecode-1.8.1.dev181710643}/braindecode/visualization/attribution.py +0 -0
- {braindecode-1.8.1.dev181543327 → braindecode-1.8.1.dev181710643}/braindecode/visualization/confusion_matrices.py +0 -0
- {braindecode-1.8.1.dev181543327 → braindecode-1.8.1.dev181710643}/braindecode/visualization/frequency.py +0 -0
- {braindecode-1.8.1.dev181543327 → braindecode-1.8.1.dev181710643}/braindecode/visualization/metrics.py +0 -0
- {braindecode-1.8.1.dev181543327 → braindecode-1.8.1.dev181710643}/braindecode/visualization/sanity.py +0 -0
- {braindecode-1.8.1.dev181543327 → braindecode-1.8.1.dev181710643}/braindecode/visualization/topology.py +0 -0
- {braindecode-1.8.1.dev181543327 → braindecode-1.8.1.dev181710643}/braindecode.egg-info/dependency_links.txt +0 -0
- {braindecode-1.8.1.dev181543327 → braindecode-1.8.1.dev181710643}/braindecode.egg-info/requires.txt +0 -0
- {braindecode-1.8.1.dev181543327 → braindecode-1.8.1.dev181710643}/braindecode.egg-info/top_level.txt +0 -0
- {braindecode-1.8.1.dev181543327 → braindecode-1.8.1.dev181710643}/docs/Makefile +0 -0
- {braindecode-1.8.1.dev181543327 → braindecode-1.8.1.dev181710643}/docs/_templates/autosummary/class.rst +0 -0
- {braindecode-1.8.1.dev181543327 → braindecode-1.8.1.dev181710643}/docs/_templates/autosummary/class_in_subdir.rst +0 -0
- {braindecode-1.8.1.dev181543327 → braindecode-1.8.1.dev181710643}/docs/_templates/autosummary/function.rst +0 -0
- {braindecode-1.8.1.dev181543327 → braindecode-1.8.1.dev181710643}/docs/_templates/autosummary/function_in_subdir.rst +0 -0
- {braindecode-1.8.1.dev181543327 → braindecode-1.8.1.dev181710643}/docs/agent_docs.rst +0 -0
- {braindecode-1.8.1.dev181543327 → braindecode-1.8.1.dev181710643}/docs/cite.rst +0 -0
- {braindecode-1.8.1.dev181543327 → braindecode-1.8.1.dev181710643}/docs/conf.py +0 -0
- {braindecode-1.8.1.dev181543327 → braindecode-1.8.1.dev181710643}/docs/help.rst +0 -0
- {braindecode-1.8.1.dev181543327 → braindecode-1.8.1.dev181710643}/docs/index.rst +0 -0
- {braindecode-1.8.1.dev181543327 → braindecode-1.8.1.dev181710643}/docs/install/install.rst +0 -0
- {braindecode-1.8.1.dev181543327 → braindecode-1.8.1.dev181710643}/docs/install/install_pip.rst +0 -0
- {braindecode-1.8.1.dev181543327 → braindecode-1.8.1.dev181710643}/docs/install/install_source.rst +0 -0
- {braindecode-1.8.1.dev181543327 → braindecode-1.8.1.dev181710643}/docs/models/categorization/attention.rst +0 -0
- {braindecode-1.8.1.dev181543327 → braindecode-1.8.1.dev181710643}/docs/models/categorization/channel.rst +0 -0
- {braindecode-1.8.1.dev181543327 → braindecode-1.8.1.dev181710643}/docs/models/categorization/convolution.rst +0 -0
- {braindecode-1.8.1.dev181543327 → braindecode-1.8.1.dev181710643}/docs/models/categorization/filterbank.rst +0 -0
- {braindecode-1.8.1.dev181543327 → braindecode-1.8.1.dev181710643}/docs/models/categorization/gnn.rst +0 -0
- {braindecode-1.8.1.dev181543327 → braindecode-1.8.1.dev181710643}/docs/models/categorization/interpretable.rst +0 -0
- {braindecode-1.8.1.dev181543327 → braindecode-1.8.1.dev181710643}/docs/models/categorization/lbm.rst +0 -0
- {braindecode-1.8.1.dev181543327 → braindecode-1.8.1.dev181710643}/docs/models/categorization/recurrent.rst +0 -0
- {braindecode-1.8.1.dev181543327 → braindecode-1.8.1.dev181710643}/docs/models/categorization/spd.rst +0 -0
- {braindecode-1.8.1.dev181543327 → braindecode-1.8.1.dev181710643}/docs/models/models.rst +0 -0
- {braindecode-1.8.1.dev181543327 → braindecode-1.8.1.dev181710643}/docs/models/models_categorization.rst +0 -0
- {braindecode-1.8.1.dev181543327 → braindecode-1.8.1.dev181710643}/docs/models/models_table.rst +0 -0
- {braindecode-1.8.1.dev181543327 → braindecode-1.8.1.dev181710643}/docs/models/models_visualization.rst +0 -0
- {braindecode-1.8.1.dev181543327 → braindecode-1.8.1.dev181710643}/docs/sg_execution_times.rst +0 -0
- {braindecode-1.8.1.dev181543327 → braindecode-1.8.1.dev181710643}/pyproject.toml +0 -0
- {braindecode-1.8.1.dev181543327 → braindecode-1.8.1.dev181710643}/setup.cfg +0 -0
|
@@ -52,6 +52,7 @@ The following components are licensed under the MIT License:
|
|
|
52
52
|
- `braindecode/modules/linear_attention.py`
|
|
53
53
|
- `braindecode/models/seizure_transformer.py`
|
|
54
54
|
- `docs/_static/model/seizure_transformer_arch.png`
|
|
55
|
+
- `braindecode/models/guetschel2026.py`
|
|
55
56
|
- `braindecode/models/tmsanet.py`
|
|
56
57
|
|
|
57
58
|
The `brainomni.py` file is a derivative of `OpenTSLab/BrainOmni` (MIT), whose
|
{braindecode-1.8.1.dev181543327/braindecode.egg-info → braindecode-1.8.1.dev181710643}/PKG-INFO
RENAMED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: braindecode
|
|
3
|
-
Version: 1.8.1.
|
|
3
|
+
Version: 1.8.1.dev181710643
|
|
4
4
|
Summary: Deep learning software to decode EEG, ECG or MEG signals
|
|
5
5
|
Author-email: Robin Tibor Schirrmeister <robintibor@gmail.com>, Bruno Aristimunha Pinto <b.aristimunha@gmail.com>, Alexandre Gramfort <agramfort@meta.com>
|
|
6
6
|
Maintainer-email: Alexandre Gramfort <agramfort@meta.com>, Bruno Aristimunha Pinto <b.aristimunha@gmail.com>, Robin Tibor Schirrmeister <robintibor@gmail.com>
|
|
@@ -3,6 +3,7 @@
|
|
|
3
3
|
# Gustavo Rodrigues <gustavenrique01@gmail.com>
|
|
4
4
|
# Bruna Lopes <brunajaflopes@gmail.com>
|
|
5
5
|
# Sarthak Tayal <sarthaktayal2@gmail.com>
|
|
6
|
+
# Anton Soloviev <anton@praviel.com>
|
|
6
7
|
#
|
|
7
8
|
# License: BSD (3-clause)
|
|
8
9
|
|
|
@@ -931,7 +932,7 @@ def _rotate_signals(
|
|
|
931
932
|
transformed_X = X.clone()
|
|
932
933
|
sensors_positions = list(sensors_positions_matrix)
|
|
933
934
|
for s, rot_sensors_matrix in enumerate(rot_sensors_matrices):
|
|
934
|
-
rot_sensors_positions = list(rot_sensors_matrix
|
|
935
|
+
rot_sensors_positions = list(rot_sensors_matrix)
|
|
935
936
|
for time in range(X.shape[-1]):
|
|
936
937
|
interpolator_t = Rbf(*sensors_positions, X[s, :, time])
|
|
937
938
|
transformed_X[s, :, time] = torch.from_numpy(
|
|
@@ -1093,7 +1094,8 @@ def segmentation_reconstruction(
|
|
|
1093
1094
|
y : torch.Tensor
|
|
1094
1095
|
EEG labels for the example or batch.
|
|
1095
1096
|
n_segments : int
|
|
1096
|
-
Number of segments to use in the batch.
|
|
1097
|
+
Number of segments to use in the batch. Any remaining samples are
|
|
1098
|
+
included in the last segment.
|
|
1097
1099
|
data_classes : list[tuple[int, torch.Tensor]]
|
|
1098
1100
|
List of tuples. Each tuple contains the class index and the corresponding EEG data.
|
|
1099
1101
|
rand_indices : array-like
|
|
@@ -1133,6 +1135,8 @@ def segmentation_reconstruction(
|
|
|
1133
1135
|
for idx_segment in range(n_segments):
|
|
1134
1136
|
start = idx_segment * segment_size
|
|
1135
1137
|
end = (idx_segment + 1) * segment_size
|
|
1138
|
+
if idx_segment == n_segments - 1:
|
|
1139
|
+
end = window_size
|
|
1136
1140
|
|
|
1137
1141
|
# Perform the data augmentation
|
|
1138
1142
|
X_aug[np.arange(n_trials), :, start:end] = X_class[
|
{braindecode-1.8.1.dev181543327 → braindecode-1.8.1.dev181710643}/braindecode/datasets/base.py
RENAMED
|
@@ -1742,7 +1742,10 @@ class BaseConcatDataset(ConcatDataset, HubDatasetMixin, Generic[T]):
|
|
|
1742
1742
|
# Create path if it doesn't exist
|
|
1743
1743
|
os.makedirs(path, exist_ok=True)
|
|
1744
1744
|
|
|
1745
|
-
|
|
1745
|
+
# With an offset the caller fills one directory piece by piece (preprocess
|
|
1746
|
+
# saves each recording at its index), so the other entries are expected:
|
|
1747
|
+
# skip the scan that would stat them all on every call and list them in a warning.
|
|
1748
|
+
path_contents = os.listdir(path) if offset == 0 else []
|
|
1746
1749
|
n_sub_dirs = len(
|
|
1747
1750
|
[e for e in path_contents if os.path.isdir(os.path.join(path, e))]
|
|
1748
1751
|
)
|
{braindecode-1.8.1.dev181543327 → braindecode-1.8.1.dev181710643}/braindecode/datasets/tuh.py
RENAMED
|
@@ -11,10 +11,12 @@ TUH Abnormal EEG Corpus.
|
|
|
11
11
|
from __future__ import annotations
|
|
12
12
|
|
|
13
13
|
import glob
|
|
14
|
+
import json
|
|
14
15
|
import os
|
|
15
16
|
import re
|
|
16
17
|
import warnings
|
|
17
18
|
from datetime import datetime, timezone
|
|
19
|
+
from functools import cache
|
|
18
20
|
from pathlib import Path
|
|
19
21
|
from typing import Iterable, Literal
|
|
20
22
|
from unittest import mock
|
|
@@ -183,11 +185,8 @@ class TUH(BaseConcatDataset):
|
|
|
183
185
|
}
|
|
184
186
|
raw.rename_channels(mapping_strip)
|
|
185
187
|
|
|
186
|
-
montage1005 = mne.channels.make_standard_montage(
|
|
187
|
-
resolve_montage_name("standard_1005")
|
|
188
|
-
)
|
|
189
188
|
mapping_eeg_names = {
|
|
190
|
-
c.upper(): c for c in
|
|
189
|
+
c.upper(): c for c in _standard_1005().ch_names if c.upper() in raw.ch_names
|
|
191
190
|
}
|
|
192
191
|
|
|
193
192
|
# Set channels whose type could not be inferred (defaulted to "eeg") to "misc":
|
|
@@ -210,10 +209,7 @@ class TUH(BaseConcatDataset):
|
|
|
210
209
|
|
|
211
210
|
@staticmethod
|
|
212
211
|
def _set_montage(raw):
|
|
213
|
-
|
|
214
|
-
resolve_montage_name("standard_1005")
|
|
215
|
-
)
|
|
216
|
-
raw.set_montage(montage, on_missing="ignore")
|
|
212
|
+
raw.set_montage(_standard_1005(), on_missing="ignore")
|
|
217
213
|
|
|
218
214
|
@staticmethod
|
|
219
215
|
def _create_dataset(
|
|
@@ -269,6 +265,12 @@ class TUH(BaseConcatDataset):
|
|
|
269
265
|
return base_dataset
|
|
270
266
|
|
|
271
267
|
|
|
268
|
+
@cache
|
|
269
|
+
def _standard_1005():
|
|
270
|
+
# Built once per process: set_montage copies the montage before using it.
|
|
271
|
+
return mne.channels.make_standard_montage(resolve_montage_name("standard_1005"))
|
|
272
|
+
|
|
273
|
+
|
|
272
274
|
def _create_description(file_paths, version, ds_name):
|
|
273
275
|
descriptions = [
|
|
274
276
|
_parse_description_from_file_path(f, version, ds_name) for f in file_paths
|
|
@@ -289,7 +291,8 @@ def _read_date(file_path):
|
|
|
289
291
|
date_path = file_path.replace(".edf", "_date.txt")
|
|
290
292
|
# if date file exists, read it
|
|
291
293
|
if os.path.exists(date_path):
|
|
292
|
-
|
|
294
|
+
with open(date_path) as f:
|
|
295
|
+
description = json.load(f)
|
|
293
296
|
# otherwise read edf file, extract date and store to file
|
|
294
297
|
else:
|
|
295
298
|
raw = mne.io.read_raw_edf(file_path, preload=False, verbose="error")
|
{braindecode-1.8.1.dev181543327 → braindecode-1.8.1.dev181710643}/braindecode/functional/__init__.py
RENAMED
|
@@ -3,11 +3,13 @@ from .functions import (
|
|
|
3
3
|
daubechies_filters,
|
|
4
4
|
drop_path,
|
|
5
5
|
dwt_max_level,
|
|
6
|
+
fft_conv1d,
|
|
6
7
|
hilbert_freq,
|
|
7
8
|
identity,
|
|
8
9
|
iou_1d,
|
|
9
10
|
pairwise_iou_1d,
|
|
10
11
|
plv_time,
|
|
12
|
+
prefer_fft_conv,
|
|
11
13
|
rotate_pairs,
|
|
12
14
|
safe_log,
|
|
13
15
|
sinusoidal_positional_encoding,
|
|
@@ -22,11 +24,13 @@ __all__ = [
|
|
|
22
24
|
"daubechies_filters",
|
|
23
25
|
"drop_path",
|
|
24
26
|
"dwt_max_level",
|
|
27
|
+
"fft_conv1d",
|
|
25
28
|
"hilbert_freq",
|
|
26
29
|
"identity",
|
|
27
30
|
"iou_1d",
|
|
28
31
|
"pairwise_iou_1d",
|
|
29
32
|
"plv_time",
|
|
33
|
+
"prefer_fft_conv",
|
|
30
34
|
"rotate_pairs",
|
|
31
35
|
"safe_log",
|
|
32
36
|
"sinusoidal_positional_encoding",
|
|
@@ -7,6 +7,7 @@
|
|
|
7
7
|
from __future__ import annotations
|
|
8
8
|
|
|
9
9
|
import math
|
|
10
|
+
from typing import Optional
|
|
10
11
|
|
|
11
12
|
import numpy as np
|
|
12
13
|
import torch
|
|
@@ -54,6 +55,95 @@ def spectral_input(x: torch.Tensor) -> torch.Tensor:
|
|
|
54
55
|
return x.to(torch.promote_types(x.dtype, torch.float32))
|
|
55
56
|
|
|
56
57
|
|
|
58
|
+
def fft_conv1d(
|
|
59
|
+
x: torch.Tensor, weight: torch.Tensor, bias: Optional[torch.Tensor] = None
|
|
60
|
+
) -> torch.Tensor:
|
|
61
|
+
"""``F.conv1d(x, weight, bias, padding="same")`` computed with FFTs.
|
|
62
|
+
|
|
63
|
+
Equal to the direct convolution up to float rounding: the FFT is long
|
|
64
|
+
enough for a linear (not circular) convolution. Its cost barely grows with
|
|
65
|
+
the kernel size, so it is faster than the direct one for long kernels on
|
|
66
|
+
CPU (see :func:`prefer_fft_conv`). float16/bfloat16 inputs are computed in
|
|
67
|
+
float32 (:func:`spectral_input`) and cast back.
|
|
68
|
+
|
|
69
|
+
Parameters
|
|
70
|
+
----------
|
|
71
|
+
x : torch.Tensor
|
|
72
|
+
Input of shape ``(batch, in_channels, n_times)``.
|
|
73
|
+
weight : torch.Tensor
|
|
74
|
+
Kernels of shape ``(out_channels, in_channels, kernel_size)``.
|
|
75
|
+
bias : torch.Tensor | None
|
|
76
|
+
Bias of shape ``(out_channels,)``.
|
|
77
|
+
|
|
78
|
+
Returns
|
|
79
|
+
-------
|
|
80
|
+
torch.Tensor
|
|
81
|
+
Output of shape ``(batch, out_channels, n_times)``, dtype and device of
|
|
82
|
+
``x``. For an even ``kernel_size`` it is aligned like torch's
|
|
83
|
+
``padding="same"`` (the extra zero padded on the right).
|
|
84
|
+
"""
|
|
85
|
+
n_times, kernel_size = x.shape[-1], weight.shape[-1]
|
|
86
|
+
# >= n_times + kernel_size - 1 (no circular wrap-around), even and
|
|
87
|
+
# 5-smooth: the fast cases of a real FFT
|
|
88
|
+
n_fft = 2 * _next_fast_len((n_times + kernel_size) // 2)
|
|
89
|
+
xs = spectral_input(x)
|
|
90
|
+
# conv1d is a cross-correlation: a convolution with the flipped kernel
|
|
91
|
+
x_f = torch.fft.rfft(xs, n=n_fft).permute(2, 0, 1) # (freq, batch, in)
|
|
92
|
+
w_f = torch.fft.rfft(weight.to(xs).flip(-1), n=n_fft).permute(2, 1, 0)
|
|
93
|
+
# Per frequency (batch, in) @ (in, out) in complex numbers, as one real
|
|
94
|
+
# matmul (a complex one is slower on CPU): [Re x; Im x] @ [Re w, Im w]
|
|
95
|
+
# (columns interleaved) holds the four real products.
|
|
96
|
+
p = torch.cat([x_f.real, x_f.imag], 1) @ torch.view_as_real(w_f).flatten(2)
|
|
97
|
+
p = p.unflatten(1, [2, x.shape[0]]).unflatten(3, [-1, 2]) # x re/im, w re/im
|
|
98
|
+
y_f = torch.complex(
|
|
99
|
+
p[:, 0, :, :, 0] - p[:, 1, :, :, 1], p[:, 0, :, :, 1] + p[:, 1, :, :, 0]
|
|
100
|
+
)
|
|
101
|
+
y = torch.fft.irfft(y_f.permute(1, 2, 0), n=n_fft)
|
|
102
|
+
# "same" output t is sample t + kernel_size // 2 of the full convolution
|
|
103
|
+
y = y[..., kernel_size // 2 : kernel_size // 2 + n_times]
|
|
104
|
+
if bias is not None:
|
|
105
|
+
y = y + bias.to(y).unsqueeze(-1)
|
|
106
|
+
return y.to(x)
|
|
107
|
+
|
|
108
|
+
|
|
109
|
+
def prefer_fft_conv(x: torch.Tensor, kernel_size: int) -> bool:
|
|
110
|
+
"""Whether :func:`fft_conv1d` is expected to beat a direct convolution.
|
|
111
|
+
|
|
112
|
+
Rule measured for :class:`~braindecode.models.EEGInceptionMI` (48 to 240
|
|
113
|
+
channels, 128-500 Hz, 2 CPU threads, oneDNN on and off): on CPU the FFT
|
|
114
|
+
wins for float16/bfloat16 inputs (no fast half-precision CPU convolution)
|
|
115
|
+
and from ``batch_size * kernel_size >= 600`` if also
|
|
116
|
+
``in_channels * kernel_size >= 120``: with one or two input channels a
|
|
117
|
+
float32 direct convolution stays cheaper up to k = 85 / 31 (13 long
|
|
118
|
+
temporal convolutions of the model zoo, 22 channels x batch 32). GPUs and
|
|
119
|
+
HPUs (no complex dtype) keep the direct convolution.
|
|
120
|
+
|
|
121
|
+
Parameters
|
|
122
|
+
----------
|
|
123
|
+
x : torch.Tensor
|
|
124
|
+
Input of the convolution, ``(batch, in_channels, n_times)``.
|
|
125
|
+
kernel_size : int
|
|
126
|
+
Kernel length in samples.
|
|
127
|
+
"""
|
|
128
|
+
return x.device.type == "cpu" and (
|
|
129
|
+
x.element_size() == 2
|
|
130
|
+
or (x.shape[0] * kernel_size >= 600 and x.shape[1] * kernel_size >= 120)
|
|
131
|
+
)
|
|
132
|
+
|
|
133
|
+
|
|
134
|
+
def _next_fast_len(n: int) -> int:
|
|
135
|
+
"""Smallest ``2^a 3^b 5^c >= n`` (scipy's ``next_fast_len(n, real=True)``)."""
|
|
136
|
+
n -= 1
|
|
137
|
+
m = 0
|
|
138
|
+
while m != 1:
|
|
139
|
+
n += 1
|
|
140
|
+
m = n
|
|
141
|
+
for p in [2, 3, 5]:
|
|
142
|
+
while m % p == 0:
|
|
143
|
+
m = m // p
|
|
144
|
+
return n
|
|
145
|
+
|
|
146
|
+
|
|
57
147
|
def drop_path(
|
|
58
148
|
x, drop_prob: float = 0.0, training: bool = False, scale_by_keep: bool = True
|
|
59
149
|
):
|
|
@@ -281,18 +371,24 @@ def plv_time(
|
|
|
281
371
|
)
|
|
282
372
|
# Normalize the analytic signal to obtain unit vectors (phasors).
|
|
283
373
|
unit_phasor = analytic_signal / amplitude.unsqueeze(-1)
|
|
374
|
+
# The real/imaginary slices are strided (step 2): matmul copied each of
|
|
375
|
+
# them for every product, per batch matrix. Copy them once.
|
|
376
|
+
real = unit_phasor[..., 0].contiguous()
|
|
377
|
+
imag = unit_phasor[..., 1].contiguous()
|
|
378
|
+
real_t = real.transpose(-2, -1).contiguous()
|
|
379
|
+
imag_t = imag.transpose(-2, -1).contiguous()
|
|
284
380
|
|
|
285
381
|
# Compute the real part of the outer product between phasors of
|
|
286
382
|
# different channels.
|
|
287
|
-
real_real = torch.matmul(
|
|
383
|
+
real_real = torch.matmul(real, real_t)
|
|
288
384
|
|
|
289
385
|
# Compute the imaginary part of the outer product between phasors of
|
|
290
386
|
# different channels.
|
|
291
|
-
imag_imag = torch.matmul(
|
|
387
|
+
imag_imag = torch.matmul(imag, imag_t)
|
|
292
388
|
|
|
293
389
|
# Compute the cross-terms for the real and imaginary parts.
|
|
294
|
-
real_imag = torch.matmul(
|
|
295
|
-
imag_real = torch.matmul(
|
|
390
|
+
real_imag = torch.matmul(real, imag_t)
|
|
391
|
+
imag_real = torch.matmul(imag, real_t)
|
|
296
392
|
|
|
297
393
|
# Combine the real and imaginary parts to form the complex correlation.
|
|
298
394
|
correlation_real = real_real + imag_imag
|
{braindecode-1.8.1.dev181543327 → braindecode-1.8.1.dev181710643}/braindecode/models/__init__.py
RENAMED
|
@@ -39,6 +39,7 @@ from .emg2qwerty import EMG2QwertyNet
|
|
|
39
39
|
from .fbcnet import FBCNet
|
|
40
40
|
from .fblightconvnet import FBLightConvNet
|
|
41
41
|
from .fbmsnet import FBMSNet
|
|
42
|
+
from .guetschel2026 import Guetschel2026
|
|
42
43
|
from .hybrid import HybridNet
|
|
43
44
|
from .ifnet import IFNet
|
|
44
45
|
from .labram import Labram
|
|
@@ -139,6 +140,7 @@ __all__ = [
|
|
|
139
140
|
"FBCNet",
|
|
140
141
|
"FBLightConvNet",
|
|
141
142
|
"FBMSNet",
|
|
143
|
+
"Guetschel2026",
|
|
142
144
|
"MetaNeuromotorHand",
|
|
143
145
|
"HybridNet",
|
|
144
146
|
"IFNet",
|
{braindecode-1.8.1.dev181543327 → braindecode-1.8.1.dev181710643}/braindecode/models/attn_sleep.py
RENAMED
|
@@ -407,16 +407,12 @@ class _MRCNN(nn.Module):
|
|
|
407
407
|
##########################################################################################
|
|
408
408
|
|
|
409
409
|
|
|
410
|
-
def _attention(
|
|
411
|
-
|
|
412
|
-
) -> tuple[torch.Tensor, torch.Tensor]:
|
|
413
|
-
"""Implementation of Scaled dot product attention."""
|
|
410
|
+
def _attention(query: torch.Tensor, key: torch.Tensor) -> torch.Tensor:
|
|
411
|
+
"""Scaled dot product attention weights."""
|
|
414
412
|
# d_k - dimension of the query and key vectors
|
|
415
413
|
d_k = query.size(-1)
|
|
416
414
|
scores = torch.matmul(query, key.transpose(-2, -1)) / math.sqrt(d_k)
|
|
417
|
-
|
|
418
|
-
output = torch.matmul(p_attn, value) # (B, h, T, d_k)
|
|
419
|
-
return output, p_attn
|
|
415
|
+
return F.softmax(scores, dim=-1) # attention weights
|
|
420
416
|
|
|
421
417
|
|
|
422
418
|
class _MultiHeadedAttention(nn.Module):
|
|
@@ -464,10 +460,8 @@ class _MultiHeadedAttention(nn.Module):
|
|
|
464
460
|
.transpose(1, 2)
|
|
465
461
|
)
|
|
466
462
|
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
attn = self.dropout(attn_weights)
|
|
470
|
-
# recompute the weighted sum with dropped weights
|
|
463
|
+
# apply dropout to the *weights*, then the weighted sum
|
|
464
|
+
attn = self.dropout(_attention(query, key))
|
|
471
465
|
x = torch.matmul(attn, value)
|
|
472
466
|
|
|
473
467
|
# merge heads and project
|
{braindecode-1.8.1.dev181543327 → braindecode-1.8.1.dev181710643}/braindecode/models/axon.py
RENAMED
|
@@ -363,8 +363,11 @@ class _AXONEncoder(nn.Module):
|
|
|
363
363
|
position = spatial.unsqueeze(1) + temporal.unsqueeze(0) # (C, P, D)
|
|
364
364
|
tokens = tokens + position.unsqueeze(0).to(tokens.dtype)
|
|
365
365
|
|
|
366
|
-
|
|
367
|
-
band
|
|
366
|
+
# Up to temporal_window + 1 patches the band covers every pair: no mask.
|
|
367
|
+
band: Optional[torch.Tensor] = None
|
|
368
|
+
if n_patches > self.temporal_window + 1:
|
|
369
|
+
index = torch.arange(n_patches, device=tokens.device)
|
|
370
|
+
band = (index[None] - index[:, None]).abs() <= self.temporal_window
|
|
368
371
|
|
|
369
372
|
for block in self.blocks:
|
|
370
373
|
tokens = block(tokens, band)
|
|
@@ -464,19 +467,23 @@ class _AxisAttention(nn.Module):
|
|
|
464
467
|
)
|
|
465
468
|
return attended.transpose(1, 2).reshape(n_seq, length, -1)
|
|
466
469
|
|
|
467
|
-
def forward(self, x: torch.Tensor, band: torch.Tensor) -> torch.Tensor:
|
|
470
|
+
def forward(self, x: torch.Tensor, band: Optional[torch.Tensor]) -> torch.Tensor:
|
|
468
471
|
batch, n_chans, n_patches, dim = x.shape
|
|
469
472
|
axis_weights = self.axis_gate(x) # (B, C, P, 2)
|
|
470
473
|
scale_weights = self.scale_gate(x) # (B, C, P, 2)
|
|
471
474
|
|
|
472
|
-
# Temporal path: one sequence of P tokens per electrode.
|
|
475
|
+
# Temporal path: one sequence of P tokens per electrode. Without a band
|
|
476
|
+
# the restricted branch is the full one; attend once unless the two
|
|
477
|
+
# branches draw their own attention dropout.
|
|
473
478
|
per_channel = self.temporal_qkv(x.reshape(batch * n_chans, n_patches, dim))
|
|
474
479
|
restricted = self.temporal_out(self._attend(per_channel, band)).reshape(
|
|
475
480
|
batch, n_chans, n_patches, dim
|
|
476
481
|
)
|
|
477
|
-
full =
|
|
478
|
-
|
|
479
|
-
|
|
482
|
+
full = restricted
|
|
483
|
+
if band is not None or (self.training and self.att_drop_prob > 0):
|
|
484
|
+
full = self.temporal_out(self._attend(per_channel, None)).reshape(
|
|
485
|
+
batch, n_chans, n_patches, dim
|
|
486
|
+
)
|
|
480
487
|
temporal = scale_weights[..., 0:1] * restricted + scale_weights[..., 1:2] * full
|
|
481
488
|
|
|
482
489
|
# Spatial path: one sequence of C tokens per time step.
|
|
@@ -511,6 +518,6 @@ class _AXONBlock(nn.Module):
|
|
|
511
518
|
self.norm_ffn = nn.RMSNorm(embed_dim, eps=1e-8)
|
|
512
519
|
self.ffn = _GatedFeedForward(embed_dim, ffn_expansion)
|
|
513
520
|
|
|
514
|
-
def forward(self, x: torch.Tensor, band: torch.Tensor) -> torch.Tensor:
|
|
521
|
+
def forward(self, x: torch.Tensor, band: Optional[torch.Tensor]) -> torch.Tensor:
|
|
515
522
|
x = x + self.attn(self.norm_attn(x), band)
|
|
516
523
|
return x + self.ffn(self.norm_ffn(x))
|
{braindecode-1.8.1.dev181543327 → braindecode-1.8.1.dev181710643}/braindecode/models/biot.py
RENAMED
|
@@ -543,10 +543,15 @@ class _BIOTEncoder(nn.Module):
|
|
|
543
543
|
emb: Tensor
|
|
544
544
|
(batch_size, emb_size)
|
|
545
545
|
"""
|
|
546
|
+
batch_size, n_chans, n_times = x.shape
|
|
547
|
+
# One spectrogram for all channels, channel-major so that each
|
|
548
|
+
# channel's (batch, freq, ts) block is contiguous
|
|
549
|
+
spec = self.stft(x.transpose(0, 1).reshape(n_chans * batch_size, 1, n_times))
|
|
550
|
+
spec = spec.unflatten(0, [n_chans, batch_size])
|
|
546
551
|
emb_seq = []
|
|
547
|
-
for i in range(
|
|
552
|
+
for i in range(n_chans):
|
|
548
553
|
# Getting the spectrogram
|
|
549
|
-
channel_spec_emb =
|
|
554
|
+
channel_spec_emb = spec[i]
|
|
550
555
|
# Linear layer to learn some representation over the frequency domain
|
|
551
556
|
# with permutation
|
|
552
557
|
channel_spec_emb = self.patch_embedding(channel_spec_emb)
|
{braindecode-1.8.1.dev181543327 → braindecode-1.8.1.dev181710643}/braindecode/models/brant.py
RENAMED
|
@@ -309,7 +309,7 @@ class Brant(EEGModuleMixin, nn.Module, license="apache-2.0"):
|
|
|
309
309
|
time_z = self.temporal_encoder(tokens, power)
|
|
310
310
|
# 4. spatial encoder over the channels of each patch
|
|
311
311
|
time_z = self.split_time(time_z) # (batch * seq_len, n_chans, embed_dim)
|
|
312
|
-
ch_z
|
|
312
|
+
ch_z = self.spatial_encoder(time_z) # (batch * seq_len, n_chans, embed_dim)
|
|
313
313
|
emb = self.merge_time(ch_z) # (batch, n_chans, seq_len, embed_dim)
|
|
314
314
|
# 5. pool over channels and patches, then classify
|
|
315
315
|
pooled = self.pool(emb) # (batch, embed_dim)
|
|
@@ -474,6 +474,7 @@ class _BrantSpatialEncoder(nn.Module):
|
|
|
474
474
|
)
|
|
475
475
|
self.trans_enc = nn.TransformerEncoder(encoder_layer, num_layers=n_layers)
|
|
476
476
|
|
|
477
|
-
def forward(self, time_z: torch.Tensor) ->
|
|
478
|
-
|
|
479
|
-
|
|
477
|
+
def forward(self, time_z: torch.Tensor) -> torch.Tensor:
|
|
478
|
+
# proj_out (the reconstruction head) is kept for checkpoints, not run:
|
|
479
|
+
# classification does not use its output.
|
|
480
|
+
return self.trans_enc(time_z)
|
{braindecode-1.8.1.dev181543327 → braindecode-1.8.1.dev181710643}/braindecode/models/codebrain.py
RENAMED
|
@@ -697,10 +697,35 @@ class _ResidualBlock(nn.Module):
|
|
|
697
697
|
# Sliding-window attention branch
|
|
698
698
|
# (batch, 2*res_channels, seq_len) -> (batch, seq_len, 2*res_channels)
|
|
699
699
|
h_attn = h_ssm.transpose(1, 2)
|
|
700
|
-
|
|
701
|
-
|
|
702
|
-
|
|
703
|
-
|
|
700
|
+
if (
|
|
701
|
+
self.swa_window_size == 1
|
|
702
|
+
and not self.training
|
|
703
|
+
and not torch.is_grad_enabled()
|
|
704
|
+
and h_attn.device.type == "cpu"
|
|
705
|
+
):
|
|
706
|
+
# A one-wide window keeps only the diagonal: the softmax weights are
|
|
707
|
+
# exactly 1 and 0, so the attention returns its value projection.
|
|
708
|
+
# Same projection calls as nn.MultiheadAttention (on its (seq,
|
|
709
|
+
# batch, embed) view), so the output is unchanged bit for bit. (In
|
|
710
|
+
# training the weights carry dropout; on Gaudi the full attention
|
|
711
|
+
# was faster.)
|
|
712
|
+
# ponytail: the unused query/key projections are computed too, to
|
|
713
|
+
# keep the rounding; in_proj_weight[2E:] alone is ~2x less GEMM.
|
|
714
|
+
embed_dim = self.attention.embed_dim
|
|
715
|
+
seq_first = h_attn.transpose(0, 1)
|
|
716
|
+
value = F.linear(
|
|
717
|
+
seq_first, self.attention.in_proj_weight, self.attention.in_proj_bias
|
|
718
|
+
)[..., 2 * embed_dim :]
|
|
719
|
+
h_attn = (
|
|
720
|
+
self.attention.out_proj(value.reshape(-1, embed_dim))
|
|
721
|
+
.view(seq_first.shape)
|
|
722
|
+
.transpose(0, 1)
|
|
723
|
+
)
|
|
724
|
+
else:
|
|
725
|
+
swa_mask = self.generate_local_window_mask(
|
|
726
|
+
seq_len, self.swa_window_size, x.device, x.dtype
|
|
727
|
+
)
|
|
728
|
+
h_attn, _ = self.attention(h_attn, h_attn, h_attn, attn_mask=swa_mask)
|
|
704
729
|
# (batch, seq_len, 2*res_channels) -> (batch, 2*res_channels, seq_len)
|
|
705
730
|
h_attn = h_attn.transpose(1, 2)
|
|
706
731
|
|
{braindecode-1.8.1.dev181543327 → braindecode-1.8.1.dev181710643}/braindecode/models/csbrain.py
RENAMED
|
@@ -710,8 +710,7 @@ class _CSBrainEncoderLayer(nn.Module):
|
|
|
710
710
|
for start, stop in self.region_bounds:
|
|
711
711
|
region_global = x[:, start:stop, :, :].mean(dim=1, keepdim=True)
|
|
712
712
|
region_global = region_global.permute(0, 2, 1, 3).reshape(batch * T, 1, Fea)
|
|
713
|
-
|
|
714
|
-
global_features[:, idx : idx + 1, :] = region_global
|
|
713
|
+
global_features[:, start:stop, :] = region_global
|
|
715
714
|
x_enhanced = x_flat + self.global_fc(global_features)
|
|
716
715
|
|
|
717
716
|
attn_output = self.inter_region_attn(
|
|
@@ -7,7 +7,7 @@ import torch
|
|
|
7
7
|
from einops.layers.torch import Rearrange
|
|
8
8
|
from torch import nn
|
|
9
9
|
|
|
10
|
-
from braindecode.functional import
|
|
10
|
+
from braindecode.functional import fft_conv1d, prefer_fft_conv
|
|
11
11
|
from braindecode.models.base import EEGModuleMixin
|
|
12
12
|
from braindecode.modules import Ensure4d
|
|
13
13
|
|
|
@@ -57,11 +57,10 @@ class EEGInceptionMI(EEGModuleMixin, nn.Module):
|
|
|
57
57
|
Activation function. Defaults to ReLU activation.
|
|
58
58
|
fft_conv : bool | None, optional
|
|
59
59
|
Compute the temporal convolutions of the inception modules with an FFT
|
|
60
|
-
(
|
|
61
|
-
instead of a direct convolution. ``None`` (default)
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
convolution otherwise, including on GPU and HPU.
|
|
60
|
+
(:func:`~braindecode.functional.fft_conv1d`: same parameters, equal up
|
|
61
|
+
to float rounding) instead of a direct convolution. ``None`` (default)
|
|
62
|
+
decides per input with :func:`~braindecode.functional.prefer_fft_conv`
|
|
63
|
+
(FFT on CPU where it was faster in benchmarks, direct on GPU and HPU).
|
|
65
64
|
|
|
66
65
|
References
|
|
67
66
|
----------
|
|
@@ -298,17 +297,13 @@ class _InceptionModuleMI(nn.Module):
|
|
|
298
297
|
bias=True,
|
|
299
298
|
)
|
|
300
299
|
|
|
301
|
-
# torch's "same" pads one extra zero on the right for even kernels; all
|
|
302
|
-
# kernels share kernel_unit's parity, so forward pads once for all convs.
|
|
303
|
-
self.pad_right = kernel_unit % 2 == 0
|
|
304
|
-
self.max_kernel = (2 * self.n_convs - 1) * kernel_unit
|
|
305
300
|
self.conv_list = nn.ModuleList(
|
|
306
301
|
[
|
|
307
302
|
nn.Conv2d(
|
|
308
303
|
in_channels=self.n_filters,
|
|
309
304
|
out_channels=self.n_filters,
|
|
310
305
|
kernel_size=(1, (n_units * 2 + 1) * kernel_unit),
|
|
311
|
-
padding=
|
|
306
|
+
padding="same",
|
|
312
307
|
bias=True,
|
|
313
308
|
)
|
|
314
309
|
for n_units in range(self.n_convs)
|
|
@@ -324,100 +319,36 @@ class _InceptionModuleMI(nn.Module):
|
|
|
324
319
|
X: torch.Tensor,
|
|
325
320
|
) -> torch.Tensor:
|
|
326
321
|
X1 = self.bottleneck(X)
|
|
322
|
+
k_max = self.conv_list[-1].kernel_size[1]
|
|
327
323
|
if self.fft_conv is None:
|
|
328
|
-
|
|
329
|
-
# in half precision (11-113x) and from 600 samples of batch x kernel.
|
|
330
|
-
use_fft = X.device.type == "cpu" and (
|
|
331
|
-
X.element_size() == 2 or X.shape[0] * self.max_kernel >= 600
|
|
332
|
-
)
|
|
324
|
+
use_fft = prefer_fft_conv(X1, k_max)
|
|
333
325
|
else:
|
|
334
326
|
use_fft = self.fft_conv
|
|
335
327
|
if use_fft:
|
|
336
|
-
|
|
328
|
+
# The parallel convs as one: kernels zero-padded (centred) to the
|
|
329
|
+
# longest, stacked along the output channels.
|
|
330
|
+
weights, biases = [], []
|
|
331
|
+
for conv in self.conv_list:
|
|
332
|
+
pad = (k_max - conv.kernel_size[1]) // 2
|
|
333
|
+
weights.append(nn.functional.pad(conv.weight.squeeze(2), [pad, pad]))
|
|
334
|
+
bias = conv.bias
|
|
335
|
+
if bias is not None:
|
|
336
|
+
biases.append(bias)
|
|
337
|
+
X1 = fft_conv1d(X1.squeeze(2), torch.cat(weights), torch.cat(biases))
|
|
338
|
+
X1 = X1.unsqueeze(2)
|
|
337
339
|
else:
|
|
338
|
-
|
|
339
|
-
X1 = nn.functional.pad(X1, (0, 1))
|
|
340
|
-
branches = [conv(X1) for conv in self.conv_list]
|
|
340
|
+
X1 = torch.cat([conv(X1) for conv in self.conv_list], 1)
|
|
341
341
|
|
|
342
|
-
# channels_last: same values
|
|
343
|
-
#
|
|
342
|
+
# channels_last: same values, but torch's CPU max pool then vectorises
|
|
343
|
+
# over channels instead of looping over them.
|
|
344
344
|
X2 = self.pooling(X.contiguous(memory_format=torch.channels_last))
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
target_len = branches[0].shape[-1]
|
|
348
|
-
|
|
349
|
-
# Crop the pooling output if its length does not match
|
|
350
|
-
if X2.shape[-1] != target_len:
|
|
351
|
-
X2 = X2[..., :target_len]
|
|
352
|
-
|
|
353
|
-
out = torch.cat(branches + [X2], 1)
|
|
345
|
+
# An even kernel_unit pools n_times + 1 samples: drop the last one.
|
|
346
|
+
X2 = self.pooling_conv(X2.contiguous())[..., : X.shape[-1]]
|
|
354
347
|
|
|
348
|
+
out = torch.cat([X1, X2], 1)
|
|
355
349
|
out = self.bn(out)
|
|
356
350
|
return self.activation(out)
|
|
357
351
|
|
|
358
|
-
def _conv_fft(self, X: torch.Tensor) -> torch.Tensor:
|
|
359
|
-
"""Every conv of ``conv_list`` through one rFFT, outputs concatenated.
|
|
360
|
-
|
|
361
|
-
Exact linear convolution (``n_fft >= n_times + k - 1``), aligned like
|
|
362
|
-
torch's "same" padding (for even ``k`` the extra zero is on the right).
|
|
363
|
-
"""
|
|
364
|
-
xs = spectral_input(X.squeeze(2)).permute(2, 0, 1) # (time, batch, in)
|
|
365
|
-
n_times, n_batch = xs.shape[0], xs.shape[1]
|
|
366
|
-
n_fft = _next_fast_len(n_times + self.max_kernel - 1)
|
|
367
|
-
# A conv layer is a cross-correlation, i.e. a convolution with the
|
|
368
|
-
# flipped kernel. Spectra are laid out (freq, in, out).
|
|
369
|
-
kernels = torch.cat(
|
|
370
|
-
[
|
|
371
|
-
torch.fft.rfft(
|
|
372
|
-
conv.weight.squeeze(2).permute(2, 1, 0).flip(0).to(xs),
|
|
373
|
-
n=n_fft,
|
|
374
|
-
dim=0,
|
|
375
|
-
)
|
|
376
|
-
for conv in self.conv_list
|
|
377
|
-
],
|
|
378
|
-
dim=2,
|
|
379
|
-
)
|
|
380
|
-
spec = torch.fft.rfft(xs, n=n_fft, dim=0) # (freq, batch, in)
|
|
381
|
-
# Complex matmul as one real bmm ([re; im] rows times interleaved re/im
|
|
382
|
-
# columns): torch's CPU complex bmm loops over the frequencies.
|
|
383
|
-
prod = torch.bmm(
|
|
384
|
-
torch.cat([torch.real(spec), torch.imag(spec)], 1),
|
|
385
|
-
torch.view_as_real(kernels).flatten(2),
|
|
386
|
-
)
|
|
387
|
-
prod = prod.unflatten(1, [2, n_batch]).unflatten(3, [-1, 2])
|
|
388
|
-
spec = torch.complex(
|
|
389
|
-
prod[:, 0, :, :, 0] - prod[:, 1, :, :, 1],
|
|
390
|
-
prod[:, 0, :, :, 1] + prod[:, 1, :, :, 0],
|
|
391
|
-
)
|
|
392
|
-
full = torch.fft.irfft(spec, n=n_fft, dim=0) # (time, batch, out)
|
|
393
|
-
out = []
|
|
394
|
-
start = 0
|
|
395
|
-
for conv in self.conv_list:
|
|
396
|
-
# "same" output t of a size-k kernel is sample t + k // 2 of the full one
|
|
397
|
-
k = conv.kernel_size[1]
|
|
398
|
-
branch = full[
|
|
399
|
-
k // 2 : k // 2 + n_times, :, start : start + conv.out_channels
|
|
400
|
-
]
|
|
401
|
-
bias = conv.bias
|
|
402
|
-
if bias is not None:
|
|
403
|
-
branch = branch + bias.to(xs)
|
|
404
|
-
out.append(branch)
|
|
405
|
-
start += conv.out_channels
|
|
406
|
-
return torch.cat(out, 2).permute(1, 2, 0).unsqueeze(2).to(X)
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
def _next_fast_len(n: int) -> int:
|
|
410
|
-
"""Smallest ``2^a 3^b 5^c >= n`` (scipy's ``next_fast_len(n, real=True)``)."""
|
|
411
|
-
n -= 1
|
|
412
|
-
m = 0
|
|
413
|
-
while m != 1:
|
|
414
|
-
n += 1
|
|
415
|
-
m = n
|
|
416
|
-
for p in [2, 3, 5]:
|
|
417
|
-
while m % p == 0:
|
|
418
|
-
m = m // p
|
|
419
|
-
return n
|
|
420
|
-
|
|
421
352
|
|
|
422
353
|
class _ResidualModuleMI(nn.Module):
|
|
423
354
|
r"""
|