braindecode 0.1.0__tar.gz → 0.1.2__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.
Files changed (42) hide show
  1. {Braindecode-0.1.0 → Braindecode-0.1.2}/Braindecode.egg-info/PKG-INFO +16 -3
  2. Braindecode-0.1.2/Braindecode.egg-info/SOURCES.txt +39 -0
  3. Braindecode-0.1.2/Braindecode.egg-info/not-zip-safe +1 -0
  4. Braindecode-0.1.2/LICENSE.txt +31 -0
  5. Braindecode-0.1.2/MANIFEST.in +5 -0
  6. {Braindecode-0.1.0 → Braindecode-0.1.2}/PKG-INFO +16 -3
  7. Braindecode-0.1.2/README.md +17 -0
  8. Braindecode-0.1.2/braindecode/datasets/__init__.py +0 -0
  9. Braindecode-0.1.2/braindecode/datasets/signal_target.py +20 -0
  10. Braindecode-0.1.2/braindecode/experiments/__init__.py +0 -0
  11. Braindecode-0.1.2/braindecode/experiments/experiment.py +207 -0
  12. Braindecode-0.1.2/braindecode/experiments/monitors.py +142 -0
  13. Braindecode-0.1.2/braindecode/experiments/stopcriteria.py +53 -0
  14. Braindecode-0.1.2/braindecode/models/__init__.py +0 -0
  15. Braindecode-0.1.2/braindecode/models/shallow_fbcsp.py +90 -0
  16. Braindecode-0.1.2/braindecode/torchext/__init__.py +0 -0
  17. Braindecode-0.1.2/braindecode/torchext/constraints.py +13 -0
  18. Braindecode-0.1.2/braindecode/torchext/functions.py +9 -0
  19. Braindecode-0.1.2/braindecode/torchext/losses.py +11 -0
  20. Braindecode-0.1.2/braindecode/torchext/modules.py +20 -0
  21. Braindecode-0.1.2/braindecode/torchext/util.py +33 -0
  22. Braindecode-0.1.2/docs/Makefile +26 -0
  23. Braindecode-0.1.2/docs/conf.py +179 -0
  24. Braindecode-0.1.2/docs/index.rst +34 -0
  25. Braindecode-0.1.2/docs/notebooks/TrialWise_Decoding.ipynb +511 -0
  26. Braindecode-0.1.2/docs/source/braindecode.datasets.rst +22 -0
  27. Braindecode-0.1.2/docs/source/braindecode.experiments.rst +38 -0
  28. Braindecode-0.1.2/docs/source/braindecode.models.rst +22 -0
  29. Braindecode-0.1.2/docs/source/braindecode.rst +56 -0
  30. Braindecode-0.1.2/docs/source/braindecode.torchext.rst +54 -0
  31. Braindecode-0.1.2/docs/source/modules.rst +7 -0
  32. {Braindecode-0.1.0 → Braindecode-0.1.2}/setup.py +4 -4
  33. Braindecode-0.1.0/Braindecode.egg-info/SOURCES.txt +0 -11
  34. {Braindecode-0.1.0 → Braindecode-0.1.2}/Braindecode.egg-info/dependency_links.txt +0 -0
  35. {Braindecode-0.1.0 → Braindecode-0.1.2}/Braindecode.egg-info/requires.txt +0 -0
  36. {Braindecode-0.1.0 → Braindecode-0.1.2}/Braindecode.egg-info/top_level.txt +0 -0
  37. {Braindecode-0.1.0 → Braindecode-0.1.2}/braindecode/__init__.py +0 -0
  38. {Braindecode-0.1.0 → Braindecode-0.1.2}/braindecode/iterators.py +0 -0
  39. {Braindecode-0.1.0 → Braindecode-0.1.2}/braindecode/splitters.py +0 -0
  40. {Braindecode-0.1.0 → Braindecode-0.1.2}/braindecode/trial_segment.py +0 -0
  41. {Braindecode-0.1.0 → Braindecode-0.1.2}/braindecode/util.py +0 -0
  42. {Braindecode-0.1.0 → Braindecode-0.1.2}/setup.cfg +0 -0
@@ -1,16 +1,29 @@
1
1
  Metadata-Version: 1.1
2
2
  Name: Braindecode
3
- Version: 0.1.0
3
+ Version: 0.1.2
4
4
  Summary: A deep learning for raw time-domain EEG decoding toolbox.
5
5
  Home-page: https://github.com/robintibor/braindecode
6
6
  Author: Robin Tibor Schirrmeister
7
7
  Author-email: robintibor@gmail.com
8
8
  License: BSD 3-Clause
9
- Description: Note: The old braindecode repository has been moved to https://github.com/robintibor/braindevel.
9
+ Description: Note: The old braindecode repository has been moved to
10
+ https://github.com/robintibor/braindevel.
11
+
12
+ Braindecode
13
+ ===========
10
14
 
11
- # Braindecode
12
15
  A deep learning for raw time-domain EEG decoding toolbox.
13
16
 
17
+ Installation
18
+ ============
19
+
20
+ Install pytorch from http://pytorch.org/.
21
+
22
+ Documentation
23
+ =============
24
+
25
+ Documentation is online under http://braindecode.readthedocs.io/
26
+
14
27
  Keywords: eeg deep-learning brain-state-decoding
15
28
  Platform: UNKNOWN
16
29
  Classifier: Development Status :: 3 - Alpha
@@ -0,0 +1,39 @@
1
+ LICENSE.txt
2
+ MANIFEST.in
3
+ README.md
4
+ setup.py
5
+ Braindecode.egg-info/PKG-INFO
6
+ Braindecode.egg-info/SOURCES.txt
7
+ Braindecode.egg-info/dependency_links.txt
8
+ Braindecode.egg-info/not-zip-safe
9
+ Braindecode.egg-info/requires.txt
10
+ Braindecode.egg-info/top_level.txt
11
+ braindecode/__init__.py
12
+ braindecode/iterators.py
13
+ braindecode/splitters.py
14
+ braindecode/trial_segment.py
15
+ braindecode/util.py
16
+ braindecode/datasets/__init__.py
17
+ braindecode/datasets/signal_target.py
18
+ braindecode/experiments/__init__.py
19
+ braindecode/experiments/experiment.py
20
+ braindecode/experiments/monitors.py
21
+ braindecode/experiments/stopcriteria.py
22
+ braindecode/models/__init__.py
23
+ braindecode/models/shallow_fbcsp.py
24
+ braindecode/torchext/__init__.py
25
+ braindecode/torchext/constraints.py
26
+ braindecode/torchext/functions.py
27
+ braindecode/torchext/losses.py
28
+ braindecode/torchext/modules.py
29
+ braindecode/torchext/util.py
30
+ docs/Makefile
31
+ docs/conf.py
32
+ docs/index.rst
33
+ docs/notebooks/TrialWise_Decoding.ipynb
34
+ docs/source/braindecode.datasets.rst
35
+ docs/source/braindecode.experiments.rst
36
+ docs/source/braindecode.models.rst
37
+ docs/source/braindecode.rst
38
+ docs/source/braindecode.torchext.rst
39
+ docs/source/modules.rst
@@ -0,0 +1,31 @@
1
+ BSD 3-Clause License
2
+
3
+ Copyright (c) 2017 Robin Tibor Schirrmeister
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,5 @@
1
+ include README.md
2
+ include LICENSE.txt
3
+
4
+ recursive-include docs *.ipynb *.rst conf.py Makefile
5
+ recursive-exclude docs *checkpoint.ipynb
@@ -1,16 +1,29 @@
1
1
  Metadata-Version: 1.1
2
2
  Name: Braindecode
3
- Version: 0.1.0
3
+ Version: 0.1.2
4
4
  Summary: A deep learning for raw time-domain EEG decoding toolbox.
5
5
  Home-page: https://github.com/robintibor/braindecode
6
6
  Author: Robin Tibor Schirrmeister
7
7
  Author-email: robintibor@gmail.com
8
8
  License: BSD 3-Clause
9
- Description: Note: The old braindecode repository has been moved to https://github.com/robintibor/braindevel.
9
+ Description: Note: The old braindecode repository has been moved to
10
+ https://github.com/robintibor/braindevel.
11
+
12
+ Braindecode
13
+ ===========
10
14
 
11
- # Braindecode
12
15
  A deep learning for raw time-domain EEG decoding toolbox.
13
16
 
17
+ Installation
18
+ ============
19
+
20
+ Install pytorch from http://pytorch.org/.
21
+
22
+ Documentation
23
+ =============
24
+
25
+ Documentation is online under http://braindecode.readthedocs.io/
26
+
14
27
  Keywords: eeg deep-learning brain-state-decoding
15
28
  Platform: UNKNOWN
16
29
  Classifier: Development Status :: 3 - Alpha
@@ -0,0 +1,17 @@
1
+ Note: The old braindecode repository has been moved to
2
+ https://github.com/robintibor/braindevel.
3
+
4
+ Braindecode
5
+ ===========
6
+
7
+ A deep learning for raw time-domain EEG decoding toolbox.
8
+
9
+ Installation
10
+ ============
11
+
12
+ Install pytorch from http://pytorch.org/.
13
+
14
+ Documentation
15
+ =============
16
+
17
+ Documentation is online under http://braindecode.readthedocs.io/
File without changes
@@ -0,0 +1,20 @@
1
+ class SignalAndTarget(object):
2
+ def __init__(self, X, y):
3
+ assert len(X) == len(y)
4
+ self.X = X
5
+ self.y = y
6
+
7
+
8
+ def apply_to_X_y(fn, *sets):
9
+ X = fn(*[s.X for s in sets])
10
+ y = fn(*[s.y for s in sets])
11
+ return SignalAndTarget(X,y)
12
+
13
+
14
+ def split_into_two_sets(dataset, fraction=None, n_boundary=None):
15
+ assert fraction is not None or n_boundary is not None
16
+ if n_boundary is None:
17
+ n_boundary = int(round(len(dataset.X) * fraction))
18
+ first_set = apply_to_X_y(lambda a: a[:n_boundary], dataset)
19
+ second_set = apply_to_X_y(lambda a: a[n_boundary:], dataset)
20
+ return first_set, second_set
File without changes
@@ -0,0 +1,207 @@
1
+ from collections import OrderedDict
2
+ import logging
3
+ from copy import deepcopy
4
+ import pandas as pd
5
+ import numpy as np
6
+
7
+ from braindecode.splitters import concatenate_sets
8
+ from braindecode.experiments.stopcriteria import MaxEpochs, ColumnBelow, Or
9
+ from braindecode.torchext.util import np_to_var, set_random_seeds
10
+
11
+ log = logging.getLogger(__name__)
12
+
13
+
14
+ class RememberBest(object):
15
+ def __init__(self, column_name):
16
+ self.column_name = column_name
17
+ self.best_epoch = 0
18
+ self.lowest_val = float('inf')
19
+ self.model_state_dict = None
20
+ self.optimizer_state_dict = None
21
+
22
+ def remember_epoch(self, epochs_df, model, optimizer):
23
+ i_epoch = len(epochs_df) - 1
24
+ current_val = float(epochs_df[self.column_name].iloc[-1])
25
+ if current_val <= self.lowest_val:
26
+ self.best_epoch = i_epoch
27
+ self.lowest_val = current_val
28
+ self.model_state_dict = deepcopy(model.state_dict())
29
+ self.optimizer_state_dict = deepcopy(optimizer.state_dict())
30
+ log.info("New best {:s}: {:5f}".format(self.column_name,
31
+ current_val))
32
+ log.info("")
33
+
34
+ def reset_to_best_model(self, epochs_df, model, optimizer):
35
+ # Remove epochs past the best one from epochs dataframe
36
+ epochs_df.drop(range(self.best_epoch+1, len(epochs_df)), inplace=True)
37
+ model.load_state_dict(self.model_state_dict)
38
+ optimizer.load_state_dict(self.optimizer_state_dict)
39
+
40
+
41
+ class Experiment(object):
42
+ def __init__(self, model, train_set, valid_set, test_set,
43
+ iterator, loss_function, optimizer, model_constraint,
44
+ monitors, stop_criterion, remember_best_column,
45
+ run_after_early_stop,
46
+ batch_modifier=None, cuda=True):
47
+ self.model = model
48
+ self.datasets = OrderedDict(
49
+ (('train', train_set), ('valid', valid_set), ('test', test_set)))
50
+ self.iterator = iterator
51
+ self.loss_function = loss_function
52
+ self.optimizer = optimizer
53
+ self.model_constraint = model_constraint
54
+ self.monitors = monitors
55
+ self.stop_criterion = stop_criterion
56
+ self.remember_best_column = remember_best_column
57
+ self.run_after_early_stop = run_after_early_stop
58
+ self.batch_modifier = batch_modifier
59
+ self.cuda = cuda
60
+ self.epochs_df = pd.DataFrame()
61
+ self.before_stop_df = None
62
+ self.rememberer = None
63
+
64
+ def run(self):
65
+ self.setup_training()
66
+ log.info("Run until first stop...")
67
+ self.run_until_early_stop()
68
+ # always setup for second stop, in order to get best model
69
+ # even if not running after early stop...
70
+ log.info("Setup for second stop...")
71
+ self.setup_after_stop_training()
72
+ if self.run_after_early_stop:
73
+ log.info("Run until second stop...")
74
+ self.run_until_second_stop()
75
+
76
+ def setup_training(self):
77
+ # reset remember best extension in case you rerun some experiment
78
+ self.rememberer = RememberBest(self.remember_best_column)
79
+ self.epochs_df = pd.DataFrame()
80
+ set_random_seeds(seed=2382938, cuda=self.cuda)
81
+ if self.cuda:
82
+ self.model.cuda()
83
+
84
+ def run_until_early_stop(self):
85
+ self.run_until_stop(self.datasets, remember_best=True)
86
+
87
+ def run_until_second_stop(self):
88
+ datasets = self.datasets
89
+ datasets['train'] = concatenate_sets(datasets['train'],
90
+ datasets['valid'])
91
+
92
+ # Todo: actually keep remembering and in case of twice number of epochs
93
+ # reset to best model again (check if valid loss not below train loss)
94
+ self.run_until_stop(datasets, remember_best=False)
95
+
96
+ def run_until_stop(self, datasets, remember_best):
97
+ self.monitor_epoch(datasets)
98
+ self.print_epoch()
99
+ if remember_best:
100
+ self.rememberer.remember_epoch(self.epochs_df, self.model,
101
+ self.optimizer)
102
+
103
+ self.iterator.reset_rng()
104
+ while not self.stop_criterion.should_stop(self.epochs_df):
105
+ self.run_one_epoch(datasets, remember_best)
106
+
107
+ def run_one_epoch(self, datasets, remember_best):
108
+ batch_generator = self.iterator.get_batches(datasets['train'],
109
+ shuffle=True)
110
+ # TODO, add timing again?
111
+ for inputs, targets in batch_generator:
112
+ if self.batch_modifier is not None:
113
+ inputs, targets = self.batch_modifier.process(inputs,
114
+ targets)
115
+ # could happen that batch modifier has removed all inputs...
116
+ if len(inputs) > 0:
117
+ self.train_batch(inputs, targets)
118
+
119
+ self.monitor_epoch(datasets)
120
+ self.print_epoch()
121
+ if remember_best:
122
+ self.rememberer.remember_epoch(self.epochs_df, self.model,
123
+ self.optimizer)
124
+
125
+ def monitor_epoch(self, datasets):
126
+ result_dicts_per_monitor = OrderedDict()
127
+ for m in self.monitors:
128
+ result_dicts_per_monitor[m] = OrderedDict()
129
+ for m in self.monitors:
130
+ result_dict = m.monitor_epoch()
131
+ if result_dict is not None:
132
+ result_dicts_per_monitor[m].update(result_dict)
133
+ for setname in datasets:
134
+ assert setname in ['train', 'valid', 'test']
135
+ dataset = datasets[setname]
136
+ all_preds = []
137
+ all_losses = []
138
+ all_batch_sizes = []
139
+ all_targets = []
140
+ for batch in self.iterator.get_batches(dataset, shuffle=False):
141
+ preds, loss = self.eval_on_batch(batch[0], batch[1])
142
+ all_preds.append(preds)
143
+ all_losses.append(loss)
144
+ all_batch_sizes.append(len(batch[0]))
145
+ all_targets.append(batch[1])
146
+
147
+ for m in self.monitors:
148
+ result_dict = m.monitor_set(setname, all_preds, all_losses,
149
+ all_batch_sizes, all_targets,
150
+ dataset)
151
+ if result_dict is not None:
152
+ result_dicts_per_monitor[m].update(result_dict)
153
+ row_dict = OrderedDict()
154
+ for m in self.monitors:
155
+ row_dict.update(result_dicts_per_monitor[m])
156
+ self.epochs_df = self.epochs_df.append(row_dict, ignore_index=True)
157
+ assert set(self.epochs_df.columns) == set(row_dict.keys())
158
+ self.epochs_df = self.epochs_df[list(row_dict.keys())]
159
+
160
+ def print_epoch(self):
161
+ # -1 due to doing one monitor at start of training
162
+ i_epoch = len(self.epochs_df) - 1
163
+ log.info("Epoch {:d}".format(i_epoch))
164
+ last_row = self.epochs_df.iloc[-1]
165
+ for key, val in last_row.iteritems():
166
+ log.info("{:25s} {:.5f}".format(key, val))
167
+ log.info("")
168
+
169
+ def eval_on_batch(self, inputs, targets):
170
+ self.model.eval()
171
+ input_vars = np_to_var(inputs)
172
+ target_vars = np_to_var(targets)
173
+ if self.cuda:
174
+ input_vars = input_vars.cuda()
175
+ target_vars = target_vars.cuda()
176
+ outputs = self.model(input_vars)
177
+ loss = self.loss_function(outputs, target_vars)
178
+ outputs = outputs.cpu().data.numpy()
179
+ loss = loss.cpu().data.numpy()
180
+ return outputs, loss
181
+
182
+ def train_batch(self, inputs, targets):
183
+ self.model.train()
184
+ input_vars = np_to_var(inputs)
185
+ target_vars = np_to_var(targets)
186
+ if self.cuda:
187
+ input_vars = input_vars.cuda()
188
+ target_vars = target_vars.cuda()
189
+ self.optimizer.zero_grad()
190
+ outputs = self.model(input_vars)
191
+ loss = self.loss_function(outputs, target_vars)
192
+ loss.backward()
193
+ self.optimizer.step()
194
+ if self.model_constraint is not None:
195
+ self.model_constraint.apply(self.model)
196
+
197
+ def setup_after_stop_training(self):
198
+ # also remember old monitor chans, will be put back into
199
+ # monitor chans after experiment finished
200
+ self.before_stop_df = deepcopy(self.epochs_df)
201
+ self.rememberer.reset_to_best_model(self.epochs_df, self.model,
202
+ self.optimizer)
203
+ loss_to_reach = float(self.epochs_df['train_loss'].iloc[-1])
204
+ self.stop_criterion = Or(stop_criteria=[
205
+ MaxEpochs(max_epochs=self.rememberer.best_epoch * 2),
206
+ ColumnBelow(column_name='valid_loss', target_value=loss_to_reach)])
207
+ log.info("Train loss to reach {:.5f}".format(loss_to_reach))
@@ -0,0 +1,142 @@
1
+ import numpy as np
2
+ import time
3
+
4
+ from braindecode.trial_segment import compute_trial_start_stop_samples
5
+
6
+
7
+ class MisclassMonitor(object):
8
+ def __init__(self, exponentiate_preds=False, col_suffix='misclass'):
9
+ self.col_suffix = col_suffix
10
+ self.exponentiate_preds = exponentiate_preds
11
+
12
+ def monitor_epoch(self, ):
13
+ return
14
+
15
+ def monitor_set(self, setname, all_preds, all_losses,
16
+ all_batch_sizes, all_targets, dataset):
17
+ all_pred_labels = []
18
+ all_target_labels = []
19
+ for i_batch in range(len(all_batch_sizes)):
20
+ preds = all_preds[i_batch]
21
+ if True:
22
+ preds = np.exp(preds)
23
+ pred_labels = np.argmax(preds, axis=1)
24
+ all_pred_labels.extend(pred_labels)
25
+ targets = all_targets[i_batch]
26
+ # targets may be one-hot-encoded or not
27
+ if targets.ndim >= pred_labels.ndim:
28
+ targets = np.argmax(targets, axis=1)
29
+ assert targets.shape == pred_labels.shape
30
+ all_target_labels.extend(targets)
31
+ all_pred_labels = np.array(all_pred_labels)
32
+ all_target_labels = np.array(all_target_labels)
33
+ assert all_pred_labels.shape == all_target_labels.shape
34
+
35
+ misclass = 1 - np.mean(all_target_labels == all_pred_labels)
36
+ column_name = "{:s}_{:s}".format(setname, self.col_suffix)
37
+ return {column_name: float(misclass)}
38
+
39
+
40
+ class LossMonitor(object):
41
+ def monitor_epoch(self,):
42
+ return
43
+
44
+ def monitor_set(self, setname, all_preds, all_losses,
45
+ all_batch_sizes, all_targets, dataset):
46
+ batch_weights = np.array(all_batch_sizes)/ np.sum(all_batch_sizes)
47
+ loss_per_batch = [np.mean(loss) for loss in all_losses]
48
+ mean_loss = np.sum(batch_weights * loss_per_batch)
49
+ column_name = "{:s}_loss".format(setname)
50
+ return {column_name: mean_loss}
51
+
52
+
53
+ class CroppedTrialMisclassMonitor(object):
54
+ def __init__(self, input_time_length=None):
55
+ self.input_time_length = input_time_length
56
+
57
+ def monitor_epoch(self,):
58
+ return
59
+
60
+ def monitor_set(self, setname, all_preds, all_losses,
61
+ all_batch_sizes, all_targets, dataset):
62
+ """Assuming one hot encoding for now"""
63
+ assert self.input_time_length is not None, "Need to know input time length..."
64
+ all_pred_labels = self.compute_pred_labels(dataset, all_preds)
65
+ assert all_pred_labels.shape == dataset.y.shape
66
+ misclass = 1 - np.mean(all_pred_labels == dataset.y)
67
+ column_name = "{:s}_misclass".format(setname)
68
+ return {column_name: float(misclass)}
69
+
70
+ def compute_pred_labels(self, dataset, all_preds,):
71
+ n_preds_per_input = all_preds[0].shape[2]
72
+ n_receptive_field = self.input_time_length - n_preds_per_input + 1
73
+
74
+ n_preds_per_trial = [trial.shape[1] - n_receptive_field + 1
75
+ for trial in dataset.X]
76
+ preds_per_trial = compute_preds_per_trial_from_n_preds_per_trial(
77
+ all_preds, n_preds_per_trial)
78
+ all_pred_labels = [np.argmax(np.mean(p, axis=1))
79
+ for p in preds_per_trial]
80
+
81
+ all_pred_labels = np.array(all_pred_labels)
82
+ assert all_pred_labels.shape == dataset.y.shape
83
+ return all_pred_labels
84
+
85
+
86
+ def compute_preds_per_trial_for_set(all_preds, input_time_length,
87
+ dataset, ):
88
+ n_preds_per_input = all_preds[0].shape[2]
89
+ n_receptive_field = input_time_length - n_preds_per_input + 1
90
+ n_preds_per_trial = [trial.shape[1] - n_receptive_field + 1
91
+ for trial in dataset.X]
92
+ preds_per_trial = compute_preds_per_trial_from_n_preds_per_trial(
93
+ all_preds, n_preds_per_trial)
94
+ return preds_per_trial
95
+
96
+
97
+ def compute_preds_per_trial_from_n_preds_per_trial(
98
+ all_preds, n_preds_per_trial):
99
+ # all_preds_arr has shape forward_passes x classes x time
100
+ all_preds_arr = np.concatenate(all_preds, axis=0)
101
+ preds_per_trial = []
102
+ i_pred_block = 0
103
+ for i_trial in range(len(n_preds_per_trial)):
104
+ n_needed_preds = n_preds_per_trial[i_trial]
105
+ preds_this_trial = []
106
+ while n_needed_preds > 0:
107
+ # - n_needed_preds: only has an effect
108
+ # in case there are more samples than we actually still need
109
+ # in the block.
110
+ # That can happen since final block of a trial can overlap
111
+ # with block before so we can have some redundant preds.
112
+ pred_samples = all_preds_arr[i_pred_block,:,
113
+ -n_needed_preds:]
114
+ preds_this_trial.append(pred_samples)
115
+ n_needed_preds -= pred_samples.shape[1]
116
+ i_pred_block += 1
117
+
118
+ preds_this_trial = np.concatenate(preds_this_trial, axis=1)
119
+ preds_per_trial.append(preds_this_trial)
120
+ assert i_pred_block == len(all_preds_arr), (
121
+ "Expect that all prediction forward passes are needed, "
122
+ "used {:d}, existing {:d}".format(
123
+ i_pred_block, len(all_preds_arr)))
124
+ return preds_per_trial
125
+
126
+
127
+ class RuntimeMonitor(object):
128
+ def __init__(self):
129
+ self.last_call_time = None
130
+
131
+ def monitor_epoch(self,):
132
+ cur_time = time.time()
133
+ if self.last_call_time is None:
134
+ # just in case of first call
135
+ self.last_call_time = cur_time
136
+ epoch_runtime = cur_time - self.last_call_time
137
+ self.last_call_time = cur_time
138
+ return {'runtime': epoch_runtime}
139
+
140
+ def monitor_set(self, setname, all_preds, all_losses,
141
+ all_batch_sizes, all_targets, dataset):
142
+ return {}
@@ -0,0 +1,53 @@
1
+ import numpy as np
2
+
3
+
4
+ class MaxEpochs(object):
5
+ def __init__(self, max_epochs):
6
+ self.max_epochs = max_epochs
7
+
8
+ def should_stop(self, epochs_df):
9
+ # Keep in mind epoch 0 without training is also part of dataframe
10
+ return len(epochs_df) - 1 >= self.max_epochs
11
+
12
+
13
+ class Or(object):
14
+ def __init__(self, stop_criteria):
15
+ self.stop_criteria = stop_criteria
16
+
17
+ def should_stop(self, epochs_df):
18
+ return np.any([s.should_stop(epochs_df)
19
+ for s in self.stop_criteria])
20
+
21
+
22
+ class NoDecrease(object):
23
+ """ Stops if there is no decrease on a given monitor channel
24
+ for given number of epochs."""
25
+
26
+ def __init__(self, column_name, num_epochs, min_decrease=1e-6):
27
+ self.column_name = column_name
28
+ self.num_epochs = num_epochs
29
+ self.min_decrease = min_decrease
30
+ self.best_epoch = 0
31
+ self.lowest_val = float('inf')
32
+
33
+ def should_stop(self, epochs_df):
34
+ # -1 due to doing one monitor at start of training
35
+ i_epoch = len(epochs_df) - 1
36
+ current_val = float(epochs_df[self.column_name].iloc[-1])
37
+ if current_val < ((1 - self.min_decrease) * self.lowest_val):
38
+ self.best_epoch = i_epoch
39
+ self.lowest_val = current_val
40
+
41
+ return (i_epoch - self.best_epoch) >= self.num_epochs
42
+
43
+
44
+ class ColumnBelow():
45
+ """ Stops if the given column is below the given value."""
46
+ def __init__(self, column_name, target_value):
47
+ self.column_name = column_name
48
+ self.target_value = target_value
49
+
50
+ def should_stop(self, epochs_df):
51
+ # -1 due to doing one monitor at start of training
52
+ current_val = float(epochs_df[self.column_name].iloc[-1])
53
+ return current_val < self.target_value
File without changes