braindecode 0.4.84__tar.gz → 0.4.85__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-0.4.84 → Braindecode-0.4.85}/Braindecode.egg-info/PKG-INFO +1 -1
- {Braindecode-0.4.84 → Braindecode-0.4.85}/PKG-INFO +1 -1
- {Braindecode-0.4.84 → Braindecode-0.4.85}/braindecode/datasets/bbci.py +89 -16
- Braindecode-0.4.85/braindecode/datasets/bcic_iv_2a.py +89 -0
- {Braindecode-0.4.84 → Braindecode-0.4.85}/braindecode/datasets/multiple.py +4 -1
- {Braindecode-0.4.84 → Braindecode-0.4.85}/braindecode/datautil/iterators.py +16 -5
- {Braindecode-0.4.84 → Braindecode-0.4.85}/braindecode/datautil/lazy_iterators.py +3 -1
- {Braindecode-0.4.84 → Braindecode-0.4.85}/braindecode/datautil/signalproc.py +29 -11
- {Braindecode-0.4.84 → Braindecode-0.4.85}/braindecode/datautil/splitters.py +8 -3
- {Braindecode-0.4.84 → Braindecode-0.4.85}/braindecode/datautil/trial_segment.py +37 -10
- {Braindecode-0.4.84 → Braindecode-0.4.85}/braindecode/experiments/experiment.py +32 -10
- {Braindecode-0.4.84 → Braindecode-0.4.85}/braindecode/experiments/monitors.py +53 -11
- {Braindecode-0.4.84 → Braindecode-0.4.85}/braindecode/mne_ext/signalproc.py +6 -2
- {Braindecode-0.4.84 → Braindecode-0.4.85}/braindecode/models/eegnet.py +45 -15
- {Braindecode-0.4.84 → Braindecode-0.4.85}/braindecode/models/hybrid.py +12 -4
- {Braindecode-0.4.84 → Braindecode-0.4.85}/braindecode/models/shallow_fbcsp.py +10 -3
- {Braindecode-0.4.84 → Braindecode-0.4.85}/braindecode/torch_ext/constraints.py +3 -1
- {Braindecode-0.4.84 → Braindecode-0.4.85}/braindecode/torch_ext/losses.py +3 -1
- {Braindecode-0.4.84 → Braindecode-0.4.85}/braindecode/torch_ext/modules.py +16 -3
- {Braindecode-0.4.84 → Braindecode-0.4.85}/braindecode/torch_ext/optimizers.py +6 -2
- {Braindecode-0.4.84 → Braindecode-0.4.85}/braindecode/torch_ext/schedulers.py +6 -2
- {Braindecode-0.4.84 → Braindecode-0.4.85}/braindecode/torch_ext/util.py +3 -1
- {Braindecode-0.4.84 → Braindecode-0.4.85}/braindecode/util.py +6 -2
- Braindecode-0.4.85/braindecode/version.py +1 -0
- {Braindecode-0.4.84 → Braindecode-0.4.85}/braindecode/visualization/input_windows.py +12 -4
- {Braindecode-0.4.84 → Braindecode-0.4.85}/braindecode/visualization/perturbation.py +8 -7
- {Braindecode-0.4.84 → Braindecode-0.4.85}/braindecode/visualization/plot.py +4 -1
- {Braindecode-0.4.84 → Braindecode-0.4.85}/braindecode/visualization/sinfit.py +3 -1
- Braindecode-0.4.84/braindecode/datasets/bcic_iv_2a.py +0 -75
- Braindecode-0.4.84/braindecode/version.py +0 -1
- {Braindecode-0.4.84 → Braindecode-0.4.85}/Braindecode.egg-info/SOURCES.txt +0 -0
- {Braindecode-0.4.84 → Braindecode-0.4.85}/Braindecode.egg-info/dependency_links.txt +0 -0
- {Braindecode-0.4.84 → Braindecode-0.4.85}/Braindecode.egg-info/not-zip-safe +0 -0
- {Braindecode-0.4.84 → Braindecode-0.4.85}/Braindecode.egg-info/requires.txt +0 -0
- {Braindecode-0.4.84 → Braindecode-0.4.85}/Braindecode.egg-info/top_level.txt +0 -0
- {Braindecode-0.4.84 → Braindecode-0.4.85}/LICENSE.txt +0 -0
- {Braindecode-0.4.84 → Braindecode-0.4.85}/MANIFEST.in +0 -0
- {Braindecode-0.4.84 → Braindecode-0.4.85}/README.rst +0 -0
- {Braindecode-0.4.84 → Braindecode-0.4.85}/braindecode/__init__.py +0 -0
- {Braindecode-0.4.84 → Braindecode-0.4.85}/braindecode/datasets/__init__.py +0 -0
- {Braindecode-0.4.84 → Braindecode-0.4.85}/braindecode/datasets/lazy_dataset.py +0 -0
- {Braindecode-0.4.84 → Braindecode-0.4.85}/braindecode/datasets/sensor_positions.py +0 -0
- {Braindecode-0.4.84 → Braindecode-0.4.85}/braindecode/datautil/__init__.py +0 -0
- {Braindecode-0.4.84 → Braindecode-0.4.85}/braindecode/datautil/signal_target.py +0 -0
- {Braindecode-0.4.84 → Braindecode-0.4.85}/braindecode/datautil/util.py +0 -0
- {Braindecode-0.4.84 → Braindecode-0.4.85}/braindecode/experiments/__init__.py +0 -0
- {Braindecode-0.4.84 → Braindecode-0.4.85}/braindecode/experiments/loggers.py +0 -0
- {Braindecode-0.4.84 → Braindecode-0.4.85}/braindecode/experiments/stopcriteria.py +0 -0
- {Braindecode-0.4.84 → Braindecode-0.4.85}/braindecode/mne_ext/__init__.py +0 -0
- {Braindecode-0.4.84 → Braindecode-0.4.85}/braindecode/models/__init__.py +0 -0
- {Braindecode-0.4.84 → Braindecode-0.4.85}/braindecode/models/base.py +0 -0
- {Braindecode-0.4.84 → Braindecode-0.4.85}/braindecode/models/deep4.py +0 -0
- {Braindecode-0.4.84 → Braindecode-0.4.85}/braindecode/models/util.py +0 -0
- {Braindecode-0.4.84 → Braindecode-0.4.85}/braindecode/torch_ext/__init__.py +0 -0
- {Braindecode-0.4.84 → Braindecode-0.4.85}/braindecode/torch_ext/functions.py +0 -0
- {Braindecode-0.4.84 → Braindecode-0.4.85}/braindecode/torch_ext/init.py +0 -0
- {Braindecode-0.4.84 → Braindecode-0.4.85}/braindecode/visualization/__init__.py +0 -0
- {Braindecode-0.4.84 → Braindecode-0.4.85}/docs/Makefile +0 -0
- {Braindecode-0.4.84 → Braindecode-0.4.85}/docs/conf.py +0 -0
- {Braindecode-0.4.84 → Braindecode-0.4.85}/docs/index.rst +0 -0
- {Braindecode-0.4.84 → Braindecode-0.4.85}/docs/notebooks/BBCI_Data.ipynb +0 -0
- {Braindecode-0.4.84 → Braindecode-0.4.85}/docs/notebooks/BBCI_Data_Start_Stop.ipynb +0 -0
- {Braindecode-0.4.84 → Braindecode-0.4.85}/docs/notebooks/BBCI_Data_Trialwise.ipynb +0 -0
- {Braindecode-0.4.84 → Braindecode-0.4.85}/docs/notebooks/Cropped_Decoding.ipynb +0 -0
- {Braindecode-0.4.84 → Braindecode-0.4.85}/docs/notebooks/Cropped_Manual_Training_Loop.ipynb +0 -0
- {Braindecode-0.4.84 → Braindecode-0.4.85}/docs/notebooks/Cropped_Trialwise_Explanation_Figures.ipynb +0 -0
- {Braindecode-0.4.84 → Braindecode-0.4.85}/docs/notebooks/Trialwise_Decoding.ipynb +0 -0
- {Braindecode-0.4.84 → Braindecode-0.4.85}/docs/notebooks/Trialwise_Manual_Training_Loop.ipynb +0 -0
- {Braindecode-0.4.84 → Braindecode-0.4.85}/docs/notebooks/visualization/Perturbation.ipynb +0 -0
- {Braindecode-0.4.84 → Braindecode-0.4.85}/docs/source/braindecode.datasets.rst +0 -0
- {Braindecode-0.4.84 → Braindecode-0.4.85}/docs/source/braindecode.datautil.rst +0 -0
- {Braindecode-0.4.84 → Braindecode-0.4.85}/docs/source/braindecode.experiments.rst +0 -0
- {Braindecode-0.4.84 → Braindecode-0.4.85}/docs/source/braindecode.mne_ext.rst +0 -0
- {Braindecode-0.4.84 → Braindecode-0.4.85}/docs/source/braindecode.models.rst +0 -0
- {Braindecode-0.4.84 → Braindecode-0.4.85}/docs/source/braindecode.rst +0 -0
- {Braindecode-0.4.84 → Braindecode-0.4.85}/docs/source/braindecode.torch_ext.rst +0 -0
- {Braindecode-0.4.84 → Braindecode-0.4.85}/docs/source/braindecode.visualization.rst +0 -0
- {Braindecode-0.4.84 → Braindecode-0.4.85}/docs/source/modules.rst +0 -0
- {Braindecode-0.4.84 → Braindecode-0.4.85}/setup.cfg +0 -0
- {Braindecode-0.4.84 → Braindecode-0.4.85}/setup.py +0 -0
|
@@ -28,7 +28,9 @@ class BBCIDataset(object):
|
|
|
28
28
|
Translational NeuroTechnology Lab, AG Ball, Freiburg, Germany.
|
|
29
29
|
"""
|
|
30
30
|
|
|
31
|
-
def __init__(
|
|
31
|
+
def __init__(
|
|
32
|
+
self, filename, load_sensor_names=None, check_class_names=False
|
|
33
|
+
):
|
|
32
34
|
self.__dict__.update(locals())
|
|
33
35
|
del self.self
|
|
34
36
|
|
|
@@ -43,7 +45,9 @@ class BBCIDataset(object):
|
|
|
43
45
|
with h5py.File(self.filename, "r") as h5file:
|
|
44
46
|
samples = int(h5file["nfo"]["T"][0, 0])
|
|
45
47
|
cnt_signal_shape = (samples, len(wanted_chan_inds))
|
|
46
|
-
continuous_signal =
|
|
48
|
+
continuous_signal = (
|
|
49
|
+
np.ones(cnt_signal_shape, dtype=np.float32) * np.nan
|
|
50
|
+
)
|
|
47
51
|
for chan_ind_arr, chan_ind_set in enumerate(wanted_chan_inds):
|
|
48
52
|
# + 1 because matlab/this hdf5-naming logic
|
|
49
53
|
# has 1-based indexing
|
|
@@ -54,7 +58,9 @@ class BBCIDataset(object):
|
|
|
54
58
|
:
|
|
55
59
|
].squeeze() # already load into memory
|
|
56
60
|
continuous_signal[:, chan_ind_arr] = chan_signal
|
|
57
|
-
assert not np.any(
|
|
61
|
+
assert not np.any(
|
|
62
|
+
np.isnan(continuous_signal)
|
|
63
|
+
), "No NaNs expected in signal"
|
|
58
64
|
|
|
59
65
|
if self.load_sensor_names is None:
|
|
60
66
|
ch_types = ["EEG"] * len(wanted_chan_inds)
|
|
@@ -77,7 +83,9 @@ class BBCIDataset(object):
|
|
|
77
83
|
eeg_sensor_names = filter(
|
|
78
84
|
lambda s: not s.startswith("BIP"), eeg_sensor_names
|
|
79
85
|
)
|
|
80
|
-
eeg_sensor_names = filter(
|
|
86
|
+
eeg_sensor_names = filter(
|
|
87
|
+
lambda s: not s.startswith("E"), eeg_sensor_names
|
|
88
|
+
)
|
|
81
89
|
eeg_sensor_names = filter(
|
|
82
90
|
lambda s: not s.startswith("Microphone"), eeg_sensor_names
|
|
83
91
|
)
|
|
@@ -95,7 +103,9 @@ class BBCIDataset(object):
|
|
|
95
103
|
or len(eeg_sensor_names) == 16
|
|
96
104
|
), "Recheck this code if you have different sensors..."
|
|
97
105
|
self.load_sensor_names = eeg_sensor_names
|
|
98
|
-
chan_inds = self._determine_chan_inds(
|
|
106
|
+
chan_inds = self._determine_chan_inds(
|
|
107
|
+
all_sensor_names, self.load_sensor_names
|
|
108
|
+
)
|
|
99
109
|
return chan_inds, self.load_sensor_names
|
|
100
110
|
|
|
101
111
|
def _determine_samplingrate(self):
|
|
@@ -109,8 +119,12 @@ class BBCIDataset(object):
|
|
|
109
119
|
def _determine_chan_inds(all_sensor_names, sensor_names):
|
|
110
120
|
assert sensor_names is not None
|
|
111
121
|
chan_inds = [all_sensor_names.index(s) for s in sensor_names]
|
|
112
|
-
assert len(chan_inds) == len(sensor_names),
|
|
113
|
-
|
|
122
|
+
assert len(chan_inds) == len(sensor_names), (
|
|
123
|
+
"All" "sensors should be there."
|
|
124
|
+
)
|
|
125
|
+
assert len(set(chan_inds)) == len(chan_inds), (
|
|
126
|
+
"No" "duplicated sensors wanted."
|
|
127
|
+
)
|
|
114
128
|
return chan_inds
|
|
115
129
|
|
|
116
130
|
@staticmethod
|
|
@@ -143,16 +157,21 @@ class BBCIDataset(object):
|
|
|
143
157
|
def _add_markers(self, cnt):
|
|
144
158
|
with h5py.File(self.filename, "r") as h5file:
|
|
145
159
|
event_times_in_ms = h5file["mrk"]["time"][:].squeeze()
|
|
146
|
-
event_classes =
|
|
160
|
+
event_classes = (
|
|
161
|
+
h5file["mrk"]["event"]["desc"][:].squeeze().astype(np.int64)
|
|
162
|
+
)
|
|
147
163
|
|
|
148
164
|
# Check whether class names known and correct order
|
|
149
165
|
class_name_set = h5file["nfo"]["className"][:].squeeze()
|
|
150
166
|
all_class_names = [
|
|
151
|
-
"".join(chr(c) for c in h5file[obj_ref])
|
|
167
|
+
"".join(chr(c) for c in h5file[obj_ref])
|
|
168
|
+
for obj_ref in class_name_set
|
|
152
169
|
]
|
|
153
170
|
|
|
154
171
|
if self.check_class_names:
|
|
155
|
-
_check_class_names(
|
|
172
|
+
_check_class_names(
|
|
173
|
+
all_class_names, event_times_in_ms, event_classes
|
|
174
|
+
)
|
|
156
175
|
|
|
157
176
|
event_times_in_samples = event_times_in_ms * cnt.info["sfreq"] / 1000.0
|
|
158
177
|
event_times_in_samples = np.uint32(np.round(event_times_in_samples))
|
|
@@ -166,7 +185,9 @@ class BBCIDataset(object):
|
|
|
166
185
|
log.warning(
|
|
167
186
|
"Same sample has at least two markers.\n"
|
|
168
187
|
"{:d}: ({:.0f} and {:.0f}).\n".format(
|
|
169
|
-
i_sample,
|
|
188
|
+
i_sample,
|
|
189
|
+
event_classes[i_event - 1],
|
|
190
|
+
event_classes[i_event],
|
|
170
191
|
)
|
|
171
192
|
+ "Marker codes will be summed."
|
|
172
193
|
)
|
|
@@ -434,7 +455,15 @@ def _check_class_names(all_class_names, event_times_in_ms, event_classes):
|
|
|
434
455
|
"__",
|
|
435
456
|
]:
|
|
436
457
|
pass
|
|
437
|
-
elif all_class_names == [
|
|
458
|
+
elif all_class_names == [
|
|
459
|
+
"0004",
|
|
460
|
+
"0056",
|
|
461
|
+
"0080",
|
|
462
|
+
"0088",
|
|
463
|
+
"0096",
|
|
464
|
+
"0120",
|
|
465
|
+
"__",
|
|
466
|
+
]:
|
|
438
467
|
pass
|
|
439
468
|
elif all_class_names == [
|
|
440
469
|
"0004",
|
|
@@ -494,7 +523,18 @@ def _check_class_names(all_class_names, event_times_in_ms, event_classes):
|
|
|
494
523
|
pass
|
|
495
524
|
elif all_class_names == ["0", "4", "16", "56", "88", "120"]:
|
|
496
525
|
pass
|
|
497
|
-
elif all_class_names == [
|
|
526
|
+
elif all_class_names == [
|
|
527
|
+
"0",
|
|
528
|
+
"4",
|
|
529
|
+
"32",
|
|
530
|
+
"48",
|
|
531
|
+
"56",
|
|
532
|
+
"64",
|
|
533
|
+
"80",
|
|
534
|
+
"88",
|
|
535
|
+
"95",
|
|
536
|
+
"120",
|
|
537
|
+
]:
|
|
498
538
|
pass
|
|
499
539
|
elif all_class_names == ["0", "4", "56", "80", "88", "96", "120"]:
|
|
500
540
|
pass
|
|
@@ -502,11 +542,44 @@ def _check_class_names(all_class_names, event_times_in_ms, event_classes):
|
|
|
502
542
|
pass
|
|
503
543
|
elif all_class_names == ["One", "Two", "Three", "Four"]:
|
|
504
544
|
pass
|
|
505
|
-
elif all_class_names == [
|
|
545
|
+
elif all_class_names == [
|
|
546
|
+
"1",
|
|
547
|
+
"10",
|
|
548
|
+
"11",
|
|
549
|
+
"12",
|
|
550
|
+
"2",
|
|
551
|
+
"20",
|
|
552
|
+
"3",
|
|
553
|
+
"30",
|
|
554
|
+
"4",
|
|
555
|
+
"40",
|
|
556
|
+
]:
|
|
506
557
|
pass
|
|
507
|
-
elif all_class_names == [
|
|
558
|
+
elif all_class_names == [
|
|
559
|
+
"1",
|
|
560
|
+
"10",
|
|
561
|
+
"12",
|
|
562
|
+
"13",
|
|
563
|
+
"2",
|
|
564
|
+
"20",
|
|
565
|
+
"3",
|
|
566
|
+
"30",
|
|
567
|
+
"4",
|
|
568
|
+
"40",
|
|
569
|
+
]:
|
|
508
570
|
pass
|
|
509
|
-
elif all_class_names == [
|
|
571
|
+
elif all_class_names == [
|
|
572
|
+
"1",
|
|
573
|
+
"10",
|
|
574
|
+
"13",
|
|
575
|
+
"2",
|
|
576
|
+
"20",
|
|
577
|
+
"3",
|
|
578
|
+
"30",
|
|
579
|
+
"4",
|
|
580
|
+
"40",
|
|
581
|
+
"99",
|
|
582
|
+
]:
|
|
510
583
|
pass
|
|
511
584
|
elif all_class_names == [
|
|
512
585
|
"1",
|
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
import numpy as np
|
|
2
|
+
import mne
|
|
3
|
+
from scipy.io import loadmat
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
class BCICompetition4Set2A(object):
|
|
7
|
+
def __init__(self, filename, load_sensor_names=None, labels_filename=None):
|
|
8
|
+
assert load_sensor_names is None
|
|
9
|
+
self.__dict__.update(locals())
|
|
10
|
+
del self.self
|
|
11
|
+
|
|
12
|
+
def load(self):
|
|
13
|
+
cnt = self.extract_data()
|
|
14
|
+
events, artifact_trial_mask = self.extract_events(cnt)
|
|
15
|
+
cnt.info["events"] = events
|
|
16
|
+
cnt.info["artifact_trial_mask"] = artifact_trial_mask
|
|
17
|
+
return cnt
|
|
18
|
+
|
|
19
|
+
def extract_data(self):
|
|
20
|
+
raw_gdf = mne.io.read_raw_gdf(self.filename, stim_channel="auto")
|
|
21
|
+
raw_gdf.load_data()
|
|
22
|
+
# correct nan values
|
|
23
|
+
|
|
24
|
+
data = raw_gdf.get_data()
|
|
25
|
+
|
|
26
|
+
for i_chan in range(data.shape[0]):
|
|
27
|
+
# first set to nan, than replace nans by nanmean.
|
|
28
|
+
this_chan = data[i_chan]
|
|
29
|
+
data[i_chan] = np.where(
|
|
30
|
+
this_chan == np.min(this_chan), np.nan, this_chan
|
|
31
|
+
)
|
|
32
|
+
mask = np.isnan(data[i_chan])
|
|
33
|
+
chan_mean = np.nanmean(data[i_chan])
|
|
34
|
+
data[i_chan, mask] = chan_mean
|
|
35
|
+
|
|
36
|
+
gdf_events = mne.events_from_annotations(raw_gdf)
|
|
37
|
+
raw_gdf = mne.io.RawArray(data, raw_gdf.info, verbose="WARNING")
|
|
38
|
+
# remember gdf events
|
|
39
|
+
raw_gdf.info["gdf_events"] = gdf_events
|
|
40
|
+
return raw_gdf
|
|
41
|
+
|
|
42
|
+
def extract_events(self, raw_gdf):
|
|
43
|
+
# all events
|
|
44
|
+
events, name_to_code = raw_gdf.info["gdf_events"]
|
|
45
|
+
|
|
46
|
+
if "class1, Left hand - cue onset (BCI experiment)" in name_to_code:
|
|
47
|
+
train_set = True
|
|
48
|
+
else:
|
|
49
|
+
train_set = False
|
|
50
|
+
assert (
|
|
51
|
+
"cue unknown/undefined (used for BCI competition) "
|
|
52
|
+
in name_to_code
|
|
53
|
+
)
|
|
54
|
+
|
|
55
|
+
if train_set:
|
|
56
|
+
trial_codes = [4, 5, 6, 7] # the 4 classes
|
|
57
|
+
else:
|
|
58
|
+
trial_codes = [4] # "unknown" class
|
|
59
|
+
|
|
60
|
+
trial_mask = [ev_code in trial_codes for ev_code in events[:, 2]]
|
|
61
|
+
trial_events = events[trial_mask]
|
|
62
|
+
assert len(trial_events) == 288, "Got {:d} markers".format(
|
|
63
|
+
len(trial_events)
|
|
64
|
+
)
|
|
65
|
+
trial_events[:, 2] = trial_events[:, 2] - 3
|
|
66
|
+
# possibly overwrite with markers from labels file
|
|
67
|
+
if self.labels_filename is not None:
|
|
68
|
+
classes = loadmat(self.labels_filename)["classlabel"].squeeze()
|
|
69
|
+
if train_set:
|
|
70
|
+
np.testing.assert_array_equal(trial_events[:, 2], classes)
|
|
71
|
+
trial_events[:, 2] = classes
|
|
72
|
+
unique_classes = np.unique(trial_events[:, 2])
|
|
73
|
+
assert np.array_equal(
|
|
74
|
+
[1, 2, 3, 4], unique_classes
|
|
75
|
+
), "Expect 1,2,3,4 as class labels, got {:s}".format(
|
|
76
|
+
str(unique_classes)
|
|
77
|
+
)
|
|
78
|
+
|
|
79
|
+
# now also create 0-1 vector for rejected trials
|
|
80
|
+
trial_start_events = events[events[:, 2] == 2]
|
|
81
|
+
assert len(trial_start_events) == len(trial_events)
|
|
82
|
+
artifact_trial_mask = np.zeros(len(trial_events), dtype=np.uint8)
|
|
83
|
+
artifact_events = events[events[:, 2] == 1]
|
|
84
|
+
|
|
85
|
+
for artifact_time in artifact_events[:, 0]:
|
|
86
|
+
i_trial = trial_start_events[:, 0].tolist().index(artifact_time)
|
|
87
|
+
artifact_trial_mask[i_trial] = 1
|
|
88
|
+
|
|
89
|
+
return trial_events, artifact_trial_mask
|
|
@@ -2,7 +2,9 @@ import numpy as np
|
|
|
2
2
|
from numpy.random import RandomState
|
|
3
3
|
|
|
4
4
|
|
|
5
|
-
def get_balanced_batches(
|
|
5
|
+
def get_balanced_batches(
|
|
6
|
+
n_trials, rng, shuffle, n_batches=None, batch_size=None
|
|
7
|
+
):
|
|
6
8
|
"""Create indices for batches balanced in size
|
|
7
9
|
(batches will have maximum size difference of 1).
|
|
8
10
|
Supply either batch size or number of batches. Resulting batches
|
|
@@ -124,7 +126,9 @@ class ClassBalancedBatchSizeIterator(object):
|
|
|
124
126
|
]
|
|
125
127
|
class_probabilities = np.array(class_probabilities)
|
|
126
128
|
# choose trials in inverse probability of class
|
|
127
|
-
trial_probabilities = [
|
|
129
|
+
trial_probabilities = [
|
|
130
|
+
1.0 / class_probabilities[y] for y in dataset.y
|
|
131
|
+
]
|
|
128
132
|
trial_probabilities = np.array(trial_probabilities) / np.sum(
|
|
129
133
|
trial_probabilities
|
|
130
134
|
)
|
|
@@ -134,7 +138,9 @@ class ClassBalancedBatchSizeIterator(object):
|
|
|
134
138
|
|
|
135
139
|
for batch_inds in batches:
|
|
136
140
|
if shuffle:
|
|
137
|
-
batch_inds = [
|
|
141
|
+
batch_inds = [
|
|
142
|
+
i_trial_to_balanced[i_trial] for i_trial in batch_inds
|
|
143
|
+
]
|
|
138
144
|
batch_X = dataset.X[batch_inds]
|
|
139
145
|
batch_y = dataset.y[batch_inds]
|
|
140
146
|
|
|
@@ -178,7 +184,11 @@ class CropsFromTrialsIterator(object):
|
|
|
178
184
|
"""
|
|
179
185
|
|
|
180
186
|
def __init__(
|
|
181
|
-
self,
|
|
187
|
+
self,
|
|
188
|
+
batch_size,
|
|
189
|
+
input_time_length,
|
|
190
|
+
n_preds_per_input,
|
|
191
|
+
seed=(2017, 6, 28),
|
|
182
192
|
):
|
|
183
193
|
self.batch_size = batch_size
|
|
184
194
|
self.input_time_length = input_time_length
|
|
@@ -283,7 +293,8 @@ def _compute_start_stop_block_inds(
|
|
|
283
293
|
# check that block is correct, all predicted samples together
|
|
284
294
|
# should be the trial samples
|
|
285
295
|
all_predicted_samples = [
|
|
286
|
-
range(stop - n_preds_per_input, stop)
|
|
296
|
+
range(stop - n_preds_per_input, stop)
|
|
297
|
+
for _, stop in start_stop_blocks
|
|
287
298
|
]
|
|
288
299
|
# this check takes about 50 ms in performance test
|
|
289
300
|
# whereas loop itself takes only 5 ms.. deactivate it if not necessary
|
|
@@ -92,7 +92,9 @@ class LazyCropsFromTrialsIterator(object):
|
|
|
92
92
|
collate_fn = partial(self.collate_fn, rng_state=random_state)
|
|
93
93
|
else:
|
|
94
94
|
collate_fn = partial(self.collate_fn, rng_state=None)
|
|
95
|
-
batch_indeces = self._get_batch_indeces(
|
|
95
|
+
batch_indeces = self._get_batch_indeces(
|
|
96
|
+
dataset=dataset, shuffle=shuffle
|
|
97
|
+
)
|
|
96
98
|
data_loader = DataLoader(
|
|
97
99
|
dataset=dataset,
|
|
98
100
|
batch_sampler=batch_indeces,
|
|
@@ -47,11 +47,15 @@ def exponential_running_standardize(
|
|
|
47
47
|
standardized = np.array(standardized)
|
|
48
48
|
if init_block_size is not None:
|
|
49
49
|
other_axis = tuple(range(1, len(data.shape)))
|
|
50
|
-
init_mean = np.mean(
|
|
51
|
-
|
|
52
|
-
init_block_standardized = (data[0:init_block_size] - init_mean) / np.maximum(
|
|
53
|
-
eps, init_std
|
|
50
|
+
init_mean = np.mean(
|
|
51
|
+
data[0:init_block_size], axis=other_axis, keepdims=True
|
|
54
52
|
)
|
|
53
|
+
init_std = np.std(
|
|
54
|
+
data[0:init_block_size], axis=other_axis, keepdims=True
|
|
55
|
+
)
|
|
56
|
+
init_block_standardized = (
|
|
57
|
+
data[0:init_block_size] - init_mean
|
|
58
|
+
) / np.maximum(eps, init_std)
|
|
55
59
|
standardized[0:init_block_size] = init_block_standardized
|
|
56
60
|
return standardized
|
|
57
61
|
|
|
@@ -85,7 +89,9 @@ def exponential_running_demean(data, factor_new=0.001, init_block_size=None):
|
|
|
85
89
|
demeaned = np.array(demeaned)
|
|
86
90
|
if init_block_size is not None:
|
|
87
91
|
other_axis = tuple(range(1, len(data.shape)))
|
|
88
|
-
init_mean = np.mean(
|
|
92
|
+
init_mean = np.mean(
|
|
93
|
+
data[0:init_block_size], axis=other_axis, keepdims=True
|
|
94
|
+
)
|
|
89
95
|
demeaned[0:init_block_size] = data[0:init_block_size] - init_mean
|
|
90
96
|
return demeaned
|
|
91
97
|
|
|
@@ -110,7 +116,9 @@ def highpass_cnt(data, low_cut_hz, fs, filt_order=3, axis=0):
|
|
|
110
116
|
if (low_cut_hz is None) or (low_cut_hz == 0):
|
|
111
117
|
log.info("Not doing any highpass, since low 0 or None")
|
|
112
118
|
return data.copy()
|
|
113
|
-
b, a = scipy.signal.butter(
|
|
119
|
+
b, a = scipy.signal.butter(
|
|
120
|
+
filt_order, low_cut_hz / (fs / 2.0), btype="highpass"
|
|
121
|
+
)
|
|
114
122
|
assert filter_is_stable(a)
|
|
115
123
|
data_highpassed = scipy.signal.lfilter(b, a, data, axis=axis)
|
|
116
124
|
return data_highpassed
|
|
@@ -134,9 +142,13 @@ def lowpass_cnt(data, high_cut_hz, fs, filt_order=3, axis=0):
|
|
|
134
142
|
Data after applying lowpass filter.
|
|
135
143
|
"""
|
|
136
144
|
if (high_cut_hz is None) or (high_cut_hz == fs / 2.0):
|
|
137
|
-
log.info(
|
|
145
|
+
log.info(
|
|
146
|
+
"Not doing any lowpass, since high cut hz is None or nyquist freq."
|
|
147
|
+
)
|
|
138
148
|
return data.copy()
|
|
139
|
-
b, a = scipy.signal.butter(
|
|
149
|
+
b, a = scipy.signal.butter(
|
|
150
|
+
filt_order, high_cut_hz / (fs / 2.0), btype="lowpass"
|
|
151
|
+
)
|
|
140
152
|
assert filter_is_stable(a)
|
|
141
153
|
data_lowpassed = scipy.signal.lfilter(b, a, data, axis=axis)
|
|
142
154
|
return data_lowpassed
|
|
@@ -174,10 +186,16 @@ def bandpass_cnt(
|
|
|
174
186
|
return data.copy()
|
|
175
187
|
if low_cut_hz == 0 or low_cut_hz == None:
|
|
176
188
|
log.info("Using lowpass filter since low cut hz is 0 or None")
|
|
177
|
-
return lowpass_cnt(
|
|
189
|
+
return lowpass_cnt(
|
|
190
|
+
data, high_cut_hz, fs, filt_order=filt_order, axis=axis
|
|
191
|
+
)
|
|
178
192
|
if high_cut_hz == None or high_cut_hz == (fs / 2.0):
|
|
179
|
-
log.info(
|
|
180
|
-
|
|
193
|
+
log.info(
|
|
194
|
+
"Using highpass filter since high cut hz is None or nyquist freq"
|
|
195
|
+
)
|
|
196
|
+
return highpass_cnt(
|
|
197
|
+
data, low_cut_hz, fs, filt_order=filt_order, axis=axis
|
|
198
|
+
)
|
|
181
199
|
|
|
182
200
|
nyq_freq = 0.5 * fs
|
|
183
201
|
low = low_cut_hz / nyq_freq
|
|
@@ -128,7 +128,9 @@ def split_into_train_valid_test(dataset, n_folds, i_test_fold, rng=None):
|
|
|
128
128
|
"""
|
|
129
129
|
n_trials = len(dataset.X)
|
|
130
130
|
if n_trials < n_folds:
|
|
131
|
-
raise ValueError(
|
|
131
|
+
raise ValueError(
|
|
132
|
+
"Less Trials: {:d} than folds: {:d}".format(n_trials, n_folds)
|
|
133
|
+
)
|
|
132
134
|
shuffle = rng is not None
|
|
133
135
|
folds = get_balanced_batches(n_trials, rng, shuffle, n_batches=n_folds)
|
|
134
136
|
test_inds = folds[i_test_fold]
|
|
@@ -139,7 +141,8 @@ def split_into_train_valid_test(dataset, n_folds, i_test_fold, rng=None):
|
|
|
139
141
|
assert np.intersect1d(train_inds, test_inds).size == 0
|
|
140
142
|
assert np.intersect1d(valid_inds, test_inds).size == 0
|
|
141
143
|
assert np.array_equal(
|
|
142
|
-
np.sort(np.union1d(train_inds, np.union1d(valid_inds, test_inds))),
|
|
144
|
+
np.sort(np.union1d(train_inds, np.union1d(valid_inds, test_inds))),
|
|
145
|
+
all_inds,
|
|
143
146
|
)
|
|
144
147
|
|
|
145
148
|
train_set = select_examples(dataset, train_inds)
|
|
@@ -170,7 +173,9 @@ def split_into_train_test(dataset, n_folds, i_test_fold, rng=None):
|
|
|
170
173
|
"""
|
|
171
174
|
n_trials = len(dataset.X)
|
|
172
175
|
if n_trials < n_folds:
|
|
173
|
-
raise ValueError(
|
|
176
|
+
raise ValueError(
|
|
177
|
+
"Less Trials: {:d} than folds: {:d}".format(n_trials, n_folds)
|
|
178
|
+
)
|
|
174
179
|
shuffle = rng is not None
|
|
175
180
|
folds = get_balanced_batches(n_trials, rng, shuffle, n_batches=n_folds)
|
|
176
181
|
test_inds = folds[i_test_fold]
|
|
@@ -161,7 +161,13 @@ def _to_mrk_code_to_name_and_y(name_to_codes):
|
|
|
161
161
|
|
|
162
162
|
|
|
163
163
|
def _create_signal_target_from_start_and_ival(
|
|
164
|
-
data,
|
|
164
|
+
data,
|
|
165
|
+
events,
|
|
166
|
+
fs,
|
|
167
|
+
name_to_codes,
|
|
168
|
+
epoch_ival_ms,
|
|
169
|
+
one_hot_labels,
|
|
170
|
+
one_label_per_trial,
|
|
165
171
|
):
|
|
166
172
|
cnt_y, i_start_stops = _create_cnt_y_and_trial_bounds_from_start_and_ival(
|
|
167
173
|
data.shape[1], events, fs, name_to_codes, epoch_ival_ms
|
|
@@ -253,7 +259,12 @@ def _create_signal_target_from_start_and_stop(
|
|
|
253
259
|
|
|
254
260
|
|
|
255
261
|
def _create_cnt_y_and_trial_bounds_from_start_stop(
|
|
256
|
-
n_samples,
|
|
262
|
+
n_samples,
|
|
263
|
+
events,
|
|
264
|
+
fs,
|
|
265
|
+
name_to_start_codes,
|
|
266
|
+
epoch_ival_ms,
|
|
267
|
+
name_to_stop_codes,
|
|
257
268
|
):
|
|
258
269
|
"""
|
|
259
270
|
Create a one-hot-encoded continuous marker array (cnt_y).
|
|
@@ -305,7 +316,9 @@ def _create_cnt_y_and_trial_bounds_from_start_stop(
|
|
|
305
316
|
codes = name_to_stop_codes[name]
|
|
306
317
|
if not hasattr(codes, "__len__"):
|
|
307
318
|
name_to_stop_codes[name] = [codes]
|
|
308
|
-
all_stop_codes = np.concatenate(list(name_to_stop_codes.values())).astype(
|
|
319
|
+
all_stop_codes = np.concatenate(list(name_to_stop_codes.values())).astype(
|
|
320
|
+
np.int64
|
|
321
|
+
)
|
|
309
322
|
class_to_n_trials = Counter()
|
|
310
323
|
n_classes = len(name_to_start_codes)
|
|
311
324
|
cnt_y = np.zeros((n_samples, n_classes), dtype=np.int64)
|
|
@@ -387,7 +400,9 @@ def _create_signal_target_from_cnt_y_start_stops(
|
|
|
387
400
|
if (i_stop - i_start) > prepad_trials_to_n_samples:
|
|
388
401
|
new_i_start_stops.append((i_start, i_stop))
|
|
389
402
|
elif i_stop >= prepad_trials_to_n_samples:
|
|
390
|
-
new_i_start_stops.append(
|
|
403
|
+
new_i_start_stops.append(
|
|
404
|
+
(i_stop - prepad_trials_to_n_samples, i_stop)
|
|
405
|
+
)
|
|
391
406
|
else:
|
|
392
407
|
log.warning(
|
|
393
408
|
"Could not pad trial enough, therefore not "
|
|
@@ -423,7 +438,9 @@ def _create_signal_target_from_cnt_y_start_stops(
|
|
|
423
438
|
new_y = []
|
|
424
439
|
for this_y in y:
|
|
425
440
|
# if destroying one hot later, just set most occuring class to 1
|
|
426
|
-
unique_labels, counts = np.unique(
|
|
441
|
+
unique_labels, counts = np.unique(
|
|
442
|
+
this_y, axis=0, return_counts=True
|
|
443
|
+
)
|
|
427
444
|
if not one_hot_labels:
|
|
428
445
|
meaned_y = np.mean(this_y, axis=0)
|
|
429
446
|
this_new_y = np.zeros_like(meaned_y)
|
|
@@ -620,10 +637,14 @@ def add_breaks(
|
|
|
620
637
|
Events with break start and stop markers.
|
|
621
638
|
"""
|
|
622
639
|
min_samples = (
|
|
623
|
-
None
|
|
640
|
+
None
|
|
641
|
+
if min_break_length_ms is None
|
|
642
|
+
else ms_to_samples(min_break_length_ms, fs)
|
|
624
643
|
)
|
|
625
644
|
max_samples = (
|
|
626
|
-
None
|
|
645
|
+
None
|
|
646
|
+
if max_break_length_ms is None
|
|
647
|
+
else ms_to_samples(max_break_length_ms, fs)
|
|
627
648
|
)
|
|
628
649
|
orig_events = events
|
|
629
650
|
break_starts, break_stops = _extract_break_start_stop_ms(
|
|
@@ -657,7 +678,9 @@ def add_breaks(
|
|
|
657
678
|
return new_events
|
|
658
679
|
|
|
659
680
|
|
|
660
|
-
def _extract_break_start_stop_ms(
|
|
681
|
+
def _extract_break_start_stop_ms(
|
|
682
|
+
events, name_to_start_codes, name_to_stop_codes
|
|
683
|
+
):
|
|
661
684
|
assert len(events[0]) == 2, "expect only 2dimensional event array here"
|
|
662
685
|
start_code_to_name_and_y = _to_mrk_code_to_name_and_y(name_to_start_codes)
|
|
663
686
|
# Ensure all stop marker codes are iterables
|
|
@@ -665,7 +688,9 @@ def _extract_break_start_stop_ms(events, name_to_start_codes, name_to_stop_codes
|
|
|
665
688
|
codes = name_to_stop_codes[name]
|
|
666
689
|
if not hasattr(codes, "__len__"):
|
|
667
690
|
name_to_stop_codes[name] = [codes]
|
|
668
|
-
all_stop_codes = np.concatenate(list(name_to_stop_codes.values())).astype(
|
|
691
|
+
all_stop_codes = np.concatenate(list(name_to_stop_codes.values())).astype(
|
|
692
|
+
np.int32
|
|
693
|
+
)
|
|
669
694
|
event_samples = events[:, 0]
|
|
670
695
|
event_codes = events[:, 1]
|
|
671
696
|
|
|
@@ -673,7 +698,9 @@ def _extract_break_start_stop_ms(events, name_to_start_codes, name_to_stop_codes
|
|
|
673
698
|
break_stops = []
|
|
674
699
|
i_event = 0
|
|
675
700
|
while i_event < len(events):
|
|
676
|
-
while (i_event < len(events)) and (
|
|
701
|
+
while (i_event < len(events)) and (
|
|
702
|
+
event_codes[i_event] not in all_stop_codes
|
|
703
|
+
):
|
|
677
704
|
i_event += 1
|
|
678
705
|
if i_event < len(events):
|
|
679
706
|
# one sample after start
|