diff --git a/TD2 Deep Learning.ipynb b/TD2 Deep Learning.ipynb index a14730c70f2925de4771746599ddab5a8f6b1fa7..a0419bff522999898d96e3bf5dd36ee65d3922e3 100644 --- a/TD2 Deep Learning.ipynb +++ b/TD2 Deep Learning.ipynb @@ -157,10 +157,18 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 2, "id": "6e18f2fd", "metadata": {}, - "outputs": [], + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "CUDA is not available. Training on CPU ...\n" + ] + } + ], "source": [ "import torch\n", "\n", @@ -183,10 +191,33 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 3, "id": "462666a2", "metadata": {}, - "outputs": [], + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Downloading https://www.cs.toronto.edu/~kriz/cifar-10-python.tar.gz to data\\cifar-10-python.tar.gz\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + "100%|██████████| 170M/170M [00:17<00:00, 9.66MB/s] \n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Extracting data\\cifar-10-python.tar.gz to data\n", + "Files already downloaded and verified\n" + ] + } + ], "source": [ "import numpy as np\n", "from torchvision import datasets, transforms\n", @@ -255,10 +286,25 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 30, "id": "317bf070", "metadata": {}, - "outputs": [], + "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", @@ -304,10 +350,65 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 31, "id": "4b53f229", "metadata": {}, - "outputs": [], + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Epoch: 0 \tTraining Loss: 43.310613 \tValidation Loss: 38.297743\n", + "Validation loss decreased (inf --> 38.297743). Saving model ...\n", + "Epoch: 1 \tTraining Loss: 34.186083 \tValidation Loss: 30.914800\n", + "Validation loss decreased (38.297743 --> 30.914800). Saving model ...\n", + "Epoch: 2 \tTraining Loss: 30.325666 \tValidation Loss: 28.688646\n", + "Validation loss decreased (30.914800 --> 28.688646). Saving model ...\n", + "Epoch: 3 \tTraining Loss: 28.072272 \tValidation Loss: 27.418195\n", + "Validation loss decreased (28.688646 --> 27.418195). Saving model ...\n", + "Epoch: 4 \tTraining Loss: 26.500710 \tValidation Loss: 25.774103\n", + "Validation loss decreased (27.418195 --> 25.774103). Saving model ...\n", + "Epoch: 5 \tTraining Loss: 25.252793 \tValidation Loss: 25.000141\n", + "Validation loss decreased (25.774103 --> 25.000141). Saving model ...\n", + "Epoch: 6 \tTraining Loss: 24.158602 \tValidation Loss: 23.680893\n", + "Validation loss decreased (25.000141 --> 23.680893). Saving model ...\n", + "Epoch: 7 \tTraining Loss: 23.210504 \tValidation Loss: 23.369460\n", + "Validation loss decreased (23.680893 --> 23.369460). Saving model ...\n", + "Epoch: 8 \tTraining Loss: 22.340226 \tValidation Loss: 23.335326\n", + "Validation loss decreased (23.369460 --> 23.335326). Saving model ...\n", + "Epoch: 9 \tTraining Loss: 21.590825 \tValidation Loss: 22.373804\n", + "Validation loss decreased (23.335326 --> 22.373804). Saving model ...\n", + "Epoch: 10 \tTraining Loss: 20.892846 \tValidation Loss: 22.866940\n", + "Epoch: 11 \tTraining Loss: 20.180947 \tValidation Loss: 21.824822\n", + "Validation loss decreased (22.373804 --> 21.824822). Saving model ...\n", + "Epoch: 12 \tTraining Loss: 19.453305 \tValidation Loss: 22.748037\n", + "Epoch: 13 \tTraining Loss: 18.863672 \tValidation Loss: 22.272626\n", + "Epoch: 14 \tTraining Loss: 18.243816 \tValidation Loss: 22.050470\n" + ] + }, + { + "ename": "KeyboardInterrupt", + "evalue": "", + "output_type": "error", + "traceback": [ + "\u001b[1;31m---------------------------------------------------------------------------\u001b[0m", + "\u001b[1;31mKeyboardInterrupt\u001b[0m Traceback (most recent call last)", + "Cell \u001b[1;32mIn[31], line 17\u001b[0m\n\u001b[0;32m 15\u001b[0m \u001b[38;5;66;03m# Train the model\u001b[39;00m\n\u001b[0;32m 16\u001b[0m model\u001b[38;5;241m.\u001b[39mtrain()\n\u001b[1;32m---> 17\u001b[0m \u001b[43m\u001b[49m\u001b[38;5;28;43;01mfor\u001b[39;49;00m\u001b[43m \u001b[49m\u001b[43mdata\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43mtarget\u001b[49m\u001b[43m \u001b[49m\u001b[38;5;129;43;01min\u001b[39;49;00m\u001b[43m \u001b[49m\u001b[43mtrain_loader\u001b[49m\u001b[43m:\u001b[49m\n\u001b[0;32m 18\u001b[0m \u001b[43m \u001b[49m\u001b[38;5;66;43;03m# Move tensors to GPU if CUDA is available\u001b[39;49;00m\n\u001b[0;32m 19\u001b[0m \u001b[43m \u001b[49m\u001b[38;5;28;43;01mif\u001b[39;49;00m\u001b[43m \u001b[49m\u001b[43mtrain_on_gpu\u001b[49m\u001b[43m:\u001b[49m\n\u001b[0;32m 20\u001b[0m \u001b[43m \u001b[49m\u001b[43mdata\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43mtarget\u001b[49m\u001b[43m \u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[43m \u001b[49m\u001b[43mdata\u001b[49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43mcuda\u001b[49m\u001b[43m(\u001b[49m\u001b[43m)\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43mtarget\u001b[49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43mcuda\u001b[49m\u001b[43m(\u001b[49m\u001b[43m)\u001b[49m\n", + "File \u001b[1;32m~\\AppData\\Local\\Packages\\PythonSoftwareFoundation.Python.3.11_qbz5n2kfra8p0\\LocalCache\\local-packages\\Python311\\site-packages\\torch\\utils\\data\\dataloader.py:701\u001b[0m, in \u001b[0;36m_BaseDataLoaderIter.__next__\u001b[1;34m(self)\u001b[0m\n\u001b[0;32m 698\u001b[0m \u001b[38;5;28;01mif\u001b[39;00m \u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39m_sampler_iter \u001b[38;5;129;01mis\u001b[39;00m \u001b[38;5;28;01mNone\u001b[39;00m:\n\u001b[0;32m 699\u001b[0m \u001b[38;5;66;03m# TODO(https://github.com/pytorch/pytorch/issues/76750)\u001b[39;00m\n\u001b[0;32m 700\u001b[0m \u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39m_reset() \u001b[38;5;66;03m# type: ignore[call-arg]\u001b[39;00m\n\u001b[1;32m--> 701\u001b[0m data \u001b[38;5;241m=\u001b[39m \u001b[38;5;28;43mself\u001b[39;49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43m_next_data\u001b[49m\u001b[43m(\u001b[49m\u001b[43m)\u001b[49m\n\u001b[0;32m 702\u001b[0m \u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39m_num_yielded \u001b[38;5;241m+\u001b[39m\u001b[38;5;241m=\u001b[39m \u001b[38;5;241m1\u001b[39m\n\u001b[0;32m 703\u001b[0m \u001b[38;5;28;01mif\u001b[39;00m (\n\u001b[0;32m 704\u001b[0m \u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39m_dataset_kind \u001b[38;5;241m==\u001b[39m _DatasetKind\u001b[38;5;241m.\u001b[39mIterable\n\u001b[0;32m 705\u001b[0m \u001b[38;5;129;01mand\u001b[39;00m \u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39m_IterableDataset_len_called \u001b[38;5;129;01mis\u001b[39;00m \u001b[38;5;129;01mnot\u001b[39;00m \u001b[38;5;28;01mNone\u001b[39;00m\n\u001b[0;32m 706\u001b[0m \u001b[38;5;129;01mand\u001b[39;00m \u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39m_num_yielded \u001b[38;5;241m>\u001b[39m \u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39m_IterableDataset_len_called\n\u001b[0;32m 707\u001b[0m ):\n", + "File \u001b[1;32m~\\AppData\\Local\\Packages\\PythonSoftwareFoundation.Python.3.11_qbz5n2kfra8p0\\LocalCache\\local-packages\\Python311\\site-packages\\torch\\utils\\data\\dataloader.py:757\u001b[0m, in \u001b[0;36m_SingleProcessDataLoaderIter._next_data\u001b[1;34m(self)\u001b[0m\n\u001b[0;32m 755\u001b[0m \u001b[38;5;28;01mdef\u001b[39;00m \u001b[38;5;21m_next_data\u001b[39m(\u001b[38;5;28mself\u001b[39m):\n\u001b[0;32m 756\u001b[0m index \u001b[38;5;241m=\u001b[39m \u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39m_next_index() \u001b[38;5;66;03m# may raise StopIteration\u001b[39;00m\n\u001b[1;32m--> 757\u001b[0m data \u001b[38;5;241m=\u001b[39m \u001b[38;5;28;43mself\u001b[39;49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43m_dataset_fetcher\u001b[49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43mfetch\u001b[49m\u001b[43m(\u001b[49m\u001b[43mindex\u001b[49m\u001b[43m)\u001b[49m \u001b[38;5;66;03m# may raise StopIteration\u001b[39;00m\n\u001b[0;32m 758\u001b[0m \u001b[38;5;28;01mif\u001b[39;00m \u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39m_pin_memory:\n\u001b[0;32m 759\u001b[0m data \u001b[38;5;241m=\u001b[39m _utils\u001b[38;5;241m.\u001b[39mpin_memory\u001b[38;5;241m.\u001b[39mpin_memory(data, \u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39m_pin_memory_device)\n", + "File \u001b[1;32m~\\AppData\\Local\\Packages\\PythonSoftwareFoundation.Python.3.11_qbz5n2kfra8p0\\LocalCache\\local-packages\\Python311\\site-packages\\torch\\utils\\data\\_utils\\fetch.py:52\u001b[0m, in \u001b[0;36m_MapDatasetFetcher.fetch\u001b[1;34m(self, possibly_batched_index)\u001b[0m\n\u001b[0;32m 50\u001b[0m data \u001b[38;5;241m=\u001b[39m \u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39mdataset\u001b[38;5;241m.\u001b[39m__getitems__(possibly_batched_index)\n\u001b[0;32m 51\u001b[0m \u001b[38;5;28;01melse\u001b[39;00m:\n\u001b[1;32m---> 52\u001b[0m data \u001b[38;5;241m=\u001b[39m \u001b[43m[\u001b[49m\u001b[38;5;28;43mself\u001b[39;49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43mdataset\u001b[49m\u001b[43m[\u001b[49m\u001b[43midx\u001b[49m\u001b[43m]\u001b[49m\u001b[43m \u001b[49m\u001b[38;5;28;43;01mfor\u001b[39;49;00m\u001b[43m \u001b[49m\u001b[43midx\u001b[49m\u001b[43m \u001b[49m\u001b[38;5;129;43;01min\u001b[39;49;00m\u001b[43m \u001b[49m\u001b[43mpossibly_batched_index\u001b[49m\u001b[43m]\u001b[49m\n\u001b[0;32m 53\u001b[0m \u001b[38;5;28;01melse\u001b[39;00m:\n\u001b[0;32m 54\u001b[0m data \u001b[38;5;241m=\u001b[39m \u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39mdataset[possibly_batched_index]\n", + "File \u001b[1;32m~\\AppData\\Local\\Packages\\PythonSoftwareFoundation.Python.3.11_qbz5n2kfra8p0\\LocalCache\\local-packages\\Python311\\site-packages\\torch\\utils\\data\\_utils\\fetch.py:52\u001b[0m, in \u001b[0;36m<listcomp>\u001b[1;34m(.0)\u001b[0m\n\u001b[0;32m 50\u001b[0m data \u001b[38;5;241m=\u001b[39m \u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39mdataset\u001b[38;5;241m.\u001b[39m__getitems__(possibly_batched_index)\n\u001b[0;32m 51\u001b[0m \u001b[38;5;28;01melse\u001b[39;00m:\n\u001b[1;32m---> 52\u001b[0m data \u001b[38;5;241m=\u001b[39m [\u001b[38;5;28;43mself\u001b[39;49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43mdataset\u001b[49m\u001b[43m[\u001b[49m\u001b[43midx\u001b[49m\u001b[43m]\u001b[49m \u001b[38;5;28;01mfor\u001b[39;00m idx \u001b[38;5;129;01min\u001b[39;00m possibly_batched_index]\n\u001b[0;32m 53\u001b[0m \u001b[38;5;28;01melse\u001b[39;00m:\n\u001b[0;32m 54\u001b[0m data \u001b[38;5;241m=\u001b[39m \u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39mdataset[possibly_batched_index]\n", + "File \u001b[1;32m~\\AppData\\Local\\Packages\\PythonSoftwareFoundation.Python.3.11_qbz5n2kfra8p0\\LocalCache\\local-packages\\Python311\\site-packages\\torchvision\\datasets\\cifar.py:119\u001b[0m, in \u001b[0;36mCIFAR10.__getitem__\u001b[1;34m(self, index)\u001b[0m\n\u001b[0;32m 116\u001b[0m img \u001b[38;5;241m=\u001b[39m Image\u001b[38;5;241m.\u001b[39mfromarray(img)\n\u001b[0;32m 118\u001b[0m \u001b[38;5;28;01mif\u001b[39;00m \u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39mtransform \u001b[38;5;129;01mis\u001b[39;00m \u001b[38;5;129;01mnot\u001b[39;00m \u001b[38;5;28;01mNone\u001b[39;00m:\n\u001b[1;32m--> 119\u001b[0m img \u001b[38;5;241m=\u001b[39m \u001b[38;5;28;43mself\u001b[39;49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43mtransform\u001b[49m\u001b[43m(\u001b[49m\u001b[43mimg\u001b[49m\u001b[43m)\u001b[49m\n\u001b[0;32m 121\u001b[0m \u001b[38;5;28;01mif\u001b[39;00m \u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39mtarget_transform \u001b[38;5;129;01mis\u001b[39;00m \u001b[38;5;129;01mnot\u001b[39;00m \u001b[38;5;28;01mNone\u001b[39;00m:\n\u001b[0;32m 122\u001b[0m target \u001b[38;5;241m=\u001b[39m \u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39mtarget_transform(target)\n", + "File \u001b[1;32m~\\AppData\\Local\\Packages\\PythonSoftwareFoundation.Python.3.11_qbz5n2kfra8p0\\LocalCache\\local-packages\\Python311\\site-packages\\torchvision\\transforms\\transforms.py:95\u001b[0m, in \u001b[0;36mCompose.__call__\u001b[1;34m(self, img)\u001b[0m\n\u001b[0;32m 93\u001b[0m \u001b[38;5;28;01mdef\u001b[39;00m \u001b[38;5;21m__call__\u001b[39m(\u001b[38;5;28mself\u001b[39m, img):\n\u001b[0;32m 94\u001b[0m \u001b[38;5;28;01mfor\u001b[39;00m t \u001b[38;5;129;01min\u001b[39;00m \u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39mtransforms:\n\u001b[1;32m---> 95\u001b[0m img \u001b[38;5;241m=\u001b[39m \u001b[43mt\u001b[49m\u001b[43m(\u001b[49m\u001b[43mimg\u001b[49m\u001b[43m)\u001b[49m\n\u001b[0;32m 96\u001b[0m \u001b[38;5;28;01mreturn\u001b[39;00m img\n", + "File \u001b[1;32m~\\AppData\\Local\\Packages\\PythonSoftwareFoundation.Python.3.11_qbz5n2kfra8p0\\LocalCache\\local-packages\\Python311\\site-packages\\torch\\nn\\modules\\module.py:1736\u001b[0m, in \u001b[0;36mModule._wrapped_call_impl\u001b[1;34m(self, *args, **kwargs)\u001b[0m\n\u001b[0;32m 1734\u001b[0m \u001b[38;5;28;01mreturn\u001b[39;00m \u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39m_compiled_call_impl(\u001b[38;5;241m*\u001b[39margs, \u001b[38;5;241m*\u001b[39m\u001b[38;5;241m*\u001b[39mkwargs) \u001b[38;5;66;03m# type: ignore[misc]\u001b[39;00m\n\u001b[0;32m 1735\u001b[0m \u001b[38;5;28;01melse\u001b[39;00m:\n\u001b[1;32m-> 1736\u001b[0m \u001b[38;5;28;01mreturn\u001b[39;00m \u001b[38;5;28;43mself\u001b[39;49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43m_call_impl\u001b[49m\u001b[43m(\u001b[49m\u001b[38;5;241;43m*\u001b[39;49m\u001b[43margs\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[38;5;241;43m*\u001b[39;49m\u001b[38;5;241;43m*\u001b[39;49m\u001b[43mkwargs\u001b[49m\u001b[43m)\u001b[49m\n", + "File \u001b[1;32m~\\AppData\\Local\\Packages\\PythonSoftwareFoundation.Python.3.11_qbz5n2kfra8p0\\LocalCache\\local-packages\\Python311\\site-packages\\torch\\nn\\modules\\module.py:1747\u001b[0m, in \u001b[0;36mModule._call_impl\u001b[1;34m(self, *args, **kwargs)\u001b[0m\n\u001b[0;32m 1742\u001b[0m \u001b[38;5;66;03m# If we don't have any hooks, we want to skip the rest of the logic in\u001b[39;00m\n\u001b[0;32m 1743\u001b[0m \u001b[38;5;66;03m# this function, and just call forward.\u001b[39;00m\n\u001b[0;32m 1744\u001b[0m \u001b[38;5;28;01mif\u001b[39;00m \u001b[38;5;129;01mnot\u001b[39;00m (\u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39m_backward_hooks \u001b[38;5;129;01mor\u001b[39;00m \u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39m_backward_pre_hooks \u001b[38;5;129;01mor\u001b[39;00m \u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39m_forward_hooks \u001b[38;5;129;01mor\u001b[39;00m \u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39m_forward_pre_hooks\n\u001b[0;32m 1745\u001b[0m \u001b[38;5;129;01mor\u001b[39;00m _global_backward_pre_hooks \u001b[38;5;129;01mor\u001b[39;00m _global_backward_hooks\n\u001b[0;32m 1746\u001b[0m \u001b[38;5;129;01mor\u001b[39;00m _global_forward_hooks \u001b[38;5;129;01mor\u001b[39;00m _global_forward_pre_hooks):\n\u001b[1;32m-> 1747\u001b[0m \u001b[38;5;28;01mreturn\u001b[39;00m \u001b[43mforward_call\u001b[49m\u001b[43m(\u001b[49m\u001b[38;5;241;43m*\u001b[39;49m\u001b[43margs\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[38;5;241;43m*\u001b[39;49m\u001b[38;5;241;43m*\u001b[39;49m\u001b[43mkwargs\u001b[49m\u001b[43m)\u001b[49m\n\u001b[0;32m 1749\u001b[0m result \u001b[38;5;241m=\u001b[39m \u001b[38;5;28;01mNone\u001b[39;00m\n\u001b[0;32m 1750\u001b[0m called_always_called_hooks \u001b[38;5;241m=\u001b[39m \u001b[38;5;28mset\u001b[39m()\n", + "File \u001b[1;32m~\\AppData\\Local\\Packages\\PythonSoftwareFoundation.Python.3.11_qbz5n2kfra8p0\\LocalCache\\local-packages\\Python311\\site-packages\\torchvision\\transforms\\transforms.py:277\u001b[0m, in \u001b[0;36mNormalize.forward\u001b[1;34m(self, tensor)\u001b[0m\n\u001b[0;32m 269\u001b[0m \u001b[38;5;28;01mdef\u001b[39;00m \u001b[38;5;21mforward\u001b[39m(\u001b[38;5;28mself\u001b[39m, tensor: Tensor) \u001b[38;5;241m-\u001b[39m\u001b[38;5;241m>\u001b[39m Tensor:\n\u001b[0;32m 270\u001b[0m \u001b[38;5;250m \u001b[39m\u001b[38;5;124;03m\"\"\"\u001b[39;00m\n\u001b[0;32m 271\u001b[0m \u001b[38;5;124;03m Args:\u001b[39;00m\n\u001b[0;32m 272\u001b[0m \u001b[38;5;124;03m tensor (Tensor): Tensor image to be normalized.\u001b[39;00m\n\u001b[1;32m (...)\u001b[0m\n\u001b[0;32m 275\u001b[0m \u001b[38;5;124;03m Tensor: Normalized Tensor image.\u001b[39;00m\n\u001b[0;32m 276\u001b[0m \u001b[38;5;124;03m \"\"\"\u001b[39;00m\n\u001b[1;32m--> 277\u001b[0m \u001b[38;5;28;01mreturn\u001b[39;00m \u001b[43mF\u001b[49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43mnormalize\u001b[49m\u001b[43m(\u001b[49m\u001b[43mtensor\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[38;5;28;43mself\u001b[39;49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43mmean\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[38;5;28;43mself\u001b[39;49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43mstd\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[38;5;28;43mself\u001b[39;49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43minplace\u001b[49m\u001b[43m)\u001b[49m\n", + "File \u001b[1;32m~\\AppData\\Local\\Packages\\PythonSoftwareFoundation.Python.3.11_qbz5n2kfra8p0\\LocalCache\\local-packages\\Python311\\site-packages\\torchvision\\transforms\\functional.py:350\u001b[0m, in \u001b[0;36mnormalize\u001b[1;34m(tensor, mean, std, inplace)\u001b[0m\n\u001b[0;32m 347\u001b[0m \u001b[38;5;28;01mif\u001b[39;00m \u001b[38;5;129;01mnot\u001b[39;00m \u001b[38;5;28misinstance\u001b[39m(tensor, torch\u001b[38;5;241m.\u001b[39mTensor):\n\u001b[0;32m 348\u001b[0m \u001b[38;5;28;01mraise\u001b[39;00m \u001b[38;5;167;01mTypeError\u001b[39;00m(\u001b[38;5;124mf\u001b[39m\u001b[38;5;124m\"\u001b[39m\u001b[38;5;124mimg should be Tensor Image. Got \u001b[39m\u001b[38;5;132;01m{\u001b[39;00m\u001b[38;5;28mtype\u001b[39m(tensor)\u001b[38;5;132;01m}\u001b[39;00m\u001b[38;5;124m\"\u001b[39m)\n\u001b[1;32m--> 350\u001b[0m \u001b[38;5;28;01mreturn\u001b[39;00m \u001b[43mF_t\u001b[49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43mnormalize\u001b[49m\u001b[43m(\u001b[49m\u001b[43mtensor\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43mmean\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[43mmean\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43mstd\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[43mstd\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43minplace\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[43minplace\u001b[49m\u001b[43m)\u001b[49m\n", + "File \u001b[1;32m~\\AppData\\Local\\Packages\\PythonSoftwareFoundation.Python.3.11_qbz5n2kfra8p0\\LocalCache\\local-packages\\Python311\\site-packages\\torchvision\\transforms\\_functional_tensor.py:917\u001b[0m, in \u001b[0;36mnormalize\u001b[1;34m(tensor, mean, std, inplace)\u001b[0m\n\u001b[0;32m 912\u001b[0m \u001b[38;5;28;01mraise\u001b[39;00m \u001b[38;5;167;01mValueError\u001b[39;00m(\n\u001b[0;32m 913\u001b[0m \u001b[38;5;124mf\u001b[39m\u001b[38;5;124m\"\u001b[39m\u001b[38;5;124mExpected tensor to be a tensor image of size (..., C, H, W). Got tensor.size() = \u001b[39m\u001b[38;5;132;01m{\u001b[39;00mtensor\u001b[38;5;241m.\u001b[39msize()\u001b[38;5;132;01m}\u001b[39;00m\u001b[38;5;124m\"\u001b[39m\n\u001b[0;32m 914\u001b[0m )\n\u001b[0;32m 916\u001b[0m \u001b[38;5;28;01mif\u001b[39;00m \u001b[38;5;129;01mnot\u001b[39;00m inplace:\n\u001b[1;32m--> 917\u001b[0m tensor \u001b[38;5;241m=\u001b[39m \u001b[43mtensor\u001b[49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43mclone\u001b[49m\u001b[43m(\u001b[49m\u001b[43m)\u001b[49m\n\u001b[0;32m 919\u001b[0m dtype \u001b[38;5;241m=\u001b[39m tensor\u001b[38;5;241m.\u001b[39mdtype\n\u001b[0;32m 920\u001b[0m mean \u001b[38;5;241m=\u001b[39m torch\u001b[38;5;241m.\u001b[39mas_tensor(mean, dtype\u001b[38;5;241m=\u001b[39mdtype, device\u001b[38;5;241m=\u001b[39mtensor\u001b[38;5;241m.\u001b[39mdevice)\n", + "\u001b[1;31mKeyboardInterrupt\u001b[0m: " + ] + } + ], "source": [ "import torch.optim as optim\n", "\n", @@ -316,7 +417,7 @@ "\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", + "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", @@ -378,30 +479,45 @@ " 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": null, + "execution_count": 33, "id": "d39df818", "metadata": {}, - "outputs": [], + "outputs": [ + { + "data": { + "image/png": "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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_list)\n", + "plt.plot(range(len(train_loss_list)), 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": "fa67ac46", + "metadata": {}, + "source": [ + "Does overfit occur ?\n", + "\n", + "*La validation loss baisse jusqu'à l'époque 14, puis se stabilise aux époques suivantes. Le modèle overfit après l'époque 14.*\n", + "\n", + "*The validation loss decreases until epoch 14, then stabilizes in subsequent epochs. The model overfits after epoch 14.*" + ] + }, { "cell_type": "markdown", "id": "11df8fd4", @@ -412,10 +528,39 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 34, "id": "e93efdfc", "metadata": {}, - "outputs": [], + "outputs": [ + { + "name": "stderr", + "output_type": "stream", + "text": [ + "C:\\Users\\Utilisateur\\AppData\\Local\\Temp\\ipykernel_5932\\3291884398.py:1: FutureWarning: You are using `torch.load` with `weights_only=False` (the current default value), which uses the default pickle module implicitly. It is possible to construct malicious pickle data which will execute arbitrary code during unpickling (See https://github.com/pytorch/pytorch/blob/main/SECURITY.md#untrusted-models for more details). In a future release, the default value for `weights_only` will be flipped to `True`. This limits the functions that could be executed during unpickling. Arbitrary objects will no longer be allowed to be loaded via this mode unless they are explicitly allowlisted by the user via `torch.serialization.add_safe_globals`. We recommend you start setting `weights_only=True` for any use case where you don't have full control of the loaded file. Please open an issue on GitHub for any issues related to this experimental feature.\n", + " model.load_state_dict(torch.load(\"./model_cifar.pt\"))\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Test Loss: 22.460758\n", + "\n", + "Test Accuracy of airplane: 70% (708/1000)\n", + "Test Accuracy of automobile: 64% (648/1000)\n", + "Test Accuracy of bird: 45% (453/1000)\n", + "Test Accuracy of cat: 47% (471/1000)\n", + "Test Accuracy of deer: 47% (476/1000)\n", + "Test Accuracy of dog: 46% (463/1000)\n", + "Test Accuracy of frog: 67% (678/1000)\n", + "Test Accuracy of horse: 64% (649/1000)\n", + "Test Accuracy of ship: 81% (811/1000)\n", + "Test Accuracy of truck: 68% (687/1000)\n", + "\n", + "Test Accuracy (Overall): 60% (6044/10000)\n" + ] + } + ], "source": [ "model.load_state_dict(torch.load(\"./model_cifar.pt\"))\n", "\n", @@ -484,6 +629,8 @@ "id": "944991a2", "metadata": {}, "source": [ + "*Test Accuracy (Overall): 60% (6044/10000)*\n", + "\n", "Build a new network with the following structure.\n", "\n", "- It has 3 convolutional layers of kernel size 3 and padding of 1.\n", @@ -496,6 +643,366 @@ "Compare the results obtained with this new network to those obtained previously." ] }, + { + "cell_type": "code", + "execution_count": null, + "id": "1e1e4ad3", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Net(\n", + " (conv1): Conv2d(3, 16, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1))\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", + " (pool): MaxPool2d(kernel_size=3, stride=2, padding=0, dilation=1, ceil_mode=False)\n", + " (fc1): Linear(in_features=576, 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" + ] + }, + { + "data": { + "text/plain": [ + "' \\nclass 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'" + ] + }, + "execution_count": 22, + "metadata": {}, + "output_type": "execute_result" + } + ], + "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, 16, 3, padding=1)\n", + " self.conv2 = nn.Conv2d(16, 32, 3, padding=1)\n", + " self.conv3 = nn.Conv2d(32, 64, 3, padding=1)\n", + " self.pool = nn.MaxPool2d(3, 2)\n", + " self.fc1 = nn.Linear(64 * 3 * 3, 512)\n", + " self.fc2 = nn.Linear(512, 64)\n", + " self.fc3 = nn.Linear(64, 10) # Dropout whose value you will suggest ???\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 * 3 * 3)\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", + "modelEx = Net()\n", + "print(modelEx)\n", + "# move tensors to GPU if CUDA is available\n", + "if train_on_gpu:\n", + " modelEx.cuda()" + ] + }, + { + "cell_type": "code", + "execution_count": 23, + "id": "4af16458", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Epoch: 0 \tTraining Loss: 45.114236 \tValidation Loss: 40.789144\n", + "Validation loss decreased (inf --> 40.789144). Saving model ...\n", + "Epoch: 1 \tTraining Loss: 36.672867 \tValidation Loss: 32.992202\n", + "Validation loss decreased (40.789144 --> 32.992202). Saving model ...\n", + "Epoch: 2 \tTraining Loss: 31.540151 \tValidation Loss: 29.471859\n", + "Validation loss decreased (32.992202 --> 29.471859). Saving model ...\n", + "Epoch: 3 \tTraining Loss: 28.217329 \tValidation Loss: 26.253962\n", + "Validation loss decreased (29.471859 --> 26.253962). Saving model ...\n", + "Epoch: 4 \tTraining Loss: 25.529990 \tValidation Loss: 24.321873\n", + "Validation loss decreased (26.253962 --> 24.321873). Saving model ...\n", + "Epoch: 5 \tTraining Loss: 23.226547 \tValidation Loss: 22.153841\n", + "Validation loss decreased (24.321873 --> 22.153841). Saving model ...\n", + "Epoch: 6 \tTraining Loss: 21.182890 \tValidation Loss: 20.297892\n", + "Validation loss decreased (22.153841 --> 20.297892). Saving model ...\n", + "Epoch: 7 \tTraining Loss: 19.363431 \tValidation Loss: 19.952192\n", + "Validation loss decreased (20.297892 --> 19.952192). Saving model ...\n", + "Epoch: 8 \tTraining Loss: 17.804383 \tValidation Loss: 18.367063\n", + "Validation loss decreased (19.952192 --> 18.367063). Saving model ...\n", + "Epoch: 9 \tTraining Loss: 16.602377 \tValidation Loss: 17.354809\n", + "Validation loss decreased (18.367063 --> 17.354809). Saving model ...\n", + "Epoch: 10 \tTraining Loss: 15.480934 \tValidation Loss: 17.487981\n", + "Epoch: 11 \tTraining Loss: 14.417038 \tValidation Loss: 16.533617\n", + "Validation loss decreased (17.354809 --> 16.533617). Saving model ...\n", + "Epoch: 12 \tTraining Loss: 13.486131 \tValidation Loss: 15.517560\n", + "Validation loss decreased (16.533617 --> 15.517560). Saving model ...\n", + "Epoch: 13 \tTraining Loss: 12.624461 \tValidation Loss: 15.282706\n", + "Validation loss decreased (15.517560 --> 15.282706). Saving model ...\n", + "Epoch: 14 \tTraining Loss: 11.833298 \tValidation Loss: 15.360621\n", + "Epoch: 15 \tTraining Loss: 11.090945 \tValidation Loss: 15.871890\n" + ] + }, + { + "ename": "KeyboardInterrupt", + "evalue": "", + "output_type": "error", + "traceback": [ + "\u001b[1;31m---------------------------------------------------------------------------\u001b[0m", + "\u001b[1;31mKeyboardInterrupt\u001b[0m Traceback (most recent call last)", + "Cell \u001b[1;32mIn[23], line 17\u001b[0m\n\u001b[0;32m 15\u001b[0m \u001b[38;5;66;03m# Train the model\u001b[39;00m\n\u001b[0;32m 16\u001b[0m modelEx\u001b[38;5;241m.\u001b[39mtrain()\n\u001b[1;32m---> 17\u001b[0m \u001b[43m\u001b[49m\u001b[38;5;28;43;01mfor\u001b[39;49;00m\u001b[43m \u001b[49m\u001b[43mdata\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43mtarget\u001b[49m\u001b[43m \u001b[49m\u001b[38;5;129;43;01min\u001b[39;49;00m\u001b[43m \u001b[49m\u001b[43mtrain_loader\u001b[49m\u001b[43m:\u001b[49m\n\u001b[0;32m 18\u001b[0m \u001b[43m \u001b[49m\u001b[38;5;66;43;03m# Move tensors to GPU if CUDA is available\u001b[39;49;00m\n\u001b[0;32m 19\u001b[0m \u001b[43m \u001b[49m\u001b[38;5;28;43;01mif\u001b[39;49;00m\u001b[43m \u001b[49m\u001b[43mtrain_on_gpu\u001b[49m\u001b[43m:\u001b[49m\n\u001b[0;32m 20\u001b[0m \u001b[43m \u001b[49m\u001b[43mdata\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43mtarget\u001b[49m\u001b[43m \u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[43m \u001b[49m\u001b[43mdata\u001b[49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43mcuda\u001b[49m\u001b[43m(\u001b[49m\u001b[43m)\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43mtarget\u001b[49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43mcuda\u001b[49m\u001b[43m(\u001b[49m\u001b[43m)\u001b[49m\n", + "File \u001b[1;32m~\\AppData\\Local\\Packages\\PythonSoftwareFoundation.Python.3.11_qbz5n2kfra8p0\\LocalCache\\local-packages\\Python311\\site-packages\\torch\\utils\\data\\dataloader.py:701\u001b[0m, in \u001b[0;36m_BaseDataLoaderIter.__next__\u001b[1;34m(self)\u001b[0m\n\u001b[0;32m 698\u001b[0m \u001b[38;5;28;01mif\u001b[39;00m \u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39m_sampler_iter \u001b[38;5;129;01mis\u001b[39;00m \u001b[38;5;28;01mNone\u001b[39;00m:\n\u001b[0;32m 699\u001b[0m \u001b[38;5;66;03m# TODO(https://github.com/pytorch/pytorch/issues/76750)\u001b[39;00m\n\u001b[0;32m 700\u001b[0m \u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39m_reset() \u001b[38;5;66;03m# type: ignore[call-arg]\u001b[39;00m\n\u001b[1;32m--> 701\u001b[0m data \u001b[38;5;241m=\u001b[39m \u001b[38;5;28;43mself\u001b[39;49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43m_next_data\u001b[49m\u001b[43m(\u001b[49m\u001b[43m)\u001b[49m\n\u001b[0;32m 702\u001b[0m \u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39m_num_yielded \u001b[38;5;241m+\u001b[39m\u001b[38;5;241m=\u001b[39m \u001b[38;5;241m1\u001b[39m\n\u001b[0;32m 703\u001b[0m \u001b[38;5;28;01mif\u001b[39;00m (\n\u001b[0;32m 704\u001b[0m \u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39m_dataset_kind \u001b[38;5;241m==\u001b[39m _DatasetKind\u001b[38;5;241m.\u001b[39mIterable\n\u001b[0;32m 705\u001b[0m \u001b[38;5;129;01mand\u001b[39;00m \u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39m_IterableDataset_len_called \u001b[38;5;129;01mis\u001b[39;00m \u001b[38;5;129;01mnot\u001b[39;00m \u001b[38;5;28;01mNone\u001b[39;00m\n\u001b[0;32m 706\u001b[0m \u001b[38;5;129;01mand\u001b[39;00m \u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39m_num_yielded \u001b[38;5;241m>\u001b[39m \u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39m_IterableDataset_len_called\n\u001b[0;32m 707\u001b[0m ):\n", + "File \u001b[1;32m~\\AppData\\Local\\Packages\\PythonSoftwareFoundation.Python.3.11_qbz5n2kfra8p0\\LocalCache\\local-packages\\Python311\\site-packages\\torch\\utils\\data\\dataloader.py:757\u001b[0m, in \u001b[0;36m_SingleProcessDataLoaderIter._next_data\u001b[1;34m(self)\u001b[0m\n\u001b[0;32m 755\u001b[0m \u001b[38;5;28;01mdef\u001b[39;00m \u001b[38;5;21m_next_data\u001b[39m(\u001b[38;5;28mself\u001b[39m):\n\u001b[0;32m 756\u001b[0m index \u001b[38;5;241m=\u001b[39m \u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39m_next_index() \u001b[38;5;66;03m# may raise StopIteration\u001b[39;00m\n\u001b[1;32m--> 757\u001b[0m data \u001b[38;5;241m=\u001b[39m \u001b[38;5;28;43mself\u001b[39;49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43m_dataset_fetcher\u001b[49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43mfetch\u001b[49m\u001b[43m(\u001b[49m\u001b[43mindex\u001b[49m\u001b[43m)\u001b[49m \u001b[38;5;66;03m# may raise StopIteration\u001b[39;00m\n\u001b[0;32m 758\u001b[0m \u001b[38;5;28;01mif\u001b[39;00m \u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39m_pin_memory:\n\u001b[0;32m 759\u001b[0m data \u001b[38;5;241m=\u001b[39m _utils\u001b[38;5;241m.\u001b[39mpin_memory\u001b[38;5;241m.\u001b[39mpin_memory(data, \u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39m_pin_memory_device)\n", + "File \u001b[1;32m~\\AppData\\Local\\Packages\\PythonSoftwareFoundation.Python.3.11_qbz5n2kfra8p0\\LocalCache\\local-packages\\Python311\\site-packages\\torch\\utils\\data\\_utils\\fetch.py:52\u001b[0m, in \u001b[0;36m_MapDatasetFetcher.fetch\u001b[1;34m(self, possibly_batched_index)\u001b[0m\n\u001b[0;32m 50\u001b[0m data \u001b[38;5;241m=\u001b[39m \u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39mdataset\u001b[38;5;241m.\u001b[39m__getitems__(possibly_batched_index)\n\u001b[0;32m 51\u001b[0m \u001b[38;5;28;01melse\u001b[39;00m:\n\u001b[1;32m---> 52\u001b[0m data \u001b[38;5;241m=\u001b[39m \u001b[43m[\u001b[49m\u001b[38;5;28;43mself\u001b[39;49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43mdataset\u001b[49m\u001b[43m[\u001b[49m\u001b[43midx\u001b[49m\u001b[43m]\u001b[49m\u001b[43m \u001b[49m\u001b[38;5;28;43;01mfor\u001b[39;49;00m\u001b[43m \u001b[49m\u001b[43midx\u001b[49m\u001b[43m \u001b[49m\u001b[38;5;129;43;01min\u001b[39;49;00m\u001b[43m \u001b[49m\u001b[43mpossibly_batched_index\u001b[49m\u001b[43m]\u001b[49m\n\u001b[0;32m 53\u001b[0m \u001b[38;5;28;01melse\u001b[39;00m:\n\u001b[0;32m 54\u001b[0m data \u001b[38;5;241m=\u001b[39m \u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39mdataset[possibly_batched_index]\n", + "File \u001b[1;32m~\\AppData\\Local\\Packages\\PythonSoftwareFoundation.Python.3.11_qbz5n2kfra8p0\\LocalCache\\local-packages\\Python311\\site-packages\\torch\\utils\\data\\_utils\\fetch.py:52\u001b[0m, in \u001b[0;36m<listcomp>\u001b[1;34m(.0)\u001b[0m\n\u001b[0;32m 50\u001b[0m data \u001b[38;5;241m=\u001b[39m \u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39mdataset\u001b[38;5;241m.\u001b[39m__getitems__(possibly_batched_index)\n\u001b[0;32m 51\u001b[0m \u001b[38;5;28;01melse\u001b[39;00m:\n\u001b[1;32m---> 52\u001b[0m data \u001b[38;5;241m=\u001b[39m [\u001b[38;5;28;43mself\u001b[39;49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43mdataset\u001b[49m\u001b[43m[\u001b[49m\u001b[43midx\u001b[49m\u001b[43m]\u001b[49m \u001b[38;5;28;01mfor\u001b[39;00m idx \u001b[38;5;129;01min\u001b[39;00m possibly_batched_index]\n\u001b[0;32m 53\u001b[0m \u001b[38;5;28;01melse\u001b[39;00m:\n\u001b[0;32m 54\u001b[0m data \u001b[38;5;241m=\u001b[39m \u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39mdataset[possibly_batched_index]\n", + "File \u001b[1;32m~\\AppData\\Local\\Packages\\PythonSoftwareFoundation.Python.3.11_qbz5n2kfra8p0\\LocalCache\\local-packages\\Python311\\site-packages\\torchvision\\datasets\\cifar.py:119\u001b[0m, in \u001b[0;36mCIFAR10.__getitem__\u001b[1;34m(self, index)\u001b[0m\n\u001b[0;32m 116\u001b[0m img \u001b[38;5;241m=\u001b[39m Image\u001b[38;5;241m.\u001b[39mfromarray(img)\n\u001b[0;32m 118\u001b[0m \u001b[38;5;28;01mif\u001b[39;00m \u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39mtransform \u001b[38;5;129;01mis\u001b[39;00m \u001b[38;5;129;01mnot\u001b[39;00m \u001b[38;5;28;01mNone\u001b[39;00m:\n\u001b[1;32m--> 119\u001b[0m img \u001b[38;5;241m=\u001b[39m \u001b[38;5;28;43mself\u001b[39;49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43mtransform\u001b[49m\u001b[43m(\u001b[49m\u001b[43mimg\u001b[49m\u001b[43m)\u001b[49m\n\u001b[0;32m 121\u001b[0m \u001b[38;5;28;01mif\u001b[39;00m \u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39mtarget_transform \u001b[38;5;129;01mis\u001b[39;00m \u001b[38;5;129;01mnot\u001b[39;00m \u001b[38;5;28;01mNone\u001b[39;00m:\n\u001b[0;32m 122\u001b[0m target \u001b[38;5;241m=\u001b[39m \u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39mtarget_transform(target)\n", + "File \u001b[1;32m~\\AppData\\Local\\Packages\\PythonSoftwareFoundation.Python.3.11_qbz5n2kfra8p0\\LocalCache\\local-packages\\Python311\\site-packages\\torchvision\\transforms\\transforms.py:95\u001b[0m, in \u001b[0;36mCompose.__call__\u001b[1;34m(self, img)\u001b[0m\n\u001b[0;32m 93\u001b[0m \u001b[38;5;28;01mdef\u001b[39;00m \u001b[38;5;21m__call__\u001b[39m(\u001b[38;5;28mself\u001b[39m, img):\n\u001b[0;32m 94\u001b[0m \u001b[38;5;28;01mfor\u001b[39;00m t \u001b[38;5;129;01min\u001b[39;00m \u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39mtransforms:\n\u001b[1;32m---> 95\u001b[0m img \u001b[38;5;241m=\u001b[39m \u001b[43mt\u001b[49m\u001b[43m(\u001b[49m\u001b[43mimg\u001b[49m\u001b[43m)\u001b[49m\n\u001b[0;32m 96\u001b[0m \u001b[38;5;28;01mreturn\u001b[39;00m img\n", + "File \u001b[1;32m~\\AppData\\Local\\Packages\\PythonSoftwareFoundation.Python.3.11_qbz5n2kfra8p0\\LocalCache\\local-packages\\Python311\\site-packages\\torch\\nn\\modules\\module.py:1736\u001b[0m, in \u001b[0;36mModule._wrapped_call_impl\u001b[1;34m(self, *args, **kwargs)\u001b[0m\n\u001b[0;32m 1734\u001b[0m \u001b[38;5;28;01mreturn\u001b[39;00m \u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39m_compiled_call_impl(\u001b[38;5;241m*\u001b[39margs, \u001b[38;5;241m*\u001b[39m\u001b[38;5;241m*\u001b[39mkwargs) \u001b[38;5;66;03m# type: ignore[misc]\u001b[39;00m\n\u001b[0;32m 1735\u001b[0m \u001b[38;5;28;01melse\u001b[39;00m:\n\u001b[1;32m-> 1736\u001b[0m \u001b[38;5;28;01mreturn\u001b[39;00m \u001b[38;5;28;43mself\u001b[39;49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43m_call_impl\u001b[49m\u001b[43m(\u001b[49m\u001b[38;5;241;43m*\u001b[39;49m\u001b[43margs\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[38;5;241;43m*\u001b[39;49m\u001b[38;5;241;43m*\u001b[39;49m\u001b[43mkwargs\u001b[49m\u001b[43m)\u001b[49m\n", + "File \u001b[1;32m~\\AppData\\Local\\Packages\\PythonSoftwareFoundation.Python.3.11_qbz5n2kfra8p0\\LocalCache\\local-packages\\Python311\\site-packages\\torch\\nn\\modules\\module.py:1747\u001b[0m, in \u001b[0;36mModule._call_impl\u001b[1;34m(self, *args, **kwargs)\u001b[0m\n\u001b[0;32m 1742\u001b[0m \u001b[38;5;66;03m# If we don't have any hooks, we want to skip the rest of the logic in\u001b[39;00m\n\u001b[0;32m 1743\u001b[0m \u001b[38;5;66;03m# this function, and just call forward.\u001b[39;00m\n\u001b[0;32m 1744\u001b[0m \u001b[38;5;28;01mif\u001b[39;00m \u001b[38;5;129;01mnot\u001b[39;00m (\u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39m_backward_hooks \u001b[38;5;129;01mor\u001b[39;00m \u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39m_backward_pre_hooks \u001b[38;5;129;01mor\u001b[39;00m \u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39m_forward_hooks \u001b[38;5;129;01mor\u001b[39;00m \u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39m_forward_pre_hooks\n\u001b[0;32m 1745\u001b[0m \u001b[38;5;129;01mor\u001b[39;00m _global_backward_pre_hooks \u001b[38;5;129;01mor\u001b[39;00m _global_backward_hooks\n\u001b[0;32m 1746\u001b[0m \u001b[38;5;129;01mor\u001b[39;00m _global_forward_hooks \u001b[38;5;129;01mor\u001b[39;00m _global_forward_pre_hooks):\n\u001b[1;32m-> 1747\u001b[0m \u001b[38;5;28;01mreturn\u001b[39;00m \u001b[43mforward_call\u001b[49m\u001b[43m(\u001b[49m\u001b[38;5;241;43m*\u001b[39;49m\u001b[43margs\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[38;5;241;43m*\u001b[39;49m\u001b[38;5;241;43m*\u001b[39;49m\u001b[43mkwargs\u001b[49m\u001b[43m)\u001b[49m\n\u001b[0;32m 1749\u001b[0m result \u001b[38;5;241m=\u001b[39m \u001b[38;5;28;01mNone\u001b[39;00m\n\u001b[0;32m 1750\u001b[0m called_always_called_hooks \u001b[38;5;241m=\u001b[39m \u001b[38;5;28mset\u001b[39m()\n", + "File \u001b[1;32m~\\AppData\\Local\\Packages\\PythonSoftwareFoundation.Python.3.11_qbz5n2kfra8p0\\LocalCache\\local-packages\\Python311\\site-packages\\torchvision\\transforms\\transforms.py:277\u001b[0m, in \u001b[0;36mNormalize.forward\u001b[1;34m(self, tensor)\u001b[0m\n\u001b[0;32m 269\u001b[0m \u001b[38;5;28;01mdef\u001b[39;00m \u001b[38;5;21mforward\u001b[39m(\u001b[38;5;28mself\u001b[39m, tensor: Tensor) \u001b[38;5;241m-\u001b[39m\u001b[38;5;241m>\u001b[39m Tensor:\n\u001b[0;32m 270\u001b[0m \u001b[38;5;250m \u001b[39m\u001b[38;5;124;03m\"\"\"\u001b[39;00m\n\u001b[0;32m 271\u001b[0m \u001b[38;5;124;03m Args:\u001b[39;00m\n\u001b[0;32m 272\u001b[0m \u001b[38;5;124;03m tensor (Tensor): Tensor image to be normalized.\u001b[39;00m\n\u001b[1;32m (...)\u001b[0m\n\u001b[0;32m 275\u001b[0m \u001b[38;5;124;03m Tensor: Normalized Tensor image.\u001b[39;00m\n\u001b[0;32m 276\u001b[0m \u001b[38;5;124;03m \"\"\"\u001b[39;00m\n\u001b[1;32m--> 277\u001b[0m \u001b[38;5;28;01mreturn\u001b[39;00m \u001b[43mF\u001b[49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43mnormalize\u001b[49m\u001b[43m(\u001b[49m\u001b[43mtensor\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[38;5;28;43mself\u001b[39;49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43mmean\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[38;5;28;43mself\u001b[39;49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43mstd\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[38;5;28;43mself\u001b[39;49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43minplace\u001b[49m\u001b[43m)\u001b[49m\n", + "File \u001b[1;32m~\\AppData\\Local\\Packages\\PythonSoftwareFoundation.Python.3.11_qbz5n2kfra8p0\\LocalCache\\local-packages\\Python311\\site-packages\\torchvision\\transforms\\functional.py:350\u001b[0m, in \u001b[0;36mnormalize\u001b[1;34m(tensor, mean, std, inplace)\u001b[0m\n\u001b[0;32m 347\u001b[0m \u001b[38;5;28;01mif\u001b[39;00m \u001b[38;5;129;01mnot\u001b[39;00m \u001b[38;5;28misinstance\u001b[39m(tensor, torch\u001b[38;5;241m.\u001b[39mTensor):\n\u001b[0;32m 348\u001b[0m \u001b[38;5;28;01mraise\u001b[39;00m \u001b[38;5;167;01mTypeError\u001b[39;00m(\u001b[38;5;124mf\u001b[39m\u001b[38;5;124m\"\u001b[39m\u001b[38;5;124mimg should be Tensor Image. Got \u001b[39m\u001b[38;5;132;01m{\u001b[39;00m\u001b[38;5;28mtype\u001b[39m(tensor)\u001b[38;5;132;01m}\u001b[39;00m\u001b[38;5;124m\"\u001b[39m)\n\u001b[1;32m--> 350\u001b[0m \u001b[38;5;28;01mreturn\u001b[39;00m \u001b[43mF_t\u001b[49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43mnormalize\u001b[49m\u001b[43m(\u001b[49m\u001b[43mtensor\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43mmean\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[43mmean\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43mstd\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[43mstd\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43minplace\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[43minplace\u001b[49m\u001b[43m)\u001b[49m\n", + "File \u001b[1;32m~\\AppData\\Local\\Packages\\PythonSoftwareFoundation.Python.3.11_qbz5n2kfra8p0\\LocalCache\\local-packages\\Python311\\site-packages\\torchvision\\transforms\\_functional_tensor.py:922\u001b[0m, in \u001b[0;36mnormalize\u001b[1;34m(tensor, mean, std, inplace)\u001b[0m\n\u001b[0;32m 920\u001b[0m mean \u001b[38;5;241m=\u001b[39m torch\u001b[38;5;241m.\u001b[39mas_tensor(mean, dtype\u001b[38;5;241m=\u001b[39mdtype, device\u001b[38;5;241m=\u001b[39mtensor\u001b[38;5;241m.\u001b[39mdevice)\n\u001b[0;32m 921\u001b[0m std \u001b[38;5;241m=\u001b[39m torch\u001b[38;5;241m.\u001b[39mas_tensor(std, dtype\u001b[38;5;241m=\u001b[39mdtype, device\u001b[38;5;241m=\u001b[39mtensor\u001b[38;5;241m.\u001b[39mdevice)\n\u001b[1;32m--> 922\u001b[0m \u001b[38;5;28;01mif\u001b[39;00m \u001b[43m(\u001b[49m\u001b[43mstd\u001b[49m\u001b[43m \u001b[49m\u001b[38;5;241;43m==\u001b[39;49m\u001b[43m \u001b[49m\u001b[38;5;241;43m0\u001b[39;49m\u001b[43m)\u001b[49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43many\u001b[49m\u001b[43m(\u001b[49m\u001b[43m)\u001b[49m:\n\u001b[0;32m 923\u001b[0m \u001b[38;5;28;01mraise\u001b[39;00m \u001b[38;5;167;01mValueError\u001b[39;00m(\u001b[38;5;124mf\u001b[39m\u001b[38;5;124m\"\u001b[39m\u001b[38;5;124mstd evaluated to zero after conversion to \u001b[39m\u001b[38;5;132;01m{\u001b[39;00mdtype\u001b[38;5;132;01m}\u001b[39;00m\u001b[38;5;124m, leading to division by zero.\u001b[39m\u001b[38;5;124m\"\u001b[39m)\n\u001b[0;32m 924\u001b[0m \u001b[38;5;28;01mif\u001b[39;00m mean\u001b[38;5;241m.\u001b[39mndim \u001b[38;5;241m==\u001b[39m \u001b[38;5;241m1\u001b[39m:\n", + "\u001b[1;31mKeyboardInterrupt\u001b[0m: " + ] + } + ], + "source": [ + "import torch.optim as optim\n", + "\n", + "criterion = nn.CrossEntropyLoss() # specify loss function\n", + "optimizer = optim.SGD(modelEx.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", + " modelEx.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 = modelEx(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", + " modelEx.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 = modelEx(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(modelEx.state_dict(), \"model_cifarEx.pt\")\n", + " valid_loss_min = valid_loss\n" + ] + }, + { + "cell_type": "markdown", + "id": "73c43cc5", + "metadata": {}, + "source": [ + "*La validation loss baisse jusqu'à l'époque 13, puis se stabilise : on arrête le training.*\n", + "\n", + "*The validation loss decreases until epoch 13, then stabilizes: we stop training.*" + ] + }, + { + "cell_type": "code", + "execution_count": 28, + "id": "bfff558d", + "metadata": {}, + "outputs": [ + { + "data": { + "image/png": "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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", + "# print(len(train_loss_list))\n", + "\n", + "plt.plot(range(len(train_loss_list)), train_loss_list)\n", + "plt.xlabel(\"Epoch\")\n", + "plt.ylabel(\"Loss\")\n", + "plt.title(\"Performance of Model 2\")\n", + "plt.show()" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "55c1bf75", + "metadata": {}, + "outputs": [ + { + "name": "stderr", + "output_type": "stream", + "text": [ + "C:\\Users\\Utilisateur\\AppData\\Local\\Temp\\ipykernel_5932\\3002838268.py:1: FutureWarning: You are using `torch.load` with `weights_only=False` (the current default value), which uses the default pickle module implicitly. It is possible to construct malicious pickle data which will execute arbitrary code during unpickling (See https://github.com/pytorch/pytorch/blob/main/SECURITY.md#untrusted-models for more details). In a future release, the default value for `weights_only` will be flipped to `True`. This limits the functions that could be executed during unpickling. Arbitrary objects will no longer be allowed to be loaded via this mode unless they are explicitly allowlisted by the user via `torch.serialization.add_safe_globals`. We recommend you start setting `weights_only=True` for any use case where you don't have full control of the loaded file. Please open an issue on GitHub for any issues related to this experimental feature.\n", + " modelEx.load_state_dict(torch.load(\"./model_cifarEx.pt\"))\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Test Loss: 15.633493\n", + "\n", + "Test Accuracy of airplane: 77% (776/1000)\n", + "Test Accuracy of automobile: 79% (795/1000)\n", + "Test Accuracy of bird: 57% (570/1000)\n", + "Test Accuracy of cat: 59% (592/1000)\n", + "Test Accuracy of deer: 72% (726/1000)\n", + "Test Accuracy of dog: 62% (623/1000)\n", + "Test Accuracy of frog: 73% (730/1000)\n", + "Test Accuracy of horse: 77% (775/1000)\n", + "Test Accuracy of ship: 83% (832/1000)\n", + "Test Accuracy of truck: 87% (874/1000)\n", + "\n", + "Test Accuracy (Overall): 72% (7293/10000)\n" + ] + }, + { + "data": { + "text/plain": [ + "' \\nmodel.load_state_dict(torch.load(\"./model_cifar.pt\"))\\n\\n# track test loss\\ntest_loss = 0.0\\nclass_correct = list(0.0 for i in range(10))\\nclass_total = list(0.0 for i in range(10))\\n\\nmodel.eval()\\n# iterate over test data\\nfor 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\\ntest_loss = test_loss / len(test_loader)\\nprint(\"Test Loss: {:.6f}\\n\".format(test_loss))\\n\\nfor 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\\nprint(\\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)\\n'" + ] + }, + "execution_count": 29, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "modelEx.load_state_dict(torch.load(\"./model_cifarEx.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", + "modelEx.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 = modelEx(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", + "id": "56bf7bf5", + "metadata": {}, + "source": [ + "*On a une précision de 72%, contre 60% avec le modèle précédent. Le temps de calcul pour les deux modèles a été équivalent : 4min17s pour le 1er modèle, 5min45s pour le 2nd.*\n", + "\n", + "*We have an accuracy of 72%, compared to 60% with the previous model. The calculation time for the two models was equivalent: 4min17s for the 1st model, 5min45s for the 2nd.*" + ] + }, { "cell_type": "markdown", "id": "bc381cf4", diff --git a/ex1Modele1.png b/ex1Modele1.png new file mode 100644 index 0000000000000000000000000000000000000000..df0701b84b29ee83ce41e20f2beaddc61a036c8c Binary files /dev/null and b/ex1Modele1.png differ diff --git a/ex1Modele2.png b/ex1Modele2.png new file mode 100644 index 0000000000000000000000000000000000000000..e2326985b0b34f73525df026ea9be20d2a2c3223 Binary files /dev/null and b/ex1Modele2.png differ