Skip to content

Commit

Permalink
Plot brain decode (#345)
Browse files Browse the repository at this point in the history
* Fix bug for MotorImagery All events, setting n_classes

* Fix bug for MotorImagery All events, setting n_classes

* Fix is Valid
Change default value n_classes=None

* Update docs/source/whats_new.rst

* plot_BrainDecode first draft

* [pre-commit.ci] auto fixes from pre-commit.com hooks

* plot_BrainDecode

* [pre-commit.ci] auto fixes from pre-commit.com hooks

* plot_BrainDecode

* plot_BrainDecode

* Update examples/plot_BrainDecode.py

Co-authored-by: Sylvain Chevallier <sylvain.chevallier@universite-paris-saclay.fr>

* Update examples/plot_BrainDecode.py

Co-authored-by: Sylvain Chevallier <sylvain.chevallier@universite-paris-saclay.fr>

* plot_BrainDecode

* plot_BrainDecode, definition of setup_seed in moabb.utils

* plot_BrainDecode, definition of setup_seed in moabb.utils

* brain decode try benchmark

* [pre-commit.ci] auto fixes from pre-commit.com hooks

* Plot_function

* [pre-commit.ci] auto fixes from pre-commit.com hooks

* Delete PyTorch_EEGNetv4.yml

* Delete plot_benchmark_BrainDecode.py

* Renaming the file

* Changing init file

* Changing the tutorial

* Renaming the file to lower

* Updating the InputSetterEEG

* Adding new function to get the models from braindecode, and forcing the reinitialize model if the shape change.

* Partially init the shallow model

* Changing to ShallowNet

* =)

Solving the issue with hardcode variable and changing the way we compare the variable.

* draft test

* removing test

* Plot_function

* [pre-commit.ci] auto fixes from pre-commit.com hooks

* update plot_braindecode

* [pre-commit.ci] auto fixes from pre-commit.com hooks

* Plot BranDecode with dynamically input setter

* [pre-commit.ci] auto fixes from pre-commit.com hooks

* Plot BranDecode with dynamically input setter

* [pre-commit.ci] auto fixes from pre-commit.com hooks

* remove plot_BrainDecode from GitIgnore

* Plot_Benchmark:
- EEGNetv4 with BrainDecode (in_chans)
- EEGInception (in_channels)
- Dataset BNCI2014001 (22channel) and BNCI2014004 (3channel)
- Change in benchmark function: if a pipeline have BrainDecode in the name it is gonna set the return_epochs to True

* [pre-commit.ci] auto fixes from pre-commit.com hooks

* Plot_Benchmark:
- EEGNetv4 with BrainDecode (in_chans)
- EEGInception (in_channels)
- ShallowFBCSPNet
- Deep4Net
- Dataset BNCI2014001 (22channel) and BNCI2014004 (3channel)
- Change in benchmark function: if a pipeline have BrainDecode in the name it is gonna set the return_epochs to True

* Plot_Benchmark:
- EEGNetv4 with BrainDecode (in_chans)
- EEGInception (in_channels)
- ShallowFBCSPNet
- Deep4Net
- Dataset BNCI2014001 (22channel) and BNCI2014004 (3channel)
- Change in benchmark function: if a pipeline have BrainDecode in the name it is gonna set the return_epochs to True

* [pre-commit.ci] auto fixes from pre-commit.com hooks

* precommit stuffs

* cleaning line

* Changing the set seed

* Changing the import

* Renaming BrainDecode to braindecode

* Update moabb/benchmark.py

* renaming to lowercase

* lower case for pipeline folder of braindecode

* Update examples/plot_braindecode.py

Co-authored-by: Sylvain Chevallier <sylvain.chevallier@universite-paris-saclay.fr>

* Update examples/plot_braindecode.py

Co-authored-by: Sylvain Chevallier <sylvain.chevallier@universite-paris-saclay.fr>

* Update examples/pipelines_braindecode/braindecode_Deep4Net.py

Co-authored-by: Sylvain Chevallier <sylvain.chevallier@universite-paris-saclay.fr>

* Update examples/pipelines_braindecode/braindecode_Deep4Net.py

Co-authored-by: Sylvain Chevallier <sylvain.chevallier@universite-paris-saclay.fr>

* Update examples/pipelines_braindecode/braindecode_EEGInception.py

Co-authored-by: Sylvain Chevallier <sylvain.chevallier@universite-paris-saclay.fr>

* Update examples/pipelines_braindecode/braindecode_EEGNetv4.py

Co-authored-by: Sylvain Chevallier <sylvain.chevallier@universite-paris-saclay.fr>

* Modification requested

* Modification requested

* typos, and another small general corrections.

* Fixing small things for the review

* Update examples/plot_benchmark_braindecode.py

Co-authored-by: Sylvain Chevallier <sylvain.chevallier@universite-paris-saclay.fr>

* Update examples/plot_braindecode.py

Co-authored-by: Sylvain Chevallier <sylvain.chevallier@universite-paris-saclay.fr>

* Update examples/pipelines_braindecode/braindecode_ShallowFBCSPNet.py

Co-authored-by: Sylvain Chevallier <sylvain.chevallier@universite-paris-saclay.fr>

* fixing tests

* Adding the Pipeline of braincode in the pipeline folder

* removing deep4net

* fixing test

* adding text

* changing to parametrize

* Updating function

* Updating test function

* changing the init file

* adding braindecode to the folder

* testing hidden util braindecode

* splitting the util tests to not download

* updating the test

---------

Co-authored-by: Sylvain Chevallier <sylvain.chevallier@universite-paris-saclay.fr>
Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com>
Co-authored-by: bruAristimunha <a.bruno@aluno.ufabc.edu.br>
  • Loading branch information
4 people authored Mar 19, 2023
1 parent 01a8133 commit 14b55a1
Show file tree
Hide file tree
Showing 18 changed files with 1,158 additions and 24 deletions.
8 changes: 5 additions & 3 deletions docs/source/pipelines.rst
Original file line number Diff line number Diff line change
Expand Up @@ -16,11 +16,11 @@ Pipelines

features.LogVariance
features.FM
features.ExtendedSSVEPSignal
features.ExtendedSSVEPSignal
features.AugmentedDataset
features.StandardScaler_Epoch
csp.TRCSP
classification.SSVEP_CCA
csp.TRCSP
classification.SSVEP_CCA
deep_learning.KerasDeepConvNet
deep_learning.KerasEEGITNet
deep_learning.KerasEEGNet_8_2
Expand All @@ -42,3 +42,5 @@ Base & Utils
utils_deep_model.EEGNet
utils_deep_model.EEGNet_TC
utils_deep_model.TCN_block
utils_pytorch.BraindecodeDatasetLoader
utils_pytorch.InputShapeSetterEEG
1 change: 1 addition & 0 deletions docs/source/whats_new.rst
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ Enhancements
- Adding new tutorial to benchmark with GridSearchCV (:gh:`323` by `Igor Carrara`_)
- Add six deep learning models (Tensorflow), and build a tutorial to show to use the deep learning model (:gh:`326` by `Igor Carrara`_, `Bruno Aristimunha`_ and `Sylvain Chevallier`_)
- Add a augmentation model to the pipeline (:gh:`326` by `Igor Carrara`_)
- Add BrainDecode example(:gh:`340` by `Igor Carrara`_ and `Bruno Aristimunha`_)
- Add Google Analytics to the documentation (:gh:`335` by `Bruno Aristimunha`_)

Bugs
Expand Down
64 changes: 64 additions & 0 deletions examples/pipelines_braindecode/braindecode_EEGInception.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
import torch
from braindecode import EEGClassifier
from braindecode.models import EEGInception
from sklearn.pipeline import Pipeline
from skorch.callbacks import EarlyStopping, EpochScoring
from skorch.dataset import ValidSplit

from moabb.pipelines.utils_pytorch import BraindecodeDatasetLoader, InputShapeSetterEEG


# Set up GPU if it is there
cuda = torch.cuda.is_available()
device = "cuda" if cuda else "cpu"

# Hyperparameter
LEARNING_RATE = 0.0001
WEIGHT_DECAY = 0
BATCH_SIZE = 64
SEED = 42
VERBOSE = 1
EPOCH = 10
PATIENCE = 3

# Create the dataset
create_dataset = BraindecodeDatasetLoader()

# Set EEG Inception model
model = EEGInception(in_channels=1, n_classes=2, input_window_samples=100)

# Define a Skorch classifier
clf = EEGClassifier(
module=model,
criterion=torch.nn.CrossEntropyLoss,
optimizer=torch.optim.Adam,
optimizer__lr=LEARNING_RATE,
batch_size=BATCH_SIZE,
max_epochs=EPOCH,
train_split=ValidSplit(0.2, random_state=SEED),
device=device,
callbacks=[
EarlyStopping(monitor="valid_loss", patience=PATIENCE),
EpochScoring(
scoring="accuracy", on_train=True, name="train_acc", lower_is_better=False
),
EpochScoring(
scoring="accuracy", on_train=False, name="valid_acc", lower_is_better=False
),
InputShapeSetterEEG(
params_list=["in_channels", "input_window_samples", "n_classes"],
),
],
verbose=VERBOSE, # Not printing the results for each epoch
)

# Create the pipelines
pipes = Pipeline([("Braindecode_dataset", create_dataset), ("EEGInception", clf)])

# this is what will be loaded
PIPELINE = {
"name": "braindecode_EEGInception",
"paradigms": ["LeftRightImagery", "MotorImagery"],
"pipeline": pipes,
"citations": "https://doi.org/10.1109/TNSRE.2020.3048106",
}
64 changes: 64 additions & 0 deletions examples/pipelines_braindecode/braindecode_EEGNetv4.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
import torch
from braindecode import EEGClassifier
from braindecode.models import EEGNetv4
from sklearn.pipeline import Pipeline
from skorch.callbacks import EarlyStopping, EpochScoring
from skorch.dataset import ValidSplit

from moabb.pipelines.utils_pytorch import BraindecodeDatasetLoader, InputShapeSetterEEG


# Set up GPU if it is there
cuda = torch.cuda.is_available()
device = "cuda" if cuda else "cpu"

# Hyperparameter
LEARNING_RATE = 0.0001
WEIGHT_DECAY = 0
BATCH_SIZE = 64
SEED = 42
VERBOSE = 1
EPOCH = 10
PATIENCE = 3

# Create the dataset
create_dataset = BraindecodeDatasetLoader()

# Set EEGNetv4 model
model = EEGNetv4(in_chans=1, n_classes=2, input_window_samples=100)

# Define a Skorch classifier
clf = EEGClassifier(
module=model,
criterion=torch.nn.CrossEntropyLoss,
optimizer=torch.optim.Adam,
optimizer__lr=LEARNING_RATE,
batch_size=BATCH_SIZE,
max_epochs=EPOCH,
train_split=ValidSplit(0.2, random_state=SEED),
device=device,
callbacks=[
EarlyStopping(monitor="valid_loss", patience=PATIENCE),
EpochScoring(
scoring="accuracy", on_train=True, name="train_acc", lower_is_better=False
),
EpochScoring(
scoring="accuracy", on_train=False, name="valid_acc", lower_is_better=False
),
InputShapeSetterEEG(
params_list=["in_chans", "input_window_samples", "n_classes"],
),
],
verbose=VERBOSE, # Not printing the results for each epoch
)

# Create the pipelines
pipes = Pipeline([("braindecode_dataset", create_dataset), ("EEGNetv4", clf)])

# this is what will be loaded
PIPELINE = {
"name": "braindecode_EEGNetv4",
"paradigms": ["LeftRightImagery", "MotorImagery"],
"pipeline": pipes,
"citations": "https://doi.org/10.1088/1741-2552/aace8c",
}
66 changes: 66 additions & 0 deletions examples/pipelines_braindecode/braindecode_ShallowFBCSPNet.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
import torch
from braindecode import EEGClassifier
from braindecode.models import ShallowFBCSPNet
from sklearn.pipeline import Pipeline
from skorch.callbacks import EarlyStopping, EpochScoring
from skorch.dataset import ValidSplit

from moabb.pipelines.utils_pytorch import BraindecodeDatasetLoader, InputShapeSetterEEG


# Set up GPU if it is there
cuda = torch.cuda.is_available()
device = "cuda" if cuda else "cpu"

# Hyperparameter
LEARNING_RATE = 0.0001
WEIGHT_DECAY = 0
BATCH_SIZE = 64
SEED = 42
VERBOSE = 1
EPOCH = 10
PATIENCE = 3

# Create the dataset
create_dataset = BraindecodeDatasetLoader()

# Set Shallow Filter Bank CSP Net model
model = ShallowFBCSPNet(
in_chans=1, n_classes=2, input_window_samples=100, final_conv_length="auto"
)

# Define a Skorch classifier
clf = EEGClassifier(
module=model,
criterion=torch.nn.CrossEntropyLoss,
optimizer=torch.optim.Adam,
optimizer__lr=LEARNING_RATE,
batch_size=BATCH_SIZE,
max_epochs=EPOCH,
train_split=ValidSplit(0.2, random_state=SEED),
device=device,
callbacks=[
EarlyStopping(monitor="valid_loss", patience=PATIENCE),
EpochScoring(
scoring="accuracy", on_train=True, name="train_acc", lower_is_better=False
),
EpochScoring(
scoring="accuracy", on_train=False, name="valid_acc", lower_is_better=False
),
InputShapeSetterEEG(
params_list=["in_chans", "input_window_samples", "n_classes"],
),
],
verbose=VERBOSE, # Not printing the results for each epoch
)

# Create the pipelines
pipes = Pipeline([("braindecode_dataset", create_dataset), ("ShallowFBCSPNet", clf)])

# this is what will be loaded
PIPELINE = {
"name": "braindecode_ShallowFBCSPNet",
"paradigms": ["LeftRightImagery", "MotorImagery"],
"pipeline": pipes,
"citations": "https://doi.org/10.1002/hbm.23730",
}
121 changes: 121 additions & 0 deletions examples/plot_benchmark_braindecode.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,121 @@
"""
=======================================================================
Benchmarking on MOABB with Braindecode (PyTorch) deep net architectures
=======================================================================
This example shows how to use MOABB to benchmark a set of Braindecode pipelines (deep learning
architectures) on all available datasets.
For this example, we will use only 2 datasets to keep the computation time low, but this benchmark is designed
to easily scale to many datasets.
"""
# Authors: Igor Carrara <igor.carrara@inria.fr>
# Bruno Aristimunha <b.aristimunha@gmail.com>
# Sylvain Chevallier <sylvain.chevallier@universite-paris-saclay.fr>
#
# License: BSD (3-clause)

import os

import matplotlib.pyplot as plt
import torch
from absl.logging import ERROR, set_verbosity

from moabb import benchmark, set_log_level
from moabb.analysis.plotting import score_plot
from moabb.datasets import BNCI2014001, BNCI2014004
from moabb.utils import setup_seed


set_log_level("info")
# Avoid output Warning
set_verbosity(ERROR)
os.environ["TF_CPP_MIN_LOG_LEVEL"] = "3"

# Print Information PyTorch
print(f"Torch Version: {torch.__version__}")

# Set up GPU if it is there
cuda = torch.cuda.is_available()
device = "cuda" if cuda else "cpu"
print("GPU is", "AVAILABLE" if cuda else "NOT AVAILABLE")

###############################################################################
# In this example, we will use only 2 subjects from the dataset ``BNCI2014001`` and ``BNCI2014004``.
#
# Running the benchmark
# ---------------------
#
# The benchmark is run using the ``benchmark`` function. You need to specify the
# folder containing the pipelines, the kind of evaluation, and the paradigm
# to use. By default, the benchmark will use all available datasets for all
# paradigms listed in the pipelines. You could restrict to specific evaluation and
# paradigm using the ``evaluations`` and ``paradigms`` arguments.
#
# To save computation time, the results are cached. If you want to re-run the
# benchmark, you can set the ``overwrite`` argument to ``True``.
#
# It is possible to indicate the folder to cache the results and the one to save
# the analysis & figures. By default, the results are saved in the ``results``
# folder, and the analysis & figures are saved in the ``benchmark`` folder.
#
# This code is implemented to run on CPU. If you're using a GPU, do not use multithreading
# (i.e. set n_jobs=1)
#
# In order to allow the benchmark function to work with return_epoch=True (Required to use Braindecode(
# we need to call each pipeline as "braindecode_xxx...", with xxx the name of the model to be
# handled correctly by the benchmark function.

# Set up reproducibility of Tensorflow
setup_seed(42)

# Restrict this example only to the first two subjects of BNCI2014001
dataset = BNCI2014001()
dataset2 = BNCI2014004()
dataset.subject_list = dataset.subject_list[:2]
dataset2.subject_list = dataset2.subject_list[:2]
datasets = [dataset, dataset2]

results = benchmark(
pipelines="./pipelines_braindecode",
evaluations=["CrossSession"],
paradigms=["LeftRightImagery"],
include_datasets=datasets,
results="./results/",
overwrite=False,
plot=False,
output="./benchmark/",
n_jobs=-1,
)

###############################################################################
# The deep learning architectures implemented in MOABB using Braindecode are:
#
# - Shallow Convolutional Network [1]_
# - Deep Convolutional Network [1]_
# - EEGNetv4 [2]_
# - EEGInception [3]_
#
# Benchmark prints a summary of the results. Detailed results are saved in a
# pandas dataframe, and can be used to generate figures. The analysis & figures
# are saved in the ``benchmark`` folder.

score_plot(results)
plt.show()

##############################################################################
# References
# ----------
# .. [1] Schirrmeister, R. T., Springenberg, J. T., Fiederer, L. D. J.,
# Glasstetter, M., Eggensperger, K., Tangermann, M., ... & Ball, T. (2017).
# `Deep learning with convolutional neural networks for EEG decoding and
# visualization <https://doi.org/10.1002/hbm.23730>`_.
# Human brain mapping, 38(11), 5391-5420.
# .. [2] Lawhern, V. J., Solon, A. J., Waytowich, N. R., Gordon, S. M.,
# Hung, C. P., & Lance, B. J. (2018). `EEGNet: a compact convolutional neural
# network for EEG-based brain-computer interfaces.
# <https://doi.org/10.1088/1741-2552/aace8c>`_
# Journal of neural engineering, 15(5), 056013.
# .. [3] Santamaria-Vazquez, E., Martinez-Cagigal, V., Vaquerizo-Villar,
# F., & Hornero, R. (2020). `EEG-inception: A novel deep convolutional neural network
# for assistive ERP-based brain-computer interfaces.
# <https://doi.org/10.1109/TNSRE.2020.3048106>`_
# IEEE Transactions on Neural Systems and Rehabilitation Engineering
Loading

0 comments on commit 14b55a1

Please sign in to comment.