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
Exemple #3
0
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,
    )
Exemple #4
0
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
Exemple #7
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()