braindecode 1.8.1.dev168760068__tar.gz → 1.8.1.dev168889947__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.dev168760068 → braindecode-1.8.1.dev168889947}/NOTICE.txt +3 -0
- {braindecode-1.8.1.dev168760068/braindecode.egg-info → braindecode-1.8.1.dev168889947}/PKG-INFO +1 -1
- {braindecode-1.8.1.dev168760068 → braindecode-1.8.1.dev168889947}/braindecode/augmentation/functional.py +5 -1
- {braindecode-1.8.1.dev168760068 → braindecode-1.8.1.dev168889947}/braindecode/functional/__init__.py +4 -0
- {braindecode-1.8.1.dev168760068 → braindecode-1.8.1.dev168889947}/braindecode/functional/functions.py +107 -7
- {braindecode-1.8.1.dev168760068 → braindecode-1.8.1.dev168889947}/braindecode/models/biot.py +16 -7
- {braindecode-1.8.1.dev168760068 → braindecode-1.8.1.dev168889947}/braindecode/models/brainomni.py +75 -40
- {braindecode-1.8.1.dev168760068 → braindecode-1.8.1.dev168889947}/braindecode/models/dance.py +1 -1
- {braindecode-1.8.1.dev168760068 → braindecode-1.8.1.dev168889947}/braindecode/models/eeginception_mi.py +25 -94
- {braindecode-1.8.1.dev168760068 → braindecode-1.8.1.dev168889947}/braindecode/models/eegpt.py +47 -74
- {braindecode-1.8.1.dev168760068 → braindecode-1.8.1.dev168889947}/braindecode/models/labram.py +55 -40
- {braindecode-1.8.1.dev168760068 → braindecode-1.8.1.dev168889947}/braindecode/models/mapa.py +108 -71
- {braindecode-1.8.1.dev168760068 → braindecode-1.8.1.dev168889947}/braindecode/models/mvpformer.py +172 -191
- {braindecode-1.8.1.dev168760068 → braindecode-1.8.1.dev168889947}/braindecode/models/tfm_tokenizer.py +8 -15
- {braindecode-1.8.1.dev168760068 → braindecode-1.8.1.dev168889947}/braindecode/modules/dance_modules.py +32 -23
- {braindecode-1.8.1.dev168760068 → braindecode-1.8.1.dev168889947}/braindecode/modules/filter.py +3 -14
- {braindecode-1.8.1.dev168760068 → braindecode-1.8.1.dev168889947}/braindecode/modules/layers.py +12 -21
- braindecode-1.8.1.dev168889947/braindecode/modules/linear_attention.py +128 -0
- {braindecode-1.8.1.dev168760068 → braindecode-1.8.1.dev168889947}/braindecode/modules/quantization.py +40 -33
- braindecode-1.8.1.dev168889947/braindecode/version.py +1 -0
- {braindecode-1.8.1.dev168760068 → braindecode-1.8.1.dev168889947/braindecode.egg-info}/PKG-INFO +1 -1
- {braindecode-1.8.1.dev168760068 → braindecode-1.8.1.dev168889947}/braindecode.egg-info/SOURCES.txt +1 -0
- {braindecode-1.8.1.dev168760068 → braindecode-1.8.1.dev168889947}/docs/api.rst +2 -0
- {braindecode-1.8.1.dev168760068 → braindecode-1.8.1.dev168889947}/docs/whats_new.rst +33 -0
- braindecode-1.8.1.dev168760068/braindecode/version.py +0 -1
- {braindecode-1.8.1.dev168760068 → braindecode-1.8.1.dev168889947}/LICENSE.txt +0 -0
- {braindecode-1.8.1.dev168760068 → braindecode-1.8.1.dev168889947}/MANIFEST.in +0 -0
- {braindecode-1.8.1.dev168760068 → braindecode-1.8.1.dev168889947}/README.rst +0 -0
- {braindecode-1.8.1.dev168760068 → braindecode-1.8.1.dev168889947}/braindecode/__init__.py +0 -0
- {braindecode-1.8.1.dev168760068 → braindecode-1.8.1.dev168889947}/braindecode/augmentation/__init__.py +0 -0
- {braindecode-1.8.1.dev168760068 → braindecode-1.8.1.dev168889947}/braindecode/augmentation/base.py +0 -0
- {braindecode-1.8.1.dev168760068 → braindecode-1.8.1.dev168889947}/braindecode/augmentation/transforms.py +0 -0
- {braindecode-1.8.1.dev168760068 → braindecode-1.8.1.dev168889947}/braindecode/classifier.py +0 -0
- {braindecode-1.8.1.dev168760068 → braindecode-1.8.1.dev168889947}/braindecode/datasets/__init__.py +0 -0
- {braindecode-1.8.1.dev168760068 → braindecode-1.8.1.dev168889947}/braindecode/datasets/_notebook_viewer.py +0 -0
- {braindecode-1.8.1.dev168760068 → braindecode-1.8.1.dev168889947}/braindecode/datasets/base.py +0 -0
- {braindecode-1.8.1.dev168760068 → braindecode-1.8.1.dev168889947}/braindecode/datasets/bbci.py +0 -0
- {braindecode-1.8.1.dev168760068 → braindecode-1.8.1.dev168889947}/braindecode/datasets/bcicomp.py +0 -0
- {braindecode-1.8.1.dev168760068 → braindecode-1.8.1.dev168889947}/braindecode/datasets/bids/__init__.py +0 -0
- {braindecode-1.8.1.dev168760068 → braindecode-1.8.1.dev168889947}/braindecode/datasets/bids/datasets.py +0 -0
- {braindecode-1.8.1.dev168760068 → braindecode-1.8.1.dev168889947}/braindecode/datasets/bids/format.py +0 -0
- {braindecode-1.8.1.dev168760068 → braindecode-1.8.1.dev168889947}/braindecode/datasets/bids/hub.py +0 -0
- {braindecode-1.8.1.dev168760068 → braindecode-1.8.1.dev168889947}/braindecode/datasets/bids/hub_format.py +0 -0
- {braindecode-1.8.1.dev168760068 → braindecode-1.8.1.dev168889947}/braindecode/datasets/bids/hub_io.py +0 -0
- {braindecode-1.8.1.dev168760068 → braindecode-1.8.1.dev168889947}/braindecode/datasets/bids/hub_validation.py +0 -0
- {braindecode-1.8.1.dev168760068 → braindecode-1.8.1.dev168889947}/braindecode/datasets/bids/iterable.py +0 -0
- {braindecode-1.8.1.dev168760068 → braindecode-1.8.1.dev168889947}/braindecode/datasets/chb_mit.py +0 -0
- {braindecode-1.8.1.dev168760068 → braindecode-1.8.1.dev168889947}/braindecode/datasets/collate.py +0 -0
- {braindecode-1.8.1.dev168760068 → braindecode-1.8.1.dev168889947}/braindecode/datasets/mne.py +0 -0
- {braindecode-1.8.1.dev168760068 → braindecode-1.8.1.dev168889947}/braindecode/datasets/moabb.py +0 -0
- {braindecode-1.8.1.dev168760068 → braindecode-1.8.1.dev168889947}/braindecode/datasets/nmt.py +0 -0
- {braindecode-1.8.1.dev168760068 → braindecode-1.8.1.dev168889947}/braindecode/datasets/registry.py +0 -0
- {braindecode-1.8.1.dev168760068 → braindecode-1.8.1.dev168889947}/braindecode/datasets/siena.py +0 -0
- {braindecode-1.8.1.dev168760068 → braindecode-1.8.1.dev168889947}/braindecode/datasets/sleep_physio_challe_18.py +0 -0
- {braindecode-1.8.1.dev168760068 → braindecode-1.8.1.dev168889947}/braindecode/datasets/sleep_physionet.py +0 -0
- {braindecode-1.8.1.dev168760068 → braindecode-1.8.1.dev168889947}/braindecode/datasets/tuh.py +0 -0
- {braindecode-1.8.1.dev168760068 → braindecode-1.8.1.dev168889947}/braindecode/datasets/utils.py +0 -0
- {braindecode-1.8.1.dev168760068 → braindecode-1.8.1.dev168889947}/braindecode/datasets/xy.py +0 -0
- {braindecode-1.8.1.dev168760068 → braindecode-1.8.1.dev168889947}/braindecode/datautil/__init__.py +0 -0
- {braindecode-1.8.1.dev168760068 → braindecode-1.8.1.dev168889947}/braindecode/datautil/channel_utils.py +0 -0
- {braindecode-1.8.1.dev168760068 → braindecode-1.8.1.dev168889947}/braindecode/datautil/hub_formats.py +0 -0
- {braindecode-1.8.1.dev168760068 → braindecode-1.8.1.dev168889947}/braindecode/datautil/serialization.py +0 -0
- {braindecode-1.8.1.dev168760068 → braindecode-1.8.1.dev168889947}/braindecode/datautil/util.py +0 -0
- {braindecode-1.8.1.dev168760068 → braindecode-1.8.1.dev168889947}/braindecode/eegneuralnet.py +0 -0
- {braindecode-1.8.1.dev168760068 → braindecode-1.8.1.dev168889947}/braindecode/functional/_real_dft.py +0 -0
- {braindecode-1.8.1.dev168760068 → braindecode-1.8.1.dev168889947}/braindecode/functional/initialization.py +0 -0
- {braindecode-1.8.1.dev168760068 → braindecode-1.8.1.dev168889947}/braindecode/models/__init__.py +0 -0
- {braindecode-1.8.1.dev168760068 → braindecode-1.8.1.dev168889947}/braindecode/models/atcnet.py +0 -0
- {braindecode-1.8.1.dev168760068 → braindecode-1.8.1.dev168889947}/braindecode/models/attentionbasenet.py +0 -0
- {braindecode-1.8.1.dev168760068 → braindecode-1.8.1.dev168889947}/braindecode/models/attn_sleep.py +0 -0
- {braindecode-1.8.1.dev168760068 → braindecode-1.8.1.dev168889947}/braindecode/models/axon.py +0 -0
- {braindecode-1.8.1.dev168760068 → braindecode-1.8.1.dev168889947}/braindecode/models/barista.py +0 -0
- {braindecode-1.8.1.dev168760068 → braindecode-1.8.1.dev168889947}/braindecode/models/base.py +0 -0
- {braindecode-1.8.1.dev168760068 → braindecode-1.8.1.dev168889947}/braindecode/models/bendr.py +0 -0
- {braindecode-1.8.1.dev168760068 → braindecode-1.8.1.dev168889947}/braindecode/models/brainbert.py +0 -0
- {braindecode-1.8.1.dev168760068 → braindecode-1.8.1.dev168889947}/braindecode/models/brainmodule.py +0 -0
- {braindecode-1.8.1.dev168760068 → braindecode-1.8.1.dev168889947}/braindecode/models/brant.py +0 -0
- {braindecode-1.8.1.dev168760068 → braindecode-1.8.1.dev168889947}/braindecode/models/cbramod.py +0 -0
- {braindecode-1.8.1.dev168760068 → braindecode-1.8.1.dev168889947}/braindecode/models/codebrain.py +0 -0
- {braindecode-1.8.1.dev168760068 → braindecode-1.8.1.dev168889947}/braindecode/models/config.py +0 -0
- {braindecode-1.8.1.dev168760068 → braindecode-1.8.1.dev168889947}/braindecode/models/contrawr.py +0 -0
- {braindecode-1.8.1.dev168760068 → braindecode-1.8.1.dev168889947}/braindecode/models/csbrain.py +0 -0
- {braindecode-1.8.1.dev168760068 → braindecode-1.8.1.dev168889947}/braindecode/models/ctnet.py +0 -0
- {braindecode-1.8.1.dev168760068 → braindecode-1.8.1.dev168889947}/braindecode/models/deep4.py +0 -0
- {braindecode-1.8.1.dev168760068 → braindecode-1.8.1.dev168889947}/braindecode/models/deepsleepnet.py +0 -0
- {braindecode-1.8.1.dev168760068 → braindecode-1.8.1.dev168889947}/braindecode/models/dgcnn.py +0 -0
- {braindecode-1.8.1.dev168760068 → braindecode-1.8.1.dev168889947}/braindecode/models/diver1.py +0 -0
- {braindecode-1.8.1.dev168760068 → braindecode-1.8.1.dev168889947}/braindecode/models/eeg_clip.py +0 -0
- {braindecode-1.8.1.dev168760068 → braindecode-1.8.1.dev168889947}/braindecode/models/eegconformer.py +0 -0
- {braindecode-1.8.1.dev168760068 → braindecode-1.8.1.dev168889947}/braindecode/models/eegdino.py +0 -0
- {braindecode-1.8.1.dev168760068 → braindecode-1.8.1.dev168889947}/braindecode/models/eeginception_erp.py +0 -0
- {braindecode-1.8.1.dev168760068 → braindecode-1.8.1.dev168889947}/braindecode/models/eegitnet.py +0 -0
- {braindecode-1.8.1.dev168760068 → braindecode-1.8.1.dev168889947}/braindecode/models/eegminer.py +0 -0
- {braindecode-1.8.1.dev168760068 → braindecode-1.8.1.dev168889947}/braindecode/models/eegnet.py +0 -0
- {braindecode-1.8.1.dev168760068 → braindecode-1.8.1.dev168889947}/braindecode/models/eegnex.py +0 -0
- {braindecode-1.8.1.dev168760068 → braindecode-1.8.1.dev168889947}/braindecode/models/eegsimpleconv.py +0 -0
- {braindecode-1.8.1.dev168760068 → braindecode-1.8.1.dev168889947}/braindecode/models/eegsym.py +0 -0
- {braindecode-1.8.1.dev168760068 → braindecode-1.8.1.dev168889947}/braindecode/models/eegtcnet.py +0 -0
- {braindecode-1.8.1.dev168760068 → braindecode-1.8.1.dev168889947}/braindecode/models/emg2qwerty.py +0 -0
- {braindecode-1.8.1.dev168760068 → braindecode-1.8.1.dev168889947}/braindecode/models/fbcnet.py +0 -0
- {braindecode-1.8.1.dev168760068 → braindecode-1.8.1.dev168889947}/braindecode/models/fblightconvnet.py +0 -0
- {braindecode-1.8.1.dev168760068 → braindecode-1.8.1.dev168889947}/braindecode/models/fbmsnet.py +0 -0
- {braindecode-1.8.1.dev168760068 → braindecode-1.8.1.dev168889947}/braindecode/models/hybrid.py +0 -0
- {braindecode-1.8.1.dev168760068 → braindecode-1.8.1.dev168889947}/braindecode/models/ifnet.py +0 -0
- {braindecode-1.8.1.dev168760068 → braindecode-1.8.1.dev168889947}/braindecode/models/luna.py +0 -0
- {braindecode-1.8.1.dev168760068 → braindecode-1.8.1.dev168889947}/braindecode/models/medformer.py +0 -0
- {braindecode-1.8.1.dev168760068 → braindecode-1.8.1.dev168889947}/braindecode/models/meta_neuromotor.py +0 -0
- {braindecode-1.8.1.dev168760068 → braindecode-1.8.1.dev168889947}/braindecode/models/mirepnet.py +0 -0
- {braindecode-1.8.1.dev168760068 → braindecode-1.8.1.dev168889947}/braindecode/models/mscformer.py +0 -0
- {braindecode-1.8.1.dev168760068 → braindecode-1.8.1.dev168889947}/braindecode/models/msvtnet.py +0 -0
- {braindecode-1.8.1.dev168760068 → braindecode-1.8.1.dev168889947}/braindecode/models/neuropose.py +0 -0
- {braindecode-1.8.1.dev168760068 → braindecode-1.8.1.dev168889947}/braindecode/models/neurorvq.py +0 -0
- {braindecode-1.8.1.dev168760068 → braindecode-1.8.1.dev168889947}/braindecode/models/neurorvq_tokenizer.py +0 -0
- {braindecode-1.8.1.dev168760068 → braindecode-1.8.1.dev168889947}/braindecode/models/patchedtransformer.py +0 -0
- {braindecode-1.8.1.dev168760068 → braindecode-1.8.1.dev168889947}/braindecode/models/popt.py +0 -0
- {braindecode-1.8.1.dev168760068 → braindecode-1.8.1.dev168889947}/braindecode/models/reve.py +0 -0
- {braindecode-1.8.1.dev168760068 → braindecode-1.8.1.dev168889947}/braindecode/models/sccnet.py +0 -0
- {braindecode-1.8.1.dev168760068 → braindecode-1.8.1.dev168889947}/braindecode/models/seizure_transformer.py +0 -0
- {braindecode-1.8.1.dev168760068 → braindecode-1.8.1.dev168889947}/braindecode/models/sensingdynamics.py +0 -0
- {braindecode-1.8.1.dev168760068 → braindecode-1.8.1.dev168889947}/braindecode/models/shallow_fbcsp.py +0 -0
- {braindecode-1.8.1.dev168760068 → braindecode-1.8.1.dev168889947}/braindecode/models/signal_jepa.py +0 -0
- {braindecode-1.8.1.dev168760068 → braindecode-1.8.1.dev168889947}/braindecode/models/sinc_shallow.py +0 -0
- {braindecode-1.8.1.dev168760068 → braindecode-1.8.1.dev168889947}/braindecode/models/sleep_stager_blanco_2020.py +0 -0
- {braindecode-1.8.1.dev168760068 → braindecode-1.8.1.dev168889947}/braindecode/models/sleep_stager_chambon_2018.py +0 -0
- {braindecode-1.8.1.dev168760068 → braindecode-1.8.1.dev168889947}/braindecode/models/sleepfm.py +0 -0
- {braindecode-1.8.1.dev168760068 → braindecode-1.8.1.dev168889947}/braindecode/models/sparcnet.py +0 -0
- {braindecode-1.8.1.dev168760068 → braindecode-1.8.1.dev168889947}/braindecode/models/sstdpn.py +0 -0
- {braindecode-1.8.1.dev168760068 → braindecode-1.8.1.dev168889947}/braindecode/models/steegformer.py +0 -0
- {braindecode-1.8.1.dev168760068 → braindecode-1.8.1.dev168889947}/braindecode/models/summary.csv +0 -0
- {braindecode-1.8.1.dev168760068 → braindecode-1.8.1.dev168889947}/braindecode/models/syncnet.py +0 -0
- {braindecode-1.8.1.dev168760068 → braindecode-1.8.1.dev168889947}/braindecode/models/tcformer.py +0 -0
- {braindecode-1.8.1.dev168760068 → braindecode-1.8.1.dev168889947}/braindecode/models/tcn.py +0 -0
- {braindecode-1.8.1.dev168760068 → braindecode-1.8.1.dev168889947}/braindecode/models/tidnet.py +0 -0
- {braindecode-1.8.1.dev168760068 → braindecode-1.8.1.dev168889947}/braindecode/models/tmsanet.py +0 -0
- {braindecode-1.8.1.dev168760068 → braindecode-1.8.1.dev168889947}/braindecode/models/tsinception.py +0 -0
- {braindecode-1.8.1.dev168760068 → braindecode-1.8.1.dev168889947}/braindecode/models/usleep.py +0 -0
- {braindecode-1.8.1.dev168760068 → braindecode-1.8.1.dev168889947}/braindecode/models/util.py +0 -0
- {braindecode-1.8.1.dev168760068 → braindecode-1.8.1.dev168889947}/braindecode/models/vemg2pose.py +0 -0
- {braindecode-1.8.1.dev168760068 → braindecode-1.8.1.dev168889947}/braindecode/models/zuna.py +0 -0
- {braindecode-1.8.1.dev168760068 → braindecode-1.8.1.dev168889947}/braindecode/modules/__init__.py +0 -0
- {braindecode-1.8.1.dev168760068 → braindecode-1.8.1.dev168889947}/braindecode/modules/activation.py +0 -0
- {braindecode-1.8.1.dev168760068 → braindecode-1.8.1.dev168889947}/braindecode/modules/attention.py +0 -0
- {braindecode-1.8.1.dev168760068 → braindecode-1.8.1.dev168889947}/braindecode/modules/blocks.py +0 -0
- {braindecode-1.8.1.dev168760068 → braindecode-1.8.1.dev168889947}/braindecode/modules/channels.py +0 -0
- {braindecode-1.8.1.dev168760068 → braindecode-1.8.1.dev168889947}/braindecode/modules/convolution.py +0 -0
- {braindecode-1.8.1.dev168760068 → braindecode-1.8.1.dev168889947}/braindecode/modules/linear.py +0 -0
- {braindecode-1.8.1.dev168760068 → braindecode-1.8.1.dev168889947}/braindecode/modules/parametrization.py +0 -0
- {braindecode-1.8.1.dev168760068 → braindecode-1.8.1.dev168889947}/braindecode/modules/popt_modules.py +0 -0
- {braindecode-1.8.1.dev168760068 → braindecode-1.8.1.dev168889947}/braindecode/modules/stats.py +0 -0
- {braindecode-1.8.1.dev168760068 → braindecode-1.8.1.dev168889947}/braindecode/modules/util.py +0 -0
- {braindecode-1.8.1.dev168760068 → braindecode-1.8.1.dev168889947}/braindecode/modules/wrapper.py +0 -0
- {braindecode-1.8.1.dev168760068 → braindecode-1.8.1.dev168889947}/braindecode/preprocessing/__init__.py +0 -0
- {braindecode-1.8.1.dev168760068 → braindecode-1.8.1.dev168889947}/braindecode/preprocessing/eegprep_preprocess.py +0 -0
- {braindecode-1.8.1.dev168760068 → braindecode-1.8.1.dev168889947}/braindecode/preprocessing/mne_preprocess.py +0 -0
- {braindecode-1.8.1.dev168760068 → braindecode-1.8.1.dev168889947}/braindecode/preprocessing/preprocess.py +0 -0
- {braindecode-1.8.1.dev168760068 → braindecode-1.8.1.dev168889947}/braindecode/preprocessing/util.py +0 -0
- {braindecode-1.8.1.dev168760068 → braindecode-1.8.1.dev168889947}/braindecode/preprocessing/windowers.py +0 -0
- {braindecode-1.8.1.dev168760068 → braindecode-1.8.1.dev168889947}/braindecode/regressor.py +0 -0
- {braindecode-1.8.1.dev168760068 → braindecode-1.8.1.dev168889947}/braindecode/samplers/__init__.py +0 -0
- {braindecode-1.8.1.dev168760068 → braindecode-1.8.1.dev168889947}/braindecode/samplers/base.py +0 -0
- {braindecode-1.8.1.dev168760068 → braindecode-1.8.1.dev168889947}/braindecode/samplers/ssl.py +0 -0
- {braindecode-1.8.1.dev168760068 → braindecode-1.8.1.dev168889947}/braindecode/training/__init__.py +0 -0
- {braindecode-1.8.1.dev168760068 → braindecode-1.8.1.dev168889947}/braindecode/training/callbacks.py +0 -0
- {braindecode-1.8.1.dev168760068 → braindecode-1.8.1.dev168889947}/braindecode/training/losses.py +0 -0
- {braindecode-1.8.1.dev168760068 → braindecode-1.8.1.dev168889947}/braindecode/training/scoring.py +0 -0
- {braindecode-1.8.1.dev168760068 → braindecode-1.8.1.dev168889947}/braindecode/util.py +0 -0
- {braindecode-1.8.1.dev168760068 → braindecode-1.8.1.dev168889947}/braindecode/visualization/__init__.py +0 -0
- {braindecode-1.8.1.dev168760068 → braindecode-1.8.1.dev168889947}/braindecode/visualization/activations.py +0 -0
- {braindecode-1.8.1.dev168760068 → braindecode-1.8.1.dev168889947}/braindecode/visualization/attribution.py +0 -0
- {braindecode-1.8.1.dev168760068 → braindecode-1.8.1.dev168889947}/braindecode/visualization/confusion_matrices.py +0 -0
- {braindecode-1.8.1.dev168760068 → braindecode-1.8.1.dev168889947}/braindecode/visualization/frequency.py +0 -0
- {braindecode-1.8.1.dev168760068 → braindecode-1.8.1.dev168889947}/braindecode/visualization/metrics.py +0 -0
- {braindecode-1.8.1.dev168760068 → braindecode-1.8.1.dev168889947}/braindecode/visualization/sanity.py +0 -0
- {braindecode-1.8.1.dev168760068 → braindecode-1.8.1.dev168889947}/braindecode/visualization/topology.py +0 -0
- {braindecode-1.8.1.dev168760068 → braindecode-1.8.1.dev168889947}/braindecode.egg-info/dependency_links.txt +0 -0
- {braindecode-1.8.1.dev168760068 → braindecode-1.8.1.dev168889947}/braindecode.egg-info/requires.txt +0 -0
- {braindecode-1.8.1.dev168760068 → braindecode-1.8.1.dev168889947}/braindecode.egg-info/top_level.txt +0 -0
- {braindecode-1.8.1.dev168760068 → braindecode-1.8.1.dev168889947}/docs/Makefile +0 -0
- {braindecode-1.8.1.dev168760068 → braindecode-1.8.1.dev168889947}/docs/_templates/autosummary/class.rst +0 -0
- {braindecode-1.8.1.dev168760068 → braindecode-1.8.1.dev168889947}/docs/_templates/autosummary/class_in_subdir.rst +0 -0
- {braindecode-1.8.1.dev168760068 → braindecode-1.8.1.dev168889947}/docs/_templates/autosummary/function.rst +0 -0
- {braindecode-1.8.1.dev168760068 → braindecode-1.8.1.dev168889947}/docs/_templates/autosummary/function_in_subdir.rst +0 -0
- {braindecode-1.8.1.dev168760068 → braindecode-1.8.1.dev168889947}/docs/agent_docs.rst +0 -0
- {braindecode-1.8.1.dev168760068 → braindecode-1.8.1.dev168889947}/docs/cite.rst +0 -0
- {braindecode-1.8.1.dev168760068 → braindecode-1.8.1.dev168889947}/docs/conf.py +0 -0
- {braindecode-1.8.1.dev168760068 → braindecode-1.8.1.dev168889947}/docs/help.rst +0 -0
- {braindecode-1.8.1.dev168760068 → braindecode-1.8.1.dev168889947}/docs/index.rst +0 -0
- {braindecode-1.8.1.dev168760068 → braindecode-1.8.1.dev168889947}/docs/install/install.rst +0 -0
- {braindecode-1.8.1.dev168760068 → braindecode-1.8.1.dev168889947}/docs/install/install_pip.rst +0 -0
- {braindecode-1.8.1.dev168760068 → braindecode-1.8.1.dev168889947}/docs/install/install_source.rst +0 -0
- {braindecode-1.8.1.dev168760068 → braindecode-1.8.1.dev168889947}/docs/models/categorization/attention.rst +0 -0
- {braindecode-1.8.1.dev168760068 → braindecode-1.8.1.dev168889947}/docs/models/categorization/channel.rst +0 -0
- {braindecode-1.8.1.dev168760068 → braindecode-1.8.1.dev168889947}/docs/models/categorization/convolution.rst +0 -0
- {braindecode-1.8.1.dev168760068 → braindecode-1.8.1.dev168889947}/docs/models/categorization/filterbank.rst +0 -0
- {braindecode-1.8.1.dev168760068 → braindecode-1.8.1.dev168889947}/docs/models/categorization/gnn.rst +0 -0
- {braindecode-1.8.1.dev168760068 → braindecode-1.8.1.dev168889947}/docs/models/categorization/interpretable.rst +0 -0
- {braindecode-1.8.1.dev168760068 → braindecode-1.8.1.dev168889947}/docs/models/categorization/lbm.rst +0 -0
- {braindecode-1.8.1.dev168760068 → braindecode-1.8.1.dev168889947}/docs/models/categorization/recurrent.rst +0 -0
- {braindecode-1.8.1.dev168760068 → braindecode-1.8.1.dev168889947}/docs/models/categorization/spd.rst +0 -0
- {braindecode-1.8.1.dev168760068 → braindecode-1.8.1.dev168889947}/docs/models/models.rst +0 -0
- {braindecode-1.8.1.dev168760068 → braindecode-1.8.1.dev168889947}/docs/models/models_categorization.rst +0 -0
- {braindecode-1.8.1.dev168760068 → braindecode-1.8.1.dev168889947}/docs/models/models_table.rst +0 -0
- {braindecode-1.8.1.dev168760068 → braindecode-1.8.1.dev168889947}/docs/models/models_visualization.rst +0 -0
- {braindecode-1.8.1.dev168760068 → braindecode-1.8.1.dev168889947}/docs/sg_execution_times.rst +0 -0
- {braindecode-1.8.1.dev168760068 → braindecode-1.8.1.dev168889947}/docs/user_guide/channel_strategies.rst +0 -0
- {braindecode-1.8.1.dev168760068 → braindecode-1.8.1.dev168889947}/pyproject.toml +0 -0
- {braindecode-1.8.1.dev168760068 → braindecode-1.8.1.dev168889947}/setup.cfg +0 -0
|
@@ -49,6 +49,7 @@ The following components are licensed under the MIT License:
|
|
|
49
49
|
- `braindecode/modules/popt_modules.py`
|
|
50
50
|
- `braindecode/models/brainomni.py`
|
|
51
51
|
- `braindecode/modules/quantization.py`
|
|
52
|
+
- `braindecode/modules/linear_attention.py`
|
|
52
53
|
- `braindecode/models/seizure_transformer.py`
|
|
53
54
|
- `docs/_static/model/seizure_transformer_arch.png`
|
|
54
55
|
- `braindecode/models/tmsanet.py`
|
|
@@ -57,6 +58,8 @@ The `brainomni.py` file is a derivative of `OpenTSLab/BrainOmni` (MIT), whose
|
|
|
57
58
|
SEANet codec derives from Meta's `facebookresearch/encodec` (MIT). The
|
|
58
59
|
`quantization.py` module holds the residual vector quantization derived from
|
|
59
60
|
`lucidrains/vector-quantize-pytorch` (MIT) and the BrainOmni port.
|
|
61
|
+
The `linear_attention.py` module is the part of
|
|
62
|
+
`lucidrains/linear-attention-transformer` (MIT) that BIOT and TFMTokenizer run.
|
|
60
63
|
|
|
61
64
|
### Apache-2.0 Licensed Files
|
|
62
65
|
|
{braindecode-1.8.1.dev168760068/braindecode.egg-info → braindecode-1.8.1.dev168889947}/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.dev168889947
|
|
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
|
|
|
@@ -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.dev168760068 → braindecode-1.8.1.dev168889947}/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,91 @@ 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``. GPUs and HPUs (no complex
|
|
116
|
+
dtype) keep the direct convolution.
|
|
117
|
+
|
|
118
|
+
Parameters
|
|
119
|
+
----------
|
|
120
|
+
x : torch.Tensor
|
|
121
|
+
Input of the convolution, ``(batch, in_channels, n_times)``.
|
|
122
|
+
kernel_size : int
|
|
123
|
+
Kernel length in samples.
|
|
124
|
+
"""
|
|
125
|
+
return x.device.type == "cpu" and (
|
|
126
|
+
x.element_size() == 2 or x.shape[0] * kernel_size >= 600
|
|
127
|
+
)
|
|
128
|
+
|
|
129
|
+
|
|
130
|
+
def _next_fast_len(n: int) -> int:
|
|
131
|
+
"""Smallest ``2^a 3^b 5^c >= n`` (scipy's ``next_fast_len(n, real=True)``)."""
|
|
132
|
+
n -= 1
|
|
133
|
+
m = 0
|
|
134
|
+
while m != 1:
|
|
135
|
+
n += 1
|
|
136
|
+
m = n
|
|
137
|
+
for p in [2, 3, 5]:
|
|
138
|
+
while m % p == 0:
|
|
139
|
+
m = m // p
|
|
140
|
+
return n
|
|
141
|
+
|
|
142
|
+
|
|
57
143
|
def drop_path(
|
|
58
144
|
x, drop_prob: float = 0.0, training: bool = False, scale_by_keep: bool = True
|
|
59
145
|
):
|
|
@@ -281,18 +367,24 @@ def plv_time(
|
|
|
281
367
|
)
|
|
282
368
|
# Normalize the analytic signal to obtain unit vectors (phasors).
|
|
283
369
|
unit_phasor = analytic_signal / amplitude.unsqueeze(-1)
|
|
370
|
+
# The real/imaginary slices are strided (step 2): matmul copied each of
|
|
371
|
+
# them for every product, per batch matrix. Copy them once.
|
|
372
|
+
real = unit_phasor[..., 0].contiguous()
|
|
373
|
+
imag = unit_phasor[..., 1].contiguous()
|
|
374
|
+
real_t = real.transpose(-2, -1).contiguous()
|
|
375
|
+
imag_t = imag.transpose(-2, -1).contiguous()
|
|
284
376
|
|
|
285
377
|
# Compute the real part of the outer product between phasors of
|
|
286
378
|
# different channels.
|
|
287
|
-
real_real = torch.matmul(
|
|
379
|
+
real_real = torch.matmul(real, real_t)
|
|
288
380
|
|
|
289
381
|
# Compute the imaginary part of the outer product between phasors of
|
|
290
382
|
# different channels.
|
|
291
|
-
imag_imag = torch.matmul(
|
|
383
|
+
imag_imag = torch.matmul(imag, imag_t)
|
|
292
384
|
|
|
293
385
|
# Compute the cross-terms for the real and imaginary parts.
|
|
294
|
-
real_imag = torch.matmul(
|
|
295
|
-
imag_real = torch.matmul(
|
|
386
|
+
real_imag = torch.matmul(real, imag_t)
|
|
387
|
+
imag_real = torch.matmul(imag, real_t)
|
|
296
388
|
|
|
297
389
|
# Combine the real and imaginary parts to form the complex correlation.
|
|
298
390
|
correlation_real = real_real + imag_imag
|
|
@@ -412,7 +504,14 @@ def dwt_max_level(n_times: int, filter_len: int) -> int:
|
|
|
412
504
|
"""
|
|
413
505
|
if n_times < filter_len:
|
|
414
506
|
return 0
|
|
415
|
-
|
|
507
|
+
# floor(log2(n_times / (filter_len - 1))) in integers (TorchScript has no
|
|
508
|
+
# math.log2): the largest level with (filter_len - 1) * 2**level <= n_times.
|
|
509
|
+
ratio = n_times // (filter_len - 1)
|
|
510
|
+
level = 0
|
|
511
|
+
while ratio >= 2:
|
|
512
|
+
ratio = ratio // 2
|
|
513
|
+
level += 1
|
|
514
|
+
return level
|
|
416
515
|
|
|
417
516
|
|
|
418
517
|
def wavelet_decomposition(
|
|
@@ -456,8 +555,9 @@ def wavelet_decomposition(
|
|
|
456
555
|
)
|
|
457
556
|
approx, detail = F.conv1d(padded, weight, stride=2).unbind(dim=1)
|
|
458
557
|
details.append(detail)
|
|
459
|
-
|
|
460
|
-
|
|
558
|
+
details.reverse() # [cD_n, ..., cD_1]
|
|
559
|
+
out = torch.cat([approx] + details, dim=-1)
|
|
560
|
+
return out.reshape(list(leading) + [-1])
|
|
461
561
|
|
|
462
562
|
|
|
463
563
|
def sinusoidal_positional_encoding(
|
{braindecode-1.8.1.dev168760068 → braindecode-1.8.1.dev168889947}/braindecode/models/biot.py
RENAMED
|
@@ -1,12 +1,13 @@
|
|
|
1
|
+
from typing import Dict, Optional, Tuple, Union
|
|
1
2
|
from warnings import warn
|
|
2
3
|
|
|
3
4
|
import torch
|
|
4
5
|
import torch.nn as nn
|
|
5
|
-
from linear_attention_transformer import LinearAttentionTransformer
|
|
6
6
|
|
|
7
7
|
from braindecode.functional import sinusoidal_positional_encoding, spectral_input
|
|
8
8
|
from braindecode.models.base import EEGModuleMixin
|
|
9
9
|
from braindecode.models.util import warn_if_sfreq_differs
|
|
10
|
+
from braindecode.modules.linear_attention import LinearAttentionTransformer
|
|
10
11
|
|
|
11
12
|
# -----------------------------------------------------------------------------
|
|
12
13
|
# Canonical BIOT channel order: the 18-channel TCP bipolar montage used by
|
|
@@ -230,7 +231,13 @@ class BIOT(EEGModuleMixin, nn.Module):
|
|
|
230
231
|
activation=self._head_activation,
|
|
231
232
|
)
|
|
232
233
|
|
|
233
|
-
def forward(
|
|
234
|
+
def forward(
|
|
235
|
+
self, x: torch.Tensor, return_features: bool = False
|
|
236
|
+
) -> Union[
|
|
237
|
+
torch.Tensor,
|
|
238
|
+
Tuple[torch.Tensor, torch.Tensor],
|
|
239
|
+
Dict[str, Optional[torch.Tensor]],
|
|
240
|
+
]:
|
|
234
241
|
"""
|
|
235
242
|
Pass the input through the BIOT encoder, and then through the
|
|
236
243
|
classification head.
|
|
@@ -255,7 +262,11 @@ class BIOT(EEGModuleMixin, nn.Module):
|
|
|
255
262
|
emb = self.encoder(x)
|
|
256
263
|
|
|
257
264
|
if return_features:
|
|
258
|
-
|
|
265
|
+
out: Dict[str, Optional[torch.Tensor]] = {
|
|
266
|
+
"features": emb,
|
|
267
|
+
"cls_token": None,
|
|
268
|
+
}
|
|
269
|
+
return out
|
|
259
270
|
|
|
260
271
|
x = self.final_layer(emb)
|
|
261
272
|
|
|
@@ -454,9 +465,7 @@ class _BIOTEncoder(nn.Module):
|
|
|
454
465
|
dim=emb_size,
|
|
455
466
|
heads=num_heads,
|
|
456
467
|
depth=n_layers,
|
|
457
|
-
max_seq_len=max_seq_len,
|
|
458
468
|
attn_layer_dropout=attn_layer_dropout,
|
|
459
|
-
attn_dropout=attn_dropout,
|
|
460
469
|
)
|
|
461
470
|
self.positional_encoding = _PositionalEncoding(emb_size, drop_prob=drop_prob)
|
|
462
471
|
|
|
@@ -497,7 +506,7 @@ class _BIOTEncoder(nn.Module):
|
|
|
497
506
|
)
|
|
498
507
|
return torch.abs(spectral).to(sample)
|
|
499
508
|
|
|
500
|
-
def forward(self, x, n_channel_offset=0, perturb=False):
|
|
509
|
+
def forward(self, x, n_channel_offset: int = 0, perturb: bool = False):
|
|
501
510
|
"""
|
|
502
511
|
Forward pass of the BIOT encoder.
|
|
503
512
|
|
|
@@ -569,7 +578,7 @@ class _BIOTEncoder(nn.Module):
|
|
|
569
578
|
# of time steps.
|
|
570
579
|
if perturb:
|
|
571
580
|
ts = channel_emb.shape[1]
|
|
572
|
-
ts_new = torch.randint(low=ts // 2, high=ts, size=(1,)).item()
|
|
581
|
+
ts_new = int(torch.randint(low=ts // 2, high=ts, size=(1,)).item())
|
|
573
582
|
selected_ts = torch.randperm(ts)[:ts_new]
|
|
574
583
|
channel_emb = channel_emb[:, selected_ts]
|
|
575
584
|
emb_seq.append(channel_emb)
|
{braindecode-1.8.1.dev168760068 → braindecode-1.8.1.dev168889947}/braindecode/models/brainomni.py
RENAMED
|
@@ -7,12 +7,13 @@
|
|
|
7
7
|
# derives from Meta's EnCodec (MIT).
|
|
8
8
|
from __future__ import annotations
|
|
9
9
|
|
|
10
|
+
from typing import Dict, Optional, Union
|
|
11
|
+
|
|
10
12
|
import mne
|
|
11
13
|
import numpy as np
|
|
12
14
|
import torch
|
|
13
15
|
import torch.nn as nn
|
|
14
16
|
import torch.nn.functional as F
|
|
15
|
-
from einops import rearrange
|
|
16
17
|
from mne.io.constants import FIFF
|
|
17
18
|
from torch.nn import RMSNorm
|
|
18
19
|
from torch.nn.utils.parametrizations import weight_norm
|
|
@@ -276,8 +277,7 @@ class BrainTokenizer(EEGModuleMixin, nn.Module, license="mit"):
|
|
|
276
277
|
feat, indices, _, _ = self._encode_quantize(x, overlap_ratio)
|
|
277
278
|
finally:
|
|
278
279
|
self.train(was_training)
|
|
279
|
-
|
|
280
|
-
return rearrange(feat, flat), rearrange(indices, flat)
|
|
280
|
+
return feat.flatten(2, 3), indices.flatten(2, 3)
|
|
281
281
|
|
|
282
282
|
|
|
283
283
|
class BrainOmni(EEGModuleMixin, nn.Module, license="mit"):
|
|
@@ -488,18 +488,33 @@ class BrainOmni(EEGModuleMixin, nn.Module, license="mit"):
|
|
|
488
488
|
|
|
489
489
|
def encode(self, x: torch.Tensor) -> torch.Tensor:
|
|
490
490
|
"""L2-normalized ``(batch, n_neuro, n_tokens, lm_dim)`` embedding."""
|
|
491
|
-
|
|
491
|
+
if torch.jit.is_scripting():
|
|
492
|
+
# TorchScript cannot switch modes, so tokenize() is not scriptable.
|
|
493
|
+
if self.tokenizer.training:
|
|
494
|
+
raise RuntimeError("Scripted BrainOmni needs tokenizer.eval().")
|
|
495
|
+
with torch.no_grad():
|
|
496
|
+
feat = self.tokenizer._encode_quantize(x, self.overlap_ratio)[0]
|
|
497
|
+
feat = feat.flatten(2, 3)
|
|
498
|
+
else:
|
|
499
|
+
feat, _ = self.tokenizer.tokenize(x, overlap_ratio=self.overlap_ratio)
|
|
492
500
|
neuro = self.tokenizer.encoder.neuros.detach().to(feat.dtype)
|
|
493
501
|
h = self.projection(feat + neuro.view(1, feat.shape[1], 1, -1))
|
|
494
|
-
for block in self.blocks
|
|
495
|
-
|
|
502
|
+
for i, block in enumerate(self.blocks): # the last block is unused, as released
|
|
503
|
+
if i < len(self.blocks) - 1:
|
|
504
|
+
h = block(h)
|
|
496
505
|
return F.normalize(h, p=2.0, dim=-1, eps=1e-6)
|
|
497
506
|
|
|
498
|
-
def forward(
|
|
507
|
+
def forward(
|
|
508
|
+
self, x: torch.Tensor, return_features: bool = False
|
|
509
|
+
) -> Union[torch.Tensor, Dict[str, Optional[torch.Tensor]]]:
|
|
499
510
|
"""Classify ``x`` or return the pooled features."""
|
|
500
511
|
feat = self.encode(x).mean(dim=2).flatten(1) # (batch, n_neuro * lm_dim)
|
|
501
512
|
if return_features:
|
|
502
|
-
|
|
513
|
+
out: Dict[str, Optional[torch.Tensor]] = {
|
|
514
|
+
"features": feat,
|
|
515
|
+
"cls_token": None, # nosec B105
|
|
516
|
+
}
|
|
517
|
+
return out
|
|
503
518
|
return self.final_layer(feat)
|
|
504
519
|
|
|
505
520
|
|
|
@@ -583,11 +598,11 @@ def _geometry_from_chs_info(chs_info):
|
|
|
583
598
|
return pos, sensor_type
|
|
584
599
|
|
|
585
600
|
|
|
586
|
-
def _attend(q, k, v, n_head: int, dropout_p: float
|
|
601
|
+
def _attend(q, k, v, n_head: int, dropout_p: float) -> torch.Tensor:
|
|
587
602
|
"""SDPA over ``(batch, seq, n_head * head_dim)`` inputs."""
|
|
588
|
-
q
|
|
589
|
-
|
|
590
|
-
|
|
603
|
+
q = q.unflatten(-1, (n_head, -1))
|
|
604
|
+
k = k.unflatten(-1, (n_head, -1))
|
|
605
|
+
v = v.unflatten(-1, (n_head, -1))
|
|
591
606
|
out = F.scaled_dot_product_attention(
|
|
592
607
|
q.transpose(1, 2), k.transpose(1, 2), v.transpose(1, 2), dropout_p=dropout_p
|
|
593
608
|
)
|
|
@@ -609,12 +624,13 @@ class _SpatialTemporalBlock(nn.Module):
|
|
|
609
624
|
self.ff = FeedForwardBlock(n_dim, 4, 0.0, _SELU, output_drop_p=dropout)
|
|
610
625
|
|
|
611
626
|
def forward(self, x: torch.Tensor) -> torch.Tensor:
|
|
612
|
-
batch,
|
|
627
|
+
batch, chans, times, dim = x.shape
|
|
613
628
|
h = self.pre_attn_norm(x)
|
|
614
|
-
|
|
615
|
-
|
|
616
|
-
|
|
617
|
-
|
|
629
|
+
# (b, c, t, d) -> (b * t, c, d) and (b * c, t, d), and back
|
|
630
|
+
xs = h[..., dim // 2 :].permute(0, 2, 1, 3).reshape(batch * times, chans, -1)
|
|
631
|
+
xt = h[..., : dim // 2].reshape(batch * chans, times, -1)
|
|
632
|
+
xs = self.spatial_attn(xs).reshape(batch, times, chans, -1).permute(0, 2, 1, 3)
|
|
633
|
+
xt = self.time_attn(xt).reshape(batch, chans, times, -1)
|
|
618
634
|
# Spatial half first: the halves swap, as released.
|
|
619
635
|
x = x + torch.cat([xs, xt], dim=-1)
|
|
620
636
|
return x + self.ff(self.pre_ff_norm(x))
|
|
@@ -629,6 +645,10 @@ class _RotaryPositionalEmbedding(nn.Module):
|
|
|
629
645
|
float32 under a dtype cast, ``freqs`` follows it.
|
|
630
646
|
"""
|
|
631
647
|
|
|
648
|
+
# TorchScript types the ``rebuilt`` buffer from this; a postponed string
|
|
649
|
+
# annotation would not resolve.
|
|
650
|
+
__annotations__ = {"rebuilt": Optional[torch.Tensor]}
|
|
651
|
+
|
|
632
652
|
def __init__(self, n_dim, base=10000):
|
|
633
653
|
super().__init__()
|
|
634
654
|
self.n_dim = n_dim
|
|
@@ -658,13 +678,15 @@ class _RotaryPositionalEmbedding(nn.Module):
|
|
|
658
678
|
def forward(self, q, k):
|
|
659
679
|
"""Rotate ``q`` and ``k`` of shape ``(batch, seq, n_heads, head_dim)``."""
|
|
660
680
|
_, seq, heads, _ = q.shape
|
|
661
|
-
|
|
681
|
+
rebuilt = self.rebuilt
|
|
682
|
+
rotate = self.rotate if rebuilt is None else rebuilt
|
|
662
683
|
if seq > rotate.shape[0]:
|
|
663
|
-
|
|
684
|
+
rotate = self._polar(seq)
|
|
685
|
+
self.rebuilt = rotate
|
|
664
686
|
# In at least float32 (the cache's dtype), float64 for float64 inputs.
|
|
665
687
|
work = torch.promote_types(q.dtype, torch.float32)
|
|
666
688
|
rotate = rotate.to(work)[:seq].repeat_interleave(2, dim=1)
|
|
667
|
-
rotate =
|
|
689
|
+
rotate = rotate.unflatten(1, (heads, -1)) # (seq, heads, head_dim, 2)
|
|
668
690
|
cos, sin = rotate[..., 0], rotate[..., 1]
|
|
669
691
|
q_float, k_float = q.to(work), k.to(work)
|
|
670
692
|
q_out = q_float * cos + rotate_pairs(q_float) * sin
|
|
@@ -687,7 +709,12 @@ class _MultiHeadAttentionRoPE(nn.Module):
|
|
|
687
709
|
def forward(self, x: torch.Tensor) -> torch.Tensor:
|
|
688
710
|
q, k, v = torch.split(self.qkv(x), self.n_dim, dim=-1)
|
|
689
711
|
dropout_p = self.dropout if self.training else 0.0
|
|
690
|
-
|
|
712
|
+
if self.rope_embedding_layer is not None: # on (batch, seq, heads, head_dim)
|
|
713
|
+
q, k = self.rope_embedding_layer(
|
|
714
|
+
q.unflatten(-1, (self.n_head, -1)), k.unflatten(-1, (self.n_head, -1))
|
|
715
|
+
)
|
|
716
|
+
q, k = q.flatten(2), k.flatten(2)
|
|
717
|
+
out = _attend(q, k, v, self.n_head, dropout_p)
|
|
691
718
|
return self.proj(out)
|
|
692
719
|
|
|
693
720
|
|
|
@@ -765,19 +792,22 @@ class _TokenizerEncoder(nn.Module):
|
|
|
765
792
|
self.k_proj = nn.Linear(n_dim, n_dim)
|
|
766
793
|
|
|
767
794
|
def forward(self, x: torch.Tensor, sensor_embedding: torch.Tensor):
|
|
768
|
-
batch, chans, nwin,
|
|
769
|
-
x = self.seanet_encoder(
|
|
770
|
-
|
|
771
|
-
|
|
772
|
-
|
|
773
|
-
|
|
774
|
-
|
|
775
|
-
)
|
|
776
|
-
|
|
795
|
+
batch, chans, nwin, length = x.shape
|
|
796
|
+
x = self.seanet_encoder(x.reshape(batch * chans * nwin, 1, length))
|
|
797
|
+
# (b c w) d t -> b c (w t) d
|
|
798
|
+
x = x.reshape(batch, chans, nwin, x.shape[1], -1).permute(0, 1, 2, 4, 3)
|
|
799
|
+
x = x.reshape(batch, chans, -1, x.shape[-1])
|
|
800
|
+
tokens, dim = x.shape[2], x.shape[3]
|
|
801
|
+
# b c t d -> (b t) c d
|
|
802
|
+
sensor_embedding = sensor_embedding.unsqueeze(2).repeat(1, 1, tokens, 1)
|
|
803
|
+
sensor_embedding = sensor_embedding.permute(0, 2, 1, 3).reshape(-1, chans, dim)
|
|
804
|
+
x = x.permute(0, 2, 1, 3).reshape(-1, chans, dim)
|
|
777
805
|
neuros = self.neuros.type_as(x).unsqueeze(0).repeat(x.shape[0], 1, 1)
|
|
778
806
|
x = self.backwardsolution(neuros, self.k_proj(x + sensor_embedding), x)
|
|
779
|
-
|
|
780
|
-
|
|
807
|
+
# (b w t) c d -> b c (w t) d -> b c w t d
|
|
808
|
+
x = x.reshape(batch, nwin, -1, x.shape[1], dim).permute(0, 3, 1, 2, 4)
|
|
809
|
+
x = x.reshape(batch, x.shape[1], -1, dim)
|
|
810
|
+
return x.reshape(batch, x.shape[1], nwin, -1, dim)
|
|
781
811
|
|
|
782
812
|
|
|
783
813
|
class _TokenizerDecoder(nn.Module):
|
|
@@ -800,16 +830,21 @@ class _TokenizerDecoder(nn.Module):
|
|
|
800
830
|
)
|
|
801
831
|
|
|
802
832
|
def forward(self, x: torch.Tensor, sensor_embedding: torch.Tensor):
|
|
803
|
-
batch,
|
|
804
|
-
|
|
805
|
-
|
|
806
|
-
|
|
807
|
-
|
|
833
|
+
batch, sources, nwin, tok, dim = x.shape
|
|
834
|
+
# b c w t d -> (b w t) c d
|
|
835
|
+
x = x.permute(0, 2, 3, 1, 4).reshape(-1, sources, dim)
|
|
836
|
+
sensor_embedding = sensor_embedding.view(batch, -1, 1, 1, dim)
|
|
837
|
+
chans = sensor_embedding.shape[1]
|
|
838
|
+
sensor_embedding = sensor_embedding.repeat(1, 1, nwin, tok, 1)
|
|
839
|
+
sensor_embedding = sensor_embedding.permute(0, 2, 3, 1, 4).reshape(
|
|
840
|
+
-1, chans, dim
|
|
808
841
|
)
|
|
809
842
|
x = self.forwardsolution(sensor_embedding, x)
|
|
810
|
-
|
|
811
|
-
x =
|
|
812
|
-
|
|
843
|
+
# (b w t) c d -> (b c w) d t
|
|
844
|
+
x = x.reshape(batch, nwin, tok, chans, dim).permute(0, 3, 1, 4, 2)
|
|
845
|
+
x = self.seanet_decoder(x.reshape(-1, dim, tok))
|
|
846
|
+
# (b c w) 1 l -> b c w l
|
|
847
|
+
return x.reshape(batch, chans, nwin, x.shape[-1])
|
|
813
848
|
|
|
814
849
|
|
|
815
850
|
class _SEANetConv1d(nn.Module):
|
{braindecode-1.8.1.dev168760068 → braindecode-1.8.1.dev168889947}/braindecode/models/dance.py
RENAMED
|
@@ -316,7 +316,7 @@ class DANCE(EEGModuleMixin, nn.Module, license="mit"):
|
|
|
316
316
|
def _encode(self, x: torch.Tensor) -> torch.Tensor:
|
|
317
317
|
if x.ndim != 3 or x.shape[-2] != self.n_chans:
|
|
318
318
|
raise ValueError(
|
|
319
|
-
f"expected (batch, {self.n_chans}, T) input; got {
|
|
319
|
+
f"expected (batch, {self.n_chans}, T) input; got {list(x.shape)}."
|
|
320
320
|
)
|
|
321
321
|
if x.shape[-1] < self._min_n_times:
|
|
322
322
|
raise ValueError(
|