.. DO NOT EDIT. .. THIS FILE WAS AUTOMATICALLY GENERATED BY SPHINX-GALLERY. .. TO MAKE CHANGES, EDIT THE SOURCE PYTHON FILE: .. "tutorials/classification_tutorial.py" .. LINE NUMBERS ARE GIVEN BELOW. .. only:: html .. note:: :class: sphx-glr-download-link-note Click :ref:`here ` to download the full example code .. rst-class:: sphx-glr-example-title .. _sphx_glr_tutorials_classification_tutorial.py: Time Series Classification with InceptionTime ============================================= **Author**: `Vincent Scharf `__ In this tutorial, we are going to learn how to train an InceptionTime style classifier. For this tutorial, we will use the Beef dataset available at the *UEA & UCR Time Series Classification Repository* :cite:`Dau2019UCR`. The beef dataset consists of four classes of beef spectrograms, from pure beef and beef adulterated with varying degrees of offal. The spectrograms are univariate time series of length 470. The train- and test set consist of 30 sampels each. .. note:: ``torchtime`` provides easy access to common, publicly accessible datasets. Please refer to the official documentation for the list of available datasets. We will do the following steps in order: 1. Load the Beef training and test datasets using ``torchtime`` and impute potential missing values 2. Define an InceptionTime style classifier 3. Define a loss function 4. Train the network on the training data 5. Test the network on the test data 1. Load and Normalize Beef ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Using ``torchtime``, it’s extremely easy to load datasets contained in the UCR & UEA time series classification repository. .. GENERATED FROM PYTHON SOURCE LINES 37-42 .. code-block:: default import torch import torch.utils.data as data import torchtime import torchtime.transforms as transforms .. GENERATED FROM PYTHON SOURCE LINES 43-45 The output of torchtime datasets can contain NaN values. We impute those missing values using ``transforms.Nan2Value()``. .. GENERATED FROM PYTHON SOURCE LINES 47-50 .. note:: If running on Windows and you get a BrokenPipeError, try setting the num_worker of torch.utils.data.DataLoader() to 0. .. GENERATED FROM PYTHON SOURCE LINES 50-67 .. code-block:: default transform = transforms.Compose( [transforms.Nan2Value()]) batch_size = 4 trainset = torchtime.datasets.UCR(root='./data', name="Beef", train=True, download=True, transform=transform) trainloader = data.DataLoader(trainset, batch_size=batch_size, shuffle=True, num_workers=2) testset = torchtime.datasets.UCR(root='./data', name="Beef", train=False, download=True, transform=transform) testloader = data.DataLoader(testset, batch_size=batch_size, shuffle=False, num_workers=2) classes = ('unadulterated', 'heart', 'kidney', 'liver', 'tripe') .. rst-class:: sphx-glr-script-out .. code-block:: none Downloading http://www.timeseriesclassification.com/Downloads/Beef.zip Downloading http://www.timeseriesclassification.com/Downloads/Beef.zip to ./data/UCR/Beef/Beef.zip 0%| | 0/432784 [00:00`_ for more details on saving PyTorch models. 5. Test the network on the test data ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ We have trained the network for 10 passes over the training dataset (as it is a relatively small dataset with a 1:1 train/test split). But we need to check if the network has learnt anything at all. We will check this by predicting the class label that the neural network outputs, and checking it against the ground-truth. If the prediction is correct, we add the sample to the list of correct predictions. Okay, first step. Let us display a series from the test set to get familiar. .. GENERATED FROM PYTHON SOURCE LINES 169-177 .. code-block:: default dataiter = iter(testloader) sequences, labels = next(dataiter) # print sequences seriesshow(sequences, labels) print('GroundTruth: ', ' '.join(f'{classes[labels[j]]:5s}' for j in range(4))) .. image-sg:: /tutorials/images/sphx_glr_classification_tutorial_002.png :alt: classification tutorial :srcset: /tutorials/images/sphx_glr_classification_tutorial_002.png :class: sphx-glr-single-img .. rst-class:: sphx-glr-script-out .. code-block:: none GroundTruth: unadulterated unadulterated unadulterated unadulterated .. GENERATED FROM PYTHON SOURCE LINES 178-180 Next, let's load back in our saved model (note: saving and re-loading the model wasn't necessary here, we only did it to illustrate how to do so): .. GENERATED FROM PYTHON SOURCE LINES 180-184 .. code-block:: default net = models.InceptionTime(n_inputs=1, n_classes=5) net.load_state_dict(torch.load(PATH)) .. rst-class:: sphx-glr-script-out .. code-block:: none .. GENERATED FROM PYTHON SOURCE LINES 185-186 Okay, now let us see what the neural network thinks these examples above are: .. GENERATED FROM PYTHON SOURCE LINES 186-189 .. code-block:: default outputs = net(sequences) .. GENERATED FROM PYTHON SOURCE LINES 190-194 The outputs are energies for the 5 classes. The higher the energy for a class, the more the network thinks that the sequence is of the particular class. So, let's get the index of the highest energy: .. GENERATED FROM PYTHON SOURCE LINES 194-199 .. code-block:: default _, predicted = torch.max(outputs, 1) print('Predicted: ', ' '.join(f'{classes[predicted[j]]:5s}' for j in range(4))) .. rst-class:: sphx-glr-script-out .. code-block:: none Predicted: heart unadulterated unadulterated unadulterated .. GENERATED FROM PYTHON SOURCE LINES 200-203 The results seem pretty good. Let us look at how the network performs on the whole dataset. .. GENERATED FROM PYTHON SOURCE LINES 203-219 .. code-block:: default correct = 0 total = 0 # since we're not training, we don't need to calculate the gradients for our outputs with torch.no_grad(): for data in testloader: sequences, labels = data # calculate outputs by running sequences through the network outputs = net(sequences) # the class with the highest energy is what we choose as prediction _, predicted = torch.max(outputs.data, 1) total += labels.size(0) correct += (predicted == labels).sum().item() print(f'Accuracy of the network on the 30 test sequences: {100 * correct // total} %') .. rst-class:: sphx-glr-script-out .. code-block:: none Accuracy of the network on the 30 test sequences: 26 % .. GENERATED FROM PYTHON SOURCE LINES 220-226 That looks way better than chance, which is 20% accuracy (randomly picking a class out of 5 classes). Seems like the network learnt something. Hmmm, what are the classes that performed well, and the classes that did not perform well: .. GENERATED FROM PYTHON SOURCE LINES 226-248 .. code-block:: default # prepare to count predictions for each class correct_pred = {classname: 0 for classname in classes} total_pred = {classname: 0 for classname in classes} # again no gradients needed with torch.no_grad(): for data in testloader: sequences, labels = data outputs = net(sequences) _, predictions = torch.max(outputs, 1) # collect the correct predictions for each class for label, prediction in zip(labels, predictions): if label == prediction: correct_pred[classes[label]] += 1 total_pred[classes[label]] += 1 # print accuracy for each class for classname, correct_count in correct_pred.items(): accuracy = 100 * float(correct_count) / total_pred[classname] print(f'Accuracy for class: {classname:5s} is {accuracy:.1f} %') .. rst-class:: sphx-glr-script-out .. code-block:: none Accuracy for class: unadulterated is 83.3 % Accuracy for class: heart is 33.3 % Accuracy for class: kidney is 0.0 % Accuracy for class: liver is 0.0 % Accuracy for class: tripe is 16.7 % .. GENERATED FROM PYTHON SOURCE LINES 249-260 Okay, so what next? How do we run these neural networks on the GPU? Training on GPU ^^^^^^^^^^^^^^^ Just like how you transfer a Tensor onto the GPU, you transfer the neural net onto the GPU. Let's first define our device as the first visible cuda device if we have CUDA available: .. GENERATED FROM PYTHON SOURCE LINES 260-267 .. code-block:: default device = torch.device('cuda:0' if torch.cuda.is_available() else 'cpu') # Assuming that we are on a CUDA machine, this should print a CUDA device: print(device) .. rst-class:: sphx-glr-script-out .. code-block:: none cpu .. GENERATED FROM PYTHON SOURCE LINES 268-287 The rest of this section assumes that ``device`` is a CUDA device. Then these methods will recursively go over all modules and convert their parameters and buffers to CUDA tensors: .. code:: python net.to(device) Remember that you will have to send the inputs and targets at every step to the GPU too: .. code:: python inputs, labels = data[0].to(device), data[1].to(device) Why don't I notice MASSIVE speedup compared to CPU? Because your network is tiny. .. rst-class:: sphx-glr-timing **Total running time of the script:** ( 0 minutes 8.902 seconds) .. _sphx_glr_download_tutorials_classification_tutorial.py: .. only:: html .. container:: sphx-glr-footer sphx-glr-footer-example .. container:: sphx-glr-download sphx-glr-download-python :download:`Download Python source code: classification_tutorial.py ` .. container:: sphx-glr-download sphx-glr-download-jupyter :download:`Download Jupyter notebook: classification_tutorial.ipynb ` .. only:: html .. rst-class:: sphx-glr-signature `Gallery generated by Sphinx-Gallery `_