From 6fddf25c6676f9e62772e2fbf38e9666468827cf Mon Sep 17 00:00:00 2001 From: bruAristimunha Date: Fri, 18 Oct 2024 14:17:09 +0200 Subject: [PATCH 01/15] MNT: fixing the numpy 2.0 --- moabb/analysis/results.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/moabb/analysis/results.py b/moabb/analysis/results.py index a5e467936..1c539983b 100644 --- a/moabb/analysis/results.py +++ b/moabb/analysis/results.py @@ -112,7 +112,7 @@ def __init__( if not osp.isfile(self.filepath): with h5py.File(self.filepath, "w") as f: - f.attrs["create_time"] = np.string_( + f.attrs["create_time"] = np.str_( "{:%Y-%m-%d, %H:%M}".format(datetime.now()) ) From 8d102156d4768c199c75c73b947d471204eaa332 Mon Sep 17 00:00:00 2001 From: bruAristimunha Date: Fri, 18 Oct 2024 14:18:33 +0200 Subject: [PATCH 02/15] DOC: fixing the docstring --- docs/source/whats_new.rst | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/source/whats_new.rst b/docs/source/whats_new.rst index 660b5bf24..719d8775d 100644 --- a/docs/source/whats_new.rst +++ b/docs/source/whats_new.rst @@ -23,6 +23,7 @@ Bugs - Fix Stieger2021 dataset bugs (:gh:`651` by `Martin Wimpff`_) - Unpinning major version Scikit-learn and numpy (:gh:`652` by `Bruno Aristimunha`_) +- Replacing the func:`numpy.string_` to func:`numpy.str_ API changes ~~~~~~~~~~~ From 83add19549ba21a438a3c06c4e14c76799f0775c Mon Sep 17 00:00:00 2001 From: bruAristimunha Date: Fri, 18 Oct 2024 14:36:09 +0200 Subject: [PATCH 03/15] DOC: fixing the docstring --- moabb/analysis/results.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/moabb/analysis/results.py b/moabb/analysis/results.py index 1c539983b..e3f224e41 100644 --- a/moabb/analysis/results.py +++ b/moabb/analysis/results.py @@ -112,7 +112,7 @@ def __init__( if not osp.isfile(self.filepath): with h5py.File(self.filepath, "w") as f: - f.attrs["create_time"] = np.str_( + f.attrs["create_time"] = np.bytes_( "{:%Y-%m-%d, %H:%M}".format(datetime.now()) ) From 06c0b976b00506f8f06e629f75b9fb23f3b48189 Mon Sep 17 00:00:00 2001 From: bruAristimunha Date: Fri, 18 Oct 2024 14:54:34 +0200 Subject: [PATCH 04/15] DOC: fixing more numpy --- moabb/analysis/meta_analysis.py | 4 ++-- moabb/evaluations/evaluations.py | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/moabb/analysis/meta_analysis.py b/moabb/analysis/meta_analysis.py index 620607107..b1a15c7ad 100644 --- a/moabb/analysis/meta_analysis.py +++ b/moabb/analysis/meta_analysis.py @@ -322,8 +322,8 @@ def find_significant_differences(df, perm_cutoff=20): nsubs = np.array([df.loc[df.dataset == d, "nsub"].mean() for d in dsets]) P_full = df.pivot_table(values="p", index=["dataset", "pipe1"], columns="pipe2") T_full = df.pivot_table(values="smd", index=["dataset", "pipe1"], columns="pipe2") - P = np.full((len(algs), len(algs)), np.NaN) - T = np.full((len(algs), len(algs)), np.NaN) + P = np.full((len(algs), len(algs)), np.nan) + T = np.full((len(algs), len(algs)), np.nan) for i in range(len(algs)): for j in range(len(algs)): if i != j: diff --git a/moabb/evaluations/evaluations.py b/moabb/evaluations/evaluations.py index 9a795b113..9685bb543 100644 --- a/moabb/evaluations/evaluations.py +++ b/moabb/evaluations/evaluations.py @@ -254,7 +254,7 @@ def _evaluate( if _carbonfootprint: emissions = tracker.stop() if emissions is None: - emissions = np.NaN + emissions = np.nan duration = time() - t_start nchan = X.info["nchan"] if isinstance(X, BaseEpochs) else X.shape[1] From cd992dc3cf3d3906235a00e7ebd52f9011b3e580 Mon Sep 17 00:00:00 2001 From: bruAristimunha Date: Fri, 18 Oct 2024 15:25:37 +0200 Subject: [PATCH 05/15] DOC: deprecated braindecode inside moabb module in favor of braindecode --- moabb/pipelines/__init__.py | 24 ----- moabb/pipelines/utils_pytorch.py | 171 ------------------------------- 2 files changed, 195 deletions(-) delete mode 100644 moabb/pipelines/utils_pytorch.py diff --git a/moabb/pipelines/__init__.py b/moabb/pipelines/__init__.py index 35de42104..f550332c3 100644 --- a/moabb/pipelines/__init__.py +++ b/moabb/pipelines/__init__.py @@ -26,18 +26,11 @@ def __getattr__(name): "EEGNet", "TCN_block", } - utils_pytorch_classes = { - "InputShapeSetterEEG", - "BraindecodeDatasetLoader", - "get_shape_from_baseconcat", - } if name in deep_learning_classes and _check_if_tensorflow_installed(): return _import_class(name, ".deep_learning") elif name in utils_deep_model_classes and _check_if_tensorflow_installed(): return _import_class(name, ".utils_deep_model") - elif name in utils_pytorch_classes and _check_if_braindecode_installed(): - return _import_class(name, ".utils_pytorch") raise AttributeError(f"Module '{__name__}' has no attribute '{name}'") @@ -77,20 +70,3 @@ def _check_if_tensorflow_installed(): "\033[0m", # This resets the color back to normal ) return False - - -def _check_if_braindecode_installed(): - try: - import braindecode - - return True - except ModuleNotFoundError: - warn( - "Braindecode is not installed. " - "You won't be able to use these braindecode functions if you " - "attempt to do so. \n" - "\033[94m" # This is the ANSI escape code for blue - "pip install braindecode" - "\033[0m", # This resets the color back to normal - ) - return False diff --git a/moabb/pipelines/utils_pytorch.py b/moabb/pipelines/utils_pytorch.py deleted file mode 100644 index b8e896482..000000000 --- a/moabb/pipelines/utils_pytorch.py +++ /dev/null @@ -1,171 +0,0 @@ -from collections import Counter -from functools import partial -from inspect import getmembers, isclass, isroutine - -import mne -from braindecode.datasets.base import BaseConcatDataset -from braindecode.datasets.xy import create_from_X_y -from numpy import unique -from sklearn.base import BaseEstimator, TransformerMixin -from skorch.callbacks import Callback -from torch.nn import Module - - -# check if the data format is numpy or mne epoch -def _check_data_format(X): - """Check if the data format is compatible with braindecode. Expect values - in the format of MNE objects. - - Parameters - ---------- - X: BaseConcatDataset - - Returns - ------- - """ - if not isinstance(X, mne.EpochsArray): - raise ValueError( - "The data format is not supported. " - "Please use the option return_epochs=True" - "inside the Evaluations module." - ) - - -class BraindecodeDatasetLoader(BaseEstimator, TransformerMixin): - """Class to Load the data from MOABB in a format compatible with - braindecode.""" - - def __init__(self, drop_last_window=False, kw_args=None): - self.drop_last_window = drop_last_window - self.kw_args = kw_args - - def fit(self, X, y=None): - _check_data_format(X) - self.y = y - return self - - def transform(self, X, y=None): - _check_data_format(X) - if y is None: - y = self.y - dataset = create_from_X_y( - X=X.get_data(), - y=y, - window_size_samples=X.get_data().shape[2], - window_stride_samples=X.get_data().shape[2], - drop_last_window=self.drop_last_window, - ch_names=X.info["ch_names"], - sfreq=X.info["sfreq"], - ) - - return dataset - - def __sklearn_is_fitted__(self): - """Return True since Transformer is stateless.""" - return True - - -def get_shape_from_baseconcat(X, param_name): - """Get the shape of the data after BaseConcatDataset is applied.""" - if isinstance(X, BaseConcatDataset): - in_channel = X[0][0].shape[0] - input_window_samples = X[0][0].shape[1] - return {param_name[0]: in_channel, param_name[1]: input_window_samples} - else: - return X.shape - - -def _find_model_from_braindecode(model_name): - # soft dependency on braindecode - model_list = [] - import braindecode.models as models - - for ds in getmembers(models, isclass): - if issubclass(ds[1], Module): - model_list.append(ds[1]) - - for model in model_list: - if model_name == model.__name__: - # return an instance of the found model not initialized - if model_name == "ShallowFBCSPNet": - model = partial(model, final_conv_length="auto") - - return model - raise ValueError(f"{model_name} not found in braindecode models") - - -class InputShapeSetterEEG(Callback): - """Sets the input dimension of the PyTorch module to the input dimension - of the training data. - This can be of use when the shape of X is not known beforehand, - e.g. when using a skorch model within an sklearn pipeline and - grid-searching feature transformers, or using feature selection - methods.InputShapeSetterEEG - Basic usage: - - Parameters - ---------- - params_list : list - The list of parameters that define the - input dimension in its ``__init__`` method. - Usually the mandatory parameters from the model. - input_dim_fn : callable, None (default=None) - In case your ``X`` value is more complex and deriving the input - dimension is not as easy as ``X.shape[-1]`` you can pass a callable - to this parameter which takes ``X`` and returns the input dimension. - module_name : str (default='module') - Only needs change when you are using more than one module in your - skorch model (e.g., in case of GANs). - """ - - def __init__( - self, - params_list=None, - input_dim_fn=get_shape_from_baseconcat, - module_name="module", - ): - self.module_name = module_name - self.params_list = params_list - self.input_dim_fn = input_dim_fn - - def get_input_dim(self, X): - if self.input_dim_fn is not None: - return self.input_dim_fn(X, self.params_list) - if len(X.shape) < 2: - raise ValueError( - "Expected at least two-dimensional input data for X. " - "If your data is one-dimensional, please use the " - "`input_dim_fn` parameter to infer the correct " - "input shape." - ) - return X.shape[-1] - - def on_train_begin(self, net, X, y, **kwargs): - # Get the parameters of the neural network - params = net.get_params() - # Get the input dimensions from the BaseConcat dataset - params_get_from_dataset: dict = self.get_input_dim(X) - # Get the number of classes in the output labels - params_get_from_dataset["n_classes"] = len(unique(y)) - - # Get all the parameters of the neural network module - all_params_module = getmembers(params["module"], lambda x: not (isroutine(x))) - # Filter the parameters to only include the selected ones - selected_params_module = { - sub[0]: sub[1] for sub in all_params_module if sub[0] in self.params_list - } - - # Check if the selected parameters are inside the model parameters - if Counter(params_get_from_dataset.keys()) != Counter( - selected_params_module.keys() - ): - raise ValueError("Set the correct input name for the model from BrainDecode.") - else: - # Find the new module based on the current module's class name - new_module = _find_model_from_braindecode(net.module.__class__.__name__) - # Initialize the new module with the dataset parameters - module_initilized = new_module(**params_get_from_dataset) - # Set the neural network module to the new initialized module - net.set_params(module=module_initilized) - # Initialize the new module - net.initialize_module() From dd25e85a26eb2327cdf3ef646e73450dfda79c72 Mon Sep 17 00:00:00 2001 From: bruAristimunha Date: Fri, 18 Oct 2024 15:28:48 +0200 Subject: [PATCH 06/15] DOC: updating whats_new.rst file --- docs/source/whats_new.rst | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/source/whats_new.rst b/docs/source/whats_new.rst index 719d8775d..b71c610b8 100644 --- a/docs/source/whats_new.rst +++ b/docs/source/whats_new.rst @@ -27,6 +27,7 @@ Bugs API changes ~~~~~~~~~~~ +- Removing the braindecode module from inside moabb (:gh:`666` by `Bruno Aristimunha`_ ) Version - 1.1.1 (Stable - PyPi) --------------------------------- From 54db463c5430901ae49b5a51e0de2dc04c100444 Mon Sep 17 00:00:00 2001 From: bruAristimunha Date: Fri, 18 Oct 2024 15:31:01 +0200 Subject: [PATCH 07/15] DOC: fixing whats_new.rst --- docs/source/whats_new.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/source/whats_new.rst b/docs/source/whats_new.rst index 719d8775d..03f64c01e 100644 --- a/docs/source/whats_new.rst +++ b/docs/source/whats_new.rst @@ -23,7 +23,7 @@ Bugs - Fix Stieger2021 dataset bugs (:gh:`651` by `Martin Wimpff`_) - Unpinning major version Scikit-learn and numpy (:gh:`652` by `Bruno Aristimunha`_) -- Replacing the func:`numpy.string_` to func:`numpy.str_ +- Replacing the func:`numpy.string_` to func:`numpy.bytes_` (:gh:`665` by `Bruno Aristimunha`_) API changes ~~~~~~~~~~~ From 33ca7f45ce232bf7159676acc439f75884e3cadc Mon Sep 17 00:00:00 2001 From: bruAristimunha Date: Fri, 18 Oct 2024 15:40:00 +0200 Subject: [PATCH 08/15] DOC: fixing api doc rst --- docs/source/pipelines.rst | 2 -- 1 file changed, 2 deletions(-) diff --git a/docs/source/pipelines.rst b/docs/source/pipelines.rst index ca4d7aa6f..51b43aa47 100644 --- a/docs/source/pipelines.rst +++ b/docs/source/pipelines.rst @@ -44,5 +44,3 @@ Base & Utils utils_deep_model.EEGNet utils_deep_model.EEGNet_TC utils_deep_model.TCN_block - utils_pytorch.BraindecodeDatasetLoader - utils_pytorch.InputShapeSetterEEG From ff077dc013df42da73e6a101f8349fe5666967d1 Mon Sep 17 00:00:00 2001 From: bruAristimunha Date: Fri, 18 Oct 2024 18:53:46 +0200 Subject: [PATCH 09/15] DOC: removing braindecode --- moabb/tests/util_braindecode.py | 175 -------------------------------- 1 file changed, 175 deletions(-) delete mode 100644 moabb/tests/util_braindecode.py diff --git a/moabb/tests/util_braindecode.py b/moabb/tests/util_braindecode.py deleted file mode 100644 index c4423b5ec..000000000 --- a/moabb/tests/util_braindecode.py +++ /dev/null @@ -1,175 +0,0 @@ -import unittest - -import numpy as np -import pytest -from mne import EpochsArray, create_info -from sklearn.preprocessing import LabelEncoder - - -try: - from braindecode.datasets.base import BaseConcatDataset, WindowsDataset - from braindecode.datasets.xy import create_from_X_y - - from moabb.pipelines.utils_pytorch import BraindecodeDatasetLoader - - no_braindecode = False -except ImportError: - no_braindecode = None - - -from moabb.datasets.fake import FakeDataset -from moabb.tests import SimpleMotorImagery - - -@pytest.fixture(scope="module") -def data(): - """Return EEG data from dataset to test transformer.""" - paradigm = SimpleMotorImagery() - dataset = FakeDataset(paradigm="imagery") - X, labels, metadata = paradigm.get_data(dataset, subjects=[1], return_epochs=True) - y = LabelEncoder().fit_transform(labels) - return X, y, labels, metadata - - -@pytest.mark.skipif(no_braindecode is None, reason="Braindecode is not installed") -class TestTransformer: - def test_transform_input_and_output_shape(self, data): - X, y, _, info = data - transformer = BraindecodeDatasetLoader() - braindecode_dataset = transformer.fit_transform(X, y=y) - assert ( - len(braindecode_dataset) == X.get_data().shape[0] - and braindecode_dataset[0][0].shape[0] == X.get_data().shape[1] - and braindecode_dataset[0][0].shape[1] == X.get_data().shape[2] - ) - - def test_sklearn_is_fitted(self, data): - transformer = BraindecodeDatasetLoader() - assert transformer.__sklearn_is_fitted__() - - def test_transformer_fit(self, data): - """Test whether transformer can fit to some training data.""" - X_train, y_train, _, _ = data - transformer = BraindecodeDatasetLoader() - assert transformer.fit(X_train, y_train) == transformer - - def test_transformer_transform_returns_dataset(self, data): - """Test whether the output of the transform method is a - BaseConcatDataset.""" - X_train, y_train, _, _ = data - transformer = BraindecodeDatasetLoader() - dataset = transformer.fit(X_train, y_train).transform(X_train, y_train) - assert isinstance(dataset, BaseConcatDataset) - - def test_transformer_transform_contents(self, data): - """Test whether the contents and metadata of a transformed dataset are - correct.""" - X_train, y_train, _, _ = data - transformer = BraindecodeDatasetLoader() - dataset = transformer.fit(X_train, y_train).transform(X_train, y_train) - assert len(dataset) == len(X_train) - # test the properties of one epoch - that they match the input MNE Epoch object - sample_epoch = dataset.datasets[0][0] - # assert with approximately equal values - assert np.allclose(sample_epoch[0], X_train.get_data()[0]) - assert sample_epoch[1] == y_train[0] - - def test_sfreq_passed_through(self, data): - """Test if the sfreq parameter makes it through the transformer.""" - sfreq = 128.0 - info = create_info(ch_names=["test"], sfreq=sfreq, ch_types=["eeg"]) - data = np.random.normal(size=(2, 1, 10 * int(sfreq))) * 1e-6 - # create some noise data in a 10s window - epochs = EpochsArray(data, info=info) - y_train = np.array([0]) - transformer = BraindecodeDatasetLoader() - dataset = transformer.fit(epochs, y_train).transform(epochs, y_train) - - if not isinstance(dataset.datasets[0], WindowsDataset): - assert dataset.datasets[0].raw.info["sfreq"] == sfreq - else: - assert dataset.datasets[0].windows.info["sfreq"] == sfreq - - def test_kw_args_initialization(self): - """Test initializing the transformer with kw_args.""" - kw_args = {"sampling_rate": 128} - transformer = BraindecodeDatasetLoader(kw_args=kw_args) - assert transformer.kw_args == kw_args - - def test_is_fitted_method(self): - """Test __sklearn_is_fitted__ returns True.""" - transformer = BraindecodeDatasetLoader() - is_fitter = transformer.__sklearn_is_fitted__() - assert is_fitter - - def test_assert_raises_value_error(self, data): - """Test that an invalid argument gives a ValueError.""" - X_train, y_train, _, _ = data - transformer = BraindecodeDatasetLoader() - invalid_param_name = "invalid" - with pytest.raises(TypeError): - transformer.fit(X_train, y=y_train, **{invalid_param_name: None}) - - def test_type_create_from_X_y_vs_transfomer(self, data): - """Test the type from create_from_X_y() and the transformer.""" - X_train, y_train, _, _ = data - - dataset = create_from_X_y( - X_train.get_data(), - y=y_train, - window_size_samples=X_train.get_data().shape[2], - window_stride_samples=X_train.get_data().shape[2], - drop_last_window=False, - sfreq=X_train.info["sfreq"], - ) - transformer = BraindecodeDatasetLoader() - dataset_trans = transformer.fit(X=X_train, y=y_train).transform(X_train) - assert isinstance(dataset_trans, BaseConcatDataset) - assert type(dataset_trans) == type(dataset) - - def test_wrong_input(self): - """Test that an invalid input raises a ValueError.""" - transformer = BraindecodeDatasetLoader() - with pytest.raises(ValueError): - transformer.fit_transform(np.random.normal(size=(2, 1, 10)), y=np.array([0])) - - def test_transformer_transform_with_custom_y(self, data): - """Test whether the provided y is used during transform.""" - X_train, y_train, _, _ = data - transformer = BraindecodeDatasetLoader() - - # Create test data with different y values - X_test = X_train.copy() - y_test = y_train + 1 - - # Fit the transformer with training data and custom y - transformer.fit(X_train, y_train) - - # Transform the test data with custom y - dataset_test = transformer.transform(X_test, y=y_test) - - # Verify that the transformed dataset contains the test data's x values and the custom y values - assert len(dataset_test) == len(X_test) - assert np.array_equal(dataset_test[0][1], y_test[0]) - assert np.array_equal(dataset_test[1][1], y_test[1]) - - def test_transformer_transform_with_default_y(self, data): - """Test whether self.y is used when y is not provided during - transform.""" - X_train, y_train, _, _ = data - transformer = BraindecodeDatasetLoader() - - # Fit the transformer with training data and default y - transformer.fit(X_train, y_train) - - # Transform the test data without providing y - dataset_test = transformer.transform(X_train) - - # Verify that the transformed dataset contains the training data's x values and the default y values - assert len(dataset_test) == len(X_train) - assert np.array_equal(dataset_test[0][1], y_train[0]) - assert np.array_equal(dataset_test[1][1], y_train[1]) - - -if __name__ == "__main__": - unittest.main() From fdd2ccda70c16d6733bec23da86bb11bc723d777 Mon Sep 17 00:00:00 2001 From: bruAristimunha Date: Fri, 18 Oct 2024 18:58:32 +0200 Subject: [PATCH 10/15] DOC: removing braindecode --- moabb/tests/util_braindecode.py | 175 -------------------------------- 1 file changed, 175 deletions(-) delete mode 100644 moabb/tests/util_braindecode.py diff --git a/moabb/tests/util_braindecode.py b/moabb/tests/util_braindecode.py deleted file mode 100644 index 8076164fb..000000000 --- a/moabb/tests/util_braindecode.py +++ /dev/null @@ -1,175 +0,0 @@ -import unittest - -import numpy as np -import pytest -from mne import EpochsArray, create_info -from sklearn.preprocessing import LabelEncoder - - -try: - from braindecode.datasets.base import BaseConcatDataset, WindowsDataset - from braindecode.datasets.xy import create_from_X_y - - from moabb.pipelines.utils_pytorch import BraindecodeDatasetLoader - - no_braindecode = False -except ImportError: - no_braindecode = None - - -from moabb.datasets.fake import FakeDataset -from moabb.tests import SimpleMotorImagery - - -@pytest.fixture(scope="module") -def data(): - """Return EEG data from dataset to test transformer.""" - paradigm = SimpleMotorImagery() - dataset = FakeDataset(paradigm="imagery") - X, labels, metadata = paradigm.get_data(dataset, subjects=[1], return_epochs=True) - y = LabelEncoder().fit_transform(labels) - return X, y, labels, metadata - - -@pytest.mark.skipif(no_braindecode is None, reason="Braindecode is not installed") -class TestTransformer: - def test_transform_input_and_output_shape(self, data): - X, y, _, info = data - transformer = BraindecodeDatasetLoader() - braindecode_dataset = transformer.fit_transform(X, y=y) - assert ( - len(braindecode_dataset) == X.get_data().shape[0] - and braindecode_dataset[0][0].shape[0] == X.get_data().shape[1] - and braindecode_dataset[0][0].shape[1] == X.get_data().shape[2] - ) - - def test_sklearn_is_fitted(self, data): - transformer = BraindecodeDatasetLoader() - assert transformer.__sklearn_is_fitted__() - - def test_transformer_fit(self, data): - """Test whether transformer can fit to some training data.""" - X_train, y_train, _, _ = data - transformer = BraindecodeDatasetLoader() - assert transformer.fit(X_train, y_train) == transformer - - def test_transformer_transform_returns_dataset(self, data): - """Test whether the output of the transform method is a - BaseConcatDataset.""" - X_train, y_train, _, _ = data - transformer = BraindecodeDatasetLoader() - dataset = transformer.fit(X_train, y_train).transform(X_train, y_train) - assert isinstance(dataset, BaseConcatDataset) - - def test_transformer_transform_contents(self, data): - """Test whether the contents and metadata of a transformed dataset are - correct.""" - X_train, y_train, _, _ = data - transformer = BraindecodeDatasetLoader() - dataset = transformer.fit(X_train, y_train).transform(X_train, y_train) - assert len(dataset) == len(X_train) - # test the properties of one epoch - that they match the input MNE Epoch object - sample_epoch = dataset.datasets[0][0] - # assert with approximately equal values - assert np.allclose(sample_epoch[0], X_train.get_data()[0]) - assert sample_epoch[1] == y_train[0] - - def test_sfreq_passed_through(self, data): - """Test if the sfreq parameter makes it through the transformer.""" - sfreq = 128.0 - info = create_info(ch_names=["test"], sfreq=sfreq, ch_types=["eeg"]) - data = np.random.normal(size=(2, 1, 10 * int(sfreq))) * 1e-6 - # create some noise data in a 10s window - epochs = EpochsArray(data, info=info) - y_train = np.array([0]) - transformer = BraindecodeDatasetLoader() - dataset = transformer.fit(epochs, y_train).transform(epochs, y_train) - - if not isinstance(dataset.datasets[0], WindowsDataset): - assert dataset.datasets[0].raw.info["sfreq"] == sfreq - else: - assert dataset.datasets[0].windows.info["sfreq"] == sfreq - - def test_kw_args_initialization(self): - """Test initializing the transformer with kw_args.""" - kw_args = {"sampling_rate": 128} - transformer = BraindecodeDatasetLoader(kw_args=kw_args) - assert transformer.kw_args == kw_args - - def test_is_fitted_method(self): - """Test __sklearn_is_fitted__ returns True.""" - transformer = BraindecodeDatasetLoader() - is_fitter = transformer.__sklearn_is_fitted__() - assert is_fitter - - def test_assert_raises_value_error(self, data): - """Test that an invalid argument gives a ValueError.""" - X_train, y_train, _, _ = data - transformer = BraindecodeDatasetLoader() - invalid_param_name = "invalid" - with pytest.raises(TypeError): - transformer.fit(X_train, y=y_train, **{invalid_param_name: None}) - - def test_type_create_from_X_y_vs_transfomer(self, data): - """Test the type from create_from_X_y() and the transformer.""" - X_train, y_train, _, _ = data - - dataset = create_from_X_y( - X_train.get_data(), - y=y_train, - window_size_samples=X_train.get_data().shape[2], - window_stride_samples=X_train.get_data().shape[2], - drop_last_window=False, - sfreq=X_train.info["sfreq"], - ) - transformer = BraindecodeDatasetLoader() - dataset_trans = transformer.fit(X=X_train, y=y_train).transform(X_train) - assert isinstance(dataset_trans, BaseConcatDataset) - assert isinstance(type(dataset_trans), type(dataset)) - - def test_wrong_input(self): - """Test that an invalid input raises a ValueError.""" - transformer = BraindecodeDatasetLoader() - with pytest.raises(ValueError): - transformer.fit_transform(np.random.normal(size=(2, 1, 10)), y=np.array([0])) - - def test_transformer_transform_with_custom_y(self, data): - """Test whether the provided y is used during transform.""" - X_train, y_train, _, _ = data - transformer = BraindecodeDatasetLoader() - - # Create test data with different y values - X_test = X_train.copy() - y_test = y_train + 1 - - # Fit the transformer with training data and custom y - transformer.fit(X_train, y_train) - - # Transform the test data with custom y - dataset_test = transformer.transform(X_test, y=y_test) - - # Verify that the transformed dataset contains the test data's x values and the custom y values - assert len(dataset_test) == len(X_test) - assert np.array_equal(dataset_test[0][1], y_test[0]) - assert np.array_equal(dataset_test[1][1], y_test[1]) - - def test_transformer_transform_with_default_y(self, data): - """Test whether self.y is used when y is not provided during - transform.""" - X_train, y_train, _, _ = data - transformer = BraindecodeDatasetLoader() - - # Fit the transformer with training data and default y - transformer.fit(X_train, y_train) - - # Transform the test data without providing y - dataset_test = transformer.transform(X_train) - - # Verify that the transformed dataset contains the training data's x values and the default y values - assert len(dataset_test) == len(X_train) - assert np.array_equal(dataset_test[0][1], y_train[0]) - assert np.array_equal(dataset_test[1][1], y_train[1]) - - -if __name__ == "__main__": - unittest.main() From 07f0aae6863ff6eb6842d3377084536ac251fa8d Mon Sep 17 00:00:00 2001 From: bruAristimunha Date: Mon, 11 Nov 2024 13:01:36 +0100 Subject: [PATCH 11/15] [FIX] removing optional poetry dependancy. --- pyproject.toml | 1 - 1 file changed, 1 deletion(-) diff --git a/pyproject.toml b/pyproject.toml index 61a9b4595..40fd36163 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -42,7 +42,6 @@ codecarbon = { version = "^2.1.4", optional = true } tensorflow = { version = ">=2.16", optional = true } keras = { version = ">=3.2.0", optional = true } scikeras = { version = "^0.13.0", optional = true } -braindecode = {version = "^0.8", optional = true} torch = { version = "^1.13.1", optional = true } libclang = { version = "^15.0", optional = true } docstring_inheritance = { version = "^2.2.0", optional = true} From f76ee735fe32647a33b702d3bcca8a25a5b1c5e7 Mon Sep 17 00:00:00 2001 From: bruAristimunha Date: Mon, 11 Nov 2024 13:02:46 +0100 Subject: [PATCH 12/15] [FIX] removing options about braindecode --- moabb/benchmark.py | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/moabb/benchmark.py b/moabb/benchmark.py index 312223f6f..55880e3f3 100644 --- a/moabb/benchmark.py +++ b/moabb/benchmark.py @@ -56,9 +56,6 @@ def benchmark( # noqa: C901 If particular paradigms are mentioned through select_paradigms, only the pipelines corresponding to those paradigms will be run. If no paradigms are mentioned, all pipelines will be run. - Pipelines stored in a file named braindecode_xxx.py will be recognized as Braindecode architectures - and they will receive epochs as input, instead of numpy array. - To define the include_datasets or exclude_dataset, you could start from the full dataset list, using for example the following code: > # Choose your paradigm @@ -171,13 +168,13 @@ def benchmark( # noqa: C901 ppl_with_epochs, ppl_with_array = {}, {} for pn, pv in prdgms[paradigm].items(): - if "braindecode" in pn or "Keras" in pn: + if "Keras" in pn: ppl_with_epochs[pn] = pv else: ppl_with_array[pn] = pv if len(ppl_with_epochs) > 0: - # Braindecode pipelines require return_epochs=True + # Keras pipelines require return_epochs=True context = eval_type[evaluation]( paradigm=p, datasets=d, From 942c1d697a12f664ba2c36263d574c888d287fa6 Mon Sep 17 00:00:00 2001 From: bruAristimunha Date: Mon, 11 Nov 2024 13:04:18 +0100 Subject: [PATCH 13/15] [FIX] removing options about braindecode --- .../braindecode_EEGInception.py | 59 --------- .../braindecode_EEGNetv4.py | 59 --------- .../braindecode_ShallowFBCSPNet.py | 59 --------- examples/plot_benchmark_braindecode.py | 122 ------------------ pipelines/braindecode_Deep4Net.py | 61 --------- pipelines/braindecode_EEGInception.py | 59 --------- pipelines/braindecode_EEGNetv4.py | 59 --------- pipelines/braindecode_ShallowFBCSPNet.py | 59 --------- 8 files changed, 537 deletions(-) delete mode 100644 examples/pipelines_braindecode/braindecode_EEGInception.py delete mode 100644 examples/pipelines_braindecode/braindecode_EEGNetv4.py delete mode 100644 examples/pipelines_braindecode/braindecode_ShallowFBCSPNet.py delete mode 100644 examples/plot_benchmark_braindecode.py delete mode 100644 pipelines/braindecode_Deep4Net.py delete mode 100644 pipelines/braindecode_EEGInception.py delete mode 100644 pipelines/braindecode_EEGNetv4.py delete mode 100644 pipelines/braindecode_ShallowFBCSPNet.py diff --git a/examples/pipelines_braindecode/braindecode_EEGInception.py b/examples/pipelines_braindecode/braindecode_EEGInception.py deleted file mode 100644 index e871c29a9..000000000 --- a/examples/pipelines_braindecode/braindecode_EEGInception.py +++ /dev/null @@ -1,59 +0,0 @@ -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.features import Resampler_Epoch - - -# 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 - -# Define a Skorch classifier -clf = EEGClassifier( - module=EEGInception, - optimizer=torch.optim.Adam, - optimizer__lr=LEARNING_RATE, - batch_size=BATCH_SIZE, - max_epochs=EPOCH, - train_split=ValidSplit(0.2, random_state=SEED, stratified=True), - 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 - ), - ], - verbose=VERBOSE, # Not printing the results for each epoch -) - -# Create the pipelines -pipes = Pipeline( - [ - ("resample", Resampler_Epoch(128)), - ("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", -} diff --git a/examples/pipelines_braindecode/braindecode_EEGNetv4.py b/examples/pipelines_braindecode/braindecode_EEGNetv4.py deleted file mode 100644 index ddadd6af7..000000000 --- a/examples/pipelines_braindecode/braindecode_EEGNetv4.py +++ /dev/null @@ -1,59 +0,0 @@ -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.features import Resampler_Epoch - - -# 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 - -# Define a Skorch classifier -clf = EEGClassifier( - module=EEGNetv4, - optimizer=torch.optim.Adam, - optimizer__lr=LEARNING_RATE, - batch_size=BATCH_SIZE, - max_epochs=EPOCH, - train_split=ValidSplit(0.2, random_state=SEED, stratified=True), - 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 - ), - ], - verbose=VERBOSE, # Not printing the results for each epoch -) - -# Create the pipelines -pipes = Pipeline( - [ - ("resample", Resampler_Epoch(128)), - ("EEGNetv4", clf), - ] -) - -# this is what will be loaded -PIPELINE = { - "name": "braindecode_EEGNetv4_resample", - "paradigms": ["LeftRightImagery", "MotorImagery"], - "pipeline": pipes, - "citations": "https://doi.org/10.1088/1741-2552/aace8c", -} diff --git a/examples/pipelines_braindecode/braindecode_ShallowFBCSPNet.py b/examples/pipelines_braindecode/braindecode_ShallowFBCSPNet.py deleted file mode 100644 index 20bcc0cf6..000000000 --- a/examples/pipelines_braindecode/braindecode_ShallowFBCSPNet.py +++ /dev/null @@ -1,59 +0,0 @@ -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.features import Resampler_Epoch - - -# 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 = 5 -PATIENCE = 3 - -# Define a Skorch classifier -clf = EEGClassifier( - module=ShallowFBCSPNet, - module__final_conv_length="auto", - optimizer=torch.optim.Adam, - optimizer__lr=LEARNING_RATE, - batch_size=BATCH_SIZE, - max_epochs=EPOCH, - train_split=ValidSplit(0.2, random_state=SEED, stratified=True), - 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 - ), - ], - verbose=VERBOSE, # Not printing the results for each epoch -) - -# Create the pipelines -pipes = Pipeline( - [ - ("resample", Resampler_Epoch(250)), - ("ShallowFBCSPNet", clf), - ] -) - -# this is what will be loaded -PIPELINE = { - "name": "braindecode_ShallowFBCSPNet", - "paradigms": ["LeftRightImagery", "MotorImagery"], - "pipeline": pipes, -} diff --git a/examples/plot_benchmark_braindecode.py b/examples/plot_benchmark_braindecode.py deleted file mode 100644 index 3b69b56b1..000000000 --- a/examples/plot_benchmark_braindecode.py +++ /dev/null @@ -1,122 +0,0 @@ -""" -======================================================================= -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 -# Bruno Aristimunha -# Sylvain Chevallier -# -# 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 BNCI2014_001, BNCI2014_004 -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 ``BNCI2014_001`` and ``BNCI2014_004``. -# -# 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 BNCI2014_001 -dataset = BNCI2014_001() -dataset2 = BNCI2014_004() -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 `_. -# 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. -# `_ -# 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. -# `_ -# IEEE Transactions on Neural Systems and Rehabilitation Engineering diff --git a/pipelines/braindecode_Deep4Net.py b/pipelines/braindecode_Deep4Net.py deleted file mode 100644 index a1a53337c..000000000 --- a/pipelines/braindecode_Deep4Net.py +++ /dev/null @@ -1,61 +0,0 @@ -import torch -from braindecode import EEGClassifier -from braindecode.models import Deep4Net -from sklearn.pipeline import Pipeline -from skorch.callbacks import EarlyStopping, EpochScoring -from skorch.dataset import ValidSplit - -from moabb.pipelines.features import Resampler_Epoch - - -# 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 = 1000 -PATIENCE = 300 - - -# Define a Skorch classifier -clf = EEGClassifier( - module=Deep4Net, - module__final_conv_length="auto", - optimizer=torch.optim.Adam, - optimizer__lr=LEARNING_RATE, - batch_size=BATCH_SIZE, - max_epochs=EPOCH, - train_split=ValidSplit(0.2, random_state=SEED, stratified=True), - 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 - ), - ], - verbose=VERBOSE, # Not printing the results for each epoch -) - -# Create the pipelines -pipes = Pipeline( - [ - ("resample", Resampler_Epoch(250)), - ("ShallowFBCSPNet", clf), - ] -) - -# this is what will be loaded -PIPELINE = { - "name": "braindecode_Deep4Net", - "paradigms": ["LeftRightImagery", "MotorImagery"], - "pipeline": pipes, - "citations": "https://doi.org/10.1002/hbm.23730", -} diff --git a/pipelines/braindecode_EEGInception.py b/pipelines/braindecode_EEGInception.py deleted file mode 100644 index aa18a49fc..000000000 --- a/pipelines/braindecode_EEGInception.py +++ /dev/null @@ -1,59 +0,0 @@ -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.features import Resampler_Epoch - - -# 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 = 1000 -PATIENCE = 300 - -# Define a Skorch classifier -clf = EEGClassifier( - module=EEGInception, - optimizer=torch.optim.Adam, - optimizer__lr=LEARNING_RATE, - batch_size=BATCH_SIZE, - max_epochs=EPOCH, - train_split=ValidSplit(0.2, random_state=SEED, stratified=True), - 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 - ), - ], - verbose=VERBOSE, # Not printing the results for each epoch -) - -# Create the pipelines -pipes = Pipeline( - [ - ("resample", Resampler_Epoch(128)), - ("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", -} diff --git a/pipelines/braindecode_EEGNetv4.py b/pipelines/braindecode_EEGNetv4.py deleted file mode 100644 index 5ad2fd106..000000000 --- a/pipelines/braindecode_EEGNetv4.py +++ /dev/null @@ -1,59 +0,0 @@ -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.features import Resampler_Epoch - - -# 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 = 1000 -PATIENCE = 300 - -# Define a Skorch classifier -clf = EEGClassifier( - module=EEGNetv4, - optimizer=torch.optim.Adam, - optimizer__lr=LEARNING_RATE, - batch_size=BATCH_SIZE, - max_epochs=EPOCH, - train_split=ValidSplit(0.2, random_state=SEED, stratified=True), - 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 - ), - ], - verbose=VERBOSE, # Not printing the results for each epoch -) - -# Create the pipelines -pipes = Pipeline( - [ - ("resample", Resampler_Epoch(128)), - ("EEGNetv4", clf), - ] -) - -# this is what will be loaded -PIPELINE = { - "name": "braindecode_EEGNetv4_resample", - "paradigms": ["LeftRightImagery", "MotorImagery"], - "pipeline": pipes, - "citations": "https://doi.org/10.1088/1741-2552/aace8c", -} diff --git a/pipelines/braindecode_ShallowFBCSPNet.py b/pipelines/braindecode_ShallowFBCSPNet.py deleted file mode 100644 index 10909b32e..000000000 --- a/pipelines/braindecode_ShallowFBCSPNet.py +++ /dev/null @@ -1,59 +0,0 @@ -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.features import Resampler_Epoch - - -# 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 = 1000 -PATIENCE = 300 - -# Define a Skorch classifier -clf = EEGClassifier( - module=ShallowFBCSPNet, - module__final_conv_length="auto", - optimizer=torch.optim.Adam, - optimizer__lr=LEARNING_RATE, - batch_size=BATCH_SIZE, - max_epochs=EPOCH, - train_split=ValidSplit(0.2, random_state=SEED, stratified=True), - 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 - ), - ], - verbose=VERBOSE, # Not printing the results for each epoch -) - -# Create the pipelines -pipes = Pipeline( - [ - ("resample", Resampler_Epoch(250)), - ("ShallowFBCSPNet", clf), - ] -) - -# this is what will be loaded -PIPELINE = { - "name": "braindecode_ShallowFBCSPNet", - "paradigms": ["LeftRightImagery", "MotorImagery"], - "pipeline": pipes, -} From 9ce2756ee0c96397e54c2a5c3fdfe37e52c56173 Mon Sep 17 00:00:00 2001 From: bruAristimunha Date: Mon, 11 Nov 2024 13:05:52 +0100 Subject: [PATCH 14/15] [FIX] removing braindecode --- examples/load_model.py | 52 ++---------------------------------------- 1 file changed, 2 insertions(+), 50 deletions(-) diff --git a/examples/load_model.py b/examples/load_model.py index 2593fd0ee..941f8c398 100644 --- a/examples/load_model.py +++ b/examples/load_model.py @@ -1,6 +1,6 @@ """ ============================================== -Load Model (Scikit, Pytorch, Keras) with MOABB +Load Model (Scikit, Keras) with MOABB ============================================== This example shows how to use load the pretrained pipeline in MOABB. @@ -13,13 +13,8 @@ from pickle import load import keras -import torch -from braindecode import EEGClassifier -from braindecode.models import EEGInception from scikeras.wrappers import KerasClassifier -from sklearn.pipeline import Pipeline, make_pipeline -from skorch.callbacks import EarlyStopping, EpochScoring -from skorch.dataset import ValidSplit +from sklearn.pipeline import Pipeline from moabb import set_log_level from moabb.pipelines.features import StandardScaler_Epoch @@ -66,46 +61,3 @@ ("Keras_DeepConvNet_Trained", Keras_DeepConvNet_Trained), ] ) - -############################################################################### -# Loading the PyTorch model - -# Hyperparameter -LEARNING_RATE = 0.0001 -WEIGHT_DECAY = 0 -BATCH_SIZE = 64 -SEED = 42 -VERBOSE = 1 -EPOCH = 2 -PATIENCE = 3 - -# Define a Skorch classifier -clf = EEGClassifier( - module=EEGInception, - optimizer=torch.optim.Adam, - optimizer__lr=LEARNING_RATE, - batch_size=BATCH_SIZE, - max_epochs=EPOCH, - train_split=ValidSplit(0.2, random_state=SEED), - 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 - ), - ], - verbose=VERBOSE, # Not printing the results for each epoch -) - -clf.initialize() - -f_params = "./results/Models_CrossSession/BNCI2014-001/1/braindecode_EEGInception/EEGInception_fitted_best_model.pkl" -f_optimizer = "./results/Models_CrossSession/BNCI2014-001/1/braindecode_EEGInception/EEGInception_fitted_best_optim.pkl" -f_history = "./results/Models_CrossSession/BNCI2014-001/1/braindecode_EEGInception/EEGInception_fitted_best_history.json" - -clf.load_params(f_params=f_params, f_optimizer=f_optimizer, f_history=f_history) - -# Create the pipelines -pipes_pytorch = make_pipeline(clf) From 40952122ff8c7a5044410157a438d4b1b7b2a74e Mon Sep 17 00:00:00 2001 From: bruAristimunha Date: Mon, 11 Nov 2024 13:06:20 +0100 Subject: [PATCH 15/15] [FIX] removing braindecode --- examples/plot_braindecode.py | 152 ----------------------------------- 1 file changed, 152 deletions(-) delete mode 100644 examples/plot_braindecode.py diff --git a/examples/plot_braindecode.py b/examples/plot_braindecode.py deleted file mode 100644 index 2bea99d11..000000000 --- a/examples/plot_braindecode.py +++ /dev/null @@ -1,152 +0,0 @@ -""" -=============================================================== -Cross-session motor imagery with deep learning EEGNet v4 model -=============================================================== -This example shows how to use BrainDecode in combination with MOABB evaluation. -In this example, we use the architecture EEGNetv4. -""" - -# Authors: Igor Carrara -# Bruno Aristimunha -# -# License: BSD (3-clause) - -import matplotlib.pyplot as plt -import mne -import seaborn as sns -import torch -from braindecode import EEGClassifier -from braindecode.models import EEGNetv4 -from sklearn.pipeline import make_pipeline -from skorch.callbacks import EarlyStopping, EpochScoring -from skorch.dataset import ValidSplit - -from moabb.datasets import BNCI2014_001 -from moabb.evaluations import CrossSessionEvaluation -from moabb.paradigms import MotorImagery -from moabb.utils import setup_seed - - -mne.set_log_level(False) - -# 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 the dataset ``BNCI2014_001``. -# -# Running the benchmark -# --------------------- -# -# This example uses the CrossSession evaluation procedure. We focus on the dataset BNCI2014_001 and only on 1 subject -# to reduce computational time. -# -# To keep the computational time low, the epoch is reduced. In a real situation, we suggest using the following: -# EPOCH = 1000 -# PATIENCE = 300 -# -# This code is implemented to run on the CPU. If you're using a GPU, do not use multithreading -# (i.e. set n_jobs=1) - - -# Set random seed to be able to reproduce results -seed = 42 -setup_seed(seed) - -# Ensure that all operations are deterministic on GPU (if used) for reproducibility -torch.backends.cudnn.deterministic = True -torch.backends.cudnn.benchmark = False - -# Hyperparameter -LEARNING_RATE = 0.0625 * 0.01 # parameter taken from Braindecode -WEIGHT_DECAY = 0 # parameter taken from Braindecode -BATCH_SIZE = 64 # parameter taken from BrainDecode -EPOCH = 10 -PATIENCE = 3 -fmin = 4 -fmax = 100 -tmin = 0 -tmax = None - -# Load the dataset -dataset = BNCI2014_001() -events = ["right_hand", "left_hand"] -paradigm = MotorImagery( - events=events, n_classes=len(events), fmin=fmin, fmax=fmax, tmin=tmin, tmax=tmax -) -subjects = [1] -X, _, _ = paradigm.get_data(dataset=dataset, subjects=subjects) - -############################################################################## -# Create Pipelines -# ---------------- -# In order to create a pipeline, we need to load a model from braindecode. -# the second step is to define a skorch model using EEGClassifier from braindecode -# that allows converting the PyTorch model in a scikit-learn classifier. -# Here, we will use the EEGNet v4 model [1]_ . -# This model has mandatory hyperparameters (the number of channels, the number of classes, -# and the temporal length of the input) but we do not need to specify them because they will -# be set dynamically by EEGClassifier using the input data during the call to the ``.fit()`` method. - -# Define a Skorch classifier -clf = EEGClassifier( - module=EEGNetv4, - 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 - ), - ], - verbose=1, # Not printing the results for each epoch -) - -# Create the pipelines -pipes = {} -pipes["EEGNetV4"] = make_pipeline(clf) - -############################################################################## -# Evaluation -# ---------- -dataset.subject_list = dataset.subject_list[:2] - -evaluation = CrossSessionEvaluation( - paradigm=paradigm, - datasets=dataset, - suffix="braindecode_example", - overwrite=True, - return_epochs=True, - n_jobs=1, -) - -results = evaluation.process(pipes) - -print(results.head()) - -############################################################################## -# Plot Results -# ---------------- -plt.figure() -sns.barplot(data=results, y="score", x="subject", palette="viridis") -plt.show() -############################################################################## -# References -# ---------- -# .. [1] 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. -# `_ -# Journal of neural engineering, 15(5), 056013.