Created
February 1, 2021 12:43
-
-
Save robintibor/21c7733b74351f1af08b3f30b46b9777 to your computer and use it in GitHub Desktop.
HighGammaDecodingCropped
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
{ | |
"cells": [ | |
{ | |
"cell_type": "code", | |
"execution_count": 1, | |
"metadata": {}, | |
"outputs": [], | |
"source": [ | |
"\"\"\"\n", | |
"Cropped Decoding on High-Gamma Dataset\n", | |
"======================================\n", | |
"\n", | |
"\"\"\"\n", | |
"\n", | |
"\n", | |
"######################################################################\n", | |
"# Building on the `Trialwise decoding\n", | |
"# tutorial <./plot_bcic_iv_2a_moabb_trial.html>`__, we now do more\n", | |
"# data-efficient cropped decoding!\n", | |
"#\n", | |
"\n", | |
"\n", | |
"######################################################################\n", | |
"# In Braindecode, there are two supported configurations created for\n", | |
"# training models: trialwise decoding and cropped decoding. We will\n", | |
"# explain this visually by comparing trialwise to cropped decoding.\n", | |
"#\n", | |
"# .. image:: ../_static/trialwise_explanation.png\n", | |
"# .. image:: ../_static/cropped_explanation.png\n", | |
"#\n", | |
"# On the left, you see trialwise decoding:\n", | |
"#\n", | |
"# 1. A complete trial is pushed through the network.\n", | |
"# 2. The network produces a prediction.\n", | |
"# 3. The prediction is compared to the target (label) for that trial to\n", | |
"# compute the loss.\n", | |
"#\n", | |
"# On the right, you see cropped decoding:\n", | |
"#\n", | |
"# 1. Instead of a complete trial, crops are pushed through the network.\n", | |
"# 2. For computational efficiency, multiple neighbouring crops are pushed\n", | |
"# through the network simultaneously (these neighbouring crops are\n", | |
"# called compute windows)\n", | |
"# 3. Therefore, the network produces multiple predictions (one per crop in\n", | |
"# the window)\n", | |
"# 4. The individual crop predictions are averaged before computing the\n", | |
"# loss function\n", | |
"#\n", | |
"# .. note::\n", | |
"#\n", | |
"# - The network architecture implicitly defines the crop size (it is the\n", | |
"# receptive field size, i.e., the number of timesteps the network uses\n", | |
"# to make a single prediction)\n", | |
"# - The window size is a user-defined hyperparameter, called\n", | |
"# ``input_window_samples`` in Braindecode. It mostly affects runtime\n", | |
"# (larger window sizes should be faster). As a rule of thumb, you can\n", | |
"# set it to two times the crop size.\n", | |
"# - Crop size and window size together define how many predictions the\n", | |
"# network makes per window: ``#window−#crop+1=#predictions``\n", | |
"#\n", | |
"\n", | |
"\n", | |
"######################################################################\n", | |
"# .. note::\n", | |
"# For cropped decoding, the above training setup is mathematically\n", | |
"# identical to sampling crops in your dataset, pushing them through the\n", | |
"# network and training directly on the individual crops. At the same time,\n", | |
"# the above training setup is much faster as it avoids redundant\n", | |
"# computations by using dilated convolutions, see our paper\n", | |
"# `Deep learning with convolutional neural networks for EEG decoding and visualization <https://arxiv.org/abs/1703.05051>`_.\n", | |
"# However, the two setups are only mathematically identical in case (1)\n", | |
"# your network does not use any padding or only left padding and\n", | |
"# (2) your loss function leads\n", | |
"# to the same gradients when using the averaged output. The first is true\n", | |
"# for our shallow and deep ConvNet models and the second is true for the\n", | |
"# log-softmax outputs and negative log likelihood loss that is typically\n", | |
"# used for classification in PyTorch.\n", | |
"#\n", | |
"\n", | |
"\n", | |
"######################################################################\n", | |
"# Loading and preprocessing the dataset\n", | |
"# -------------------------------------\n", | |
"#\n", | |
"\n", | |
"\n", | |
"######################################################################\n", | |
"# Loading and preprocessing stays the same as in the `Trialwise decoding\n", | |
"# tutorial <./plot_bcic_iv_2a_moabb_trial.html>`__.\n", | |
"#\n", | |
"\n", | |
"from braindecode.datasets.moabb import MOABBDataset\n", | |
"import mne\n", | |
"\n", | |
"subject_id = 3\n", | |
"dataset = MOABBDataset(dataset_name=\"Schirrmeister2017\", subject_ids=[subject_id])" | |
] | |
}, | |
{ | |
"cell_type": "code", | |
"execution_count": 2, | |
"metadata": {}, | |
"outputs": [], | |
"source": [ | |
"from braindecode.datautil.preprocess import exponential_moving_standardize\n", | |
"from braindecode.datautil.preprocess import MNEPreproc, NumpyPreproc, preprocess\n", | |
"import numpy as np\n", | |
"\n", | |
"C_sensors = [\n", | |
" 'FC5', 'FC1', 'FC2', 'FC6', 'C3', 'Cz', 'C4', 'CP5',\n", | |
" 'CP1', 'CP2', 'CP6', 'FC3', 'FCz', 'FC4', 'C5', 'C1', 'C2', 'C6',\n", | |
" 'CP3', 'CPz', 'CP4', 'FFC5h', 'FFC3h', 'FFC4h', 'FFC6h', 'FCC5h',\n", | |
" 'FCC3h', 'FCC4h', 'FCC6h', 'CCP5h', 'CCP3h', 'CCP4h', 'CCP6h', 'CPP5h',\n", | |
" 'CPP3h', 'CPP4h', 'CPP6h', 'FFC1h', 'FFC2h', 'FCC1h', 'FCC2h', 'CCP1h',\n", | |
" 'CCP2h', 'CPP1h', 'CPP2h']\n", | |
"low_cut_hz = None # low cut frequency for filtering\n", | |
"high_cut_hz = None # high cut frequency for filtering\n", | |
"# Parameters for exponential moving standardization\n", | |
"factor_new = 1e-3\n", | |
"init_block_size = 1000\n", | |
"\n", | |
"preprocessors = [\n", | |
" # keep only C sensors\n", | |
" #MNEPreproc(fn='pick_types', eeg=True, meg=False, stim=False),\n", | |
" MNEPreproc(fn='pick_channels', ch_names=C_sensors, ordered=True),\n", | |
" # convert from volt to microvolt, directly modifying the numpy array\n", | |
" NumpyPreproc(fn=lambda x: x * 1e6),\n", | |
" NumpyPreproc(fn=lambda x: np.clip(x, -800,800)),\n", | |
" MNEPreproc(fn='resample', sfreq=250),\n", | |
" # bandpass filter\n", | |
" MNEPreproc(fn='filter', l_freq=low_cut_hz, h_freq=high_cut_hz),\n", | |
" # exponential moving standardization\n", | |
" NumpyPreproc(fn=exponential_moving_standardize, factor_new=factor_new,\n", | |
" init_block_size=init_block_size)\n", | |
"]\n", | |
"\n", | |
"# Transform the data\n", | |
"preprocess(dataset, preprocessors)" | |
] | |
}, | |
{ | |
"cell_type": "code", | |
"execution_count": 3, | |
"metadata": {}, | |
"outputs": [], | |
"source": [ | |
"######################################################################\n", | |
"# Create model and compute windowing parameters\n", | |
"# ---------------------------------------------\n", | |
"#\n", | |
"\n", | |
"\n", | |
"######################################################################\n", | |
"# In contrast to trialwise decoding, we first have to create the model\n", | |
"# before we can cut the dataset into windows. This is because we need to\n", | |
"# know the receptive field of the network to know how large the window\n", | |
"# stride should be.\n", | |
"#\n", | |
"\n", | |
"\n", | |
"######################################################################\n", | |
"# We first choose the compute/input window size that will be fed to the\n", | |
"# network during training This has to be larger than the networks\n", | |
"# receptive field size and can otherwise be chosen for computational\n", | |
"# efficiency (see explanations in the beginning of this tutorial). Here we\n", | |
"# choose 1000 samples, which are 4 seconds for the 250 Hz sampling rate.\n", | |
"#\n", | |
"\n", | |
"input_window_samples = 1000\n", | |
"\n", | |
"\n", | |
"######################################################################\n", | |
"# Now we create the model. To enable it to be used in cropped decoding\n", | |
"# efficiently, we manually set the length of the final convolution layer\n", | |
"# to some length that makes the receptive field of the ConvNet smaller\n", | |
"# than ``input_window_samples`` (see ``final_conv_length=30`` in the model\n", | |
"# definition).\n", | |
"#\n", | |
"\n", | |
"import torch\n", | |
"from braindecode.util import set_random_seeds\n", | |
"from braindecode.models import ShallowFBCSPNet\n", | |
"from braindecode.models import Deep4Net\n", | |
"\n", | |
"\n", | |
"cuda = torch.cuda.is_available() # check if GPU is available, if True chooses to use it\n", | |
"device = 'cuda' if cuda else 'cpu'\n", | |
"if cuda:\n", | |
" torch.backends.cudnn.benchmark = True\n", | |
"seed = 20200220 # random seed to make results reproducible\n", | |
"# Set random seed to be able to reproduce results\n", | |
"set_random_seeds(seed=seed, cuda=cuda)\n", | |
"\n", | |
"n_classes=4\n", | |
"# Extract number of chans from dataset\n", | |
"n_chans = dataset[0][0].shape[0]\n", | |
"\n", | |
"#model = ShallowFBCSPNet(\n", | |
"# n_chans,\n", | |
"# n_classes,\n", | |
"# input_window_samples=input_window_samples,\n", | |
"# final_conv_length=30,\n", | |
"#)\n", | |
"\n", | |
"model = Deep4Net(\n", | |
" n_chans,\n", | |
" n_classes,\n", | |
" input_window_samples=input_window_samples,\n", | |
" final_conv_length=2,\n", | |
")\n", | |
"\n", | |
"# Send model to GPU\n", | |
"if cuda:\n", | |
" model.cuda()\n", | |
"\n", | |
"\n", | |
"\n", | |
"######################################################################\n", | |
"# And now we transform model with strides to a model that outputs dense\n", | |
"# prediction, so we can use it to obtain predictions for all\n", | |
"# crops.\n", | |
"#\n", | |
"\n", | |
"from braindecode.models.util import to_dense_prediction_model, get_output_shape\n", | |
"to_dense_prediction_model(model)\n", | |
"\n", | |
"\n", | |
"######################################################################\n", | |
"# To know the models’ receptive field, we calculate the shape of model\n", | |
"# output for a dummy input.\n", | |
"#\n", | |
"\n", | |
"n_preds_per_input = get_output_shape(model, n_chans, input_window_samples)[2]\n", | |
"\n", | |
"\n", | |
"######################################################################\n", | |
"# Cut the data into windows\n", | |
"# -------------------------\n", | |
"#\n", | |
"\n", | |
"\n", | |
"######################################################################\n", | |
"# In contrast to trialwise decoding, we have to supply an explicit window size and window stride to the\n", | |
"# ``create_windows_from_events`` function.\n", | |
"#\n", | |
"\n", | |
"import numpy as np\n", | |
"from braindecode.datautil.windowers import create_windows_from_events\n", | |
"\n", | |
"trial_start_offset_seconds = -0.5\n", | |
"# Extract sampling frequency, check that they are same in all datasets\n", | |
"sfreq = dataset.datasets[0].raw.info['sfreq']\n", | |
"assert all([ds.raw.info['sfreq'] == sfreq for ds in dataset.datasets])\n", | |
"\n", | |
"# Calculate the trial start offset in samples.\n", | |
"trial_start_offset_samples = int(trial_start_offset_seconds * sfreq)\n", | |
"\n", | |
"# Create windows using braindecode function for this. It needs parameters to define how\n", | |
"# trials should be used.\n", | |
"windows_dataset = create_windows_from_events(\n", | |
" dataset,\n", | |
" trial_start_offset_samples=trial_start_offset_samples,\n", | |
" trial_stop_offset_samples=0,\n", | |
" window_size_samples=input_window_samples,\n", | |
" window_stride_samples=n_preds_per_input,\n", | |
" drop_last_window=False,\n", | |
" preload=True,\n", | |
")\n", | |
"\n", | |
"\n", | |
"######################################################################\n", | |
"# Split the dataset\n", | |
"# -----------------\n", | |
"#\n", | |
"# This code is the same as in trialwise decoding.\n", | |
"#\n", | |
"\n", | |
"from torch.utils.data import Subset\n", | |
"from braindecode.util import set_random_seeds\n", | |
"splitted = windows_dataset.split('run')\n", | |
"full_train_set = splitted['train']\n", | |
"\n", | |
"n_split = int(np.round(0.8 * len(full_train_set)))\n", | |
"# ensure this is mutiple of 2 (number of windows per trial)\n", | |
"n_windows_per_trial = 2 # here set by hand\n", | |
"n_split = n_split - (n_split % n_windows_per_trial)\n", | |
"valid_set = Subset(full_train_set, range(n_split,len(full_train_set)))\n", | |
"train_set = Subset(full_train_set, range(0, n_split))" | |
] | |
}, | |
{ | |
"cell_type": "code", | |
"execution_count": 5, | |
"metadata": {}, | |
"outputs": [ | |
{ | |
"name": "stdout", | |
"output_type": "stream", | |
"text": [ | |
" epoch train_accuracy train_loss valid_accuracy valid_loss lr dur\n", | |
"------- ---------------- ------------ ---------------- ------------ ------ ------\n", | |
" 1 \u001b[36m0.5241\u001b[0m \u001b[32m1.2109\u001b[0m \u001b[35m0.4886\u001b[0m \u001b[31m1.3814\u001b[0m 0.0100 0.9335\n" | |
] | |
}, | |
{ | |
"name": "stderr", | |
"output_type": "stream", | |
"text": [ | |
"/home/schirrmr/anaconda3/envs/invertible/lib/python3.7/site-packages/torch/optim/lr_scheduler.py:156: UserWarning: The epoch parameter in `scheduler.step()` was not necessary and is being deprecated where possible. Please use `scheduler.step()` to step the scheduler. During the deprecation, if epoch is different from None, the closed form is used instead of the new chainable form, where available. Please open an issue if you are unable to replicate your use case: https://github.com/pytorch/pytorch/issues/new/choose.\n", | |
" warnings.warn(EPOCH_DEPRECATION_WARNING, UserWarning)\n" | |
] | |
}, | |
{ | |
"name": "stdout", | |
"output_type": "stream", | |
"text": [ | |
" 2 \u001b[36m0.6151\u001b[0m \u001b[32m0.7518\u001b[0m \u001b[35m0.5909\u001b[0m \u001b[31m1.1750\u001b[0m 0.0099 0.8997\n", | |
" 3 \u001b[36m0.7543\u001b[0m \u001b[32m0.5807\u001b[0m \u001b[35m0.7273\u001b[0m \u001b[31m0.7860\u001b[0m 0.0097 0.9028\n", | |
" 4 \u001b[36m0.8636\u001b[0m \u001b[32m0.5199\u001b[0m \u001b[35m0.8466\u001b[0m \u001b[31m0.5854\u001b[0m 0.0094 1.0053\n", | |
" 5 0.8153 \u001b[32m0.4566\u001b[0m 0.7216 0.7571 0.0089 0.9145\n", | |
" 6 \u001b[36m0.9048\u001b[0m \u001b[32m0.4265\u001b[0m 0.8466 0.5915 0.0084 0.8947\n", | |
" 7 \u001b[36m0.9446\u001b[0m 0.4487 \u001b[35m0.8920\u001b[0m \u001b[31m0.5045\u001b[0m 0.0077 0.9005\n", | |
" 8 0.9403 \u001b[32m0.3627\u001b[0m 0.8580 \u001b[31m0.4926\u001b[0m 0.0070 0.9180\n", | |
" 9 \u001b[36m0.9503\u001b[0m \u001b[32m0.3125\u001b[0m 0.8920 0.5103 0.0062 0.9011\n", | |
" 10 0.9318 0.3230 0.8409 0.5442 0.0054 0.8999\n", | |
" 11 0.9361 \u001b[32m0.2744\u001b[0m 0.8125 0.5912 0.0046 0.9079\n", | |
" 12 0.9389 \u001b[32m0.2592\u001b[0m 0.8295 0.5651 0.0038 0.9187\n", | |
" 13 \u001b[36m0.9602\u001b[0m \u001b[32m0.2490\u001b[0m 0.8580 0.5088 0.0030 0.8992\n", | |
" 14 \u001b[36m0.9815\u001b[0m \u001b[32m0.2442\u001b[0m \u001b[35m0.9034\u001b[0m \u001b[31m0.4241\u001b[0m 0.0023 0.9066\n", | |
" 15 \u001b[36m0.9844\u001b[0m \u001b[32m0.2154\u001b[0m 0.8920 0.4346 0.0016 0.9034\n", | |
" 16 0.9787 \u001b[32m0.2113\u001b[0m 0.8750 0.4896 0.0011 0.9146\n", | |
" 17 \u001b[36m0.9858\u001b[0m 0.2115 0.8807 0.4505 0.0006 0.9023\n", | |
" 18 0.9858 \u001b[32m0.2068\u001b[0m 0.8864 0.4537 0.0003 0.9045\n", | |
" 19 0.9844 \u001b[32m0.2059\u001b[0m 0.8864 0.4569 0.0001 0.8997\n", | |
" 20 0.9858 \u001b[32m0.2007\u001b[0m 0.8864 0.4569 0.0000 0.9014\n" | |
] | |
}, | |
{ | |
"data": { | |
"image/png": "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9NFHad26NcXFxcycOZOxY8eyceNGVKrKb5mbN292acOIiIhaqUNlVNV2AD169ODNN990flZXETjNH9oOYOfOnS6fjxw5wiOPPFLldQh133a+3P/9+brzhejnn6fx+PEU//AD+Z+vJXvB++i7diVs6FCCB/T3OcCfE1lQbykuLpZbt24tf/vtt17zpKamyi1btpQPHTp0FUtWfd577z158ODBPuf/5JNP5A4dOshGo9GZNnfuXLlXr16y3W6vjSJeUebNmyd36tRJNhgMHvf7S7vJsiy3b99e/vzzz52f7Xa73LNnT3nevHnONKPRKLdv315euXKlVztvvvmmfNNNN7mkvfjii/KwYcOufKF9pGLdPPHHH3/ILVu2lI8dO+Y1z08//SS3bNlSzsnJudJFvCw81W/ChAnyuHHjqmXHX9tu0qRJ8qBBgyrNU1/bruL9vyFdd75iycyUsxctkk/e8jf5ePcesq24uFrHi1lU9ZiSkhLsdjshISFV5n3iiSfo3r07w4cP56uvvroKpas+qamp9O7dm/79+/PMM8+QmprqNe/Bgwfp3LkzAQEBzrRevXqRmZlJWlra1ShujZFlmTVr1nDHHXeg0+kqzesP7VaRtLQ0srKy6NmzpzMtICCALl26cODAAa/HHTx40OUYcLTpkSNHsFgstVbey6W4uBjwrXftnnvuoVevXowaNYqffvqptotWY/bt20f37t25+eabeemll8jJyak0vz+2XUlJCZs3b2bYsGE+5a9vbVfx/v+/dt0B2I1GbIVF2A0GFHp9pcH/PCGGqOox06dP59prr6VDhw5e8+j1eiZMmEDHjh1RKpVs27aNZ555BpPJxJAhQ65iaSunXbt2zJgxg8TERHJzc5k/fz7Dhw9n06ZNhIeHu+XPzs4mOjraJS0yMtK5r2nTplel3DVh165dpKWlce+993rN4y/t5omsrCzgYnuU06hRIzIzM70el52dTffu3V3SIiMjsVqt5OXl0bhx4ytf2MvEbDYzc+ZM+vXrxzWV+AJERUXxyiuv0LZtWywWCxs2bGD06NEsX76cLl26XMUSV03v3r256aabiIuLIz09nVmzZjFq1CjWrl2LpizQWkX8se02bdqExWLhrrvuqjRffW27ivf//5Xrzl5aSuGXX5H/+RpKj/xG8MCBNJk5g8AKdfAFIXDqKTNmzGDfvn2s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\n", | |
"text/plain": [ | |
"<Figure size 576x216 with 2 Axes>" | |
] | |
}, | |
"metadata": {}, | |
"output_type": "display_data" | |
} | |
], | |
"source": [ | |
"\n", | |
"######################################################################\n", | |
"# Training\n", | |
"# --------\n", | |
"#\n", | |
"\n", | |
"\n", | |
"######################################################################\n", | |
"# In difference to trialwise decoding, we now should supply\n", | |
"# ``cropped=True`` to the EEGClassifier, and ``CroppedLoss`` as the\n", | |
"# criterion, as well as ``criterion__loss_function`` as the loss function\n", | |
"# applied to the meaned predictions.\n", | |
"#\n", | |
"\n", | |
"\n", | |
"######################################################################\n", | |
"# .. note::\n", | |
"# In this tutorial, we use some default parameters that we\n", | |
"# have found to work well for motor decoding, however we strongly\n", | |
"# encourage you to perform your own hyperparameter optimization using\n", | |
"# cross validation on your training data.\n", | |
"#\n", | |
"\n", | |
"from skorch.callbacks import LRScheduler\n", | |
"from skorch.helper import predefined_split\n", | |
"\n", | |
"from braindecode import EEGClassifier\n", | |
"from braindecode.training.losses import CroppedLoss\n", | |
"\n", | |
"# These values we found good for shallow network:\n", | |
"#lr = 0.0625 * 0.01\n", | |
"#weight_decay = 0\n", | |
"\n", | |
"# For deep4 they should be:\n", | |
"lr = 1 * 0.01\n", | |
"weight_decay = 0.5 * 0.001\n", | |
"\n", | |
"batch_size = 64\n", | |
"n_epochs = 20\n", | |
"\n", | |
"clf = EEGClassifier(\n", | |
" model,\n", | |
" cropped=True,\n", | |
" criterion=CroppedLoss,\n", | |
" criterion__loss_function=torch.nn.functional.nll_loss,\n", | |
" optimizer=torch.optim.AdamW,\n", | |
" train_split=predefined_split(valid_set),\n", | |
" optimizer__lr=lr,\n", | |
" optimizer__weight_decay=weight_decay,\n", | |
" iterator_train__shuffle=True,\n", | |
" batch_size=batch_size,\n", | |
" callbacks=[\n", | |
" \"accuracy\", (\"lr_scheduler\", LRScheduler('CosineAnnealingLR', T_max=n_epochs - 1)),\n", | |
" ],\n", | |
" device=device,\n", | |
")\n", | |
"# Model training for a specified number of epochs. `y` is None as it is already supplied\n", | |
"# in the dataset.\n", | |
"clf.fit(train_set, y=None, epochs=n_epochs)\n", | |
"\n", | |
"\n", | |
"######################################################################\n", | |
"# Plot Results\n", | |
"# ------------\n", | |
"#\n", | |
"\n", | |
"\n", | |
"######################################################################\n", | |
"# This is again the same code as in trialwise decoding.\n", | |
"#\n", | |
"# .. note::\n", | |
"# Note that we drop further in the classification error and\n", | |
"# loss as in the trialwise decoding tutorial.\n", | |
"#\n", | |
"\n", | |
"import matplotlib.pyplot as plt\n", | |
"from matplotlib.lines import Line2D\n", | |
"import pandas as pd\n", | |
"# Extract loss and accuracy values for plotting from history object\n", | |
"results_columns = ['train_loss', 'valid_loss', 'train_accuracy', 'valid_accuracy']\n", | |
"df = pd.DataFrame(clf.history[:, results_columns], columns=results_columns,\n", | |
" index=clf.history[:, 'epoch'])\n", | |
"\n", | |
"# get percent of misclass for better visual comparison to loss\n", | |
"df = df.assign(train_misclass=100 - 100 * df.train_accuracy,\n", | |
" valid_misclass=100 - 100 * df.valid_accuracy)\n", | |
"\n", | |
"plt.style.use('seaborn')\n", | |
"fig, ax1 = plt.subplots(figsize=(8, 3))\n", | |
"df.loc[:, ['train_loss', 'valid_loss']].plot(\n", | |
" ax=ax1, style=['-', ':'], marker='o', color='tab:blue', legend=False, fontsize=14)\n", | |
"\n", | |
"ax1.tick_params(axis='y', labelcolor='tab:blue', labelsize=14)\n", | |
"ax1.set_ylabel(\"Loss\", color='tab:blue', fontsize=14)\n", | |
"\n", | |
"ax2 = ax1.twinx() # instantiate a second axes that shares the same x-axis\n", | |
"\n", | |
"df.loc[:, ['train_misclass', 'valid_misclass']].plot(\n", | |
" ax=ax2, style=['-', ':'], marker='o', color='tab:red', legend=False)\n", | |
"ax2.tick_params(axis='y', labelcolor='tab:red', labelsize=14)\n", | |
"ax2.set_ylabel(\"Misclassification Rate [%]\", color='tab:red', fontsize=14)\n", | |
"ax2.set_ylim(ax2.get_ylim()[0], 85) # make some room for legend\n", | |
"ax1.set_xlabel(\"Epoch\", fontsize=14)\n", | |
"\n", | |
"# where some data has already been plotted to ax\n", | |
"handles = []\n", | |
"handles.append(Line2D([0], [0], color='black', linewidth=1, linestyle='-', label='Train'))\n", | |
"handles.append(Line2D([0], [0], color='black', linewidth=1, linestyle=':', label='Valid'))\n", | |
"plt.legend(handles, [h.get_label() for h in handles], fontsize=14)\n", | |
"plt.tight_layout()" | |
] | |
}, | |
{ | |
"cell_type": "code", | |
"execution_count": null, | |
"metadata": {}, | |
"outputs": [], | |
"source": [] | |
}, | |
{ | |
"cell_type": "code", | |
"execution_count": null, | |
"metadata": {}, | |
"outputs": [], | |
"source": [] | |
} | |
], | |
"metadata": { | |
"kernelspec": { | |
"display_name": "Python 3", | |
"language": "python", | |
"name": "python3" | |
}, | |
"language_info": { | |
"codemirror_mode": { | |
"name": "ipython", | |
"version": 3 | |
}, | |
"file_extension": ".py", | |
"mimetype": "text/x-python", | |
"name": "python", | |
"nbconvert_exporter": "python", | |
"pygments_lexer": "ipython3", | |
"version": "3.7.5" | |
} | |
}, | |
"nbformat": 4, | |
"nbformat_minor": 4 | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment