diff --git a/TD2 Deep Learning.ipynb b/TD2 Deep Learning.ipynb index 914955a139097172c2cc84e7578aff07465025a4..dcc5c4a6e34de84f358de193b6d2a39dee87fe6a 100644 --- a/TD2 Deep Learning.ipynb +++ b/TD2 Deep Learning.ipynb @@ -213,7 +213,7 @@ "colab": { "base_uri": "https://localhost:8080/" }, - "outputId": "03e195b7-3c7a-4170-ceca-068b700790f8" + "outputId": "5afda067-1a64-4471-c2bc-0426403a9d65" }, "outputs": [ { @@ -248,14 +248,14 @@ }, { "cell_type": "code", - "execution_count": 3, + "execution_count": 6, "id": "462666a2", "metadata": { "id": "462666a2", "colab": { "base_uri": "https://localhost:8080/" }, - "outputId": "efadf484-b9e7-4451-9685-278d30164520" + "outputId": "60d68453-a1bd-4c64-cfbb-0b8e51b009a3" }, "outputs": [ { @@ -269,7 +269,7 @@ "output_type": "stream", "name": "stderr", "text": [ - "100%|██████████| 170498071/170498071 [00:01<00:00, 103869184.28it/s]\n" + "100%|██████████| 170498071/170498071 [00:04<00:00, 42416276.91it/s]\n" ] }, { @@ -351,14 +351,14 @@ }, { "cell_type": "code", - "execution_count": 8, + "execution_count": 7, "id": "317bf070", "metadata": { "id": "317bf070", "colab": { "base_uri": "https://localhost:8080/" }, - "outputId": "c3bf54b9-cce3-4017-aeab-b8041ea655e7" + "outputId": "d6a4ea53-8797-4886-b714-5b913ff75ffc" }, "outputs": [ { @@ -423,50 +423,17 @@ }, { "cell_type": "code", - "execution_count": 9, + "execution_count": 8, "id": "4b53f229", "metadata": { "id": "4b53f229", "colab": { "base_uri": "https://localhost:8080/", - "height": 881 + "height": 391 }, - "outputId": "8c5ea9a1-3f8a-4814-eaee-3628910f3636" + "outputId": "288c9f15-e0aa-4d15-e534-d7e71a689c1a" }, "outputs": [ - { - "output_type": "stream", - "name": "stdout", - "text": [ - "Epoch: 0 \tTraining Loss: 44.038732 \tValidation Loss: 39.409209\n", - "Validation loss decreased (inf --> 39.409209). Saving model ...\n", - "Epoch: 1 \tTraining Loss: 35.157346 \tValidation Loss: 31.752622\n", - "Validation loss decreased (39.409209 --> 31.752622). Saving model ...\n", - "Epoch: 2 \tTraining Loss: 30.638388 \tValidation Loss: 29.289384\n", - "Validation loss decreased (31.752622 --> 29.289384). Saving model ...\n", - "Epoch: 3 \tTraining Loss: 28.499834 \tValidation Loss: 27.327754\n", - "Validation loss decreased (29.289384 --> 27.327754). Saving model ...\n", - "Epoch: 4 \tTraining Loss: 26.784333 \tValidation Loss: 27.843559\n", - "Epoch: 5 \tTraining Loss: 25.244284 \tValidation Loss: 26.936346\n", - "Validation loss decreased (27.327754 --> 26.936346). Saving model ...\n", - "Epoch: 6 \tTraining Loss: 23.937883 \tValidation Loss: 24.311266\n", - "Validation loss decreased (26.936346 --> 24.311266). Saving model ...\n", - "Epoch: 7 \tTraining Loss: 22.804158 \tValidation Loss: 22.877894\n", - "Validation loss decreased (24.311266 --> 22.877894). Saving model ...\n", - "Epoch: 8 \tTraining Loss: 21.733578 \tValidation Loss: 22.296608\n", - "Validation loss decreased (22.877894 --> 22.296608). Saving model ...\n", - "Epoch: 9 \tTraining Loss: 20.862017 \tValidation Loss: 21.442494\n", - "Validation loss decreased (22.296608 --> 21.442494). Saving model ...\n", - "Epoch: 10 \tTraining Loss: 19.986339 \tValidation Loss: 21.860503\n", - "Epoch: 11 \tTraining Loss: 19.199303 \tValidation Loss: 21.217101\n", - "Validation loss decreased (21.442494 --> 21.217101). Saving model ...\n", - "Epoch: 12 \tTraining Loss: 18.541731 \tValidation Loss: 21.502720\n", - "Epoch: 13 \tTraining Loss: 17.861395 \tValidation Loss: 21.135662\n", - "Validation loss decreased (21.217101 --> 21.135662). Saving model ...\n", - "Epoch: 14 \tTraining Loss: 17.303609 \tValidation Loss: 21.811283\n", - "Epoch: 15 \tTraining Loss: 16.740100 \tValidation Loss: 22.032390\n" - ] - }, { "output_type": "error", "ename": "KeyboardInterrupt", @@ -474,9 +441,14 @@ "traceback": [ "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m", "\u001b[0;31mKeyboardInterrupt\u001b[0m Traceback (most recent call last)", - "\u001b[0;32m<ipython-input-9-e3e3eae4d15a>\u001b[0m in \u001b[0;36m<cell line: 10>\u001b[0;34m()\u001b[0m\n\u001b[1;32m 26\u001b[0m \u001b[0mloss\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mcriterion\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0moutput\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mtarget\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 27\u001b[0m \u001b[0;31m# Backward pass: compute gradient of the loss with respect to model parameters\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m---> 28\u001b[0;31m \u001b[0mloss\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mbackward\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m 29\u001b[0m \u001b[0;31m# Perform a single optimization step (parameter update)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 30\u001b[0m \u001b[0moptimizer\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mstep\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n", - "\u001b[0;32m/usr/local/lib/python3.10/dist-packages/torch/_tensor.py\u001b[0m in \u001b[0;36mbackward\u001b[0;34m(self, gradient, retain_graph, create_graph, inputs)\u001b[0m\n\u001b[1;32m 490\u001b[0m \u001b[0minputs\u001b[0m\u001b[0;34m=\u001b[0m\u001b[0minputs\u001b[0m\u001b[0;34m,\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 491\u001b[0m )\n\u001b[0;32m--> 492\u001b[0;31m torch.autograd.backward(\n\u001b[0m\u001b[1;32m 493\u001b[0m \u001b[0mself\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mgradient\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mretain_graph\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mcreate_graph\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0minputs\u001b[0m\u001b[0;34m=\u001b[0m\u001b[0minputs\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 494\u001b[0m )\n", - "\u001b[0;32m/usr/local/lib/python3.10/dist-packages/torch/autograd/__init__.py\u001b[0m in \u001b[0;36mbackward\u001b[0;34m(tensors, grad_tensors, retain_graph, create_graph, grad_variables, inputs)\u001b[0m\n\u001b[1;32m 249\u001b[0m \u001b[0;31m# some Python versions print out the first line of a multi-line function\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 250\u001b[0m \u001b[0;31m# calls in the traceback and some print out the last line\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m--> 251\u001b[0;31m Variable._execution_engine.run_backward( # Calls into the C++ engine to run the backward pass\n\u001b[0m\u001b[1;32m 252\u001b[0m \u001b[0mtensors\u001b[0m\u001b[0;34m,\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 253\u001b[0m \u001b[0mgrad_tensors_\u001b[0m\u001b[0;34m,\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n", + "\u001b[0;32m<ipython-input-8-e3e3eae4d15a>\u001b[0m in \u001b[0;36m<cell line: 10>\u001b[0;34m()\u001b[0m\n\u001b[1;32m 22\u001b[0m \u001b[0moptimizer\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mzero_grad\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 23\u001b[0m \u001b[0;31m# Forward pass: compute predicted outputs by passing inputs to the model\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m---> 24\u001b[0;31m \u001b[0moutput\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mmodel\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mdata\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m 25\u001b[0m \u001b[0;31m# Calculate the batch loss\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 26\u001b[0m \u001b[0mloss\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mcriterion\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0moutput\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mtarget\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n", + "\u001b[0;32m/usr/local/lib/python3.10/dist-packages/torch/nn/modules/module.py\u001b[0m in \u001b[0;36m_wrapped_call_impl\u001b[0;34m(self, *args, **kwargs)\u001b[0m\n\u001b[1;32m 1516\u001b[0m \u001b[0;32mreturn\u001b[0m \u001b[0mself\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0m_compiled_call_impl\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m*\u001b[0m\u001b[0margs\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0;34m**\u001b[0m\u001b[0mkwargs\u001b[0m\u001b[0;34m)\u001b[0m \u001b[0;31m# type: ignore[misc]\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 1517\u001b[0m \u001b[0;32melse\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m-> 1518\u001b[0;31m \u001b[0;32mreturn\u001b[0m \u001b[0mself\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0m_call_impl\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m*\u001b[0m\u001b[0margs\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0;34m**\u001b[0m\u001b[0mkwargs\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m 1519\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 1520\u001b[0m \u001b[0;32mdef\u001b[0m \u001b[0m_call_impl\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mself\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0;34m*\u001b[0m\u001b[0margs\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0;34m**\u001b[0m\u001b[0mkwargs\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n", + "\u001b[0;32m/usr/local/lib/python3.10/dist-packages/torch/nn/modules/module.py\u001b[0m in \u001b[0;36m_call_impl\u001b[0;34m(self, *args, **kwargs)\u001b[0m\n\u001b[1;32m 1525\u001b[0m \u001b[0;32mor\u001b[0m \u001b[0m_global_backward_pre_hooks\u001b[0m \u001b[0;32mor\u001b[0m \u001b[0m_global_backward_hooks\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 1526\u001b[0m or _global_forward_hooks or _global_forward_pre_hooks):\n\u001b[0;32m-> 1527\u001b[0;31m \u001b[0;32mreturn\u001b[0m \u001b[0mforward_call\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m*\u001b[0m\u001b[0margs\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0;34m**\u001b[0m\u001b[0mkwargs\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m 1528\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 1529\u001b[0m \u001b[0;32mtry\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n", + "\u001b[0;32m<ipython-input-7-271e17bdd28c>\u001b[0m in \u001b[0;36mforward\u001b[0;34m(self, x)\u001b[0m\n\u001b[1;32m 16\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 17\u001b[0m \u001b[0;32mdef\u001b[0m \u001b[0mforward\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mself\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mx\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m---> 18\u001b[0;31m \u001b[0mx\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mself\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mpool\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mF\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mrelu\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mself\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mconv1\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mx\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m 19\u001b[0m \u001b[0mx\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mself\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mpool\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mF\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mrelu\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mself\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mconv2\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mx\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 20\u001b[0m \u001b[0mx\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mx\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mview\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m-\u001b[0m\u001b[0;36m1\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0;36m16\u001b[0m \u001b[0;34m*\u001b[0m \u001b[0;36m5\u001b[0m \u001b[0;34m*\u001b[0m \u001b[0;36m5\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n", + "\u001b[0;32m/usr/local/lib/python3.10/dist-packages/torch/nn/modules/module.py\u001b[0m in \u001b[0;36m_wrapped_call_impl\u001b[0;34m(self, *args, **kwargs)\u001b[0m\n\u001b[1;32m 1516\u001b[0m \u001b[0;32mreturn\u001b[0m \u001b[0mself\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0m_compiled_call_impl\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m*\u001b[0m\u001b[0margs\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0;34m**\u001b[0m\u001b[0mkwargs\u001b[0m\u001b[0;34m)\u001b[0m \u001b[0;31m# type: ignore[misc]\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 1517\u001b[0m \u001b[0;32melse\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m-> 1518\u001b[0;31m \u001b[0;32mreturn\u001b[0m \u001b[0mself\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0m_call_impl\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m*\u001b[0m\u001b[0margs\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0;34m**\u001b[0m\u001b[0mkwargs\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m 1519\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 1520\u001b[0m \u001b[0;32mdef\u001b[0m \u001b[0m_call_impl\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mself\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0;34m*\u001b[0m\u001b[0margs\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0;34m**\u001b[0m\u001b[0mkwargs\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n", + "\u001b[0;32m/usr/local/lib/python3.10/dist-packages/torch/nn/modules/module.py\u001b[0m in \u001b[0;36m_call_impl\u001b[0;34m(self, *args, **kwargs)\u001b[0m\n\u001b[1;32m 1525\u001b[0m \u001b[0;32mor\u001b[0m \u001b[0m_global_backward_pre_hooks\u001b[0m \u001b[0;32mor\u001b[0m \u001b[0m_global_backward_hooks\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 1526\u001b[0m or _global_forward_hooks or _global_forward_pre_hooks):\n\u001b[0;32m-> 1527\u001b[0;31m \u001b[0;32mreturn\u001b[0m \u001b[0mforward_call\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m*\u001b[0m\u001b[0margs\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0;34m**\u001b[0m\u001b[0mkwargs\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m 1528\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 1529\u001b[0m \u001b[0;32mtry\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n", + "\u001b[0;32m/usr/local/lib/python3.10/dist-packages/torch/nn/modules/conv.py\u001b[0m in \u001b[0;36mforward\u001b[0;34m(self, input)\u001b[0m\n\u001b[1;32m 458\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 459\u001b[0m \u001b[0;32mdef\u001b[0m \u001b[0mforward\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mself\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0minput\u001b[0m\u001b[0;34m:\u001b[0m \u001b[0mTensor\u001b[0m\u001b[0;34m)\u001b[0m \u001b[0;34m->\u001b[0m \u001b[0mTensor\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m--> 460\u001b[0;31m \u001b[0;32mreturn\u001b[0m \u001b[0mself\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0m_conv_forward\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0minput\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mself\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mweight\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mself\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mbias\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m 461\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 462\u001b[0m \u001b[0;32mclass\u001b[0m \u001b[0mConv3d\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0m_ConvNd\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n", + "\u001b[0;32m/usr/local/lib/python3.10/dist-packages/torch/nn/modules/conv.py\u001b[0m in \u001b[0;36m_conv_forward\u001b[0;34m(self, input, weight, bias)\u001b[0m\n\u001b[1;32m 454\u001b[0m \u001b[0mweight\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mbias\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mself\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mstride\u001b[0m\u001b[0;34m,\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 455\u001b[0m _pair(0), self.dilation, self.groups)\n\u001b[0;32m--> 456\u001b[0;31m return F.conv2d(input, weight, bias, self.stride,\n\u001b[0m\u001b[1;32m 457\u001b[0m self.padding, self.dilation, self.groups)\n\u001b[1;32m 458\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n", "\u001b[0;31mKeyboardInterrupt\u001b[0m: " ] } @@ -720,6 +692,361 @@ "Compare the results obtained with this new network to those obtained previously." ] }, + { + "cell_type": "code", + "source": [ + "#NEW NETWORK\n", + "\n", + "import torch.nn as nn\n", + "import torch.nn.functional as F\n", + "\n", + "# define the CNN architecture\n", + "\n", + "\n", + "class Net_new(nn.Module):\n", + " def __init__(self):\n", + " super(Net_new, self).__init__()\n", + "\n", + " #Convolution layer 1\n", + " self.conv1 = nn.Conv2d(in_channels=3, out_channels = 16, kernel_size=3, padding=1)\n", + "\n", + "\n", + " #Convolution layer 2\n", + " self.conv2 = nn.Conv2d(in_channels=16, out_channels = 32, kernel_size=3, padding=1)\n", + "\n", + "\n", + " #Convolution layer 3\n", + " self.conv3 = nn.Conv2d(in_channels=32, out_channels = 64, kernel_size=3, padding=1)\n", + "\n", + " #Max pooling layer\n", + " self.pool = nn.MaxPool2d(2, 2)\n", + "\n", + " #Fully connected Layers\n", + " self.fc1 = nn.Linear(in_features=64 * 4 * 4, out_features=512)\n", + " self.fc2 = nn.Linear(in_features=512, out_features=64)\n", + " self.fc3 = nn.Linear(64, 10)\n", + "\n", + " self.dropout = nn.Dropout(p = 0.5)\n", + "\n", + " def forward(self, x):\n", + "\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", + "\n", + " x = x.view(-1, 64 * 4 * 4) #linearisation of the tensor\n", + " x = self.dropout(F.relu(self.fc1(x)))\n", + " x = self.dropout(F.relu(self.fc2(x)))\n", + " x = self.fc3(x) # output layer\n", + " return x\n", + "\n", + "\n", + "# create a complete CNN\n", + "model= Net_new()\n", + "print(model)\n", + "# move tensors to GPU if CUDA is available\n", + "if train_on_gpu:\n", + " model.cuda()" + ], + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/" + }, + "id": "rjG3agxFVnHc", + "outputId": "8255f8dd-69b4-4c88-9e65-ce684f728c93" + }, + "id": "rjG3agxFVnHc", + "execution_count": 11, + "outputs": [ + { + "output_type": "stream", + "name": "stdout", + "text": [ + "Net_new(\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=2, stride=2, padding=0, dilation=1, ceil_mode=False)\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", + " (dropout): Dropout(p=0.5, inplace=False)\n", + ")\n" + ] + } + ] + }, + { + "cell_type": "code", + "source": [ + "#LOSS FUNCTION AND TRAINING OF NEW MODEL\n", + "\n", + "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" + ], + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/", + "height": 825 + }, + "id": "qdnbb2j3cukU", + "outputId": "64b5be42-d6a6-4047-bd10-c82870e1d8e8" + }, + "id": "qdnbb2j3cukU", + "execution_count": 12, + "outputs": [ + { + "output_type": "stream", + "name": "stdout", + "text": [ + "Epoch: 0 \tTraining Loss: 45.437011 \tValidation Loss: 42.235335\n", + "Validation loss decreased (inf --> 42.235335). Saving model ...\n", + "Epoch: 1 \tTraining Loss: 40.342287 \tValidation Loss: 37.157713\n", + "Validation loss decreased (42.235335 --> 37.157713). Saving model ...\n", + "Epoch: 2 \tTraining Loss: 36.543231 \tValidation Loss: 34.165958\n", + "Validation loss decreased (37.157713 --> 34.165958). Saving model ...\n", + "Epoch: 3 \tTraining Loss: 33.370877 \tValidation Loss: 30.313300\n", + "Validation loss decreased (34.165958 --> 30.313300). Saving model ...\n", + "Epoch: 4 \tTraining Loss: 31.175180 \tValidation Loss: 28.547296\n", + "Validation loss decreased (30.313300 --> 28.547296). Saving model ...\n", + "Epoch: 5 \tTraining Loss: 29.419332 \tValidation Loss: 27.043618\n", + "Validation loss decreased (28.547296 --> 27.043618). Saving model ...\n", + "Epoch: 6 \tTraining Loss: 27.940666 \tValidation Loss: 25.369496\n", + "Validation loss decreased (27.043618 --> 25.369496). Saving model ...\n", + "Epoch: 7 \tTraining Loss: 26.553561 \tValidation Loss: 24.676774\n", + "Validation loss decreased (25.369496 --> 24.676774). Saving model ...\n", + "Epoch: 8 \tTraining Loss: 25.182271 \tValidation Loss: 22.769694\n", + "Validation loss decreased (24.676774 --> 22.769694). Saving model ...\n", + "Epoch: 9 \tTraining Loss: 23.964245 \tValidation Loss: 21.769041\n", + "Validation loss decreased (22.769694 --> 21.769041). Saving model ...\n", + "Epoch: 10 \tTraining Loss: 22.847915 \tValidation Loss: 21.022394\n", + "Validation loss decreased (21.769041 --> 21.022394). Saving model ...\n", + "Epoch: 11 \tTraining Loss: 21.847575 \tValidation Loss: 19.916893\n", + "Validation loss decreased (21.022394 --> 19.916893). Saving model ...\n", + "Epoch: 12 \tTraining Loss: 20.925242 \tValidation Loss: 20.110298\n" + ] + }, + { + "output_type": "error", + "ename": "KeyboardInterrupt", + "evalue": "ignored", + "traceback": [ + "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m", + "\u001b[0;31mKeyboardInterrupt\u001b[0m Traceback (most recent call last)", + "\u001b[0;32m<ipython-input-12-18675338ef88>\u001b[0m in \u001b[0;36m<cell line: 12>\u001b[0;34m()\u001b[0m\n\u001b[1;32m 17\u001b[0m \u001b[0;31m# Train the model\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 18\u001b[0m \u001b[0mmodel\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mtrain\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m---> 19\u001b[0;31m \u001b[0;32mfor\u001b[0m \u001b[0mdata\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mtarget\u001b[0m \u001b[0;32min\u001b[0m \u001b[0mtrain_loader\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m 20\u001b[0m \u001b[0;31m# Move tensors to GPU if CUDA is available\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 21\u001b[0m \u001b[0;32mif\u001b[0m \u001b[0mtrain_on_gpu\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n", + "\u001b[0;32m/usr/local/lib/python3.10/dist-packages/torch/utils/data/dataloader.py\u001b[0m in \u001b[0;36m__next__\u001b[0;34m(self)\u001b[0m\n\u001b[1;32m 624\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 625\u001b[0m \u001b[0;32mdef\u001b[0m \u001b[0m__next__\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mself\u001b[0m\u001b[0;34m)\u001b[0m \u001b[0;34m->\u001b[0m \u001b[0mAny\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m--> 626\u001b[0;31m \u001b[0;32mwith\u001b[0m \u001b[0mtorch\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mautograd\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mprofiler\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mrecord_function\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mself\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0m_profile_name\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m 627\u001b[0m \u001b[0;32mif\u001b[0m \u001b[0mself\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0m_sampler_iter\u001b[0m \u001b[0;32mis\u001b[0m \u001b[0;32mNone\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 628\u001b[0m \u001b[0;31m# TODO(https://github.com/pytorch/pytorch/issues/76750)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n", + "\u001b[0;32m/usr/local/lib/python3.10/dist-packages/torch/autograd/profiler.py\u001b[0m in \u001b[0;36m__exit__\u001b[0;34m(self, exc_type, exc_value, traceback)\u001b[0m\n\u001b[1;32m 646\u001b[0m \u001b[0;32mif\u001b[0m \u001b[0;32mnot\u001b[0m \u001b[0mtorch\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mjit\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mis_scripting\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 647\u001b[0m \u001b[0;32mwith\u001b[0m \u001b[0mtorch\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0m_C\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mDisableTorchFunctionSubclass\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m--> 648\u001b[0;31m \u001b[0mtorch\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mops\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mprofiler\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0m_record_function_exit\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0m_RecordFunction\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mrecord\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m 649\u001b[0m \u001b[0;32melse\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 650\u001b[0m \u001b[0mtorch\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mops\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mprofiler\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0m_record_function_exit\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mrecord\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n", + "\u001b[0;32m/usr/local/lib/python3.10/dist-packages/torch/_ops.py\u001b[0m in \u001b[0;36m__call__\u001b[0;34m(self, *args, **kwargs)\u001b[0m\n\u001b[1;32m 446\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 447\u001b[0m \u001b[0;32mdef\u001b[0m \u001b[0m__call__\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mself\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0;34m*\u001b[0m\u001b[0margs\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0;34m**\u001b[0m\u001b[0mkwargs\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m--> 448\u001b[0;31m \u001b[0;32mreturn\u001b[0m \u001b[0mself\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0m_op\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m*\u001b[0m\u001b[0margs\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0;34m**\u001b[0m\u001b[0mkwargs\u001b[0m \u001b[0;32mor\u001b[0m \u001b[0;34m{\u001b[0m\u001b[0;34m}\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m 449\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 450\u001b[0m \u001b[0;32mdef\u001b[0m \u001b[0m__hash__\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mself\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n", + "\u001b[0;31mKeyboardInterrupt\u001b[0m: " + ] + } + ] + }, + { + "cell_type": "code", + "source": [ + "import matplotlib.pyplot as plt\n", + "n_epochs_stop = 13\n", + "plt.plot(range(n_epochs_stop), train_loss_list)\n", + "plt.xlabel(\"Epoch\")\n", + "plt.ylabel(\"Loss\")\n", + "plt.title(\"Performance of Model 2\")\n", + "plt.show()" + ], + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/", + "height": 472 + }, + "id": "KGzDZzwghfB1", + "outputId": "3057999f-37a8-467a-91c8-5ecb19b25874" + }, + "id": "KGzDZzwghfB1", + "execution_count": 14, + "outputs": [ + { + "output_type": "display_data", + "data": { + "text/plain": [ + "<Figure size 640x480 with 1 Axes>" + ], + "image/png": "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\n" + }, + "metadata": {} + } + ] + }, + { + "cell_type": "code", + "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", + ")" + ], + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/" + }, + "id": "FesxSklkiFfp", + "outputId": "8de507ca-08a4-4a71-b34f-1db8ecabd278" + }, + "id": "FesxSklkiFfp", + "execution_count": 15, + "outputs": [ + { + "output_type": "stream", + "name": "stdout", + "text": [ + "Test Loss: 19.730781\n", + "\n", + "Test Accuracy of airplane: 73% (734/1000)\n", + "Test Accuracy of automobile: 80% (808/1000)\n", + "Test Accuracy of bird: 43% (433/1000)\n", + "Test Accuracy of cat: 40% (407/1000)\n", + "Test Accuracy of deer: 58% (588/1000)\n", + "Test Accuracy of dog: 50% (509/1000)\n", + "Test Accuracy of frog: 76% (765/1000)\n", + "Test Accuracy of horse: 76% (761/1000)\n", + "Test Accuracy of ship: 79% (798/1000)\n", + "Test Accuracy of truck: 73% (736/1000)\n", + "\n", + "Test Accuracy (Overall): 65% (6539/10000)\n" + ] + } + ] + }, + { + "cell_type": "markdown", + "source": [ + "The accuracy is slightly higher than the first model" + ], + "metadata": { + "id": "90Lcg-xjiU2w" + }, + "id": "90Lcg-xjiU2w" + }, { "cell_type": "markdown", "id": "bc381cf4",