Braindecode 1.3.2.dev182544824__tar.gz → 1.3.2.dev183191339__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.3.2.dev182544824/braindecode.egg-info → braindecode-1.3.2.dev183191339}/PKG-INFO +1 -1
- {braindecode-1.3.2.dev182544824 → braindecode-1.3.2.dev183191339}/braindecode/models/base.py +153 -20
- {braindecode-1.3.2.dev182544824 → braindecode-1.3.2.dev183191339}/braindecode/models/bendr.py +17 -6
- {braindecode-1.3.2.dev182544824 → braindecode-1.3.2.dev183191339}/braindecode/models/biot.py +23 -5
- {braindecode-1.3.2.dev182544824 → braindecode-1.3.2.dev183191339}/braindecode/models/cbramod.py +19 -11
- {braindecode-1.3.2.dev182544824 → braindecode-1.3.2.dev183191339}/braindecode/models/eegpt.py +15 -2
- {braindecode-1.3.2.dev182544824 → braindecode-1.3.2.dev183191339}/braindecode/models/labram.py +15 -1
- {braindecode-1.3.2.dev182544824 → braindecode-1.3.2.dev183191339}/braindecode/models/luna.py +5 -16
- {braindecode-1.3.2.dev182544824 → braindecode-1.3.2.dev183191339}/braindecode/models/reve.py +36 -20
- {braindecode-1.3.2.dev182544824 → braindecode-1.3.2.dev183191339}/braindecode/models/signal_jepa.py +63 -13
- braindecode-1.3.2.dev183191339/braindecode/version.py +1 -0
- {braindecode-1.3.2.dev182544824 → braindecode-1.3.2.dev183191339/braindecode.egg-info}/PKG-INFO +1 -1
- {braindecode-1.3.2.dev182544824 → braindecode-1.3.2.dev183191339}/docs/conf.py +0 -7
- {braindecode-1.3.2.dev182544824 → braindecode-1.3.2.dev183191339}/docs/whats_new.rst +27 -0
- braindecode-1.3.2.dev182544824/braindecode/version.py +0 -1
- {braindecode-1.3.2.dev182544824 → braindecode-1.3.2.dev183191339}/LICENSE.txt +0 -0
- {braindecode-1.3.2.dev182544824 → braindecode-1.3.2.dev183191339}/MANIFEST.in +0 -0
- {braindecode-1.3.2.dev182544824 → braindecode-1.3.2.dev183191339}/NOTICE.txt +0 -0
- {braindecode-1.3.2.dev182544824 → braindecode-1.3.2.dev183191339}/README.rst +0 -0
- {braindecode-1.3.2.dev182544824 → braindecode-1.3.2.dev183191339}/braindecode/__init__.py +0 -0
- {braindecode-1.3.2.dev182544824 → braindecode-1.3.2.dev183191339}/braindecode/augmentation/__init__.py +0 -0
- {braindecode-1.3.2.dev182544824 → braindecode-1.3.2.dev183191339}/braindecode/augmentation/base.py +0 -0
- {braindecode-1.3.2.dev182544824 → braindecode-1.3.2.dev183191339}/braindecode/augmentation/functional.py +0 -0
- {braindecode-1.3.2.dev182544824 → braindecode-1.3.2.dev183191339}/braindecode/augmentation/transforms.py +0 -0
- {braindecode-1.3.2.dev182544824 → braindecode-1.3.2.dev183191339}/braindecode/classifier.py +0 -0
- {braindecode-1.3.2.dev182544824 → braindecode-1.3.2.dev183191339}/braindecode/datasets/__init__.py +0 -0
- {braindecode-1.3.2.dev182544824 → braindecode-1.3.2.dev183191339}/braindecode/datasets/base.py +0 -0
- {braindecode-1.3.2.dev182544824 → braindecode-1.3.2.dev183191339}/braindecode/datasets/bbci.py +0 -0
- {braindecode-1.3.2.dev182544824 → braindecode-1.3.2.dev183191339}/braindecode/datasets/bcicomp.py +0 -0
- {braindecode-1.3.2.dev182544824 → braindecode-1.3.2.dev183191339}/braindecode/datasets/bids/__init__.py +0 -0
- {braindecode-1.3.2.dev182544824 → braindecode-1.3.2.dev183191339}/braindecode/datasets/bids/datasets.py +0 -0
- {braindecode-1.3.2.dev182544824 → braindecode-1.3.2.dev183191339}/braindecode/datasets/bids/format.py +0 -0
- {braindecode-1.3.2.dev182544824 → braindecode-1.3.2.dev183191339}/braindecode/datasets/bids/hub.py +0 -0
- {braindecode-1.3.2.dev182544824 → braindecode-1.3.2.dev183191339}/braindecode/datasets/bids/hub_format.py +0 -0
- {braindecode-1.3.2.dev182544824 → braindecode-1.3.2.dev183191339}/braindecode/datasets/bids/hub_io.py +0 -0
- {braindecode-1.3.2.dev182544824 → braindecode-1.3.2.dev183191339}/braindecode/datasets/bids/hub_validation.py +0 -0
- {braindecode-1.3.2.dev182544824 → braindecode-1.3.2.dev183191339}/braindecode/datasets/bids/iterable.py +0 -0
- {braindecode-1.3.2.dev182544824 → braindecode-1.3.2.dev183191339}/braindecode/datasets/chb_mit.py +0 -0
- {braindecode-1.3.2.dev182544824 → braindecode-1.3.2.dev183191339}/braindecode/datasets/mne.py +0 -0
- {braindecode-1.3.2.dev182544824 → braindecode-1.3.2.dev183191339}/braindecode/datasets/moabb.py +0 -0
- {braindecode-1.3.2.dev182544824 → braindecode-1.3.2.dev183191339}/braindecode/datasets/nmt.py +0 -0
- {braindecode-1.3.2.dev182544824 → braindecode-1.3.2.dev183191339}/braindecode/datasets/registry.py +0 -0
- {braindecode-1.3.2.dev182544824 → braindecode-1.3.2.dev183191339}/braindecode/datasets/siena.py +0 -0
- {braindecode-1.3.2.dev182544824 → braindecode-1.3.2.dev183191339}/braindecode/datasets/sleep_physio_challe_18.py +0 -0
- {braindecode-1.3.2.dev182544824 → braindecode-1.3.2.dev183191339}/braindecode/datasets/sleep_physionet.py +0 -0
- {braindecode-1.3.2.dev182544824 → braindecode-1.3.2.dev183191339}/braindecode/datasets/tuh.py +0 -0
- {braindecode-1.3.2.dev182544824 → braindecode-1.3.2.dev183191339}/braindecode/datasets/utils.py +0 -0
- {braindecode-1.3.2.dev182544824 → braindecode-1.3.2.dev183191339}/braindecode/datasets/xy.py +0 -0
- {braindecode-1.3.2.dev182544824 → braindecode-1.3.2.dev183191339}/braindecode/datautil/__init__.py +0 -0
- {braindecode-1.3.2.dev182544824 → braindecode-1.3.2.dev183191339}/braindecode/datautil/channel_utils.py +0 -0
- {braindecode-1.3.2.dev182544824 → braindecode-1.3.2.dev183191339}/braindecode/datautil/hub_formats.py +0 -0
- {braindecode-1.3.2.dev182544824 → braindecode-1.3.2.dev183191339}/braindecode/datautil/serialization.py +0 -0
- {braindecode-1.3.2.dev182544824 → braindecode-1.3.2.dev183191339}/braindecode/datautil/util.py +0 -0
- {braindecode-1.3.2.dev182544824 → braindecode-1.3.2.dev183191339}/braindecode/eegneuralnet.py +0 -0
- {braindecode-1.3.2.dev182544824 → braindecode-1.3.2.dev183191339}/braindecode/functional/__init__.py +0 -0
- {braindecode-1.3.2.dev182544824 → braindecode-1.3.2.dev183191339}/braindecode/functional/functions.py +0 -0
- {braindecode-1.3.2.dev182544824 → braindecode-1.3.2.dev183191339}/braindecode/functional/initialization.py +0 -0
- {braindecode-1.3.2.dev182544824 → braindecode-1.3.2.dev183191339}/braindecode/models/__init__.py +0 -0
- {braindecode-1.3.2.dev182544824 → braindecode-1.3.2.dev183191339}/braindecode/models/atcnet.py +0 -0
- {braindecode-1.3.2.dev182544824 → braindecode-1.3.2.dev183191339}/braindecode/models/attentionbasenet.py +0 -0
- {braindecode-1.3.2.dev182544824 → braindecode-1.3.2.dev183191339}/braindecode/models/attn_sleep.py +0 -0
- {braindecode-1.3.2.dev182544824 → braindecode-1.3.2.dev183191339}/braindecode/models/brainmodule.py +0 -0
- {braindecode-1.3.2.dev182544824 → braindecode-1.3.2.dev183191339}/braindecode/models/config.py +0 -0
- {braindecode-1.3.2.dev182544824 → braindecode-1.3.2.dev183191339}/braindecode/models/contrawr.py +0 -0
- {braindecode-1.3.2.dev182544824 → braindecode-1.3.2.dev183191339}/braindecode/models/ctnet.py +0 -0
- {braindecode-1.3.2.dev182544824 → braindecode-1.3.2.dev183191339}/braindecode/models/deep4.py +0 -0
- {braindecode-1.3.2.dev182544824 → braindecode-1.3.2.dev183191339}/braindecode/models/deepsleepnet.py +0 -0
- {braindecode-1.3.2.dev182544824 → braindecode-1.3.2.dev183191339}/braindecode/models/dgcnn.py +0 -0
- {braindecode-1.3.2.dev182544824 → braindecode-1.3.2.dev183191339}/braindecode/models/eegconformer.py +0 -0
- {braindecode-1.3.2.dev182544824 → braindecode-1.3.2.dev183191339}/braindecode/models/eeginception_erp.py +0 -0
- {braindecode-1.3.2.dev182544824 → braindecode-1.3.2.dev183191339}/braindecode/models/eeginception_mi.py +0 -0
- {braindecode-1.3.2.dev182544824 → braindecode-1.3.2.dev183191339}/braindecode/models/eegitnet.py +0 -0
- {braindecode-1.3.2.dev182544824 → braindecode-1.3.2.dev183191339}/braindecode/models/eegminer.py +0 -0
- {braindecode-1.3.2.dev182544824 → braindecode-1.3.2.dev183191339}/braindecode/models/eegnet.py +0 -0
- {braindecode-1.3.2.dev182544824 → braindecode-1.3.2.dev183191339}/braindecode/models/eegnex.py +0 -0
- {braindecode-1.3.2.dev182544824 → braindecode-1.3.2.dev183191339}/braindecode/models/eegsimpleconv.py +0 -0
- {braindecode-1.3.2.dev182544824 → braindecode-1.3.2.dev183191339}/braindecode/models/eegsym.py +0 -0
- {braindecode-1.3.2.dev182544824 → braindecode-1.3.2.dev183191339}/braindecode/models/eegtcnet.py +0 -0
- {braindecode-1.3.2.dev182544824 → braindecode-1.3.2.dev183191339}/braindecode/models/fbcnet.py +0 -0
- {braindecode-1.3.2.dev182544824 → braindecode-1.3.2.dev183191339}/braindecode/models/fblightconvnet.py +0 -0
- {braindecode-1.3.2.dev182544824 → braindecode-1.3.2.dev183191339}/braindecode/models/fbmsnet.py +0 -0
- {braindecode-1.3.2.dev182544824 → braindecode-1.3.2.dev183191339}/braindecode/models/hybrid.py +0 -0
- {braindecode-1.3.2.dev182544824 → braindecode-1.3.2.dev183191339}/braindecode/models/ifnet.py +0 -0
- {braindecode-1.3.2.dev182544824 → braindecode-1.3.2.dev183191339}/braindecode/models/medformer.py +0 -0
- {braindecode-1.3.2.dev182544824 → braindecode-1.3.2.dev183191339}/braindecode/models/msvtnet.py +0 -0
- {braindecode-1.3.2.dev182544824 → braindecode-1.3.2.dev183191339}/braindecode/models/patchedtransformer.py +0 -0
- {braindecode-1.3.2.dev182544824 → braindecode-1.3.2.dev183191339}/braindecode/models/sccnet.py +0 -0
- {braindecode-1.3.2.dev182544824 → braindecode-1.3.2.dev183191339}/braindecode/models/shallow_fbcsp.py +0 -0
- {braindecode-1.3.2.dev182544824 → braindecode-1.3.2.dev183191339}/braindecode/models/sinc_shallow.py +0 -0
- {braindecode-1.3.2.dev182544824 → braindecode-1.3.2.dev183191339}/braindecode/models/sleep_stager_blanco_2020.py +0 -0
- {braindecode-1.3.2.dev182544824 → braindecode-1.3.2.dev183191339}/braindecode/models/sleep_stager_chambon_2018.py +0 -0
- {braindecode-1.3.2.dev182544824 → braindecode-1.3.2.dev183191339}/braindecode/models/sparcnet.py +0 -0
- {braindecode-1.3.2.dev182544824 → braindecode-1.3.2.dev183191339}/braindecode/models/sstdpn.py +0 -0
- {braindecode-1.3.2.dev182544824 → braindecode-1.3.2.dev183191339}/braindecode/models/summary.csv +0 -0
- {braindecode-1.3.2.dev182544824 → braindecode-1.3.2.dev183191339}/braindecode/models/syncnet.py +0 -0
- {braindecode-1.3.2.dev182544824 → braindecode-1.3.2.dev183191339}/braindecode/models/tcn.py +0 -0
- {braindecode-1.3.2.dev182544824 → braindecode-1.3.2.dev183191339}/braindecode/models/tidnet.py +0 -0
- {braindecode-1.3.2.dev182544824 → braindecode-1.3.2.dev183191339}/braindecode/models/tsinception.py +0 -0
- {braindecode-1.3.2.dev182544824 → braindecode-1.3.2.dev183191339}/braindecode/models/usleep.py +0 -0
- {braindecode-1.3.2.dev182544824 → braindecode-1.3.2.dev183191339}/braindecode/models/util.py +0 -0
- {braindecode-1.3.2.dev182544824 → braindecode-1.3.2.dev183191339}/braindecode/modules/__init__.py +0 -0
- {braindecode-1.3.2.dev182544824 → braindecode-1.3.2.dev183191339}/braindecode/modules/activation.py +0 -0
- {braindecode-1.3.2.dev182544824 → braindecode-1.3.2.dev183191339}/braindecode/modules/attention.py +0 -0
- {braindecode-1.3.2.dev182544824 → braindecode-1.3.2.dev183191339}/braindecode/modules/blocks.py +0 -0
- {braindecode-1.3.2.dev182544824 → braindecode-1.3.2.dev183191339}/braindecode/modules/convolution.py +0 -0
- {braindecode-1.3.2.dev182544824 → braindecode-1.3.2.dev183191339}/braindecode/modules/filter.py +0 -0
- {braindecode-1.3.2.dev182544824 → braindecode-1.3.2.dev183191339}/braindecode/modules/layers.py +0 -0
- {braindecode-1.3.2.dev182544824 → braindecode-1.3.2.dev183191339}/braindecode/modules/linear.py +0 -0
- {braindecode-1.3.2.dev182544824 → braindecode-1.3.2.dev183191339}/braindecode/modules/parametrization.py +0 -0
- {braindecode-1.3.2.dev182544824 → braindecode-1.3.2.dev183191339}/braindecode/modules/stats.py +0 -0
- {braindecode-1.3.2.dev182544824 → braindecode-1.3.2.dev183191339}/braindecode/modules/util.py +0 -0
- {braindecode-1.3.2.dev182544824 → braindecode-1.3.2.dev183191339}/braindecode/modules/wrapper.py +0 -0
- {braindecode-1.3.2.dev182544824 → braindecode-1.3.2.dev183191339}/braindecode/preprocessing/__init__.py +0 -0
- {braindecode-1.3.2.dev182544824 → braindecode-1.3.2.dev183191339}/braindecode/preprocessing/eegprep_preprocess.py +0 -0
- {braindecode-1.3.2.dev182544824 → braindecode-1.3.2.dev183191339}/braindecode/preprocessing/mne_preprocess.py +0 -0
- {braindecode-1.3.2.dev182544824 → braindecode-1.3.2.dev183191339}/braindecode/preprocessing/preprocess.py +0 -0
- {braindecode-1.3.2.dev182544824 → braindecode-1.3.2.dev183191339}/braindecode/preprocessing/util.py +0 -0
- {braindecode-1.3.2.dev182544824 → braindecode-1.3.2.dev183191339}/braindecode/preprocessing/windowers.py +0 -0
- {braindecode-1.3.2.dev182544824 → braindecode-1.3.2.dev183191339}/braindecode/regressor.py +0 -0
- {braindecode-1.3.2.dev182544824 → braindecode-1.3.2.dev183191339}/braindecode/samplers/__init__.py +0 -0
- {braindecode-1.3.2.dev182544824 → braindecode-1.3.2.dev183191339}/braindecode/samplers/base.py +0 -0
- {braindecode-1.3.2.dev182544824 → braindecode-1.3.2.dev183191339}/braindecode/samplers/ssl.py +0 -0
- {braindecode-1.3.2.dev182544824 → braindecode-1.3.2.dev183191339}/braindecode/training/__init__.py +0 -0
- {braindecode-1.3.2.dev182544824 → braindecode-1.3.2.dev183191339}/braindecode/training/callbacks.py +0 -0
- {braindecode-1.3.2.dev182544824 → braindecode-1.3.2.dev183191339}/braindecode/training/losses.py +0 -0
- {braindecode-1.3.2.dev182544824 → braindecode-1.3.2.dev183191339}/braindecode/training/scoring.py +0 -0
- {braindecode-1.3.2.dev182544824 → braindecode-1.3.2.dev183191339}/braindecode/util.py +0 -0
- {braindecode-1.3.2.dev182544824 → braindecode-1.3.2.dev183191339}/braindecode/visualization/__init__.py +0 -0
- {braindecode-1.3.2.dev182544824 → braindecode-1.3.2.dev183191339}/braindecode/visualization/confusion_matrices.py +0 -0
- {braindecode-1.3.2.dev182544824 → braindecode-1.3.2.dev183191339}/braindecode/visualization/gradients.py +0 -0
- {braindecode-1.3.2.dev182544824 → braindecode-1.3.2.dev183191339}/braindecode.egg-info/SOURCES.txt +0 -0
- {braindecode-1.3.2.dev182544824 → braindecode-1.3.2.dev183191339}/braindecode.egg-info/dependency_links.txt +0 -0
- {braindecode-1.3.2.dev182544824 → braindecode-1.3.2.dev183191339}/braindecode.egg-info/requires.txt +0 -0
- {braindecode-1.3.2.dev182544824 → braindecode-1.3.2.dev183191339}/braindecode.egg-info/top_level.txt +0 -0
- {braindecode-1.3.2.dev182544824 → braindecode-1.3.2.dev183191339}/docs/Makefile +0 -0
- {braindecode-1.3.2.dev182544824 → braindecode-1.3.2.dev183191339}/docs/_templates/autosummary/class.rst +0 -0
- {braindecode-1.3.2.dev182544824 → braindecode-1.3.2.dev183191339}/docs/_templates/autosummary/class_in_subdir.rst +0 -0
- {braindecode-1.3.2.dev182544824 → braindecode-1.3.2.dev183191339}/docs/_templates/autosummary/function.rst +0 -0
- {braindecode-1.3.2.dev182544824 → braindecode-1.3.2.dev183191339}/docs/_templates/autosummary/function_in_subdir.rst +0 -0
- {braindecode-1.3.2.dev182544824 → braindecode-1.3.2.dev183191339}/docs/api.rst +0 -0
- {braindecode-1.3.2.dev182544824 → braindecode-1.3.2.dev183191339}/docs/cite.rst +0 -0
- {braindecode-1.3.2.dev182544824 → braindecode-1.3.2.dev183191339}/docs/help.rst +0 -0
- {braindecode-1.3.2.dev182544824 → braindecode-1.3.2.dev183191339}/docs/index.rst +0 -0
- {braindecode-1.3.2.dev182544824 → braindecode-1.3.2.dev183191339}/docs/install/install.rst +0 -0
- {braindecode-1.3.2.dev182544824 → braindecode-1.3.2.dev183191339}/docs/install/install_pip.rst +0 -0
- {braindecode-1.3.2.dev182544824 → braindecode-1.3.2.dev183191339}/docs/install/install_source.rst +0 -0
- {braindecode-1.3.2.dev182544824 → braindecode-1.3.2.dev183191339}/docs/models/categorization/attention.rst +0 -0
- {braindecode-1.3.2.dev182544824 → braindecode-1.3.2.dev183191339}/docs/models/categorization/channel.rst +0 -0
- {braindecode-1.3.2.dev182544824 → braindecode-1.3.2.dev183191339}/docs/models/categorization/convolution.rst +0 -0
- {braindecode-1.3.2.dev182544824 → braindecode-1.3.2.dev183191339}/docs/models/categorization/filterbank.rst +0 -0
- {braindecode-1.3.2.dev182544824 → braindecode-1.3.2.dev183191339}/docs/models/categorization/gnn.rst +0 -0
- {braindecode-1.3.2.dev182544824 → braindecode-1.3.2.dev183191339}/docs/models/categorization/interpretable.rst +0 -0
- {braindecode-1.3.2.dev182544824 → braindecode-1.3.2.dev183191339}/docs/models/categorization/lbm.rst +0 -0
- {braindecode-1.3.2.dev182544824 → braindecode-1.3.2.dev183191339}/docs/models/categorization/recurrent.rst +0 -0
- {braindecode-1.3.2.dev182544824 → braindecode-1.3.2.dev183191339}/docs/models/categorization/spd.rst +0 -0
- {braindecode-1.3.2.dev182544824 → braindecode-1.3.2.dev183191339}/docs/models/models.rst +0 -0
- {braindecode-1.3.2.dev182544824 → braindecode-1.3.2.dev183191339}/docs/models/models_categorization.rst +0 -0
- {braindecode-1.3.2.dev182544824 → braindecode-1.3.2.dev183191339}/docs/models/models_table.rst +0 -0
- {braindecode-1.3.2.dev182544824 → braindecode-1.3.2.dev183191339}/docs/models/models_visualization.rst +0 -0
- {braindecode-1.3.2.dev182544824 → braindecode-1.3.2.dev183191339}/docs/sg_execution_times.rst +0 -0
- {braindecode-1.3.2.dev182544824 → braindecode-1.3.2.dev183191339}/pyproject.toml +0 -0
- {braindecode-1.3.2.dev182544824 → braindecode-1.3.2.dev183191339}/setup.cfg +0 -0
{braindecode-1.3.2.dev182544824/braindecode.egg-info → braindecode-1.3.2.dev183191339}/PKG-INFO
RENAMED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: braindecode
|
|
3
|
-
Version: 1.3.2.
|
|
3
|
+
Version: 1.3.2.dev183191339
|
|
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>
|
{braindecode-1.3.2.dev182544824 → braindecode-1.3.2.dev183191339}/braindecode/models/base.py
RENAMED
|
@@ -59,7 +59,25 @@ def deprecated_args(obj, *old_new_args):
|
|
|
59
59
|
return out_args
|
|
60
60
|
|
|
61
61
|
|
|
62
|
-
class
|
|
62
|
+
class _BraindecodeDocstringMeta(NumpyDocstringInheritanceInitMeta):
|
|
63
|
+
"""Defer ``__init__`` wrapping until after docstring inheritance.
|
|
64
|
+
|
|
65
|
+
``NumpyDocstringInheritanceInitMeta`` uses ``inspect.unwrap()``
|
|
66
|
+
internally, which bypasses ``@wraps`` wrappers. By wrapping
|
|
67
|
+
``__init__`` *after* docstring processing, the metaclass sees the
|
|
68
|
+
unwrapped function and correctly inherits ``cls.__doc__``.
|
|
69
|
+
"""
|
|
70
|
+
|
|
71
|
+
def __init__(cls, class_name, class_bases, class_dict):
|
|
72
|
+
super().__init__(class_name, class_bases, class_dict)
|
|
73
|
+
# Only wrap subclass __init__s, not EEGModuleMixin itself.
|
|
74
|
+
# Wrapping the mixin would cause super().__init__() calls to
|
|
75
|
+
# overwrite _braindecode_init_kwargs captured by the subclass.
|
|
76
|
+
if any(isinstance(b, _BraindecodeDocstringMeta) for b in class_bases):
|
|
77
|
+
track_model_init_kwargs(cls)
|
|
78
|
+
|
|
79
|
+
|
|
80
|
+
class EEGModuleMixin(_BaseHubMixin, metaclass=_BraindecodeDocstringMeta):
|
|
63
81
|
"""
|
|
64
82
|
Mixin class for all EEG models in braindecode.
|
|
65
83
|
|
|
@@ -132,20 +150,46 @@ class EEGModuleMixin(_BaseHubMixin, metaclass=NumpyDocstringInheritanceInitMeta)
|
|
|
132
150
|
# Load pretrained model
|
|
133
151
|
model = {name}.from_pretrained("username/my-{name_lower}-model")
|
|
134
152
|
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
153
|
+
# Load with a different number of outputs (head is rebuilt automatically)
|
|
154
|
+
model = {name}.from_pretrained("username/my-{name_lower}-model", n_outputs=4)
|
|
155
|
+
|
|
156
|
+
**Extracting features and replacing the head:**
|
|
157
|
+
|
|
158
|
+
.. code-block::
|
|
159
|
+
|
|
160
|
+
import torch
|
|
161
|
+
|
|
162
|
+
x = torch.randn(1, model.n_chans, model.n_times)
|
|
163
|
+
# Extract encoder features (consistent dict across all models)
|
|
164
|
+
out = model(x, return_features=True)
|
|
165
|
+
features = out["features"]
|
|
166
|
+
|
|
167
|
+
# Replace the classification head
|
|
168
|
+
model.reset_head(n_outputs=10)
|
|
169
|
+
|
|
170
|
+
**Saving and restoring full configuration:**
|
|
171
|
+
|
|
172
|
+
.. code-block::
|
|
173
|
+
|
|
174
|
+
import json
|
|
175
|
+
|
|
176
|
+
config = model.get_config() # all __init__ params
|
|
177
|
+
with open("config.json", "w") as f:
|
|
178
|
+
json.dump(config, f)
|
|
179
|
+
|
|
180
|
+
model2 = {name}.from_config(config) # reconstruct (no weights)
|
|
139
181
|
|
|
140
182
|
All model parameters (both EEG-specific and model-specific such as
|
|
141
183
|
dropout rates, activation functions, number of filters) are automatically
|
|
142
184
|
saved to the Hub and restored when loading.
|
|
185
|
+
|
|
186
|
+
See :ref:`load-pretrained-models` for a complete tutorial.
|
|
143
187
|
"""
|
|
144
188
|
|
|
145
189
|
def __init_subclass__(cls, **kwargs):
|
|
146
190
|
# Append model-specific Hub integration notes to the docstring.
|
|
147
|
-
# This runs
|
|
148
|
-
#
|
|
191
|
+
# This runs before the metaclass __init__, so the Hub notes will
|
|
192
|
+
# be included in the docstring that the metaclass processes.
|
|
149
193
|
if cls.__doc__ is not None:
|
|
150
194
|
hub_notes = cls._HUB_NOTES_TEMPLATE.format(
|
|
151
195
|
name=cls.__name__,
|
|
@@ -155,7 +199,6 @@ class EEGModuleMixin(_BaseHubMixin, metaclass=NumpyDocstringInheritanceInitMeta)
|
|
|
155
199
|
|
|
156
200
|
if not HAS_HF_HUB:
|
|
157
201
|
super().__init_subclass__(**kwargs)
|
|
158
|
-
track_model_init_kwargs(cls)
|
|
159
202
|
return
|
|
160
203
|
|
|
161
204
|
base_tags = ["braindecode", cls.__name__]
|
|
@@ -195,7 +238,6 @@ class EEGModuleMixin(_BaseHubMixin, metaclass=NumpyDocstringInheritanceInitMeta)
|
|
|
195
238
|
coders=coders,
|
|
196
239
|
**kwargs,
|
|
197
240
|
)
|
|
198
|
-
track_model_init_kwargs(cls)
|
|
199
241
|
|
|
200
242
|
def __init__(
|
|
201
243
|
self,
|
|
@@ -426,6 +468,34 @@ class EEGModuleMixin(_BaseHubMixin, metaclass=NumpyDocstringInheritanceInitMeta)
|
|
|
426
468
|
resolve_type_kwargs(cls, config)
|
|
427
469
|
return cls(**config)
|
|
428
470
|
|
|
471
|
+
def reset_head(self, n_outputs):
|
|
472
|
+
"""Replace the classification head for a new number of outputs.
|
|
473
|
+
|
|
474
|
+
This is called automatically by :meth:`from_pretrained` when the
|
|
475
|
+
user passes an ``n_outputs`` that differs from the saved config.
|
|
476
|
+
Override in subclasses that need a model-specific head structure.
|
|
477
|
+
|
|
478
|
+
Parameters
|
|
479
|
+
----------
|
|
480
|
+
n_outputs : int
|
|
481
|
+
New number of output classes.
|
|
482
|
+
|
|
483
|
+
Examples
|
|
484
|
+
--------
|
|
485
|
+
>>> from braindecode.models import BENDR
|
|
486
|
+
>>> model = BENDR(n_chans=22, n_times=1000, n_outputs=4)
|
|
487
|
+
>>> model.reset_head(10)
|
|
488
|
+
>>> model.n_outputs
|
|
489
|
+
10
|
|
490
|
+
|
|
491
|
+
.. versionadded:: 1.4
|
|
492
|
+
"""
|
|
493
|
+
raise NotImplementedError(
|
|
494
|
+
f"{type(self).__name__} does not implement reset_head(). "
|
|
495
|
+
"Override this method to support changing n_outputs after "
|
|
496
|
+
"loading pretrained weights."
|
|
497
|
+
)
|
|
498
|
+
|
|
429
499
|
mapping: Optional[Dict[str, str]] = None
|
|
430
500
|
|
|
431
501
|
def load_state_dict(self, state_dict, *args, **kwargs):
|
|
@@ -625,15 +695,78 @@ class EEGModuleMixin(_BaseHubMixin, metaclass=NumpyDocstringInheritanceInitMeta)
|
|
|
625
695
|
**model_kwargs,
|
|
626
696
|
):
|
|
627
697
|
model_kwargs.pop("braindecode_version", None)
|
|
698
|
+
filename = model_kwargs.pop("filename", None)
|
|
628
699
|
resolve_type_kwargs(cls, model_kwargs)
|
|
629
|
-
|
|
630
|
-
|
|
631
|
-
|
|
632
|
-
|
|
633
|
-
|
|
634
|
-
|
|
635
|
-
|
|
636
|
-
|
|
637
|
-
|
|
638
|
-
|
|
639
|
-
|
|
700
|
+
|
|
701
|
+
# Read saved n_outputs from config.json to detect when the
|
|
702
|
+
# user wants a different number of outputs. Works for both
|
|
703
|
+
# local directories and Hub repo IDs.
|
|
704
|
+
saved_n_outputs = None
|
|
705
|
+
try:
|
|
706
|
+
if Path(model_id).is_dir():
|
|
707
|
+
config_file = Path(model_id) / "config.json"
|
|
708
|
+
else:
|
|
709
|
+
config_file = huggingface_hub.hf_hub_download(
|
|
710
|
+
repo_id=model_id,
|
|
711
|
+
filename="config.json",
|
|
712
|
+
revision=revision,
|
|
713
|
+
cache_dir=cache_dir,
|
|
714
|
+
force_download=force_download,
|
|
715
|
+
token=token,
|
|
716
|
+
local_files_only=local_files_only,
|
|
717
|
+
)
|
|
718
|
+
with open(config_file, "r") as f:
|
|
719
|
+
saved_n_outputs = json.load(f).get("n_outputs")
|
|
720
|
+
except (OSError, json.JSONDecodeError, KeyError):
|
|
721
|
+
pass # config unavailable; skip reset_head logic
|
|
722
|
+
|
|
723
|
+
requested_n_outputs = model_kwargs.get("n_outputs")
|
|
724
|
+
|
|
725
|
+
# If the user requests different n_outputs, load with the
|
|
726
|
+
# saved value first (so weights match), then swap the head.
|
|
727
|
+
if (
|
|
728
|
+
saved_n_outputs is not None
|
|
729
|
+
and requested_n_outputs is not None
|
|
730
|
+
and requested_n_outputs != saved_n_outputs
|
|
731
|
+
):
|
|
732
|
+
model_kwargs["n_outputs"] = saved_n_outputs
|
|
733
|
+
|
|
734
|
+
# If a custom filename is provided, temporarily override the
|
|
735
|
+
# HuggingFace constant so the parent class downloads the
|
|
736
|
+
# correct file (e.g. "LUNA_base.safetensors" instead of
|
|
737
|
+
# "model.safetensors").
|
|
738
|
+
hf_constants = huggingface_hub.constants
|
|
739
|
+
_orig_safetensors = hf_constants.SAFETENSORS_SINGLE_FILE
|
|
740
|
+
if filename is not None:
|
|
741
|
+
hf_constants.SAFETENSORS_SINGLE_FILE = filename
|
|
742
|
+
try:
|
|
743
|
+
model = super()._from_pretrained( # type: ignore
|
|
744
|
+
model_id=model_id,
|
|
745
|
+
revision=revision,
|
|
746
|
+
cache_dir=cache_dir,
|
|
747
|
+
force_download=force_download,
|
|
748
|
+
local_files_only=local_files_only,
|
|
749
|
+
token=token,
|
|
750
|
+
map_location=map_location,
|
|
751
|
+
strict=strict,
|
|
752
|
+
**model_kwargs,
|
|
753
|
+
)
|
|
754
|
+
finally:
|
|
755
|
+
hf_constants.SAFETENSORS_SINGLE_FILE = _orig_safetensors
|
|
756
|
+
|
|
757
|
+
if (
|
|
758
|
+
saved_n_outputs is not None
|
|
759
|
+
and requested_n_outputs is not None
|
|
760
|
+
and requested_n_outputs != saved_n_outputs
|
|
761
|
+
):
|
|
762
|
+
try:
|
|
763
|
+
model.reset_head(requested_n_outputs)
|
|
764
|
+
except NotImplementedError:
|
|
765
|
+
raise ValueError(
|
|
766
|
+
f"{type(model).__name__} does not support changing "
|
|
767
|
+
f"n_outputs after loading. Saved model has "
|
|
768
|
+
f"n_outputs={saved_n_outputs}, but "
|
|
769
|
+
f"n_outputs={requested_n_outputs} was requested."
|
|
770
|
+
) from None
|
|
771
|
+
|
|
772
|
+
return model
|
{braindecode-1.3.2.dev182544824 → braindecode-1.3.2.dev183191339}/braindecode/models/bendr.py
RENAMED
|
@@ -291,15 +291,23 @@ class BENDR(EEGModuleMixin, nn.Module):
|
|
|
291
291
|
else:
|
|
292
292
|
in_features = encoder_h
|
|
293
293
|
|
|
294
|
+
self._head_in_features = in_features
|
|
294
295
|
self.final_layer = None
|
|
295
296
|
if self.include_final_layer:
|
|
296
|
-
|
|
297
|
-
linear = nn.Linear(in_features=in_features, out_features=self.n_outputs)
|
|
298
|
-
self.final_layer = nn.utils.parametrizations.weight_norm(
|
|
299
|
-
linear, name="weight", dim=1
|
|
300
|
-
)
|
|
297
|
+
self._build_head(self.n_outputs)
|
|
301
298
|
|
|
302
|
-
def
|
|
299
|
+
def _build_head(self, n_outputs):
|
|
300
|
+
linear = nn.Linear(in_features=self._head_in_features, out_features=n_outputs)
|
|
301
|
+
self.final_layer = nn.utils.parametrizations.weight_norm(
|
|
302
|
+
linear, name="weight", dim=1
|
|
303
|
+
)
|
|
304
|
+
|
|
305
|
+
def reset_head(self, n_outputs):
|
|
306
|
+
self._n_outputs = n_outputs
|
|
307
|
+
self.include_final_layer = True
|
|
308
|
+
self._build_head(n_outputs)
|
|
309
|
+
|
|
310
|
+
def forward(self, x, return_features=False):
|
|
303
311
|
if self.channel_projection is not None:
|
|
304
312
|
x = self.channel_projection(x)
|
|
305
313
|
encoded = self.encoder(x)
|
|
@@ -328,6 +336,9 @@ class BENDR(EEGModuleMixin, nn.Module):
|
|
|
328
336
|
feature = context[:, :, 0]
|
|
329
337
|
# feature: [batch_size, encoder_h]
|
|
330
338
|
|
|
339
|
+
if return_features:
|
|
340
|
+
return {"features": feature, "cls_token": None}
|
|
341
|
+
|
|
331
342
|
if self.final_layer is not None:
|
|
332
343
|
feature = self.final_layer(feature)
|
|
333
344
|
# feature: [batch_size, n_outputs]
|
{braindecode-1.3.2.dev182544824 → braindecode-1.3.2.dev183191339}/braindecode/models/biot.py
RENAMED
|
@@ -183,13 +183,22 @@ class BIOT(EEGModuleMixin, nn.Module):
|
|
|
183
183
|
attn_layer_dropout=att_layer_drop_prob,
|
|
184
184
|
)
|
|
185
185
|
|
|
186
|
+
self._head_activation = activation
|
|
186
187
|
self.final_layer = _ClassificationHead(
|
|
187
188
|
emb_size=self.embed_dim,
|
|
188
189
|
n_outputs=self.n_outputs,
|
|
189
190
|
activation=activation,
|
|
190
191
|
)
|
|
191
192
|
|
|
192
|
-
def
|
|
193
|
+
def reset_head(self, n_outputs):
|
|
194
|
+
self._n_outputs = n_outputs
|
|
195
|
+
self.final_layer = _ClassificationHead(
|
|
196
|
+
emb_size=self.embed_dim,
|
|
197
|
+
n_outputs=n_outputs,
|
|
198
|
+
activation=self._head_activation,
|
|
199
|
+
)
|
|
200
|
+
|
|
201
|
+
def forward(self, x, return_features=False):
|
|
193
202
|
"""
|
|
194
203
|
Pass the input through the BIOT encoder, and then through the
|
|
195
204
|
classification head.
|
|
@@ -198,15 +207,24 @@ class BIOT(EEGModuleMixin, nn.Module):
|
|
|
198
207
|
----------
|
|
199
208
|
x: Tensor
|
|
200
209
|
(batch_size, n_channels, n_times)
|
|
210
|
+
return_features : bool
|
|
211
|
+
If True, return a dict with ``"features"`` and ``"cls_token"``
|
|
212
|
+
instead of the classification output.
|
|
201
213
|
|
|
202
214
|
Returns
|
|
203
215
|
-------
|
|
204
|
-
|
|
205
|
-
(batch_size, n_outputs)
|
|
206
|
-
|
|
207
|
-
(batch_size,
|
|
216
|
+
torch.Tensor or tuple or dict
|
|
217
|
+
Default: ``torch.Tensor`` of shape ``(batch_size, n_outputs)``.
|
|
218
|
+
If ``return_features=True``: ``dict`` with ``"features"``
|
|
219
|
+
``(batch_size, emb_size)`` and ``"cls_token"`` (``None``).
|
|
220
|
+
If legacy ``return_feature=True`` (init param):
|
|
221
|
+
``(out, emb)`` tuple (ignored when ``return_features=True``).
|
|
208
222
|
"""
|
|
209
223
|
emb = self.encoder(x)
|
|
224
|
+
|
|
225
|
+
if return_features:
|
|
226
|
+
return {"features": emb, "cls_token": None}
|
|
227
|
+
|
|
210
228
|
x = self.final_layer(emb)
|
|
211
229
|
|
|
212
230
|
if self.return_feature:
|
{braindecode-1.3.2.dev182544824 → braindecode-1.3.2.dev183191339}/braindecode/models/cbramod.py
RENAMED
|
@@ -205,20 +205,15 @@ class CBraMod(EEGModuleMixin, nn.Module):
|
|
|
205
205
|
self.encoder = _TransformerEncoder(encoder_layer, num_layers=n_layer)
|
|
206
206
|
self.proj_out = nn.Sequential(nn.Linear(d_model, emb_dim))
|
|
207
207
|
|
|
208
|
+
self._emb_dim = emb_dim
|
|
209
|
+
self._patch_size = patch_size
|
|
208
210
|
self._weights_init()
|
|
209
211
|
|
|
210
|
-
try:
|
|
211
|
-
n_times = self.n_times
|
|
212
|
-
n_chans = self.n_chans
|
|
213
|
-
except ValueError:
|
|
214
|
-
n_times = None
|
|
215
|
-
n_chans = None
|
|
216
|
-
|
|
217
212
|
if return_encoder_output:
|
|
218
213
|
self.final_layer = nn.Identity()
|
|
219
|
-
elif
|
|
220
|
-
n_patch =
|
|
221
|
-
flat_dim =
|
|
214
|
+
elif self._n_times is not None and self._n_chans is not None:
|
|
215
|
+
n_patch = self._n_times // patch_size
|
|
216
|
+
flat_dim = self._n_chans * n_patch * emb_dim
|
|
222
217
|
self.final_layer = nn.Sequential(
|
|
223
218
|
nn.Flatten(), nn.Linear(flat_dim, self.n_outputs)
|
|
224
219
|
)
|
|
@@ -227,6 +222,17 @@ class CBraMod(EEGModuleMixin, nn.Module):
|
|
|
227
222
|
nn.Flatten(), nn.LazyLinear(self.n_outputs)
|
|
228
223
|
)
|
|
229
224
|
|
|
225
|
+
def reset_head(self, n_outputs):
|
|
226
|
+
self._n_outputs = n_outputs
|
|
227
|
+
if self._n_times is not None and self._n_chans is not None:
|
|
228
|
+
n_patch = self._n_times // self._patch_size
|
|
229
|
+
flat_dim = self._n_chans * n_patch * self._emb_dim
|
|
230
|
+
self.final_layer = nn.Sequential(
|
|
231
|
+
nn.Flatten(), nn.Linear(flat_dim, n_outputs)
|
|
232
|
+
)
|
|
233
|
+
else:
|
|
234
|
+
self.final_layer = nn.Sequential(nn.Flatten(), nn.LazyLinear(n_outputs))
|
|
235
|
+
|
|
230
236
|
def _weights_init(self):
|
|
231
237
|
for m in self.modules():
|
|
232
238
|
if isinstance(m, nn.Linear):
|
|
@@ -237,11 +243,13 @@ class CBraMod(EEGModuleMixin, nn.Module):
|
|
|
237
243
|
nn.init.constant_(m.weight, 1)
|
|
238
244
|
nn.init.constant_(m.bias, 0)
|
|
239
245
|
|
|
240
|
-
def forward(self, x, mask=None):
|
|
246
|
+
def forward(self, x, mask=None, return_features=False):
|
|
241
247
|
x = self.rearrange(x)
|
|
242
248
|
patch_emb = self.patch_embedding(x, mask)
|
|
243
249
|
feats = self.encoder(patch_emb)
|
|
244
250
|
out = self.proj_out(feats)
|
|
251
|
+
if return_features:
|
|
252
|
+
return {"features": out, "cls_token": None}
|
|
245
253
|
return self.final_layer(out)
|
|
246
254
|
|
|
247
255
|
|
{braindecode-1.3.2.dev182544824 → braindecode-1.3.2.dev183191339}/braindecode/models/eegpt.py
RENAMED
|
@@ -368,6 +368,13 @@ class EEGPT(EEGModuleMixin, nn.Module):
|
|
|
368
368
|
"""Number of temporal patches from encoder."""
|
|
369
369
|
return self.target_encoder.num_patches[1]
|
|
370
370
|
|
|
371
|
+
def reset_head(self, n_outputs):
|
|
372
|
+
self._n_outputs = n_outputs
|
|
373
|
+
self.final_layer = _LinearConstraintProbe(
|
|
374
|
+
**self.get_probe_params(),
|
|
375
|
+
n_outputs=n_outputs,
|
|
376
|
+
)
|
|
377
|
+
|
|
371
378
|
def get_probe_params(self) -> dict:
|
|
372
379
|
"""Get parameters needed to create a _LinearConstraintProbe.
|
|
373
380
|
|
|
@@ -382,7 +389,7 @@ class EEGPT(EEGModuleMixin, nn.Module):
|
|
|
382
389
|
"embed_dim": self.embed_dim,
|
|
383
390
|
}
|
|
384
391
|
|
|
385
|
-
def forward(self, x):
|
|
392
|
+
def forward(self, x, return_features=False):
|
|
386
393
|
"""
|
|
387
394
|
Forward pass.
|
|
388
395
|
|
|
@@ -390,10 +397,13 @@ class EEGPT(EEGModuleMixin, nn.Module):
|
|
|
390
397
|
----------
|
|
391
398
|
x : torch.Tensor
|
|
392
399
|
EEG data of shape (batch, n_chans, n_times).
|
|
400
|
+
return_features : bool
|
|
401
|
+
If True, return a dict with ``"features"`` and ``"cls_token"``
|
|
402
|
+
instead of the classification output.
|
|
393
403
|
|
|
394
404
|
Returns
|
|
395
405
|
-------
|
|
396
|
-
torch.Tensor
|
|
406
|
+
torch.Tensor or dict
|
|
397
407
|
Model output. Shape depends on `n_outputs` and `return_encoder_output`.
|
|
398
408
|
"""
|
|
399
409
|
# Channel projection (if configured)
|
|
@@ -402,6 +412,9 @@ class EEGPT(EEGModuleMixin, nn.Module):
|
|
|
402
412
|
# z shape: (batch, n_patches, embed_num, embed_dim)
|
|
403
413
|
z = self.target_encoder(x, self.chans_id)
|
|
404
414
|
|
|
415
|
+
if return_features:
|
|
416
|
+
return {"features": z.flatten(2), "cls_token": None}
|
|
417
|
+
|
|
405
418
|
if self.return_encoder_output:
|
|
406
419
|
return z
|
|
407
420
|
|
{braindecode-1.3.2.dev182544824 → braindecode-1.3.2.dev183191339}/braindecode/models/labram.py
RENAMED
|
@@ -790,6 +790,7 @@ class Labram(EEGModuleMixin, nn.Module):
|
|
|
790
790
|
ch_names: list[str] | None = None,
|
|
791
791
|
return_patch_tokens=False,
|
|
792
792
|
return_all_tokens=False,
|
|
793
|
+
return_features=False,
|
|
793
794
|
):
|
|
794
795
|
"""
|
|
795
796
|
Forward the input EEG data through the model.
|
|
@@ -805,6 +806,9 @@ class Labram(EEGModuleMixin, nn.Module):
|
|
|
805
806
|
If not provided, the channels provided during model initialization
|
|
806
807
|
(via ``chs_info``), channels will be used instead
|
|
807
808
|
If neither is provided, an error will be raised.
|
|
809
|
+
return_features : bool
|
|
810
|
+
If True, return a dict with ``"features"`` (patch tokens) and
|
|
811
|
+
``"cls_token"`` instead of the classification output.
|
|
808
812
|
return_patch_tokens: bool
|
|
809
813
|
Return the patch tokens
|
|
810
814
|
return_all_tokens: bool
|
|
@@ -812,12 +816,18 @@ class Labram(EEGModuleMixin, nn.Module):
|
|
|
812
816
|
|
|
813
817
|
Returns
|
|
814
818
|
-------
|
|
815
|
-
torch.Tensor
|
|
819
|
+
torch.Tensor or dict
|
|
816
820
|
The output of the model with dimensions (batch, n_outputs)
|
|
817
821
|
"""
|
|
818
822
|
# Apply automatic channel reordering if configured and input_chans not provided
|
|
819
823
|
x, input_chans = self._select_channels(x, ch_names=ch_names)
|
|
820
824
|
|
|
825
|
+
if return_features:
|
|
826
|
+
x = self.forward_features(
|
|
827
|
+
x, input_chans=input_chans, return_all_tokens=True
|
|
828
|
+
)
|
|
829
|
+
return {"features": x[:, 1:, :], "cls_token": x[:, 0, :]}
|
|
830
|
+
|
|
821
831
|
x = self.forward_features(
|
|
822
832
|
x,
|
|
823
833
|
input_chans=input_chans,
|
|
@@ -851,6 +861,10 @@ class Labram(EEGModuleMixin, nn.Module):
|
|
|
851
861
|
nn.Linear(self.embed_dim, n_outputs) if n_outputs > 0 else nn.Identity()
|
|
852
862
|
)
|
|
853
863
|
|
|
864
|
+
def reset_head(self, n_outputs):
|
|
865
|
+
self._n_outputs = n_outputs
|
|
866
|
+
self.reset_classifier(n_outputs)
|
|
867
|
+
|
|
854
868
|
def _adj_temporal_embedding(self, num_ch, batch_size, dim_embed=None):
|
|
855
869
|
"""
|
|
856
870
|
Adjust the dimensions of the time embedding to match the
|
{braindecode-1.3.2.dev182544824 → braindecode-1.3.2.dev183191339}/braindecode/models/luna.py
RENAMED
|
@@ -49,7 +49,7 @@ class LUNA(EEGModuleMixin, nn.Module):
|
|
|
49
49
|
**Pre-trained Weights Available**
|
|
50
50
|
|
|
51
51
|
This model has pre-trained weights available on the Hugging Face Hub
|
|
52
|
-
at `
|
|
52
|
+
at `PulpBio/LUNA <https://huggingface.co/PulpBio/LUNA>`_.
|
|
53
53
|
|
|
54
54
|
Available model variants:
|
|
55
55
|
|
|
@@ -61,19 +61,13 @@ class LUNA(EEGModuleMixin, nn.Module):
|
|
|
61
61
|
|
|
62
62
|
.. code-block:: python
|
|
63
63
|
|
|
64
|
-
from huggingface_hub import hf_hub_download
|
|
65
|
-
from safetensors.torch import load_file
|
|
66
64
|
from braindecode.models import LUNA
|
|
67
65
|
|
|
68
|
-
#
|
|
69
|
-
|
|
70
|
-
|
|
66
|
+
# Load pre-trained base model from Hugging Face Hub
|
|
67
|
+
model = LUNA.from_pretrained(
|
|
68
|
+
"PulpBio/LUNA",
|
|
71
69
|
filename="LUNA_base.safetensors",
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
# Create model for classification (fine-tuning)
|
|
75
|
-
model = LUNA(
|
|
76
|
-
n_outputs=2, # Number of classes for your task
|
|
70
|
+
n_outputs=2,
|
|
77
71
|
n_chans=22,
|
|
78
72
|
n_times=1000,
|
|
79
73
|
embed_dim=64,
|
|
@@ -81,11 +75,6 @@ class LUNA(EEGModuleMixin, nn.Module):
|
|
|
81
75
|
depth=8,
|
|
82
76
|
)
|
|
83
77
|
|
|
84
|
-
# Load pre-trained encoder weights
|
|
85
|
-
state_dict = load_file(model_path)
|
|
86
|
-
# load_state_dict applies model.mapping automatically
|
|
87
|
-
model.load_state_dict(state_dict, strict=False)
|
|
88
|
-
|
|
89
78
|
To push your own trained model to the Hub:
|
|
90
79
|
|
|
91
80
|
.. code-block:: python
|
{braindecode-1.3.2.dev182544824 → braindecode-1.3.2.dev183191339}/braindecode/models/reve.py
RENAMED
|
@@ -311,19 +311,7 @@ class REVE(EEGModuleMixin, nn.Module):
|
|
|
311
311
|
geglu=self.use_geglu,
|
|
312
312
|
)
|
|
313
313
|
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
if self.use_attention_pooling:
|
|
317
|
-
self.final_layer = nn.Sequential(
|
|
318
|
-
nn.LayerNorm(self.embed_dim),
|
|
319
|
-
nn.Linear(self.embed_dim, self.n_outputs),
|
|
320
|
-
)
|
|
321
|
-
else:
|
|
322
|
-
self.final_layer = nn.Sequential(
|
|
323
|
-
nn.Flatten(),
|
|
324
|
-
nn.LayerNorm(final_dim),
|
|
325
|
-
nn.Linear(final_dim, self.n_outputs),
|
|
326
|
-
)
|
|
314
|
+
self._build_head(self.n_outputs)
|
|
327
315
|
|
|
328
316
|
if self.use_attention_pooling:
|
|
329
317
|
self.cls_query_token = nn.Parameter(torch.randn(1, 1, self.embed_dim))
|
|
@@ -352,6 +340,24 @@ class REVE(EEGModuleMixin, nn.Module):
|
|
|
352
340
|
flat_dim = self.n_chans * n_patches * self.embed_dim
|
|
353
341
|
return flat_dim
|
|
354
342
|
|
|
343
|
+
def _build_head(self, n_outputs):
|
|
344
|
+
if self.use_attention_pooling:
|
|
345
|
+
self.final_layer = nn.Sequential(
|
|
346
|
+
nn.LayerNorm(self.embed_dim),
|
|
347
|
+
nn.Linear(self.embed_dim, n_outputs),
|
|
348
|
+
)
|
|
349
|
+
else:
|
|
350
|
+
final_dim = self._get_flattened_output_dim()
|
|
351
|
+
self.final_layer = nn.Sequential(
|
|
352
|
+
nn.Flatten(),
|
|
353
|
+
nn.LayerNorm(final_dim),
|
|
354
|
+
nn.Linear(final_dim, n_outputs),
|
|
355
|
+
)
|
|
356
|
+
|
|
357
|
+
def reset_head(self, n_outputs):
|
|
358
|
+
self._n_outputs = n_outputs
|
|
359
|
+
self._build_head(n_outputs)
|
|
360
|
+
|
|
355
361
|
def get_positions(self, channel_names: list[str]) -> torch.Tensor:
|
|
356
362
|
"""Fetch channel positions from the position bank. The position bank is downloaded when the model is instantiated.
|
|
357
363
|
|
|
@@ -373,7 +379,8 @@ class REVE(EEGModuleMixin, nn.Module):
|
|
|
373
379
|
eeg: torch.Tensor,
|
|
374
380
|
pos: Optional[torch.Tensor] = None,
|
|
375
381
|
return_output: bool = False,
|
|
376
|
-
|
|
382
|
+
return_features: bool = False,
|
|
383
|
+
) -> Union[torch.Tensor, list[torch.Tensor], dict]:
|
|
377
384
|
"""
|
|
378
385
|
Forward pass of the model.
|
|
379
386
|
|
|
@@ -392,17 +399,23 @@ class REVE(EEGModuleMixin, nn.Module):
|
|
|
392
399
|
return_output : bool, optional
|
|
393
400
|
If True, returns the output from the transformer directly.
|
|
394
401
|
If False, applies the final layer and returns the processed output. Default is False.
|
|
402
|
+
return_features : bool, optional
|
|
403
|
+
If True, returns a dict ``{"features": Tensor, "cls_token": None}``
|
|
404
|
+
with encoder features before the final layer. Default is False.
|
|
395
405
|
|
|
396
406
|
Returns
|
|
397
407
|
-------
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
The output tensor(s) from the model. If `return_output` is True,
|
|
403
|
-
returns the transformer output; otherwise, returns the output after the final layer.
|
|
408
|
+
torch.Tensor or list[torch.Tensor] or dict
|
|
409
|
+
Default: ``torch.Tensor`` after the final layer.
|
|
410
|
+
If ``return_output=True``: ``list[torch.Tensor]`` from transformer layers.
|
|
411
|
+
If ``return_features=True``: ``dict`` with ``"features"`` and ``"cls_token"`` keys.
|
|
404
412
|
"""
|
|
405
413
|
|
|
414
|
+
if return_output and return_features:
|
|
415
|
+
raise ValueError(
|
|
416
|
+
"return_output and return_features are mutually exclusive."
|
|
417
|
+
)
|
|
418
|
+
|
|
406
419
|
patches = eeg.unfold(
|
|
407
420
|
dimension=2,
|
|
408
421
|
size=self.patch_size,
|
|
@@ -453,6 +466,9 @@ class REVE(EEGModuleMixin, nn.Module):
|
|
|
453
466
|
emb=self.embed_dim,
|
|
454
467
|
)
|
|
455
468
|
|
|
469
|
+
if return_features:
|
|
470
|
+
return {"features": x, "cls_token": None}
|
|
471
|
+
|
|
456
472
|
if self.use_attention_pooling:
|
|
457
473
|
x = self._attention_pooling(x)
|
|
458
474
|
|