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.
Files changed (69) hide show
  1. Braindecode-0.5.1.dist-info/LICENSE.txt +31 -0
  2. Braindecode-0.5.1.dist-info/METADATA +133 -0
  3. Braindecode-0.5.1.dist-info/RECORD +69 -0
  4. Braindecode-0.5.1.dist-info/WHEEL +5 -0
  5. Braindecode-0.5.1.dist-info/top_level.txt +2 -0
  6. braindecode/__init__.py +4 -0
  7. braindecode/classifier.py +258 -0
  8. braindecode/datasets/__init__.py +7 -0
  9. braindecode/datasets/base.py +293 -0
  10. braindecode/datasets/bbci.py +679 -0
  11. braindecode/datasets/moabb.py +110 -0
  12. braindecode/datasets/sleep_physionet.py +103 -0
  13. braindecode/datasets/tuh.py +230 -0
  14. braindecode/datautil/__init__.py +11 -0
  15. braindecode/datautil/mne.py +136 -0
  16. braindecode/datautil/preprocess.py +364 -0
  17. braindecode/datautil/serialization.py +111 -0
  18. braindecode/datautil/util.py +36 -0
  19. braindecode/datautil/windowers.py +435 -0
  20. braindecode/datautil/xy.py +77 -0
  21. braindecode/models/__init__.py +12 -0
  22. braindecode/models/deep4.py +252 -0
  23. braindecode/models/eegnet.py +339 -0
  24. braindecode/models/eegresnet.py +232 -0
  25. braindecode/models/functions.py +43 -0
  26. braindecode/models/hybrid.py +103 -0
  27. braindecode/models/modules.py +150 -0
  28. braindecode/models/shallow_fbcsp.py +158 -0
  29. braindecode/models/sleep_stager_chambon_2018.py +113 -0
  30. braindecode/models/tcn.py +143 -0
  31. braindecode/models/util.py +66 -0
  32. braindecode/regressor.py +240 -0
  33. braindecode/samplers/__init__.py +5 -0
  34. braindecode/samplers/base.py +78 -0
  35. braindecode/samplers/ssl.py +118 -0
  36. braindecode/training/__init__.py +8 -0
  37. braindecode/training/callbacks.py +21 -0
  38. braindecode/training/losses.py +17 -0
  39. braindecode/training/scoring.py +296 -0
  40. braindecode/util.py +362 -0
  41. braindecode/version.py +1 -0
  42. braindecode/visualization/__init__.py +5 -0
  43. braindecode/visualization/gradients.py +53 -0
  44. test/__init__.py +0 -0
  45. test/acceptance_tests/__init__.py +0 -0
  46. test/acceptance_tests/test_cropped_decoding.py +171 -0
  47. test/acceptance_tests/test_eeg_classifier.py +255 -0
  48. test/acceptance_tests/test_model_architectures.py +54 -0
  49. test/acceptance_tests/test_trialwise_decoding.py +168 -0
  50. test/unit_tests/__init__.py +0 -0
  51. test/unit_tests/datasets/__init__.py +0 -0
  52. test/unit_tests/datasets/test_dataset.py +227 -0
  53. test/unit_tests/datasets/test_mne.py +145 -0
  54. test/unit_tests/datasets/test_sleep_physionet.py +23 -0
  55. test/unit_tests/datasets/test_tuh.py +97 -0
  56. test/unit_tests/datasets/test_xy.py +31 -0
  57. test/unit_tests/datautil/__init__.py +0 -0
  58. test/unit_tests/datautil/test_preprocess.py +270 -0
  59. test/unit_tests/datautil/test_serialization.py +127 -0
  60. test/unit_tests/datautil/test_windowers.py +519 -0
  61. test/unit_tests/models/__init__.py +0 -0
  62. test/unit_tests/models/test_models.py +136 -0
  63. test/unit_tests/models/test_util.py +22 -0
  64. test/unit_tests/test_eeg_classifier.py +73 -0
  65. test/unit_tests/test_eeg_regressor.py +72 -0
  66. test/unit_tests/test_scoring.py +282 -0
  67. test/unit_tests/test_util.py +30 -0
  68. test/unit_tests/visualization/__init__.py +0 -0
  69. test/unit_tests/visualization/test_gradients.py +38 -0
@@ -0,0 +1,270 @@
1
+ # Authors: Hubert Banville <hubert.jbanville@gmail.com>
2
+ # Lukas Gemein <l.gemein@gmail.com>
3
+ #
4
+ # License: BSD-3
5
+
6
+ import copy
7
+
8
+ import pytest
9
+ import numpy as np
10
+
11
+ from braindecode.datasets import MOABBDataset
12
+ from braindecode.datautil.preprocess import preprocess, zscore, scale, \
13
+ Preprocessor, filterbank, exponential_moving_demean, \
14
+ exponential_moving_standardize, MNEPreproc, NumpyPreproc
15
+ from braindecode.datautil.windowers import create_fixed_length_windows
16
+
17
+
18
+ # We can't use fixtures with scope='module' as the dataset objects are modified
19
+ # inplace during preprocessing. To avoid the long setup time caused by calling
20
+ # the dataset/windowing functions multiple times, we instantiate the dataset
21
+ # objects once and deep-copy them in fixture.
22
+ raw_ds = MOABBDataset(dataset_name='BNCI2014001', subject_ids=[1, 2])
23
+ windows_ds = create_fixed_length_windows(
24
+ raw_ds, start_offset_samples=100, stop_offset_samples=None,
25
+ window_size_samples=1000, window_stride_samples=1000,
26
+ drop_last_window=True, mapping=None, preload=True)
27
+
28
+
29
+ @pytest.fixture
30
+ def base_concat_ds():
31
+ return copy.deepcopy(raw_ds)
32
+
33
+
34
+ @pytest.fixture
35
+ def windows_concat_ds():
36
+ return copy.deepcopy(windows_ds)
37
+
38
+
39
+ def modify_windows_object(epochs, factor=1):
40
+ epochs._data *= factor
41
+
42
+
43
+ def test_not_list():
44
+ with pytest.raises(AssertionError):
45
+ preprocess(None, {'test': 1})
46
+
47
+
48
+ def test_no_raw_or_epochs():
49
+ class EmptyDataset(object):
50
+ def __init__(self):
51
+ self.datasets = [1, 2, 3]
52
+
53
+ ds = EmptyDataset()
54
+ with pytest.raises(AssertionError):
55
+ preprocess(ds, ["dummy", "dummy"])
56
+
57
+
58
+ def test_deprecated_preprocs(base_concat_ds):
59
+ msg1 = 'MNEPreproc is deprecated. Use Preprocessor with ' \
60
+ '`apply_on_array=False` instead.'
61
+ msg2 = 'NumpyPreproc is deprecated. Use Preprocessor with ' \
62
+ '`apply_on_array=True` instead.'
63
+ with pytest.warns(UserWarning, match=msg1):
64
+ mne_preproc = MNEPreproc('pick_types', eeg=True, meg=False, stim=False)
65
+ factor = 1e6
66
+ with pytest.warns(UserWarning, match=msg2):
67
+ np_preproc = NumpyPreproc(scale, factor=factor)
68
+
69
+ raw_timepoint = base_concat_ds[0][0][:22] # only keep EEG channels
70
+ preprocess(base_concat_ds, [mne_preproc, np_preproc])
71
+ np.testing.assert_allclose(base_concat_ds[0][0], raw_timepoint * factor,
72
+ rtol=1e-4, atol=1e-4)
73
+
74
+
75
+ def test_method_not_available(base_concat_ds):
76
+ preprocessors = [Preprocessor('this_method_is_not_real', )]
77
+ with pytest.raises(AttributeError):
78
+ preprocess(base_concat_ds, preprocessors)
79
+
80
+
81
+ def test_preprocess_raw_str(base_concat_ds):
82
+ preprocessors = [Preprocessor('crop', tmax=10, include_tmax=False)]
83
+ preprocess(base_concat_ds, preprocessors)
84
+ assert len(base_concat_ds.datasets[0].raw.times) == 2500
85
+
86
+
87
+ def test_preprocess_windows_str(windows_concat_ds):
88
+ preprocessors = [
89
+ Preprocessor('crop', tmin=0, tmax=0.1, include_tmax=False)]
90
+ preprocess(windows_concat_ds, preprocessors)
91
+ assert windows_concat_ds[0][0].shape[1] == 25
92
+
93
+
94
+ def test_preprocess_raw_callable_on_array(base_concat_ds):
95
+ # Case tested in test_zscore_continuous
96
+ pass
97
+
98
+
99
+ def test_preprocess_windows_callable_on_array(windows_concat_ds):
100
+ # Case tested in test_zscore_windows
101
+ pass
102
+
103
+
104
+ def test_preprocess_raw_callable_on_object(base_concat_ds):
105
+ # Case tested in test_filterbank
106
+ pass
107
+
108
+
109
+ def test_preprocess_windows_callable_on_object(windows_concat_ds):
110
+ factor = 10
111
+ preprocessors = [Preprocessor(modify_windows_object, apply_on_array=False,
112
+ factor=factor)]
113
+ raw_window = windows_concat_ds[0][0]
114
+ preprocess(windows_concat_ds, preprocessors)
115
+ np.testing.assert_allclose(windows_concat_ds[0][0], raw_window * factor,
116
+ rtol=1e-4, atol=1e-4)
117
+
118
+
119
+ def test_zscore_continuous(base_concat_ds):
120
+ preprocessors = [
121
+ Preprocessor('pick_types', eeg=True, meg=False, stim=False),
122
+ Preprocessor(zscore, channel_wise=True)
123
+ ]
124
+ preprocess(base_concat_ds, preprocessors)
125
+ for ds in base_concat_ds.datasets:
126
+ raw_data = ds.raw.get_data()
127
+ shape = raw_data.shape
128
+ # zero mean
129
+ expected = np.zeros(shape[:-1])
130
+ np.testing.assert_allclose(
131
+ raw_data.mean(axis=-1), expected, rtol=1e-4, atol=1e-4)
132
+ # unit variance
133
+ expected = np.ones(shape[:-1])
134
+ np.testing.assert_allclose(
135
+ raw_data.std(axis=-1), expected, rtol=1e-4, atol=1e-4)
136
+
137
+
138
+ def test_zscore_windows(windows_concat_ds):
139
+ preprocessors = [
140
+ Preprocessor('pick_types', eeg=True, meg=False, stim=False),
141
+ Preprocessor(zscore)
142
+ ]
143
+ preprocess(windows_concat_ds, preprocessors)
144
+ for ds in windows_concat_ds.datasets:
145
+ windowed_data = ds.windows.get_data()
146
+ shape = windowed_data.shape
147
+ # zero mean
148
+ expected = np.zeros(shape[:-1])
149
+ np.testing.assert_allclose(
150
+ windowed_data.mean(axis=-1), expected, rtol=1e-4, atol=1e-4)
151
+ # unit variance
152
+ expected = np.ones(shape[:-1])
153
+ np.testing.assert_allclose(
154
+ windowed_data.std(axis=-1), expected, rtol=1e-4, atol=1e-4)
155
+
156
+
157
+ def test_scale_continuous(base_concat_ds):
158
+ factor = 1e6
159
+ preprocessors = [
160
+ Preprocessor('pick_types', eeg=True, meg=False, stim=False),
161
+ Preprocessor(scale, factor=factor)
162
+ ]
163
+ raw_timepoint = base_concat_ds[0][0][:22] # only keep EEG channels
164
+ preprocess(base_concat_ds, preprocessors)
165
+ np.testing.assert_allclose(base_concat_ds[0][0], raw_timepoint * factor,
166
+ rtol=1e-4, atol=1e-4)
167
+
168
+
169
+ def test_scale_windows(windows_concat_ds):
170
+ factor = 1e6
171
+ preprocessors = [
172
+ Preprocessor('pick_types', eeg=True, meg=False, stim=False),
173
+ Preprocessor(scale, factor=factor)
174
+ ]
175
+ raw_window = windows_concat_ds[0][0][:22] # only keep EEG channels
176
+ preprocess(windows_concat_ds, preprocessors)
177
+ np.testing.assert_allclose(windows_concat_ds[0][0], raw_window * factor,
178
+ rtol=1e-4, atol=1e-4)
179
+
180
+
181
+ @pytest.fixture(scope='module')
182
+ def mock_data():
183
+ mock_input = np.random.RandomState(20200217).rand(2, 10).reshape(2, 10)
184
+ expected_standardized = np.array(
185
+ [[ 0. , -1.41385996, -1.67770482, 1.95328935, 0.61618697,
186
+ -0.55294099, -1.08890304, 1.04546089, -1.368485 , -1.08669994],
187
+ [ 0. , -1.41385996, -0.41117774, 1.65212819, -0.5392431 ,
188
+ -0.23009334, 0.15087203, -1.45238971, 1.88407553, -0.38583499]])
189
+ expected_demeaned = np.array(
190
+ [[ 0. , -0.02547392, -0.10004415, 0.47681459, 0.1399319 ,
191
+ -0.11764405, -0.23535964, 0.22749205, -0.3155749 , -0.25316515],
192
+ [ 0. , -0.29211105, -0.07138808, 0.44137798, -0.13274718,
193
+ -0.0519248 , 0.03156507, -0.33137195, 0.52134583, -0.1020266 ]])
194
+ return mock_input, expected_standardized, expected_demeaned
195
+
196
+
197
+ def test_exponential_running_standardize(mock_data):
198
+ mock_input, expected_data, _ = mock_data
199
+ standardized_data = exponential_moving_standardize(mock_input)
200
+ assert mock_input.shape == standardized_data.shape == expected_data.shape
201
+ np.testing.assert_allclose(
202
+ standardized_data, expected_data, rtol=1e-4, atol=1e-4)
203
+
204
+
205
+ def test_exponential_running_demean(mock_data):
206
+ mock_input, _, expected_data = mock_data
207
+ demeaned_data = exponential_moving_demean(mock_input)
208
+ assert mock_input.shape == demeaned_data.shape == expected_data.shape
209
+ np.testing.assert_allclose(
210
+ demeaned_data, expected_data, rtol=1e-4, atol=1e-4)
211
+
212
+
213
+ def test_exponential_running_init_block_size(mock_data):
214
+ mock_input, _, _ = mock_data
215
+ init_block_size = 3
216
+ standardized_data = exponential_moving_standardize(
217
+ mock_input, init_block_size=init_block_size)
218
+ # mean over time axis (1!) should give 0 per channel
219
+ np.testing.assert_allclose(
220
+ standardized_data[:, :init_block_size].mean(axis=1), 0,
221
+ rtol=1e-4, atol=1e-4)
222
+ np.testing.assert_allclose(
223
+ standardized_data[:, :init_block_size].std(axis=1), 1,
224
+ rtol=1e-4, atol=1e-4)
225
+
226
+ # mean over time axis (1!) should give 0 per channel
227
+ demeaned_data = exponential_moving_demean(
228
+ mock_input, init_block_size=init_block_size)
229
+ np.testing.assert_allclose(
230
+ demeaned_data[:, :init_block_size].mean(axis=1), 0, rtol=1e-4,
231
+ atol=1e-4)
232
+
233
+
234
+ def test_filterbank(base_concat_ds):
235
+ base_concat_ds = base_concat_ds.split([[0]])['0']
236
+ preprocessors = [
237
+ Preprocessor('pick_channels', ch_names=sorted(['C4', 'Cz']),
238
+ ordered=True),
239
+ Preprocessor(filterbank, frequency_bands=[(0, 4), (4, 8), (8, 13)],
240
+ drop_original_signals=False, apply_on_array=False)
241
+ ]
242
+ preprocess(base_concat_ds, preprocessors)
243
+ for x, y in base_concat_ds:
244
+ break
245
+ assert x.shape[0] == 8
246
+ freq_band_annots = [
247
+ ch.split('_')[-1]
248
+ for ch in base_concat_ds.datasets[0].raw.ch_names
249
+ if '_' in ch]
250
+ assert len(np.unique(freq_band_annots)) == 3
251
+ np.testing.assert_array_equal(base_concat_ds.datasets[0].raw.ch_names, [
252
+ 'C4', 'C4_0-4', 'C4_4-8', 'C4_8-13',
253
+ 'Cz', 'Cz_0-4', 'Cz_4-8', 'Cz_8-13',
254
+ ])
255
+
256
+
257
+ def test_filterbank_order_channels_by_freq(base_concat_ds):
258
+ base_concat_ds = base_concat_ds.split([[0]])['0']
259
+ preprocessors = [
260
+ Preprocessor(
261
+ 'pick_channels', ch_names=sorted(['C4', 'Cz']), ordered=True),
262
+ Preprocessor(
263
+ filterbank, frequency_bands=[(0, 4), (4, 8), (8, 13)],
264
+ drop_original_signals=False, order_by_frequency_band=True,
265
+ apply_on_array=False)]
266
+ preprocess(base_concat_ds, preprocessors)
267
+ np.testing.assert_array_equal(base_concat_ds.datasets[0].raw.ch_names, [
268
+ 'C4', 'Cz', 'C4_0-4', 'Cz_0-4',
269
+ 'C4_4-8', 'Cz_4-8', 'C4_8-13', 'Cz_8-13'
270
+ ])
@@ -0,0 +1,127 @@
1
+ # Authors: Lukas Gemein <l.gemein@gmail.com>
2
+ #
3
+ # License: BSD-3
4
+
5
+ import os
6
+
7
+ import pytest
8
+ import numpy as np
9
+ import pandas as pd
10
+
11
+ from braindecode.datasets.moabb import MOABBDataset
12
+ from braindecode.datautil.windowers import create_windows_from_events
13
+ from braindecode.datautil.serialization import (
14
+ save_concat_dataset, load_concat_dataset)
15
+
16
+
17
+ @pytest.fixture(scope="module")
18
+ def setup_concat_raw_dataset():
19
+ return MOABBDataset(dataset_name="BNCI2014001", subject_ids=[1])
20
+
21
+
22
+ @pytest.fixture(scope="module")
23
+ def setup_concat_windows_dataset(setup_concat_raw_dataset):
24
+ moabb_dataset = setup_concat_raw_dataset
25
+ return create_windows_from_events(
26
+ concat_ds=moabb_dataset,
27
+ trial_start_offset_samples=0,
28
+ trial_stop_offset_samples=0)
29
+
30
+
31
+ def test_save_concat_raw_dataset(setup_concat_raw_dataset, tmpdir):
32
+ concat_raw_dataset = setup_concat_raw_dataset
33
+ n_raw_datasets = len(concat_raw_dataset.datasets)
34
+ save_concat_dataset(path=tmpdir, concat_dataset=concat_raw_dataset,
35
+ overwrite=False)
36
+ assert os.path.exists(tmpdir.join(f"description.json"))
37
+ for raw_i in range(n_raw_datasets):
38
+ assert os.path.exists(tmpdir.join(f"{raw_i}-raw.fif"))
39
+ assert not os.path.exists(tmpdir.join(f"{n_raw_datasets}-raw.fif"))
40
+
41
+
42
+ def test_save_concat_windows_dataset(setup_concat_windows_dataset, tmpdir):
43
+ concat_windows_dataset = setup_concat_windows_dataset
44
+ n_windows_datasets = len(concat_windows_dataset.datasets)
45
+ save_concat_dataset(path=tmpdir, concat_dataset=concat_windows_dataset,
46
+ overwrite=False)
47
+ assert os.path.exists(tmpdir.join(f"description.json"))
48
+ for windows_i in range(n_windows_datasets):
49
+ assert os.path.exists(tmpdir.join(f"{windows_i}-epo.fif"))
50
+ assert not os.path.exists(tmpdir.join(f"{n_windows_datasets}-epo.fif"))
51
+
52
+
53
+ def test_load_concat_raw_dataset(setup_concat_raw_dataset, tmpdir):
54
+ concat_raw_dataset = setup_concat_raw_dataset
55
+ n_raw_datasets = len(concat_raw_dataset.datasets)
56
+ save_concat_dataset(path=tmpdir, concat_dataset=concat_raw_dataset,
57
+ overwrite=False)
58
+ loaded_concat_raw_dataset = load_concat_dataset(
59
+ path=tmpdir, preload=False)
60
+ assert len(concat_raw_dataset) == len(loaded_concat_raw_dataset)
61
+ assert (len(concat_raw_dataset.datasets) ==
62
+ len(loaded_concat_raw_dataset.datasets))
63
+ assert (len(concat_raw_dataset.description) ==
64
+ len(loaded_concat_raw_dataset.description))
65
+ for raw_i in range(n_raw_datasets):
66
+ actual_x, actual_y = concat_raw_dataset[raw_i]
67
+ x, y = loaded_concat_raw_dataset[raw_i]
68
+ np.testing.assert_allclose(x, actual_x, rtol=1e-4, atol=1e-5)
69
+ pd.testing.assert_frame_equal(
70
+ concat_raw_dataset.description, loaded_concat_raw_dataset.description)
71
+
72
+
73
+ def test_load_concat_windows_dataset(setup_concat_windows_dataset, tmpdir):
74
+ concat_windows_dataset = setup_concat_windows_dataset
75
+ n_windows_datasets = len(concat_windows_dataset.datasets)
76
+ save_concat_dataset(path=tmpdir, concat_dataset=concat_windows_dataset,
77
+ overwrite=False)
78
+ loaded_concat_windows_dataset = load_concat_dataset(
79
+ path=tmpdir, preload=False)
80
+ assert len(concat_windows_dataset) == len(loaded_concat_windows_dataset)
81
+ assert (len(concat_windows_dataset.datasets) ==
82
+ len(loaded_concat_windows_dataset.datasets))
83
+ assert (len(concat_windows_dataset.description) ==
84
+ len(loaded_concat_windows_dataset.description))
85
+ for windows_i in range(n_windows_datasets):
86
+ actual_x, actual_y, actual_crop_inds = concat_windows_dataset[windows_i]
87
+ x, y, crop_inds = loaded_concat_windows_dataset[windows_i]
88
+ np.testing.assert_allclose(x, actual_x, rtol=1e-4, atol=1e-5)
89
+ np.testing.assert_allclose(y, actual_y, rtol=1e-4, atol=1e-5)
90
+ np.testing.assert_array_equal(crop_inds, actual_crop_inds)
91
+ pd.testing.assert_frame_equal(concat_windows_dataset.description,
92
+ loaded_concat_windows_dataset.description)
93
+
94
+
95
+ def test_load_multiple_concat_raw_dataset(setup_concat_raw_dataset, tmpdir):
96
+ concat_raw_dataset = setup_concat_raw_dataset
97
+ for i in range(2):
98
+ path = os.path.join(tmpdir, str(i))
99
+ os.makedirs(path)
100
+ save_concat_dataset(path=path,
101
+ concat_dataset=concat_raw_dataset,
102
+ overwrite=False)
103
+ loaded_concat_raw_datasets = load_concat_dataset(
104
+ path=tmpdir, preload=False)
105
+ assert 2*len(concat_raw_dataset) == len(loaded_concat_raw_datasets)
106
+ assert (2*len(concat_raw_dataset.datasets) ==
107
+ len(loaded_concat_raw_datasets.datasets))
108
+ assert (2*len(concat_raw_dataset.description) ==
109
+ len(loaded_concat_raw_datasets.description))
110
+
111
+
112
+ def test_load_multiple_concat_windows_dataset(setup_concat_windows_dataset,
113
+ tmpdir):
114
+ concat_windows_dataset = setup_concat_windows_dataset
115
+ for i in range(2):
116
+ path = os.path.join(tmpdir, str(i))
117
+ os.makedirs(path)
118
+ save_concat_dataset(path=path,
119
+ concat_dataset=concat_windows_dataset,
120
+ overwrite=False)
121
+ loaded_concat_windows_datasets = load_concat_dataset(
122
+ path=tmpdir, preload=False)
123
+ assert 2*len(concat_windows_dataset) == len(loaded_concat_windows_datasets)
124
+ assert (2*len(concat_windows_dataset.datasets) ==
125
+ len(loaded_concat_windows_datasets.datasets))
126
+ assert (2*len(concat_windows_dataset.description) ==
127
+ len(loaded_concat_windows_datasets.description))