diff --git a/TD2 Deep Learning.ipynb b/TD2 Deep Learning.ipynb index d59ed6c4a0aa124393eb61023129c75ca1576d1b..63d0b6b561725f7044048f31c284c1299db4b44b 100644 --- a/TD2 Deep Learning.ipynb +++ b/TD2 Deep Learning.ipynb @@ -33,7 +33,7 @@ }, { "cell_type": "code", - "execution_count": 1, + "execution_count": 4, "metadata": {}, "outputs": [], "source": [ @@ -43,7 +43,7 @@ }, { "cell_type": "code", - "execution_count": 2, + "execution_count": 5, "id": "330a42f5", "metadata": {}, "outputs": [ @@ -54,19 +54,19 @@ "Requirement already satisfied: torch in c:\\users\\zineb\\anaconda3\\lib\\site-packages (2.1.0)\n", "Requirement already satisfied: torchvision in c:\\users\\zineb\\anaconda3\\lib\\site-packages (0.16.0)\n", "Requirement already satisfied: typing-extensions in c:\\users\\zineb\\anaconda3\\lib\\site-packages (from torch) (4.4.0)\n", + "Requirement already satisfied: jinja2 in c:\\users\\zineb\\anaconda3\\lib\\site-packages (from torch) (3.1.2)\n", "Requirement already satisfied: fsspec in c:\\users\\zineb\\anaconda3\\lib\\site-packages (from torch) (2022.11.0)\n", "Requirement already satisfied: filelock in c:\\users\\zineb\\anaconda3\\lib\\site-packages (from torch) (3.9.0)\n", - "Requirement already satisfied: jinja2 in c:\\users\\zineb\\anaconda3\\lib\\site-packages (from torch) (3.1.2)\n", - "Requirement already satisfied: sympy in c:\\users\\zineb\\anaconda3\\lib\\site-packages (from torch) (1.11.1)\n", "Requirement already satisfied: networkx in c:\\users\\zineb\\anaconda3\\lib\\site-packages (from torch) (2.8.4)\n", - "Requirement already satisfied: requests in c:\\users\\zineb\\anaconda3\\lib\\site-packages (from torchvision) (2.28.1)\n", + "Requirement already satisfied: sympy in c:\\users\\zineb\\anaconda3\\lib\\site-packages (from torch) (1.11.1)\n", "Requirement already satisfied: numpy in c:\\users\\zineb\\anaconda3\\lib\\site-packages (from torchvision) (1.23.5)\n", + "Requirement already satisfied: requests in c:\\users\\zineb\\anaconda3\\lib\\site-packages (from torchvision) (2.28.1)\n", "Requirement already satisfied: pillow!=8.3.*,>=5.3.0 in c:\\users\\zineb\\anaconda3\\lib\\site-packages (from torchvision) (9.4.0)\n", "Requirement already satisfied: MarkupSafe>=2.0 in c:\\users\\zineb\\anaconda3\\lib\\site-packages (from jinja2->torch) (2.1.1)\n", - "Requirement already satisfied: idna<4,>=2.5 in c:\\users\\zineb\\anaconda3\\lib\\site-packages (from requests->torchvision) (3.4)\n", + "Requirement already satisfied: urllib3<1.27,>=1.21.1 in c:\\users\\zineb\\anaconda3\\lib\\site-packages (from requests->torchvision) (1.26.14)\n", "Requirement already satisfied: charset-normalizer<3,>=2 in c:\\users\\zineb\\anaconda3\\lib\\site-packages (from requests->torchvision) (2.0.4)\n", + "Requirement already satisfied: idna<4,>=2.5 in c:\\users\\zineb\\anaconda3\\lib\\site-packages (from requests->torchvision) (3.4)\n", "Requirement already satisfied: certifi>=2017.4.17 in c:\\users\\zineb\\anaconda3\\lib\\site-packages (from requests->torchvision) (2022.12.7)\n", - "Requirement already satisfied: urllib3<1.27,>=1.21.1 in c:\\users\\zineb\\anaconda3\\lib\\site-packages (from requests->torchvision) (1.26.14)\n", "Requirement already satisfied: mpmath>=0.19 in c:\\users\\zineb\\anaconda3\\lib\\site-packages (from sympy->torch) (1.2.1)\n", "Note: you may need to restart the kernel to use updated packages.\n" ] @@ -87,7 +87,7 @@ }, { "cell_type": "code", - "execution_count": 3, + "execution_count": 6, "id": "b1950f0a", "metadata": {}, "outputs": [ @@ -95,34 +95,34 @@ "name": "stdout", "output_type": "stream", "text": [ - "tensor([[ 1.1239, -0.1932, -0.3678, 0.6501, -1.6171, 0.8080, -0.6757, 0.7948,\n", - " 1.5157, -1.3117],\n", - " [-0.8269, 0.9166, -1.0019, -0.2305, -0.3064, 1.0889, 0.9980, -0.3777,\n", - " 0.4656, 0.4016],\n", - " [-0.8129, -1.3841, -0.4977, -0.9127, 0.0263, -1.9956, 0.6943, 0.6797,\n", - " -1.2654, 0.3845],\n", - " [ 1.8559, -0.6340, 0.4447, -0.4551, 2.3249, -1.0240, 1.1692, 1.0055,\n", - " 1.1300, -1.1291],\n", - " [-1.2167, -0.1497, -0.3531, 0.3234, 0.0849, -0.9314, 0.2087, 0.1036,\n", - " 0.6657, 0.7696],\n", - " [-0.8422, 0.0149, 0.4670, 0.8750, 0.6934, -0.6946, -0.8375, 0.3733,\n", - " 2.1730, 0.4021],\n", - " [-1.7150, -0.5338, -1.1197, 0.8048, -0.3672, 1.4353, 0.9914, 0.1067,\n", - " -1.5501, -0.3670],\n", - " [ 0.7398, -1.3274, 0.9454, -0.8925, 1.3522, -0.1251, -1.0844, 0.2798,\n", - " 0.8869, 1.9583],\n", - " [ 0.6190, 0.2013, 1.2158, -1.9120, -0.8225, 1.0157, -0.8829, 1.1086,\n", - " 0.3689, -0.7653],\n", - " [-1.4697, 0.1193, 0.1927, 0.1938, 1.2624, 1.4603, -0.5729, 0.7812,\n", - " -0.1746, 0.3517],\n", - " [-2.3466, -0.7611, 0.2812, 0.1764, -0.2962, 1.6342, -0.9823, 1.4876,\n", - " -0.0404, -0.5239],\n", - " [ 0.3076, 0.7985, -1.1781, 1.1919, -1.2734, -0.1057, 0.5247, -0.0806,\n", - " -1.7013, -0.6426],\n", - " [-0.0850, 1.5228, 0.4942, 0.3237, -0.3474, 2.0463, 0.6448, 0.5552,\n", - " 0.9487, -0.2049],\n", - " [ 0.9692, -1.2029, -0.7236, -0.4824, -1.5250, -0.2548, -1.2384, 0.3218,\n", - " -0.4170, 0.0320]])\n", + "tensor([[-1.1210e+00, 5.2764e-01, -3.1968e-01, 2.2298e-02, 3.2028e-01,\n", + " 1.1693e+00, 9.9867e-03, 1.6576e+00, -6.4607e-01, -1.0916e+00],\n", + " [ 1.0161e-01, -1.3867e-01, -1.1610e+00, -5.4409e-01, 3.9804e-01,\n", + " 4.3068e-01, -1.3733e+00, 6.4579e-01, -9.3711e-01, -6.2921e-01],\n", + " [-4.5891e-01, 1.7762e+00, 3.5168e-01, 8.2529e-01, -3.6480e-01,\n", + " -9.3685e-01, 8.2215e-01, 6.8467e-01, -4.3484e-01, 1.7282e+00],\n", + " [ 2.3554e-01, -6.2146e-01, -9.5119e-01, 3.6604e-01, -5.5549e-02,\n", + " -1.5742e-01, 8.4236e-01, -1.6707e+00, 3.5272e-01, 1.2580e-01],\n", + " [-6.1302e-01, -7.8174e-02, 2.0755e+00, -5.7493e-01, 1.8069e+00,\n", + " -1.1747e+00, 1.1533e+00, 4.4674e-01, 8.0904e-01, 1.2371e+00],\n", + " [ 6.5255e-01, -2.4173e-01, -1.1272e-01, -8.6760e-01, 3.9370e-01,\n", + " 2.4600e-01, -1.2426e-01, 3.1234e-01, -4.4381e-01, -3.1786e-01],\n", + " [-1.7306e+00, 8.6443e-01, -4.1809e-02, -1.3328e+00, 9.7420e-01,\n", + " -4.8587e-01, 8.9359e-01, -3.0943e-01, 1.0975e+00, -1.5249e-03],\n", + " [ 1.4104e+00, -1.3197e+00, -9.9384e-01, -1.0551e+00, -9.5739e-02,\n", + " 8.5214e-01, 5.9754e-01, 4.2689e-01, 4.4546e-01, -5.3021e-01],\n", + " [ 7.9181e-01, 4.7276e-01, 1.1692e+00, -4.4760e-01, -4.8100e-01,\n", + " -5.0203e-01, 1.3627e+00, -1.7923e-01, 7.2266e-01, 1.0586e-01],\n", + " [-2.7925e-01, -2.4732e-01, 6.7349e-01, -9.2926e-01, -9.7715e-02,\n", + " 7.5156e-01, 5.2089e-01, 5.8953e-01, -2.2539e-01, 4.2665e-01],\n", + " [ 2.9770e-01, 7.1523e-01, -5.1163e-01, -1.2523e+00, -2.9311e-01,\n", + " 6.6724e-01, 5.6068e-01, 8.2418e-02, -3.0311e-01, 1.3625e+00],\n", + " [ 1.9347e-01, -1.9955e-01, -4.1287e-01, -1.3899e+00, -2.0153e-01,\n", + " 7.8712e-01, -1.1849e+00, -2.5764e-01, -2.4629e-01, -1.4975e-01],\n", + " [ 1.7681e+00, 7.0654e-01, -2.1209e+00, -3.2242e-01, -1.7948e-01,\n", + " 8.7081e-01, 4.8530e-01, -7.2095e-01, -1.3229e+00, 1.9485e-01],\n", + " [ 7.5603e-01, -3.8439e-01, -3.0080e-01, 5.0654e-01, 9.5246e-03,\n", + " 1.8669e+00, -2.6733e+00, -3.4223e-02, -9.7327e-01, 1.1582e-01]])\n", "AlexNet(\n", " (features): Sequential(\n", " (0): Conv2d(3, 64, kernel_size=(11, 11), stride=(4, 4), padding=(2, 2))\n", @@ -192,7 +192,7 @@ }, { "cell_type": "code", - "execution_count": 4, + "execution_count": 7, "id": "6e18f2fd", "metadata": {}, "outputs": [ @@ -226,7 +226,7 @@ }, { "cell_type": "code", - "execution_count": 5, + "execution_count": 8, "id": "462666a2", "metadata": {}, "outputs": [ @@ -529,10 +529,6 @@ "source": [ "import matplotlib.pyplot as plt\n", "\n", - "#On peut détecter un overfitting en surveillant les performances du modèle sur les données\n", - "# d'entraînement et de test au fil du temps. Si les performances du modèle sur les données \n", - "# d'entraînement continuent de s'améliorer tandis que celles sur les données de test diminuent, \n", - "# cela indique un surapprentissage\n", "plt.plot(range(n_epochs), train_loss_list, label='Training Loss')\n", "plt.plot(range(n_epochs), Valid_loss_list, label='Validation Loss')\n", "plt.xlabel(\"Epoch\")\n", @@ -542,6 +538,16 @@ "plt.show() " ] }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "On peut détecter un overfitting en surveillant les performances du modèle sur les données\n", + "d'entraînement et de test au fil du temps. Si les performances du modèle sur les données \n", + "d'entraînement continuent de s'améliorer tandis que celles sur les données de test diminuent, \n", + "cela indique un surapprentissage. Ici dans notre cas à partir de l'epoch 15, on remarque que la valeur de valid_loss commence à augmenter alors que train_loss diminue toujours.\n" + ] + }, { "cell_type": "markdown", "id": "11df8fd4", @@ -552,10 +558,31 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 14, "id": "e93efdfc", "metadata": {}, - "outputs": [], + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Test Loss: 21.195169\n", + "\n", + "Test Accuracy of airplane: 70% (702/1000)\n", + "Test Accuracy of automobile: 77% (775/1000)\n", + "Test Accuracy of bird: 55% (555/1000)\n", + "Test Accuracy of cat: 36% (364/1000)\n", + "Test Accuracy of deer: 55% (557/1000)\n", + "Test Accuracy of dog: 54% (545/1000)\n", + "Test Accuracy of frog: 77% (779/1000)\n", + "Test Accuracy of horse: 65% (657/1000)\n", + "Test Accuracy of ship: 75% (752/1000)\n", + "Test Accuracy of truck: 66% (665/1000)\n", + "\n", + "Test Accuracy (Overall): 63% (6351/10000)\n" + ] + } + ], "source": [ "model.load_state_dict(torch.load(\"./model_cifar.pt\"))\n", "\n", @@ -638,39 +665,344 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 37, "metadata": {}, - "outputs": [], + "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": "code", + "execution_count": 38, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Net2(\n", + " (conv1): Conv2d(3, 16, kernel_size=(3, 3), stride=(1, 1))\n", + " (relu1): ReLU()\n", + " (pool1): 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))\n", + " (relu2): ReLU()\n", + " (pool2): MaxPool2d(kernel_size=2, stride=2, padding=0, dilation=1, ceil_mode=False)\n", + " (conv3): Conv2d(32, 64, kernel_size=(3, 3), stride=(1, 1))\n", + " (relu3): ReLU()\n", + " (pool3): MaxPool2d(kernel_size=2, stride=2, padding=0, dilation=1, ceil_mode=False)\n", + " (adaptive_pool): AdaptiveAvgPool2d(output_size=(1, 1))\n", + " (fc1): Linear(in_features=64, out_features=512, bias=True)\n", + " (relu4): ReLU()\n", + " (dropout1): Dropout(p=0.5, inplace=False)\n", + " (fc2): Linear(in_features=512, out_features=64, bias=True)\n", + " (relu5): ReLU()\n", + " (dropout2): Dropout(p=0.5, inplace=False)\n", + " (fc3): Linear(in_features=64, out_features=10, bias=True)\n", + ")\n" + ] + } + ], "source": [ + "import torch\n", + "import torch.nn as nn\n", "\n", "class Net2(nn.Module):\n", - " def __init__(self, dropout_rate=0.5):\n", + " def __init__(self, dropout_rate=0.5, num_classes=10):\n", " super(Net2, self).__init__()\n", "\n", " # Convolutional layers\n", - " self.conv1 = nn.Conv2d(3, 16,3,1)\n", + " self.conv1 = nn.Conv2d(3, 16, 3, 1)\n", + " self.relu1 = nn.ReLU()\n", + " self.pool1 = nn.MaxPool2d(2)\n", " self.conv2 = nn.Conv2d(16, 32, 3, 1)\n", + " self.relu2 = nn.ReLU()\n", + " self.pool2 = nn.MaxPool2d(2)\n", " self.conv3 = nn.Conv2d(32, 64, 3, 1)\n", - " self.fc1 = nn.Linear(64 * 4 * 4, 512)\n", + " self.relu3 = nn.ReLU()\n", + " self.pool3 = nn.MaxPool2d(2)\n", + "\n", + " # Adaptive pooling to dynamically adjust to input size\n", + " self.adaptive_pool = nn.AdaptiveAvgPool2d((1, 1))\n", + "\n", + " # Fully connected layers\n", + " self.fc1 = nn.Linear(64, 512)\n", + " self.relu4 = nn.ReLU()\n", + " self.dropout1 = nn.Dropout(dropout_rate)\n", + "\n", " self.fc2 = nn.Linear(512, 64)\n", - " self.fc3 = nn.Linear(64, 10)\n", - " self.relu = nn.ReLU()\n", - " self.pool = nn.MaxPool2d(2, 2)\n", - " self.dropout = nn.Dropout(dropout_rate)\n", + " self.relu5 = nn.ReLU()\n", + " self.dropout2 = nn.Dropout(dropout_rate)\n", + "\n", + " self.fc3 = nn.Linear(64, num_classes)\n", "\n", " def forward(self, x):\n", - " x = self.pool(self.relu(self.conv1(x)))\n", - " x = self.pool(self.relu(self.conv2(x)))\n", - " x = self.pool(self.relu(self.conv3(x)))\n", - " x = x.view(-1, 64 * 4 * 4)\n", - " x = self.dropout(self.relu(self.fc1(x)))\n", - " x = self.dropout(self.relu(self.fc2(x)))\n", + " # Convolutional layers\n", + " x = self.pool1(self.relu1(self.conv1(x)))\n", + " x = self.pool2(self.relu2(self.conv2(x)))\n", + " x = self.pool3(self.relu3(self.conv3(x)))\n", + "\n", + " # Adaptive pooling to dynamically adjust to input size\n", + " x = self.adaptive_pool(x)\n", + "\n", + " # Flatten before fully connected layers\n", + " x = x.view(x.size(0), -1)\n", "\n", + " # Fully connected layers\n", + " x = self.dropout1(self.relu4(self.fc1(x)))\n", + " x = self.dropout2(self.relu5(self.fc2(x)))\n", " x = self.fc3(x)\n", + "\n", " return x\n", "\n", - "model = Net2()\n", - "print(model)" + "# Instantiate the model\n", + "model2 = Net2()\n", + "\n", + "# Print the model architecture\n", + "print(model2)\n" + ] + }, + { + "cell_type": "code", + "execution_count": 39, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Epoch: 0 \tTraining Loss: 45.993847 \tValidation Loss: 45.659072\n", + "Validation loss decreased (inf --> 45.659072). Saving model ...\n", + "Epoch: 1 \tTraining Loss: 42.969891 \tValidation Loss: 39.458595\n", + "Validation loss decreased (45.659072 --> 39.458595). Saving model ...\n", + "Epoch: 2 \tTraining Loss: 38.748317 \tValidation Loss: 36.780595\n", + "Validation loss decreased (39.458595 --> 36.780595). Saving model ...\n", + "Epoch: 3 \tTraining Loss: 36.406563 \tValidation Loss: 34.876807\n", + "Validation loss decreased (36.780595 --> 34.876807). Saving model ...\n", + "Epoch: 4 \tTraining Loss: 34.736435 \tValidation Loss: 32.692011\n", + "Validation loss decreased (34.876807 --> 32.692011). Saving model ...\n", + "Epoch: 5 \tTraining Loss: 33.093783 \tValidation Loss: 32.273968\n", + "Validation loss decreased (32.692011 --> 32.273968). Saving model ...\n", + "Epoch: 6 \tTraining Loss: 32.013036 \tValidation Loss: 29.922774\n", + "Validation loss decreased (32.273968 --> 29.922774). Saving model ...\n", + "Epoch: 7 \tTraining Loss: 31.049389 \tValidation Loss: 28.974758\n", + "Validation loss decreased (29.922774 --> 28.974758). Saving model ...\n", + "Epoch: 8 \tTraining Loss: 30.163901 \tValidation Loss: 28.224655\n", + "Validation loss decreased (28.974758 --> 28.224655). Saving model ...\n", + "Epoch: 9 \tTraining Loss: 29.254000 \tValidation Loss: 27.222523\n", + "Validation loss decreased (28.224655 --> 27.222523). Saving model ...\n", + "Epoch: 10 \tTraining Loss: 28.108061 \tValidation Loss: 26.104135\n", + "Validation loss decreased (27.222523 --> 26.104135). Saving model ...\n", + "Epoch: 11 \tTraining Loss: 27.228062 \tValidation Loss: 25.670827\n", + "Validation loss decreased (26.104135 --> 25.670827). Saving model ...\n", + "Epoch: 12 \tTraining Loss: 26.315241 \tValidation Loss: 24.450983\n", + "Validation loss decreased (25.670827 --> 24.450983). Saving model ...\n", + "Epoch: 13 \tTraining Loss: 25.466175 \tValidation Loss: 23.767074\n", + "Validation loss decreased (24.450983 --> 23.767074). Saving model ...\n", + "Epoch: 14 \tTraining Loss: 24.800794 \tValidation Loss: 23.662658\n", + "Validation loss decreased (23.767074 --> 23.662658). Saving model ...\n", + "Epoch: 15 \tTraining Loss: 24.069690 \tValidation Loss: 22.466158\n", + "Validation loss decreased (23.662658 --> 22.466158). Saving model ...\n", + "Epoch: 16 \tTraining Loss: 23.422421 \tValidation Loss: 21.784056\n", + "Validation loss decreased (22.466158 --> 21.784056). Saving model ...\n", + "Epoch: 17 \tTraining Loss: 22.939551 \tValidation Loss: 21.506103\n", + "Validation loss decreased (21.784056 --> 21.506103). Saving model ...\n", + "Epoch: 18 \tTraining Loss: 22.376958 \tValidation Loss: 21.859394\n", + "Epoch: 19 \tTraining Loss: 21.936516 \tValidation Loss: 20.984741\n", + "Validation loss decreased (21.506103 --> 20.984741). Saving model ...\n", + "Epoch: 20 \tTraining Loss: 21.373166 \tValidation Loss: 20.880130\n", + "Validation loss decreased (20.984741 --> 20.880130). Saving model ...\n", + "Epoch: 21 \tTraining Loss: 20.836367 \tValidation Loss: 20.546615\n", + "Validation loss decreased (20.880130 --> 20.546615). Saving model ...\n", + "Epoch: 22 \tTraining Loss: 20.522886 \tValidation Loss: 20.174353\n", + "Validation loss decreased (20.546615 --> 20.174353). Saving model ...\n", + "Epoch: 23 \tTraining Loss: 20.074364 \tValidation Loss: 19.755045\n", + "Validation loss decreased (20.174353 --> 19.755045). Saving model ...\n", + "Epoch: 24 \tTraining Loss: 19.662466 \tValidation Loss: 20.041506\n", + "Epoch: 25 \tTraining Loss: 19.304117 \tValidation Loss: 19.140105\n", + "Validation loss decreased (19.755045 --> 19.140105). Saving model ...\n", + "Epoch: 26 \tTraining Loss: 19.006838 \tValidation Loss: 19.709049\n", + "Epoch: 27 \tTraining Loss: 18.619268 \tValidation Loss: 19.128607\n", + "Validation loss decreased (19.140105 --> 19.128607). Saving model ...\n", + "Epoch: 28 \tTraining Loss: 18.314379 \tValidation Loss: 18.985464\n", + "Validation loss decreased (19.128607 --> 18.985464). Saving model ...\n", + "Epoch: 29 \tTraining Loss: 18.055548 \tValidation Loss: 19.365814\n" + ] + } + ], + "source": [ + "import torch.optim as optim\n", + "\n", + "criterion = nn.CrossEntropyLoss() # specify loss function\n", + "optimizer = optim.SGD(model2.parameters(), lr=0.01) # specify optimizer\n", + "\n", + "n_epochs = 30 # number of epochs to train the model\n", + "train_loss_list2 = [] # list to store loss to visualize\n", + "Valid_loss_list2 = []\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", + " model2.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 = model2(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", + " model2.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 = model2(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_list2.append(train_loss)\n", + " Valid_loss_list2.append(valid_loss)\n", + " \n", + "\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(model2.state_dict(), \"model_cifar.pt\")\n", + " valid_loss_min = valid_loss\n", + "\n", + " " + ] + }, + { + "cell_type": "code", + "execution_count": 45, + "metadata": {}, + "outputs": [ + { + "data": { + "image/png": "iVBORw0KGgoAAAANSUhEUgAAAjQAAAHFCAYAAADlrWMiAAAAOXRFWHRTb2Z0d2FyZQBNYXRwbG90bGliIHZlcnNpb24zLjcuMCwgaHR0cHM6Ly9tYXRwbG90bGliLm9yZy88F64QAAAACXBIWXMAAA9hAAAPYQGoP6dpAABx8klEQVR4nO3dd3RU1d7G8e9MeockpEEIoST03pHeEaTotYAINkRF5aoXrmABC1hevWLDdgU7XqWIitJ774ReAwESAoR00s/7x5BgQktCJpOE57PWLM6cOeU3w8g87rPP3ibDMAxEREREyjGzrQsQERERuVkKNCIiIlLuKdCIiIhIuadAIyIiIuWeAo2IiIiUewo0IiIiUu4p0IiIiEi5p0AjIiIi5Z4CjYiIiJR7CjQiJWjmzJmYTKa8h729PdWqVePBBx/k1KlTJXqujIwMRo8eTWBgIHZ2djRt2rREjy8WI0eOpEaNGrYuo0SZTCYmTZpU5P0iIyMxmUzMnDmzxGsSuVn2ti5ApCKaMWMGdevW5eLFi6xatYqpU6eycuVKIiIicHNzK5FzTJ8+nc8++4wPP/yQFi1a4O7uXiLHFREpjxRoRKygYcOGtGzZEoCuXbuSnZ3Na6+9xrx58xg2bNhNHTs1NRVXV1d2796Ni4sLY8aMKYmSAbh48SIuLi4ldjwRkdKiS04ipaBt27YAHD9+HADDMPjkk09o2rQpLi4uVK5cmbvuuoujR4/m269Lly40bNiQVatW0b59e1xdXXnooYcwmUx8+eWXXLx4Me/yVu5lgLS0NF544QVCQ0NxdHSkatWqPPnkk8THx+c7do0aNejfvz9z5syhWbNmODs7M3nyZFasWIHJZOKHH35g/PjxBAYG4u7uzoABAzhz5gxJSUmMGjUKX19ffH19efDBB0lOTs537I8//phOnTrh5+eHm5sbjRo14u233yYzM/Oq72/z5s107NgRV1dXatasyZtvvklOTk6+bePj43nuueeoWbMmTk5O+Pn50a9fP/bv35+3TUZGBq+//jp169bFycmJKlWq8OCDD3L27NlC/T3NnDmT8PBwnJycqFevHt98880V2+R+PitWrMi3vrCXY3IvSy5btoxHH30UHx8fPD09eeCBB0hJSSEmJoa7776bSpUqERgYyPPPP3/F5xYXF8cTTzxB1apVcXR0pGbNmkycOJH09PR82yUmJuadw93dnT59+nDw4MGr1nXo0CGGDh2Kn59f3vv/+OOPb/yhiZQRaqERKQWHDx8GoEqVKgA89thjzJw5k6effpq33nqLuLg4Xn31Vdq3b8/OnTvx9/fP2zc6Opr777+fcePGMWXKFMxmM2PHjuW1115j+fLlLFu2DIBatWphGAaDBg1i6dKlvPDCC3Ts2JFdu3bxyiuvsH79etavX4+Tk1Pesbdt28a+fft48cUXCQ0Nxc3NjZSUFAAmTJhA165dmTlzJpGRkTz//PPcd9992Nvb06RJE3788Ue2b9/OhAkT8PDw4IMPPsg77pEjRxg6dGheqNq5cydvvPEG+/fv56uvvsr32cTExDBs2DCee+45XnnlFebOncsLL7xAUFAQDzzwAABJSUncdtttREZGMn78eNq0aUNycjKrVq0iOjqaunXrkpOTw8CBA1m9ejXjxo2jffv2HD9+nFdeeYUuXbqwZcuW67Y+zZw5kwcffJCBAwfy7rvvkpCQwKRJk0hPT8dsLvn/93vkkUcYMmQIs2bNyvscs7KyOHDgAEOGDGHUqFEsWbKEt956i6CgIJ599lnAEli7du3KkSNHmDx5Mo0bN2b16tVMnTqVHTt28McffwDkfRfWrVvHyy+/TKtWrVi7di19+/a9opa9e/fSvn17qlevzrvvvktAQAALFy7k6aef5ty5c7zyyisl/v5FSpwhIiVmxowZBmBs2LDByMzMNJKSkozff//dqFKliuHh4WHExMQY69evNwDj3XffzbdvVFSU4eLiYowbNy5vXefOnQ3AWLp06RXnGjFihOHm5pZv3V9//WUAxttvv51v/U8//WQAxueff563LiQkxLCzszMOHDiQb9vly5cbgDFgwIB868eOHWsAxtNPP51v/aBBgwxvb+9rfibZ2dlGZmam8c033xh2dnZGXFzcFe9v48aN+fapX7++0bt377znr776qgEYixcvvuZ5fvzxRwMwZs+enW/95s2bDcD45JNPrltjUFCQ0bx5cyMnJydvfWRkpOHg4GCEhITkrcv9fJYvX57vGMeOHTMAY8aMGdc8j2Fc/o489dRT+dYPGjTIAIz33nsv3/qmTZsazZs3z3v+6aefGoDxv//9L992b731lgEYixYtMgzDMP78808DMKZNm5ZvuzfeeMMAjFdeeSVvXe/evY1q1aoZCQkJ+bYdM2aM4ezsnPd3Vtj3KGILuuQkYgVt27bFwcEBDw8P+vfvT0BAAH/++Sf+/v78/vvvmEwm7r//frKysvIeAQEBNGnS5IpLGZUrV6Zbt26FOm9ua83IkSPzrf/HP/6Bm5sbS5cuzbe+cePGhIWFXfVY/fv3z/e8Xr16ANx+++1XrI+Li8t32Wn79u3ccccd+Pj4YGdnh4ODAw888ADZ2dlXXPIICAigdevWV9SVe3kO4M8//yQsLIwePXpc663z+++/U6lSJQYMGJDvc23atCkBAQFXfK5/d+DAAU6fPs3QoUMxmUx560NCQmjfvv0197sZRfl8//5ZLFu2DDc3N+6666582+X+nef+HS9fvhzgij5bQ4cOzfc8LS2NpUuXMnjwYFxdXfN9dv369SMtLY0NGzYU812KlB5dchKxgm+++YZ69ephb2+Pv78/gYGBea+dOXMGwzDyXVb6u5o1a+Z7/vd9b+T8+fPY29vnXdrKZTKZCAgI4Pz584U+tre3d77njo6O112flpaGu7s7J06coGPHjoSHhzNt2jRq1KiBs7MzmzZt4sknn+TixYv59vfx8bni3E5OTvm2O3v2LNWrV79mrWD5XOPj4/PqKejcuXPX3Df3cwkICLjitYCAACIjI6977uIoyueblpaW9/z8+fMEBATkC14Afn5+2Nvb572X3O9Cwc+34Hs8f/48WVlZfPjhh3z44YdXrfV6n51IWaFAI2IF9erVy7vLqSBfX19MJhOrV6/O158lV8F1BX+4rsfHx4esrCzOnj2bL9QYhkFMTAytWrUq9rELa968eaSkpDBnzhxCQkLy1u/YsaPYx6xSpQonT5687ja+vr74+Pjw119/XfV1Dw+Pa+6b+6MfExNzxWsF1zk7OwNc0QG3tH70fXx82LhxI4Zh5Pv7i42NJSsrC19f37ztsrKyOH/+fL5QU/D9VK5cGTs7O4YPH86TTz551XOGhoZa4Z2IlCxdchIpZf3798cwDE6dOkXLli2veDRq1KjYx+7evTsA3333Xb71s2fPJiUlJe91a8r9kf17MDMMgy+++KLYx+zbty8HDx7Mu6R2Nf379+f8+fNkZ2df9XMNDw+/5r7h4eEEBgby448/YhhG3vrjx4+zbt26fNvmDrK3a9eufOvnz59fjHdWdN27dyc5OZl58+blW597R1bu33HXrl0B+P777/Nt98MPP+R77urqSteuXdm+fTuNGze+6md3tVY0kbJGLTQipaxDhw6MGjWKBx98kC1bttCpUyfc3NyIjo5mzZo1NGrUiMcff7xYx+7Zsye9e/dm/PjxJCYm0qFDh7y7nJo1a8bw4cNL+N1cvQZHR0fuu+8+xo0bR1paGtOnT+fChQvFPubYsWP56aefGDhwIP/+979p3bo1Fy9eZOXKlfTv35+uXbty77338v3339OvXz+eeeYZWrdujYODAydPnmT58uUMHDiQwYMHX/X4ZrOZ1157jUceeYTBgwfz6KOPEh8fz6RJk664RBMQEECPHj2YOnUqlStXJiQkhKVLlzJnzpxiv7+ieOCBB/j4448ZMWIEkZGRNGrUiDVr1jBlyhT69euX18+oV69edOrUiXHjxpGSkkLLli1Zu3Yt33777RXHnDZtGrfddhsdO3bk8ccfp0aNGiQlJXH48GF+++236wZJkbJCgUbEBj777DPatm3LZ599xieffEJOTg5BQUF06NDhig6yRWEymZg3bx6TJk1ixowZvPHGG/j6+jJ8+HCmTJly1UtcJa1u3brMnj2bF198kSFDhuDj48PQoUN59tlnr3rLcGF4eHiwZs0aJk2axOeff87kyZOpXLkyrVq1YtSoUQDY2dkxf/58pk2bxrfffsvUqVPzpp7o3LnzDVu+Hn74YQDeeusthgwZQo0aNZgwYQIrV668okPxt99+y1NPPcX48ePJzs5mwIAB/Pjjj9e8zFiSnJ2dWb58ORMnTuSdd97h7NmzVK1aleeffz7f7dVms5n58+fz7LPP8vbbb5ORkUGHDh1YsGABdevWzXfM+vXrs23bNl577TVefPFFYmNjqVSpEnXq1KFfv35Wf08iJcFk/L19VURERKQcUh8aERERKfcUaERERKTcU6ARERGRck+BRkRERMo9BRoREREp9xRoREREpNyr8OPQ5OTkcPr0aTw8PKwyzLuIiIiUPMMwSEpKIigoCLP5xu0vFT7QnD59muDgYFuXISIiIsUQFRVFtWrVbrhdhQ80uRPSRUVF4enpaeNqREREpDASExMJDg6+7sSyf1fhA03uZSZPT08FGhERkXKmsN1F1ClYREREyj0FGhERESn3FGhERESk3KvwfWhERKTiyc7OJjMz09ZlyE1wcHDAzs6uxI6nQCMiIuWGYRjExMQQHx9v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W09c4FxyurWrExERKbfKRKDZvHkzn3/+OY0bN863/u233+a9997jo48+YvPmzQQEBNCzZ0+SkpJsVOlNcnIH33DLciFaaQK9XGhY1RPDgGX7NVmliIjItdg80CQnJzNs2DC++OILKleunLfeMAzef/99Jk6cyJAhQ2jYsCFff/01qamp/PDDDzas+CYVYTwagJ71AgBddhIREbkemweaJ598kttvv50ePXrkW3/s2DFiYmLo1atX3jonJyc6d+7MunXrrnm89PR0EhMT8z3KlKrNLH8WYsRggB71Lf1oVh86R1pmtrWqEhERKddsGmhmzZrFtm3bmDp16hWvxcRY+pj4+/vnW+/v75/32tVMnToVLy+vvEdwcHDJFn2z/t4x2LjxtAb1Az2pWsmFi5nZrD2sySpFRESuxmaBJioqimeeeYbvvvsOZ2fna25nMpnyPTcM44p1f/fCCy+QkJCQ94iKiiqxmkuEXwOwc4S0eIg7esPNTSYTPepp1GAREZHrsVmg2bp1K7GxsbRo0QJ7e3vs7e1ZuXIlH3zwAfb29nktMwVbY2JjY69otfk7JycnPD098z3KFHtHCGhkWT69vVC75N7ttGRfLDmarFJEROQKNgs03bt3JyIigh07duQ9WrZsybBhw9ixYwc1a9YkICCAxYsX5+2TkZHBypUrad++va3KLhlF7BjcJtQHDyd7ziWns/NkvPXqEhERKafsbXViDw8PGjZsmG+dm5sbPj4+eevHjh3LlClTqFOnDnXq1GHKlCm4uroydOhQW5RccoowYjCAo72ZzuFV+H1XNIv3nqFZ9co33klEROQWYvO7nK5n3LhxjB07lieeeIKWLVty6tQpFi1ahIeHh61Luzm5LTTROyE7q1C79My77KR+NCIiIgWZDKMQt9qUY4mJiXh5eZGQkFB2+tPk5MBbNSA9Ae6fDbV73HCXhNRMWry+mKwcg5X/6kKIj5v16xQREbGRov5+l+kWmgrLbIam91mWV79XqF28XB1oHeoN6G4nERGRghRobKX902B2gONr4fi1Bwr8O112EhERuToFGlvxqgrNhlmWV/1foXbpUc8SaDZHXiA+NcNalYmIiJQ7CjS21GEsmOzgyNJC3cId7O1K3QAPsnMMlh/QZJUiIiK5FGhsyTsUGv3DslzIvjS5l53Uj0ZEROQyBRpb6/gsYIL9v8OZ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", + "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_list2, label='train_loss')\n", + "plt.plot(range(n_epochs), Valid_loss_list2, label='Valid_loss')\n", + "\n", + "plt.xlabel(\"Epoch\")\n", + "plt.ylabel(\"Loss\")\n", + "plt.title(\"Performance du model\")\n", + "plt.legend()\n", + "plt.show()" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Le nouveau modèle est beaucoup plus performant, on a pas de problème d'overfitting ." ] }, {