def get_corr_coef(dataset, model): len = int(dataset.X.shape[0] / 2) print(len) with torch.no_grad(): if cuda: outs1 = model.double()(np_to_var(dataset.X[:len]).cuda()) outs2 = model.double()(np_to_var(dataset.X[len:]).cuda()) # outs = model.float()(np_to_var(dataset.X).float().cuda()) else: # outs = model(np_to_var(dataset.X).double()) outs = model.double()(np_to_var(dataset.X)) all_y = np.array(dataset.y) if cuda: preds1 = var_to_np(outs1) preds2 = var_to_np(outs2) preds = np.concatenate([preds1, preds2]) # preds = var_to_np(outs) print(preds.shape) else: preds = var_to_np(outs) preds_flat = np.concatenate(preds) y_flat = np.concatenate(all_y[:, -preds.shape[1]:]) # corrcoef = np.corrcoef(np.abs(y_flat), np.abs(preds_flat))[0, 1] corrcoef = np.corrcoef(y_flat, preds_flat)[0, 1] return corrcoef
def get_outs(batch_X, new_model, outs_shape=None, grad_type='amps'): """gets output of the network when signal with amplitudes and frequencies is given on input""" iffted, amps_th, phases_th = calculate_phase_and_amps(batch_X) if cuda: outs = new_model(iffted.double().cuda()) else: outs = new_model(iffted.double()) assert outs.shape[1] == 1 if outs_shape is not None: mean_out = get_outs_shape(outs_shape, outs) else: mean_out = torch.mean(outs) mean_out.backward(retain_graph=True) amp_grads = var_to_np(amps_th.grad).squeeze(-1) phase_grads = var_to_np(phases_th.grad).squeeze(-1) if grad_type == 'amps': return amp_grads, outs else: return phase_grads, outs
def test_trialwise_decoding(): # 5,6,7,10,13,14 are codes for executed and imagined hands/feet subject_id = 1 event_codes = [5, 6, 9, 10, 13, 14] # This will download the files if you don't have them yet, # and then return the paths to the files. physionet_paths = mne.datasets.eegbci.load_data( subject_id, event_codes, update_path=False ) # Load each of the files parts = [ mne.io.read_raw_edf( path, preload=True, stim_channel="auto", verbose="WARNING" ) for path in physionet_paths ] # Concatenate them raw = concatenate_raws(parts) # Find the events in this dataset events, _ = mne.events_from_annotations(raw) # Use only EEG channels eeg_channel_inds = mne.pick_types( raw.info, meg=False, eeg=True, stim=False, eog=False, exclude="bads" ) # Extract trials, only using EEG channels epoched = mne.Epochs( raw, events, dict(hands=2, feet=3), tmin=1, tmax=4.1, proj=False, picks=eeg_channel_inds, baseline=None, preload=True, ) # Convert data from volt to millivolt # Pytorch expects float32 for input and int64 for labels. X = (epoched.get_data() * 1e6).astype(np.float32) y = (epoched.events[:, 2] - 2).astype(np.int64) # 2,3 -> 0,1 SignalAndTarget = namedtuple("SignalAndTarget", "X y") train_set = SignalAndTarget(X[:60], y=y[:60]) test_set = SignalAndTarget(X[60:], y=y[60:]) # Set if you want to use GPU # You can also use torch.cuda.is_available() to determine if cuda is available on your machine. cuda = False set_random_seeds(seed=20170629, cuda=cuda) n_classes = 2 in_chans = train_set.X.shape[1] # final_conv_length = auto ensures we only get a single output in the time dimension model = ShallowFBCSPNet( in_chans=in_chans, n_classes=n_classes, input_time_length=train_set.X.shape[2], final_conv_length="auto", ) if cuda: model.cuda() optimizer = optim.Adam(model.parameters()) rng = RandomState((2017, 6, 30)) losses = [] accuracies = [] for i_epoch in range(6): i_trials_in_batch = get_balanced_batches( len(train_set.X), rng, shuffle=True, batch_size=30 ) # Set model to training mode model.train() for i_trials in i_trials_in_batch: # Have to add empty fourth dimension to X batch_X = train_set.X[i_trials][:, :, :, None] batch_y = train_set.y[i_trials] net_in = np_to_var(batch_X) if cuda: net_in = net_in.cuda() net_target = np_to_var(batch_y) if cuda: net_target = net_target.cuda() # Remove gradients of last backward pass from all parameters optimizer.zero_grad() # Compute outputs of the network outputs = model(net_in) # Compute the loss loss = F.nll_loss(outputs, net_target) # Do the backpropagation loss.backward() # Update parameters with the optimizer optimizer.step() # Print some statistics each epoch model.eval() print("Epoch {:d}".format(i_epoch)) for setname, dataset in (("Train", train_set), ("Test", test_set)): # Here, we will use the entire dataset at once, which is still possible # for such smaller datasets. Otherwise we would have to use batches. net_in = np_to_var(dataset.X[:, :, :, None]) if cuda: net_in = net_in.cuda() net_target = np_to_var(dataset.y) if cuda: net_target = net_target.cuda() outputs = model(net_in) loss = F.nll_loss(outputs, net_target) losses.append(float(var_to_np(loss))) print("{:6s} Loss: {:.5f}".format(setname, float(var_to_np(loss)))) predicted_labels = np.argmax(var_to_np(outputs), axis=1) accuracy = np.mean(dataset.y == predicted_labels) accuracies.append(accuracy * 100) print("{:6s} Accuracy: {:.1f}%".format(setname, accuracy * 100)) np.testing.assert_allclose( np.array(losses), np.array( [ 0.91796708, 1.2714895, 0.4999536, 0.94365239, 0.39268905, 0.89928466, 0.37648854, 0.8940345, 0.35774994, 0.86749417, 0.35080773, 0.80767328, ] ), rtol=1e-4, atol=1e-5, ) np.testing.assert_allclose( np.array(accuracies), np.array( [ 55.0, 63.33333333, 71.66666667, 63.33333333, 81.66666667, 60.0, 78.33333333, 63.33333333, 83.33333333, 66.66666667, 80.0, 66.66666667, ] ), rtol=1e-4, atol=1e-5, )
def test_cropped_decoding(): # 5,6,7,10,13,14 are codes for executed and imagined hands/feet subject_id = 1 event_codes = [5, 6, 9, 10, 13, 14] # This will download the files if you don't have them yet, # and then return the paths to the files. physionet_paths = mne.datasets.eegbci.load_data(subject_id, event_codes, update_path=True) # Load each of the files parts = [ mne.io.read_raw_edf(path, preload=True, stim_channel='auto', verbose='WARNING') for path in physionet_paths ] # Concatenate them raw = concatenate_raws(parts) # Find the events in this dataset events, _ = mne.events_from_annotations(raw) # Use only EEG channels eeg_channel_inds = mne.pick_types(raw.info, meg=False, eeg=True, stim=False, eog=False, exclude='bads') # Extract trials, only using EEG channels epoched = mne.Epochs(raw, events, dict(hands=2, feet=3), tmin=1, tmax=4.1, proj=False, picks=eeg_channel_inds, baseline=None, preload=True) # Convert data from volt to millivolt # Pytorch expects float32 for input and int64 for labels. X = (epoched.get_data() * 1e6).astype(np.float32) y = (epoched.events[:, 2] - 2).astype(np.int64) # 2,3 -> 0,1 train_set = SignalAndTarget(X[:60], y=y[:60]) test_set = SignalAndTarget(X[60:], y=y[60:]) # Set if you want to use GPU # You can also use torch.cuda.is_available() to determine if cuda is available on your machine. cuda = False set_random_seeds(seed=20170629, cuda=cuda) # This will determine how many crops are processed in parallel input_time_length = 450 n_classes = 2 in_chans = train_set.X.shape[1] # final_conv_length determines the size of the receptive field of the ConvNet model = ShallowFBCSPNet(in_chans=in_chans, n_classes=n_classes, input_time_length=input_time_length, final_conv_length=12).create_network() to_dense_prediction_model(model) if cuda: model.cuda() optimizer = optim.Adam(model.parameters()) # determine output size test_input = np_to_var( np.ones((2, in_chans, input_time_length, 1), dtype=np.float32)) if cuda: test_input = test_input.cuda() out = model(test_input) n_preds_per_input = out.cpu().data.numpy().shape[2] print("{:d} predictions per input/trial".format(n_preds_per_input)) iterator = CropsFromTrialsIterator(batch_size=32, input_time_length=input_time_length, n_preds_per_input=n_preds_per_input) losses = [] accuracies = [] for i_epoch in range(4): # Set model to training mode model.train() for batch_X, batch_y in iterator.get_batches(train_set, shuffle=False): net_in = np_to_var(batch_X) if cuda: net_in = net_in.cuda() net_target = np_to_var(batch_y) if cuda: net_target = net_target.cuda() # Remove gradients of last backward pass from all parameters optimizer.zero_grad() outputs = model(net_in) # Mean predictions across trial # Note that this will give identical gradients to computing # a per-prediction loss (at least for the combination of log softmax activation # and negative log likelihood loss which we are using here) outputs = th.mean(outputs, dim=2, keepdim=False) loss = F.nll_loss(outputs, net_target) loss.backward() optimizer.step() # Print some statistics each epoch model.eval() print("Epoch {:d}".format(i_epoch)) for setname, dataset in (('Train', train_set), ('Test', test_set)): # Collect all predictions and losses all_preds = [] all_losses = [] batch_sizes = [] for batch_X, batch_y in iterator.get_batches(dataset, shuffle=False): net_in = np_to_var(batch_X) if cuda: net_in = net_in.cuda() net_target = np_to_var(batch_y) if cuda: net_target = net_target.cuda() outputs = model(net_in) all_preds.append(var_to_np(outputs)) outputs = th.mean(outputs, dim=2, keepdim=False) loss = F.nll_loss(outputs, net_target) loss = float(var_to_np(loss)) all_losses.append(loss) batch_sizes.append(len(batch_X)) # Compute mean per-input loss loss = np.mean( np.array(all_losses) * np.array(batch_sizes) / np.mean(batch_sizes)) print("{:6s} Loss: {:.5f}".format(setname, loss)) losses.append(loss) # Assign the predictions to the trials preds_per_trial = compute_preds_per_trial_from_crops( all_preds, input_time_length, dataset.X) # preds per trial are now trials x classes x timesteps/predictions # Now mean across timesteps for each trial to get per-trial predictions meaned_preds_per_trial = np.array( [np.mean(p, axis=1) for p in preds_per_trial]) predicted_labels = np.argmax(meaned_preds_per_trial, axis=1) accuracy = np.mean(predicted_labels == dataset.y) accuracies.append(accuracy * 100) print("{:6s} Accuracy: {:.1f}%".format(setname, accuracy * 100)) np.testing.assert_allclose(np.array(losses), np.array([ 1.31657708, 1.73548156, 1.02950428, 1.43932164, 0.78677772, 1.12382019, 0.55920881, 0.87277424 ]), rtol=1e-4, atol=1e-5) np.testing.assert_allclose(np.array(accuracies), np.array([ 50., 46.66666667, 50., 46.66666667, 50., 46.66666667, 66.66666667, 50. ]), rtol=1e-4, atol=1e-5)
def pred_fn(x): return var_to_np( th.mean( new_model(np_to_var(x).cuda())[:, :, :, 0], dim=2, keepdim=False ) )
def get_module_gradients(model, module_name, X_reshaped, small_window): print("Module {:s}...".format(module_name)) ## Create new model new_model = torch.nn.Sequential() found_selected = False for name, child in model.named_children(): new_model.add_module(name, child) if name == module_name: found_selected = True break assert found_selected # Batch through X for GPU memory reasons print("Computing gradients...") with torch.no_grad(): if cuda: test_out = new_model(np_to_var(X_reshaped[:2]).cuda()) else: test_out = new_model(np_to_var(X_reshaped[:2])) n_filters = test_out.shape[1] n_preds = test_out.shape[2] print('test out shape:', test_out.shape) if small_window is None: small_window = min((input_time_length - n_preds) * 2, 1200) new_X_reshaped = X_reshaped[:, :, :small_window, :] # filters x windows x channels x freqs all_amp_grads = np.ones( (n_filters, ) + new_X_reshaped.shape[:2] + (len(np.fft.rfftfreq(new_X_reshaped.shape[2], d=1 / 250.0)), ), dtype=np.float32) * np.nan # all_phases_grads = np.ones( # (n_filters,) + new_X_reshaped.shape[:2] + (len(np.fft.rfftfreq(new_X_reshaped.shape[2], d=1 / 250.0)),), # dtype=np.float32) * np.nan i_start = 0 print('small window:', small_window) for batch_X in np.array_split(new_X_reshaped, 5): iffted, amps_th, phases_th = calculate_phase_and_amps(batch_X) if cuda: outs = new_model(iffted.double().cuda()) else: outs = new_model(iffted.double()) assert outs.shape[1] == n_filters print('model outputs shape:', outs.shape) for i_filter in range(n_filters): mean_out = torch.mean(outs[:, i_filter]) mean_out.backward(retain_graph=True) amp_grads = var_to_np(amps_th.grad) # print(amp_grads.shape) all_amp_grads[i_filter, i_start:i_start + len(amp_grads)] = amp_grads.squeeze(-1) phases_grads = var_to_np(phases_th.grad) # print(phases_grads.shape) # all_phases_grads[i_filter, i_start:i_start + len(phases_grads)] = phases_grads.squeeze(-1) amps_th.grad.zero_() phases_th.grad.zero_() i_start += len(amp_grads) del amp_grads # just make sure I don't use it accidentally now del phases_grads # just make sure I don't use it accidentally now assert i_start == all_amp_grads.shape[1] assert not np.any(np.isnan(all_amp_grads)) # assert i_start == all_phases_grads.shape[1] # assert not np.any(np.isnan(all_phases_grads)) # mean across windows meaned_amp_grads = np.mean(all_amp_grads, axis=1) # meaned_phase_grads = np.mean(all_phases_grads, axis=1) meaned_phase_grads = None # phase_grads_list.append(meaned_phase_grads) # amp_grads_list.append(meaned_amp_grads) print('grads shape:', meaned_amp_grads.shape) return meaned_amp_grads, meaned_phase_grads, small_window
def manually_manipulate_signal(X_reshaped, output, model, maxpool_model=False, white_noise=True): """ Adds a certain frequencies or white noise to the signal in X_reshaped Plots how the output of the network changes with this added frequency. """ if white_noise: freqs = ['white_noise'] else: freqs = (250 / 3, 60, 40, 250 / (3**2), 250 / (3**3)) for freq in freqs: with torch.no_grad(): batch_X = X_reshaped[:1] if maxpool_model: outs = model(np_to_var(batch_X)) outs = np.mean(np.asarray(outs), axis=1) else: outs = model(np_to_var(batch_X)) if white_noise: sine = np.random.normal(0, 1, batch_X.shape[2]) else: sine = np.sin( np.linspace(0, freq * np.pi * 2 * batch_X.shape[2] / 250, batch_X.shape[2])) changed_X = batch_X + sine[None, None, :, None] * 0.5 if maxpool_model: changed_outs = np.mean(np.asarray( model(np_to_var(changed_X, dtype=np.float32).double())), axis=1) else: changed_outs = model(np_to_var(changed_X)) plt.figure(figsize=(16, 4)) plt.plot(batch_X[0, 0, 1:250, 0], ) plt.plot(changed_X[0, 0, 1:250, 0]) plt.legend(("Original X", "Changed X")) plt.xlabel("Timestep") if not white_noise: freq = f'{freq:.2f}' plt.title(f"Frequency {freq} Hz") plt.tight_layout() plt.savefig(f'{output}/mm_original_and_changed_{freq}Hz.png', format='png') plt.show() plt.figure(figsize=(16, 4)) if maxpool_model: plt.plot(np.squeeze(outs)) plt.plot(np.squeeze(changed_outs)) else: plt.plot(var_to_np(outs.squeeze())) plt.plot(var_to_np(changed_outs.squeeze())) plt.legend(("Original out", "Changed out")) plt.xlabel("Timestep") plt.title(f"Frequency {freq} Hz") plt.tight_layout() plt.savefig(f'{output}/mm_original_out_and_changed_out_{freq}Hz.png') plt.show() plt.figure(figsize=(16, 4)) if maxpool_model: plt.plot(np.squeeze(changed_outs) - np.squeeze(outs)) else: plt.plot( var_to_np(changed_outs.squeeze()) - var_to_np(outs.squeeze())) plt.plot(sine[-len(outs.squeeze()):] * 0.4) plt.legend(("Out diff", "Added sine last part")) plt.title(f"Frequency {freq} Hz") plt.tight_layout() plt.savefig(f'{output}/mm_output_original_difference_time{freq}Hz.png') plt.xlabel("Timestep") plt.show() plt.figure(figsize=(16, 4)) if maxpool_model: plt.plot( np.fft.rfftfreq(len(np.squeeze(outs)), 1 / 250.0), np.abs( np.fft.rfft(np.squeeze(changed_outs) - np.squeeze(outs)))) # plt.plot(np.fft.rfftfreq(len(np.squeeze(changed_outs)), 1 / 250.0)[1:], # np.abs(np.fft.rfft(sine[-len(np.squeeze(outs)):] * 0.4))[1:]) else: plt.plot( np.fft.rfftfreq(len(np.squeeze(outs)), 1 / 250.0), np.abs( np.fft.rfft(np.squeeze(changed_outs) - np.squeeze(outs)))) # plt.plot(np.fft.rfftfreq(len(np.squeeze(changed_outs)), 1 / 250.0)[1:], # np.abs(np.fft.rfft(sine[-len(np.squeeze(outs)):] * 0.4))[1:]) plt.legend(("Out diff", "Added sine last part")) plt.xlabel("Frequency [Hz]") plt.title(f"Frequency {freq} Hz") plt.tight_layout() plt.savefig( f'{output}/mm_output_original_difference_time_frequency_{freq}Hz.png' ) plt.show()