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,227 @@
|
|
|
1
|
+
# Authors: Maciej Sliwowski <maciek.sliwowski@gmail.com>
|
|
2
|
+
# Lukas Gemein <l.gemein@gmail.com>
|
|
3
|
+
#
|
|
4
|
+
# License: BSD (3-clause)
|
|
5
|
+
|
|
6
|
+
import mne
|
|
7
|
+
import numpy as np
|
|
8
|
+
import pandas as pd
|
|
9
|
+
import pytest
|
|
10
|
+
|
|
11
|
+
from braindecode.datasets import WindowsDataset, BaseDataset, BaseConcatDataset
|
|
12
|
+
from braindecode.datasets.moabb import fetch_data_with_moabb
|
|
13
|
+
from braindecode.datautil.windowers import create_windows_from_events
|
|
14
|
+
|
|
15
|
+
# TODO: split file up into files with proper matching names
|
|
16
|
+
@pytest.fixture(scope="module")
|
|
17
|
+
# TODO: add test for transformers and case when subject_info is used
|
|
18
|
+
def set_up():
|
|
19
|
+
rng = np.random.RandomState(42)
|
|
20
|
+
info = mne.create_info(ch_names=['0', '1'], sfreq=50, ch_types='eeg')
|
|
21
|
+
raw = mne.io.RawArray(data=rng.randn(2, 1000), info=info)
|
|
22
|
+
desc = pd.Series({'pathological': True, 'gender': 'M', 'age': 48})
|
|
23
|
+
base_dataset = BaseDataset(raw, desc, target_name='age')
|
|
24
|
+
|
|
25
|
+
events = np.array([[100, 0, 1],
|
|
26
|
+
[200, 0, 2],
|
|
27
|
+
[300, 0, 1],
|
|
28
|
+
[400, 0, 4],
|
|
29
|
+
[500, 0, 3]])
|
|
30
|
+
window_idxs = [(0, 0, 100),
|
|
31
|
+
(0, 100, 200),
|
|
32
|
+
(1, 0, 100),
|
|
33
|
+
(2, 0, 100),
|
|
34
|
+
(2, 50, 150)]
|
|
35
|
+
i_window_in_trial, i_start_in_trial, i_stop_in_trial = list(
|
|
36
|
+
zip(*window_idxs))
|
|
37
|
+
metadata = pd.DataFrame(
|
|
38
|
+
{'sample': events[:, 0],
|
|
39
|
+
'x': events[:, 1],
|
|
40
|
+
'target': events[:, 2],
|
|
41
|
+
'i_window_in_trial': i_window_in_trial,
|
|
42
|
+
'i_start_in_trial': i_start_in_trial,
|
|
43
|
+
'i_stop_in_trial': i_stop_in_trial})
|
|
44
|
+
|
|
45
|
+
mne_epochs = mne.Epochs(raw=raw, events=events, metadata=metadata)
|
|
46
|
+
windows_dataset = WindowsDataset(mne_epochs, desc)
|
|
47
|
+
|
|
48
|
+
return raw, base_dataset, mne_epochs, windows_dataset, events, window_idxs
|
|
49
|
+
|
|
50
|
+
|
|
51
|
+
@pytest.fixture(scope="module")
|
|
52
|
+
def concat_ds_targets():
|
|
53
|
+
raws, description = fetch_data_with_moabb(
|
|
54
|
+
dataset_name="BNCI2014001", subject_ids=4)
|
|
55
|
+
events, _ = mne.events_from_annotations(raws[0])
|
|
56
|
+
targets = events[:, -1] - 1
|
|
57
|
+
ds = [BaseDataset(raws[i], description.iloc[i]) for i in range(3)]
|
|
58
|
+
concat_ds = BaseConcatDataset(ds)
|
|
59
|
+
return concat_ds, targets
|
|
60
|
+
|
|
61
|
+
|
|
62
|
+
@pytest.fixture(scope='module')
|
|
63
|
+
def concat_windows_dataset(concat_ds_targets):
|
|
64
|
+
concat_ds, targets = concat_ds_targets
|
|
65
|
+
windows_ds = create_windows_from_events(
|
|
66
|
+
concat_ds=concat_ds, trial_start_offset_samples=0,
|
|
67
|
+
trial_stop_offset_samples=0, window_size_samples=100,
|
|
68
|
+
window_stride_samples=100, drop_last_window=False)
|
|
69
|
+
|
|
70
|
+
return windows_ds
|
|
71
|
+
|
|
72
|
+
|
|
73
|
+
def test_get_item(set_up):
|
|
74
|
+
_, _, mne_epochs, windows_dataset, events, window_idxs = set_up
|
|
75
|
+
for i, epoch in enumerate(mne_epochs.get_data()):
|
|
76
|
+
x, y, inds = windows_dataset[i]
|
|
77
|
+
np.testing.assert_allclose(epoch, x)
|
|
78
|
+
assert events[i, 2] == y, f'Y not equal for epoch {i}'
|
|
79
|
+
np.testing.assert_array_equal(window_idxs[i], inds,
|
|
80
|
+
f'window inds not equal for epoch {i}')
|
|
81
|
+
|
|
82
|
+
|
|
83
|
+
def test_len_windows_dataset(set_up):
|
|
84
|
+
_, _, mne_epochs, windows_dataset, _, _ = set_up
|
|
85
|
+
assert len(mne_epochs.events) == len(windows_dataset)
|
|
86
|
+
|
|
87
|
+
|
|
88
|
+
def test_len_base_dataset(set_up):
|
|
89
|
+
raw, base_dataset, _, _, _, _ = set_up
|
|
90
|
+
assert len(raw) == len(base_dataset)
|
|
91
|
+
|
|
92
|
+
|
|
93
|
+
def test_len_concat_dataset(concat_ds_targets):
|
|
94
|
+
concat_ds = concat_ds_targets[0]
|
|
95
|
+
assert len(concat_ds) == sum([len(c) for c in concat_ds.datasets])
|
|
96
|
+
|
|
97
|
+
|
|
98
|
+
def test_target_in_subject_info(set_up):
|
|
99
|
+
raw, _, _, _, _, _ = set_up
|
|
100
|
+
desc = pd.Series({'pathological': True, 'gender': 'M', 'age': 48})
|
|
101
|
+
with pytest.raises(ValueError, match="'does_not_exist' not in description"):
|
|
102
|
+
BaseDataset(raw, desc, target_name='does_not_exist')
|
|
103
|
+
|
|
104
|
+
|
|
105
|
+
def test_description_concat_dataset(concat_ds_targets):
|
|
106
|
+
concat_ds = concat_ds_targets[0]
|
|
107
|
+
assert isinstance(concat_ds.description, pd.DataFrame)
|
|
108
|
+
assert concat_ds.description.shape[0] == len(concat_ds.datasets)
|
|
109
|
+
|
|
110
|
+
|
|
111
|
+
def test_split_concat_dataset(concat_ds_targets):
|
|
112
|
+
concat_ds = concat_ds_targets[0]
|
|
113
|
+
splits = concat_ds.split('run')
|
|
114
|
+
|
|
115
|
+
for k, v in splits.items():
|
|
116
|
+
assert k == v.description['run'].values
|
|
117
|
+
assert isinstance(v, BaseConcatDataset)
|
|
118
|
+
|
|
119
|
+
assert len(concat_ds) == sum([len(v) for v in splits.values()])
|
|
120
|
+
|
|
121
|
+
|
|
122
|
+
def test_concat_concat_dataset(concat_ds_targets):
|
|
123
|
+
concat_ds, targets = concat_ds_targets
|
|
124
|
+
concat_ds1 = BaseConcatDataset(concat_ds.datasets[:2])
|
|
125
|
+
concat_ds2 = BaseConcatDataset(concat_ds.datasets[2:])
|
|
126
|
+
list_of_concat_ds = [concat_ds1, concat_ds2]
|
|
127
|
+
descriptions = pd.concat([ds.description for ds in list_of_concat_ds])
|
|
128
|
+
descriptions.reset_index(inplace=True, drop=True)
|
|
129
|
+
lens = [0] + [len(ds) for ds in list_of_concat_ds]
|
|
130
|
+
cumsums = [ds.cumulative_sizes for ds in list_of_concat_ds]
|
|
131
|
+
cumsums = [l
|
|
132
|
+
for i, cumsum in enumerate(cumsums)
|
|
133
|
+
for l in np.array(cumsum) + lens[i]]
|
|
134
|
+
concat_concat_ds = BaseConcatDataset(list_of_concat_ds)
|
|
135
|
+
assert len(concat_concat_ds) == sum(lens)
|
|
136
|
+
assert len(concat_concat_ds) == concat_concat_ds.cumulative_sizes[-1]
|
|
137
|
+
assert len(concat_concat_ds.datasets) == len(descriptions)
|
|
138
|
+
assert len(concat_concat_ds.description) == len(descriptions)
|
|
139
|
+
np.testing.assert_array_equal(cumsums, concat_concat_ds.cumulative_sizes)
|
|
140
|
+
pd.testing.assert_frame_equal(descriptions, concat_concat_ds.description)
|
|
141
|
+
|
|
142
|
+
|
|
143
|
+
def test_split_dataset_failure(concat_ds_targets):
|
|
144
|
+
concat_ds = concat_ds_targets[0]
|
|
145
|
+
with pytest.raises(KeyError):
|
|
146
|
+
concat_ds.split("test")
|
|
147
|
+
|
|
148
|
+
with pytest.raises(IndexError):
|
|
149
|
+
concat_ds.split([])
|
|
150
|
+
|
|
151
|
+
with pytest.raises(
|
|
152
|
+
AssertionError, match="datasets should not be an empty iterable"):
|
|
153
|
+
concat_ds.split([[]])
|
|
154
|
+
|
|
155
|
+
with pytest.raises(TypeError):
|
|
156
|
+
concat_ds.split([[[]]])
|
|
157
|
+
|
|
158
|
+
with pytest.raises(IndexError):
|
|
159
|
+
concat_ds.split([len(concat_ds.description)])
|
|
160
|
+
|
|
161
|
+
|
|
162
|
+
def test_split_dataset(concat_ds_targets):
|
|
163
|
+
concat_ds = concat_ds_targets[0]
|
|
164
|
+
splits = concat_ds.split("run")
|
|
165
|
+
assert len(splits) == len(concat_ds.description["run"].unique())
|
|
166
|
+
|
|
167
|
+
splits = concat_ds.split([1])
|
|
168
|
+
assert len(splits) == 1
|
|
169
|
+
assert len(splits["0"].datasets) == 1
|
|
170
|
+
|
|
171
|
+
splits = concat_ds.split([[2]])
|
|
172
|
+
assert len(splits) == 1
|
|
173
|
+
assert len(splits["0"].datasets) == 1
|
|
174
|
+
|
|
175
|
+
original_ids = [1, 2]
|
|
176
|
+
splits = concat_ds.split([[0], original_ids])
|
|
177
|
+
assert len(splits) == 2
|
|
178
|
+
assert list(splits["0"].description.index) == [0]
|
|
179
|
+
assert len(splits["0"].datasets) == 1
|
|
180
|
+
# when creating new BaseConcatDataset, index is reset
|
|
181
|
+
split_ids = [0, 1]
|
|
182
|
+
assert list(splits["1"].description.index) == split_ids
|
|
183
|
+
assert len(splits["1"].datasets) == 2
|
|
184
|
+
|
|
185
|
+
for i, ds in enumerate(splits["1"].datasets):
|
|
186
|
+
np.testing.assert_array_equal(
|
|
187
|
+
ds.raw.get_data(), concat_ds.datasets[original_ids[i]].raw.get_data())
|
|
188
|
+
|
|
189
|
+
|
|
190
|
+
def test_metadata(concat_windows_dataset):
|
|
191
|
+
md = concat_windows_dataset.get_metadata()
|
|
192
|
+
assert isinstance(md, pd.DataFrame)
|
|
193
|
+
assert all([c in md.columns
|
|
194
|
+
for c in concat_windows_dataset.description.columns])
|
|
195
|
+
assert md.shape[0] == len(concat_windows_dataset)
|
|
196
|
+
|
|
197
|
+
|
|
198
|
+
def test_no_metadata(concat_ds_targets):
|
|
199
|
+
with pytest.raises(TypeError, match='Metadata dataframe can only be'):
|
|
200
|
+
concat_ds_targets[0].get_metadata()
|
|
201
|
+
|
|
202
|
+
|
|
203
|
+
def test_on_the_fly_transforms_base_dataset(concat_ds_targets):
|
|
204
|
+
concat_ds, targets = concat_ds_targets
|
|
205
|
+
original_X = concat_ds[0][0]
|
|
206
|
+
factor = 10
|
|
207
|
+
transform = lambda x: x * factor
|
|
208
|
+
concat_ds.transform = transform
|
|
209
|
+
transformed_X = concat_ds[0][0]
|
|
210
|
+
|
|
211
|
+
assert (factor * original_X == transformed_X).all()
|
|
212
|
+
|
|
213
|
+
with pytest.raises(ValueError):
|
|
214
|
+
concat_ds.transform = 0
|
|
215
|
+
|
|
216
|
+
|
|
217
|
+
def test_on_the_fly_transforms_windows_dataset(concat_windows_dataset):
|
|
218
|
+
original_X = concat_windows_dataset[0][0]
|
|
219
|
+
factor = 10
|
|
220
|
+
transform = lambda x: x * factor
|
|
221
|
+
concat_windows_dataset.transform = transform
|
|
222
|
+
transformed_X = concat_windows_dataset[0][0]
|
|
223
|
+
|
|
224
|
+
assert (factor * original_X == transformed_X).all()
|
|
225
|
+
|
|
226
|
+
with pytest.raises(ValueError):
|
|
227
|
+
concat_windows_dataset.transform = 0
|
|
@@ -0,0 +1,145 @@
|
|
|
1
|
+
# Authors: Lukas Gemein <l.gemein@gmail.com>
|
|
2
|
+
#
|
|
3
|
+
# License: BSD-3
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
import numpy as np
|
|
7
|
+
import mne
|
|
8
|
+
|
|
9
|
+
from braindecode.datautil.mne import (
|
|
10
|
+
create_from_mne_raw, create_from_mne_epochs)
|
|
11
|
+
|
|
12
|
+
def test_create_from_single_raw():
|
|
13
|
+
n_channels = 50
|
|
14
|
+
n_times = 500
|
|
15
|
+
sfreq = 100
|
|
16
|
+
|
|
17
|
+
rng = np.random.RandomState(34834)
|
|
18
|
+
data = rng.rand(n_channels, n_times)
|
|
19
|
+
ch_names = [f'ch{i}' for i in range(n_channels)]
|
|
20
|
+
ch_types = ['eeg'] * n_channels
|
|
21
|
+
info = mne.create_info(ch_names=ch_names, sfreq=sfreq, ch_types=ch_types)
|
|
22
|
+
raw = mne.io.RawArray(data, info)
|
|
23
|
+
|
|
24
|
+
n_anns = 10
|
|
25
|
+
inds = np.linspace(0, n_times, n_anns, endpoint=False).astype(int)
|
|
26
|
+
onsets = raw.times[inds]
|
|
27
|
+
durations = np.ones(n_anns) * 0.2
|
|
28
|
+
descriptions = ['test_trial'] * len(durations)
|
|
29
|
+
anns = mne.Annotations(onsets, durations, descriptions)
|
|
30
|
+
raw = raw.set_annotations(anns)
|
|
31
|
+
|
|
32
|
+
windows = create_from_mne_raw([raw], 0, 0, 5, 2, False)
|
|
33
|
+
|
|
34
|
+
# windows per trial: 0-5,2-7,4-9,6-11,...,14-19,15-20
|
|
35
|
+
assert len(windows) == 9 * n_anns
|
|
36
|
+
for i_w, (x, y, (i_w_in_t, i_start, i_stop)) in enumerate(windows):
|
|
37
|
+
assert i_w_in_t == i_w % 9
|
|
38
|
+
i_t = i_w // 9
|
|
39
|
+
assert i_start == inds[i_t] + i_w_in_t * 2 - (i_w_in_t == 8)
|
|
40
|
+
assert i_stop == inds[i_t] + i_w_in_t * 2 - (i_w_in_t == 8) + 5
|
|
41
|
+
np.testing.assert_allclose(x, data[:, i_start:i_stop],
|
|
42
|
+
atol=1e-5, rtol=1e-5)
|
|
43
|
+
|
|
44
|
+
|
|
45
|
+
def test_create_from_two_raws_with_varying_trial_lengths():
|
|
46
|
+
n_channels = 50
|
|
47
|
+
n_times = 500
|
|
48
|
+
sfreq = 100
|
|
49
|
+
rng = np.random.RandomState(34834)
|
|
50
|
+
raws = []
|
|
51
|
+
datas = []
|
|
52
|
+
for i_raw in range(2):
|
|
53
|
+
data = rng.rand(n_channels, n_times)
|
|
54
|
+
ch_names = [f'ch{i}' for i in range(n_channels)]
|
|
55
|
+
ch_types = ['eeg'] * n_channels
|
|
56
|
+
info = mne.create_info(ch_names=ch_names, sfreq=sfreq, ch_types=ch_types)
|
|
57
|
+
raw = mne.io.RawArray(data, info)
|
|
58
|
+
|
|
59
|
+
n_anns = 10
|
|
60
|
+
inds = np.linspace(0, n_times, n_anns, endpoint=False).astype(int)
|
|
61
|
+
onsets = raw.times[inds]
|
|
62
|
+
if i_raw == 0:
|
|
63
|
+
trial_dur = 0.2 # in sec
|
|
64
|
+
else:
|
|
65
|
+
trial_dur = 0.1
|
|
66
|
+
durations = np.ones(n_anns) * trial_dur
|
|
67
|
+
descriptions = ['test_trial'] * len(durations)
|
|
68
|
+
anns = mne.Annotations(onsets, durations, descriptions)
|
|
69
|
+
raw = raw.set_annotations(anns)
|
|
70
|
+
raws.append(raw)
|
|
71
|
+
datas.append(data)
|
|
72
|
+
|
|
73
|
+
windows = create_from_mne_raw(raws, 0, 0, 5, 2, False)
|
|
74
|
+
|
|
75
|
+
# windows per trial: 0-5,2-7,4-9,6-11,...,14-19,15-20
|
|
76
|
+
# and then: 0-5,2-7,4-9,5-10
|
|
77
|
+
assert len(windows) == 9 * n_anns + 4 * n_anns
|
|
78
|
+
for i_w, (x, y, (i_w_in_t, i_start, i_stop)) in enumerate(windows):
|
|
79
|
+
if i_w < 9 * n_anns:
|
|
80
|
+
assert i_w_in_t == i_w % 9
|
|
81
|
+
i_t = i_w // 9
|
|
82
|
+
assert i_start == inds[i_t] + i_w_in_t * 2 - (i_w_in_t == 8)
|
|
83
|
+
assert i_stop == inds[i_t] + i_w_in_t * 2 - (i_w_in_t == 8) + 5
|
|
84
|
+
np.testing.assert_allclose(x, datas[0][:, i_start:i_stop],
|
|
85
|
+
atol=1e-5, rtol=1e-5)
|
|
86
|
+
else:
|
|
87
|
+
assert i_w_in_t == (i_w - n_anns * 9) % 4
|
|
88
|
+
i_t = ((i_w - n_anns * 9) // 4)
|
|
89
|
+
assert i_start == inds[i_t] + i_w_in_t * 2 - (i_w_in_t == 3)
|
|
90
|
+
assert i_stop == inds[i_t] + i_w_in_t * 2 - (i_w_in_t == 3) + 5
|
|
91
|
+
|
|
92
|
+
|
|
93
|
+
def test_create_from_mne_epochs():
|
|
94
|
+
n_channels = 50
|
|
95
|
+
n_times = 500
|
|
96
|
+
sfreq = 100
|
|
97
|
+
rng = np.random.RandomState(34834)
|
|
98
|
+
all_epochs = []
|
|
99
|
+
datas = []
|
|
100
|
+
for i_raw in range(2):
|
|
101
|
+
data = rng.rand(n_channels, n_times)
|
|
102
|
+
ch_names = [f'ch{i}' for i in range(n_channels)]
|
|
103
|
+
ch_types = ['eeg'] * n_channels
|
|
104
|
+
info = mne.create_info(ch_names=ch_names, sfreq=sfreq,
|
|
105
|
+
ch_types=ch_types)
|
|
106
|
+
raw = mne.io.RawArray(data, info)
|
|
107
|
+
|
|
108
|
+
n_anns = 10
|
|
109
|
+
inds = np.linspace(0, n_times, n_anns, endpoint=False).astype(int)
|
|
110
|
+
onsets = raw.times[inds]
|
|
111
|
+
if i_raw == 0:
|
|
112
|
+
trial_dur = 0.2 # in sec
|
|
113
|
+
else:
|
|
114
|
+
trial_dur = 0.1
|
|
115
|
+
durations = np.ones(n_anns) * trial_dur
|
|
116
|
+
descriptions = ['test_trial'] * len(durations)
|
|
117
|
+
anns = mne.Annotations(onsets, durations, descriptions)
|
|
118
|
+
raw = raw.set_annotations(anns)
|
|
119
|
+
events, event_id = mne.events_from_annotations(raw, )
|
|
120
|
+
epochs = mne.Epochs(raw, events, event_id=event_id, preload=True,
|
|
121
|
+
baseline=None,
|
|
122
|
+
tmin=0, tmax=trial_dur - 1e-2)
|
|
123
|
+
all_epochs.append(epochs)
|
|
124
|
+
datas.append(data)
|
|
125
|
+
|
|
126
|
+
windows = create_from_mne_epochs(all_epochs, window_size_samples=5,
|
|
127
|
+
window_stride_samples=2,
|
|
128
|
+
drop_last_window=False)
|
|
129
|
+
|
|
130
|
+
# windows per trial: 0-5,2-7,4-9,6-11,...,14-19,15-20
|
|
131
|
+
# and then: 0-5,2-7,4-9,5-10
|
|
132
|
+
assert len(windows) == 9 * n_anns + 4 * n_anns
|
|
133
|
+
for i_w, (x, y, (i_w_in_t, i_start, i_stop)) in enumerate(windows):
|
|
134
|
+
if i_w < 9 * n_anns:
|
|
135
|
+
assert i_w_in_t == i_w % 9
|
|
136
|
+
i_t = i_w // 9
|
|
137
|
+
assert i_start == inds[i_t] + i_w_in_t * 2 - (i_w_in_t == 8)
|
|
138
|
+
assert i_stop == inds[i_t] + i_w_in_t * 2 - (i_w_in_t == 8) + 5
|
|
139
|
+
np.testing.assert_allclose(x, datas[0][:, i_start:i_stop],
|
|
140
|
+
atol=1e-5, rtol=1e-5)
|
|
141
|
+
else:
|
|
142
|
+
assert i_w_in_t == (i_w - n_anns * 9) % 4
|
|
143
|
+
i_t = ((i_w - n_anns * 9) // 4)
|
|
144
|
+
assert i_start == inds[i_t] + i_w_in_t * 2 - (i_w_in_t == 3)
|
|
145
|
+
assert i_stop == inds[i_t] + i_w_in_t * 2 - (i_w_in_t == 3) + 5
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
from braindecode.datasets.sleep_physionet import SleepPhysionet
|
|
2
|
+
from braindecode.datasets.base import BaseConcatDataset
|
|
3
|
+
|
|
4
|
+
|
|
5
|
+
def test_sleep_physionet():
|
|
6
|
+
sp = SleepPhysionet(
|
|
7
|
+
subject_ids=[0], recording_ids=[1], preload=True, load_eeg_only=True)
|
|
8
|
+
assert isinstance(sp, BaseConcatDataset)
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
def test_all_signals():
|
|
12
|
+
sp = SleepPhysionet(
|
|
13
|
+
subject_ids=[0], recording_ids=[1], preload=True, load_eeg_only=False)
|
|
14
|
+
assert len(sp.datasets[0].raw.ch_names) == 7
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
def test_crop_wake():
|
|
18
|
+
sp = SleepPhysionet(
|
|
19
|
+
subject_ids=[0], recording_ids=[1], preload=True, load_eeg_only=True,
|
|
20
|
+
crop_wake_mins=30)
|
|
21
|
+
sfreq = sp.datasets[0].raw.info['sfreq']
|
|
22
|
+
duration_h = len(sp) / (3600 * sfreq)
|
|
23
|
+
assert duration_h < 7 and duration_h > 6
|
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
# Authors: Lukas Gemein <l.gemein@gmail.com>
|
|
2
|
+
#
|
|
3
|
+
# License: BSD-3
|
|
4
|
+
|
|
5
|
+
from braindecode.datasets.tuh import (
|
|
6
|
+
_parse_description_from_file_path, _create_chronological_description,
|
|
7
|
+
TUHAbnormal)
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
def test_parse_from_tuh_file_path():
|
|
11
|
+
file_path = ("v2.0.0/edf/01_tcp_ar/000/00000021/"
|
|
12
|
+
"s004_2013_08_15/00000021_s004_t000.edf")
|
|
13
|
+
description = _parse_description_from_file_path(file_path)
|
|
14
|
+
assert len(description) == 9
|
|
15
|
+
assert description['path'] == file_path
|
|
16
|
+
assert description['year'] == 2013
|
|
17
|
+
assert description['month'] == 8
|
|
18
|
+
assert description['day'] == 15
|
|
19
|
+
assert description['subject'] == 21
|
|
20
|
+
assert description['session'] == 4
|
|
21
|
+
assert description['segment'] == 0
|
|
22
|
+
assert description['reference'] == 'ar'
|
|
23
|
+
assert description['version'] == 'v2.0.0'
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
def test_parse_from_tuh_abnormal_file_path():
|
|
27
|
+
file_path = ("v2.0.0/edf/eval/abnormal/01_tcp_ar/107/00010782/"
|
|
28
|
+
"s002_2013_10_05/00010782_s002_t001.edf")
|
|
29
|
+
additional_description = (
|
|
30
|
+
TUHAbnormal._parse_additional_description_from_file_path(file_path))
|
|
31
|
+
assert len(additional_description) == 2
|
|
32
|
+
assert additional_description['pathological']
|
|
33
|
+
assert not additional_description['train']
|
|
34
|
+
|
|
35
|
+
file_path = ("v2.0.0/edf/train/normal/01_tcp_ar/107/00010782/"
|
|
36
|
+
"s002_2013_10_05/00010782_s002_t001.edf")
|
|
37
|
+
additional_description = (
|
|
38
|
+
TUHAbnormal._parse_additional_description_from_file_path(file_path))
|
|
39
|
+
assert len(additional_description) == 2
|
|
40
|
+
assert not additional_description['pathological']
|
|
41
|
+
assert additional_description['train']
|
|
42
|
+
|
|
43
|
+
|
|
44
|
+
def test_sort_chronologically():
|
|
45
|
+
file_paths = [
|
|
46
|
+
"v2.0.0/edf/train/normal/01_tcp_ar/108/00010832/s001_2013_10_03/"
|
|
47
|
+
"00010831_s002_t001.edf",
|
|
48
|
+
"v2.0.0/edf/train/abnormal/01_tcp_ar/000/00000068/s009_2011_09_12/"
|
|
49
|
+
"00000068_s009_t000.edf",
|
|
50
|
+
"v2.0.0/edf/train/abnormal/01_tcp_ar/000/00000016/s004_2012_02_08/"
|
|
51
|
+
"00000016_s004_t000.edf",
|
|
52
|
+
"v2.0.0/edf/train/normal/01_tcp_ar/108/00010839/s001_2013_11_22/"
|
|
53
|
+
"00010839_s001_t000.edf",
|
|
54
|
+
"v2.0.0/edf/train/abnormal/01_tcp_ar/000/00000068/s008_2010_09_28/"
|
|
55
|
+
"00000068_s008_t001.edf",
|
|
56
|
+
"v2.0.0/edf/train/normal/01_tcp_ar/108/00010832/s001_2013_10_03/"
|
|
57
|
+
"00010831_s002_t000.edf",
|
|
58
|
+
"v2.0.0/edf/train/abnormal/01_tcp_ar/000/00000016/s005_2013_07_12/"
|
|
59
|
+
"00000016_s005_t001.edf",
|
|
60
|
+
"v2.0.0/edf/train/normal/01_tcp_ar/108/00010810/s001_2013_10_03/"
|
|
61
|
+
"00010810_s001_t000.edf",
|
|
62
|
+
"v2.0.0/edf/train/normal/01_tcp_ar/108/00010831/s001_2013_10_03/"
|
|
63
|
+
"00010831_s001_t000.edf",
|
|
64
|
+
"v2.0.0/edf/train/abnormal/01_tcp_ar/000/00000019/s002_2013_07_18/"
|
|
65
|
+
"00000019_s002_t001.edf",
|
|
66
|
+
"v2.0.0/edf/train/normal/01_tcp_ar/108/00010816/s001_2013_10_03/"
|
|
67
|
+
"00010816_s001_t001.edf",
|
|
68
|
+
]
|
|
69
|
+
description = _create_chronological_description(file_paths)
|
|
70
|
+
expected = [
|
|
71
|
+
"v2.0.0/edf/train/abnormal/01_tcp_ar/000/00000068/s008_2010_09_28/"
|
|
72
|
+
"00000068_s008_t001.edf",
|
|
73
|
+
"v2.0.0/edf/train/abnormal/01_tcp_ar/000/00000068/s009_2011_09_12/"
|
|
74
|
+
"00000068_s009_t000.edf",
|
|
75
|
+
"v2.0.0/edf/train/abnormal/01_tcp_ar/000/00000016/s004_2012_02_08/"
|
|
76
|
+
"00000016_s004_t000.edf",
|
|
77
|
+
"v2.0.0/edf/train/abnormal/01_tcp_ar/000/00000016/s005_2013_07_12/"
|
|
78
|
+
"00000016_s005_t001.edf",
|
|
79
|
+
"v2.0.0/edf/train/abnormal/01_tcp_ar/000/00000019/s002_2013_07_18/"
|
|
80
|
+
"00000019_s002_t001.edf",
|
|
81
|
+
|
|
82
|
+
"v2.0.0/edf/train/normal/01_tcp_ar/108/00010810/s001_2013_10_03/"
|
|
83
|
+
"00010810_s001_t000.edf",
|
|
84
|
+
"v2.0.0/edf/train/normal/01_tcp_ar/108/00010816/s001_2013_10_03/"
|
|
85
|
+
"00010816_s001_t001.edf",
|
|
86
|
+
"v2.0.0/edf/train/normal/01_tcp_ar/108/00010831/s001_2013_10_03/"
|
|
87
|
+
"00010831_s001_t000.edf",
|
|
88
|
+
"v2.0.0/edf/train/normal/01_tcp_ar/108/00010832/s001_2013_10_03/"
|
|
89
|
+
"00010831_s002_t000.edf",
|
|
90
|
+
"v2.0.0/edf/train/normal/01_tcp_ar/108/00010832/s001_2013_10_03/"
|
|
91
|
+
"00010831_s002_t001.edf",
|
|
92
|
+
|
|
93
|
+
"v2.0.0/edf/train/normal/01_tcp_ar/108/00010839/s001_2013_11_22/"
|
|
94
|
+
"00010839_s001_t000.edf",
|
|
95
|
+
]
|
|
96
|
+
for p1, p2 in zip(expected, description.T.path):
|
|
97
|
+
assert p1 == p2
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
# Authors: Lukas Gemein <l.gemein@gmail.com>
|
|
2
|
+
#
|
|
3
|
+
# License: BSD-3
|
|
4
|
+
|
|
5
|
+
import numpy as np
|
|
6
|
+
from braindecode.datautil.xy import create_from_X_y
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
def test_crops_data_loader_explicit():
|
|
10
|
+
|
|
11
|
+
X = np.arange(0, 15)
|
|
12
|
+
y = [0]
|
|
13
|
+
|
|
14
|
+
n_time_in = 10
|
|
15
|
+
n_time_out = 4
|
|
16
|
+
|
|
17
|
+
expected_crops = [np.arange(0, 10), np.arange(4, 14), np.arange(5, 15)]
|
|
18
|
+
|
|
19
|
+
dataset = create_from_X_y(
|
|
20
|
+
X[None, None], y,
|
|
21
|
+
window_size_samples=n_time_in,
|
|
22
|
+
window_stride_samples=n_time_out,
|
|
23
|
+
drop_last_window=False
|
|
24
|
+
)
|
|
25
|
+
|
|
26
|
+
Xs, ys, i_s = zip(*list(dataset))
|
|
27
|
+
|
|
28
|
+
assert len(Xs) == len(ys) == 3
|
|
29
|
+
|
|
30
|
+
for actual, expected, in zip(Xs, expected_crops):
|
|
31
|
+
np.testing.assert_array_equal(actual.squeeze(), expected)
|
|
File without changes
|