braindecode 0.5.1__py3-none-any.whl
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-0.5.1.dist-info/LICENSE.txt +31 -0
- Braindecode-0.5.1.dist-info/METADATA +133 -0
- Braindecode-0.5.1.dist-info/RECORD +69 -0
- Braindecode-0.5.1.dist-info/WHEEL +5 -0
- Braindecode-0.5.1.dist-info/top_level.txt +2 -0
- braindecode/__init__.py +4 -0
- braindecode/classifier.py +258 -0
- braindecode/datasets/__init__.py +7 -0
- braindecode/datasets/base.py +293 -0
- braindecode/datasets/bbci.py +679 -0
- braindecode/datasets/moabb.py +110 -0
- braindecode/datasets/sleep_physionet.py +103 -0
- braindecode/datasets/tuh.py +230 -0
- braindecode/datautil/__init__.py +11 -0
- braindecode/datautil/mne.py +136 -0
- braindecode/datautil/preprocess.py +364 -0
- braindecode/datautil/serialization.py +111 -0
- braindecode/datautil/util.py +36 -0
- braindecode/datautil/windowers.py +435 -0
- braindecode/datautil/xy.py +77 -0
- braindecode/models/__init__.py +12 -0
- braindecode/models/deep4.py +252 -0
- braindecode/models/eegnet.py +339 -0
- braindecode/models/eegresnet.py +232 -0
- braindecode/models/functions.py +43 -0
- braindecode/models/hybrid.py +103 -0
- braindecode/models/modules.py +150 -0
- braindecode/models/shallow_fbcsp.py +158 -0
- braindecode/models/sleep_stager_chambon_2018.py +113 -0
- braindecode/models/tcn.py +143 -0
- braindecode/models/util.py +66 -0
- braindecode/regressor.py +240 -0
- braindecode/samplers/__init__.py +5 -0
- braindecode/samplers/base.py +78 -0
- braindecode/samplers/ssl.py +118 -0
- braindecode/training/__init__.py +8 -0
- braindecode/training/callbacks.py +21 -0
- braindecode/training/losses.py +17 -0
- braindecode/training/scoring.py +296 -0
- braindecode/util.py +362 -0
- braindecode/version.py +1 -0
- braindecode/visualization/__init__.py +5 -0
- braindecode/visualization/gradients.py +53 -0
- test/__init__.py +0 -0
- test/acceptance_tests/__init__.py +0 -0
- test/acceptance_tests/test_cropped_decoding.py +171 -0
- test/acceptance_tests/test_eeg_classifier.py +255 -0
- test/acceptance_tests/test_model_architectures.py +54 -0
- test/acceptance_tests/test_trialwise_decoding.py +168 -0
- test/unit_tests/__init__.py +0 -0
- test/unit_tests/datasets/__init__.py +0 -0
- test/unit_tests/datasets/test_dataset.py +227 -0
- test/unit_tests/datasets/test_mne.py +145 -0
- test/unit_tests/datasets/test_sleep_physionet.py +23 -0
- test/unit_tests/datasets/test_tuh.py +97 -0
- test/unit_tests/datasets/test_xy.py +31 -0
- test/unit_tests/datautil/__init__.py +0 -0
- test/unit_tests/datautil/test_preprocess.py +270 -0
- test/unit_tests/datautil/test_serialization.py +127 -0
- test/unit_tests/datautil/test_windowers.py +519 -0
- test/unit_tests/models/__init__.py +0 -0
- test/unit_tests/models/test_models.py +136 -0
- test/unit_tests/models/test_util.py +22 -0
- test/unit_tests/test_eeg_classifier.py +73 -0
- test/unit_tests/test_eeg_regressor.py +72 -0
- test/unit_tests/test_scoring.py +282 -0
- test/unit_tests/test_util.py +30 -0
- test/unit_tests/visualization/__init__.py +0 -0
- test/unit_tests/visualization/test_gradients.py +38 -0
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
BSD 3-Clause License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2017-2020 Braindecode Developers
|
|
4
|
+
All rights reserved.
|
|
5
|
+
|
|
6
|
+
Redistribution and use in source and binary forms, with or without modification,
|
|
7
|
+
are permitted provided that the following conditions are met:
|
|
8
|
+
|
|
9
|
+
1. Redistributions of source code must retain the above copyright notice,
|
|
10
|
+
this list of conditions and the following disclaimer.
|
|
11
|
+
|
|
12
|
+
2. Redistributions in binary form must reproduce the above copyright notice,
|
|
13
|
+
this list of conditions and the following disclaimer in the documentation
|
|
14
|
+
and/or other materials provided with the distribution.
|
|
15
|
+
|
|
16
|
+
3. Neither the name of the copyright holder nor the names of its contributors
|
|
17
|
+
may be used to endorse or promote products derived from this software
|
|
18
|
+
without specific prior written permission.
|
|
19
|
+
|
|
20
|
+
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
|
21
|
+
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
|
|
22
|
+
THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A P
|
|
23
|
+
ARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER
|
|
24
|
+
OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
|
25
|
+
EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
|
26
|
+
PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
|
27
|
+
PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
|
28
|
+
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
|
29
|
+
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY
|
|
30
|
+
WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
|
31
|
+
POSSIBILITY OF SUCH DAMAGE.
|
|
@@ -0,0 +1,133 @@
|
|
|
1
|
+
Metadata-Version: 2.1
|
|
2
|
+
Name: Braindecode
|
|
3
|
+
Version: 0.5.1
|
|
4
|
+
Summary: A deep learning toolbox to decode raw time-domain EEG.
|
|
5
|
+
Home-page: https://github.com/braindecode/braindecode
|
|
6
|
+
Author: Robin Tibor Schirrmeister
|
|
7
|
+
Author-email: robintibor@gmail.com
|
|
8
|
+
License: BSD 3-Clause
|
|
9
|
+
Keywords: eeg deep-learning brain-state-decoding
|
|
10
|
+
Platform: UNKNOWN
|
|
11
|
+
Classifier: Development Status :: 3 - Alpha
|
|
12
|
+
Classifier: Intended Audience :: Developers
|
|
13
|
+
Classifier: Intended Audience :: Science/Research
|
|
14
|
+
Classifier: Topic :: Software Development :: Build Tools
|
|
15
|
+
Classifier: Topic :: Scientific/Engineering :: Artificial Intelligence
|
|
16
|
+
Classifier: License :: OSI Approved :: BSD License
|
|
17
|
+
Classifier: Programming Language :: Python :: 3.7
|
|
18
|
+
Requires-Dist: mne
|
|
19
|
+
Requires-Dist: numpy
|
|
20
|
+
Requires-Dist: pandas
|
|
21
|
+
Requires-Dist: scipy
|
|
22
|
+
Requires-Dist: matplotlib
|
|
23
|
+
Requires-Dist: h5py
|
|
24
|
+
Requires-Dist: skorch
|
|
25
|
+
|
|
26
|
+
Braindecode
|
|
27
|
+
===========
|
|
28
|
+
|
|
29
|
+
.. image:: https://badges.gitter.im/braindecodechat/community.svg
|
|
30
|
+
:alt: Join the chat at https://gitter.im/braindecodechat/community
|
|
31
|
+
:target: https://gitter.im/braindecodechat/community?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge
|
|
32
|
+
|
|
33
|
+
.. image:: https://github.com/braindecode/braindecode/workflows/tests-and-docs/badge.svg
|
|
34
|
+
:target: https://github.com/braindecode/braindecode/actions
|
|
35
|
+
|
|
36
|
+
.. image:: https://circleci.com/gh/braindecode/braindecode.svg?style=svg
|
|
37
|
+
:target: https://circleci.com/gh/braindecode/braindecode
|
|
38
|
+
:alt: Doc build on CircleCI
|
|
39
|
+
|
|
40
|
+
.. image:: https://codecov.io/gh/braindecode/braindecode/branch/master/graph/badge.svg
|
|
41
|
+
:target: https://codecov.io/gh/braindecode/braindecode
|
|
42
|
+
:alt: Code Coverage
|
|
43
|
+
|
|
44
|
+
A deep learning toolbox to decode raw time-domain EEG.
|
|
45
|
+
|
|
46
|
+
For EEG researchers who want to work with deep learning and
|
|
47
|
+
deep learning researchers who want to work with EEG data.
|
|
48
|
+
For now focused on convolutional networks.
|
|
49
|
+
|
|
50
|
+
|
|
51
|
+
Installation
|
|
52
|
+
============
|
|
53
|
+
|
|
54
|
+
1. Install pytorch from http://pytorch.org/ (you don't need to install torchvision).
|
|
55
|
+
|
|
56
|
+
2. Install `MOABB <https://github.com/NeuroTechX/moabb>`_ via pip (needed if you want to use MOABB datasets utilities):
|
|
57
|
+
|
|
58
|
+
.. code-block:: bash
|
|
59
|
+
|
|
60
|
+
pip install moabb
|
|
61
|
+
|
|
62
|
+
3. Install latest release of braindecode via pip:
|
|
63
|
+
|
|
64
|
+
.. code-block:: bash
|
|
65
|
+
|
|
66
|
+
pip install braindecode
|
|
67
|
+
|
|
68
|
+
alternatively, if you use conda, you could create a dedicated environment with the following:
|
|
69
|
+
|
|
70
|
+
.. code-block:: bash
|
|
71
|
+
|
|
72
|
+
curl -O https://raw.githubusercontent.com/braindecode/braindecode/master/environment.yml
|
|
73
|
+
conda env create -f environment.yml
|
|
74
|
+
conda activate braindecode
|
|
75
|
+
|
|
76
|
+
alternatively, install the latest version of braindecode via pip:
|
|
77
|
+
|
|
78
|
+
.. code-block:: bash
|
|
79
|
+
|
|
80
|
+
pip install -U https://api.github.com/repos/braindecode/braindecode/zipball/master
|
|
81
|
+
|
|
82
|
+
|
|
83
|
+
Documentation
|
|
84
|
+
=============
|
|
85
|
+
|
|
86
|
+
Documentation is online under https://braindecode.org
|
|
87
|
+
|
|
88
|
+
|
|
89
|
+
Dataset
|
|
90
|
+
=======
|
|
91
|
+
The high-gamma dataset used in our publication (see below), including trained models, is available under:
|
|
92
|
+
https://web.gin.g-node.org/robintibor/high-gamma-dataset/
|
|
93
|
+
|
|
94
|
+
|
|
95
|
+
Citing
|
|
96
|
+
======
|
|
97
|
+
|
|
98
|
+
If you use this code in a scientific publication, please cite us as:
|
|
99
|
+
|
|
100
|
+
.. code-block:: bibtex
|
|
101
|
+
|
|
102
|
+
@article {HBM:HBM23730,
|
|
103
|
+
author = {Schirrmeister, Robin Tibor and Springenberg, Jost Tobias and Fiederer,
|
|
104
|
+
Lukas Dominique Josef and Glasstetter, Martin and Eggensperger, Katharina and Tangermann, Michael and
|
|
105
|
+
Hutter, Frank and Burgard, Wolfram and Ball, Tonio},
|
|
106
|
+
title = {Deep learning with convolutional neural networks for EEG decoding and visualization},
|
|
107
|
+
journal = {Human Brain Mapping},
|
|
108
|
+
issn = {1097-0193},
|
|
109
|
+
url = {http://dx.doi.org/10.1002/hbm.23730},
|
|
110
|
+
doi = {10.1002/hbm.23730},
|
|
111
|
+
month = {aug},
|
|
112
|
+
year = {2017},
|
|
113
|
+
keywords = {electroencephalography, EEG analysis, machine learning, end-to-end learning, brain–machine interface,
|
|
114
|
+
brain–computer interface, model interpretability, brain mapping},
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
as well as the `MNE-Python <https://mne.tools>`_ software that is used by braindecode:
|
|
118
|
+
|
|
119
|
+
.. code-block:: bibtex
|
|
120
|
+
|
|
121
|
+
@article{10.3389/fnins.2013.00267,
|
|
122
|
+
author={Gramfort, Alexandre and Luessi, Martin and Larson, Eric and Engemann, Denis and Strohmeier, Daniel and Brodbeck, Christian and Goj, Roman and Jas, Mainak and Brooks, Teon and Parkkonen, Lauri and Hämäläinen, Matti},
|
|
123
|
+
title={{MEG and EEG data analysis with MNE-Python}},
|
|
124
|
+
journal={Frontiers in Neuroscience},
|
|
125
|
+
volume={7},
|
|
126
|
+
pages={267},
|
|
127
|
+
year={2013},
|
|
128
|
+
url={https://www.frontiersin.org/article/10.3389/fnins.2013.00267},
|
|
129
|
+
doi={10.3389/fnins.2013.00267},
|
|
130
|
+
issn={1662-453X},
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
braindecode/__init__.py,sha256=rjgsIxcVssXL6fBLz410QRIXMGbQJg_IqzUTAtlPiNE,108
|
|
2
|
+
braindecode/classifier.py,sha256=tNu4b16Hk6Qg9OCIB7I-naWsFz8PrqioBA6u7XXDJuY,10634
|
|
3
|
+
braindecode/regressor.py,sha256=-Puf-309OLHQv9Wo6OZ-eZQ4j1TIIHZd5UilHNWnVB0,10281
|
|
4
|
+
braindecode/util.py,sha256=jkXvXWhFX35WiBchyGuRjg3L1nT3JljfmQ0GUD-ylwM,10908
|
|
5
|
+
braindecode/version.py,sha256=eZ1bOun1DDVV0YLOBW4wj2FP1ajReLjbIrGmzN7ASBw,22
|
|
6
|
+
braindecode/datasets/__init__.py,sha256=wuQJAYHJt-XM7mt5tl8X239JWoSx15f-oDHfBxcWgMs,214
|
|
7
|
+
braindecode/datasets/base.py,sha256=79-gP80SqlvCruan8OWHNKmYGu8L_zDCEM8usaSgEWM,11173
|
|
8
|
+
braindecode/datasets/bbci.py,sha256=Xe0n0zTNGutmwB5zYPL-YDJpxvdV42esMd5JqfY55DU,18138
|
|
9
|
+
braindecode/datasets/moabb.py,sha256=G_YD13R1Kv2vpdpdPZZR6VJsNEggotHmsxcH6jRUwh4,3586
|
|
10
|
+
braindecode/datasets/sleep_physionet.py,sha256=buECDZ7-qWg9IYs4TCd8pyHewETKYP8Z6_piduDzC7M,3642
|
|
11
|
+
braindecode/datasets/tuh.py,sha256=ScDJA9hK-1AJDgpZOjYxMVjkx1b2ZZ_zeBu8zUy-qX0,9343
|
|
12
|
+
braindecode/datautil/__init__.py,sha256=LdDKYju3PjPXmnyTOdDIcs_ZnEMe6oo6pLyRiuXwGU0,469
|
|
13
|
+
braindecode/datautil/mne.py,sha256=wK4vBupUHQLjzsGxu8TwAXZbwalzKJH3D4V34zOgV8E,5139
|
|
14
|
+
braindecode/datautil/preprocess.py,sha256=j1zsJlxBtzpeJNta6ajGsle0eSYxlHBbqKsBfxfPe1w,13532
|
|
15
|
+
braindecode/datautil/serialization.py,sha256=Nd0xpi9sQ11wipSMZ9RnlW58qAbNoke8eVJ-1AAJMIs,4177
|
|
16
|
+
braindecode/datautil/util.py,sha256=6T3crOjQh-H66RW6qO8SNVp2QbuKEn-jD4P6-E7HaNs,598
|
|
17
|
+
braindecode/datautil/windowers.py,sha256=pH2Lf0uSVX3eL-gHIqRd2WHBK0MW0CH8piNFArbrGPc,18045
|
|
18
|
+
braindecode/datautil/xy.py,sha256=NWbTniC1kuCcBt1NL83qIpgnmaxqeaEO0mqjwwcYnoQ,2773
|
|
19
|
+
braindecode/models/__init__.py,sha256=hJJ9nDKuf-44UqNtOT7SI76UpjAqhUocpMrx-y8ntTs,356
|
|
20
|
+
braindecode/models/deep4.py,sha256=M5quxf9ng1c137ET6gh__32qvgKPsQXsWDADB-SATZ8,9115
|
|
21
|
+
braindecode/models/eegnet.py,sha256=QcNRTG6MjH0cpQ7oABFiKJzvQFQa2gAAyzbqR6GUY5o,10813
|
|
22
|
+
braindecode/models/eegresnet.py,sha256=JD29wJDGva0ttiPViXh8Y6z0LOMb0nRCJH9umTvU2D0,10347
|
|
23
|
+
braindecode/models/functions.py,sha256=M594jERE0NncoT-m82cQV65x-aHnn8-c5bV6hkQXVto,834
|
|
24
|
+
braindecode/models/hybrid.py,sha256=y2V3z0Zo_R9zLOdptAFLygOdWVVHA6eaUZImYso51_w,3550
|
|
25
|
+
braindecode/models/modules.py,sha256=QD7pvtE1m33yPz_pocD6zaAlad9EKhT6HoRruixpHfs,4720
|
|
26
|
+
braindecode/models/shallow_fbcsp.py,sha256=dirHSromjm5VRzE-nspPG3X71XgvviXLPf8tqWbeG90,5459
|
|
27
|
+
braindecode/models/sleep_stager_chambon_2018.py,sha256=MFu-XYaPCYEma61SqPlKv5vPud8CNUoQ8G_rwrSTmMU,3765
|
|
28
|
+
braindecode/models/tcn.py,sha256=3dMhI82n3UzQDQ-EtXlNnvCM9vo_EcqXKJOqL6Oi9F0,4968
|
|
29
|
+
braindecode/models/util.py,sha256=OYH9-KlBZ0_5-jbuioxysicaaT2r6S4SYVaFQ14c6VE,2253
|
|
30
|
+
braindecode/samplers/__init__.py,sha256=98li_WbqJ9YRcaB4imtaZGrGER18GZp-rIuhwOUp-FY,115
|
|
31
|
+
braindecode/samplers/base.py,sha256=S8Cbx_-Js2khcLOy4vt50tKTal_6ZPykEWvGnnKuGYU,2853
|
|
32
|
+
braindecode/samplers/ssl.py,sha256=fxeQtQdI4C25ChnWJ05MGunMRVCVxl9rlDptNdqn_0Y,4260
|
|
33
|
+
braindecode/training/__init__.py,sha256=Zt8Wife2goc4Nt9jk5AcnuRFYYc2cEYfB0MPh483Utg,207
|
|
34
|
+
braindecode/training/callbacks.py,sha256=cvkTKTaG0qNfCgrGNQ9DZ3CNGF_JxnooyBDBXfLPMLM,807
|
|
35
|
+
braindecode/training/losses.py,sha256=BamiYR6uUAhIMx7CxiDBj13gaq5zfLMdMlUvHdZOspc,517
|
|
36
|
+
braindecode/training/scoring.py,sha256=fkSBFjQ3VGOieGrHoWPuFFojwXkndMPgUgjgjW4vUjY,11191
|
|
37
|
+
braindecode/visualization/__init__.py,sha256=7njSpH6RdLESFnN-OWSEtvxOgmV5ykAOPFIaoYAuwJg,118
|
|
38
|
+
braindecode/visualization/gradients.py,sha256=7rzYDzdexJIEk1T7PM7Vse1D53gHnLBkTeWxTqBK5JA,1976
|
|
39
|
+
test/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
40
|
+
test/acceptance_tests/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
41
|
+
test/acceptance_tests/test_cropped_decoding.py,sha256=dfKAYlhlLRaJ1VwSinzFiT1XinoerbgxK-I-SFzC9w0,4797
|
|
42
|
+
test/acceptance_tests/test_eeg_classifier.py,sha256=u52shacGL7XLW3bzZlMRFFkwPnsCwsYSyGalWnOlRT8,9750
|
|
43
|
+
test/acceptance_tests/test_model_architectures.py,sha256=rXIKalmoioOhPNt7AJtpH_5Rnn0Wo1CySZ0Kd505XsI,2346
|
|
44
|
+
test/acceptance_tests/test_trialwise_decoding.py,sha256=ab26R-FZRaUwAfIFv8zWU928FHNuEAtKUuYAvI86eNs,4134
|
|
45
|
+
test/unit_tests/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
46
|
+
test/unit_tests/test_eeg_classifier.py,sha256=EfMkrFwJExpcO1acK0KXGee03vNPb7ruk6BZY9jbb54,2103
|
|
47
|
+
test/unit_tests/test_eeg_regressor.py,sha256=_XONUabm12BoMGPBH9vNE1GgOf9Y7KmwBwLlwU5ZNfc,1981
|
|
48
|
+
test/unit_tests/test_scoring.py,sha256=-ZDFNG1MGdQd18yeb2xsiS0FG8eYBER9XkGjUTVHpMI,9367
|
|
49
|
+
test/unit_tests/test_util.py,sha256=bzW96dQIy-UkIm4hQs1Q8TdNuPt4RDkXwnS-ylYeiTE,839
|
|
50
|
+
test/unit_tests/datasets/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
51
|
+
test/unit_tests/datasets/test_dataset.py,sha256=-B0eM4Xxj6SkMDnyAXZLnPnxMu1Mux9iYhdyBJavHO8,8070
|
|
52
|
+
test/unit_tests/datasets/test_mne.py,sha256=cKAd1JHzoRzECrHno7k3Kei8OLcYPf2RcNKXZdc7vew,5567
|
|
53
|
+
test/unit_tests/datasets/test_sleep_physionet.py,sha256=jY--u8JFiptmw79Z12bJRkHY0EGlKaCkoFlsY21WVSI,763
|
|
54
|
+
test/unit_tests/datasets/test_tuh.py,sha256=n3VyDJmMj73YTIwF_UXz3LKXQYYrCi6Le_SBodYHQws,4229
|
|
55
|
+
test/unit_tests/datasets/test_xy.py,sha256=N70ctHQLrjPQG9sm3h0hvuRqTR_my_CrOfbkKauOgQM,704
|
|
56
|
+
test/unit_tests/datautil/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
57
|
+
test/unit_tests/datautil/test_preprocess.py,sha256=R_XAa50b8ihMMBdLcfCjcqU--D0jeIpY32mShgJGmmQ,9939
|
|
58
|
+
test/unit_tests/datautil/test_serialization.py,sha256=aKlkEyudNjmbBO95IlWi8AzAy-CY2-R23Hs_Ri-1B9Y,5679
|
|
59
|
+
test/unit_tests/datautil/test_windowers.py,sha256=_h6WUAqm2U_uf_oVggavuh4fjI8RHEYlLdOcKdmH3gg,21706
|
|
60
|
+
test/unit_tests/models/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
61
|
+
test/unit_tests/models/test_models.py,sha256=PNQDMsyz4Ssxu9QhMCg6pRuzixrJNkJrIWwNsXIHmqo,4434
|
|
62
|
+
test/unit_tests/models/test_util.py,sha256=gt5-jDBxYz5kWTn_hlj5ElvIeKLuYBXqvbFzJH_3rSM,650
|
|
63
|
+
test/unit_tests/visualization/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
64
|
+
test/unit_tests/visualization/test_gradients.py,sha256=-Ck_-3NBl1CCvEOfjYZKnhNFc7z13wexBpXNQ9E9OGY,1568
|
|
65
|
+
Braindecode-0.5.1.dist-info/LICENSE.txt,sha256=1IX7wR-nRXQap6IOIEXe-ZtJHIaXuiX5UOMsQCrou2I,1520
|
|
66
|
+
Braindecode-0.5.1.dist-info/METADATA,sha256=TAgN4ZQvjiMImcANRLOxZ39wGL6U1sK6eA2cCyIYOs4,4430
|
|
67
|
+
Braindecode-0.5.1.dist-info/WHEEL,sha256=OqRkF0eY5GHssMorFjlbTIq072vpHpF60fIQA6lS9xA,92
|
|
68
|
+
Braindecode-0.5.1.dist-info/top_level.txt,sha256=cLHnLHwrOBLTtfXQ_t0YUzOnEvnucbpMAZztWLvBuxE,17
|
|
69
|
+
Braindecode-0.5.1.dist-info/RECORD,,
|
braindecode/__init__.py
ADDED
|
@@ -0,0 +1,258 @@
|
|
|
1
|
+
import numpy as np
|
|
2
|
+
from sklearn.metrics import get_scorer
|
|
3
|
+
from skorch.callbacks import EpochTimer, BatchScoring, PrintLog, EpochScoring
|
|
4
|
+
from skorch.classifier import NeuralNet
|
|
5
|
+
from skorch.classifier import NeuralNetClassifier
|
|
6
|
+
from skorch.utils import train_loss_score, valid_loss_score, noop, to_numpy
|
|
7
|
+
|
|
8
|
+
from .training.scoring import PostEpochTrainScoring, CroppedTrialEpochScoring
|
|
9
|
+
from .util import ThrowAwayIndexLoader, update_estimator_docstring
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
class EEGClassifier(NeuralNetClassifier):
|
|
13
|
+
doc = """Classifier that does not assume softmax activation.
|
|
14
|
+
Calls loss function directly without applying log or anything.
|
|
15
|
+
|
|
16
|
+
Parameters
|
|
17
|
+
----------
|
|
18
|
+
cropped: bool (default=False)
|
|
19
|
+
Defines whether torch model passed to this class is cropped or not.
|
|
20
|
+
Currently used for callbacks definition.
|
|
21
|
+
|
|
22
|
+
callbacks: None or list of strings or list of Callback instances (default=None)
|
|
23
|
+
More callbacks, in addition to those returned by
|
|
24
|
+
``get_default_callbacks``. Each callback should inherit from
|
|
25
|
+
:class:`skorch.callbacks.Callback`. If not ``None``, callbacks can be a
|
|
26
|
+
list of strings specifying `sklearn` scoring functions (for scoring
|
|
27
|
+
functions names see: https://scikit-learn.org/stable/modules/model_evaluation.html#scoring-parameter)
|
|
28
|
+
or a list of callbacks where the callback names are inferred from the
|
|
29
|
+
class name. Name conflicts are resolved by appending a count suffix
|
|
30
|
+
starting with 1, e.g. ``EpochScoring_1``. Alternatively,
|
|
31
|
+
a tuple ``(name, callback)`` can be passed, where ``name``
|
|
32
|
+
should be unique. Callbacks may or may not be instantiated.
|
|
33
|
+
The callback name can be used to set parameters on specific
|
|
34
|
+
callbacks (e.g., for the callback with name ``'print_log'``, use
|
|
35
|
+
``net.set_params(callbacks__print_log__keys_ignored=['epoch',
|
|
36
|
+
'train_loss'])``).
|
|
37
|
+
|
|
38
|
+
iterator_train__shuffle: bool (default=True)
|
|
39
|
+
Defines whether train dataset will be shuffled. As skorch does not
|
|
40
|
+
shuffle the train dataset by default this one overwrites this option.
|
|
41
|
+
|
|
42
|
+
"""
|
|
43
|
+
__doc__ = update_estimator_docstring(NeuralNetClassifier, doc)
|
|
44
|
+
|
|
45
|
+
def __init__(self, *args, cropped=False, callbacks=None,
|
|
46
|
+
iterator_train__shuffle=True, **kwargs):
|
|
47
|
+
self.cropped = cropped
|
|
48
|
+
callbacks = self._parse_callbacks(callbacks)
|
|
49
|
+
|
|
50
|
+
super().__init__(*args,
|
|
51
|
+
callbacks=callbacks,
|
|
52
|
+
iterator_train__shuffle=iterator_train__shuffle,
|
|
53
|
+
**kwargs)
|
|
54
|
+
|
|
55
|
+
def _parse_callbacks(self, callbacks):
|
|
56
|
+
callbacks_list = []
|
|
57
|
+
if callbacks is not None:
|
|
58
|
+
for callback in callbacks:
|
|
59
|
+
if isinstance(callback, tuple):
|
|
60
|
+
callbacks_list.append(callback)
|
|
61
|
+
else:
|
|
62
|
+
assert isinstance(callback, str)
|
|
63
|
+
scoring = get_scorer(callback)
|
|
64
|
+
scoring_name = scoring._score_func.__name__
|
|
65
|
+
assert scoring_name.endswith(
|
|
66
|
+
('_score', '_error', '_deviance', '_loss'))
|
|
67
|
+
if (scoring_name.endswith('_score') or
|
|
68
|
+
callback.startswith('neg_')):
|
|
69
|
+
lower_is_better = False
|
|
70
|
+
else:
|
|
71
|
+
lower_is_better = True
|
|
72
|
+
train_name = f'train_{callback}'
|
|
73
|
+
valid_name = f'valid_{callback}'
|
|
74
|
+
if self.cropped:
|
|
75
|
+
# In case of cropped decoding we are using braindecode
|
|
76
|
+
# specific scoring created for cropped decoding
|
|
77
|
+
train_scoring = CroppedTrialEpochScoring(
|
|
78
|
+
callback, lower_is_better, on_train=True, name=train_name
|
|
79
|
+
)
|
|
80
|
+
valid_scoring = CroppedTrialEpochScoring(
|
|
81
|
+
callback, lower_is_better, on_train=False, name=valid_name
|
|
82
|
+
)
|
|
83
|
+
else:
|
|
84
|
+
train_scoring = PostEpochTrainScoring(
|
|
85
|
+
callback, lower_is_better, name=train_name
|
|
86
|
+
)
|
|
87
|
+
valid_scoring = EpochScoring(
|
|
88
|
+
callback, lower_is_better, on_train=False, name=valid_name
|
|
89
|
+
)
|
|
90
|
+
callbacks_list.extend([
|
|
91
|
+
(train_name, train_scoring),
|
|
92
|
+
(valid_name, valid_scoring)
|
|
93
|
+
])
|
|
94
|
+
|
|
95
|
+
return callbacks_list
|
|
96
|
+
|
|
97
|
+
# pylint: disable=arguments-differ
|
|
98
|
+
def get_loss(self, y_pred, y_true, *args, **kwargs):
|
|
99
|
+
"""Return the loss for this batch by calling NeuralNet get_loss.
|
|
100
|
+
Parameters
|
|
101
|
+
----------
|
|
102
|
+
y_pred : torch tensor
|
|
103
|
+
Predicted target values
|
|
104
|
+
y_true : torch tensor
|
|
105
|
+
True target values.
|
|
106
|
+
X : input data, compatible with skorch.dataset.Dataset
|
|
107
|
+
By default, you should be able to pass:
|
|
108
|
+
* numpy arrays
|
|
109
|
+
* torch tensors
|
|
110
|
+
* pandas DataFrame or Series
|
|
111
|
+
* scipy sparse CSR matrices
|
|
112
|
+
* a dictionary of the former three
|
|
113
|
+
* a list/tuple of the former three
|
|
114
|
+
* a Dataset
|
|
115
|
+
If this doesn't work with your data, you have to pass a
|
|
116
|
+
``Dataset`` that can deal with the data.
|
|
117
|
+
training : bool (default=False)
|
|
118
|
+
Whether train mode should be used or not.
|
|
119
|
+
|
|
120
|
+
"""
|
|
121
|
+
return NeuralNet.get_loss(self, y_pred, y_true, *args, **kwargs)
|
|
122
|
+
|
|
123
|
+
def get_iterator(self, dataset, training=False, drop_index=True):
|
|
124
|
+
iterator = super().get_iterator(dataset, training=training)
|
|
125
|
+
if drop_index:
|
|
126
|
+
return ThrowAwayIndexLoader(self, iterator, is_regression=False)
|
|
127
|
+
else:
|
|
128
|
+
return iterator
|
|
129
|
+
|
|
130
|
+
def on_batch_end(self, net, X, y, training=False, **kwargs):
|
|
131
|
+
# If training is false, assume that our loader has indices for this
|
|
132
|
+
# batch
|
|
133
|
+
if not training:
|
|
134
|
+
cbs = self._default_callbacks + self.callbacks
|
|
135
|
+
epoch_cbs = []
|
|
136
|
+
for name, cb in cbs:
|
|
137
|
+
if (cb.__class__.__name__ == 'CroppedTrialEpochScoring') and (
|
|
138
|
+
hasattr(cb, 'window_inds_')) and (cb.on_train == False):
|
|
139
|
+
epoch_cbs.append(cb)
|
|
140
|
+
# for trialwise decoding stuffs it might also be we don't have
|
|
141
|
+
# cropped loader, so no indices there
|
|
142
|
+
if len(epoch_cbs) > 0:
|
|
143
|
+
assert hasattr(self, '_last_window_inds')
|
|
144
|
+
for cb in epoch_cbs:
|
|
145
|
+
cb.window_inds_.append(self._last_window_inds)
|
|
146
|
+
del self._last_window_inds
|
|
147
|
+
|
|
148
|
+
def predict_with_window_inds_and_ys(self, dataset):
|
|
149
|
+
preds = []
|
|
150
|
+
i_window_in_trials = []
|
|
151
|
+
i_window_stops = []
|
|
152
|
+
window_ys = []
|
|
153
|
+
for X, y, i in self.get_iterator(dataset, drop_index=False):
|
|
154
|
+
i_window_in_trials.append(i[0].cpu().numpy())
|
|
155
|
+
i_window_stops.append(i[2].cpu().numpy())
|
|
156
|
+
preds.append(to_numpy(self.forward(X)))
|
|
157
|
+
window_ys.append(y.cpu().numpy())
|
|
158
|
+
preds = np.concatenate(preds)
|
|
159
|
+
i_window_in_trials = np.concatenate(i_window_in_trials)
|
|
160
|
+
i_window_stops = np.concatenate(i_window_stops)
|
|
161
|
+
window_ys = np.concatenate(window_ys)
|
|
162
|
+
return dict(
|
|
163
|
+
preds=preds, i_window_in_trials=i_window_in_trials,
|
|
164
|
+
i_window_stops=i_window_stops, window_ys=window_ys)
|
|
165
|
+
|
|
166
|
+
# Removes default EpochScoring callback computing 'accuracy' to work properly
|
|
167
|
+
# with cropped decoding.
|
|
168
|
+
@property
|
|
169
|
+
def _default_callbacks(self):
|
|
170
|
+
return [
|
|
171
|
+
("epoch_timer", EpochTimer()),
|
|
172
|
+
(
|
|
173
|
+
"train_loss",
|
|
174
|
+
BatchScoring(
|
|
175
|
+
train_loss_score,
|
|
176
|
+
name="train_loss",
|
|
177
|
+
on_train=True,
|
|
178
|
+
target_extractor=noop,
|
|
179
|
+
),
|
|
180
|
+
),
|
|
181
|
+
(
|
|
182
|
+
"valid_loss",
|
|
183
|
+
BatchScoring(
|
|
184
|
+
valid_loss_score, name="valid_loss", target_extractor=noop,
|
|
185
|
+
),
|
|
186
|
+
),
|
|
187
|
+
("print_log", PrintLog()),
|
|
188
|
+
]
|
|
189
|
+
|
|
190
|
+
def predict_proba(self, X):
|
|
191
|
+
"""Return the output of the module's forward method as a numpy
|
|
192
|
+
array. In case of cropped decoding returns averaged values for
|
|
193
|
+
each trial.
|
|
194
|
+
|
|
195
|
+
If the module's forward method returns multiple outputs as a
|
|
196
|
+
tuple, it is assumed that the first output contains the
|
|
197
|
+
relevant information and the other values are ignored.
|
|
198
|
+
If all values are relevant or module's output for each crop
|
|
199
|
+
is needed, consider using :func:`~skorch.NeuralNet.forward`
|
|
200
|
+
instead.
|
|
201
|
+
|
|
202
|
+
Parameters
|
|
203
|
+
----------
|
|
204
|
+
X : input data, compatible with skorch.dataset.Dataset
|
|
205
|
+
By default, you should be able to pass:
|
|
206
|
+
|
|
207
|
+
* numpy arrays
|
|
208
|
+
* torch tensors
|
|
209
|
+
* pandas DataFrame or Series
|
|
210
|
+
* scipy sparse CSR matrices
|
|
211
|
+
* a dictionary of the former three
|
|
212
|
+
* a list/tuple of the former three
|
|
213
|
+
* a Dataset
|
|
214
|
+
|
|
215
|
+
If this doesn't work with your data, you have to pass a
|
|
216
|
+
``Dataset`` that can deal with the data.
|
|
217
|
+
|
|
218
|
+
Returns
|
|
219
|
+
-------
|
|
220
|
+
y_proba : numpy ndarray
|
|
221
|
+
|
|
222
|
+
"""
|
|
223
|
+
y_pred = super().predict_proba(X)
|
|
224
|
+
# Normally, we have to average the predictions across crops/timesteps
|
|
225
|
+
# to get one prediction per window/trial
|
|
226
|
+
# Predictions may be already averaged in CroppedTrialEpochScoring (y_pred.shape==2).
|
|
227
|
+
# However, when predictions are computed outside of CroppedTrialEpochScoring
|
|
228
|
+
# we have to average predictions, hence the check if len(y_pred.shape) == 3
|
|
229
|
+
if self.cropped and len(y_pred.shape) == 3:
|
|
230
|
+
return y_pred.mean(axis=-1)
|
|
231
|
+
else:
|
|
232
|
+
return y_pred
|
|
233
|
+
|
|
234
|
+
def predict(self, X):
|
|
235
|
+
"""Return class labels for samples in X.
|
|
236
|
+
|
|
237
|
+
Parameters
|
|
238
|
+
----------
|
|
239
|
+
X : input data, compatible with skorch.dataset.Dataset
|
|
240
|
+
By default, you should be able to pass:
|
|
241
|
+
|
|
242
|
+
* numpy arrays
|
|
243
|
+
* torch tensors
|
|
244
|
+
* pandas DataFrame or Series
|
|
245
|
+
* scipy sparse CSR matrices
|
|
246
|
+
* a dictionary of the former three
|
|
247
|
+
* a list/tuple of the former three
|
|
248
|
+
* a Dataset
|
|
249
|
+
|
|
250
|
+
If this doesn't work with your data, you have to pass a
|
|
251
|
+
``Dataset`` that can deal with the data.
|
|
252
|
+
|
|
253
|
+
Returns
|
|
254
|
+
-------
|
|
255
|
+
y_pred : numpy ndarray
|
|
256
|
+
|
|
257
|
+
"""
|
|
258
|
+
return self.predict_proba(X).argmax(1)
|