braindecode 0.3.1__tar.gz → 0.3.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 (71) hide show
  1. {Braindecode-0.3.1 → Braindecode-0.3.2}/Braindecode.egg-info/PKG-INFO +1 -1
  2. {Braindecode-0.3.1 → Braindecode-0.3.2}/Braindecode.egg-info/SOURCES.txt +2 -0
  3. {Braindecode-0.3.1 → Braindecode-0.3.2}/PKG-INFO +1 -1
  4. {Braindecode-0.3.1 → Braindecode-0.3.2}/braindecode/datasets/bbci.py +3 -3
  5. {Braindecode-0.3.1 → Braindecode-0.3.2}/braindecode/datasets/sensor_positions.py +27 -21
  6. {Braindecode-0.3.1 → Braindecode-0.3.2}/braindecode/datautil/signalproc.py +8 -2
  7. {Braindecode-0.3.1 → Braindecode-0.3.2}/braindecode/torch_ext/modules.py +51 -9
  8. Braindecode-0.3.2/braindecode/version.py +1 -0
  9. Braindecode-0.3.2/braindecode/visualization/input_windows.py +170 -0
  10. Braindecode-0.3.2/braindecode/visualization/perturbation.py +291 -0
  11. Braindecode-0.3.2/braindecode/visualization/sinfit.py +89 -0
  12. {Braindecode-0.3.1 → Braindecode-0.3.2}/docs/notebooks/visualization/Perturbation.ipynb +5 -23
  13. {Braindecode-0.3.1 → Braindecode-0.3.2}/docs/source/braindecode.visualization.rst +16 -0
  14. {Braindecode-0.3.1 → Braindecode-0.3.2}/setup.cfg +0 -1
  15. Braindecode-0.3.1/braindecode/version.py +0 -1
  16. Braindecode-0.3.1/braindecode/visualization/perturbation.py +0 -116
  17. {Braindecode-0.3.1 → Braindecode-0.3.2}/Braindecode.egg-info/dependency_links.txt +0 -0
  18. {Braindecode-0.3.1 → Braindecode-0.3.2}/Braindecode.egg-info/not-zip-safe +0 -0
  19. {Braindecode-0.3.1 → Braindecode-0.3.2}/Braindecode.egg-info/requires.txt +0 -0
  20. {Braindecode-0.3.1 → Braindecode-0.3.2}/Braindecode.egg-info/top_level.txt +0 -0
  21. {Braindecode-0.3.1 → Braindecode-0.3.2}/LICENSE.txt +0 -0
  22. {Braindecode-0.3.1 → Braindecode-0.3.2}/MANIFEST.in +0 -0
  23. {Braindecode-0.3.1 → Braindecode-0.3.2}/README.rst +0 -0
  24. {Braindecode-0.3.1 → Braindecode-0.3.2}/braindecode/__init__.py +0 -0
  25. {Braindecode-0.3.1 → Braindecode-0.3.2}/braindecode/datasets/__init__.py +0 -0
  26. {Braindecode-0.3.1 → Braindecode-0.3.2}/braindecode/datasets/bcic_iv_2a.py +0 -0
  27. {Braindecode-0.3.1 → Braindecode-0.3.2}/braindecode/datasets/multiple.py +0 -0
  28. {Braindecode-0.3.1 → Braindecode-0.3.2}/braindecode/datautil/__init__.py +0 -0
  29. {Braindecode-0.3.1 → Braindecode-0.3.2}/braindecode/datautil/iterators.py +0 -0
  30. {Braindecode-0.3.1 → Braindecode-0.3.2}/braindecode/datautil/signal_target.py +0 -0
  31. {Braindecode-0.3.1 → Braindecode-0.3.2}/braindecode/datautil/splitters.py +0 -0
  32. {Braindecode-0.3.1 → Braindecode-0.3.2}/braindecode/datautil/trial_segment.py +0 -0
  33. {Braindecode-0.3.1 → Braindecode-0.3.2}/braindecode/datautil/util.py +0 -0
  34. {Braindecode-0.3.1 → Braindecode-0.3.2}/braindecode/experiments/__init__.py +0 -0
  35. {Braindecode-0.3.1 → Braindecode-0.3.2}/braindecode/experiments/experiment.py +0 -0
  36. {Braindecode-0.3.1 → Braindecode-0.3.2}/braindecode/experiments/monitors.py +0 -0
  37. {Braindecode-0.3.1 → Braindecode-0.3.2}/braindecode/experiments/stopcriteria.py +0 -0
  38. {Braindecode-0.3.1 → Braindecode-0.3.2}/braindecode/mne_ext/__init__.py +0 -0
  39. {Braindecode-0.3.1 → Braindecode-0.3.2}/braindecode/mne_ext/signalproc.py +0 -0
  40. {Braindecode-0.3.1 → Braindecode-0.3.2}/braindecode/models/__init__.py +0 -0
  41. {Braindecode-0.3.1 → Braindecode-0.3.2}/braindecode/models/deep4.py +0 -0
  42. {Braindecode-0.3.1 → Braindecode-0.3.2}/braindecode/models/eegnet.py +0 -0
  43. {Braindecode-0.3.1 → Braindecode-0.3.2}/braindecode/models/shallow_fbcsp.py +0 -0
  44. {Braindecode-0.3.1 → Braindecode-0.3.2}/braindecode/models/util.py +0 -0
  45. {Braindecode-0.3.1 → Braindecode-0.3.2}/braindecode/torch_ext/__init__.py +0 -0
  46. {Braindecode-0.3.1 → Braindecode-0.3.2}/braindecode/torch_ext/constraints.py +0 -0
  47. {Braindecode-0.3.1 → Braindecode-0.3.2}/braindecode/torch_ext/functions.py +0 -0
  48. {Braindecode-0.3.1 → Braindecode-0.3.2}/braindecode/torch_ext/init.py +0 -0
  49. {Braindecode-0.3.1 → Braindecode-0.3.2}/braindecode/torch_ext/losses.py +0 -0
  50. {Braindecode-0.3.1 → Braindecode-0.3.2}/braindecode/torch_ext/util.py +0 -0
  51. {Braindecode-0.3.1 → Braindecode-0.3.2}/braindecode/util.py +0 -0
  52. {Braindecode-0.3.1 → Braindecode-0.3.2}/braindecode/visualization/__init__.py +0 -0
  53. {Braindecode-0.3.1 → Braindecode-0.3.2}/braindecode/visualization/plot.py +0 -0
  54. {Braindecode-0.3.1 → Braindecode-0.3.2}/docs/Makefile +0 -0
  55. {Braindecode-0.3.1 → Braindecode-0.3.2}/docs/conf.py +0 -0
  56. {Braindecode-0.3.1 → Braindecode-0.3.2}/docs/index.rst +0 -0
  57. {Braindecode-0.3.1 → Braindecode-0.3.2}/docs/notebooks/BBCI_Data.ipynb +0 -0
  58. {Braindecode-0.3.1 → Braindecode-0.3.2}/docs/notebooks/BBCI_Data_Start_Stop.ipynb +0 -0
  59. {Braindecode-0.3.1 → Braindecode-0.3.2}/docs/notebooks/BBCI_Data_Trialwise.ipynb +0 -0
  60. {Braindecode-0.3.1 → Braindecode-0.3.2}/docs/notebooks/Cropped_Decoding.ipynb +0 -0
  61. {Braindecode-0.3.1 → Braindecode-0.3.2}/docs/notebooks/Experiment_Class.ipynb +0 -0
  62. {Braindecode-0.3.1 → Braindecode-0.3.2}/docs/notebooks/TrialWise_Decoding.ipynb +0 -0
  63. {Braindecode-0.3.1 → Braindecode-0.3.2}/docs/source/braindecode.datasets.rst +0 -0
  64. {Braindecode-0.3.1 → Braindecode-0.3.2}/docs/source/braindecode.datautil.rst +0 -0
  65. {Braindecode-0.3.1 → Braindecode-0.3.2}/docs/source/braindecode.experiments.rst +0 -0
  66. {Braindecode-0.3.1 → Braindecode-0.3.2}/docs/source/braindecode.mne_ext.rst +0 -0
  67. {Braindecode-0.3.1 → Braindecode-0.3.2}/docs/source/braindecode.models.rst +0 -0
  68. {Braindecode-0.3.1 → Braindecode-0.3.2}/docs/source/braindecode.rst +0 -0
  69. {Braindecode-0.3.1 → Braindecode-0.3.2}/docs/source/braindecode.torch_ext.rst +0 -0
  70. {Braindecode-0.3.1 → Braindecode-0.3.2}/docs/source/modules.rst +0 -0
  71. {Braindecode-0.3.1 → Braindecode-0.3.2}/setup.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 1.1
2
2
  Name: Braindecode
3
- Version: 0.3.1
3
+ Version: 0.3.2
4
4
  Summary: A deep learning toolbox to decode raw time-domain EEG.
5
5
  Home-page: https://github.com/robintibor/braindecode
6
6
  Author: Robin Tibor Schirrmeister
@@ -42,8 +42,10 @@ braindecode/torch_ext/losses.py
42
42
  braindecode/torch_ext/modules.py
43
43
  braindecode/torch_ext/util.py
44
44
  braindecode/visualization/__init__.py
45
+ braindecode/visualization/input_windows.py
45
46
  braindecode/visualization/perturbation.py
46
47
  braindecode/visualization/plot.py
48
+ braindecode/visualization/sinfit.py
47
49
  docs/Makefile
48
50
  docs/conf.py
49
51
  docs/index.rst
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 1.1
2
2
  Name: Braindecode
3
- Version: 0.3.1
3
+ Version: 0.3.2
4
4
  Summary: A deep learning toolbox to decode raw time-domain EEG.
5
5
  Home-page: https://github.com/robintibor/braindecode
6
6
  Author: Robin Tibor Schirrmeister
@@ -93,7 +93,7 @@ class BBCIDataset(object):
93
93
 
94
94
  def _determine_samplingrate(self):
95
95
  with h5py.File(self.filename, 'r') as h5file:
96
- fs = h5file['dat']['fs'][0, 0]
96
+ fs = h5file['nfo']['fs'][0, 0]
97
97
  assert isinstance(fs, int) or fs.is_integer()
98
98
  fs = int(fs)
99
99
  return fs
@@ -125,7 +125,7 @@ class BBCIDataset(object):
125
125
  Sensor names that match the pattern or all sensor names in the file.
126
126
  """
127
127
  with h5py.File(filename, 'r') as h5file:
128
- clab_set = h5file['dat']['clab'][:].squeeze()
128
+ clab_set = h5file['nfo']['clab'][:].squeeze()
129
129
  all_sensor_names = [''.join(chr(c) for c in h5file[obj_ref]) for
130
130
  obj_ref in clab_set]
131
131
  if pattern is not None:
@@ -137,7 +137,7 @@ class BBCIDataset(object):
137
137
  def _add_markers(self, cnt):
138
138
  with h5py.File(self.filename, 'r') as h5file:
139
139
  event_times_in_ms = h5file['mrk']['time'][:].squeeze()
140
- event_classes = h5file['mrk']['event']['desc'][:].squeeze()
140
+ event_classes = h5file['mrk']['event']['desc'][:].squeeze().astype(np.int64)
141
141
 
142
142
  # Check whether class names known and correct order
143
143
  class_name_set = h5file['nfo']['className'][:].squeeze()
@@ -192,26 +192,32 @@ def get_channelpos_from_angle(channame, chan_pos_list=CHANNEL_10_20_APPROX):
192
192
  if i[0].lower() == channame:
193
193
  # convert the 90/4th angular position into x, y, z
194
194
  p = i[1]
195
- ea, eb = p[0] * (90 / 4), p[1] * (90 / 4)
196
- ea = ea * math.pi / 180
197
- eb = eb * math.pi / 180
198
- x = math.sin(ea) * math.cos(eb)
199
- y = math.sin(eb)
200
- z = math.cos(ea) * math.cos(eb)
201
- # Calculate the stereographic projection.
202
- # Given a unit sphere with radius ``r = 1`` and center at
203
- # the origin. Project the point ``p = (x, y, z)`` from the
204
- # sphere's South pole (0, 0, -1) on a plane on the sphere's
205
- # North pole (0, 0, 1).
206
- #
207
- # The formula is:
208
- #
209
- # P' = P * (2r / (r + z))
210
- #
211
- # We changed the values to move the point of projection
212
- # further below the south pole
213
- mu = 1 / (1.3 + z)
214
- x *= mu
215
- y *= mu
195
+ x, y = _convert_2d_angle_to_2d_coord(*p)
216
196
  return x, y
217
197
  return None
198
+
199
+
200
+ def _convert_2d_angle_to_2d_coord(a,b):
201
+ # convert the 90/4th angular position into x, y, z
202
+ ea, eb = a * (90 / 4), b * (90 / 4)
203
+ ea = ea * math.pi / 180
204
+ eb = eb * math.pi / 180
205
+ x = math.sin(ea) * math.cos(eb)
206
+ y = math.sin(eb)
207
+ z = math.cos(ea) * math.cos(eb)
208
+ # Calculate the stereographic projection.
209
+ # Given a unit sphere with radius ``r = 1`` and center at
210
+ # the origin. Project the point ``p = (x, y, z)`` from the
211
+ # sphere's South pole (0, 0, -1) on a plane on the sphere's
212
+ # North pole (0, 0, 1).
213
+ #
214
+ # The formula is:
215
+ #
216
+ # P' = P * (2r / (r + z))
217
+ #
218
+ # We changed the values to move the point of projection
219
+ # further below the south pole
220
+ mu = 1 / (1.3 + z)
221
+ x *= mu
222
+ y *= mu
223
+ return x, y
@@ -146,7 +146,8 @@ def lowpass_cnt(data, high_cut_hz, fs, filt_order=3, axis=0):
146
146
  return data_lowpassed
147
147
 
148
148
 
149
- def bandpass_cnt(data, low_cut_hz, high_cut_hz, fs, filt_order=3, axis=0):
149
+ def bandpass_cnt(data, low_cut_hz, high_cut_hz, fs, filt_order=3, axis=0,
150
+ filtfilt=False):
150
151
  """
151
152
  Bandpass signal applying **causal** butterworth filter of given order.
152
153
 
@@ -158,6 +159,8 @@ def bandpass_cnt(data, low_cut_hz, high_cut_hz, fs, filt_order=3, axis=0):
158
159
  high_cut_hz: float
159
160
  fs: float
160
161
  filt_order: int
162
+ filtfilt: bool
163
+ Whether to use filtfilt instead of lfilter
161
164
 
162
165
  Returns
163
166
  -------
@@ -182,7 +185,10 @@ def bandpass_cnt(data, low_cut_hz, high_cut_hz, fs, filt_order=3, axis=0):
182
185
  high = high_cut_hz / nyq_freq
183
186
  b, a = scipy.signal.butter(filt_order, [low, high], btype='bandpass')
184
187
  assert filter_is_stable(a), "Filter should be stable..."
185
- data_bandpassed = scipy.signal.lfilter(b, a, data, axis=axis)
188
+ if filtfilt:
189
+ data_bandpassed = scipy.signal.filtfilt(b, a, data, axis=axis)
190
+ else:
191
+ data_bandpassed = scipy.signal.lfilter(b, a, data, axis=axis)
186
192
  return data_bandpassed
187
193
 
188
194
 
@@ -8,7 +8,7 @@ from braindecode.torch_ext.util import np_to_var
8
8
  class Expression(torch.nn.Module):
9
9
  """
10
10
  Compute given expression on forward pass.
11
-
11
+
12
12
  Parameters
13
13
  ----------
14
14
  expression_fn: function
@@ -37,7 +37,7 @@ class Expression(torch.nn.Module):
37
37
  class AvgPool2dWithConv(torch.nn.Module):
38
38
  """
39
39
  Compute average pooling using a convolution, to have the dilation parameter.
40
-
40
+
41
41
  Parameters
42
42
  ----------
43
43
  kernel_size: (int,int)
@@ -52,7 +52,10 @@ class AvgPool2dWithConv(torch.nn.Module):
52
52
  self.kernel_size = kernel_size
53
53
  self.stride = stride
54
54
  self.dilation = dilation
55
- self.weights = None
55
+ # don't name them "weights" to
56
+ # make sure these are not accidentally used by some procedure
57
+ # that initializes parameters or something
58
+ self._pool_weights = None
56
59
 
57
60
  def forward(self, x):
58
61
  # Create weights for the convolution on demand:
@@ -60,11 +63,11 @@ class AvgPool2dWithConv(torch.nn.Module):
60
63
  in_channels = x.size()[1]
61
64
  weight_shape = (in_channels, 1,
62
65
  self.kernel_size[0], self.kernel_size[1])
63
- if self.weights is None or (
64
- (tuple(self.weights.size()) != tuple(weight_shape)) or (
65
- self.weights.is_cuda != x.is_cuda
66
+ if self._pool_weights is None or (
67
+ (tuple(self._pool_weights.size()) != tuple(weight_shape)) or (
68
+ self._pool_weights.is_cuda != x.is_cuda
66
69
  ) or (
67
- self.weights.data.type() != x.data.type()
70
+ self._pool_weights.data.type() != x.data.type()
68
71
  )):
69
72
  n_pool = np.prod(self.kernel_size)
70
73
  weights = np_to_var(
@@ -72,9 +75,48 @@ class AvgPool2dWithConv(torch.nn.Module):
72
75
  weights = weights.type_as(x)
73
76
  if x.is_cuda:
74
77
  weights = weights.cuda()
75
- self.weights = weights
78
+ self._pool_weights = weights
76
79
 
77
- pooled = F.conv2d(x, self.weights, bias=None, stride=self.stride,
80
+ pooled = F.conv2d(x, self._pool_weights, bias=None, stride=self.stride,
78
81
  dilation=self.dilation,
79
82
  groups=in_channels,)
80
83
  return pooled
84
+
85
+
86
+ class IntermediateOutputWrapper(torch.nn.Module):
87
+ """Wraps network model such that outputs of intermediate layers can be returned.
88
+ forward() returns list of intermediate activations in a network during forward pass.
89
+
90
+ Parameters
91
+ ----------
92
+ to_select : list
93
+ list of module names for which activation should be returned
94
+ model : model object
95
+ network model
96
+
97
+ Examples
98
+ --------
99
+ >>> model = Deep4Net()
100
+ >>> select_modules = ['conv_spat','conv_2','conv_3','conv_4'] # Specify intermediate outputs
101
+ >>> model_pert = IntermediateOutputWrapper(select_modules,model) # Wrap model
102
+ """
103
+ def __init__(self, to_select, model):
104
+ if not len(list(model.children()))==len(list(model.named_children())):
105
+ raise Exception('All modules in model need to have names!')
106
+
107
+ super(IntermediateOutputWrapper, self).__init__()
108
+
109
+ modules_list = model.named_children()
110
+ for key, module in modules_list:
111
+ self.add_module(key, module)
112
+ self._modules[key].load_state_dict(module.state_dict())
113
+ self._to_select = to_select
114
+
115
+ def forward(self,x):
116
+ # Call modules individually and append activation to output if module is in to_select
117
+ o = []
118
+ for name, module in self._modules.items():
119
+ x = module(x)
120
+ if name in self._to_select:
121
+ o.append(x)
122
+ return o
@@ -0,0 +1 @@
1
+ __version__ = "0.3.2"
@@ -0,0 +1,170 @@
1
+ import numpy as np
2
+ import torch
3
+
4
+ def calc_Hout(Hin, kernel, stride, dilation):
5
+ Hout = np.floor((Hin-dilation*(kernel-1)-1)/stride+1)
6
+ return Hout
7
+
8
+ def calc_Hin(Hout, kernel, stride, dilation):
9
+ Hin = np.ceil((Hout-1)*stride+1+dilation*(kernel-1))
10
+ return Hin
11
+
12
+ def calc_receptive_field_size(model,layer_ind,start_receptive_field=np.ones((2))):
13
+ """Calculate receptive field size for unit in specific layer of the network
14
+ Only tested for 2d convolutions/poolings. Dimshuffle operations may lead to a wrong result
15
+
16
+ Parameters
17
+ ----------
18
+ model : model object
19
+ Network model
20
+ layer_ind: int
21
+ Index of the layer of interest in `model.children()`
22
+ start_receptive_field: int, optional
23
+ How many units are looked at in specified layer (default: [1,1])
24
+
25
+ Returns
26
+ -------
27
+ receptive_field_size : numpy array
28
+ [HxW] in the input layer
29
+ """
30
+ receptive_field = start_receptive_field
31
+ children = list(model.children())[:layer_ind][::-1]
32
+ for child in children:
33
+ if isinstance(child,torch.nn.Sequential):
34
+ receptive_field = calc_receptive_field(child,-1)
35
+ elif isinstance(child,torch.nn.Conv2d) or isinstance(child,torch.nn.MaxPool2d) or isinstance(child,torch.nn.AvgPool2d):
36
+ receptive_field = calc_Hin(receptive_field,np.asarray(child.kernel_size),
37
+ np.asarray(child.stride), np.asarray(child.dilation))
38
+
39
+ receptive_field_size = receptive_field.astype(np.int)
40
+ return receptive_field_size
41
+
42
+ def get_max_act_index(activations,unique_per_input=True,n_units=None):
43
+ """Retrieve index of maximum activation in a feature map
44
+
45
+ Parameters
46
+ ----------
47
+ activations : numpy array
48
+ [Nx1xHxW] can only take 1 filter
49
+ unique_per_input : bool, optional
50
+ Specifies if only 1 index (maximum) for each input is returned (default: True)
51
+ n_units : int, optional
52
+ How many indeces are returned in total. If None all (default: None)
53
+
54
+ Returns
55
+ -------
56
+ units : numpy array
57
+ [Nx4] with the columns `Input_i`,`Filter(0)`,`H_i`,`W_i` indeces of the units
58
+ units_activation : numpy array
59
+ Activation of the units
60
+ """
61
+ assert len(activations.shape)==4,"Has to be 4d array"
62
+ assert activations.shape[1] == 1,"Can only handle individual filter activations"
63
+
64
+ activations_sorted = activations.argsort(axis=None)[::-1]
65
+ activations_sorted_ind = np.unravel_index(activations_sorted,activations.shape)
66
+ unique_ind = np.arange(len(activations_sorted_ind[0]))
67
+ if unique_per_input:
68
+ a,unique_ind = np.unique(activations_sorted_ind[0],return_index=True)
69
+ unique_ind = sorted(unique_ind)
70
+
71
+ if n_units==None:
72
+ n_units = len(unique_ind)
73
+ activations_sorted_ind = np.asarray(activations_sorted_ind).T
74
+ units = activations_sorted_ind[unique_ind[:n_units],:].astype(np.int)
75
+ units_activation = activations.flat[activations_sorted[unique_ind[:n_units]]]
76
+
77
+ return units,units_activation
78
+
79
+ def calc_receptive_field_for_units_2d(units,receptive_field_size):
80
+ recptive_field_tmp = receptive_field_size[np.newaxis,np.newaxis,:,:]
81
+ start_inds = units[:,0,]
82
+ stop_inds = start_inds+receptive_field_tmp
83
+
84
+ return start_inds,stop_inds
85
+
86
+ def get_input_windows_from_units_2d(inputs,units,receptive_field_size):
87
+ """Cut input windows in receptive field of specified units from inputs
88
+
89
+ Parameters
90
+ ----------
91
+ inputs : numpy array
92
+ [NxCxHxW] Inputs x Channels x Time x W
93
+ units : numpy array
94
+ [Mx4] unit indeces specifying Input and time indeces.
95
+ Second dimension consists of Input x Filter(1) x H x W indeces. Can only handle 1 filter.
96
+ receptive_field_size : int
97
+ Size of receptive field of units on input
98
+
99
+ Returns
100
+ -------
101
+ windows : numpy array
102
+ Cut input windows
103
+ """
104
+ windows = np.zeros((units.shape[0],inputs.shape[1],receptive_field_size[0],receptive_field_size[1]))
105
+ for i,unit in enumerate(units):
106
+ windows[i] = inputs[unit[0],:,
107
+ unit[2]:unit[2]+receptive_field_size[0],
108
+ unit[3]:unit[3]+receptive_field_size[1]]
109
+ return windows
110
+
111
+
112
+ def most_activating_input_windows(inputs,activations,receptive_field_size,top_percentage=0.05):
113
+ """Get the input windows that evoked highest activation in a feature map
114
+
115
+ Parameters
116
+ ----------
117
+ inputs : numpy array
118
+ [NxCxTx1] Inputs used for the calculation of activations
119
+ activations : numpy array
120
+ [NxFxHx1] Activations
121
+ receptive_field_size : numpy array
122
+ [Wx1] Receptive field of a unit of the layer on the input
123
+ top_percentage : float, optional
124
+ How many of the most activating input windows should be returned (default: top 5%)
125
+
126
+ Returns
127
+ -------
128
+ input_windows : numpy array
129
+ [FxUxCxWx1] Returns `U` (resulting from top_percentage) input windows for each filter
130
+ """
131
+ n_units = int(inputs.shape[0]*top_percentage)
132
+ input_windows = np.zeros((activations.shape[1],n_units,inputs.shape[1],
133
+ receptive_field_size[0],receptive_field_size[1]))
134
+ for filt in range(activations.shape[1]):
135
+ units,w = get_max_act_index(activations[:,[filt]],n_units=n_units)
136
+ w = w.squeeze()
137
+ windows_tmp = get_input_windows_from_units_2d(inputs,units,receptive_field_size)
138
+ input_windows[filt] = windows_tmp
139
+ return input_windows
140
+
141
+ def activation_reverse_correlation(inputs,activations,receptive_field_size):
142
+ """Get reverse correlations for filters
143
+
144
+ Parameters
145
+ ----------
146
+ inputs : numpy array
147
+ [NxCxTx1] Inputs used for the calculation of activations
148
+ activations : numpy array
149
+ [NxFxHx1] Activations
150
+ receptive_field_size : numpy array
151
+ [Wx1] Receptive field of a unit of the layer on the input
152
+
153
+ Returns
154
+ -------
155
+ reverse_corr : numpy array
156
+ [FxCxWx1] Reverse correlations over all input windows for each filter
157
+ """
158
+ reverse_corr = np.zeros((activations.shape[1],inputs.shape[1],
159
+ receptive_field_size[0],receptive_field_size[1]))
160
+ for filt in range(activations.shape[1]):
161
+ act_tmp = activations[:,filt]
162
+ divisor = 0
163
+ for start_ind in range(activations.shape[2]):
164
+ end_ind = start_ind+receptive_field_size[0]
165
+ w = act_tmp[:,[start_ind],:,np.newaxis]
166
+ windows_tmp = inputs[:,:,start_ind:end_ind]
167
+ reverse_corr[filt] += np.sum(w*windows_tmp,axis=0)
168
+ divisor += np.sum(np.abs(w))
169
+ reverse_corr[filt] /= divisor
170
+ return reverse_corr
@@ -0,0 +1,291 @@
1
+ import logging
2
+
3
+ import numpy as np
4
+
5
+ from braindecode.datautil.iterators import get_balanced_batches
6
+ from braindecode.util import wrap_reshape_apply_fn, corr
7
+
8
+ log = logging.getLogger(__name__)
9
+
10
+
11
+ def phase_perturbation(amps,phases,rng=np.random.RandomState()):
12
+ """Takes amps and phases of BxCxF with B input, C channels, F frequencies
13
+ Shifts spectral phases randomly U(-pi,pi) for input and frequencies, but same for all channels
14
+
15
+ Parameters
16
+ ----------
17
+ amps : numpy array
18
+ Spectral amplitude (not used)
19
+ phases : numpy array
20
+ Spectral phases
21
+ rng : object
22
+ Random Seed
23
+
24
+ Returns
25
+ -------
26
+ amps : numpy array
27
+ Input amps (not modified)
28
+ phases_pert : numpy array
29
+ Shifted phases
30
+ pert_vals : numpy array
31
+ Absolute phase shifts
32
+ """
33
+ noise_shape = list(phases.shape)
34
+ noise_shape[1] = 1 # Do not sample noise for channels individually
35
+
36
+ # Sample phase perturbation noise
37
+ phase_noise = rng.uniform(-np.pi,np.pi,noise_shape).astype(np.float32)
38
+ phase_noise_rep = phase_noise.repeat(phases.shape[1],axis=1)
39
+ # Apply noise to inputs
40
+ phases_pert = phases+phase_noise_rep
41
+ phases_pert[phases_pert<-np.pi] += 2*np.pi
42
+ phases_pert[phases_pert>np.pi] -= 2*np.pi
43
+
44
+ pert_vals = np.abs(phase_noise)
45
+ return amps,phases_pert,pert_vals
46
+
47
+ def amp_perturbation_additive(amps,phases,rng=np.random.RandomState()):
48
+ """Takes amplitudes and phases of BxCxF with B input, C channels, F frequencies
49
+ Adds additive noise N(0,0.02) to amplitudes
50
+
51
+ Parameters
52
+ ----------
53
+ amps : numpy array
54
+ Spectral amplitude
55
+ phases : numpy array
56
+ Spectral phases (not used)
57
+ rng : object
58
+ Random Seed
59
+
60
+ Returns
61
+ -------
62
+ amps_pert : numpy array
63
+ Scaled amplitudes
64
+ phases_pert : numpy array
65
+ Input phases (not modified)
66
+ pert_vals : numpy array
67
+ Amplitude noise
68
+ """
69
+ amp_noise = rng.normal(0,1,amps.shape).astype(np.float32)
70
+ amps_pert = amps+amp_noise
71
+ amps_pert[amps_pert<0] = 0
72
+ amp_noise = amps_pert-amps
73
+ return amps_pert,phases,amp_noise
74
+
75
+ def amp_perturbation_multiplicative(amps,phases,rng=np.random.RandomState()):
76
+ """Takes amplitude and phases of BxCxF with B input, C channels, F frequencies
77
+ Adds multiplicative noise N(1,0.02) to amplitudes
78
+
79
+ Parameters
80
+ ----------
81
+ amps : numpy array
82
+ Spectral amplitude
83
+ phases : numpy array
84
+ Spectral phases (not used)
85
+ rng : object
86
+ Random Seed
87
+
88
+ Returns
89
+ -------
90
+ amps_pert : numpy array
91
+ Scaled amplitudes
92
+ phases_pert : numpy array
93
+ Input phases (not modified)
94
+ pert_vals : numpy array
95
+ Amplitude scaling factor
96
+ """
97
+ amp_noise = rng.normal(1,0.02,amps.shape).astype(np.float32)
98
+ amps_pert = amps*amp_noise
99
+ amps_pert[amps_pert<0] = 0
100
+ return amps_pert,phases,amp_noise
101
+
102
+ def correlate_feature_maps(x,y):
103
+ """Takes two activation matrices of the form Bx[F]xT where B is batch size, F number of filters (optional) and T time points
104
+ Returns correlations of the corresponding activations over T
105
+
106
+ Parameters
107
+ ----------
108
+ x : numpy array
109
+ Activations Bx[F]xT
110
+ y : numpy array
111
+ Activations Bx[F]xT
112
+
113
+ Returns
114
+ correlations : numpy array
115
+ Correlations of `x` and `y` Bx[F]
116
+ """
117
+ shape_x = x.shape
118
+ shape_y = y.shape
119
+ assert np.array_equal(shape_x,shape_y)
120
+ assert len(shape_x)<4
121
+ x = x.reshape((-1,shape_x[-1]))
122
+ y = y.reshape((-1,shape_y[-1]))
123
+
124
+ x = (x-x.mean(axis=1,keepdims=True))/x.std(axis=1,keepdims=True)
125
+ y = (y-y.mean(axis=1,keepdims=True))/y.std(axis=1,keepdims=True)
126
+
127
+ tmp_corr = x*y
128
+ corr_ = tmp_corr.sum(axis=1)
129
+ #corr_ = np.zeros((x.shape[0]))
130
+ #for i in range(x.shape[0]):
131
+ # # Correlation of standardized variables
132
+ # corr_[i] = np.correlate((x[i]-x[i].mean())/x[i].std(),(y[i]-y[i].mean())/y[i].std())
133
+
134
+ correlations = corr_.reshape(*shape_x[:-1])
135
+ return correlations
136
+
137
+ def mean_diff_feature_maps(x,y):
138
+ """Takes two activation matrices of the form BxFxT where B is batch size, F number of filters and T time points
139
+ Returns mean difference between feature map activations
140
+
141
+ Parameters
142
+ ----------
143
+ x : numpy array
144
+ Activations Bx[F]xT
145
+ y : numpy array
146
+ Activations Bx[F]xT
147
+
148
+ Returns
149
+ mean_diff : numpy array
150
+ Mean difference between `x` and `y` Bx[F]
151
+ """
152
+ mean_diff = np.mean(x-y,axis=2)
153
+ return mean_diff
154
+
155
+ def spectral_perturbation_correlation(pert_fn, diff_fn, pred_fn, n_layers, inputs, n_iterations,
156
+ batch_size=30,
157
+ seed=((2017, 7, 10))):
158
+ """Calculates perturbation correlations for layers in network by perturbing either amplitudes or phases
159
+
160
+ Parameters
161
+ ----------
162
+ pert_fn : function
163
+ Function that perturbs spectral phase and amplitudes of inputs
164
+ diff_fn : function
165
+ Function that calculates difference between original and perturbed activations
166
+ pred_fn : function
167
+ Function that returns a list of activations.
168
+ Each entry in the list corresponds to the output of 1 layer in a network
169
+ n_layers : int
170
+ Number of layers pred_fn returns activations for.
171
+ inputs : numpy array
172
+ Original inputs that are used for perturbation [B,X,T,1]
173
+ Phase perturbations are sampled for each input individually, but applied to all X of that input
174
+ n_iterations : int
175
+ Number of iterations of correlation computation. The higher the better
176
+ batch_size : int
177
+ Number of inputs that are used for one forward pass. (Concatenated for all inputs)
178
+
179
+ Returns
180
+ -------
181
+ pert_corrs : numpy array
182
+ List of length n_layers containing average perturbation correlations over iterations
183
+ L x CxFrxFi (Channels,Frequencies,Filters)
184
+ """
185
+ rng = np.random.RandomState(seed)
186
+
187
+ # Get batch indeces
188
+ batch_inds = get_balanced_batches(
189
+ n_trials=len(inputs), rng=rng, shuffle=False, batch_size=batch_size)
190
+ # Calculate layer activations and reshape
191
+ log.info("Compute original predictions...")
192
+ orig_preds = [pred_fn(inputs[inds])
193
+ for inds in batch_inds]
194
+ use_shape = []
195
+ for l in range(n_layers):
196
+ tmp = list(orig_preds[0][l].shape)
197
+ tmp.extend([1]*(4-len(tmp)))
198
+ tmp[0] = len(inputs)
199
+ use_shape.append(tmp)
200
+ orig_preds_layers = [np.concatenate([orig_preds[o][l] for o in range(len(orig_preds))]).reshape(use_shape[l])
201
+ for l in range(n_layers)]
202
+
203
+ # Compute FFT of inputs
204
+ fft_input = np.fft.rfft(inputs, n=inputs.shape[2], axis=2)
205
+ amps = np.abs(fft_input)
206
+ phases = np.angle(fft_input)
207
+
208
+ pert_corrs = [0]*n_layers
209
+ for i in range(n_iterations):
210
+ log.info("Iteration {:d}...".format(i))
211
+ log.info("Sample perturbation...")
212
+ amps_pert,phases_pert,pert_vals = pert_fn(amps,phases,rng=rng)
213
+
214
+ # Compute perturbed inputs
215
+ log.info("Compute perturbed complex inputs...")
216
+ fft_pert = amps_pert*np.exp(1j*phases_pert)
217
+ log.info("Compute perturbed real inputs...")
218
+ inputs_pert = np.fft.irfft(fft_pert, n=inputs.shape[2], axis=2).astype(np.float32)
219
+
220
+ # Calculate layer activations for perturbed inputs
221
+ log.info("Compute new predictions...")
222
+ new_preds = [pred_fn(inputs_pert[inds])
223
+ for inds in batch_inds]
224
+ new_preds_layers = [np.concatenate([new_preds[o][l] for o in range(len(new_preds))]).reshape(use_shape[l])
225
+ for l in range(n_layers)]
226
+
227
+ for l in range(n_layers):
228
+ log.info("Layer {:d}...".format(l))
229
+ # Calculate difference of original and perturbed feature map activations
230
+ log.info("Compute activation difference...")
231
+ preds_diff = diff_fn(new_preds_layers[l][:,:,:,0],orig_preds_layers[l][:,:,:,0])
232
+
233
+ # Calculate feature map differences with perturbations
234
+ log.info("Compute correlation...")
235
+ pert_corrs_tmp = wrap_reshape_apply_fn(corr,
236
+ pert_vals[:,:,:,0],preds_diff,
237
+ axis_a=(0,), axis_b=(0))
238
+ pert_corrs[l] += pert_corrs_tmp
239
+
240
+ pert_corrs = [pert_corrs[l]/n_iterations for l in range(n_layers)] #mean over iterations
241
+ return pert_corrs
242
+
243
+
244
+ def compute_amplitude_prediction_correlations(pred_fn, examples, n_iterations,
245
+ perturb_fn=amp_perturbation_additive,
246
+ batch_size=30,
247
+ seed=((2017, 7, 10))):
248
+ """
249
+ Perturb input amplitudes and compute correlation between amplitude
250
+ perturbations and prediction changes when pushing perturbed input through
251
+ the prediction function.
252
+
253
+ For more details, see [EEGDeepLearning]_.
254
+
255
+ Parameters
256
+ ----------
257
+ pred_fn: function
258
+ Function accepting an numpy input and returning prediction.
259
+ examples: ndarray
260
+ Numpy examples, first axis should be example axis.
261
+ n_iterations: int
262
+ Number of iterations to compute.
263
+ perturb_fn: function, optional
264
+ Function accepting amplitude array and random generator and returning
265
+ perturbation. Default is Gaussian perturbation.
266
+ batch_size: int, optional
267
+ Batch size for computing predictions.
268
+ seed: int, optional
269
+ Random generator seed
270
+
271
+ Returns
272
+ -------
273
+ amplitude_pred_corrs: ndarray
274
+ Correlations between amplitude perturbations and prediction changes
275
+ for all sensors and frequency bins.
276
+
277
+ References
278
+ ----------
279
+
280
+ .. [EEGDeepLearning] Schirrmeister, R. T., Springenberg, J. T., Fiederer, L. D. J.,
281
+ Glasstetter, M., Eggensperger, K., Tangermann, M., ... & Ball, T. (2017).
282
+ Deep learning with convolutional neural networks for EEG decoding and
283
+ visualization.
284
+ arXiv preprint arXiv:1703.05051.
285
+ """
286
+ pred_fn_new = lambda x: [pred_fn(x)]
287
+ pred_corrs = spectral_perturbation_correlation(perturb_fn, mean_diff_feature_maps,
288
+ pred_fn_new, 1, examples, n_iterations,
289
+ batch_size=batch_size, seed=seed)
290
+
291
+ return pred_corrs[0]
@@ -0,0 +1,89 @@
1
+ from scipy.optimize import leastsq
2
+ import numpy as np
3
+
4
+ def err_fn_sin(p,x,y):
5
+ return (y-fit_fn_sin(x,*p)).flat
6
+
7
+ def err_fn_lin(p,x,y):
8
+ return (y-fit_fn_lin(x,*p)).flat
9
+
10
+ def fit_fn_lin(x,*kwargs):
11
+ return kwargs[0]+kwargs[1]*x
12
+
13
+ def fit_fn_sin(x,*kwargs):
14
+ freqs = kwargs[0]
15
+ amps = kwargs[1]
16
+ phases = kwargs[2]
17
+ offset = kwargs[3]
18
+ sig = np.zeros((len(x)))+offset
19
+ sig += amps*np.cos(x*freqs+phases)
20
+ return sig
21
+
22
+ def signal_fit(signals,fs):
23
+ """Fits sinusoid and linear function to signals
24
+ see sinfit.fit_fn_sin and sinfit.fit_fn_lin
25
+
26
+ Parameters
27
+ ----------
28
+ signals : numpy array
29
+ [FxCxTx1] Filters x Channels x Time x 1
30
+ fs : float
31
+ Sampling frequency
32
+
33
+ Returns
34
+ -------
35
+ params_sin : numpy array
36
+ [FxCx4] Parameters of sinusoid fit
37
+ Parameters are: Frequency,Amplitude,Phase,DCOffset
38
+ params_lin : numpy array
39
+ [FxCx2] Parameters of sinusoid fit
40
+ Parameters are: Frequency,Amplitude,Phase,DCOffset
41
+ err_sin : numpy array
42
+ [FxCx1] MSE for sinusoid fit
43
+ err_lin : numpy array
44
+ [FxCx1] MSE for linear fit
45
+ """
46
+ params_sin = []
47
+ params_lin = []
48
+
49
+ err_sin = []
50
+ err_lin = []
51
+
52
+ freqs = np.fft.rfftfreq(signals.shape[2], d=1.0/fs)[1:]
53
+ x = np.linspace(0,signals.shape[2]/fs,signals.shape[2])*2*np.pi
54
+ for filt in range(signals.shape[0]):
55
+ params_sin_tmp = []
56
+ params_lin_tmp = []
57
+
58
+ err_sin_tmp = []
59
+ err_lin_tmp = []
60
+ for ch in range(signals.shape[1]):
61
+ X_tmp = signals[filt,ch].squeeze()
62
+ fft_X = np.fft.rfft(X_tmp,axis=0)
63
+ amps_mean = np.abs(fft_X)[1:]
64
+ phases_mean = np.angle(fft_X)[1:]
65
+ offset = X_tmp.mean()
66
+
67
+ sort = np.argsort(amps_mean)[::-1][0]
68
+ p0 = [freqs[sort],amps_mean[sort],phases_mean[sort],offset]
69
+
70
+ fit_sin_ch = leastsq(err_fn_sin, p0, args=(x, X_tmp),maxfev=100000)
71
+ fit_lin_ch = leastsq(err_fn_lin, [0,0], args=(x, X_tmp),maxfev=100000)
72
+
73
+ err_sin_ch = np.square(fit_fn_sin(x,*fit_sin_ch[0]) - X_tmp).mean()
74
+ err_lin_ch = np.square(fit_fn_lin(x,*fit_lin_ch[0]) - X_tmp).mean()
75
+
76
+ params_sin_tmp.append(fit_sin_ch[0])
77
+ params_lin_tmp.append(fit_lin_ch[0])
78
+ err_sin_tmp.append(err_sin_ch)
79
+ err_lin_tmp.append(err_lin_ch)
80
+ params_sin.append(params_sin_tmp)
81
+ params_lin.append(params_lin_tmp)
82
+ err_sin.append(err_sin_tmp)
83
+ err_lin.append(err_lin_tmp)
84
+ params_sin = np.asarray(params_sin)
85
+ params_lin = np.asarray(params_lin)
86
+ err_sin = np.asarray(err_sin)
87
+ err_lin = np.asarray(err_lin)
88
+
89
+ return params_sin,params_lin,err_sin,err_lin
@@ -553,24 +553,6 @@
553
553
  "## Plot correlations"
554
554
  ]
555
555
  },
556
- {
557
- "cell_type": "markdown",
558
- "metadata": {},
559
- "source": [
560
- "Compute the mean correlations across iterations."
561
- ]
562
- },
563
- {
564
- "cell_type": "code",
565
- "execution_count": 8,
566
- "metadata": {
567
- "collapsed": true
568
- },
569
- "outputs": [],
570
- "source": [
571
- "mean_corr = np.mean(amp_pred_corrs, axis=0)"
572
- ]
573
- },
574
556
  {
575
557
  "cell_type": "markdown",
576
558
  "metadata": {},
@@ -738,21 +720,21 @@
738
720
  "keep_outputs": true
739
721
  },
740
722
  "kernelspec": {
741
- "display_name": "Python 3",
723
+ "display_name": "Python 2",
742
724
  "language": "python",
743
- "name": "python3"
725
+ "name": "python2"
744
726
  },
745
727
  "language_info": {
746
728
  "codemirror_mode": {
747
729
  "name": "ipython",
748
- "version": 3
730
+ "version": 2
749
731
  },
750
732
  "file_extension": ".py",
751
733
  "mimetype": "text/x-python",
752
734
  "name": "python",
753
735
  "nbconvert_exporter": "python",
754
- "pygments_lexer": "ipython3",
755
- "version": "3.6.2"
736
+ "pygments_lexer": "ipython2",
737
+ "version": "2.7.13"
756
738
  }
757
739
  },
758
740
  "nbformat": 4,
@@ -9,6 +9,14 @@ braindecode\.visualization package
9
9
  Submodules
10
10
  ----------
11
11
 
12
+ braindecode\.visualization\.input\_windows module
13
+ -------------------------------------------------
14
+
15
+ .. automodule:: braindecode.visualization.input_windows
16
+ :members:
17
+ :undoc-members:
18
+ :show-inheritance:
19
+
12
20
  braindecode\.visualization\.perturbation module
13
21
  -----------------------------------------------
14
22
 
@@ -25,4 +33,12 @@ braindecode\.visualization\.plot module
25
33
  :undoc-members:
26
34
  :show-inheritance:
27
35
 
36
+ braindecode\.visualization\.sinfit module
37
+ -----------------------------------------
38
+
39
+ .. automodule:: braindecode.visualization.sinfit
40
+ :members:
41
+ :undoc-members:
42
+ :show-inheritance:
43
+
28
44
 
@@ -1,5 +1,4 @@
1
1
  [egg_info]
2
2
  tag_build =
3
3
  tag_date = 0
4
- tag_svn_revision = 0
5
4
 
@@ -1 +0,0 @@
1
- __version__ = "0.3.1"
@@ -1,116 +0,0 @@
1
- import logging
2
-
3
- import numpy as np
4
- from numpy.random import RandomState
5
-
6
- from braindecode.datautil.iterators import get_balanced_batches
7
- from braindecode.util import wrap_reshape_apply_fn, corr
8
-
9
- log = logging.getLogger(__name__)
10
-
11
-
12
- def gaussian_perturbation(amps, rng):
13
- """
14
- Create gaussian noise tensor with same shape as amplitudes.
15
-
16
- Parameters
17
- ----------
18
- amps: ndarray
19
- Amplitudes.
20
- rng: RandomState
21
- Random generator.
22
-
23
- Returns
24
- -------
25
- perturbation: ndarray
26
- Perturbations to add to the amplitudes.
27
- """
28
- perturbation = rng.randn(*amps.shape).astype(np.float32)
29
- return perturbation
30
-
31
-
32
- def compute_amplitude_prediction_correlations(pred_fn, examples, n_iterations,
33
- perturb_fn=gaussian_perturbation,
34
- batch_size=30,
35
- seed=((2017, 7, 10))):
36
- """
37
- Perturb input amplitudes and compute correlation between amplitude
38
- perturbations and prediction changes when pushing perturbed input through
39
- the prediction function.
40
-
41
- For more details, see [EEGDeepLearning]_.
42
-
43
- Parameters
44
- ----------
45
- pred_fn: function
46
- Function accepting an numpy input and returning prediction.
47
- examples: ndarray
48
- Numpy examples, first axis should be example axis.
49
- n_iterations: int
50
- Number of iterations to compute.
51
- perturb_fn: function, optional
52
- Function accepting amplitude array and random generator and returning
53
- perturbation. Default is Gaussian perturbation.
54
- batch_size: int, optional
55
- Batch size for computing predictions.
56
- seed: int, optional
57
- Random generator seed
58
-
59
- Returns
60
- -------
61
- amplitude_pred_corrs: ndarray
62
- Correlations between amplitude perturbations and prediction changes
63
- for all sensors and frequency bins.
64
-
65
- References
66
- ----------
67
-
68
- .. [EEGDeepLearning] Schirrmeister, R. T., Springenberg, J. T., Fiederer, L. D. J.,
69
- Glasstetter, M., Eggensperger, K., Tangermann, M., ... & Ball, T. (2017).
70
- Deep learning with convolutional neural networks for EEG decoding and
71
- visualization.
72
- arXiv preprint arXiv:1703.05051.
73
- """
74
- inds_per_batch = get_balanced_batches(
75
- n_trials=len(examples), rng=None, shuffle=False, batch_size=batch_size)
76
- log.info("Compute original predictions...")
77
- orig_preds = [pred_fn(examples[example_inds])
78
- for example_inds in inds_per_batch]
79
- orig_preds_arr = np.concatenate(orig_preds)
80
- rng = RandomState(seed)
81
- fft_input = np.fft.rfft(examples, axis=2)
82
- amps = np.abs(fft_input)
83
- phases = np.angle(fft_input)
84
-
85
- amp_pred_corrs = []
86
- for i_iteration in range(n_iterations):
87
- log.info("Iteration {:d}...".format(i_iteration))
88
- log.info("Sample perturbation...")
89
- perturbation = perturb_fn(amps, rng)
90
- log.info("Compute new amplitudes...")
91
- # do not allow perturbation to make amplitudes go below
92
- # zero
93
- perturbation = np.maximum(-amps, perturbation)
94
- new_amps = amps + perturbation
95
- log.info("Compute new complex inputs...")
96
- new_complex = _amplitude_phase_to_complex(new_amps, phases)
97
- log.info("Compute new real inputs...")
98
- new_in = np.fft.irfft(new_complex, axis=2).astype(np.float32)
99
- log.info("Compute new predictions...")
100
- new_preds = [pred_fn(new_in[example_inds])
101
- for example_inds in inds_per_batch]
102
-
103
- new_preds_arr = np.concatenate(new_preds)
104
-
105
- diff_preds = new_preds_arr - orig_preds_arr
106
-
107
- log.info("Compute correlation...")
108
- amp_pred_corr = wrap_reshape_apply_fn(corr, perturbation[:, :, :, 0],
109
- diff_preds,
110
- axis_a=(0,), axis_b=(0))
111
- amp_pred_corrs.append(amp_pred_corr)
112
- return amp_pred_corrs
113
-
114
-
115
- def _amplitude_phase_to_complex(amplitude, phase):
116
- return amplitude * np.cos(phase) + amplitude * np.sin(phase) * 1j
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes