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 test_input(input_channels, model): test_input = np_to_var( np.ones((2, input_channels, input_time_length, 1), dtype=np.float32)) print(test_input.shape) out = model(test_input.double()) n_preds_per_input = out.cpu().data.numpy().shape[1] return n_preds_per_input, test_input
def calculate_phase_and_amps(batch_X): """ Hooks the amplitude and phase of the signal in batch_X :param batch_X: one training batch :return: returns the original signal with hooked amplitudes and phases """ ffted = np.fft.rfft(batch_X, axis=2) amps = np.abs(ffted) phases = np.angle(ffted) amps_th = np_to_var(amps, requires_grad=True, dtype=np.float32) phases_th = np_to_var(phases, requires_grad=True, dtype=np.float32) fft_coefs = amps_th.unsqueeze(-1) * torch.stack( (torch.cos(phases_th), torch.sin(phases_th)), dim=-1) fft_coefs = fft_coefs.squeeze(3) iffted = torch.irfft(fft_coefs, signal_ndim=1, signal_sizes=(batch_X.shape[2], )).unsqueeze(-1) return iffted, amps_th, phases_th
def __init__(self, chn_num, class_num, wind, blocks): super().__init__() self.blocks = blocks self.chn_num = chn_num self.class_num = class_num self.wind = wind self.conv_time = nn.Conv2d(1, 64, kernel_size=(1, 50), stride=(1, 1)) self.conv_spatial = nn.Conv2d(64, 50, kernel_size=(self.chn_num, 1), stride=(1, 1), bias=False) self.bn1 = nn.BatchNorm2d(50, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True) self.nonlinear1 = nn.ELU() self.mp1 = nn.MaxPool2d(kernel_size=(1, 3), stride=(1, 3), padding=0, dilation=1, ceil_mode=False) self.drop1 = nn.Dropout(p=0.5, inplace=False) self.seq = nn.Sequential( nn.Conv2d(50, 50, kernel_size=(1, 10), stride=(1, 1), bias=False), nn.BatchNorm2d(50, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True), nn.ELU(), nn.Dropout(p=0.5, inplace=False)) self.block_seq = [] for b in range(self.blocks): self.block_seq.append([]) self.block_seq[b] = self.seq self.seq = nn.Sequential(self.conv_time, self.drop0, self.conv_spatial, self.bn1, self.nonlinear1, self.mp1, self.drop1, *self.block_seq) out = self.seq( np_to_var( np.ones((1, 1, self.chn_num, self.wind), dtype=np.float32))) len = out.shape[3] self.ap = nn.AvgPool2d(kernel_size=(1, len), stride=(1, len), padding=0) self.final_linear = nn.Linear(in_features=50, out_features=self.class_num, bias=True)
freqs = np.fft.rfftfreq(new_train_set.shape[2], d=1 / 250.) history = History() history = history.from_file( home + '/logs/model_1_lr_0.001/histories/history_{last_epoch[epoch]}.json') plot_history(history, None) correlation_monitor = CorrelationMonitor1D( input_time_length=input_time_length, setname='idk') all_preds = [] all_targets = [] dataset = test_set for X, y in zip(train_set.X, train_set.y): preds = model(np_to_var(X).double()) all_preds.append(preds) all_targets.append(y) preds_2d = [p[:, None] for p in all_preds] preds_per_trial = correlation_monitor.compute_preds_per_trial_from_crops( preds_2d, input_time_length, dataset.X)[0][0] ys_2d = [y[:, None] for y in all_targets] targets_per_trial = correlation_monitor.compute_preds_per_trial_from_crops( ys_2d, input_time_length, dataset.X)[0][0] assert preds_per_trial.shape == targets_per_trial.shape pred_vals = [] resp_vals = [] cc_folds = np.corrcoef(preds_per_trial, targets_per_trial)[0, 1]
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 __init__( self, in_chans, n_classes, input_window_samples, final_conv_length, n_filters_time=64, n_filters_spat=64, filter_time_length=50, pool_time_length=3, pool_time_stride=3, n_filters_2=50, filter_length_2=10, n_filters_3=50, filter_length_3=10, n_filters_4=50, filter_length_4=10, first_nonlin=elu, first_pool_mode="max", first_pool_nonlin=identity, later_nonlin=elu, later_pool_mode="max", later_pool_nonlin=identity, drop_prob=0.5, double_time_convs=False, split_first_layer=True, batch_norm=True, batch_norm_alpha=0.1, stride_before_pool=False, ): super().__init__() if final_conv_length == "auto": assert input_window_samples is not None self.in_chans = in_chans self.n_classes = n_classes self.input_window_samples = input_window_samples self.final_conv_length = final_conv_length self.n_filters_time = n_filters_time self.n_filters_spat = n_filters_spat self.filter_time_length = filter_time_length self.pool_time_length = pool_time_length self.pool_time_stride = pool_time_stride self.n_filters_2 = n_filters_2 self.filter_length_2 = filter_length_2 self.n_filters_3 = n_filters_3 self.filter_length_3 = filter_length_3 self.n_filters_4 = n_filters_4 self.filter_length_4 = filter_length_4 self.first_nonlin = first_nonlin self.first_pool_mode = first_pool_mode self.first_pool_nonlin = first_pool_nonlin self.later_nonlin = later_nonlin self.later_pool_mode = later_pool_mode self.later_pool_nonlin = later_pool_nonlin self.drop_prob = drop_prob self.double_time_convs = double_time_convs self.split_first_layer = split_first_layer self.batch_norm = batch_norm self.batch_norm_alpha = batch_norm_alpha self.stride_before_pool = stride_before_pool if self.stride_before_pool: conv_stride = self.pool_time_stride pool_stride = 1 else: conv_stride = 1 pool_stride = self.pool_time_stride self.add_module("Add_dim", expand_dim()) pool_class_dict = dict(max=nn.MaxPool2d, mean=AvgPool2dWithConv) first_pool_class = pool_class_dict[self.first_pool_mode] later_pool_class = pool_class_dict[self.later_pool_mode] if self.split_first_layer: self.add_module("dimshuffle", Expression(swap_time_spat)) self.add_module( "conv_time", nn.Conv2d( 1, self.n_filters_time, (self.filter_time_length, 1), stride=1, ), ) self.add_module( "conv_spat", nn.Conv2d( self.n_filters_time, self.n_filters_spat, (1, self.in_chans), stride=(conv_stride, 1), bias=not self.batch_norm, ), ) n_filters_conv = self.n_filters_spat else: self.add_module( "conv_time", nn.Conv2d( self.in_chans, self.n_filters_time, (self.filter_time_length, 1), stride=(conv_stride, 1), bias=not self.batch_norm, ), ) n_filters_conv = self.n_filters_time if self.batch_norm: self.add_module( "bnorm", nn.BatchNorm2d( n_filters_conv, momentum=self.batch_norm_alpha, affine=True, eps=1e-5, ), ) self.add_module("conv_nonlin", Expression(self.first_nonlin)) #elu self.add_module( "pool", first_pool_class(kernel_size=(self.pool_time_length, 1), stride=(pool_stride, 1)), ) #MaxPool2d #self.add_module("pool_nonlin", Expression(self.first_pool_nonlin)) # identity def add_conv_pool_block(model, n_filters_before, n_filters, filter_length, block_nr): suffix = "_{:d}".format(block_nr) self.add_module("drop" + suffix, nn.Dropout(p=self.drop_prob)) self.add_module( "conv" + suffix, nn.Conv2d( n_filters_before, n_filters, (filter_length, 1), stride=(conv_stride, 1), bias=not self.batch_norm, ), ) if self.batch_norm: self.add_module( "bnorm" + suffix, nn.BatchNorm2d( n_filters, momentum=self.batch_norm_alpha, affine=True, eps=1e-5, ), ) self.add_module("nonlin" + suffix, Expression(self.later_nonlin)) # elu # maxpool2d #self.add_module("pool" + suffix,later_pool_class(kernel_size=(self.pool_time_length, 1),stride=(pool_stride, 1),),) #Expression(expression=identity) #self.add_module("pool_nonlin" + suffix, Expression(self.later_pool_nonlin)) # identity add_conv_pool_block(self, n_filters_conv, self.n_filters_2, self.filter_length_2, 2) add_conv_pool_block(self, self.n_filters_2, self.n_filters_3, self.filter_length_3, 3) add_conv_pool_block(self, self.n_filters_3, self.n_filters_4, self.filter_length_4, 4) self.add_module("last_drop", nn.Dropout(p=self.drop_prob)) # self.add_module('drop_classifier', nn.Dropout(p=self.drop_prob)) self.eval() if self.final_conv_length == "auto": out = self( np_to_var( np.ones( (1, self.in_chans, self.input_window_samples), dtype=np.float32, ))) n_channels = out.cpu().data.numpy().shape[1] n_out_time, n_out_spatial = out.cpu().data.numpy( ).shape[2], out.cpu().data.numpy().shape[3] self.final_conv_length = n_out_time #self.add_module("conv_classifier",nn.Conv2d(self.n_filters_4,self.n_classes,(self.final_conv_length, 1),bias=True,),) self.add_module("globalAvgPooling", nn.AvgPool2d((n_out_time, n_out_spatial))) self.add_module("squeeze1", Expression(squeeze_all)) self.add_module("conv_classifier", nn.Linear(n_channels, n_classes)) #self.add_module("softmax", nn.LogSoftmax(dim=1)) #self.add_module("squeeze2", Expression(squeeze_final_output)) # Initialization, xavier is same as in our paper... # was default from lasagne init.xavier_uniform_(self.conv_time.weight, gain=1) # maybe no bias in case of no split layer and batch norm if self.split_first_layer or (not self.batch_norm): init.constant_(self.conv_time.bias, 0) if self.split_first_layer: init.xavier_uniform_(self.conv_spat.weight, gain=1) if not self.batch_norm: init.constant_(self.conv_spat.bias, 0) if self.batch_norm: init.constant_(self.bnorm.weight, 1) init.constant_(self.bnorm.bias, 0) param_dict = dict(list(self.named_parameters())) for block_nr in range(2, 5): conv_weight = param_dict["conv_{:d}.weight".format(block_nr)] init.xavier_uniform_(conv_weight, gain=1) if not self.batch_norm: conv_bias = param_dict["conv_{:d}.bias".format(block_nr)] init.constant_(conv_bias, 0) else: bnorm_weight = param_dict["bnorm_{:d}.weight".format(block_nr)] bnorm_bias = param_dict["bnorm_{:d}.bias".format(block_nr)] init.constant_(bnorm_weight, 1) init.constant_(bnorm_bias, 0) init.xavier_uniform_(self.conv_classifier.weight, gain=1) init.constant_(self.conv_classifier.bias, 0) # Start in eval mode self.eval()
def test_experiment_class(): # 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) # 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:]) train_set, valid_set = split_into_two_sets(train_set, first_set_fraction=0.8) # 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 is used to iterate over datasets both for training # and evaluation iterator = CropsFromTrialsIterator(batch_size=32, input_time_length=input_time_length, n_preds_per_input=n_preds_per_input) # Loss function takes predictions as they come out of the network and the targets # and returns a loss def loss_function(preds, targets): return F.nll_loss(th.mean(preds, dim=2, keepdim=False), targets) # Could be used to apply some constraint on the models, then should be object # with apply method that accepts a module model_constraint = None # Monitors log the training progress monitors = [ LossMonitor(), MisclassMonitor(col_suffix='sample_misclass'), CroppedTrialMisclassMonitor(input_time_length), RuntimeMonitor(), ] # Stop criterion determines when the first stop happens stop_criterion = MaxEpochs(4) exp = Experiment(model, train_set, valid_set, test_set, iterator, loss_function, optimizer, model_constraint, monitors, stop_criterion, remember_best_column='valid_misclass', run_after_early_stop=True, batch_modifier=None, cuda=cuda) # need to setup python logging before to be able to see anything logging.basicConfig(format='%(asctime)s %(levelname)s : %(message)s', level=logging.DEBUG, stream=sys.stdout) exp.run() compare_df = pd.read_csv( StringIO( 'train_loss,valid_loss,test_loss,train_sample_misclass,valid_sample_misclass,' 'test_sample_misclass,train_misclass,valid_misclass,test_misclass\n' '14.167170524597168,13.910758018493652,15.945781707763672,0.5,0.5,' '0.5333333333333333,0.5,0.5,0.5333333333333333\n' '1.1735659837722778,1.4342904090881348,1.8664429187774658,0.4629567736185384,' '0.5120320855614973,0.5336007130124778,0.5,0.5,0.5333333333333333\n' '1.3168460130691528,1.60431969165802,1.9181344509124756,0.49298128342245995,' '0.5109180035650625,0.531729055258467,0.5,0.5,0.5333333333333333\n' '0.8465543389320374,1.280307412147522,1.439755916595459,0.4413435828877005,' '0.5461229946524064,0.5283422459893048,0.47916666666666663,0.5,' '0.5333333333333333\n0.6977059841156006,1.1762590408325195,1.2779350280761719,' '0.40290775401069523,0.588903743315508,0.5307486631016043,0.5,0.5,0.5\n' '0.7934166193008423,1.1762590408325195,1.2779350280761719,0.4401069518716577,' '0.588903743315508,0.5307486631016043,0.5,0.5,0.5\n0.5982189178466797,' '0.8581563830375671,0.9598925113677979,0.32032085561497325,0.47660427807486627,' '0.4672905525846702,0.31666666666666665,0.5,0.4666666666666667\n0.5044312477111816,' '0.7133197784423828,0.8164243102073669,0.2591354723707665,0.45699643493761144,' '0.4393048128342246,0.16666666666666663,0.41666666666666663,0.43333333333333335\n' '0.4815250039100647,0.6736412644386292,0.8016976714134216,0.23413547237076648,' '0.39505347593582885,0.42932263814616756,0.15000000000000002,0.41666666666666663,0.5\n' )) for col in compare_df: np.testing.assert_allclose(np.array(compare_df[col]), exp.epochs_df[col], rtol=1e-3, atol=1e-4)
def test_eeg_classifier(): # 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 # 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_window_samples = 450 n_classes = 2 in_chans = 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_window_samples=input_window_samples, final_conv_length=12, ) to_dense_prediction_model(model) if cuda: model.cuda() # determine output size test_input = np_to_var( np.ones((2, in_chans, input_window_samples, 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] train_set = create_from_X_y(X[:48], y[:48], drop_last_window=False, window_size_samples=input_window_samples, window_stride_samples=n_preds_per_input) valid_set = create_from_X_y(X[48:60], y[48:60], drop_last_window=False, window_size_samples=input_window_samples, window_stride_samples=n_preds_per_input) cropped_cb_train = CroppedTrialEpochScoring( "accuracy", name="train_trial_accuracy", lower_is_better=False, on_train=True, ) cropped_cb_valid = CroppedTrialEpochScoring( "accuracy", on_train=False, name="valid_trial_accuracy", lower_is_better=False, ) clf = EEGClassifier( model, cropped=True, criterion=CroppedLoss, criterion__loss_function=nll_loss, optimizer=optim.Adam, train_split=predefined_split(valid_set), batch_size=32, callbacks=[ ("train_trial_accuracy", cropped_cb_train), ("valid_trial_accuracy", cropped_cb_valid), ], ) clf.fit(train_set, y=None, epochs=4) expected = [{ 'batches': [{ 'train_batch_size': 32, 'train_loss': 1.6639312505722046 }, { 'train_batch_size': 32, 'train_loss': 2.6161606311798096 }, { 'train_batch_size': 32, 'train_loss': 1.627132773399353 }, { 'valid_batch_size': 24, 'valid_loss': 0.9677614569664001 }], 'epoch': 1, 'train_batch_count': 3, 'train_loss': 1.9690748850504558, 'train_loss_best': True, 'train_trial_accuracy': 0.4791666666666667, 'train_trial_accuracy_best': True, 'valid_batch_count': 1, 'valid_loss': 0.9677614569664001, 'valid_loss_best': True, 'valid_trial_accuracy': 0.5, 'valid_trial_accuracy_best': True }, { 'batches': [{ 'train_batch_size': 32, 'train_loss': 1.3829222917556763 }, { 'train_batch_size': 32, 'train_loss': 1.3123714923858643 }, { 'train_batch_size': 32, 'train_loss': 1.0109959840774536 }, { 'valid_batch_size': 24, 'valid_loss': 1.9435862302780151 }], 'epoch': 2, 'train_batch_count': 3, 'train_loss': 1.2354299227396648, 'train_loss_best': True, 'train_trial_accuracy': 0.5, 'train_trial_accuracy_best': True, 'valid_batch_count': 1, 'valid_loss': 1.9435862302780151, 'valid_loss_best': False, 'valid_trial_accuracy': 0.5, 'valid_trial_accuracy_best': False }, { 'batches': [{ 'train_batch_size': 32, 'train_loss': 1.172208547592163 }, { 'train_batch_size': 32, 'train_loss': 0.8899562954902649 }, { 'train_batch_size': 32, 'train_loss': 1.0232216119766235 }, { 'valid_batch_size': 24, 'valid_loss': 0.9585554599761963 }], 'epoch': 3, 'train_batch_count': 3, 'train_loss': 1.0284621516863506, 'train_loss_best': True, 'train_trial_accuracy': 0.5, 'train_trial_accuracy_best': False, 'valid_batch_count': 1, 'valid_loss': 0.9585554599761963, 'valid_loss_best': True, 'valid_trial_accuracy': 0.5, 'valid_trial_accuracy_best': False }, { 'batches': [{ 'train_batch_size': 32, 'train_loss': 0.9693693518638611 }, { 'train_batch_size': 32, 'train_loss': 0.900641918182373 }, { 'train_batch_size': 32, 'train_loss': 0.8839665651321411 }, { 'valid_batch_size': 24, 'valid_loss': 0.873468816280365 }], 'epoch': 4, 'train_batch_count': 3, 'train_loss': 0.9179926117261251, 'train_loss_best': True, 'train_trial_accuracy': 0.625, 'train_trial_accuracy_best': True, 'valid_batch_count': 1, 'valid_loss': 0.873468816280365, 'valid_loss_best': True, 'valid_trial_accuracy': 0.4166666666666667, 'valid_trial_accuracy_best': False }] history_without_dur = [{k: v for k, v in h.items() if k != "dur"} for h in clf.history] assert_deep_allclose(expected, history_without_dur, atol=1e-3, rtol=1e-3)
def test_eeg_classifier(): # 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 # 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 = 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, ) to_dense_prediction_model(model) if cuda: model.cuda() # 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] train_set = CroppedXyDataset(X[:60], y=y[:60], input_time_length=input_time_length, n_preds_per_input=n_preds_per_input) cropped_cb_train = CroppedTrialEpochScoring( "accuracy", name="train_trial_accuracy", lower_is_better=False, on_train=True, ) cropped_cb_valid = CroppedTrialEpochScoring( "accuracy", on_train=False, name="valid_trial_accuracy", lower_is_better=False, ) clf = EEGClassifier( model, criterion=CroppedNLLLoss, optimizer=optim.Adam, train_split=TrainTestSplit( train_size=0.8, input_time_length=input_time_length, n_preds_per_input=n_preds_per_input, ), batch_size=32, callbacks=[ ("train_trial_accuracy", cropped_cb_train), ("valid_trial_accuracy", cropped_cb_valid), ], ) clf.fit(train_set.X, train_set.y, epochs=4) expected = [ { "batches": [ { "train_loss": 2.0750882625579834, "train_batch_size": 32 }, { "train_loss": 3.09424090385437, "train_batch_size": 32 }, { "train_loss": 1.079931378364563, "train_batch_size": 32 }, { "valid_loss": 2.3208131790161133, "valid_batch_size": 24 }, ], "epoch": 1, "train_batch_count": 3, "valid_batch_count": 1, "train_loss": 2.083086848258972, "train_loss_best": True, "valid_loss": 2.3208131790161133, "valid_loss_best": True, "train_trial_accuracy": 0.5, "train_trial_accuracy_best": True, "valid_trial_accuracy": 0.5, "valid_trial_accuracy_best": True, }, { "batches": [ { "train_loss": 1.827332615852356, "train_batch_size": 32 }, { "train_loss": 1.4135494232177734, "train_batch_size": 32 }, { "train_loss": 1.1295170783996582, "train_batch_size": 32 }, { "valid_loss": 1.4291356801986694, "valid_batch_size": 24 }, ], "epoch": 2, "train_batch_count": 3, "valid_batch_count": 1, "train_loss": 1.4567997058232625, "train_loss_best": True, "valid_loss": 1.4291356801986694, "valid_loss_best": True, "train_trial_accuracy": 0.5, "train_trial_accuracy_best": False, "valid_trial_accuracy": 0.5, "valid_trial_accuracy_best": False, }, { "batches": [ { "train_loss": 1.1495535373687744, "train_batch_size": 32 }, { "train_loss": 2.356320381164551, "train_batch_size": 32 }, { "train_loss": 0.9548418521881104, "train_batch_size": 32 }, { "valid_loss": 2.248246908187866, "valid_batch_size": 24 }, ], "epoch": 3, "train_batch_count": 3, "valid_batch_count": 1, "train_loss": 1.4869052569071453, "train_loss_best": False, "valid_loss": 2.248246908187866, "valid_loss_best": False, "train_trial_accuracy": 0.5, "train_trial_accuracy_best": False, "valid_trial_accuracy": 0.5, "valid_trial_accuracy_best": False, }, { "batches": [ { "train_loss": 1.2157528400421143, "train_batch_size": 32 }, { "train_loss": 1.1182057857513428, "train_batch_size": 32 }, { "train_loss": 0.9163083434104919, "train_batch_size": 32 }, { "valid_loss": 0.9732739925384521, "valid_batch_size": 24 }, ], "epoch": 4, "train_batch_count": 3, "valid_batch_count": 1, "train_loss": 1.083422323067983, "train_loss_best": True, "valid_loss": 0.9732739925384521, "valid_loss_best": True, "train_trial_accuracy": 0.5, "train_trial_accuracy_best": False, "valid_trial_accuracy": 0.5, "valid_trial_accuracy_best": False, }, ] history_without_dur = [{k: v for k, v in h.items() if k != "dur"} for h in clf.history] assert_deep_allclose(history_without_dur, expected, atol=1e-3, rtol=1e-3)
def test_eeg_classifier(): # 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 # 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_window_samples = 450 n_classes = 2 in_chans = 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_window_samples=input_window_samples, final_conv_length=12, ) to_dense_prediction_model(model) if cuda: model.cuda() # determine output size test_input = np_to_var( np.ones((2, in_chans, input_window_samples, 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] train_set = create_from_X_y(X[:48], y[:48], drop_last_window=False, window_size_samples=input_window_samples, window_stride_samples=n_preds_per_input) valid_set = create_from_X_y(X[48:60], y[48:60], drop_last_window=False, window_size_samples=input_window_samples, window_stride_samples=n_preds_per_input) cropped_cb_train = CroppedTrialEpochScoring( "accuracy", name="train_trial_accuracy", lower_is_better=False, on_train=True, ) cropped_cb_valid = CroppedTrialEpochScoring( "accuracy", on_train=False, name="valid_trial_accuracy", lower_is_better=False, ) clf = EEGClassifier( model, criterion=CroppedLoss, criterion__loss_function=nll_loss, optimizer=optim.Adam, train_split=predefined_split(valid_set), batch_size=32, callbacks=[ ("train_trial_accuracy", cropped_cb_train), ("valid_trial_accuracy", cropped_cb_valid), ], ) clf.fit(train_set, y=None, epochs=4) expected = [{ 'batches': [{ 'train_batch_size': 32, 'train_loss': 1.9391239881515503 }, { 'train_batch_size': 32, 'train_loss': 2.895704507827759 }, { 'train_batch_size': 32, 'train_loss': 1.0713887214660645 }, { 'valid_batch_size': 24, 'valid_loss': 1.18110191822052 }], 'epoch': 1, 'train_batch_count': 3, 'train_loss': 1.9687390724817913, 'train_loss_best': True, 'train_trial_accuracy': 0.4791666666666667, 'train_trial_accuracy_best': True, 'valid_batch_count': 1, 'valid_loss': 1.18110191822052, 'valid_loss_best': True, 'valid_trial_accuracy': 0.5, 'valid_trial_accuracy_best': True }, { 'batches': [{ 'train_batch_size': 32, 'train_loss': 1.6741573810577393 }, { 'train_batch_size': 32, 'train_loss': 0.9984264373779297 }, { 'train_batch_size': 32, 'train_loss': 1.1340471506118774 }, { 'valid_batch_size': 24, 'valid_loss': 2.5375664234161377 }], 'epoch': 2, 'train_batch_count': 3, 'train_loss': 1.2688769896825154, 'train_loss_best': True, 'train_trial_accuracy': 0.5, 'train_trial_accuracy_best': True, 'valid_batch_count': 1, 'valid_loss': 2.5375664234161377, 'valid_loss_best': False, 'valid_trial_accuracy': 0.5, 'valid_trial_accuracy_best': False }, { 'batches': [{ 'train_batch_size': 32, 'train_loss': 0.8795645833015442 }, { 'train_batch_size': 32, 'train_loss': 1.0339491367340088 }, { 'train_batch_size': 32, 'train_loss': 1.19275963306427 }, { 'valid_batch_size': 24, 'valid_loss': 1.655737042427063 }], 'epoch': 3, 'train_batch_count': 3, 'train_loss': 1.0354244510332744, 'train_loss_best': True, 'train_trial_accuracy': 0.5, 'train_trial_accuracy_best': False, 'valid_batch_count': 1, 'valid_loss': 1.655737042427063, 'valid_loss_best': False, 'valid_trial_accuracy': 0.5, 'valid_trial_accuracy_best': False }, { 'batches': [{ 'train_batch_size': 32, 'train_loss': 1.1963350772857666 }, { 'train_batch_size': 32, 'train_loss': 0.8621770143508911 }, { 'train_batch_size': 32, 'train_loss': 1.099318265914917 }, { 'valid_batch_size': 24, 'valid_loss': 1.0293445587158203 }], 'epoch': 4, 'train_batch_count': 3, 'train_loss': 1.0526101191838582, 'train_loss_best': False, 'train_trial_accuracy': 0.625, 'train_trial_accuracy_best': True, 'valid_batch_count': 1, 'valid_loss': 1.0293445587158203, 'valid_loss_best': True, 'valid_trial_accuracy': 0.25, 'valid_trial_accuracy_best': False }] history_without_dur = [{k: v for k, v in h.items() if k != "dur"} for h in clf.history] assert_deep_allclose(expected, history_without_dur, atol=1e-3, rtol=1e-3)
return x def get_maxpool_layers(num_of_layers, kernel_sizes, strides, dilations): model = MaxPoolModel(num_of_layers, kernel_sizes, strides, dilations) data = Data(home + '/previous_work/ALL_11_FR1_day1_absVel.mat', -1) return model, data if __name__ == '__main__': num_of_layers = 1 kernel_size = '3' strides = '1' dilations = '3' w_size = 1038 graph_output = os.path.join(home + f'/outputs/max_pool_graphs/model_k_{kernel_size}_s{strides}_d{dilations}') model_output = os.path.join(home + f'/models/maxpool_models/model_k_{kernel_size}_s{strides}_d{dilations}') model, data = get_maxpool_layers(1, [(3, 1)], [(1, 1)]*num_of_layers, [(3, 1)]) torch.save(model, model_output) test_input = np_to_var( np.ones((2, data.in_channels, input_time_length, 1), dtype=np.float32)) test_out = model(test_input) n_preds_per_input = test_out.shape[2] data.cut_input(input_time_length, n_preds_per_input, False) x_reshaped = reshape_Xs(w_size, np.asarray(data.train_set.X)) Path(graph_output).mkdir(exist_ok=True, parents=True) manually_manipulate_signal(np.asarray(data.train_set.X), graph_output, model, maxpool_model=True, white_noise=True)
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
output = f'{home}/results/model_to_true_predictions/{model_string}_{model_name}/valid/graph_patient_{patient_index}.png' full_out = f'{home}/results/model_to_true_predictions/{model_string}_{model_name}/valid/graph_patient_{patient_index}_full.png' hp_out = f'{home}/results/model_to_true_predictions/{model_string}_{model_name}/valid/graph_patient_{patient_index}_hp.png' Path( f'{home}/results/model_to_true_predictions/{model_string}_{model_name}/valid/' ).mkdir(parents=True, exist_ok=True) Path( f'{home}/results/model_to_true_predictions/{model_string}_{model_name}/valid_data/' ).mkdir(parents=True, exist_ok=True) df = pandas.DataFrame() for input_full, input_hp, correct_out in zip(data_full.test_set.X, data_hp.test_set.X, data_full.test_set.y): out_full = changed_model_full.double()(np_to_var( input_full.reshape([ 1, input_full.shape[0], input_full.shape[1], input_full.shape[2] ])).double()) out_hp = changed_model_hp.double()(np_to_var( input_hp.reshape(1, input_full.shape[0], input_full.shape[1], input_full.shape[2])).double()) xs.append(out_full) ys.append(out_hp) zs.append(correct_out.reshape([1, correct_out.shape[0]])) # out_full = out_full.reshape([out_full.shape[1]]) # out_hp = out_hp.reshape([out_hp.shape[1]]) # print(correct_out.shape) # fig = plt.figure() # # ax = fig.add_subplot(111, projection='3d')
def model_gradients_heatmap(files, layers, variable, prefix, gradient_dir, saved_models_dir='lr_0.001'): for layer in layers: output_dir = f'{home}/outputs/{gradient_dir}/{layer}/{prefix}/' Path(output_dir).mkdir(parents=True, exist_ok=True) fig, ax = plt.subplots(1, 3, sharey='row', figsize=(15, 6)) gradient_dfs = [] titles = [] for i, gradient_kind in enumerate(['ALLCH', 'MCH', 'NCH']): gradient_dict = {} index_dict = {} for file in files: gradient_df = pandas.DataFrame() gradient = get_gradient_for_file(file, layer, gradient_kind, variable, prefix, gradient_dir) gradient_dict[file] = gradient gradient_df[file] = gradient if 'sbp1' in file: shape = min((input_time_length - 519) * 2, 1200) else: model = load_model( f'/models/saved_models/{saved_models_dir}/{prefix}_{file}/{prefix}_{file}_p_1/last_model' ) with torch.no_grad(): in_channels = list(model.parameters())[2].shape[3] test_out = model.double()(np_to_var( np.zeros([1, in_channels, 1200])).cuda()) shape = min((input_time_length - test_out.shape[1]) * 2, 1200) y = np.around(np.fft.rfftfreq(shape, 1 / 250.0), 0) gradient_df = gradient_df.set_index(pandas.Index(y), drop=True) index_dict[file] = list(gradient_df.index.values) sorted_gradient_dict = { k: v for k, v in sorted(gradient_dict.items(), key=lambda item: len(item[1]), reverse=True) } longest_k = list(sorted_gradient_dict.keys())[0] gradient_df = pandas.DataFrame() gradient_df[longest_k] = sorted_gradient_dict[longest_k] gradient_df.set_index(pandas.Index(index_dict[longest_k]), drop=True) for k, v in sorted_gradient_dict.items(): if k != longest_k: gradient, new_index = extend_second_list( long_list=sorted_gradient_dict[longest_k], long_index_list=index_dict[longest_k], shorter_list=v, shorter_index_list=index_dict[k]) gradient_df[k] = gradient # print(gradient_df[f'{variable}_k1_d3'].tolist()) gradient_df = gradient_df.reindex([ f'{variable}_k1_d3', f'{variable}_k2_d3', f'{variable}_k3_d3', f'{variable}_k2_d1', f'{variable}_k3_d1', f'{variable}_k2_d2', f'{variable}_k3_d2' ], axis=1) gradient_df = gradient_df.rename( { f'{variable}_k3_d3': f'{variable}_k3_d3_sbp0', f'{variable}_k1_d3': f'{variable}_k1' }, axis=1) # print(gradient_df[f'{variable}_k1'].tolist()) title = get_gradient_title(layer, gradient_kind) gradient_dfs.append(gradient_df) titles.append(title) output = f'{output_dir}/{variable}_model_gradients_all_kinds.png' plot_gradient_heatmap(gradient_dfs, titles, output, xlabel='Models', ax=ax) plt.tight_layout() plt.savefig(output)
def test_eeg_classifier(): # 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 # 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_window_samples = 450 n_classes = 2 in_chans = 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_window_samples=input_window_samples, final_conv_length=12, ) to_dense_prediction_model(model) if cuda: model.cuda() # determine output size test_input = np_to_var( np.ones((2, in_chans, input_window_samples, 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] train_set = create_from_X_y(X[:48], y[:48], drop_last_window=False, window_size_samples=input_window_samples, window_stride_samples=n_preds_per_input) valid_set = create_from_X_y(X[48:60], y[48:60], drop_last_window=False, window_size_samples=input_window_samples, window_stride_samples=n_preds_per_input) cropped_cb_train = CroppedTrialEpochScoring( "accuracy", name="train_trial_accuracy", lower_is_better=False, on_train=True, ) cropped_cb_valid = CroppedTrialEpochScoring( "accuracy", on_train=False, name="valid_trial_accuracy", lower_is_better=False, ) clf = EEGClassifier( model, criterion=CroppedLoss, criterion__loss_function=nll_loss, optimizer=optim.Adam, train_split=predefined_split(valid_set), batch_size=32, callbacks=[ ("train_trial_accuracy", cropped_cb_train), ("valid_trial_accuracy", cropped_cb_valid), ], ) clf.fit(train_set, y=None, epochs=4) expected = [ { "batches": [ { "train_loss": 1.9391239881515503, "train_batch_size": 32 }, { "train_loss": 2.895704507827759, "train_batch_size": 32 }, { "train_loss": 1.0713893175125122, "train_batch_size": 32 }, { "valid_loss": 1.1811838150024414, "valid_batch_size": 24 }, ], "epoch": 1, "train_batch_count": 3, "valid_batch_count": 1, "train_loss": 1.9687392711639404, "train_loss_best": True, "valid_loss": 1.1811838150024414, "valid_loss_best": True, "train_trial_accuracy": 0.4791666666666667, "train_trial_accuracy_best": True, "valid_trial_accuracy": 0.5, "valid_trial_accuracy_best": True, }, { "batches": [ { "train_loss": 1.5488793849945068, "train_batch_size": 32 }, { "train_loss": 1.1174801588058472, "train_batch_size": 32 }, { "train_loss": 1.1525697708129883, "train_batch_size": 32 }, { "valid_loss": 2.202029228210449, "valid_batch_size": 24 }, ], "epoch": 2, "train_batch_count": 3, "valid_batch_count": 1, "train_loss": 1.2729764382044475, "train_loss_best": True, "valid_loss": 2.202029228210449, "valid_loss_best": False, "train_trial_accuracy": 0.5, "train_trial_accuracy_best": True, "valid_trial_accuracy": 0.5, "valid_trial_accuracy_best": False, }, { "batches": [ { "train_loss": 1.0049529075622559, "train_batch_size": 32 }, { "train_loss": 1.0266971588134766, "train_batch_size": 32 }, { "train_loss": 1.0799436569213867, "train_batch_size": 32 }, { "valid_loss": 1.0638500452041626, "valid_batch_size": 24 }, ], "epoch": 3, "train_batch_count": 3, "valid_batch_count": 1, "train_loss": 1.0371979077657063, "train_loss_best": True, "valid_loss": 1.0638500452041626, "valid_loss_best": True, "train_trial_accuracy": 0.5, "train_trial_accuracy_best": False, "valid_trial_accuracy": 0.5, "valid_trial_accuracy_best": False, }, { "batches": [ { "train_loss": 1.0052555799484253, "train_batch_size": 32 }, { "train_loss": 0.8479514718055725, "train_batch_size": 32 }, { "train_loss": 0.9589881300926208, "train_batch_size": 32 }, { "valid_loss": 0.8794112801551819, "valid_batch_size": 24 }, ], "epoch": 4, "train_batch_count": 3, "valid_batch_count": 1, "train_loss": 0.9373983939488729, "train_loss_best": True, "valid_loss": 0.8794112801551819, "valid_loss_best": True, "train_trial_accuracy": 0.5, "train_trial_accuracy_best": False, "valid_trial_accuracy": 0.5, "valid_trial_accuracy_best": False, }, ] history_without_dur = [{k: v for k, v in h.items() if k != "dur"} for h in clf.history] assert_deep_allclose(expected, history_without_dur, atol=1e-3, rtol=1e-3)
def __init__(self, chn_num, class_num, wind): super().__init__() self.chn_num = chn_num self.class_num = class_num self.wind = wind self.conv_spatial_top = nn.Conv2d(1, self.chn_num, kernel_size=(self.chn_num, 1), stride=(1, 1), bias=False) self.conv_time = nn.Conv2d(1, 64, kernel_size=(1, 10), stride=(1, 1)) self.conv_spatial = nn.Conv2d(64, 64, kernel_size=(self.chn_num, 1), stride=(1, 1), bias=False) self.bn1 = nn.BatchNorm2d(64, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True) self.nonlinear1 = nn.ELU() self.mp1 = nn.MaxPool2d(kernel_size=(1, 3), stride=(1, 3), padding=0, dilation=1, ceil_mode=False) self.drop1 = nn.Dropout(p=0.5, inplace=False) self.conv2 = nn.Conv2d(64, 128, kernel_size=(1, 10), stride=(1, 1), bias=False) self.bn2 = nn.BatchNorm2d(128, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True) self.nonlinear2 = nn.ELU() self.drop2 = nn.Dropout(p=0.5, inplace=False) self.conv3 = nn.Conv2d(128, 256, kernel_size=(1, 10), stride=(1, 1), bias=False) self.bn3 = nn.BatchNorm2d(256, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True) self.nonlinear3 = nn.ELU() self.drop3 = nn.Dropout(p=0.5, inplace=False) self.conv4 = nn.Conv2d(256, 512, kernel_size=(1, 10), stride=(1, 1), bias=False) self.bn4 = nn.BatchNorm2d(512, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True) self.nonlinear4 = nn.ELU() self.drop4 = nn.Dropout(p=0.5, inplace=False) self.bn0 = nn.BatchNorm2d(self.chn_num, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True) self.nonlinear0 = nn.ELU() self.drop0 = nn.Dropout(p=0.5, inplace=False) #self.seq0=nn.Sequential(self.bn0,self.nonlinear0,self.drop0) self.seq0 = nn.Sequential(self.drop0) self.seq = nn.Sequential(Expression(swap_plan_spat), self.conv_time, self.drop0, self.conv_spatial, self.bn1, self.nonlinear1, self.mp1, self.drop1, self.conv2, self.bn2, self.nonlinear2, self.drop2, self.conv3, self.bn3, self.nonlinear3, self.drop3, self.conv4, self.bn4, self.nonlinear4, self.drop4) test = np_to_var( np.ones((1, 1, self.chn_num, self.wind), dtype=np.float32)) test = self.conv_spatial_top(test) test = self.seq0(test) #test=test.permute(0,2,1,3) out = self.seq(test) len = out.shape[3] self.ap = nn.AvgPool2d(kernel_size=(1, len), stride=(1, len), padding=0) self.final_linear = nn.Linear(in_features=512, out_features=self.class_num, bias=True)
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 __init__(self, chn_num, class_num, wind): super().__init__() self.chn_num = chn_num self.class_num = class_num self.wind = wind self.conv_time = nn.Conv2d(1, 64, kernel_size=(1, 50), stride=(1, 1)) self.conv_spatial = nn.Conv2d(64, 64, kernel_size=(self.chn_num, 1), stride=(1, 1), bias=False) self.bn1 = nn.BatchNorm2d(64, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True) self.nonlinear1 = nn.ELU() self.mp1 = nn.MaxPool2d(kernel_size=(1, 3), stride=(1, 3), padding=0, dilation=1, ceil_mode=False) self.drop1 = nn.Dropout(p=0.5, inplace=False) self.conv2 = nn.Conv2d(64, 50, kernel_size=(1, 10), stride=(1, 1), bias=False) self.bn2 = nn.BatchNorm2d(50, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True) self.nonlinear2 = nn.ELU() self.drop2 = nn.Dropout(p=0.5, inplace=False) self.conv3 = nn.Conv2d(50, 50, kernel_size=(1, 10), stride=(1, 1), bias=False) self.bn3 = nn.BatchNorm2d(50, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True) self.nonlinear3 = nn.ELU() self.drop3 = nn.Dropout(p=0.5, inplace=False) self.conv4 = nn.Conv2d(50, 50, kernel_size=(1, 10), stride=(1, 1), bias=False) self.bn4 = nn.BatchNorm2d(50, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True) self.nonlinear4 = nn.ELU() self.drop4 = nn.Dropout(p=0.5, inplace=False) self.seq = nn.Sequential(self.conv_time, self.conv_spatial, self.bn1, self.nonlinear1, self.mp1, self.drop1, self.conv2, self.bn2, self.nonlinear2, self.drop2, self.conv3, self.bn3, self.nonlinear3, self.drop3, self.conv4, self.bn4, self.nonlinear4, self.drop4) out = self.seq( np_to_var( np.ones((1, 1, self.chn_num, self.wind), dtype=np.float32))) #(32,50,1,123) len = out.shape[3] Hin = out.shape[1] self.lstm1 = nn.LSTM(Hin, int(Hin / 2), batch_first=True) self.drop5 = nn.Dropout(p=0.2, inplace=False) #self.ap = nn.AvgPool2d(kernel_size=(1, len), stride=(1, len), padding=0) self.final_linear = nn.Linear(in_features=int(Hin / 2), out_features=self.class_num, bias=True)
def __init__( self, in_chans, n_classes, input_window_samples=None, n_filters_time=40, filter_time_length=25, n_filters_spat=40, pool_time_length=75, pool_time_stride=15, final_conv_length=30, conv_nonlin=square, pool_mode="mean", pool_nonlin=safe_log, split_first_layer=True, batch_norm=True, batch_norm_alpha=0.1, drop_prob=0.5, ): super().__init__() if final_conv_length == "auto": assert input_window_samples is not None self.in_chans = in_chans self.n_classes = n_classes self.input_window_samples = input_window_samples self.n_filters_time = n_filters_time self.filter_time_length = filter_time_length self.n_filters_spat = n_filters_spat self.pool_time_length = pool_time_length self.pool_time_stride = pool_time_stride self.final_conv_length = final_conv_length self.conv_nonlin = conv_nonlin self.pool_mode = pool_mode self.pool_nonlin = pool_nonlin self.split_first_layer = split_first_layer self.batch_norm = batch_norm self.batch_norm_alpha = batch_norm_alpha self.drop_prob = drop_prob self.add_module("ensuredims", Ensure4d()) pool_class = dict(max=nn.MaxPool2d, mean=nn.AvgPool2d)[self.pool_mode] if self.split_first_layer: self.add_module("dimshuffle", Expression(transpose_time_to_spat)) self.add_module( "conv_time", nn.Conv2d( 1, self.n_filters_time, (self.filter_time_length, 1), stride=1, ), ) self.add_module( "conv_spat", nn.Conv2d( self.n_filters_time, self.n_filters_spat, (1, self.in_chans), stride=1, bias=not self.batch_norm, ), ) n_filters_conv = self.n_filters_spat else: self.add_module( "conv_time", nn.Conv2d( self.in_chans, self.n_filters_time, (self.filter_time_length, 1), stride=1, bias=not self.batch_norm, ), ) n_filters_conv = self.n_filters_time if self.batch_norm: self.add_module( "bnorm", nn.BatchNorm2d(n_filters_conv, momentum=self.batch_norm_alpha, affine=True), ) self.add_module("conv_nonlin_exp", Expression(self.conv_nonlin)) self.add_module( "pool", pool_class( kernel_size=(self.pool_time_length, 1), stride=(self.pool_time_stride, 1), ), ) self.add_module("pool_nonlin_exp", Expression(self.pool_nonlin)) self.add_module("drop", nn.Dropout(p=self.drop_prob)) self.eval() if self.final_conv_length == "auto": out = self( np_to_var( np.ones( (1, self.in_chans, self.input_window_samples, 1), dtype=np.float32, ))) n_out_time = out.cpu().data.numpy().shape[2] self.final_conv_length = n_out_time self.add_module( "conv_classifier", nn.Conv2d( n_filters_conv, self.n_classes, (self.final_conv_length, 1), bias=True, ), ) self.add_module("softmax", nn.LogSoftmax(dim=1)) self.add_module("squeeze", Expression(squeeze_final_output)) # Initialization, xavier is same as in paper... init.xavier_uniform_(self.conv_time.weight, gain=1) # maybe no bias in case of no split layer and batch norm if self.split_first_layer or (not self.batch_norm): init.constant_(self.conv_time.bias, 0) if self.split_first_layer: init.xavier_uniform_(self.conv_spat.weight, gain=1) if not self.batch_norm: init.constant_(self.conv_spat.bias, 0) if self.batch_norm: init.constant_(self.bnorm.weight, 1) init.constant_(self.bnorm.bias, 0) init.xavier_uniform_(self.conv_classifier.weight, gain=1) init.constant_(self.conv_classifier.bias, 0)
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()