Code Monkey home page Code Monkey logo

vlawhern / arl-eegmodels Goto Github PK

View Code? Open in Web Editor NEW
1.1K 1.1K 277.0 73 KB

This is the Army Research Laboratory (ARL) EEGModels Project: A Collection of Convolutional Neural Network (CNN) models for EEG signal classification, using Keras and Tensorflow

License: Other

Python 100.00%
brain-computer-interface convolutional-neural-networks deep-learning eeg eeg-classification event-related-potentials keras sensory-motor-rhythm tensorflow time-series-classification

arl-eegmodels's People

Contributors

agramfort avatar robintibor avatar vlawhern avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

arl-eegmodels's Issues

Cite MNE

hi,

thanks a lot for this great work. I see that you use MNE for you work. It would be really appreciated if you could properly cite MNE in your papers: http://martinos.org/mne/stable/faq.html#cite so we can continue to get funding for this project by justifying of its actual impact.

thanks a lot
Alex

How to define the dataset size as the input to EEGNet model

Hello,
I am working on a course project using 4 channels of EEG signals and 256 as sampling rate for BCI application of binary image classification. My training dataset size is 1004256 and my label array is of 1001 size, in which I trimmed 100 epochs of signals in each an image was shown to the user. I can see that the input size is considered as channelssamples in your codes, but I don not know how to reshape the size of the training and test data sets to make compatible with your codes, so I would appreciate it if you could direct me on that. Thank you and looking forward to hearing back from you soon.
Regards
Amin

Problem using EEGNet on ERN dataset

I followed the code in the example for applying on ERP dataset and tried it on ERN dataset. However, the result shows as random classification. I applied bandpass filter too, but I cannot understand what makes it a random classification. Do you have any suggestion?

Why the pretrained weights can't fit in?

Hello,
I 'm a freshman in AI and recently studying your model. I try to load the pretrained weight into EEGNet but it comes out there's a shape mise match at the first Conv2D layer:
ValueError: Shapes (1, 64, 1, 8) and (8, 1, 1, 32) are incompatible

the code I use is this:
model = EEGNet(nb_classes=3)
model.load_weights('examples/EEGNet-8-2-weights.h5')

Any advice will be appreciated
Regards
Asagiri

Problem with the dataset BCI IV 2a : Result Doesn't match the paper's one.

Hi,

I tried to recreate the result for EEGNET-4-1 to use it as a baseline in cross-subject case. The problem is that I couldn't get the same result where simulation gets higher Accuracy around 50 and 60 (in the paper 40).

I reused completely the code from braindecode as data preprocessing code and I add the resampling function as in the paper and It not working.

If someone can check the code below and look for something I missed it would be great.

The Preprocessing part:

path='/home/user'
import logging
import os.path
import time
from collections import OrderedDict
import sys

import numpy as np


from braindecode.datasets.bcic_iv_2a import BCICompetition4Set2A
from braindecode.experiments.monitors import LossMonitor, MisclassMonitor, \
    RuntimeMonitor
from braindecode.experiments.stopcriteria import MaxEpochs, NoDecrease, Or
from braindecode.datautil.iterators import BalancedBatchSizeIterator
from braindecode.datautil.splitters import split_into_two_sets
from braindecode.mne_ext.signalproc import mne_apply,resample_cnt
from braindecode.datautil.signalproc import (bandpass_cnt,
                                             exponential_running_standardize)
from braindecode.datautil.trial_segment import create_signal_target_from_raw_mne
X_train_set=list()
y_train_set=list()
X_test_set=list()
y_test_set=list()

for subject_id in list(range(1,10)):
    data_folder= path
    low_cut_hz=4
    ival = [500, 2500]
    high_cut_hz = 40
    factor_new = 1e-3
    init_block_size = 1000

    train_filename = 'A{:02d}T.gdf'.format(subject_id)
    test_filename = 'A{:02d}E.gdf'.format(subject_id)
    train_filepath = os.path.join(data_folder, train_filename)
    test_filepath = os.path.join(data_folder, test_filename)
    train_label_filepath = train_filepath.replace('.gdf', '.mat')
    test_label_filepath = test_filepath.replace('.gdf', '.mat')

    train_loader = BCICompetition4Set2A(
        train_filepath, labels_filename=train_label_filepath)
    test_loader = BCICompetition4Set2A(
        test_filepath, labels_filename=test_label_filepath)
    train_cnt = train_loader.load()
    test_cnt = test_loader.load()

    # Preprocessing

    train_cnt = train_cnt.drop_channels(['STI 014', 'EOG-left',
                                         'EOG-central', 'EOG-right'])
    assert len(train_cnt.ch_names) == 22
    # lets convert to millvolt for numerical stability of next operations
    train_cnt = resample_cnt(train_cnt, 128)### added by me as suggeste in the paper
    train_cnt = mne_apply(lambda a: a * 1e6, train_cnt)
    train_cnt = mne_apply(
        lambda a: bandpass_cnt(a, low_cut_hz, high_cut_hz, train_cnt.info['sfreq'],
                               filt_order=3,
                               axis=1), train_cnt)
    train_cnt = mne_apply(
        lambda a: exponential_running_standardize(a.T, factor_new=factor_new,
                                                  init_block_size=init_block_size,
                                                  eps=1e-4).T,
        train_cnt)

    test_cnt = test_cnt.drop_channels(['STI 014', 'EOG-left',
                                       'EOG-central', 'EOG-right'])
    assert len(test_cnt.ch_names) == 22
    test_cnt = resample_cnt(test_cnt, 128)### added by me as suggeste in the paper
    test_cnt = mne_apply(lambda a: a * 1e6, test_cnt)
    test_cnt = mne_apply(
        lambda a: bandpass_cnt(a, low_cut_hz, high_cut_hz, test_cnt.info['sfreq'],
                               filt_order=3,
                               axis=1), test_cnt)
    test_cnt = mne_apply(
        lambda a: exponential_running_standardize(a.T, factor_new=factor_new,
                                                  init_block_size=init_block_size,
                                                  eps=1e-4).T,
        test_cnt)

    marker_def = OrderedDict([('Left Hand', [1]), ('Right Hand', [2],),
                              ('Foot', [3]), ('Tongue', [4])])

    train_set = create_signal_target_from_raw_mne(train_cnt, marker_def, ival)
    test_set = create_signal_target_from_raw_mne(test_cnt, marker_def, ival)

    X_train_set.append(train_set.X)
    y_train_set.append(train_set.y)
    X_test_set.append(test_set.X)
    y_test_set.append(test_set.y)



subject='1' # the subject id as string
subject = int(subject)-1 # str to int
# shuffle part 
from random import shuffle
Lt = list(range(0, 9)) 
shuffle(Lt)
Lt.remove(subject)
Lv = Lt[0:3]
[Lt.remove(i) for i in Lv]
X_t = list()
X_v = list()
y_t = list()
y_v = list()
print(len(X_train_set))
for i in Lt:
    X_t.append(X_train_set[i])
    y_t.append(y_train_set[i])


for i in Lv:
    X_v.append(X_train_set[i])
    y_v.append(y_train_set[i])

X_train = np.concatenate(X_t, axis=0).astype('float32')
    
print(Lt)#list training set
print(Lv)#list testing set
print(len(X_t))
print(len(X_v))
print(X_train.shape)
print(y_train.shape)



X_train = np.concatenate(X_t, axis=0).astype('float32')
X_val = np.concatenate(X_v, axis=0).astype('float32')
X_test = X_test_set[subject].astype('float32')

y_train = np.concatenate(y_t, axis=0).astype('int16')
y_val = np.concatenate(y_v, axis=0).astype('int16')
y_test = y_test_set[subject].astype('int16')

y_train = y_train.reshape((288*5))
y_val = y_val.reshape((288*3))
y_test = y_test.reshape((288))
y_train = keras.utils.to_categorical(y_train, 4)
y_val = keras.utils.to_categorical(y_val, 4)
y_test = keras.utils.to_categorical(y_test, 4)

How to deal with the input data that contains the different sampling points?

Hi, Thanks for your generosity, What a great job! I just checked the input data of demo script that have the exactly same sampling points, which showed the experimental control temporally. Do you have any suggestion for dealing with the different sampling points with EEGnet models? Right now, I was using re-sampling to align it.

Issue with Tensorflow and import

So, I decided to use Google Colab for my interface of choice for my project. I have opted to upgrade to Colab Pro to see if it will benefit me. I am runing this whole network on the GPU.

My error is the KeyError shown at the very end of this message. I have put the contents of the EEGmodels.py file in the code block right before my imports block. And my imports block contains the following code. Sometimes I have an AttributeError, but once I pip install deepexplain it turns into a KeyError.

import numpy as np
import mne
import mneflow
import tensorflow as tf
# Disable eager execution
tf.compat.v1.disable_eager_execution()
from tensorflow.keras.models import Model
from tensorflow.keras import backend as K
from tensorflow.keras import utils as np_utils
from tensorflow.keras.callbacks import ModelCheckpoint
from tensorflow.python.keras import backend as K
import sklearn
import pandas as pd
import os
import pyriemann
import matplotlib
from deepexplain.tensorflow import DeepExplain
from google.colab import drive

# Make numpy values easier to read.
np.set_printoptions(precision=3, suppress=True)
from tensorflow.keras import layers

Every time I exit out of the notebook and I start it back up again I have to reinstall some of the packages that were not natively installed in google Collab (this includes mne, mneflow, pyriemann, and deepexplain). So, I re-installed โ€œ deepexplainโ€ out of habit via GitHub. At first it was giving me a โ€œKeyErrorโ€ and (when I search for the error) I was told upgrade TensorFlow.

Iโ€™ve upgraded TensorFlow and restarted my runtime. Iโ€™m running on the GPU with the standard ram option.

This is the error:
image

cannot replicate the within-subject experimental results of BCI Competition IV dataset 2a using PyTorch

I cannot replicate the within-subject experimental results of BCI Competition IV dataset 2a using PyTorch
Here is my code for data processing

def getdata_A_T_22(filename,ids):
    raw_gdf = mne.io.read_raw_gdf(filename, stim_channel="auto", verbose='ERROR',
                                  exclude=(["EOG-left", "EOG-central", "EOG-right"]))
    #rename
    raw_gdf.rename_channels(
        {'EEG-Fz': 'Fz', 'EEG-0': 'FC3', 'EEG-1': 'FC1', 'EEG-2': 'FCz', 'EEG-3': 'FC2', 'EEG-4': 'FC4',
         'EEG-5': 'C5', 'EEG-C3': 'C3', 'EEG-6': 'C1', 'EEG-Cz': 'Cz', 'EEG-7': 'C2', 'EEG-C4': 'C4', 'EEG-8': 'C6',
         'EEG-9': 'CP3', 'EEG-10': 'CP1', 'EEG-11': 'CPz', 'EEG-12': 'CP2', 'EEG-13': 'CP4',
         'EEG-14': 'P1', 'EEG-15': 'Pz', 'EEG-16': 'P2', 'EEG-Pz': 'POz'})
    # Pre-load the data
    raw_gdf.load_data()
    #Bandpass filter 4-40Hz
    raw_gdf.filter(4.0, 40.0, fir_design="firwin", skip_by_annotation="edge")
    # Select data from 0.5s to 2.5s after the cue.  
    tmin, tmax =.5 , 2.5
    #  events_id
    events, events_id = mne.events_from_annotations(raw_gdf)
    event_id = dict({'769': 7, '770': 8, '771': 9, '772': 10})
    #get epoches
    epochs = mne.Epochs(raw_gdf, events, event_id, tmin, tmax, proj=True, baseline=None, preload=True)
    # print(epochs)
    labels = epochs.events[:, -1]
    data = epochs.get_data()
    # resample to 128Hz
    original_sampling_rate = 250
    target_sampling_rate = 128
    original_length = data.shape[-1]
    target_length = int(original_length * target_sampling_rate / original_sampling_rate)
    # resample    
    resampled_data = np.zeros((data.shape[0], data.shape[1], target_length))
    for i in range(data.shape[0]):
        for j in range(data.shape[1]):
            resampled_data[i, j, :] = resample(data[i, j, :], target_length)
    # print results
    print(f"orginal shape: {data.shape}, new shape: {resampled_data.shape}")
    data = resampled_data
    labels[labels == 7] = 0
    labels[labels == 8] = 1
    labels[labels == 9] = 2
    labels[labels == 10] = 3
    X = torch.from_numpy(data).unsqueeze(1)
    y = torch.from_numpy(labels).long()
    X, y = shuffle(X, y, random_state=42)  
    #Performing four-fold cross-validation
    num_folds = 4
    skf = StratifiedKFold(n_splits=num_folds, shuffle=True, random_state=42)
    folded_data = []
    for train_index, val_index in skf.split(X, y):
        X_train, X_val = X[train_index], X[val_index]
        y_train, y_val = y[train_index], y[val_index]
        #print(y_val)
        folded_data.append((X_train, y_train, X_val, y_val))
    # save
    for i, fold_data in enumerate(folded_data):
        X_train, y_train, X_val, y_val = fold_data
        print('shape',X_train.shape)
        print(f"Fold {i + 1}: Training Set Size = {len(X_train)}, Validation Set Size = {len(X_val)}")
        np.save(f'./2a_T_22s/train_data_a0{ids}_{i+1}.npy', X_train)
        np.save(f'./2a_T_22s/test_data_a0{ids}_{i+1}.npy', X_val)
        np.save(f'./2a_T_22s/train_labels_a0{ids}_{i+1}.npy', y_train)
        np.save(f'./2a_T_22s/test_labels_a0{ids}_{i+1}.npy', y_val)
for i in range(9):
    #The third subject's event differs
    if i==3:
        continue
    print(i+1)
    getdata_A_T_22(f"./BCICIV_2a_gdf/A0{i+1}T.gdf",i+1)

here is my code for train

class EEGNet(nn.Module):
    def __init__(self,Chans, T,clas, F1, D, F2 ):
        super(EEGNet, self).__init__()
        self.drop_out = 0.5
        self.block_1 = nn.Sequential(
            nn.Conv2d(
                in_channels=1,  
                out_channels=F1,  
                kernel_size=(1, 32),  
                bias=False,
                padding='same'
            ),  
            nn.BatchNorm2d(F1)  
        )
        self.block_2 = nn.Sequential(
            nn.Conv2d(
                in_channels=F1,  
                out_channels=D*F1,  
                kernel_size=(Chans, 1), 
                groups=F1,
                bias=False, 
                padding='valid'
            ),  
            nn.BatchNorm2d(D*F1),  
            nn.ELU(),
            nn.AvgPool2d((1, 4)),  
            nn.Dropout(self.drop_out)  
        )

        self.block_3 = nn.Sequential(
            nn.Conv2d(
                in_channels=D*F1,  
                out_channels=D*F1,  
                kernel_size=(1, 16),  
                groups=D*F1,
                bias=False,
                padding='same'
            ),  
            nn.Conv2d(
                in_channels=D*F1,  
                out_channels=F2,  
                kernel_size=(1, 1),  
                bias=False,
                padding='same'
            ),  
            nn.BatchNorm2d(F2), 
            nn.ELU(),
            nn.AvgPool2d((1, 8)),  
            nn.Dropout(self.drop_out)
        )

        self.out = nn.Linear((F2 * (T//32)), clas)

    def forward(self, x):
        x = self.block_1(x)
        x = self.block_2(x)
        x = self.block_3(x)

        x = x.view(x.size(0), -1)
        x = self.out(x)
        return x
device = torch.device("cuda")
creation=nn.CrossEntropyLoss()  
creation=creation.to(device)
learning_rate=3e-4
beta1=0.9
beta2=0.999
accs=np.zeros((9,4))
for sub in range(9):
    for fold in range(4):
        print(sub,fold)
        # load data
        loaded_train_data = np.load(f"./2a_T_22s/train_data_a0{sub+1}_{fold+1}.npy")
        #print(f"./2a_T_22s/train_data_a0{sub+1}_{fold+1}.npy")
        loaded_test_data = np.load(f'./2a_T_22s/test_data_a0{sub+1}_{fold+1}.npy')
        loaded_train_labels = np.load(f'./2a_T_22s/train_labels_a0{sub+1}_{fold+1}.npy')
        loaded_test_labels = np.load(f'./2a_T_22s/test_labels_a0{sub+1}_{fold+1}.npy')
        print(loaded_train_data.shape, loaded_train_labels.shape)
        #  PyTorch Tensor
        loaded_train_data_tensor = torch.Tensor(loaded_train_data)
        loaded_test_data_tensor = torch.Tensor(loaded_test_data)
        loaded_train_labels_tensor = torch.Tensor(loaded_train_labels).long()
        loaded_test_labels_tensor = torch.Tensor(loaded_test_labels).long()
        print(loaded_train_data_tensor.shape, loaded_train_labels_tensor.shape)
        # TensorDataset
        loaded_train_dataset = TensorDataset(loaded_train_data_tensor, loaded_train_labels_tensor)
        loaded_test_dataset = TensorDataset(loaded_test_data_tensor, loaded_test_labels_tensor)

        #  DataLoader
        batch_size = 32
        train_loader = DataLoader(loaded_train_dataset, batch_size=batch_size, shuffle=True)
        test_loader = DataLoader(loaded_test_dataset, batch_size=batch_size, shuffle=False)

        model = EEGNet(22,256,4,8, 2, 16)       
        optimizer=torch.optim.Adam(model.parameters(),lr=learning_rate)  
        model_save_path = './2a_T_22/models/'
        os.makedirs(model_save_path, exist_ok=True)
        EPOCHS = 300
        train_steps = 0
        model.cuda()
        test_steps = 0
        losses = []
        accuracies = []
        ftrain_label = torch.tensor(loaded_train_labels).to(device)

        for epoch in range(EPOCHS):  
            model.train() 
            epoch_train_loss = 0.0
            for train_batch, (train_image, train_label) in enumerate(train_loader):

                train_image, train_label = train_image.to(device), train_label.to(device)  
                train_predictions = model(train_image)

                batch_train_loss = creation(train_predictions, train_label)
                optimizer.zero_grad()  
                batch_train_loss.backward()
                optimizer.step()
                epoch_train_loss += batch_train_loss.item()
                train_steps += 1
                if train_steps % 500 == 0:
                    print("train{}๏ผŒtrain loss{}".format(train_steps, batch_train_loss.item()))
                if epoch%100==0:
                        model.eval()
                        with torch.no_grad():
                            predictions=model(loaded_test_data_tensor.to(device)).cpu()
                            predictions.numpy()
                            test_acc=(predictions.argmax(dim=1)==torch.tensor(loaded_test_labels )).sum()
                            print("test acc",test_acc/len(loaded_test_labels))
            losses.append(epoch_train_loss)
            train_predictions = model(loaded_train_data_tensor.to(device))

            accuracy = (torch.argmax(train_predictions, dim=1) == ftrain_label).float().mean().item()
            accuracies.append(accuracy)


        torch.save(model.state_dict(), model_save_path + f"modela0_{sub+1}{fold+1}.pth".format(epoch + 1))
        print("finish๏ผ")
        with torch.no_grad():
            predictions = model(loaded_test_data_tensor.to(device)).cpu()
            print(predictions[10])
            test_loss = creation(predictions, torch.tensor(loaded_test_labels))
            predictions.numpy()

            test_acc = (predictions.argmax(dim=1) == torch.tensor(loaded_test_labels)).sum()
            print("test acc", test_acc / len(loaded_test_labels))
            print("test loss{}".format(test_loss.item()))
            accs[sub][fold]=test_acc/len(loaded_test_labels)
average_per_experiment = np.mean(accs, axis=1)
# box
plt.boxplot(accs.T)

plt.title('Boxplot of Average per Experiment')
plt.xlabel('Experiment')
plt.ylabel('Average Value')
plt.show()

Here is my results
e9a08f98575f7f91dbd0848d74f399c

A question about data imbalance

Hello, thanks for sharing your code. I was wondering how the authors deal with the data imbalance problem while training the P300 data. It would be nice if the authors could share your code. Thanks again!

Down sampling keras data to 128Hz

Hey I'm wondering if you could help me with down sampling. I'm trying to implement EEGNet on the keras bci challenge data as you guys did in your paper.

When I call epochs.resample(sfreq = 128), I'm left with an epoch shape of (2720, 59, 161) and 2720 because I'm only using half the training data. I get a weird shape if I down sample raw before epoching as well. I understand it has something to do with the extraction window of [0, 1.25] but I'm not sure how to compensate for that. Any help would be appreciated, thanks!

Request for dataset 1

I am now trying to run your model on your dataset first, but I cannot find the first dataset described in your paper. May I know where I can grab that dataset? Thank you.

Batch normalization layers

Hello vlawhern,

I really appreciate that you have implemented all these models in tensorflow and put them available here. They are really easy to use and it saved me a lot of time.

I have only one remark. I've noticed that different libraries (tensorflow/torch etc) use momentum in batch normalization differently (in tensorflow momentum of 0.9 corresponds to 0.1 in torch). I've checked the code of the authors of DeepConvNet and ShallowConvNet (https://github.com/robintibor/braindecode) and they are using torch, so the default momentum in tensorflow should be 0.9.

Best regards,

Sara

InvalidArgumentError: Default AvgPoolingOp only supports NHWC on device type CPU

When I try to fit the eegnet model, I get the following error:

InvalidArgumentError: Default AvgPoolingOp only supports NHWC on device type CPU
[[{{node average_pooling2d/AvgPool}} = AvgPoolT=DT_FLOAT, _class=["loc:@training/Adam/gradients/average_pooling2d/AvgPool_grad/AvgPoolGrad"], data_format="NCHW", ksize=[1, 1, 1, 4], padding="VALID", strides=[1, 1, 1, 4], _device="/job:localhost/replica:0/task:0/device:CPU:0"]]

I have cuda installed, but it does not appear to be working. What is the appropriate cuda setup for gpu support?

Trying to fit my data to the input shape

Hello...
I am tring to fit my data to the required shape

input1 = Input(shape = (Chans, Samples, 1))

I have data which is 17388 x 640 and it has been reshaped to 17388 x 32 x 20 x 1

However an error is issued

Exception has occurred: ValueError
Negative dimension size caused by subtracting 8 from 5 for '{{node average_pooling2d_1/AvgPool}} = AvgPoolT=DT_FLOAT, data_format="NHWC", ksize=[1, 1, 8, 1], padding="VALID", strides=[1, 1, 8, 1]' with input shapes: [?,1,5,16].

May I know to proplery prepare my data to fit the EEGNet Model?

Thank you

The implement of PyTorch

I am wondering whether you would release a pytorch implement of this repo? If possibile, it will be a great convenient for us!

bci application

im looking for a image classification model using deep learning for images of eeg signals and im not finding any, does any one know any thing that can help me and i will be very appreciated .

Validation accuracy of example ERP.py suddently dropped drastically, with an additional warning

I am getting the following warning:

Epoch 1/300 WARNING:tensorflow:Entity <function Function._initialize_uninitialized_variables.<locals>.initialize_variables at 0x7f8af8da4830> could not be transformed and will be executed as-is. Please report this to the AutoGraph team. When filing the bug, set the verbosity to 10 (on Linux, export AUTOGRAPH_VERBOSITY=10) and attach the full output. Cause: WARNING: Entity <function Function._initialize_uninitialized_variables.<locals>.initialize_variables at 0x7f8af8da4830> could not be transformed and will be executed as-is. Please report this to the AutoGraph team. When filing the bug, set the verbosity to 10 (on Linux, export AUTOGRAPH_VERBOSITY=10`) and attach the full output. Cause:

Epoch 00001: val_loss improved from inf to 1.38645, saving model to /tmp/checkpoint_original.h5
144/144 - 2s - loss: 1.4062 - accuracy: 0.2986 - val_loss: 1.3864 - val_accuracy: 0.2222
Epoch 2/300

Epoch 00002: val_loss did not improve from 1.38645
144/144 - 0s - loss: 1.3726 - accuracy: 0.3194 - val_loss: 1.3865 - val_accuracy: 0.2361
Epoch 3/300

Epoch 00003: val_loss did not improve from 1.38645
144/144 - 0s - loss: 1.3613 - accuracy: 0.3750 - val_loss: 1.3865 - val_accuracy: 0.2361
Epoch 4/300
WARNING:tensorflow:Can save best model only with val_loss available, skipping.
Traceback (most recent call last):`

I should let you know that since yesterday, I have created my own separate script to analyze my own data. I am getting the same warning and accuracies are low - and I can't be sure if it is because the data is actually not separable.

Help Needed; Unable to run the process to run the EEGNet

Hi!
This is Karthikay, am a a beginner to this field and I'd like to work on this EEGNet to make a personal project. I'm not able to succeed in running the process and would like to recive some help. Please let me know if there's any other way to connect so that I can understand the process.

Thank You.

Unable to find program entry

I tried to reproduce your paper work, but I looked at your project and couldn't find a complete program entrance. Can you tell me how to run this project?

Negative dimension size caused by subtracting 50 from 1 for 'depthwise_conv2d_5/depthwise' (op: 'DepthwiseConv2dNative') with input shapes: [?,1,50,8], [50,1,8,2].

I am using EEGNet model for classifying 4-class BCI competition IV Dataset 2a for Motor Imagery detection i.e. detecting (SMR)
I read the data for one subject using the MAT file I have. After reading the training data, the x

print(np.shape(X))
print(np.shape(y))

The output is :

(273, 22, 1500)
(273, 1)

where 272 are trials, 22 channels, 1500 samples from each trial

I partitioned and cropped the data. The cropping I did because the data in the region 500:1000 (i.e. from the start of the cue to the 2 sec after cue) is much related for ERD/ERS.

# take 50/25/25 percent of the data to train/validate/test
X_train      = X[0:150,:,500:1000]
Y_train      = y[0:150]
X_validate   = X[151:200,:,500:1000]
Y_validate   = y[151:200]
X_test       = X[201:,:,500:1000]
Y_test       = y[201:]
print(np.shape(X_train))
print(np.shape(Y_train))
print(np.shape(X_validate))
print(np.shape(Y_validate))
print(np.shape(X_test))
print(np.shape(Y_test))

Output:

(150, 22, 500)
(150, 1)
(49, 22, 500)
(49, 1)
(72, 22, 500)
(72, 1)

Following parameter, I used and reshaped the data

kernels, chans, samples = 1, 22, 500
# convert data to NCHW (trials, kernels, channels, samples) format. Data 
# contains 22 channels and 500 time-points. Set the number of kernels to 1.
X_train      = X_train.reshape(X_train.shape[0], kernels, chans, samples)
X_validate   = X_validate.reshape(X_validate.shape[0], kernels, chans, samples)
X_test       = X_test.reshape(X_test.shape[0], kernels, chans, samples)
   
print('X_train shape:', X_train.shape)
print(X_train.shape[0], 'train samples')
print(X_test.shape[0], 'test samples')

Output:

X_train shape: (150, 1, 22, 500)
150 train samples
72 test samples

Now, while creating the model

model = EEGNet(nb_classes = 4, Chans = 22, Samples = 500, 
             dropoutRate = 0.5, kernLength = 25, F1 = 8, 
             D = 2, F2 = 16, norm_rate = 0.25, dropoutType = 'Dropout')

Now the error, I am getting is given as follows:

ValueError: Negative dimension size caused by subtracting 22 from 8 for 'depthwise_conv2d/depthwise' (op: 'DepthwiseConv2dNative') with input shapes: [?,8,22,500], [22,1,500,2].

I am wondering what mistake I am making? any clue, please
Many thanks

Can't reproduce experimental results of BCI Competition IV dataset 2a for within classification

Hello.

I am trying to reproduce experimental results of BCI Competition IV dataset 2a for within classification in the paper.
I reused EEGNet class but got mean accuracy 60~63. I expected around 68.

I read #7 and tried EEGNet-8,2, with kernLength = 32.
I did 4-fold blockwise cross-validation that splits training set into three equal contiguous partitions(96/96/96) and selects each one of three partitions as validation set while retaining test set(288). So there were three training for each subject.

I did preprocess using braindecode. And I also tried preprocessing uisng scipy, but got similar accuracy.
In my thought, I missed something in preprocessing.
Could you check the code below and help me find something I missed?
Or, it would be thankful if you share the preprocessing code you used.

Here is code using braindecode:

import tensorflow as tf
from tensorflow.keras import backend as K
from tensorflow.keras.callbacks import ModelCheckpoint

import numpy as np
import pickle
import argparse
import os
import shutil

from arl_eegmodels.EEGModels import EEGNet

from braindecode.datasets.moabb import MOABBDataset
from braindecode.datautil.preprocess import (
    exponential_moving_standardize, preprocess, Preprocessor)
from braindecode.datautil.windowers import create_windows_from_events

# while the default tensorflow ordering is 'channels_last' we set it here
# to be explicit in case if the user has changed the default ordering
K.set_image_data_format('channels_last')


###################
## Configuration ##
###################
# SYSTEM
parser = argparse.ArgumentParser()
parser.add_argument('--name', required=True)
parser.add_argument('--device', default=None)
parser.add_argument('--subject', type=int, required=True)
args = parser.parse_args()

if args.device:
    os.environ["CUDA_VISIBLE_DEVICES"] = args.device # use specific gpu

name = args.name
subject_id = args.subject

def make_results_directory(name, subject_id, base="."):
    results_dir = f"{base}/results/{name}_subject{subject_id}"
    if os.path.exists(results_dir):
        print(f"'{results_dir}' already exists!")
        raise
    os.mkdir(results_dir)
    
    shutil.copy("main.py", results_dir)
    print(f"'{results_dir}' is created!")
    
make_results_directory(name, subject_id, base=".")

###################
#### Load Data ####
###################
dataset = MOABBDataset(dataset_name="BNCI2014001", subject_ids=[subject_id])

low_cut_hz = 4.  # low cut frequency for filtering
high_cut_hz = 40.  # high cut frequency for filtering
# Parameters for exponential moving standardization
factor_new = 1e-3
init_block_size = 1000

preprocessors = [
    Preprocessor('pick_types', eeg=True, meg=False, stim=False),  # Keep EEG sensors
    Preprocessor(lambda x: x * 1e6),  # Convert from V to uV
    Preprocessor('resample', sfreq=128), # Added by me
    Preprocessor('filter', l_freq=low_cut_hz, h_freq=high_cut_hz),  # Bandpass filter
    Preprocessor(exponential_moving_standardize,  # Exponential moving standardization
                 factor_new=factor_new, init_block_size=init_block_size)
]
# Transform the data
preprocess(dataset, preprocessors)

trial_start_offset_seconds = 0.5
# Extract sampling frequency, check that they are same in all datasets
sfreq = dataset.datasets[0].raw.info['sfreq']
assert all([ds.raw.info['sfreq'] == sfreq for ds in dataset.datasets])
# Calculate the trial start offset in samples.
trial_start_offset_samples = int(trial_start_offset_seconds * sfreq)


trial_stop_offset_seconds = -1.5 
trial_stop_offset_samples = int(trial_stop_offset_seconds * sfreq)


# Create windows using braindecode function for this. It needs parameters to define how
# trials should be used.
windows_dataset = create_windows_from_events(
    dataset,
    trial_start_offset_samples=trial_start_offset_samples,
    trial_stop_offset_samples=trial_stop_offset_samples,
    preload=True,
)

splitted = windows_dataset.split('session')
train_set = splitted['session_T']
test_set = splitted['session_E']


X_Train = []
y_Train = []
for run in train_set.datasets:
    for X, y, _ in run:
        X_Train.append(X)
        y_Train.append(y)
X_Train = np.array(X_Train)
y_Train = np.array(y_Train)
        
X_test = []
y_test = []
for run in test_set.datasets:
    for X, y, _ in run:
        X_test.append(X)
        y_test.append(y)
X_test = np.array(X_test)
y_test = np.array(y_test)

print("X_Train shape:", X_Train.shape, "y_Train shape:", y_Train.shape)
print("X_test shape:", X_test.shape, "y_test shape:", y_test.shape)

fold1 = list(range(0,  96))
fold2 = list(range(96, 192))
fold3 = list(range(192,288))
train_val_split = [
    (fold2 + fold3, fold1),    
    (fold3 + fold1, fold2),
    (fold1 + fold2, fold3)
]
    
###########################
#### Cross Validation #####
###########################

fold_hist = []
for fold_step, (train_index, val_index) in enumerate(train_val_split):
    print(f"Start fold {fold_step}")
    print("Train", train_index)
    print("Val", val_index)
    X_train = X_Train[train_index]
    y_train = y_Train[train_index]
    X_val   = X_Train[val_index]
    y_val   = y_Train[val_index]
    
    ###################
    #### Modeling #####
    ###################
    model = EEGNet(nb_classes=4,
                   Chans=22,
                   Samples=256, # 2 seconds at 128 Hz
                   dropoutRate=0.5,
                   kernLength=32, # for SMR data
                   F1=8,
                   D=2,
                   F2=16,
                   norm_rate=0.25, # FC layer
                   dropoutType="Dropout")
    
    ####################
    #    Training      #
    ####################
    # set a valid path for your system to record model checkpoints
    checkpointer = ModelCheckpoint(filepath=f'results/{name}_subject{subject_id}/{name}_subject{subject_id}_fold{fold_step}.h5', verbose=1,
                                   save_best_only=True)

    model.compile(optimizer='adam',
                  loss='sparse_categorical_crossentropy',
                  metrics=['accuracy'])

    train_hist = model.fit(X_train, y_train, 
             batch_size=64, epochs=500,
             verbose=2, validation_data=(X_val, y_val),
             callbacks=[checkpointer])
    
    # load optimal weights
    model.load_weights(f'results/{name}_subject{subject_id}/{name}_subject{subject_id}_fold{fold_step}.h5')
    test_hist = model.evaluate(X_test,  y_test, verbose=2)
    
    fold_hist.append({"train_hist":train_hist.history, "test_hist":test_hist})
    
    fold_best_val_acc = [np.max(_["train_hist"]["val_accuracy"]) for _ in fold_hist]
fold_test_acc = [_["test_hist"][1] for _ in fold_hist]
fold_mean_test_acc = np.mean([_["test_hist"][1] for _ in fold_hist])

print("\n##############################################")
print("subejct", subject_id, "- 3fold best val  accuracy", fold_best_val_acc)
print("subejct", subject_id, "- 3fold      test accuracy", fold_test_acc)
print("subejct", subject_id, "- 3fold mean test accuract:", fold_mean_test_acc)

with open(f"results/{name}_subject{subject_id}/fold_hist.pkl", "wb") as f:
    pickle.dump(fold_hist, f)

Can't not run the code

when I run the code, I got the error "Negative dimension size caused by subtracting 64 from 1 for 'depthwise_conv2d/depthwise' (op: 'DepthwiseConv2dNative') with input shapes: [?,1,64,8], [64,1,8,2]." and I found it's not caused by my dataset, it's caused by the DepthwiseConv2D operate in line 139.

installing EEGLearn in google colab

I tried to install this library in colab using pip install command, however I faced the following error:

ERROR: Cannot unpack file /tmp/pip-unpack-vxbd6gy5/EEGLearn.git (downloaded from /tmp/pip-req-build-eq0fmo3q, content-type: text/html; charset=utf-8); cannot detect archive format
ERROR: Cannot determine archive format of /tmp/pip-req-build-eq0fmo3q

how can I solve this?

A question about max_norm

class MaxNorm(Constraint):
"""MaxNorm weight constraint.

Constrains the weights incident to each hidden unit
to have a norm less than or equal to a desired value.

# Arguments
    m: the maximum norm for the incoming weights.
    axis: integer, axis along which to calculate weight norms.
        For instance, in a `Dense` layer the weight matrix
        has shape `(input_dim, output_dim)`,
        set `axis` to `0` to constrain each weight vector
        of length `(input_dim,)`.
        In a `Conv2D` layer with `data_format="channels_last"`,
        the weight tensor has shape
        `(rows, cols, input_depth, output_depth)`,
        set `axis` to `[0, 1, 2]`
        to constrain the weights of each filter tensor of size
        `(rows, cols, input_depth)`.

# References
    - [Dropout: A Simple Way to Prevent Neural Networks from Overfitting Srivastava, Hinton, et al. 2014](http://www.cs.toronto.edu/~rsalakhu/papers/srivastava14a.pdf)
"""

def __init__(self, max_value=2, axis=0):
    self.max_value = max_value
    self.axis = axis

def __call__(self, w):
    norms = K.sqrt(K.sum(K.square(w), axis=self.axis, keepdims=True))
    desired = K.clip(norms, 0, self.max_value)
    w *= (desired / (K.epsilon() + norms))
    return w

def get_config(self):
    return {'max_value': self.max_value,
            'axis': self.axis}

It seems that the default parameter is not suitable for conv2d?

Input shape consistency with paper

Hi there, thanks for releasing your code.

Assuming that the input has shape (C, T) where C is the number of channels and T is the number of samples in the window, according to Table 2 of the published version of the paper (EEGNet v4), the first layer of the network reshapes the input to a shape of (1, C, T) (so that the first convolutional layer with kernel size (1, 64) is applied along the temporal dimension (temporal convolution/filtering).

Screen Shot 2022-06-24 at 9 58 05 AM

By looking at the code though it seems to me that the input has shape (C, T, 1).

arl-eegmodels/EEGModels.py

Lines 127 to 132 in 4a512e5

input1 = Input(shape = (Chans, Samples, 1))
##################################################################
block1 = Conv2D(F1, (1, kernLength), padding = 'same',
input_shape = (Chans, Samples, 1),
use_bias = False)(input1)

Should there not be a Reshape layer at the bottom of the network? Or am I missing something obvious here?

Error with the Example

I tried to run the example file ("ERP.py"), but got this error:
image

Please can you help with this?

Dimension error EEGnet

InvalidArgumentError: Negative dimension size caused by subtracting 64 from 1 for 'depthwise_conv2d_1/depthwise' (op: 'DepthwiseConv2dNative') with input shapes: [?,1,64,4], [64,1,4,2].
:S

-

i konw

Run EEGNet on CPU

Hi,

I'm getting this error message when testing the code:

tensorflow.python.framework.errors_impl.InvalidArgumentError: Default AvgPoolingOp only supports NHWC on device type CPU
	 [[{{node average_pooling2d/AvgPool}}]]

Is it possible to run EEGNet without GPU?

Problem with the feature explainability methods

Hi,
I have got the DeepLIFT to work and understood the method, though the two other methods mentioned in [1] have I not managed to implement.

For the first method, summarizing averaged outputs of hidden unit activations:

  • How can you access the spatially-filtered data from the layer?
  • Is the topoplots, shown in [1] fig. 6 A, taken from a specified time-stamp? And how do you still know which data corresponds to the different channels?

For the second method, visualizing the convolutional kernel weights:

  • From which layers are the visualized kernels taken from? (Fig 7 and 8 in [1])

Using the weights EEGNet_8_2

Hi,
Thanks for this. I was looking to make use of the weights in EEGNet_8_2.h5 file but I'm encountering errors. Though, my data is in a different shape (16, 768), I was thinking with the necessary params defined (Chans, Samples...),I could create the model and then load the weights from the file.
Error: Shapes (1, 64, 1, 16) and (8, 1, 1, 32) are incompatible
I know the dimensions are different but I was thinking it could carry through somehow.
How would you suggest going about this?
Thanks.

Fitting model only performs on one epoch and then exits

when I run the ERP.py script (after fixing other issues flagged by previous posts), the script runs on one epoch based on this line:
fittedModel = model.fit(X_train, Y_train, batch_size = 16, epochs = 300, verbose = 2, validation_data=(X_validate, Y_validate), callbacks=[checkpointer], class_weight = class_weights)

This is the console output:
Train on 144 samples, validate on 72 samples Epoch 1/300

Could you please help me fix this issue?

Thanks!

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.