From e8a70c0f1e30e8af70ebee373fe077500c190287 Mon Sep 17 00:00:00 2001 From: Ben Akka Zakariae <zakariae.ben-akka@etu.ec-lyon.fr> Date: Thu, 23 Nov 2023 11:17:53 +0000 Subject: [PATCH] Upload New File --- TD2_Deep_Learning.ipynb | 993 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 993 insertions(+) create mode 100644 TD2_Deep_Learning.ipynb diff --git a/TD2_Deep_Learning.ipynb b/TD2_Deep_Learning.ipynb new file mode 100644 index 0000000..fd619c2 --- /dev/null +++ b/TD2_Deep_Learning.ipynb @@ -0,0 +1,993 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "id": "7edf7168", + "metadata": {}, + "source": [ + "# TD2: Deep learning" + ] + }, + { + "cell_type": "markdown", + "id": "fbb8c8df", + "metadata": {}, + "source": [ + "In this TD, you must modify this notebook to answer the questions. To do this,\n", + "\n", + "1. Fork this repository\n", + "2. Clone your forked repository on your local computer\n", + "3. Answer the questions\n", + "4. Commit and push regularly\n", + "\n", + "The last commit is due on Sunday, December 1, 11:59 PM. Later commits will not be taken into account." + ] + }, + { + "cell_type": "markdown", + "id": "3d167a29", + "metadata": {}, + "source": [ + "Install and test PyTorch from https://pytorch.org/get-started/locally." + ] + }, + { + "cell_type": "code", + "execution_count": 4, + "id": "330a42f5", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Requirement already satisfied: torch in c:\\users\\lenovo\\appdata\\local\\packages\\pythonsoftwarefoundation.python.3.11_qbz5n2kfra8p0\\localcache\\local-packages\\python311\\site-packages (2.1.0+cu118)\n", + "Requirement already satisfied: torchvision in c:\\users\\lenovo\\appdata\\local\\packages\\pythonsoftwarefoundation.python.3.11_qbz5n2kfra8p0\\localcache\\local-packages\\python311\\site-packages (0.16.0+cu118)\n", + "Requirement already satisfied: filelock in c:\\users\\lenovo\\appdata\\local\\packages\\pythonsoftwarefoundation.python.3.11_qbz5n2kfra8p0\\localcache\\local-packages\\python311\\site-packages (from torch) (3.9.0)\n", + "Requirement already satisfied: typing-extensions in c:\\users\\lenovo\\appdata\\local\\packages\\pythonsoftwarefoundation.python.3.11_qbz5n2kfra8p0\\localcache\\local-packages\\python311\\site-packages (from torch) (4.4.0)\n", + "Requirement already satisfied: sympy in c:\\users\\lenovo\\appdata\\local\\packages\\pythonsoftwarefoundation.python.3.11_qbz5n2kfra8p0\\localcache\\local-packages\\python311\\site-packages (from torch) (1.12)\n", + "Requirement already satisfied: networkx in c:\\users\\lenovo\\appdata\\local\\packages\\pythonsoftwarefoundation.python.3.11_qbz5n2kfra8p0\\localcache\\local-packages\\python311\\site-packages (from torch) (3.0)\n", + "Requirement already satisfied: jinja2 in c:\\users\\lenovo\\appdata\\local\\packages\\pythonsoftwarefoundation.python.3.11_qbz5n2kfra8p0\\localcache\\local-packages\\python311\\site-packages (from torch) (3.1.2)\n", + "Requirement already satisfied: fsspec in c:\\users\\lenovo\\appdata\\local\\packages\\pythonsoftwarefoundation.python.3.11_qbz5n2kfra8p0\\localcache\\local-packages\\python311\\site-packages (from torch) (2023.4.0)\n", + "Requirement already satisfied: numpy in c:\\users\\lenovo\\appdata\\local\\packages\\pythonsoftwarefoundation.python.3.11_qbz5n2kfra8p0\\localcache\\local-packages\\python311\\site-packages (from torchvision) (1.26.1)\n", + "Requirement already satisfied: requests in c:\\users\\lenovo\\appdata\\local\\packages\\pythonsoftwarefoundation.python.3.11_qbz5n2kfra8p0\\localcache\\local-packages\\python311\\site-packages (from torchvision) (2.31.0)\n", + "Requirement already satisfied: pillow!=8.3.*,>=5.3.0 in c:\\users\\lenovo\\appdata\\local\\packages\\pythonsoftwarefoundation.python.3.11_qbz5n2kfra8p0\\localcache\\local-packages\\python311\\site-packages (from torchvision) (10.1.0)\n", + "Requirement already satisfied: MarkupSafe>=2.0 in c:\\users\\lenovo\\appdata\\local\\packages\\pythonsoftwarefoundation.python.3.11_qbz5n2kfra8p0\\localcache\\local-packages\\python311\\site-packages (from jinja2->torch) (2.1.2)\n", + "Requirement already satisfied: charset-normalizer<4,>=2 in c:\\users\\lenovo\\appdata\\local\\packages\\pythonsoftwarefoundation.python.3.11_qbz5n2kfra8p0\\localcache\\local-packages\\python311\\site-packages (from requests->torchvision) (3.3.1)\n", + "Requirement already satisfied: idna<4,>=2.5 in c:\\users\\lenovo\\appdata\\local\\packages\\pythonsoftwarefoundation.python.3.11_qbz5n2kfra8p0\\localcache\\local-packages\\python311\\site-packages (from requests->torchvision) (3.4)\n", + "Requirement already satisfied: urllib3<3,>=1.21.1 in c:\\users\\lenovo\\appdata\\local\\packages\\pythonsoftwarefoundation.python.3.11_qbz5n2kfra8p0\\localcache\\local-packages\\python311\\site-packages (from requests->torchvision) (2.0.7)\n", + "Requirement already satisfied: certifi>=2017.4.17 in c:\\users\\lenovo\\appdata\\local\\packages\\pythonsoftwarefoundation.python.3.11_qbz5n2kfra8p0\\localcache\\local-packages\\python311\\site-packages (from requests->torchvision) (2023.7.22)\n", + "Requirement already satisfied: mpmath>=0.19 in c:\\users\\lenovo\\appdata\\local\\packages\\pythonsoftwarefoundation.python.3.11_qbz5n2kfra8p0\\localcache\\local-packages\\python311\\site-packages (from sympy->torch) (1.3.0)\n", + "Note: you may need to restart the kernel to use updated packages.\n" + ] + } + ], + "source": [ + "%pip install torch torchvision" + ] + }, + { + "cell_type": "markdown", + "id": "0882a636", + "metadata": {}, + "source": [ + "\n", + "To test run the following code" + ] + }, + { + "cell_type": "code", + "execution_count": 5, + "id": "b1950f0a", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "tensor([[ 1.0605, 0.4877, 1.3848, -0.5006, 0.0414, 0.2985, 0.1982, 0.5928,\n", + " 0.4444, 0.3458],\n", + " [-0.1176, -1.5951, -1.1404, 0.6262, -1.0974, -0.7637, 0.4559, 0.3599,\n", + " 0.7854, 0.1764],\n", + " [ 0.2529, 0.4114, 1.5469, 0.2975, -0.9362, -1.0877, 0.3287, 1.8137,\n", + " 0.9959, -0.9416],\n", + " [ 0.8527, -1.1763, 1.0453, 0.2173, 1.2337, -0.4122, -0.4660, 0.5123,\n", + " -0.5657, 0.2373],\n", + " [-0.5439, 0.9611, 0.8822, -1.0495, -0.8781, -0.9642, -0.9343, 0.6947,\n", + " -0.1654, -0.6049],\n", + " [-1.2154, 1.4457, 0.5532, 0.5507, 0.9646, 1.6836, -0.7217, -1.5023,\n", + " -0.1566, -0.0864],\n", + " [ 2.1407, 0.1364, 0.5218, 0.5398, 0.8079, 1.3318, 0.1576, 0.7597,\n", + " 1.8427, -0.1918],\n", + " [-0.4011, -2.5381, 0.6992, -0.8056, 0.1494, -0.8711, -1.0129, 0.4020,\n", + " 0.1074, 1.4686],\n", + " [-0.1769, 1.0718, 0.6540, -1.6458, 2.1758, 0.0703, 0.7089, 0.9214,\n", + " 1.4192, -0.5498],\n", + " [-1.4553, -0.0320, 0.4980, -0.9733, 0.4106, -0.4363, 1.5308, -0.8421,\n", + " 0.0412, -2.0390],\n", + " [ 0.1056, 0.6472, -0.1967, 0.9547, 0.8193, -1.4786, -0.5792, -0.1598,\n", + " -0.1151, 0.0905],\n", + " [ 0.6584, -2.2935, 0.0100, -1.8383, 2.2067, -0.1495, 0.0839, 2.0443,\n", + " -1.7859, -0.5420],\n", + " [ 0.4898, -0.1235, 0.4655, -0.9289, -0.8926, -2.5259, 0.4773, -0.2087,\n", + " 2.2034, 0.1863],\n", + " [-1.3225, 0.4705, -0.3551, -0.0710, -0.4115, -0.2432, -1.2216, 1.2093,\n", + " -0.1206, 1.0373]])\n", + "AlexNet(\n", + " (features): Sequential(\n", + " (0): Conv2d(3, 64, kernel_size=(11, 11), stride=(4, 4), padding=(2, 2))\n", + " (1): ReLU(inplace=True)\n", + " (2): MaxPool2d(kernel_size=3, stride=2, padding=0, dilation=1, ceil_mode=False)\n", + " (3): Conv2d(64, 192, kernel_size=(5, 5), stride=(1, 1), padding=(2, 2))\n", + " (4): ReLU(inplace=True)\n", + " (5): MaxPool2d(kernel_size=3, stride=2, padding=0, dilation=1, ceil_mode=False)\n", + " (6): Conv2d(192, 384, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1))\n", + " (7): ReLU(inplace=True)\n", + " (8): Conv2d(384, 256, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1))\n", + " (9): ReLU(inplace=True)\n", + " (10): Conv2d(256, 256, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1))\n", + " (11): ReLU(inplace=True)\n", + " (12): MaxPool2d(kernel_size=3, stride=2, padding=0, dilation=1, ceil_mode=False)\n", + " )\n", + " (avgpool): AdaptiveAvgPool2d(output_size=(6, 6))\n", + " (classifier): Sequential(\n", + " (0): Dropout(p=0.5, inplace=False)\n", + " (1): Linear(in_features=9216, out_features=4096, bias=True)\n", + " (2): ReLU(inplace=True)\n", + " (3): Dropout(p=0.5, inplace=False)\n", + " (4): Linear(in_features=4096, out_features=4096, bias=True)\n", + " (5): ReLU(inplace=True)\n", + " (6): Linear(in_features=4096, out_features=1000, bias=True)\n", + " )\n", + ")\n" + ] + } + ], + "source": [ + "import torch\n", + "\n", + "N, D = 14, 10\n", + "x = torch.randn(N, D).type(torch.FloatTensor)\n", + "print(x)\n", + "\n", + "from torchvision import models\n", + "\n", + "alexnet = models.alexnet()\n", + "print(alexnet)" + ] + }, + { + "cell_type": "markdown", + "id": "23f266da", + "metadata": {}, + "source": [ + "## Exercise 1: CNN on CIFAR10\n", + "\n", + "The goal is to apply a Convolutional Neural Net (CNN) model on the CIFAR10 image dataset and test the accuracy of the model on the basis of image classification. Compare the Accuracy VS the neural network implemented during TD1.\n", + "\n", + "Have a look at the following documentation to be familiar with PyTorch.\n", + "\n", + "https://pytorch.org/tutorials/beginner/pytorch_with_examples.html\n", + "\n", + "https://pytorch.org/tutorials/beginner/deep_learning_60min_blitz.html" + ] + }, + { + "cell_type": "markdown", + "id": "4ba1c82d", + "metadata": {}, + "source": [ + "You can test if GPU is available on your machine and thus train on it to speed up the process" + ] + }, + { + "cell_type": "code", + "execution_count": 6, + "id": "6e18f2fd", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "CUDA is not available. Training on CPU ...\n" + ] + } + ], + "source": [ + "import torch\n", + "\n", + "# check if CUDA is available\n", + "train_on_gpu = torch.cuda.is_available()\n", + "\n", + "if not train_on_gpu:\n", + " print(\"CUDA is not available. Training on CPU ...\")\n", + "else:\n", + " print(\"CUDA is available! Training on GPU ...\")" + ] + }, + { + "cell_type": "markdown", + "id": "5cf214eb", + "metadata": {}, + "source": [ + "Next we load the CIFAR10 dataset" + ] + }, + { + "cell_type": "code", + "execution_count": 7, + "id": "462666a2", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Files already downloaded and verified\n", + "Files already downloaded and verified\n" + ] + } + ], + "source": [ + "import numpy as np\n", + "from torchvision import datasets, transforms\n", + "from torch.utils.data.sampler import SubsetRandomSampler\n", + "\n", + "# number of subprocesses to use for data loading\n", + "num_workers = 0\n", + "# how many samples per batch to load\n", + "batch_size = 20\n", + "# percentage of training set to use as validation\n", + "valid_size = 0.2\n", + "\n", + "# convert data to a normalized torch.FloatTensor\n", + "transform = transforms.Compose(\n", + " [transforms.ToTensor(), transforms.Normalize((0.5, 0.5, 0.5), (0.5, 0.5, 0.5))]\n", + ")\n", + "\n", + "# choose the training and test datasets\n", + "train_data = datasets.CIFAR10(\"data\", train=True, download=True, transform=transform)\n", + "test_data = datasets.CIFAR10(\"data\", train=False, download=True, transform=transform)\n", + "\n", + "# obtain training indices that will be used for validation\n", + "num_train = len(train_data)\n", + "indices = list(range(num_train))\n", + "np.random.shuffle(indices)\n", + "split = int(np.floor(valid_size * num_train))\n", + "train_idx, valid_idx = indices[split:], indices[:split]\n", + "\n", + "# define samplers for obtaining training and validation batches\n", + "train_sampler = SubsetRandomSampler(train_idx)\n", + "valid_sampler = SubsetRandomSampler(valid_idx)\n", + "\n", + "# prepare data loaders (combine dataset and sampler)\n", + "train_loader = torch.utils.data.DataLoader(\n", + " train_data, batch_size=batch_size, sampler=train_sampler, num_workers=num_workers\n", + ")\n", + "valid_loader = torch.utils.data.DataLoader(\n", + " train_data, batch_size=batch_size, sampler=valid_sampler, num_workers=num_workers\n", + ")\n", + "test_loader = torch.utils.data.DataLoader(\n", + " test_data, batch_size=batch_size, num_workers=num_workers\n", + ")\n", + "\n", + "# specify the image classes\n", + "classes = [\n", + " \"airplane\",\n", + " \"automobile\",\n", + " \"bird\",\n", + " \"cat\",\n", + " \"deer\",\n", + " \"dog\",\n", + " \"frog\",\n", + " \"horse\",\n", + " \"ship\",\n", + " \"truck\",\n", + "]" + ] + }, + { + "cell_type": "markdown", + "id": "58ec3903", + "metadata": {}, + "source": [ + "CNN definition (this one is an example)" + ] + }, + { + "cell_type": "code", + "execution_count": 15, + "id": "317bf070", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Net(\n", + " (conv1): Conv2d(3, 6, kernel_size=(5, 5), stride=(1, 1))\n", + " (pool): MaxPool2d(kernel_size=2, stride=2, padding=0, dilation=1, ceil_mode=False)\n", + " (conv2): Conv2d(6, 16, kernel_size=(5, 5), stride=(1, 1))\n", + " (fc1): Linear(in_features=400, out_features=120, bias=True)\n", + " (fc2): Linear(in_features=120, out_features=84, bias=True)\n", + " (fc3): Linear(in_features=84, out_features=10, bias=True)\n", + ")\n" + ] + } + ], + "source": [ + "import torch.nn as nn\n", + "import torch.nn.functional as F\n", + "\n", + "# define the CNN architecture\n", + "\n", + "\n", + "class Net(nn.Module):\n", + " def __init__(self):\n", + " super(Net, self).__init__()\n", + " self.conv1 = nn.Conv2d(3, 6, 5)\n", + " self.pool = nn.MaxPool2d(2, 2)\n", + " self.conv2 = nn.Conv2d(6, 16, 5)\n", + " self.fc1 = nn.Linear(16 * 5 * 5, 120)\n", + " self.fc2 = nn.Linear(120, 84)\n", + " self.fc3 = nn.Linear(84, 10)\n", + "\n", + " def forward(self, x):\n", + " x = self.pool(F.relu(self.conv1(x)))\n", + " x = self.pool(F.relu(self.conv2(x)))\n", + " x = x.view(-1, 16 * 5 * 5)\n", + " x = F.relu(self.fc1(x))\n", + " x = F.relu(self.fc2(x))\n", + " x = self.fc3(x)\n", + " return x\n", + "\n", + "\n", + "# create a complete CNN\n", + "model = Net()\n", + "print(model)\n", + "# move tensors to GPU if CUDA is available\n", + "if train_on_gpu:\n", + " model.cuda()" + ] + }, + { + "cell_type": "markdown", + "id": "a2dc4974", + "metadata": {}, + "source": [ + "Loss function and training using SGD (Stochastic Gradient Descent) optimizer" + ] + }, + { + "cell_type": "code", + "execution_count": 16, + "id": "4b53f229", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Epoch: 0 \tTraining Loss: 42.825791 \tValidation Loss: 38.047178\n", + "Validation loss decreased (inf --> 38.047178). Saving model ...\n", + "Epoch: 1 \tTraining Loss: 34.432099 \tValidation Loss: 32.259117\n", + "Validation loss decreased (38.047178 --> 32.259117). Saving model ...\n", + "Epoch: 2 \tTraining Loss: 30.593193 \tValidation Loss: 29.343884\n", + "Validation loss decreased (32.259117 --> 29.343884). Saving model ...\n", + "Epoch: 3 \tTraining Loss: 28.517643 \tValidation Loss: 28.747610\n", + "Validation loss decreased (29.343884 --> 28.747610). Saving model ...\n", + "Epoch: 4 \tTraining Loss: 27.061891 \tValidation Loss: 26.789136\n", + "Validation loss decreased (28.747610 --> 26.789136). Saving model ...\n", + "Epoch: 5 \tTraining Loss: 25.740426 \tValidation Loss: 25.652807\n", + "Validation loss decreased (26.789136 --> 25.652807). Saving model ...\n", + "Epoch: 6 \tTraining Loss: 24.557613 \tValidation Loss: 24.589273\n", + "Validation loss decreased (25.652807 --> 24.589273). Saving model ...\n", + "Epoch: 7 \tTraining Loss: 23.515031 \tValidation Loss: 25.103045\n", + "Epoch: 8 \tTraining Loss: 22.581234 \tValidation Loss: 24.104360\n", + "Validation loss decreased (24.589273 --> 24.104360). Saving model ...\n", + "Epoch: 9 \tTraining Loss: 21.738190 \tValidation Loss: 23.372788\n", + "Validation loss decreased (24.104360 --> 23.372788). Saving model ...\n", + "Epoch: 10 \tTraining Loss: 20.909772 \tValidation Loss: 23.101869\n", + "Validation loss decreased (23.372788 --> 23.101869). Saving model ...\n", + "Epoch: 11 \tTraining Loss: 20.140882 \tValidation Loss: 22.718813\n", + "Validation loss decreased (23.101869 --> 22.718813). Saving model ...\n", + "Epoch: 12 \tTraining Loss: 19.447754 \tValidation Loss: 22.743659\n", + "Epoch: 13 \tTraining Loss: 18.741209 \tValidation Loss: 21.960046\n", + "Validation loss decreased (22.718813 --> 21.960046). Saving model ...\n", + "Epoch: 14 \tTraining Loss: 18.086207 \tValidation Loss: 23.175453\n", + "Epoch: 15 \tTraining Loss: 17.524023 \tValidation Loss: 22.036695\n", + "Epoch: 16 \tTraining Loss: 16.883423 \tValidation Loss: 21.853538\n", + "Validation loss decreased (21.960046 --> 21.853538). Saving model ...\n", + "Epoch: 17 \tTraining Loss: 16.315123 \tValidation Loss: 22.812885\n", + "Epoch: 18 \tTraining Loss: 15.772240 \tValidation Loss: 22.325363\n", + "Epoch: 19 \tTraining Loss: 15.269639 \tValidation Loss: 22.520727\n", + "Epoch: 20 \tTraining Loss: 14.745204 \tValidation Loss: 22.754284\n", + "Epoch: 21 \tTraining Loss: 14.261328 \tValidation Loss: 22.611392\n", + "Epoch: 22 \tTraining Loss: 13.771852 \tValidation Loss: 24.175723\n", + "Epoch: 23 \tTraining Loss: 13.320821 \tValidation Loss: 23.895067\n", + "Epoch: 24 \tTraining Loss: 12.871154 \tValidation Loss: 24.741432\n", + "Epoch: 25 \tTraining Loss: 12.380433 \tValidation Loss: 24.762289\n", + "Epoch: 26 \tTraining Loss: 11.955164 \tValidation Loss: 24.945322\n", + "Epoch: 27 \tTraining Loss: 11.516984 \tValidation Loss: 26.506488\n", + "Epoch: 28 \tTraining Loss: 11.121875 \tValidation Loss: 26.109028\n", + "Epoch: 29 \tTraining Loss: 10.736281 \tValidation Loss: 26.803389\n" + ] + } + ], + "source": [ + "import torch.optim as optim\n", + "\n", + "criterion = nn.CrossEntropyLoss() # specify loss function\n", + "optimizer = optim.SGD(model.parameters(), lr=0.01) # specify optimizer\n", + "\n", + "n_epochs = 30 # number of epochs to train the model\n", + "train_loss_list = [] # list to store loss to visualize\n", + "valid_loss_min = np.Inf # track change in validation loss\n", + "\n", + "for epoch in range(n_epochs):\n", + " # Keep track of training and validation loss\n", + " train_loss = 0.0\n", + " valid_loss = 0.0\n", + "\n", + " # Train the model\n", + " model.train()\n", + " for data, target in train_loader:\n", + " # Move tensors to GPU if CUDA is available\n", + " if train_on_gpu:\n", + " data, target = data.cuda(), target.cuda()\n", + " # Clear the gradients of all optimized variables\n", + " optimizer.zero_grad()\n", + " # Forward pass: compute predicted outputs by passing inputs to the model\n", + " output = model(data)\n", + " # Calculate the batch loss\n", + " loss = criterion(output, target)\n", + " # Backward pass: compute gradient of the loss with respect to model parameters\n", + " loss.backward()\n", + " # Perform a single optimization step (parameter update)\n", + " optimizer.step()\n", + " # Update training loss\n", + " train_loss += loss.item() * data.size(0)\n", + "\n", + " # Validate the model\n", + " model.eval()\n", + " for data, target in valid_loader:\n", + " # Move tensors to GPU if CUDA is available\n", + " if train_on_gpu:\n", + " data, target = data.cuda(), target.cuda()\n", + " # Forward pass: compute predicted outputs by passing inputs to the model\n", + " output = model(data)\n", + " # Calculate the batch loss\n", + " loss = criterion(output, target)\n", + " # Update average validation loss\n", + " valid_loss += loss.item() * data.size(0)\n", + "\n", + " # Calculate average losses\n", + " train_loss = train_loss / len(train_loader)\n", + " valid_loss = valid_loss / len(valid_loader)\n", + " train_loss_list.append(train_loss)\n", + "\n", + " # Print training/validation statistics\n", + " print(\n", + " \"Epoch: {} \\tTraining Loss: {:.6f} \\tValidation Loss: {:.6f}\".format(\n", + " epoch, train_loss, valid_loss\n", + " )\n", + " )\n", + "\n", + " # Save model if validation loss has decreased\n", + " if valid_loss <= valid_loss_min:\n", + " print(\n", + " \"Validation loss decreased ({:.6f} --> {:.6f}). Saving model ...\".format(\n", + " valid_loss_min, valid_loss\n", + " )\n", + " )\n", + " torch.save(model.state_dict(), \"model_cifar.pt\")\n", + " valid_loss_min = valid_loss" + ] + }, + { + "cell_type": "markdown", + "id": "13e1df74", + "metadata": {}, + "source": [ + "Does overfit occur? If so, do an early stopping." + ] + }, + { + "cell_type": "code", + "execution_count": 17, + "id": "d39df818", + "metadata": {}, + "outputs": [ + { + "data": { + "image/png": "iVBORw0KGgoAAAANSUhEUgAAAjQAAAHHCAYAAACoZcIpAAAAOXRFWHRTb2Z0d2FyZQBNYXRwbG90bGliIHZlcnNpb24zLjguMCwgaHR0cHM6Ly9tYXRwbG90bGliLm9yZy81sbWrAAAACXBIWXMAAA9hAAAPYQGoP6dpAABS20lEQVR4nO3dd1hTd98G8DthhA2yQTYoqAgqLtyrKlon1qodWlttHX2qtcsutePRtu9Tuxy1Qzu0Vq246qgTF+6FiiiIArJBwg6QnPcPJDVxY8hJ4P5cV66ac05Ovjmkcnt+SyIIggAiIiIiIyYVuwAiIiKix8VAQ0REREaPgYaIiIiMHgMNERERGT0GGiIiIjJ6DDRERERk9BhoiIiIyOgx0BAREZHRY6AhIiIio8dAQ2QkvvjiCwQEBMDExARt2rQRu5xGY/v27WjTpg0sLCwgkUhQWFgodkl3kEgkmDt37iO/7tq1a5BIJFixYoXOayLSNwYaojpasWIFJBKJ+mFhYYHmzZtj+vTpyM7O1ul7/fPPP3jrrbfQtWtXLF++HP/97391en66u/z8fIwePRqWlpZYtGgRfvvtN1hbW9/12Nu/DwcPHrxjvyAI8Pb2hkQiwZNPPlnfpevcp59+iqFDh8LNza3OAYqoPpmKXQCRsfvoo4/g7++PiooKHDx4EEuWLMHWrVtx/vx5WFlZ6eQ99uzZA6lUip9++gnm5uY6OSc92PHjx1FcXIyPP/4Y/fr1e6jXWFhYYNWqVejWrZvG9tjYWKSnp0Mmk9VHqfXu/fffh7u7O9q2bYsdO3aIXQ7RHXiHhugxRUVF4dlnn8VLL72EFStWYMaMGUhJScHGjRsf+9xlZWUAgJycHFhaWuoszAiCgPLycp2cqyHLyckBADg4ODz0awYNGoS1a9eiurpaY/uqVasQEREBd3d3XZaoNykpKcjMzMTvv/8udilEd8VAQ6Rjffr0AVDzC6DW77//joiICFhaWsLR0RFjxoxBWlqaxut69eqF0NBQnDx5Ej169ICVlRXeffddSCQSLF++HKWlpeomjdo+D9XV1fj4448RGBgImUwGPz8/vPvuu1AoFBrn9vPzw5NPPokdO3agffv2sLS0xPfff499+/ZBIpFgzZo1mDdvHpo2bQpbW1uMGjUKcrkcCoUCM2bMgKurK2xsbPDCCy/cce7ly5ejT58+cHV1hUwmQ8uWLbFkyZI7rkttDQcPHkTHjh1hYWGBgIAA/Prrr3ccW1hYiJkzZ8LPzw8ymQxeXl54/vnnkZeXpz5GoVBgzpw5CAoKgkwmg7e3N95666076ruXtWvXqn8mzs7OePbZZ3Hjxg2Nn8f48eMBAB06dIBEIsGECRMeeN6xY8ciPz8fO3fuVG+rrKzEunXrMG7cuLu+prS0FLNmzYK3tzdkMhmCg4Pxf//3fxAEQeM4hUKBmTNnwsXFBba2thg6dCjS09Pves4bN25g4sSJcHNzg0wmQ6tWrfDzzz8/sP578fPzq/NrifSBTU5EOpacnAwAcHJyAlDT9+CDDz7A6NGj8dJLLyE3NxfffvstevTogdOnT2v86z8/Px9RUVEYM2YMnn32Wbi5uaF9+/ZYtmwZjh07hh9//BEA0KVLFwDASy+9hF9++QWjRo3CrFmzcPToUcyfPx8JCQmIiYnRqCsxMRFjx47Fyy+/jEmTJiE4OFi9b/78+bC0tMQ777yDpKQkfPvttzAzM4NUKsXNmzcxd+5cHDlyBCtWrIC/vz8+/PBD9WuXLFmCVq1aYejQoTA1NcXmzZsxdepUqFQqTJs2TaOGpKQkjBo1Ci+++CLGjx+Pn3/+GRMmTEBERARatWoFACgpKUH37t2RkJCAiRMnol27dsjLy8OmTZuQnp4OZ2dnqFQqDB06FAcPHsTkyZPRokULxMfHY+HChbh8+TI2bNhw35/RihUr8MILL6BDhw6YP38+srOz8fXXX+PQoUPqn8l7772H4OBgLFu2TN2sGBgY+MCfv5+fHyIjI/HHH38gKioKALBt2zbI5XKMGTMG33zzjcbxgiBg6NCh2Lt3L1588UW0adMGO3bswJtvvokbN25g4cKF6mNfeukl/P777xg3bhy6dOmCPXv2YPDgwXfUkJ2djc6dO0MikWD69OlwcXHBtm3b8OKLL6KoqAgzZsx44OcgMjoCEdXJ8uXLBQDCrl27hNzcXCEtLU1YvXq14OTkJFhaWgrp6enCtWvXBBMTE+HTTz/VeG18fLxgamqqsb1nz54CAGHp0qV3vNf48eMFa2trjW1nzpwRAAgvvfSSxvY33nhDACDs2bNHvc3X11cAIGzfvl3j2L179woAhNDQUKGyslK9fezYsYJEIhGioqI0jo+MjBR8fX01tpWVld1R74ABA4SAgACNbbU17N+/X70tJydHkMlkwqxZs9TbPvzwQwGAsH79+jvOq1KpBEEQhN9++02QSqXCgQMHNPYvXbpUACAcOnTojtfWqqysFFxdXYXQ0FChvLxcvX3Lli0CAOHDDz9Ub6v9GR8/fvye57vbsd99951ga2urvjZPPfWU0Lt3b/V1GDx4sPp1GzZsEAAIn3zyicb5Ro0aJUgkEiEpKUkQhH9/3lOnTtU4bty4cQIAYc6cOeptL774ouDh4SHk5eVpHDtmzBjB3t5eXVdKSooAQFi+fPkDP1+t3NzcO96PyBCwyYnoMfXr1w8uLi7w9vbGmDFjYGNjg5iYGDRt2hTr16+HSqXC6NGjkZeXp364u7ujWbNm2Lt3r8a5ZDIZXnjhhYd6361btwIAXn/9dY3ts2bNAgD8/fffGtv9/f0xYMCAu57r+eefh5mZmfp5p06dIAgCJk6cqHFcp06dkJaWptE/xNLSUv1nuVyOvLw89OzZE1evXoVcLtd4fcuWLdG9e3f1cxcXFwQHB+Pq1avqbX/99RfCw8MxYsSIO+qUSCQAapqLWrRogZCQEI3rWtvcp31db3fixAnk5ORg6tSpsLCwUG8fPHgwQkJC7rhudTF69GiUl5djy5YtKC4uxpYtW+7Z3LR161aYmJjgP//5j8b2WbNmQRAEbNu2TX0cgDuO077bIggC/vrrLwwZMgSCIGhcnwEDBkAul+PUqVOP/RmJDA2bnIge06JFi9C8eXOYmprCzc0NwcHBkEpr/q1w5coVCIKAZs2a3fW1t4cIAGjatOlDd/y9fv06pFIpgoKCNLa7u7vDwcEB169f19ju7+9/z3P5+PhoPLe3twcAeHt737FdpVJBLperm9QOHTqEOXPmIC4uTt2JuZZcLlef627vAwBNmjTBzZs31c+Tk5MRHR19z1qBmuuakJAAFxeXu+6v7cx7N7XX5fYmt1ohISF3HXL9qFxcXNCvXz+sWrUKZWVlUCqVGDVq1D3r8fT0hK2trcb2Fi1aaNRb+/PWbvbS/hy5ubkoLCzEsmXLsGzZsru+5/2uD5GxYqAhekwdO3ZE+/bt77pPpVJBIpFg27ZtMDExuWO/jY2NxvPb73Y8rNq7Fg9yv3Pfrbb7bRdudVZNTk5G3759ERISgi+//BLe3t4wNzfH1q1bsXDhQqhUqkc638NSqVRo3bo1vvzyy7vu1w5iYhg3bhwmTZqErKwsREVFPdJIqcdRe82fffZZdadmbWFhYXqphUifGGiI6lFgYCAEQYC/vz+aN2+u03P7+vpCpVLhypUr6n/NAzUdQgsLC+Hr66vT97ubzZs3Q6FQYNOmTRp3X+7X5PMggYGBOH/+/AOPOXv2LPr27fvQga5W7XVJTExUN1HVSkxM1Nl1GzFiBF5++WUcOXIEf/75533r2bVrF4qLizXu0ly6dEmj3tqfd3JyssZdmcTERI3z1Y6AUiqVDz13DlFDwD40RPVo5MiRMDExwbx58+64CyEIAvLz8+t87kGDBgEAvvrqK43ttXct7jb6Rddq77jc/tnkcjmWL19e53NGR0fj7Nmzd4zSuv19Ro8ejRs3buCHH36445jy8nKUlpbe8/zt27eHq6srli5dqjHEe9u2bUhISNDZdbOxscGSJUswd+5cDBky5J7HDRo0CEqlEt99953G9oULF0IikahHStX+V3uUlPbP38TEBNHR0fjrr7/uGgxzc3Pr8nGIDB7v0BDVo8DAQHzyySeYPXs2rl27huHDh8PW1hYpKSmIiYnB5MmT8cYbb9Tp3OHh4Rg/fjyWLVuGwsJC9OzZE8eOHcMvv/yC4cOHo3fv3jr+NHfq378/zM3NMWTIELz88ssoKSnBDz/8AFdXV2RmZtbpnG+++SbWrVuHp556ChMnTkRERAQKCgqwadMmLF26FOHh4XjuueewZs0avPLKK9i7dy+6du0KpVKJS5cuYc2aNer5du7GzMwMn332GV544QX07NkTY8eOVQ/b9vPzw8yZMx/nkmi4V5PP7YYMGYLevXvjvffew7Vr1xAeHo5//vkHGzduxIwZM9R9Ztq0aYOxY8di8eLFkMvl6NKlC3bv3o2kpKQ7zrlgwQLs3bsXnTp1wqRJk9CyZUsUFBTg1KlT2LVrFwoKCh75s/z222+4fv26up/U/v378cknnwAAnnvuOb3cESS6HwYaonr2zjvvoHnz5li4cCHmzZsHoKaPR//+/TF06NDHOvePP/6IgIAArFixAjExMXB3d8fs2bMxZ84cXZT+QMHBwVi3bh3ef/99vPHGG3B3d8eUKVPg4uJyxwiph2VjY4MDBw5gzpw5iImJwS+//AJXV1f07dsXXl5eAACpVIoNGzZg4cKF+PXXXxETEwMrKysEBATgtddee2Dz3oQJE2BlZYUFCxbg7bffhrW1NUaMGIHPPvtMb31dakmlUmzatAkffvgh/vzzTyxfvhx+fn744osv1CPWav38889wcXHBypUrsWHDBvTp0wd///33HX2G3NzccOzYMXz00UdYv349Fi9eDCcnJ7Rq1QqfffZZner86aefEBsbq36+d+9eddNit27dGGhIdBLhUXvjERERERkY9qEhIiIio8dAQ0REREaPgYaIiIiMHgMNERERGT0GGiIiIjJ6DDRERERk9Br8PDQqlQoZGRmwtbV95CnSiYiISByCIKC4uBienp7qBX/vp8EHmoyMDINYqI6IiIgeXVpamnpSzftp8IGmdrG3tLQ02NnZiVwNERERPYyioiJ4e3trLNp6Pw0+0NQ2M9nZ2THQEBERGZmH7S7CTsFERERk9BhoiIiIyOgx0BAREZHRY6AhIiIio8dAQ0REREaPgYaIiIiMHgMNERERGT0GGiIiIjJ6DDRERERk9BhoiIiIyOgx0BAREZHRY6AhIiIio8dAU0dKlYCruSXIK1GIXQoREVGjx0BTR6/+cQp9/heLzWczxC6FiIio0WOgqaMgFxsAwKXMYpErISIiIgaaOgp2twMAXMpmoCEiIhIbA00dBbvbAgAuZxVDpRJEroaIiKhxY6CpIz8nK5ibSlFepURqQZnY5RARETVqDDR1ZGoiRXO3W/1ostjsREREJCYGmscQ7FbTjyaRgYaIiEhUDDSPIeRWP5rE7CKRKyEiImrcGGgeQ4hHTaDh0G0iIiJxMdA8htqRTtfyS1FRpRS5GiIiosaLgeYxuNjI4GhtDpUAXMkuEbscIiKiRouB5jFIJBIEu9XcpUnIYj8aIiIisTDQPKbafjQc6URERCQeBprHpB7pxEBDREQkGgaax6Re04mBhoiISDQMNI+puZsNJBIgr0SBvBKF2OUQERE1Sgw0j8nK3BS+jlYA2OxEREQkFgYaHaidj4bNTkREROJgoNEBdT+aTA7dJiIiEgMDjQ60UK/pxDs0REREYmCg0YHaJqfL2cVQqgSRqyEiImp8GGh0wNfJGhZmUlRUqZBaUCZ2OURERI0OA40OmEglaO5Wu/I2+9EQERHpGwONjtSu6cSRTkRERPrHQKMjwVwCgYiISDQMNDrSwqN2CQQ2OREREembwQSaBQsWQCKRYMaMGeptFRUVmDZtGpycnGBjY4Po6GhkZ2eLV+R91N6huV5QhrLKapGrISIialwMItAcP34c33//PcLCwjS2z5w5E5s3b8batWsRGxuLjIwMjBw5UqQq78/ZRgZnG3MIAnAlu0TscoiIiBoV0QNNSUkJnnnmGfzwww9o0qSJertcLsdPP/2EL7/8En369EFERASWL1+Ow4cP48iRIyJWfG/sR0NERCQO0QPNtGnTMHjwYPTr109j+8mTJ1FVVaWxPSQkBD4+PoiLi9N3mQ8l5NYSCAnsR0NERKRXpmK++erVq3Hq1CkcP378jn1ZWVkwNzeHg4ODxnY3NzdkZWXd85wKhQIKhUL9vKhIf+GCd2iIiIjEIdodmrS0NLz22mtYuXIlLCwsdHbe+fPnw97eXv3w9vbW2bkfJOS2VbcFgUsgEBER6YtogebkyZPIyclBu3btYGpqClNTU8TGxuKbb76Bqakp3NzcUFlZicLCQo3XZWdnw93d/Z7nnT17NuRyufqRlpZWz5/kX81cbSGVAAWllcgtUTz4BURERKQTojU59e3bF/Hx8RrbXnjhBYSEhODtt9+Gt7c3zMzMsHv3bkRHRwMAEhMTkZqaisjIyHueVyaTQSaT1Wvt92JpbgI/J2tczStFYlYxXG11d+eJiIiI7k20QGNra4vQ0FCNbdbW1nByclJvf/HFF/H666/D0dERdnZ2ePXVVxEZGYnOnTuLUfJDCXa3VQea7s1cxC6HiIioURC1U/CDLFy4EFKpFNHR0VAoFBgwYAAWL14sdln3Fexui23ns7imExERkR4ZVKDZt2+fxnMLCwssWrQIixYtEqegOqgdus0lEIiIiPRH9HloGprakU5XskugVHGkExERkT4w0OiYj6MVLM1MoKhW4Vp+qdjlEBERNQoMNDomlUrQvHY+mkz2oyEiItIHBpp6EOJWO2Mw+9EQERHpAwNNPQi+bcZgIiIiqn8MNPWgtmNwYjYDDRERkT4w0NSD2js01/PLUKqoFrkaIiKiho+Bph442cjgYluz/MJl3qUhIiKqdww09UTd7MR+NERERPWOgaaehLBjMBERkd4w0NSTYC6BQEREpDcMNPXk9iYnQeASCERERPWJgaaeBLnaQCoBbpZVIbdYIXY5REREDRoDTT2xMDOBv7M1ACCB/WiIiIjqFQNNPQq51Y+GSyAQERHVLwaaesQlEIiIiPSDgaYehXDVbSIiIr1goKlHtU1OSbklqFaqRK6GiIio4WKgqUdeTSxhZW6CymoVruWXil0OERFRg8VAU4+kUgn70RAREekBA009Yz8aIiKi+sdAU8+C3XiHhoiIqL4x0NSz2jWdErM5Fw0REVF9YaCpZ7VNTmkF5ShRVItcDRERUcPEQFPPmlibw81OBqBmoUoiIiLSPQYaPVA3OzHQEBER1QsGGj1ocavZiWs6ERER1Q8GGj2onYuGq24TERHVDwYaPQhW36EphiAIIldDRETU8DDQ6EGQqw1MpBLIy6uQXaQQuxwiIqIGh4FGD2SmJghwtgYAJLAfDRERkc4x0OjJ7c1OREREpFsMNHoSwkBDRERUbxho9CTk1lw0XNOJiIhI9xho9KS2ySkppxhVSpXI1RARETUsDDR64tXEEjYyU1QpBaTklYpdDhERUYPCQKMnEokEzd1sALDZiYiISNcYaPQoxONWP5pMDt0mIiLSJQYaPeJIJyIiovrBQKNHwW41gYZNTkRERLrFQKNHtUO3bxSWo6iiSuRqiIiIGg4GGj2ytzKDh70FAOAy79IQERHpjKiBZsmSJQgLC4OdnR3s7OwQGRmJbdu2qff36tULEolE4/HKK6+IWPHjq52Phs1OREREumMq5pt7eXlhwYIFaNasGQRBwC+//IJhw4bh9OnTaNWqFQBg0qRJ+Oijj9SvsbKyEqtcnQhxt8O+xFx2DCYiItIhUQPNkCFDNJ5/+umnWLJkCY4cOaIONFZWVnB3dxejvHoRor5Dw6HbREREumIwfWiUSiVWr16N0tJSREZGqrevXLkSzs7OCA0NxezZs1FWVnbf8ygUChQVFWk8DMntTU6CIIhcDRERUcMg6h0aAIiPj0dkZCQqKipgY2ODmJgYtGzZEgAwbtw4+Pr6wtPTE+fOncPbb7+NxMRErF+//p7nmz9/PubNm6ev8h9ZoIsNTKUSFFdUI1NeAU8HS7FLIiIiMnoSQeTbBJWVlUhNTYVcLse6devw448/IjY2Vh1qbrdnzx707dsXSUlJCAwMvOv5FAoFFAqF+nlRURG8vb0hl8thZ2dXb5/jUQxYuB+J2cVYPqEDeoe4il0OERGRwSkqKoK9vf1D//4WvcnJ3NwcQUFBiIiIwPz58xEeHo6vv/76rsd26tQJAJCUlHTP88lkMvWoqdqHoaltdkpgPxoiIiKdED3QaFOpVBp3WG535swZAICHh4ceK9K9YC6BQEREpFOi9qGZPXs2oqKi4OPjg+LiYqxatQr79u3Djh07kJycjFWrVmHQoEFwcnLCuXPnMHPmTPTo0QNhYWFilv3YWngw0BAREemSqIEmJycHzz//PDIzM2Fvb4+wsDDs2LEDTzzxBNLS0rBr1y589dVXKC0thbe3N6Kjo/H++++LWbJOBN9aAiEppwSlimpYy0Tvm01ERGTURP1N+tNPP91zn7e3N2JjY/VYjf542lvAz8kK1/LL8Hd8Jka39xa7JCIiIqNmcH1oGgOJRIKnboWYNcfTRK6GiIjI+DHQiGRUhBekEuDE9ZtIyikRuxwiIiKjxkAjEjc7C/QOrpmDZu0J3qUhIiJ6HAw0IhrdoabZ6a9T6ahSqkSuhoiIyHgx0IioT4grnG1kyCupxJ5LOWKXQ0REZLQYaERkZiJFdLumANg5mIiI6HEw0IisdrTT3sQcZBdViFwNERGRcWKgEVmQqw3a+zaBSgDWnUwXuxwiIiKjxEBjAGo7B685kQaVStTFz4mIiIwSA40BGNzaA9bmJrieX4ajKQVil0NERGR0GGgMgLXMFEPCPQHU3KUhIiKiR8NAYyBqm522xmdCXl4lcjVERETGhYHGQLT1dkBzNxsoqlXYdDZD7HKIiIiMCgONgZBIJOpVtzknDRER0aNhoDEgI9t5wcxEgvgbclzMKBK7HCIiIqPBQGNAHK3N8URLNwDsHExERPQoGGgMTG2zU8zpG6ioUopcDRERkXFgoDEw3Zu5wNPeAvLyKvxzMVvscoiIiIwCA42BMZFKMCrCCwA7BxMRET0sBhoDVLtg5cGkPKQVlIlcDRERkeFjoDFA3o5W6BrkBABYywUriYiIHoiBxkDVdg5edyINSi5YSUREdF8MNAZqQCt32FuaIUNegYNJeWKXQ0REZNAYaAyUhZkJhre5tWAlOwcTERHdFwONAatdsPKfi1koKK0UuRoiIiLDxUBjwFp52iO0qR2qlAJiTt8QuxwiIiKDxUBj4J6+bcFKQWDnYCIiorthoDFwQ9s0hcxUisTsYpxNl4tdDhERkUFioDFw9pZmiAp1BwD8yc7BREREd8VAYwRqOwdvPpuBsspqkashIiIyPAw0RqCzvxN8HK1QoqjG1vgsscshIiIyOAw0RkAqlWB0ey5YSUREdC8MNEZiVIQ3pBLg2LUCXM0tEbscIiIig8JAYyTc7S3Qs7kLAGDNCS5YSUREdDsGGiPy9K3OwX+dSke1UiVyNURERIaDgcaI9Alxg5O1OXKLFdibmCt2OURERAaDgcaImJtKER1R0zmYc9IQERH9i4HGyIy+tRTC3sQc5BRViFwNERGRYWCgMTJBrjaI8G0CpUrA70eui10OERGRQWCgMUITuvgBABbvS8a59EJRayEiIjIEDDRG6MkwD0SFuqNaJeC11WdQquByCERE1LiJGmiWLFmCsLAw2NnZwc7ODpGRkdi2bZt6f0VFBaZNmwYnJyfY2NggOjoa2dnZIlZsGCQSCeaPbA0Pewuk5JXio80XxS6JiIhIVKIGGi8vLyxYsAAnT57EiRMn0KdPHwwbNgwXLlwAAMycORObN2/G2rVrERsbi4yMDIwcOVLMkg2Gg5U5Fj7dBhIJ8OeJNGyLzxS7JCIiItFIBEEQxC7ido6Ojvjiiy8watQouLi4YNWqVRg1ahQA4NKlS2jRogXi4uLQuXPnhzpfUVER7O3tIZfLYWdnV5+li+Lz7ZeweF8y7C3NsO217vB0sBS7JCIiosf2qL+/DaYPjVKpxOrVq1FaWorIyEicPHkSVVVV6Nevn/qYkJAQ+Pj4IC4u7p7nUSgUKCoq0ng0ZDOfaI5wL3vIy6vw+pozUKoMKp8SERHpheiBJj4+HjY2NpDJZHjllVcQExODli1bIisrC+bm5nBwcNA43s3NDVlZWfc83/z582Fvb69+eHt71/MnEJeZiRRfj2kLK3MTHLlagKWxyWKXREREpHeiB5rg4GCcOXMGR48exZQpUzB+/HhcvFj3Tq6zZ8+GXC5XP9LSGv6Mun7O1pg7tBUAYOHOyzibVihuQURERHomeqAxNzdHUFAQIiIiMH/+fISHh+Prr7+Gu7s7KisrUVhYqHF8dnY23N3d73k+mUymHjVV+2gMnorwwuAwj1tDuU9zKDcRETUqogcabSqVCgqFAhERETAzM8Pu3bvV+xITE5GamorIyEgRKzRMEokE/x3eGp72FriWX4a5my6IXRIREZHemIr55rNnz0ZUVBR8fHxQXFyMVatWYd++fdixYwfs7e3x4osv4vXXX4ejoyPs7Ozw6quvIjIy8qFHODU29lZmWPh0G4z94QjWnkxHr2BXDA7zELssIiKieidqoMnJycHzzz+PzMxM2NvbIywsDDt27MATTzwBAFi4cCGkUimio6OhUCgwYMAALF68WMySDV6nACdM7RWE7/YmYfb6c2jj44CmHMpNREQNnMHNQ6NrDX0emrupUqrw1NI4nEkrREd/R/wxqTNMpBKxyyIiInpoRjsPDelOzVDuNrA2N8GxlAIs2ZckdklERET1ioGmgfJ1ssa8YaEAgIW7ruB06k2RKyIiIqo/DDQNWHS7phgS7gnlrVW5SziUm4iIGigGmgZMIpHgk+GhaOpgidSCMszZyKHcRETUMDHQNHD2lmb4akwbSCXAX6fSsflshtglERER6RwDTSPQwc8R03sHAQDejYlH+s0ykSsiIiLSLQaaRuI/fZuhrY8DiiuqMfNPrspNREQNCwNNI2FqIsXXT7eFjcwUx6/dxKK9HMpNREQNBwNNI+LjZIWPh9esyv3VrsvYeOaGyBURERHpBgNNIzOirRfGdfKBSgBm/nkG606mi10SERHRY2OgaYQ+GRaKsR1rQs2b687iz+OpYpdERET0WBhoGiGpVIJPh4fi+UhfCALw9l/x+P3IdbHLIiIiqjMGmkZKKpVg3tBWmNjVHwDw/obz+OXwNXGLIiIiqiMGmkZMIpHggydb4OUeAQCAOZsu4McDV0WuioiI6NEx0DRyEokE70SFYFrvQADAJ38nYGlssshVERERPZo6BZq0tDSkp/87OubYsWOYMWMGli1bprPCSH8kEgne6B+M1/o2AwAs2HYJ3+6+InJVRERED69OgWbcuHHYu3cvACArKwtPPPEEjh07hvfeew8fffSRTgsk/ZBIJJj5RHPMeqI5AOB/Oy9j4c7LEATOKExERIavToHm/Pnz6NixIwBgzZo1CA0NxeHDh7Fy5UqsWLFCl/WRnr3atxneHhgCAPh69xX83z+JDDVERGTw6hRoqqqqIJPJAAC7du3C0KFDAQAhISHIzMzUXXUkiim9AvH+4BYAgEV7k7Fg2yWGGiIiMmh1CjStWrXC0qVLceDAAezcuRMDBw4EAGRkZMDJyUmnBZI4XuoegLlDWgIAvt9/FR9tuchQQ0REBqtOgeazzz7D999/j169emHs2LEIDw8HAGzatEndFEXGb0JXf3wyPBQAsPzQNczZdAEqrtJNREQGSCLU8Z/dSqUSRUVFaNKkiXrbtWvXYGVlBVdXV50V+LiKiopgb28PuVwOOzs7scsxSquPpWJ2TDwEARjb0QefDg+FVCoRuywiImrAHvX3d53u0JSXl0OhUKjDzPXr1/HVV18hMTHRoMIM6caYjj74YlQ4JBLgj2OpeGf9OSh5p4aIiAxInQLNsGHD8OuvvwIACgsL0alTJ/zvf//D8OHDsWTJEp0WSIZhVIQXFo5uA6kEWHMiHTP+PANFtVLssoiIiADUMdCcOnUK3bt3BwCsW7cObm5uuH79On799Vd88803Oi2QDMfwtk3xzdi2MJVKsPlsBl5YfhxFFVVil0VERFS3QFNWVgZbW1sAwD///IORI0dCKpWic+fOuH6dqzY3ZE+GeeLnCR1gbW6Cw8n5GL00DlnyCrHLIiKiRq5OgSYoKAgbNmxAWloaduzYgf79+wMAcnJy2PG2EejR3AV/vhwJZxsZLmUVY+TiQ7iSXSx2WURE1IjVKdB8+OGHeOONN+Dn54eOHTsiMjISQM3dmrZt2+q0QDJMoU3tETO1CwKcrZEhr0D0ksM4llIgdllERNRI1XnYdlZWFjIzMxEeHg6ptCYXHTt2DHZ2dggJCdFpkY+Dw7brV0FpJV765ThOpRbC3FSKr59ug6jWHmKXRURERu5Rf3/XOdDUql1128vL63FOU28YaOpfeaUSr/5xGrsSsiGRAHOebIkJXf3FLouIiIyYXuahUalU+Oijj2Bvbw9fX1/4+vrCwcEBH3/8MVQqVV1OSUbM0twES59th2c6+UAQgLmbL2L+tgTOKkxERHpjWpcXvffee/jpp5+wYMECdO3aFQBw8OBBzJ07FxUVFfj00091WiQZPlMTKT4ZHgpPB0t8sSMR38deRba8Ap+PCoe5aZ1yMxER0UOrU5OTp6cnli5dql5lu9bGjRsxdepU3LhxQ2cFPi42Oenf2hNpeGd9PJQqAV2DnLD02QjYWpiJXRYRERkRvTQ5FRQU3LXjb0hICAoKONKlsXuqvTd+Gt8eVuYmOJSUj9HfH0F2EeeqISKi+lOnQBMeHo7vvvvuju3fffcdwsLCHrsoMn69gl3x5+RIONuYIyGzCCMXH0ZSDueqISKi+lGnJqfY2FgMHjwYPj4+6jlo4uLikJaWhq1bt6qXRTAEbHISV2p+GcYvP4aUvFLYW5rhp/Ht0d7PUeyyiIjIwOmlyalnz564fPkyRowYgcLCQhQWFmLkyJG4cOECfvvtt7qckhooHycr/DWlC9p4O0BeXoVnfjyK7eezxC6LiIgamMeeh+Z2Z8+eRbt27aBUGs4qzLxDYxhq5qo5hV0JOZBIgDf6B2Nqr0BIJBKxSyMiIgOklzs0RI+qZq6aCDzbuWaumi92JGLK76dQoqgWuzQiImoAGGhIb2rmqmmN/45oDTMTCbZfyMKIRYeQklcqdmlERGTkGGhI78Z18sHqyZFwtZXhSk4Jhn53ELsTssUui4iIjNgjzRQ8cuTI++4vLCx8pDefP38+1q9fj0uXLsHS0hJdunTBZ599huDgYPUxvXr1QmxsrMbrXn75ZSxduvSR3osMS4RvE2x5tRumrjyFE9dv4sVfTmBmv+Z4tU8QpFL2qyEiokfzSHdo7O3t7/vw9fXF888//9Dni42NxbRp03DkyBHs3LkTVVVV6N+/P0pLNZsgJk2ahMzMTPXj888/f5SyyUC52llg1aTOeK6zLwBg4a7LePn3kyiuqBK5MiIiMjY6HeX0uHJzc+Hq6orY2Fj06NEDQM0dmjZt2uCrr76q0zk5ysk4rDmRhvc3nEdltQoBLtZY9lx7BLnaiF0WERGJxKhHOcnlcgCAo6PmxGsrV66Es7MzQkNDMXv2bJSVlYlRHtWj0e29sfblSHjYW+BqbimGLzqEHRc4Xw0RET0cg7lDo1KpMHToUBQWFuLgwYPq7cuWLYOvry88PT1x7tw5vP322+jYsSPWr19/1/MoFAooFAr186KiInh7e/MOjZHIK1Fg6spTOJZSsybYf/oEYUa/5uxXQ0TUyDzqHRqDCTRTpkzBtm3bcPDgQXh5ed3zuD179qBv375ISkpCYGDgHfvnzp2LefPm3bGdgcZ4VClV+O/WBCw/dA0A0CfEFQufbgN7S67YTUTUWBhloJk+fTo2btyI/fv3w9/f/77HlpaWwsbGBtu3b8eAAQPu2M87NA3H+lPpmL0+HopqFfycrLDs+fZo7mYrdllERKQHRtWHRhAETJ8+HTExMdizZ88DwwwAnDlzBgDg4eFx1/0ymQx2dnYaDzJOI9t54a8pXdDUwRLX8sswfNEhbI3PFLssIiIyQKLeoZk6dSpWrVqFjRs3asw9Y29vD0tLSyQnJ2PVqlUYNGgQnJyccO7cOcycORNeXl53zE1zLxzlZPzySxR49Y/TOJycDwCY1N0fbwwIhszUROTKiIiovhhVk9O9FiZcvnw5JkyYgLS0NDz77LM4f/48SktL4e3tjREjRuD9999/6HDCQNMwVCtV+Gz7JfxwIAUA0MLDDl+PacMmKCKiBsqoAo0+MNA0LP9cyMI76+NRUFoJc1Mp3hkYggld/DgKioiogTGqPjREj6p/K3dsn9EdvYJdUFmtwkdbLmL88mPILqoQuzQiIhIRAw0ZHVdbCyyf0AEfD2sFmakUB67kYcBX+9lhmIioEWOgIaMkkUjwXKQf/v5Pd4Q2tUNhWRWmrjyFWWvOci0oIqJGiIGGjFqQqw3WT+mKab0DIZEAf51KR9TXB3D8WoHYpRERkR4x0JDRMzeV4s0BIfhzciSaOlgi/WY5nv4+Dl/suITKapXY5RERkR4w0FCD0dHfEdtmdMfIdk2hEoBFe5MRveQwknJKxC6NiIjqGQMNNSh2Fmb4cnQbLBrXDvaWZoi/IceT3x7Ab3HX0MBnKCAiatQYaKhBGhzmgR0zeqBbkDMqqlT4YOMFvLDiOHKKObybiKghYqChBsvd3gK/TuyID59sCXNTKfYl5mLgVwew4fQN3q0hImpgGGioQZNKJZjYzR+bp3dDiLstCkorMePPM3j+52O4nl8qdnlERKQjDDTUKAS722Lj9K54/YnmML81GV//hfuxeF8SqpQcCUVEZOwYaKjRkJma4D99m2H7a90RGeAERbUKn29PxJBvD+JU6k2xyyMiosfAQEONToCLDVZN6oQvRoXBwcoMl7KKEb3kMD7ceJ6zDBMRGSkGGmqUJBIJnmrvjd2v98TItk0hCMCvcdfR78tYbD+fyU7DRERGhoGGGjUnGxm+fLoNVr7UCX5OVsguUuCV309h0q8nkVFYLnZ5RET0kBhoiAB0DXLG9hk9ML13EEylEuxKyMYTX8bi54MpUKp4t4aIyNAx0BDdYmFmgjcGBGPra90R4dsEpZVKfLTlIkYsPoTzN+Ril0dERPfBQEOkpbmbLda+HIlPR4TC1sIU59LlGLboED79+yLKKqvFLo+IiO6CgYboLqRSCZ7p5Ivdr/fE4DAPKFUCfjiQgr7/i0XM6XSo2AxFRGRQJEIDH85RVFQEe3t7yOVy2NnZiV0OGam9l3Lw/obzuHGro3C4twM+fLIFInwdRa6MiKhhetTf3ww0RA+pokqJnw6mYPHeJJRWKgEAT4Z54J2oEHg1sRK5OiKihoWBRgsDDelaTnEF/rfjMtacTIMgAOamUkzq7o8pvYJgIzMVuzwiogaBgUYLAw3VlwsZcny85SKOXC0AALjYyvBm/2BER3jBRCoRuToiIuPGQKOFgYbqkyAI+OdiNv67NQHX88sAAC097PDBky0RGegkcnVERMaLgUYLAw3pg6JaiV8PX8c3e66guKJmaPeAVm54d1AL+DpZi1wdEZHxYaDRwkBD+pRfosBXu65g1bFUKFUCzEwkeKGrP6b3CYKdhZnY5RERGQ0GGi0MNCSGy9nF+OTvBOy/nAsAcLQ2x8wnmmNsB2+YmnD6JyKiB2Gg0cJAQ2Lam5iDT/9OQFJOCQAgyNUG7w4KQe9gV0gk7DhMRHQvDDRaGGhIbFVKFVYdTcVXuy7jZlkVAKBrkBPeG9QSLT35nSQiuhsGGi0MNGQo5OVVWLw3CcsPXUOlUgWJBBjVzgtvDAiGm52F2OURERkUBhotDDRkaNIKyvDZ9kvYci4TAGBpZoLJPQLwcs8AWJlzYj4iIoCB5g4MNGSoTqXexKd/J+Dk9ZsAAFdbGd7gxHxERAAYaO7AQEOGTBAEbDufhQXbLiG1oGZivhB3W7w3uAW6N3MRuToiIvEw0GhhoCFjoKhW4re46/hm9xUU3ZqYr1ewC94d1ALN3WxFro6ISP8YaLQw0JAxuVlaiW/2XMFvcddRrRIglQBPd/DB6080h4utTOzyiIj0hoFGCwMNGaOUvFJ8tu0Stl/IAgBYm5vg5Z6BmNjNnyt6E1GjwECjhYGGjNmxlAJ8+vdFnE2XA6iZcXhqr0A829kXFmYmIldHRFR/GGi0MNCQsVOpBGyJz8TCnZeRklcKoGZE1Kt9gvB0Bx+Ym3IpBSJqeBhotDDQUENRrVRh/akb+Hr3FdwoLAcAeDWxxGt9m2FE26ZcI4qIGhQGGi0MNNTQKKqV+PN4Gr7dk4TcYgUAIMDFGjP7Ncfg1h6Qcg4bImoAGGi0MNBQQ1VeqcRvR65hyb5k9RpRIe62mNU/GP1acPFLIjJuDDRaGGiooStRVOPngyn4Yf9VFCtq5rAJ93bAG/2bo1uQM4MNERmlR/39LWqj+/z589GhQwfY2trC1dUVw4cPR2JiosYxFRUVmDZtGpycnGBjY4Po6GhkZ2eLVDGR4bGRmeI/fZvhwNu9MbVXICzNTHA2rRDP/XQMY5YdwfFrBWKXSERU70QNNLGxsZg2bRqOHDmCnTt3oqqqCv3790dpaan6mJkzZ2Lz5s1Yu3YtYmNjkZGRgZEjR4pYNZFhcrAyx1sDQ7D/rd6Y2NUf5qZSHE0pwFNL4zD+52M4eZ3BhogaLoNqcsrNzYWrqytiY2PRo0cPyOVyuLi4YNWqVRg1ahQA4NKlS2jRogXi4uLQuXPnB56TTU7UWGXKy/HtniSsOZ6GalXN/+Yd/RzxSq8A9A5mHxsiMmxG1eSkTS6/NXmYoyMA4OTJk6iqqkK/fv3Ux4SEhMDHxwdxcXF3PYdCoUBRUZHGg6gx8rC3xH9HtMaeWb0wpoM3zE2kOHatABNXnEDU1wcQczodVUqV2GUSEemEwQQalUqFGTNmoGvXrggNDQUAZGVlwdzcHA4ODhrHurm5ISsr667nmT9/Puzt7dUPb2/v+i6dyKD5OFlhQXQYDrzdGy/3CICNzBSXsoox88+z6PXFPqw4lILySqXYZRIRPRaDCTTTpk3D+fPnsXr16sc6z+zZsyGXy9WPtLQ0HVVIZNzc7Cwwe1ALHHqnD94cEAxnG3PcKCzH3M0X0fWzPfh61xXcLK0Uu0wiojoxiFXupk+fji1btmD//v3w8vJSb3d3d0dlZSUKCws17tJkZ2fD3d39rueSyWSQybgqMdG92FuaYVrvILzYzR/rTqZj2f6rSC0ow8Jdl/H9/mSM6eCDl7r7w9PBUuxSiYgemqh3aARBwPTp0xETE4M9e/bA399fY39ERATMzMywe/du9bbExESkpqYiMjJS3+USNSgWZiZ4trMv9szqiW/HtkVLDzuUVSrx86EU9Ph8L2atOYsr2cVil0lE9FBEHeU0depUrFq1Chs3bkRwcLB6u729PSwta/51OGXKFGzduhUrVqyAnZ0dXn31VQDA4cOHH+o9OMqJ6OEIgoADV/KwZF8y4q7mq7f3a+GGKb0CEeHbRMTqiKixMaqZgu81bHT58uWYMGECgJqJ9WbNmoU//vgDCoUCAwYMwOLFi+/Z5KSNgYbo0Z1JK8TSfcnYcTELtX9DdPJ3xLTeQejejLMPE1H9M6pAow8MNER1l5xbgmWxV7H+dDqqlDV/VbRuao9pvQPRv6U7F8IkonrDQKOFgYbo8WXKy/HD/hT8cSwV5VU1Q7wDXawxpVcQhrXxhJmJwQyYJKIGgoFGCwMNke4UlFZixaEUrDh8DUUVNQthNnWwxOQeAXi6gzcszExErpCIGgoGGi0MNES6V1xRhZVHU/HjgRTklSgAAM425pjYzR/PdvaFnYWZyBUSkbFjoNHCQENUfyqqlFh7Ig1LY6/iRmE5AMDWwhTjI/3wQlc/ONlwTigiqhsGGi0MNET1r0qpwuazGVi8LxlJOSUAAAszKcZ08MHkHgGcpI+IHhkDjRYGGiL9UakE/HMxG4v3JeFces1is2YmEgwJ88TEbv4IbWovcoVEZCwYaLQw0BDpnyAIOJiUh8V7NSfp6+TviBe7+aNvCzeYcMg3Ed0HA40WBhoicZ1NK8RPB1OwNT4T1aqav258nazwQhc/PNXeG9Yyg1hSjogMDAONFgYaIsOQKS/HL4ev449jqZCXVwGo6UA8tqMPxnfxQ1P2syGi2zDQaGGgITIsZZXV+OtkOpYfuoareaUAABOpBAND3fFiN3+08+GaUUTEQHMHBhoiw6RSCdh3OQc/HUzBoaR/+9m09XHAi938MbCVO0w5AzFRo8VAo4WBhsjwJWQW4eeDKdh4JgOVShWAmhmIx3fxxdMdfGBvyYn6iBobBhotDDRExiO3WIHfj1zH70euI7+0EkDNfDaDQj0wqr0XOvs7cUFMokaCgUYLAw2R8amoUmLTmQz8fCgFl7KK1du9mlhiVIQXott5wdvRSsQKiai+MdBoYaAhMl6CIOBMWiHWnkzH5jMZKFZUq/dFBjjhqfZeiAr1gKU5F8UkamgYaLQw0BA1DOWVSvxzMQtrT6TjUHIeav/mspGZ4skwDzzV3gvtfJpAImGTFFFDwECjhYGGqOFJv1mG9aduYN3JdKQWlKm3B7hYq5uk3OwsRKyQiB4XA40WBhqihkulEnDsWgHWnkjH1vhMlFcpAQBSCdCjuQtGRXjhiZZukJmySYrI2DDQaGGgIWocShTV2HouE2tPpuH4tZvq7c42MjzTyQfPdPaBqy3v2hAZCwYaLQw0RI1PSl4p1p1Mw7qT6cguUgCoWfX7yTBPTOjih3BvB3ELJKIHYqDRwkBD1HhVKVXYfj4LKw5fw8nr/961aefjgAld/REV6g4zzkZMZJAYaLQw0BARULPq94rD17DlXAaqlDV/7bnZyfBcZ1+M7egDJxuZyBUS0e0YaLQw0BDR7XKKK7DqaCp+P5KKvJKa5ihzUymGhXtiQlc/tPK0F7lCIgIYaO7AQENEd6OoVmJrfCaWH7qGc+ly9faO/o6Y2NUP/Vq4cXFMIhEx0GhhoCGi+xEEAadSC7H8UAq2nc+CUlXzV2JTB0s829kXoyK84GLL5igifWOg0cJAQ0QPK1NejpVHUrHqWCoKbi2OaSqVoHeIK0a390avYBd2IibSEwYaLQw0RPSoahfH/ON4Kk6nFqq3O9vIEN2uKZ5q74UgV1vxCiRqBBhotDDQENHjuJJdjLUn07H+VDrySirV29v5OGB0e28MDvOArYWZiBUSNUwMNFoYaIhIF6qUKuy9lIM1J9KxNzFH3dfG0swEUa3dMbq9Nzr5O3JxTCIdYaDRwkBDRLqWU1yBmFM3sOZEGpJzS9XbfZ2s8FSEF6IjvOBhbylihUTGj4FGCwMNEdWX2hFSa0+kYfPZDJRW/rs4Zvdm/y6OaWHGxTGJHhUDjRYGGiLSh7LKamyNz8KaE2k4llKg3m4rM8Wg1h4Y2a4pOvg5QiplkxTRw2Cg0cJAQ0T6di2vFOtOpiPm9A3cKCxXb/dqYokRbZtiRNumCHCxEbFCIsPHQKOFgYaIxKJSCTh2rQDrT6Vja3wWShTV6n1tfRwwsm1TPBnmiSbW5iJWSWSYGGi0MNAQkSEor1RiZ0I21p9Kx4EreepRUmYmEvQJccWItl7oHeICmSn72xABDDR3YKAhIkOTU1yBTWcysP7UDVzMLFJvd7Ayw5NhHhjZzgttvR04BJwaNQYaLQw0RGTILmUVIebUDcScvoGcYoV6u7+zNZ4M88CTYZ4IduesxNT4MNBoYaAhImOgVAk4nJyH9aduYPv5LJRXKdX7mrnaYPCtcBPkys7E1Dgw0GhhoCEiY1OqqMauhGxsPpuJ/ZdzUalUqfeFuNuq79z4OVuLWCVR/WKg0cJAQ0TGTF5ehV0Xs7HlXAYOXMlDterfv7JbedrhyTBPPBnmAW9HKxGrJNI9BhotDDRE1FAUllXinwvZ2BKfiUNJ/46UAoBwL3s8GeaJQWEeaOrAZRfI+D3q72+pHmq6p/3792PIkCHw9PSERCLBhg0bNPZPmDABEolE4zFw4EBxiiUiEpmDlTlGd/DGrxM74vh7/fDfEa3RNcgJUglwNl2OT7cmoOuCPRi5+BCWH0pBTnGF2CUT6Y2pmG9eWlqK8PBwTJw4ESNHjrzrMQMHDsTy5cvVz2Uymb7KIyIyWI7W5hjXyQfjOvkgt1iB7ReysOVsBo5dK8Cp1EKcSi3Ex1suomuQM4a1aYoBrdxga2EmdtlE9UbUQBMVFYWoqKj7HiOTyeDu7q6nioiIjI+LrQzPdfbFc519kV1Uga3xmdh4JgNn0gpx4EoeDlzJw3sxUvRr4YahbTzRK5gT+FHDI2qgeRj79u2Dq6srmjRpgj59+uCTTz6Bk5PTPY9XKBRQKP6dy6GoqOiexxIRNTRudhZ4oas/Xujqj+v5pdh0JgMbztxAcm4p/o7PxN/xmbCzqFkwc1ibpujkzwUzqWEwmE7BEokEMTExGD58uHrb6tWrYWVlBX9/fyQnJ+Pdd9+FjY0N4uLiYGJy939dzJ07F/PmzbtjOzsFE1FjJQgCLmQUYeOZG9h0NgPZRf/+o8/dzgJD23hiaLgnWnnacXZiMhhGO8rpboFG29WrVxEYGIhdu3ahb9++dz3mbndovL29GWiIiFAzgd/RlHxsOpOBrfGZKKr4d8HMIFcbDAv3xNA2nvB14hw3JK5HDTQG3+R0u4CAADg7OyMpKemegUYmk7HjMBHRPZhIJegS6Iwugc6YN6wV9iXmYuOZG9iVkIOknBL8b+dl/G/nZbRuao+Boe6ICnVHgAtnJybDZ1SBJj09Hfn5+fDw8BC7FCIioyczNcGAVu4Y0ModxRVV2HEhGxvP3MChpDzE35Aj/oYcX+xIRIi7LQaGumNQaw80c7VhsxQZJFGbnEpKSpCUlAQAaNu2Lb788kv07t0bjo6OcHR0xLx58xAdHQ13d3ckJyfjrbfeQnFxMeLj4x/6Lgwn1iMiejT5JQr8czEb285n4XCS5uzEAS7WiAp1R1SoB/vcUL0yqj40+/btQ+/eve/YPn78eCxZsgTDhw/H6dOnUVhYCE9PT/Tv3x8ff/wx3NzcHvo9GGiIiOqusKwSuxJysC0+Eweu5GmsK+XtaIlBoR4YGOqONt4ODDekU0YVaPSBgYaISDeKK6qw51IOtsVnYd/lHFRU/RtuPO0tMODWnZsI3yYw4VBwekwMNFoYaIiIdK+sshr7EnOx7XwW9iRko7RSqd7nYivDwFY1fW46+jsy3FCdMNBoYaAhIqpfFVVKHLiSh23xmdiZkI3i24aCO9uYo38rdwxu7YFO/o4wNRF1CUEyIgw0WhhoiIj0p7JahUPJNeHmn4vZKCyrUu9rYmWGAbfu3EQGOsGM4Ybug4FGCwMNEZE4qpQqxCXnY9v5TOy4kI2C0kr1PgcrM/Rv6Yao1h7oGugMc1OGG9LEQKOFgYaISHzVShWOphRga3wmdlzIQl7Jv+HGzsIUT7R0x6DW7ujWzJkLZxIABpo7MNAQERkWpUrAsZQCbDufiW3ns5Bb/O9yNbYyU/QMdsETLd3Qq7kr7K3MRKyUxMRAo4WBhojIcClVAk5ev4mt8ZnYdj5TY+FME6kEHf0c0a+lG/q1cOX6Uo0MA40WBhoiIuOgUgk4k16I3QnZ2HUxB4nZxRr7m7na3Ao3bmjj7cDh4A0cA40WBhoiIuOUml+GXQnZ2JWQjWMpBRpLMDhZm6NPiCv6tXRD92bOsDI3qqUJ6SEw0GhhoCEiMn7y8irEXs7FrovZ2JuYozHXjbmpFF0DndCvpRv6hrjB3d5CxEpJVxhotDDQEBE1LFVKFY6nFGBXQg52JmQhraBcY3/rpvbo18INfVu4cgFNI8ZAo4WBhoio4RIEAVdySrDzYk3T1Jm0Qtz+W83D3gJ9W7iiXws3dA5wgoUZh4QbCwYaLQw0RESNR26xAnsv5WBXQjYOXMlDedW/a0xZmZugRzMX9G3hij4hrnCykYlYKT0IA40WBhoiosapokqJuOR87EzIxu6EbI0h4RIJ0M6nCfq1qBkSHuRqw6YpA8NAo4WBhoiIBEHA+RtF6lFTFzKKNPb7Olmhb4gbBrRyQ3s/rhBuCBhotDDQEBGRtozCcuy+lINdF7MRl5yPSqVKvc/FVoaoUHdEhXqgoz/DjVgYaLQw0BAR0f2UKKpx8Eou/rmQjZ0J2RpDwp1tZBgY6oZBt8KNKVcI1xsGGi0MNERE9LAU1UocTsrH3/GZ+OdCFopuCzdO1uYYEOqOQaEe6BzAcFPfGGi0MNAQEVFdVFarcDg5D9vis7DjYhYKy6rU+5pYmWFAK3cMau2ByEAnmDHc6BwDjRYGGiIielxVShXikvOx7Xwmtp/Pws3bwo2DlRn6t3RDVGhNuOFcN7rBQKOFgYaIiHSpWqnC0ZQC/B2fiR3ns5BfWqneJzOVIjLQCb2au6B3CFcIfxwMNFoYaIiIqL5UK1U4dq0AW+MzsTshB5nyCo39/s7W6Hkr3HTyd+Tdm0fAQKOFgYaIiPRBEAQkZhdjX2Iu9iXm4MS1mxorhFuYSREZ4ITeIa7o1dwVPk5WIlZr+BhotDDQEBGRGIorqnAoKe9WwMlFVpHm3ZsAF2v0au6KXsEu6Mi7N3dgoNHCQENERGITBAGXsm67e3P9JpS33b2xNDNB16Cauzd9QlzhYW8pYrWGgYFGCwMNEREZmqKKKhy6cuvuzeUcjXWmAKClhx36hLiiTwtXhHs5NMrZihlotDDQEBGRIRMEAQmZxdibmIPdCdk4nVaI238zO1qbo1ewC/qEuKJHcxfYWZiJV6weMdBoYaAhIiJjkl+iQOzlXOy5lIPYy7kaSzGYSiVo79cEfUPc0KeFKwKcrRvsKuEMNFoYaIiIyFhVKVU4ef0m9lzKwZ5LOUjKKdHY7+tkhT4hrugd7NrgOhYz0GhhoCEiooYiNb8Mey5lY/elHBy9WqCxSri5qRQd/Jqga5AzugU5o5WnvVH3vWGg0cJAQ0REDVGpohoHk/KwJ6GmaUp7WLi9pRm6BDqha5Azujdzho+jlVE1TzHQaGGgISKihk4QBFzNK8WhpDwcvJKHuOR8FCuqNY7xamKJbkHO6BrkjC6BTnCykYlU7cNhoNHCQENERI1NtVKFczfkOHQlDweT8nAq9SaqlJq/7lt62KFbs5qA09HPEZbmhtX/hoFGCwMNERE1dmWV1TiWUlBzBycpHwmZRRr7zUwkaOvTBF0DndElyAnhXg4wN5WKVG0NBhotDDRERESa8koUOJycj4NXcnEoKR83Css19luZm6CDn6O6D04LDzu9dzBmoNHCQENERHRvgiDgen4ZDifn43ByTf+b/NJKjWPsLc0QGeCELkFO6BLojECX+p//hoFGCwMNERHRw1OpBFzOKcahpHzEJefhyNUClGh1MHa1laFLoBO63Opg7NVE9yuHM9BoYaAhIiKqu2qlCvE35Oo7OCeu3YSiWqVxzKwnmuPVvs10+r6P+vvbVKfvTkRERA2KqYkUbX2aoK1PE0zrHYSKKiVOpd7E4aSagHM2XY5QL3uxy2SgISIioodnYWaCLoHO6BLoDCAYxRVVkJmKP+SbgYaIiIjqzNZAVv8WdZD5/v37MWTIEHh6ekIikWDDhg0a+wVBwIcffggPDw9YWlqiX79+uHLlijjFEhERkcESNdCUlpYiPDwcixYtuuv+zz//HN988w2WLl2Ko0ePwtraGgMGDEBFRcVdjyciIqLGSdQmp6ioKERFRd11nyAI+Oqrr/D+++9j2LBhAIBff/0Vbm5u2LBhA8aMGaPPUomIiMiAiTuv8X2kpKQgKysL/fr1U2+zt7dHp06dEBcXJ2JlREREZGgMtlNwVlYWAMDNzU1ju5ubm3rf3SgUCigUCvXzoqKiex5LREREDYPB3qGpq/nz58Pe3l798Pb2FrskIiIiqmcGG2jc3d0BANnZ2Rrbs7Oz1fvuZvbs2ZDL5epHWlpavdZJRERE4jPYQOPv7w93d3fs3r1bva2oqAhHjx5FZGTkPV8nk8lgZ2en8SAiIqKGTdQ+NCUlJUhKSlI/T0lJwZkzZ+Do6AgfHx/MmDEDn3zyCZo1awZ/f3988MEH8PT0xPDhw8UrmoiIiAyOqIHmxIkT6N27t/r566+/DgAYP348VqxYgbfeegulpaWYPHkyCgsL0a1bN2zfvh0WFhZilUxEREQGiKttExERkcF51N/fBtuHhoiIiOhhMdAQERGR0TPYifV0pbZFjRPsERERGY/a39sP2zOmwQea4uJiAOAEe0REREaouLgY9vb2DzyuwXcKVqlUyMjIgK2tLSQSic7OW1RUBG9vb6SlpbGz8SPgdasbXre64XV7dLxmdcPrVjf3u26CIKC4uBienp6QSh/cQ6bB36GRSqXw8vKqt/Nz8r664XWrG163uuF1e3S8ZnXD61Y397puD3NnphY7BRMREZHRY6AhIiIio8dAU0cymQxz5syBTCYTuxSjwutWN7xudcPr9uh4zeqG161udHndGnynYCIiImr4eIeGiIiIjB4DDRERERk9BhoiIiIyegw0REREZPQYaOpo0aJF8PPzg4WFBTp16oRjx46JXZJBmzt3LiQSicYjJCRE7LIMzv79+zFkyBB4enpCIpFgw4YNGvsFQcCHH34IDw8PWFpaol+/frhy5Yo4xRqIB12zCRMm3PHdGzhwoDjFGpD58+ejQ4cOsLW1haurK4YPH47ExESNYyoqKjBt2jQ4OTnBxsYG0dHRyM7OFqli8T3MNevVq9cd37dXXnlFpIoNw5IlSxAWFqaePC8yMhLbtm1T79fV94yBpg7+/PNPvP7665gzZw5OnTqF8PBwDBgwADk5OWKXZtBatWqFzMxM9ePgwYNil2RwSktLER4ejkWLFt11/+eff45vvvkGS5cuxdGjR2FtbY0BAwagoqJCz5UajgddMwAYOHCgxnfvjz/+0GOFhik2NhbTpk3DkSNHsHPnTlRVVaF///4oLS1VHzNz5kxs3rwZa9euRWxsLDIyMjBy5EgRqxbXw1wzAJg0aZLG9+3zzz8XqWLD4OXlhQULFuDkyZM4ceIE+vTpg2HDhuHChQsAdPg9E+iRdezYUZg2bZr6uVKpFDw9PYX58+eLWJVhmzNnjhAeHi52GUYFgBATE6N+rlKpBHd3d+GLL75QbyssLBRkMpnwxx9/iFCh4dG+ZoIgCOPHjxeGDRsmSj3GJCcnRwAgxMbGCoJQ890yMzMT1q5dqz4mISFBACDExcWJVaZB0b5mgiAIPXv2FF577TXxijISTZo0EX788Uedfs94h+YRVVZW4uTJk+jXr596m1QqRb9+/RAXFydiZYbvypUr8PT0REBAAJ555hmkpqaKXZJRSUlJQVZWlsZ3z97eHp06deJ37wH27dsHV1dXBAcHY8qUKcjPzxe7JIMjl8sBAI6OjgCAkydPoqqqSuP7FhISAh8fH37fbtG+ZrVWrlwJZ2dnhIaGYvbs2SgrKxOjPIOkVCqxevVqlJaWIjIyUqffswa/OKWu5eXlQalUws3NTWO7m5sbLl26JFJVhq9Tp05YsWIFgoODkZmZiXnz5qF79+44f/48bG1txS7PKGRlZQHAXb97tfvoTgMHDsTIkSPh7++P5ORkvPvuu4iKikJcXBxMTEzELs8gqFQqzJgxA127dkVoaCiAmu+bubk5HBwcNI7l963G3a4ZAIwbNw6+vr7w9PTEuXPn8PbbbyMxMRHr168XsVrxxcfHIzIyEhUVFbCxsUFMTAxatmyJM2fO6Ox7xkBDehEVFaX+c1hYGDp16gRfX1+sWbMGL774ooiVUUM3ZswY9Z9bt26NsLAwBAYGYt++fejbt6+IlRmOadOm4fz58+zX9gjudc0mT56s/nPr1q3h4eGBvn37Ijk5GYGBgfou02AEBwfjzJkzkMvlWLduHcaPH4/Y2FidvgebnB6Rs7MzTExM7uiBnZ2dDXd3d5GqMj4ODg5o3rw5kpKSxC7FaNR+v/jdezwBAQFwdnbmd++W6dOnY8uWLdi7dy+8vLzU293d3VFZWYnCwkKN4/l9u/c1u5tOnToBQKP/vpmbmyMoKAgRERGYP38+wsPD8fXXX+v0e8ZA84jMzc0RERGB3bt3q7epVCrs3r0bkZGRIlZmXEpKSpCcnAwPDw+xSzEa/v7+cHd31/juFRUV4ejRo/zuPYL09HTk5+c3+u+eIAiYPn06YmJisGfPHvj7+2vsj4iIgJmZmcb3LTExEampqY32+/aga3Y3Z86cAYBG/33TplKpoFAodPs9022/5cZh9erVgkwmE1asWCFcvHhRmDx5suDg4CBkZWWJXZrBmjVrlrBv3z4hJSVFOHTokNCvXz/B2dlZyMnJEbs0g1JcXCycPn1aOH36tABA+PLLL4XTp08L169fFwRBEBYsWCA4ODgIGzduFM6dOycMGzZM8Pf3F8rLy0WuXDz3u2bFxcXCG2+8IcTFxQkpKSnCrl27hHbt2gnNmjUTKioqxC5dVFOmTBHs7e2Fffv2CZmZmepHWVmZ+phXXnlF8PHxEfbs2SOcOHFCiIyMFCIjI0WsWlwPumZJSUnCRx99JJw4cUJISUkRNm7cKAQEBAg9evQQuXJxvfPOO0JsbKyQkpIinDt3TnjnnXcEiUQi/PPPP4Ig6O57xkBTR99++63g4+MjmJubCx07dhSOHDkidkkG7emnnxY8PDwEc3NzoWnTpsLTTz8tJCUliV2Wwdm7d68A4I7H+PHjBUGoGbr9wQcfCG5uboJMJhP69u0rJCYmilu0yO53zcrKyoT+/fsLLi4ugpmZmeDr6ytMmjSJ//gQhLteMwDC8uXL1ceUl5cLU6dOFZo0aSJYWVkJI0aMEDIzM8UrWmQPumapqalCjx49BEdHR0EmkwlBQUHCm2++KcjlcnELF9nEiRMFX19fwdzcXHBxcRH69u2rDjOCoLvvmUQQBKGOd4yIiIiIDAL70BAREZHRY6AhIiIio8dAQ0REREaPgYaIiIiMHgMNERERGT0GGiIiIjJ6DDRERERk9BhoiKjRkUgk2LBhg9hlEJEOMdAQkV5NmDABEonkjsfAgQPFLo2IjJip2AUQUeMzcOBALF++XGObTCYTqRoiagh4h4aI9E4mk8Hd3V3j0aRJEwA1zUFLlixBVFQULC0tERAQgHXr1mm8Pj4+Hn369IGlpSWcnJwwefJklJSUaBzz888/o1WrVpDJZPDw8MD06dM19ufl5WHEiBGwsrJCs2bNsGnTpvr90ERUrxhoiMjgfPDBB4iOjsbZs2fxzDPPYMyYMUhISAAAlJaWYsCAAWjSpAmOHz+OtWvXYteuXRqBZcmSJZg2bRomT56M+Ph4bNq0CUFBQRrvMW/ePIwePRrnzp3DoEGD8Mwzz6CgoECvn5OIdEh362kSET3Y+PHjBRMTE8Ha2lrj8emnnwqCULOi8SuvvKLxmk6dOglTpkwRBEEQli1bJjRp0kQoKSlR7//7778FqVSqXkXb09NTeO+99+5ZAwDh/fffVz8vKSkRAAjbtm3T2eckIv1iHxoi0rvevXtjyZIlGtscHR3Vf46MjNTYFxkZiTNnzgAAEhISEB4eDmtra/X+rl27QqVSITExERKJBBkZGejbt+99awgLC1P/2draGnZ2dsjJyanrRyIikTHQEJHeWVtb39EEpCuWlpYPdZyZmZnGc4lEApVKVR8lEZEesA8NERmcI0eO3PG8RYsWAIAWLVrg7NmzKC0tVe8/dOgQpFIpgoODYWtrCz8/P+zevVuvNRORuHiHhoj0TqFQICsrS2ObqakpnJ2dAQBr165F+/bt0a1bN6xcuRLHjh3DTz/9BAB45plnMGfOHIwfPx5z585Fbm4uXn31VTz33HNwc3MDAMydOxevvPIKXF1dERUVheLiYhw6dAivvvqqfj8oEekNAw0R6d327dvh4eGhsS04OBiXLl0CUDMCafXq1Zg6dSo8PDzwxx9/oGXLlgAAKysr7NixA6+99ho6dOgAKysrREdH48svv1Sfa/z48aioqMDChQvxxhtvwNnZGaNGjdLfByQivZMIgiCIXQQRUS2JRIKYmBgMHz5c7FKIyIiwDw0REREZPQYaIiIiMnrsQ0NEBoWt4ERUF7xDQ0REREaPgYaIiIiMHgMNERERGT0GGiIiIjJ6DDRERERk9BhoiIiIyOgx0BAREZHRY6AhIiIio8dAQ0REREbv/wEz5FwxSaYZEwAAAABJRU5ErkJggg==", + "text/plain": [ + "<Figure size 640x480 with 1 Axes>" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "import matplotlib.pyplot as plt\n", + "\n", + "plt.plot(range(n_epochs), train_loss_list)\n", + "plt.xlabel(\"Epoch\")\n", + "plt.ylabel(\"Loss\")\n", + "plt.title(\"Performance of Model 1\")\n", + "plt.show()" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Now loading the model with the lowest validation loss value" + ] + }, + { + "cell_type": "code", + "execution_count": 18, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Test Loss: 21.960862\n", + "\n", + "Test Accuracy of airplane: 68% (681/1000)\n", + "Test Accuracy of automobile: 74% (740/1000)\n", + "Test Accuracy of bird: 45% (452/1000)\n", + "Test Accuracy of cat: 51% (518/1000)\n", + "Test Accuracy of deer: 55% (550/1000)\n", + "Test Accuracy of dog: 50% (505/1000)\n", + "Test Accuracy of frog: 73% (730/1000)\n", + "Test Accuracy of horse: 66% (669/1000)\n", + "Test Accuracy of ship: 79% (796/1000)\n", + "Test Accuracy of truck: 62% (621/1000)\n", + "\n", + "Test Accuracy (Overall): 62% (6262/10000)\n" + ] + } + ], + "source": [ + "model.load_state_dict(torch.load(\"./model_cifar.pt\"))\n", + "\n", + "# track test loss\n", + "test_loss = 0.0\n", + "class_correct = list(0.0 for i in range(10))\n", + "class_total = list(0.0 for i in range(10))\n", + "\n", + "model.eval()\n", + "# iterate over test data\n", + "for data, target in test_loader:\n", + " # move tensors to GPU if CUDA is available\n", + " if train_on_gpu:\n", + " data, target = data.cuda(), target.cuda()\n", + " # forward pass: compute predicted outputs by passing inputs to the model\n", + " output = model(data)\n", + " # calculate the batch loss\n", + " loss = criterion(output, target)\n", + " # update test loss\n", + " test_loss += loss.item() * data.size(0)\n", + " # convert output probabilities to predicted class\n", + " _, pred = torch.max(output, 1)\n", + " # compare predictions to true label\n", + " correct_tensor = pred.eq(target.data.view_as(pred))\n", + " correct = (\n", + " np.squeeze(correct_tensor.numpy())\n", + " if not train_on_gpu\n", + " else np.squeeze(correct_tensor.cpu().numpy())\n", + " )\n", + " # calculate test accuracy for each object class\n", + " for i in range(batch_size):\n", + " label = target.data[i]\n", + " class_correct[label] += correct[i].item()\n", + " class_total[label] += 1\n", + "\n", + "# average test loss\n", + "test_loss = test_loss / len(test_loader)\n", + "print(\"Test Loss: {:.6f}\\n\".format(test_loss))\n", + "\n", + "for i in range(10):\n", + " if class_total[i] > 0:\n", + " print(\n", + " \"Test Accuracy of %5s: %2d%% (%2d/%2d)\"\n", + " % (\n", + " classes[i],\n", + " 100 * class_correct[i] / class_total[i],\n", + " np.sum(class_correct[i]),\n", + " np.sum(class_total[i]),\n", + " )\n", + " )\n", + " else:\n", + " print(\"Test Accuracy of %5s: N/A (no training examples)\" % (classes[i]))\n", + "\n", + "print(\n", + " \"\\nTest Accuracy (Overall): %2d%% (%2d/%2d)\"\n", + " % (\n", + " 100.0 * np.sum(class_correct) / np.sum(class_total),\n", + " np.sum(class_correct),\n", + " np.sum(class_total),\n", + " )\n", + ")" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Second Network :" + ] + }, + { + "cell_type": "code", + "execution_count": 2, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Second_Net(\n", + " (conv1): Conv2d(3, 16, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1))\n", + " (pool): MaxPool2d(kernel_size=2, stride=2, padding=0, dilation=1, ceil_mode=False)\n", + " (conv2): Conv2d(16, 32, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1))\n", + " (conv3): Conv2d(32, 64, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1))\n", + " (fc1): Linear(in_features=1024, out_features=512, bias=True)\n", + " (fc2): Linear(in_features=512, out_features=64, bias=True)\n", + " (fc3): Linear(in_features=64, out_features=10, bias=True)\n", + ")\n" + ] + } + ], + "source": [ + "import torch.nn as nn\n", + "import torch.nn.functional as F\n", + "\n", + "# define the CNN architecture\n", + "\n", + "\n", + "class Second_Net(nn.Module):\n", + " def __init__(self):\n", + " super(Second_Net, self).__init__()\n", + " self.conv1 = nn.Conv2d(3, 16, 3, padding=1)\n", + " # H_out(conv1) = W_out(conv1) = (H_in + 2*padding - Kernel)/stride + 1 = (32 + 2 - 3)/1 + 1 = 32\n", + " # Size(conv1_out) = 32*32*16\n", + " self.pool = nn.MaxPool2d(2, 2) # pool = 16*16\n", + " # H_out(conv2) = W_out(conv2) = (H_in + 2*padding - Kernel)/stride + 1 = (16 + 2 - 3)/1 + 1 = 16\n", + " self.conv2 = nn.Conv2d(16, 32, 3, padding=1)\n", + " # H_out(conv3) = W_out(conv3) = (H_in + 2*padding - Kernel)/stride + 1 = (16 + 2 - 3)/1 + 1 = 8\n", + " self.conv3 = nn.Conv2d(32, 64, 3, padding=1) \n", + " self.fc1 = nn.Linear(64 * 4 * 4, 512)\n", + " self.fc2 = nn.Linear(512, 64)\n", + " self.fc3 = nn.Linear(64, 10)\n", + "\n", + " def forward(self, x):\n", + " x = self.pool(F.relu(self.conv1(x)))\n", + " x = self.pool(F.relu(self.conv2(x)))\n", + " x = self.pool(F.relu(self.conv3(x)))\n", + " x = x.view(-1, 64 * 4 * 4)\n", + " x = F.relu(self.fc1(x))\n", + " x = F.relu(self.fc2(x))\n", + " x = self.fc3(x)\n", + " return x\n", + "\n", + "\n", + "# create a complete CNN\n", + "model = Second_Net()\n", + "print(model)\n", + "# move tensors to GPU if CUDA is available\n", + "# if train_on_gpu:\n", + " # model.cuda()" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + " Training the new model" + ] + }, + { + "cell_type": "code", + "execution_count": 8, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Epoch: 0 \tTraining Loss: 45.224616 \tValidation Loss: 41.426994\n", + "Validation loss decreased (inf --> 41.426994). Saving model ...\n", + "Epoch: 1 \tTraining Loss: 36.723764 \tValidation Loss: 32.832016\n", + "Validation loss decreased (41.426994 --> 32.832016). Saving model ...\n", + "Epoch: 2 \tTraining Loss: 31.097073 \tValidation Loss: 29.986182\n", + "Validation loss decreased (32.832016 --> 29.986182). Saving model ...\n", + "Epoch: 3 \tTraining Loss: 27.964499 \tValidation Loss: 26.652988\n", + "Validation loss decreased (29.986182 --> 26.652988). Saving model ...\n", + "Epoch: 4 \tTraining Loss: 25.368614 \tValidation Loss: 25.234237\n", + "Validation loss decreased (26.652988 --> 25.234237). Saving model ...\n", + "Epoch: 5 \tTraining Loss: 23.028257 \tValidation Loss: 22.257799\n", + "Validation loss decreased (25.234237 --> 22.257799). Saving model ...\n", + "Epoch: 6 \tTraining Loss: 21.007300 \tValidation Loss: 21.598088\n", + "Validation loss decreased (22.257799 --> 21.598088). Saving model ...\n", + "Epoch: 7 \tTraining Loss: 19.216898 \tValidation Loss: 20.251749\n", + "Validation loss decreased (21.598088 --> 20.251749). Saving model ...\n", + "Epoch: 8 \tTraining Loss: 17.697483 \tValidation Loss: 20.098650\n", + "Validation loss decreased (20.251749 --> 20.098650). Saving model ...\n", + "Epoch: 9 \tTraining Loss: 16.180104 \tValidation Loss: 18.660767\n", + "Validation loss decreased (20.098650 --> 18.660767). Saving model ...\n", + "Epoch: 10 \tTraining Loss: 14.774329 \tValidation Loss: 17.974099\n", + "Validation loss decreased (18.660767 --> 17.974099). Saving model ...\n", + "Epoch: 11 \tTraining Loss: 13.394195 \tValidation Loss: 17.683563\n", + "Validation loss decreased (17.974099 --> 17.683563). Saving model ...\n", + "Epoch: 12 \tTraining Loss: 12.029678 \tValidation Loss: 18.618383\n", + "Epoch: 13 \tTraining Loss: 10.594165 \tValidation Loss: 18.077175\n", + "Epoch: 14 \tTraining Loss: 9.346292 \tValidation Loss: 19.066724\n", + "Epoch: 15 \tTraining Loss: 7.995027 \tValidation Loss: 20.780326\n", + "Epoch: 16 \tTraining Loss: 6.687421 \tValidation Loss: 21.976052\n", + "Epoch: 17 \tTraining Loss: 5.550229 \tValidation Loss: 22.871844\n", + "Epoch: 18 \tTraining Loss: 4.561936 \tValidation Loss: 24.607759\n", + "Epoch: 19 \tTraining Loss: 3.798454 \tValidation Loss: 25.928546\n", + "Epoch: 20 \tTraining Loss: 2.968054 \tValidation Loss: 26.749855\n", + "Epoch: 21 \tTraining Loss: 2.694036 \tValidation Loss: 30.236186\n", + "Epoch: 22 \tTraining Loss: 2.217052 \tValidation Loss: 30.743367\n", + "Epoch: 23 \tTraining Loss: 1.851026 \tValidation Loss: 31.145896\n", + "Epoch: 24 \tTraining Loss: 1.434988 \tValidation Loss: 33.876719\n", + "Epoch: 25 \tTraining Loss: 1.226250 \tValidation Loss: 36.642382\n", + "Epoch: 26 \tTraining Loss: 1.181099 \tValidation Loss: 35.523206\n", + "Epoch: 27 \tTraining Loss: 0.926557 \tValidation Loss: 37.227898\n", + "Epoch: 28 \tTraining Loss: 1.313841 \tValidation Loss: 38.011964\n", + "Epoch: 29 \tTraining Loss: 0.968135 \tValidation Loss: 38.862978\n" + ] + } + ], + "source": [ + "import torch.optim as optim \n", + "model = Second_Net()\n", + "\n", + "criterion = nn.CrossEntropyLoss() # specify loss function\n", + "optimizer = optim.SGD(model.parameters(), lr=0.01) # specify optimizer\n", + "\n", + "n_epochs = 30 # number of epochs to train the model\n", + "train_loss_list = [] # list to store loss to visualize\n", + "valid_loss_min = np.Inf # track change in validation loss\n", + "\n", + "for epoch in range(n_epochs):\n", + " # Keep track of training and validation loss\n", + " train_loss = 0.0\n", + " valid_loss = 0.0\n", + "\n", + " # Train the model\n", + " model.train()\n", + " for data, target in train_loader:\n", + " # Move tensors to GPU if CUDA is available\n", + " if train_on_gpu:\n", + " data, target = data.cuda(), target.cuda()\n", + " # Clear the gradients of all optimized variables\n", + " optimizer.zero_grad()\n", + " # Forward pass: compute predicted outputs by passing inputs to the model\n", + " output = model(data)\n", + " # Calculate the batch loss\n", + " loss = criterion(output, target)\n", + " # Backward pass: compute gradient of the loss with respect to model parameters\n", + " loss.backward()\n", + " # Perform a single optimization step (parameter update)\n", + " optimizer.step()\n", + " # Update training loss\n", + " train_loss += loss.item() * data.size(0)\n", + "\n", + " # Validate the model\n", + " model.eval()\n", + " for data, target in valid_loader:\n", + " # Move tensors to GPU if CUDA is available\n", + " if train_on_gpu:\n", + " data, target = data.cuda(), target.cuda()\n", + " # Forward pass: compute predicted outputs by passing inputs to the model\n", + " output = model(data)\n", + " # Calculate the batch loss\n", + " loss = criterion(output, target)\n", + " # Update average validation loss\n", + " valid_loss += loss.item() * data.size(0)\n", + "\n", + " # Calculate average losses\n", + " train_loss = train_loss / len(train_loader)\n", + " valid_loss = valid_loss / len(valid_loader)\n", + " train_loss_list.append(train_loss)\n", + "\n", + " # Print training/validation statistics\n", + " print(\n", + " \"Epoch: {} \\tTraining Loss: {:.6f} \\tValidation Loss: {:.6f}\".format(\n", + " epoch, train_loss, valid_loss\n", + " )\n", + " )\n", + "\n", + " # Save model if validation loss has decreased\n", + " if valid_loss <= valid_loss_min:\n", + " print(\n", + " \"Validation loss decreased ({:.6f} --> {:.6f}). Saving model ...\".format(\n", + " valid_loss_min, valid_loss\n", + " )\n", + " )\n", + " torch.save(model.state_dict(), \"new_model_cifar.pt\")\n", + " valid_loss_min = valid_loss" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Loading the second model with the lowest validation loss value" + ] + }, + { + "cell_type": "code", + "execution_count": 9, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Test Loss: 17.850414\n", + "\n", + "Test Accuracy of airplane: 79% (794/1000)\n", + "Test Accuracy of automobile: 87% (873/1000)\n", + "Test Accuracy of bird: 58% (585/1000)\n", + "Test Accuracy of cat: 40% (402/1000)\n", + "Test Accuracy of deer: 61% (616/1000)\n", + "Test Accuracy of dog: 67% (670/1000)\n", + "Test Accuracy of frog: 73% (732/1000)\n", + "Test Accuracy of horse: 76% (769/1000)\n", + "Test Accuracy of ship: 77% (779/1000)\n", + "Test Accuracy of truck: 73% (731/1000)\n", + "\n", + "Test Accuracy (Overall): 69% (6951/10000)\n" + ] + } + ], + "source": [ + "model.load_state_dict(torch.load(\"./new_model_cifar.pt\"))\n", + "\n", + "# track test loss\n", + "test_loss = 0.0\n", + "class_correct = list(0.0 for i in range(10))\n", + "class_total = list(0.0 for i in range(10))\n", + "\n", + "model.eval()\n", + "# iterate over test data\n", + "for data, target in test_loader:\n", + " # move tensors to GPU if CUDA is available\n", + " if train_on_gpu:\n", + " data, target = data.cuda(), target.cuda()\n", + " # forward pass: compute predicted outputs by passing inputs to the model\n", + " output = model(data)\n", + " # calculate the batch loss\n", + " loss = criterion(output, target)\n", + " # update test loss\n", + " test_loss += loss.item() * data.size(0)\n", + " # convert output probabilities to predicted class\n", + " _, pred = torch.max(output, 1)\n", + " # compare predictions to true label\n", + " correct_tensor = pred.eq(target.data.view_as(pred))\n", + " correct = (\n", + " np.squeeze(correct_tensor.numpy())\n", + " if not train_on_gpu\n", + " else np.squeeze(correct_tensor.cpu().numpy())\n", + " )\n", + " # calculate test accuracy for each object class\n", + " for i in range(batch_size):\n", + " label = target.data[i]\n", + " class_correct[label] += correct[i].item()\n", + " class_total[label] += 1\n", + "\n", + "# average test loss\n", + "test_loss = test_loss / len(test_loader)\n", + "print(\"Test Loss: {:.6f}\\n\".format(test_loss))\n", + "\n", + "for i in range(10):\n", + " if class_total[i] > 0:\n", + " print(\n", + " \"Test Accuracy of %5s: %2d%% (%2d/%2d)\"\n", + " % (\n", + " classes[i],\n", + " 100 * class_correct[i] / class_total[i],\n", + " np.sum(class_correct[i]),\n", + " np.sum(class_total[i]),\n", + " )\n", + " )\n", + " else:\n", + " print(\"Test Accuracy of %5s: N/A (no training examples)\" % (classes[i]))\n", + "\n", + "print(\n", + " \"\\nTest Accuracy (Overall): %2d%% (%2d/%2d)\"\n", + " % (\n", + " 100.0 * np.sum(class_correct) / np.sum(class_total),\n", + " np.sum(class_correct),\n", + " np.sum(class_total),\n", + " )\n", + ")" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Plot Loss in function epoch for the new model" + ] + }, + { + "cell_type": "code", + "execution_count": 10, + "metadata": {}, + "outputs": [ + { + "data": { + "image/png": "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KYwbNw6TJ09GamoqBg0aVKuZUo+icp+/8MIL2kHNVQUEBDRIFqKGxEJDVI9atGgBURTh6+uL1q1b63Xb3t7e0Gg0uHbtmvb/5oGKAaHZ2dnw9vbW68+ryY4dO1BcXIzt27frHH253ymfB2nRogUuXLjwwHXOnTuHfv36PXShq1S5X2JjY7WnqCrFxsbqbb8NGzYMr732Go4fP45ffvnlvnn27duH3NxcnaM0V65c0clb+fe+fv26zlGZ2NhYne1VzoAqLy9/6GvnEDUGHENDVI+GDx8OuVyO999/v9pRCFEUcfv27Tpv+6mnngIAfP755zrLK49a1DT7Rd8qj7j883dTq9UICwur8zZHjBiBc+fOVZul9c+fM2rUKCQlJeGbb76ptk5hYSHy8/Pvuf1OnTrB2dkZK1eu1JnivXv3bly+fFlv+83a2horVqzAwoUL8eyzz95zvaeeegrl5eX46quvdJYvXboUgiBoZ0pV/lt1llTVv79cLseIESOwefPmGothRkZGXX4dIoPHIzRE9ahFixb46KOPMG/ePNy4cQNDhw6FUqlEfHw8wsPD8eqrr2Lu3Ll12nZgYCDGjx+P1atXIzs7G71790ZUVBR++OEHDB06FH369NHzb1Nd//79YWZmhmeffRavvfYa8vLy8M0338DZ2RkpKSl12ua//vUvbNq0Cc899xxefvllBAUFISsrC9u3b8fKlSsRGBiIF198Eb/++iumTJmCgwcPonv37igvL8eVK1fw66+/aq+3UxNTU1N88sknmDhxInr37o2xY8dqp237+Phg1qxZj7JLdNzrlM8/Pfvss+jTpw/eeecd3LhxA4GBgfj999+xbds2zJw5UztmpkOHDhg7diy+/vprqNVqdOvWDfv370dcXFy1bS5evBgHDx5EcHAwJk+ejLZt2yIrKwunT5/Gvn37kJWVVevf5aeffsLNmze146QOHz6Mjz76CADw4osvNsgRQaL7YaEhqmdvv/02WrdujaVLl+L9998HUDHGo3///hg8ePAjbfvbb79F8+bNsWbNGoSHh8PV1RXz5s3DggUL9BH9gfz8/LBp0ya8++67mDt3LlxdXTF16lQ4OTlVmyH1sKytrXHkyBEsWLAA4eHh+OGHH+Ds7Ix+/frBw8MDACCTybB161YsXboUP/74I8LDw2FpaYnmzZvjzTfffODpvQkT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jmZQcnNzxTNnzohnzpwRAYhLliwRz5w5I968eVMURVFcvHixaGtrK27btk08f/68OGTIENHX11csLCyUOLl07rfPcnNzxblz54qRkZFifHy8uG/fPrFjx45iq1atxKKiIqmjS2rq1KmiSqUSDx06JKakpGgfBQUF2nWmTJkienl5iQcOHBBPnTolhoSEiCEhIRKmltaD9llcXJz4wQcfiKdOnRLj4+PFbdu2ic2bNxd79eolcXJpvf3222JERIQYHx8vnj9/Xnz77bdFQRDE33//XRRF/b3PWGjq6MsvvxS9vLxEMzMzsUuXLuLx48eljmTQRo8eLbq5uYlmZmZis2bNxNGjR4txcXFSxzI4Bw8eFAFUe4wfP14UxYqp2++9957o4uIiKhQKsV+/fmJsbKy0oSV2v31WUFAg9u/fX3RychJNTU1Fb29vcfLkyfyfD1GscZ8BEMPCwrTrFBYWitOmTRPt7OxES0tLcdiwYWJKSop0oSX2oH1269YtsVevXqK9vb2oUCjEli1biv/6179EtVotbXCJvfzyy6K3t7doZmYmOjk5if369dOWGVHU3/tMEEVRrOMRIyIiIiKDwDE0REREZPRYaIiIiMjosdAQERGR0WOhISIiIqPHQkNERERGj4WGiIiIjB4LDRERERk9FhoianIEQcDWrVuljkFEesRCQ0QNasKECRAEodpj4MCBUkcjIiNmInUAImp6Bg4ciLCwMJ1lCoVCojRE1BjwCA0RNTiFQgFXV1edh52dHYCK00ErVqzAoEGDYGFhgebNm2PTpk06r4+JiUHfvn1hYWEBBwcHvPrqq8jLy9NZ5/vvv0e7du2gUCjg5uaGGTNm6DyfmZmJYcOGwdLSEq1atcL27dvr95cmonrFQkNEBue9997DiBEjcO7cOTz//PMYM2YMLl++DADIz8/HgAEDYGdnh5MnT2Ljxo3Yt2+fTmFZsWIFpk+fjldffRUxMTHYvn07WrZsqfMz3n//fYwaNQrnz5/HU089heeffx5ZWVkN+nsSkR7p736aREQPNn78eFEul4tWVlY6j48//lgUxYo7Gk+ZMkXnNcHBweLUqVNFURTF1atXi3Z2dmJeXp72+d9++02UyWTau2i7u7uL77zzzj0zABDfffdd7fd5eXkiAHH37t16+z2JqGFxDA0RNbg+ffpgxYoVOsvs7e21X4eEhOg8FxISgrNnzwIALl++jMDAQFhZWWmf7969OzQaDWJjYyEIApKTk9GvX7/7ZggICNB+bWVlBRsbG6Snp9f1VyIiibHQEFGDs7KyqnYKSF8sLCweaj1TU1Od7wVBgEajqY9IRNQAOIaGiAzO8ePHq33fpk0bAECbNm1w7tw55Ofna58/duwYZDIZ/Pz8oFQq4ePjg/379zdoZiKSFo/QEFGDKy4uRmpqqs4yExMTODo6AgA2btyITp06oUePHli7di2ioqLw3XffAQCef/55LFiwAOPHj8fChQuRkZGB119/HS+++CJcXFwAAAsXLsSUKVPg7OyMQYMGITc3F8eOHcPrr7/esL8oETUYFhoianB79uyBm5ubzjI/Pz9cuXIFQMUMpA0bNmDatGlwc3PD+vXr0bZtWwCApaUl9u7dizfffBOdO3eGpaUlRowYgSVLlmi3NX78eBQVFWHp0qWYO3cuHB0dMXLkyIb7BYmowQmiKIpShyAiqiQIAsLDwzF06FCpoxCREeEYGiIiIjJ6LDRERERk9DiGhogMCs+CE1Fd8AgNERERGT0WGiIiIjJ6LDRERERk9FhoiIiIyOix0BAREZHRY6EhIiIio8dCQ0REREaPhYaIiIiMHgsNERERGb3/BwwpR6P+K4YFAAAAAElFTkSuQmCC", + "text/plain": [ + "<Figure size 640x480 with 1 Axes>" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "import matplotlib.pyplot as plt\n", + "\n", + "plt.plot(range(n_epochs), train_loss_list)\n", + "plt.xlabel(\"Epoch\")\n", + "plt.ylabel(\"Loss\")\n", + "plt.title(\"Performance of Model 1\")\n", + "plt.show()" + ] + }, + { + "cell_type": "markdown", + "id": "944991a2", + "metadata": {}, + "source": [ + "Build a new network with the following structure.\n", + "\n", + "- It has 3 convolutional layers of kernel size 3 and padding of 1.\n", + "- The first convolutional layer must output 16 channels, the second 32 and the third 64.\n", + "- At each convolutional layer output, we apply a ReLU activation then a MaxPool with kernel size of 2.\n", + "- Then, three fully connected layers, the first two being followed by a ReLU activation and a dropout whose value you will suggest.\n", + "- The first fully connected layer will have an output size of 512.\n", + "- The second fully connected layer will have an output size of 64.\n", + "\n", + "Compare the results obtained with this new network to those obtained previously." + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3.8.5 ('base')", + "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.11.6" + }, + "vscode": { + "interpreter": { + "hash": "9e3efbebb05da2d4a1968abe9a0645745f54b63feb7a85a514e4da0495be97eb" + } + } + }, + "nbformat": 4, + "nbformat_minor": 5 +} -- GitLab