|
4 | 4 | "cell_type": "markdown",
|
5 | 5 | "metadata": {},
|
6 | 6 | "source": [
|
7 |
| - "\n\n# Sleep staging on the Sleep Physionet dataset using Chambon2018 network\n\nThis tutorial shows how to train and test a sleep staging neural network with\nBraindecode. We adapt the time distributed approach of [1]_ to learn on\nsequences of EEG windows using the openly accessible Sleep Physionet dataset\n[2]_ [3]_.\n" |
| 7 | + "\n# Sleep staging on the Sleep Physionet dataset using Chambon2018 network\n\nThis tutorial shows how to train and test a sleep staging neural network with\nBraindecode. We adapt the time distributed approach of [1]_ to learn on\nsequences of EEG windows using the openly accessible Sleep Physionet dataset\n[2]_ [3]_.\n" |
8 | 8 | ]
|
9 | 9 | },
|
10 | 10 | {
|
|
51 | 51 | },
|
52 | 52 | "outputs": [],
|
53 | 53 | "source": [
|
54 |
| - "from braindecode.preprocessing import preprocess, Preprocessor\nfrom numpy import multiply\n\nhigh_cut_hz = 30\nfactor = 1e6\n\npreprocessors = [\n Preprocessor(\n lambda data: multiply(data, factor), apply_on_array=True\n ), # Convert from V to uV\n Preprocessor(\"filter\", l_freq=None, h_freq=high_cut_hz),\n]\n\n# Transform the data\npreprocess(dataset, preprocessors)" |
| 54 | + "from numpy import multiply\n\nfrom braindecode.preprocessing import Preprocessor, preprocess\n\nhigh_cut_hz = 30\nfactor = 1e6\n\npreprocessors = [\n Preprocessor(\n lambda data: multiply(data, factor), apply_on_array=True\n ), # Convert from V to uV\n Preprocessor(\"filter\", l_freq=None, h_freq=high_cut_hz),\n]\n\n# Transform the data\npreprocess(dataset, preprocessors)" |
55 | 55 | ]
|
56 | 56 | },
|
57 | 57 | {
|
|
123 | 123 | },
|
124 | 124 | "outputs": [],
|
125 | 125 | "source": [
|
126 |
| - "import numpy as np\nfrom braindecode.samplers import SequenceSampler\n\nn_windows = 3 # Sequences of 3 consecutive windows\nn_windows_stride = 3 # Maximally overlapping sequences\n\ntrain_sampler = SequenceSampler(\n train_set.get_metadata(), n_windows, n_windows_stride, randomize=True\n)\nvalid_sampler = SequenceSampler(valid_set.get_metadata(), n_windows, n_windows_stride)\n\n# Print number of examples per class\nprint(\"Training examples: \", len(train_sampler))\nprint(\"Validation examples: \", len(valid_sampler))" |
| 126 | + "import numpy as np\n\nfrom braindecode.samplers import SequenceSampler\n\nn_windows = 3 # Sequences of 3 consecutive windows\nn_windows_stride = 3 # Maximally overlapping sequences\n\ntrain_sampler = SequenceSampler(\n train_set.get_metadata(), n_windows, n_windows_stride, randomize=True\n)\nvalid_sampler = SequenceSampler(valid_set.get_metadata(), n_windows, n_windows_stride)\n\n# Print number of examples per class\nprint(\"Training examples: \", len(train_sampler))\nprint(\"Validation examples: \", len(valid_sampler))" |
127 | 127 | ]
|
128 | 128 | },
|
129 | 129 | {
|
|
177 | 177 | },
|
178 | 178 | "outputs": [],
|
179 | 179 | "source": [
|
180 |
| - "import torch\nfrom torch import nn\nfrom braindecode.util import set_random_seeds\nfrom braindecode.models import SleepStagerChambon2018, TimeDistributed\n\ncuda = torch.cuda.is_available() # check if GPU is available\ndevice = \"cuda\" if torch.cuda.is_available() else \"cpu\"\nif cuda:\n torch.backends.cudnn.benchmark = True\n# Set random seed to be able to roughly reproduce results\n# Note that with cudnn benchmark set to True, GPU indeterminism\n# may still make results substantially different between runs.\n# To obtain more consistent results at the cost of increased computation time,\n# you can set `cudnn_benchmark=False` in `set_random_seeds`\n# or remove `torch.backends.cudnn.benchmark = True`\nset_random_seeds(seed=31, cuda=cuda)\n\nn_classes = 5\n# Extract number of channels and time steps from dataset\nn_channels, input_size_samples = train_set[0][0].shape\n\nfeat_extractor = SleepStagerChambon2018(\n n_channels,\n sfreq,\n n_outputs=n_classes,\n n_times=input_size_samples,\n return_feats=True,\n)\n\nmodel = nn.Sequential(\n TimeDistributed(feat_extractor), # apply model on each 30-s window\n nn.Sequential( # apply linear layer on concatenated feature vectors\n nn.Flatten(start_dim=1),\n nn.Dropout(0.5),\n nn.Linear(feat_extractor.len_last_layer * n_windows, n_classes),\n ),\n)\n\n# Send model to GPU\nif cuda:\n model.cuda()" |
| 180 | + "import torch\nfrom torch import nn\n\nfrom braindecode.models import SleepStagerChambon2018\nfrom braindecode.modules import TimeDistributed\nfrom braindecode.util import set_random_seeds\n\ncuda = torch.cuda.is_available() # check if GPU is available\ndevice = \"cuda\" if torch.cuda.is_available() else \"cpu\"\nif cuda:\n torch.backends.cudnn.benchmark = True\n# Set random seed to be able to roughly reproduce results\n# Note that with cudnn benchmark set to True, GPU indeterminism\n# may still make results substantially different between runs.\n# To obtain more consistent results at the cost of increased computation time,\n# you can set `cudnn_benchmark=False` in `set_random_seeds`\n# or remove `torch.backends.cudnn.benchmark = True`\nset_random_seeds(seed=31, cuda=cuda)\n\nn_classes = 5\n# Extract number of channels and time steps from dataset\nn_channels, input_size_samples = train_set[0][0].shape\n\nfeat_extractor = SleepStagerChambon2018(\n n_channels,\n sfreq,\n n_outputs=n_classes,\n n_times=input_size_samples,\n return_feats=True,\n)\n\nmodel = nn.Sequential(\n TimeDistributed(feat_extractor), # apply model on each 30-s window\n nn.Sequential( # apply linear layer on concatenated feature vectors\n nn.Flatten(start_dim=1),\n nn.Dropout(0.5),\n nn.Linear(feat_extractor.len_last_layer * n_windows, n_classes),\n ),\n)\n\n# Send model to GPU\nif cuda:\n model.cuda()" |
181 | 181 | ]
|
182 | 182 | },
|
183 | 183 | {
|
|
195 | 195 | },
|
196 | 196 | "outputs": [],
|
197 | 197 | "source": [
|
198 |
| - "from skorch.helper import predefined_split\nfrom skorch.callbacks import EpochScoring\nfrom braindecode import EEGClassifier\n\nlr = 1e-3\nbatch_size = 32\nn_epochs = 10\n\ntrain_bal_acc = EpochScoring(\n scoring=\"balanced_accuracy\",\n on_train=True,\n name=\"train_bal_acc\",\n lower_is_better=False,\n)\nvalid_bal_acc = EpochScoring(\n scoring=\"balanced_accuracy\",\n on_train=False,\n name=\"valid_bal_acc\",\n lower_is_better=False,\n)\ncallbacks = [(\"train_bal_acc\", train_bal_acc), (\"valid_bal_acc\", valid_bal_acc)]\n\nclf = EEGClassifier(\n model,\n criterion=torch.nn.CrossEntropyLoss,\n criterion__weight=torch.Tensor(class_weights).to(device),\n optimizer=torch.optim.Adam,\n iterator_train__shuffle=False,\n iterator_train__sampler=train_sampler,\n iterator_valid__sampler=valid_sampler,\n train_split=predefined_split(valid_set), # using valid_set for validation\n optimizer__lr=lr,\n batch_size=batch_size,\n callbacks=callbacks,\n device=device,\n classes=np.unique(y_train),\n)\n# Model training for a specified number of epochs. `y` is None as it is already\n# supplied in the dataset.\nclf.fit(train_set, y=None, epochs=n_epochs)" |
| 198 | + "from skorch.callbacks import EpochScoring\nfrom skorch.helper import predefined_split\n\nfrom braindecode import EEGClassifier\n\nlr = 1e-3\nbatch_size = 32\nn_epochs = 10\n\ntrain_bal_acc = EpochScoring(\n scoring=\"balanced_accuracy\",\n on_train=True,\n name=\"train_bal_acc\",\n lower_is_better=False,\n)\nvalid_bal_acc = EpochScoring(\n scoring=\"balanced_accuracy\",\n on_train=False,\n name=\"valid_bal_acc\",\n lower_is_better=False,\n)\ncallbacks = [(\"train_bal_acc\", train_bal_acc), (\"valid_bal_acc\", valid_bal_acc)]\n\nclf = EEGClassifier(\n model,\n criterion=torch.nn.CrossEntropyLoss,\n criterion__weight=torch.Tensor(class_weights).to(device),\n optimizer=torch.optim.Adam,\n iterator_train__shuffle=False,\n iterator_train__sampler=train_sampler,\n iterator_valid__sampler=valid_sampler,\n train_split=predefined_split(valid_set), # using valid_set for validation\n optimizer__lr=lr,\n batch_size=batch_size,\n callbacks=callbacks,\n device=device,\n classes=np.unique(y_train),\n)\n# Model training for a specified number of epochs. `y` is None as it is already\n# supplied in the dataset.\nclf.fit(train_set, y=None, epochs=n_epochs)" |
199 | 199 | ]
|
200 | 200 | },
|
201 | 201 | {
|
|
231 | 231 | },
|
232 | 232 | "outputs": [],
|
233 | 233 | "source": [
|
234 |
| - "from sklearn.metrics import confusion_matrix, classification_report\nfrom braindecode.visualization import plot_confusion_matrix\n\ny_true = [valid_set[[i]][1][0] for i in range(len(valid_sampler))]\ny_pred = clf.predict(valid_set)\n\nconfusion_mat = confusion_matrix(y_true, y_pred)\n\nplot_confusion_matrix(\n confusion_mat=confusion_mat, class_names=[\"Wake\", \"N1\", \"N2\", \"N3\", \"REM\"]\n)\n\nprint(classification_report(y_true, y_pred))" |
| 234 | + "from sklearn.metrics import classification_report, confusion_matrix\n\nfrom braindecode.visualization import plot_confusion_matrix\n\ny_true = [valid_set[[i]][1][0] for i in range(len(valid_sampler))]\ny_pred = clf.predict(valid_set)\n\nconfusion_mat = confusion_matrix(y_true, y_pred)\n\nplot_confusion_matrix(\n confusion_mat=confusion_mat, class_names=[\"Wake\", \"N1\", \"N2\", \"N3\", \"REM\"]\n)\n\nprint(classification_report(y_true, y_pred))" |
235 | 235 | ]
|
236 | 236 | },
|
237 | 237 | {
|
|
0 commit comments