Giter VIP home page Giter VIP logo

braindecode's Introduction

Join the chat at https://gitter.im/braindecodechat/community

image

Doc build on CircleCI

Code Coverage

Braindecode

Braindecode is an open-source Python toolbox for decoding raw electrophysiological brain data with deep learning models. It includes dataset fetchers, data preprocessing and visualization tools, as well as implementations of several deep learning architectures and data augmentations for analysis of EEG, ECoG and MEG.

For neuroscientists who want to work with deep learning and deep learning researchers who want to work with neurophysiological data.

Installation Braindecode

  1. Install pytorch from http://pytorch.org/ (you don't need to install torchvision).
  2. If you want to download EEG datasets from MOABB, install it:
pip install moabb
  1. Install latest release of braindecode via pip:
pip install braindecode

If you want to install the latest development version of braindecode, please refer to contributing page

Documentation

Documentation is online under https://braindecode.org, both in the stable and dev versions.

Contributing to Braindecode

Guidelines for contributing to the library can be found on the braindecode github:

https://github.com/braindecode/braindecode/blob/master/CONTRIBUTING.md

Braindecode chat

https://gitter.im/braindecodechat/community

Citing

If you use this code in a scientific publication, please cite us as:

@article {HBM:HBM23730,
author = {Schirrmeister, Robin Tibor and Springenberg, Jost Tobias and Fiederer,
  Lukas Dominique Josef and Glasstetter, Martin and Eggensperger, Katharina and Tangermann, Michael and
  Hutter, Frank and Burgard, Wolfram and Ball, Tonio},
title = {Deep learning with convolutional neural networks for EEG decoding and visualization},
journal = {Human Brain Mapping},
issn = {1097-0193},
url = {http://dx.doi.org/10.1002/hbm.23730},
doi = {10.1002/hbm.23730},
month = {aug},
year = {2017},
keywords = {electroencephalography, EEG analysis, machine learning, end-to-end learning, brain–machine interface,
  brain–computer interface, model interpretability, brain mapping},
}

as well as the MNE-Python software that is used by braindecode:

@article{10.3389/fnins.2013.00267,
author={Gramfort, Alexandre and Luessi, Martin and Larson, Eric and Engemann, Denis and Strohmeier, Daniel and Brodbeck, Christian and Goj, Roman and Jas, Mainak and Brooks, Teon and Parkkonen, Lauri and Hämäläinen, Matti},
title={{MEG and EEG data analysis with MNE-Python}},
journal={Frontiers in Neuroscience},
volume={7},
pages={267},
year={2013},
url={https://www.frontiersin.org/article/10.3389/fnins.2013.00267},
doi={10.3389/fnins.2013.00267},
issn={1662-453X},
}

Licensing

Braindecode is BSD-licenced (BSD-3-Clause):

This software is OSI Certified Open Source Software. OSI Certified is a certification mark of the Open Source Initiative.

Copyright (c) 2011-2022, authors of Braindecode. All rights reserved.

Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:

  • Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
  • Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
  • Neither the names of braindecode authors nor the names of any contributors may be used to endorse or promote products derived from this software without specific prior written permission.

This software is provided by the copyright holders and contributors "as is" and any express or implied warranties, including, but not limited to, the implied warranties of merchantability and fitness for a particular purpose are disclaimed. In no event shall the copyright owner or contributors be liable for any direct, indirect, incidental, special, exemplary, or consequential damages (including, but not limited to, procurement of substitute goods or services; loss of use, data, or profits; or business interruption) however caused and on any theory of liability, whether in contract, strict liability, or tort (including negligence or otherwise) arising in any way out of the use of this software, even if advised of the possibility of such damage.

braindecode's People

Contributors

agramfort avatar bruaristimunha avatar brunaafl avatar cedricrommel avatar dcwil avatar div12345 avatar erikbjare avatar gemeinl avatar ghblg avatar gifale95 avatar gitter-badger avatar hubertjb avatar jpaillard avatar kahartma avatar martinwimpff avatar matthieutrs avatar mohammadjavadd avatar overlordgolddragon avatar pierregtch avatar remidbs avatar robintibor avatar sara04 avatar sbbrandt avatar sliwy avatar sylvchev avatar tgnassou avatar tgy avatar tommoral avatar vytjan avatar zambonimarco99 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

braindecode's Issues

**Existing Metrics Check**

Easy to understand interface

  • for existing metrics, check necessary inputs and outputs to define common interface

Preprocessing / scaling of targets

Some applications might benefit of preprocessing / scaling of targets, e.g. age regression. How could we include this in braindecode? Do we introduce another function next to transform_concat_ds to apply transforms to targets or would you argue for a combination of both?

Improving the transforms

The most recent implementation of transforms asks for an OrderedDict of callables or mne.Raw/Epochs methods that are called successively on the internal Raw/Epochs objects in a ConcatDataset (https://github.com/braindecode/braindecode/blob/master/braindecode/datautil/transforms.py#L18). I wanted to discuss possible improvements to this design:

  1. The current design requires the callables or methods to act in-place, i.e., they must directly modify the Raw/Epochs object. However, apart from .resample and .filter, most mne methods do not seem to act in-place. As for callables, they can be made to modify the objects in-place, but this would mean all the transforms would have to be mne object-aware. I don't have a specific solution in mind, but maybe we could discuss this here.
  2. There is currently no way to apply a transform on-the-fly, i.e., every time a window is about to be returned. This is central to preprocessing steps in a lazy loading scenario however. The design we had started to implement during the sprint used Transform objects that were saved in the dataset object, and called inside __getitem__. This is how torch-vision does it for instance.

What are your thoughts @gemeinl @sbbrandt ?

CircleCI should not redownload data all the time

For unclear reasons, CircleCI sometimes downloads the physionet data multiple times (https://circleci.com/gh/braindecode/braindecode/153 2 times, https://circleci.com/gh/braindecode/braindecode/108 3 times).

And it puts them in exactly the same locations, e.g.:

First download returns (among other names):
'/home/circleci/mne_data/MNE-eegbci-data/physiobank/database/eegmmidb/S001/S001R04.edf'
Second download returns (among other names):
'/home/circleci/mne_data/MNE-eegbci-data/physiobank/database/eegmmidb/S001/S001R04.edf'

Other times it seems to have it cached/not download it, https://circleci.com/gh/braindecode/braindecode/147

I don't understand the behavior and how to make it work properly. @agramfort

**Checkpointing Save Load**

Run Large Experiments, save resources

  • Note down which parts have to be saved
  • Check for any local functions etc.

Analysing the performance of different methods to get windows

I've started looking at the performance of various ways of getting windows:
1- MNE: epochs.get_data(ind)[0] with lazy loading (preload=False)
2- MNE: epochs.get_data(ind)[0] with eager loading (preload=True)
3- MNE: direct access to the internal numpy array with epochs._data[index] (requires eager loading)
4- HDF5: using h5py (lazy loading)

The script that I used to run the comparison is here:
https://github.com/hubertjb/braindecode/blob/profiling-mne-epochs/test/others/profiling_mne_epochs.py
Also, I ran the comparison on a single CPU using:
>>> taskset -c 0 python profiling_mne_epochs.py

Here's the resulting figure, where the x-axis is the number of time samples in the continuous recording:
timing_results

For the moment, it looks like:
1- ._data[index] is unsurprisingly the fastest, however it requires to load the entire data into memory.
2- hdf5 is very close, with around 0.5 ms per loop, which is great knowing it's able to only load one window at a time.
3- get_data(index) is much slower, but this is expected as we know it creates a new mne.Epochs object every time it's called. Also, the gap between preload=True and preload=False is about 1.5 ms, which might be OK. The main issue though seems to be the linear increase of execution time as the continuous data gets bigger and bigger.

Next steps

Considering the benefits of using MNE for handling the EEG data inside the Dataset classes, I think it would be important to dive deeper into the inner workings of get_data() to see whether simple changes could make this more efficient. I can do some actual profiling on that. What do you think @agramfort @robintibor @gemeinl ?

Note: I haven't included the extraction of labels in this test.

"Trialwise Decoding" notebook does not give "stable" results

(I'm new to machine-learning, so forgive me if this bug-report is misguided.)

I downloaded the "plot_bcic_iv_2a_moabb_trial.ipynb" example from here.

I noticed this code:

seed = 20200220  # random seed to make results reproducible
# Set random seed to be able to reproduce results
set_random_seeds(seed=seed, cuda=cuda)

Shouldn't this code make it so that every time I run the notebook, the results are the same in the learning-progress logging, and in the displayed plot?

However, it gives different results each time it runs, despite no code modifications: Screen Capture

Questions:

  1. Is it supposed to get different results each time?
  2. If it is supposed to, is there any way I can modify the code to instead give "stable" results?

Rethink where to put nn inits

Right now, one only used by EEGNet is in nn_init.py another one is inside eegresnet... should both be in nn_init? Or both be in models and private?

How to calculate input-feature unit-output maps?

Hi! First of all, thank you for your interesting work and for publishing and documenting everything here! :-)

For my master's thesis, I'm trying to classify the attentive state of patients with disorders of consciousness. The major challenge is that there is no ground truth available for these patients. To tackle this, I have two approaches. First, I'm using a Keras implementation of your deep network in combination with learning mechanisms that are robust to label noise. After training, gaining insight into what the network learned is the second aspect I'd like to investigate. So the input-feature unit-output correlation maps seem to be a promising method. I followed your tutorial on Amplitude Perturbation Visualization, which worked using the learned model's prediction function.
But regarding the input-feature unit-output correlation maps (without the perturbation), I don't know how I can calculate them. I read through the classes in the visualization package, but I'm not sure where to start. My goal would be an evaluation similar to figures 6/7 in your paper.

Can you point me in the right direction?

Kind regards, Constantin

Remove mne_ext

  • mne_apply and common_average_reference_cnt should be removed and replaced with mne functions through the transforms API (https://github.com/braindecode/braindecode/blob/master/braindecode/datautil/transforms.py#L18)
  • concatenate_raws_with_events could potentially be replaced by mne.concatenate_raws. However, this modifies the first raw in-place which is probably not intended. Furthermore, there might be a bug, where events of raws are not properly combined. To be tested. If there actually is a bug, report to mne.

Deprecate old braindecode

Put only link to new braindecode in readme, move old readme, remove parts about pip install. make sure github pages as well as github readme is updated.

moving to the annotations object

As mentioned in the last PR, we thought about moving to the annotations objects to get the events.
So far, the events are read from the stimulus channel for the BCIC IV 2a dataset. Other datasets from MOABB might not have a stimulus channel, but come with an annotation object right away.

I have implemented a method to set the annotations object for the MOABB datasets, but Lukas and I came up with a few questions.

The event description in an annotations object is the description string, e.g. 'left_feet', instead of the integer values. For the event windower, we would need to call events_from_annotations(raw) to get the indices of the events. Here, a new mapping is needed/generated as the events now become integers again. The default option here would result in events starting from 1 on. For classification we would need events from 0 on. Anyway it would be handy to have the resulting mapping saved in the dataset.

The main questions here are:

  • would we define a custom default mapping to have events started from 0 on in the windower or move that part to the training step?
  • should we have an events_desc attribute containing the mapping for the dataset?
  • also I thought about discarding the stimulus channel when setting the annotations, as it is not needed anymore afterwards.

Beside that, the onset of the annotations would start at the actual experiment onset, e.g. shifted by 2s for bcic, and the duration is contained as well. These information can be accessed via MOABB.

What do you think @hubertjb @gemeinl

Different results using skorch and my training function

I was trying to translate my codes to use braindecode. Previously I had a function train that took pytorch neural net and trained model. Now I wanted to replace this function with skorch classifier. I created an example that should use the same network, the same parameters and the same dataset and it gives different results (with my train function it gives 1.0 train accuracy after around 10-15 epoch instead of not even similar results after 50 epochs). On my dataset it does not work at all, so that is why I got interested in the skorch performance.
I'm stuck and I don't have any idea what causes this behavior. If anyone has some time and would like to help me here is a link to the python file with the example, maybe fresh look can help https://github.com/sliwy/braindecode/blob/strange_example/examples/skorch_slow_learning.py

image
image

Tests refactor/cleanup

test_cropped_decoding.py, test_trialwise_decoding.py refactor to use new dataset classes

Naming of models

Rename Deep4Net -> Deep4Model, ShallowFBCSPNet -> ShallowFBCSPModel

And/But: EEGNet ->EEGNetModel

Code Style and Naming

When we have the first integrated version skorch-api+dataset, we can make a pass over the code to enforce some more consistency and see what style we prefer (beyond just pep8).

Let's collect open questions for now:

  • to indicate a variable that specifies an index/counter, e.g., the index of a trial, should we prefix with i(=i_trial) or with idx=idx_trial

Move to new Skorch-based API, remove old Experiment/Model API

Create new package(or not, see below) with name such as engine, trainer(s) or training for skorchbased training/experiment loop api, check bcic_iv_2a_cropped.py (bcic_iv_2a.py already checked) and replace then in other examples as well (also reply amir email)

  • experiments/experiment.py -> remove
  • experiments/loggers.py -> remove
  • experiments/monitors.py -> move code needed for cropped decoding computations out (temporarily to scoring? or other place? maybe cropped.py in new engine/trainer module?), then remove
  • experiments/stopcriteria.py -> remove
  • models/base.py -> remove, rewrite existing models to not inherit from it anymore, adapt examples (also grep for create_network in all of braindecode and remove)
  • torch_ext/losses.py -> remove
  • torch_ext/schedulers.py -> remove
    *datautil/splitters.py -> remove

For name for new package, some ways of others:

Improve Dataset classes and Windower interaction

1 Re-fine definition of a BaseDataset:

  • does it inherit from pytorch Dataset?
  • if it is a pytorch Dataset, length should be n_times
  • is there a use case for calling getitem?

2 Have a BaseConcatDataset

  • should implement a 'split' method

3 Datasets should not know the windower

  • move EventWindower / FixedLengthWindower out of MOABBDataset/TUHAbnormal

4 Windowers should be applied to datasets

  • Windowers could be functions instead of classes
  • windowers should accept a ConcatDataset on call and return a ConcatDataset

5 Avoid variable name ambiguities

  • for example with mne.Raw.info

CircleCI redownloads

Is there a reason for the force_update=True introduced in 01aa0ce ?

These lines

if [[ $(cat $FNAME | grep -x ".*datasets.*eegbci.*" | wc -l) -gt 0 ]]; then
python -c "import mne; print([mne.datasets.eegbci.load_data(s, [4, 5, 6, 8, 9, 10, 12, 13, 14], update_path=True, force_update=True) for s in range(1, 51)])";
fi;
if [[ $(cat $FNAME | grep -x ".*datasets.*sleep_physionet.*" | wc -l) -gt 0 ]]; then
python -c "import mne; print(mne.datasets.sleep_physionet.age.fetch_data([0, 1], recording=[1], update_path=True, force_update=True))";

seem to lead to quite long downloads in case there is a example different from master branch as far as I understand.

See e.g. https://app.circleci.com/pipelines/github/braindecode/braindecode/340/workflows/75971e52-7fec-47ea-a4b9-ffdc114e2410/jobs/398/steps

Wouldn't update_path=False, force_update=False work? This is what we do inside code usually (force_update=False per default from mne), e.g.

# and then return the paths to the files.
physionet_paths = mne.datasets.eegbci.load_data(
subject_id, event_codes, update_path=False

Or will this break CircleCI completely again? Annoying to wait for long times in new pull requests always redownloading same stuff, even multiple times :/ @agramfort

**Dataloader Use Cases**

Allow many people to use it

  • write down all different use cases (classification(single label/multi label)/regression/continuous labels etc.)
  • describe how implementation could work in pytorch dataloader logic

**Remove assumption on 3d/4d from code**

Easier to understand interface, less code

  • if model assumes 4d input, put into model ensure_4d or something like that
  • remove code everywhere posible that adds empty dimensions etc.

Transforms->Preprocessors?

While rewriting and refactoring for new tutorials, I thought about one possible renaming: Transforms->Preprocessors.
The reason is that our current transforms are applied directy to the data, not on-the-fly as torchvision transforms. This renaming would also allow to distinguish to-be-added transforms that are applied on-the-fly like in torchvision. However, don't feel 100% sure about it. What do you think @agramfort @sliwy @gemeinl

Overview dataset / tutorial

Description:

  • what is windower wrapping?
  • what is the purpose of this class? what does it produce?
  • what is the input to windower class, moabb dataset or anything?

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.