{
  "cells": [
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "b9oFE05WQl_K"
      },
      "source": [
        "# Neural Networks"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "### Time to play first !"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "1. Open the TensorFlow playground at https://playground.tensorflow.org/, select the dataset with\n",
        "two clusters, the features x1 and x2 and keep zero hidden layers and linear activation. Train the model\n",
        "by clicking on the play button. Does the classifier correctly learn the boundary?"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "2. Now select the XOR dataset and repeat the training? Does the classifier work?"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "3. Keeping the same dataset, try adding and removing features to see if the performance improves?\n",
        "What is the minimal number of features that are needed to correctly learn the boundary? What are\n",
        "the features? Why do they work well?"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "4. Now pick the concentric circles dataset. Repeat the feature selection process from the last point."
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "Now we can start with the real excercises !"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "6Z62lEnyREle"
      },
      "source": [
        "*Adapted from `pytorch.org/tutorials/beginner/basics/quickstart_tutorial.html`.*"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "# Example 1 : Two-Hidden Layer NN"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "In this first example you will train your first NN ! You will also validate and test your results. The code here is fully shown so that you can analyse it. In particular, be careful at the syntax and the standard commands that are used in pytorch."
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 1,
      "metadata": {},
      "outputs": [],
      "source": [
        "import torch\n",
        "import torch.nn as nn\n",
        "import torch.optim as optim\n",
        "import torchvision\n",
        "import torchvision.transforms as transforms\n",
        "import matplotlib.pyplot as plt\n",
        "from torch.utils.data import DataLoader\n",
        "from torchvision.transforms import ToTensor\n"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "PyTorch has two [primitives to work with data](https://pytorch.org/docs/stable/data.html):\n",
        "``torch.utils.data.DataLoader`` and ``torch.utils.data.Dataset``.\n",
        "``Dataset`` stores the samples and their corresponding labels, and ``DataLoader`` wraps an iterable around\n",
        "the ``Dataset``.\n",
        "\n",
        "PyTorch offers domain-specific libraries such as [TorchText](https://pytorch.org/text/stable/index.html),\n",
        "[TorchVision](https://pytorch.org/vision/stable/index.html), and [TorchAudio](https://pytorch.org/audio/stable/index.html),\n",
        "all of which include datasets. For this tutorial, we  will be using a TorchVision dataset.\n",
        "\n",
        "The ``torchvision.datasets`` module contains ``Dataset`` objects for many real-world vision data like\n",
        "MNIST, CIFAR. In this tutorial, we\n",
        "use the MNIST dataset. Every TorchVision ``Dataset`` includes two arguments: ``transform`` and\n",
        "``target_transform`` to modify the samples and labels respectively.\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 2,
      "metadata": {},
      "outputs": [],
      "source": [
        "# Define transformations for the training and validation sets\n",
        "transform = transforms.Compose([\n",
        "    transforms.ToTensor(), # Feature transformations (convert images to tensors)\n",
        "    transforms.Normalize((0.5,), (0.5,))\n",
        "])\n",
        "\n",
        "# Download and load the training data\n",
        "trainset = torchvision.datasets.MNIST(\n",
        "    root='./data',   # Path where data is stored\n",
        "    train=True, # Training or test dataset\n",
        "    download=True, # Download the data if not available locally\n",
        "    transform=transform) # Feature transformations (convert images to tensors)\n",
        "\n",
        "\n",
        "# Download and load the validation data\n",
        "validationset = torchvision.datasets.MNIST(\n",
        "    root='./data', \n",
        "    train=False, \n",
        "    download=True, \n",
        "    transform=transform)\n",
        "\n"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "We pass the ``Dataset`` as an argument to ``DataLoader``. This wraps an iterable over our dataset, and supports\n",
        "automatic batching, sampling, shuffling and multiprocess data loading. Here we define a batch size of 64, i.e., each element\n",
        "in the dataloader iterable will return a batch of 64 features and labels.\n",
        "\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 3,
      "metadata": {},
      "outputs": [],
      "source": [
        "batch_size = 64\n",
        "\n",
        "# Create data loaders.\n",
        "\n",
        "trainloader = torch.utils.data.DataLoader(\n",
        "    trainset, batch_size=batch_size, shuffle=True)\n",
        "\n",
        "\n",
        "\n",
        "validationloader = torch.utils.data.DataLoader(\n",
        "    validationset, batch_size=batch_size, shuffle=False)"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 4,
      "metadata": {},
      "outputs": [
        {
          "name": "stdout",
          "output_type": "stream",
          "text": [
            "Shape of X [N, C, H, W]: torch.Size([64, 1, 28, 28])\n",
            "Shape of y: torch.Size([64]) torch.int64\n"
          ]
        }
      ],
      "source": [
        "for X, y in validationloader:\n",
        "    print(f\"Shape of X [N, C, H, W]: {X.shape}\")\n",
        "    print(f\"Shape of y: {y.shape} {y.dtype}\")\n",
        "    break"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 5,
      "metadata": {},
      "outputs": [
        {
          "name": "stdout",
          "output_type": "stream",
          "text": [
            "tensor([[[-1.0000, -1.0000, -1.0000, -1.0000, -1.0000, -1.0000, -1.0000,\n",
            "          -1.0000, -1.0000, -1.0000, -1.0000, -1.0000, -1.0000, -1.0000,\n",
            "          -1.0000, -1.0000, -1.0000, -1.0000, -1.0000, -1.0000, -1.0000,\n",
            "          -1.0000, -1.0000, -1.0000, -1.0000, -1.0000, -1.0000, -1.0000],\n",
            "         [-1.0000, -1.0000, -1.0000, -1.0000, -1.0000, -1.0000, -1.0000,\n",
            "          -1.0000, -1.0000, -1.0000, -1.0000, -1.0000, -1.0000, -1.0000,\n",
            "          -1.0000, -1.0000, -1.0000, -1.0000, -1.0000, -1.0000, -1.0000,\n",
            "          -1.0000, -1.0000, -1.0000, -1.0000, -1.0000, -1.0000, -1.0000],\n",
            "         [-1.0000, -1.0000, -1.0000, -1.0000, -1.0000, -1.0000, -1.0000,\n",
            "          -1.0000, -1.0000, -1.0000, -1.0000, -1.0000, -1.0000, -1.0000,\n",
            "          -1.0000, -1.0000, -1.0000, -1.0000, -1.0000, -1.0000, -1.0000,\n",
            "          -1.0000, -1.0000, -1.0000, -1.0000, -1.0000, -1.0000, -1.0000],\n",
            "         [-1.0000, -1.0000, -1.0000, -1.0000, -1.0000, -1.0000, -1.0000,\n",
            "          -1.0000, -1.0000, -1.0000, -1.0000, -1.0000, -1.0000, -1.0000,\n",
            "          -1.0000, -1.0000, -1.0000, -1.0000, -1.0000, -1.0000, -1.0000,\n",
            "          -1.0000, -1.0000, -1.0000, -1.0000, -1.0000, -1.0000, -1.0000],\n",
            "         [-1.0000, -1.0000, -1.0000, -1.0000, -1.0000, -1.0000, -1.0000,\n",
            "          -1.0000, -1.0000, -1.0000, -1.0000, -1.0000, -1.0000, -1.0000,\n",
            "          -1.0000, -1.0000, -1.0000, -1.0000, -1.0000, -1.0000, -1.0000,\n",
            "          -1.0000, -1.0000, -1.0000, -1.0000, -1.0000, -1.0000, -1.0000],\n",
            "         [-1.0000, -1.0000, -1.0000, -1.0000, -1.0000, -1.0000, -1.0000,\n",
            "          -1.0000, -1.0000, -1.0000, -1.0000, -1.0000, -1.0000, -1.0000,\n",
            "          -1.0000, -1.0000, -1.0000, -1.0000, -1.0000, -1.0000, -1.0000,\n",
            "          -1.0000, -1.0000, -1.0000, -1.0000, -1.0000, -1.0000, -1.0000],\n",
            "         [-1.0000, -1.0000, -1.0000, -1.0000, -1.0000, -1.0000, -1.0000,\n",
            "          -1.0000, -1.0000, -1.0000, -1.0000, -1.0000, -1.0000, -1.0000,\n",
            "          -1.0000, -1.0000, -1.0000, -1.0000, -1.0000, -1.0000, -1.0000,\n",
            "          -1.0000, -1.0000, -1.0000, -1.0000, -1.0000, -1.0000, -1.0000],\n",
            "         [-1.0000, -1.0000, -1.0000, -1.0000, -1.0000, -1.0000, -0.3412,\n",
            "           0.4510,  0.2471,  0.1843, -0.5294, -0.7176, -1.0000, -1.0000,\n",
            "          -1.0000, -1.0000, -1.0000, -1.0000, -1.0000, -1.0000, -1.0000,\n",
            "          -1.0000, -1.0000, -1.0000, -1.0000, -1.0000, -1.0000, -1.0000],\n",
            "         [-1.0000, -1.0000, -1.0000, -1.0000, -1.0000, -1.0000,  0.7412,\n",
            "           0.9922,  0.9922,  0.9922,  0.9922,  0.8902,  0.5529,  0.5529,\n",
            "           0.5529,  0.5529,  0.5529,  0.5529,  0.5529,  0.5529,  0.3333,\n",
            "          -0.5922, -1.0000, -1.0000, -1.0000, -1.0000, -1.0000, -1.0000],\n",
            "         [-1.0000, -1.0000, -1.0000, -1.0000, -1.0000, -1.0000, -0.4745,\n",
            "          -0.1059, -0.4353, -0.1059,  0.2784,  0.7804,  0.9922,  0.7647,\n",
            "           0.9922,  0.9922,  0.9922,  0.9608,  0.7961,  0.9922,  0.9922,\n",
            "           0.0980, -1.0000, -1.0000, -1.0000, -1.0000, -1.0000, -1.0000],\n",
            "         [-1.0000, -1.0000, -1.0000, -1.0000, -1.0000, -1.0000, -1.0000,\n",
            "          -1.0000, -1.0000, -1.0000, -1.0000, -0.8667, -0.4824, -0.8902,\n",
            "          -0.4745, -0.4745, -0.4745, -0.5373, -0.8353,  0.8510,  0.9922,\n",
            "          -0.1686, -1.0000, -1.0000, -1.0000, -1.0000, -1.0000, -1.0000],\n",
            "         [-1.0000, -1.0000, -1.0000, -1.0000, -1.0000, -1.0000, -1.0000,\n",
            "          -1.0000, -1.0000, -1.0000, -1.0000, -1.0000, -1.0000, -1.0000,\n",
            "          -1.0000, -1.0000, -1.0000, -1.0000, -0.3490,  0.9843,  0.6392,\n",
            "          -0.8588, -1.0000, -1.0000, -1.0000, -1.0000, -1.0000, -1.0000],\n",
            "         [-1.0000, -1.0000, -1.0000, -1.0000, -1.0000, -1.0000, -1.0000,\n",
            "          -1.0000, -1.0000, -1.0000, -1.0000, -1.0000, -1.0000, -1.0000,\n",
            "          -1.0000, -1.0000, -1.0000, -0.8275,  0.8275,  1.0000, -0.3490,\n",
            "          -1.0000, -1.0000, -1.0000, -1.0000, -1.0000, -1.0000, -1.0000],\n",
            "         [-1.0000, -1.0000, -1.0000, -1.0000, -1.0000, -1.0000, -1.0000,\n",
            "          -1.0000, -1.0000, -1.0000, -1.0000, -1.0000, -1.0000, -1.0000,\n",
            "          -1.0000, -1.0000, -1.0000,  0.0118,  0.9922,  0.8667, -0.6549,\n",
            "          -1.0000, -1.0000, -1.0000, -1.0000, -1.0000, -1.0000, -1.0000],\n",
            "         [-1.0000, -1.0000, -1.0000, -1.0000, -1.0000, -1.0000, -1.0000,\n",
            "          -1.0000, -1.0000, -1.0000, -1.0000, -1.0000, -1.0000, -1.0000,\n",
            "          -1.0000, -1.0000, -0.5373,  0.9529,  0.9922, -0.5137, -1.0000,\n",
            "          -1.0000, -1.0000, -1.0000, -1.0000, -1.0000, -1.0000, -1.0000],\n",
            "         [-1.0000, -1.0000, -1.0000, -1.0000, -1.0000, -1.0000, -1.0000,\n",
            "          -1.0000, -1.0000, -1.0000, -1.0000, -1.0000, -1.0000, -1.0000,\n",
            "          -1.0000, -1.0000,  0.0431,  0.9922,  0.4667, -0.9608, -1.0000,\n",
            "          -1.0000, -1.0000, -1.0000, -1.0000, -1.0000, -1.0000, -1.0000],\n",
            "         [-1.0000, -1.0000, -1.0000, -1.0000, -1.0000, -1.0000, -1.0000,\n",
            "          -1.0000, -1.0000, -1.0000, -1.0000, -1.0000, -1.0000, -1.0000,\n",
            "          -1.0000, -0.9294,  0.6078,  0.9451, -0.5451, -1.0000, -1.0000,\n",
            "          -1.0000, -1.0000, -1.0000, -1.0000, -1.0000, -1.0000, -1.0000],\n",
            "         [-1.0000, -1.0000, -1.0000, -1.0000, -1.0000, -1.0000, -1.0000,\n",
            "          -1.0000, -1.0000, -1.0000, -1.0000, -1.0000, -1.0000, -1.0000,\n",
            "          -1.0000, -0.0118,  0.9922,  0.4275, -1.0000, -1.0000, -1.0000,\n",
            "          -1.0000, -1.0000, -1.0000, -1.0000, -1.0000, -1.0000, -1.0000],\n",
            "         [-1.0000, -1.0000, -1.0000, -1.0000, -1.0000, -1.0000, -1.0000,\n",
            "          -1.0000, -1.0000, -1.0000, -1.0000, -1.0000, -1.0000, -1.0000,\n",
            "          -0.4118,  0.9686,  0.8824, -0.5529, -1.0000, -1.0000, -1.0000,\n",
            "          -1.0000, -1.0000, -1.0000, -1.0000, -1.0000, -1.0000, -1.0000],\n",
            "         [-1.0000, -1.0000, -1.0000, -1.0000, -1.0000, -1.0000, -1.0000,\n",
            "          -1.0000, -1.0000, -1.0000, -1.0000, -1.0000, -1.0000, -0.8510,\n",
            "           0.7333,  0.9922,  0.3020, -1.0000, -1.0000, -1.0000, -1.0000,\n",
            "          -1.0000, -1.0000, -1.0000, -1.0000, -1.0000, -1.0000, -1.0000],\n",
            "         [-1.0000, -1.0000, -1.0000, -1.0000, -1.0000, -1.0000, -1.0000,\n",
            "          -1.0000, -1.0000, -1.0000, -1.0000, -1.0000, -0.9765,  0.5922,\n",
            "           0.9922,  0.7176, -0.7255, -1.0000, -1.0000, -1.0000, -1.0000,\n",
            "          -1.0000, -1.0000, -1.0000, -1.0000, -1.0000, -1.0000, -1.0000],\n",
            "         [-1.0000, -1.0000, -1.0000, -1.0000, -1.0000, -1.0000, -1.0000,\n",
            "          -1.0000, -1.0000, -1.0000, -1.0000, -1.0000, -0.7020,  0.9922,\n",
            "           0.9922, -0.3961, -1.0000, -1.0000, -1.0000, -1.0000, -1.0000,\n",
            "          -1.0000, -1.0000, -1.0000, -1.0000, -1.0000, -1.0000, -1.0000],\n",
            "         [-1.0000, -1.0000, -1.0000, -1.0000, -1.0000, -1.0000, -1.0000,\n",
            "          -1.0000, -1.0000, -1.0000, -1.0000, -0.7569,  0.7569,  0.9922,\n",
            "          -0.0980, -0.9922, -1.0000, -1.0000, -1.0000, -1.0000, -1.0000,\n",
            "          -1.0000, -1.0000, -1.0000, -1.0000, -1.0000, -1.0000, -1.0000],\n",
            "         [-1.0000, -1.0000, -1.0000, -1.0000, -1.0000, -1.0000, -1.0000,\n",
            "          -1.0000, -1.0000, -1.0000, -1.0000,  0.0431,  0.9922,  0.9922,\n",
            "          -0.5922, -1.0000, -1.0000, -1.0000, -1.0000, -1.0000, -1.0000,\n",
            "          -1.0000, -1.0000, -1.0000, -1.0000, -1.0000, -1.0000, -1.0000],\n",
            "         [-1.0000, -1.0000, -1.0000, -1.0000, -1.0000, -1.0000, -1.0000,\n",
            "          -1.0000, -1.0000, -1.0000, -0.5216,  0.8980,  0.9922,  0.9922,\n",
            "          -0.5922, -1.0000, -1.0000, -1.0000, -1.0000, -1.0000, -1.0000,\n",
            "          -1.0000, -1.0000, -1.0000, -1.0000, -1.0000, -1.0000, -1.0000],\n",
            "         [-1.0000, -1.0000, -1.0000, -1.0000, -1.0000, -1.0000, -1.0000,\n",
            "          -1.0000, -1.0000, -1.0000, -0.0510,  0.9922,  0.9922,  0.7176,\n",
            "          -0.6863, -1.0000, -1.0000, -1.0000, -1.0000, -1.0000, -1.0000,\n",
            "          -1.0000, -1.0000, -1.0000, -1.0000, -1.0000, -1.0000, -1.0000],\n",
            "         [-1.0000, -1.0000, -1.0000, -1.0000, -1.0000, -1.0000, -1.0000,\n",
            "          -1.0000, -1.0000, -1.0000, -0.0510,  0.9922,  0.6235, -0.8588,\n",
            "          -1.0000, -1.0000, -1.0000, -1.0000, -1.0000, -1.0000, -1.0000,\n",
            "          -1.0000, -1.0000, -1.0000, -1.0000, -1.0000, -1.0000, -1.0000],\n",
            "         [-1.0000, -1.0000, -1.0000, -1.0000, -1.0000, -1.0000, -1.0000,\n",
            "          -1.0000, -1.0000, -1.0000, -1.0000, -1.0000, -1.0000, -1.0000,\n",
            "          -1.0000, -1.0000, -1.0000, -1.0000, -1.0000, -1.0000, -1.0000,\n",
            "          -1.0000, -1.0000, -1.0000, -1.0000, -1.0000, -1.0000, -1.0000]]])\n"
          ]
        },
        {
          "data": {
            "text/plain": [
              "<matplotlib.image.AxesImage at 0x1394e7b00>"
            ]
          },
          "execution_count": 5,
          "metadata": {},
          "output_type": "execute_result"
        },
        {
          "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",
        "print(X[0])\n",
        "plt.imshow(X[0,0], cmap=\"gray\")"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "To define a neural network in PyTorch, we use`nn.Sequential` and define the layers of the network. The `torch.nn` namespace provides all the building blocks you need to build your own neural network. Every module in PyTorch subclasses the `nn.Module` and a neural network is a module itself that consists of other modules (layers). This nested structure allows for building and managing complex architectures easily.\n",
        "\n",
        "To accelerate operations in the neural network, we move it to the GPU if available."
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 10,
      "metadata": {},
      "outputs": [
        {
          "name": "stdout",
          "output_type": "stream",
          "text": [
            "Using cpu\n"
          ]
        }
      ],
      "source": [
        "# Get cpu or gpu device for training.\n",
        "device = \"cuda\" if torch.cuda.is_available() else \"cpu\"\n",
        "print(f\"Using {device}\")"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 11,
      "metadata": {},
      "outputs": [
        {
          "name": "stdout",
          "output_type": "stream",
          "text": [
            "Sequential(\n",
            "  (0): Flatten(start_dim=1, end_dim=-1)\n",
            "  (1): Linear(in_features=784, out_features=512, bias=True)\n",
            "  (2): ReLU()\n",
            "  (3): Linear(in_features=512, out_features=512, bias=True)\n",
            "  (4): ReLU()\n",
            "  (5): Linear(in_features=512, out_features=10, bias=True)\n",
            ")\n"
          ]
        }
      ],
      "source": [
        "# Define model. nn.Sequential is the standard command.\n",
        "# In the following instead we'll construct a class of two layers newral networks, another way of constructing a model.\n",
        "model = nn.Sequential( # Ordered container of modules\n",
        "    nn.Flatten(), # Convert the 28x28 matrix of pixels into an array of length 784\n",
        "    nn.Linear(28*28, 512), # Apply a linear transformation on the input using weights and biases\n",
        "    nn.ReLU(), # Non-linear activation\n",
        "    nn.Linear(512, 512),\n",
        "    nn.ReLU(),\n",
        "    nn.Linear(512, 10)\n",
        ").to(device)\n",
        "\n",
        "print(model) # Print the structure of the neural network"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 12,
      "metadata": {},
      "outputs": [],
      "source": [
        "# In this example we will stick to this model.\n",
        "# Define a class conteining your model, a Two-Hidden Layer Neural Network. All the relevant parameters are specified.\n",
        "#Note the ReLU activation function.\n",
        "class TwoHiddenLayerNN(nn.Module):\n",
        "    def __init__(self):\n",
        "        super(TwoHiddenLayerNN, self).__init__()\n",
        "        self.fc1 = nn.Linear(28 * 28, 256)  # Input to first hidden layer\n",
        "        self.fc2 = nn.Linear(256, 128)      # First hidden to second hidden\n",
        "        self.fc3 = nn.Linear(128, 10)       # Second hidden to output\n",
        "        self.relu = nn.ReLU()\n",
        "        \n",
        "    def forward(self, x):\n",
        "        x = x.view(-1, 28 * 28)            # Flatten the image\n",
        "        x = self.relu(self.fc1(x))         # First hidden layer with ReLU\n",
        "        x = self.relu(self.fc2(x))         # Second hidden layer with ReLU\n",
        "        x = self.fc3(x)                    # Output layer\n",
        "        return x\n",
        "\n",
        "# Instantiate the network\n",
        "net = TwoHiddenLayerNN()"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 13,
      "metadata": {},
      "outputs": [],
      "source": [
        "#To train a model, we need a loss function and an optimizer.\n",
        "#You have to specify a loss, i.e. cross-entropy in this case, and also a way to optimise your weights, i.e. Adam (Adaptive Moment Estimation) in this case. You can use whatever you prefer, also SGD as you will do below.\n",
        "criterion = nn.CrossEntropyLoss()\n",
        "learning_rate = 1e-3\n",
        "optimizer = optim.Adam(net.parameters(), lr=learning_rate) # Pass model parameters to optimizer"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 14,
      "metadata": {},
      "outputs": [
        {
          "name": "stdout",
          "output_type": "stream",
          "text": [
            "Epoch 1/10, Train Loss: 0.3438, Validation Loss: 0.1819, Train Acc: 89.62%, Validation Acc: 94.40%\n",
            "Epoch 2/10, Train Loss: 0.1519, Validation Loss: 0.1308, Train Acc: 95.30%, Validation Acc: 95.87%\n",
            "Epoch 3/10, Train Loss: 0.1118, Validation Loss: 0.0973, Train Acc: 96.53%, Validation Acc: 96.94%\n",
            "Epoch 4/10, Train Loss: 0.0921, Validation Loss: 0.0906, Train Acc: 97.09%, Validation Acc: 97.26%\n",
            "Epoch 5/10, Train Loss: 0.0776, Validation Loss: 0.0912, Train Acc: 97.53%, Validation Acc: 97.08%\n",
            "Epoch 6/10, Train Loss: 0.0678, Validation Loss: 0.1021, Train Acc: 97.80%, Validation Acc: 97.04%\n",
            "Epoch 7/10, Train Loss: 0.0597, Validation Loss: 0.0786, Train Acc: 98.07%, Validation Acc: 97.53%\n",
            "Epoch 8/10, Train Loss: 0.0544, Validation Loss: 0.1078, Train Acc: 98.29%, Validation Acc: 96.77%\n",
            "Epoch 9/10, Train Loss: 0.0474, Validation Loss: 0.0944, Train Acc: 98.38%, Validation Acc: 97.10%\n",
            "Epoch 10/10, Train Loss: 0.0437, Validation Loss: 0.0919, Train Acc: 98.57%, Validation Acc: 97.21%\n"
          ]
        }
      ],
      "source": [
        "#this example is very simple: we train our model onto our data and we want to monitor how the training and validation loss decreases with the number of epochs.\n",
        "epochs = 10 \n",
        "train_losses, val_losses = [], []\n",
        "train_accuracies, val_accuracies = [], []\n",
        "\n",
        "for epoch in range(epochs):\n",
        "    net.train()\n",
        "    running_loss = 0.0\n",
        "    correct_train = 0\n",
        "    total_train = 0\n",
        "    \n",
        "    for images, labels in trainloader:\n",
        "        optimizer.zero_grad()\n",
        "        outputs = net(images)\n",
        "        loss = criterion(outputs, labels)\n",
        "        loss.backward()\n",
        "        optimizer.step()\n",
        "        \n",
        "        running_loss += loss.item()\n",
        "        _, predicted = torch.max(outputs.data, 1)\n",
        "        total_train += labels.size(0)\n",
        "        correct_train += (predicted == labels).sum().item()\n",
        "        \n",
        "    train_losses.append(running_loss / len(trainloader))\n",
        "    train_accuracy = 100 * correct_train / total_train\n",
        "    train_accuracies.append(train_accuracy)\n",
        "    \n",
        "    # Validation Phase\n",
        "    net.eval()\n",
        "    val_loss = 0.0\n",
        "    correct_val = 0\n",
        "    total_val = 0\n",
        "    with torch.no_grad():\n",
        "        for images, labels in validationloader:\n",
        "            outputs = net(images)\n",
        "            loss = criterion(outputs, labels)\n",
        "            val_loss += loss.item()\n",
        "            _, predicted = torch.max(outputs.data, 1)\n",
        "            total_val += labels.size(0)\n",
        "            correct_val += (predicted == labels).sum().item()\n",
        "    \n",
        "    val_losses.append(val_loss / len(validationloader))\n",
        "    val_accuracy = 100 * correct_val / total_val\n",
        "    val_accuracies.append(val_accuracy)\n",
        "    \n",
        "    print(f'Epoch {epoch+1}/{epochs}, '\n",
        "          f'Train Loss: {train_losses[-1]:.4f}, '\n",
        "          f'Validation Loss: {val_losses[-1]:.4f}, '\n",
        "          f'Train Acc: {train_accuracy:.2f}%, '\n",
        "          f'Validation Acc: {val_accuracy:.2f}%')\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 9,
      "metadata": {},
      "outputs": [
        {
          "name": "stdout",
          "output_type": "stream",
          "text": [
            "Final Test Accuracy: 96.69%\n"
          ]
        }
      ],
      "source": [
        "#We here print our final test accuracy.\n",
        "net.eval()\n",
        "correct_test = 0\n",
        "total_test = 0\n",
        "with torch.no_grad():\n",
        "    for images, labels in validationloader:\n",
        "        outputs = net(images)\n",
        "        _, predicted = torch.max(outputs.data, 1)\n",
        "        total_test += labels.size(0)\n",
        "        correct_test += (predicted == labels).sum().item()\n",
        "\n",
        "test_accuracy = 100 * correct_test / total_test\n",
        "print(f'Final Test Accuracy: {test_accuracy:.2f}%')"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 15,
      "metadata": {},
      "outputs": [
        {
          "data": {
            "image/png": "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t956i7lz5/LJJ59gamqqO/Yvv/yCl5cXHTp0eGF8d+/epU6dOiQlJfH1119TrFgx/vvvPz7++GOuXbvG7NmzMTc355133mHu3LnMmjULe3t73fOXLVtGQkICffv2BbQXt+vXr8/t27d17/O5c+f48ssvOXPmDFu3btUbqbdmzRr27NnDl19+iYeHB25ubq98T5933mBiYoKJiX4fZv/+/WnatCl//vknt27d4osvvqBBgwacPn2aQoUKATB58mQ+++wzunfvzuTJk7l//z7jx4+ndu3aHDlyhJIlSwKwadMm2rZtS5kyZfjxxx8pWrQoN27cYPPmzeli6dSpE926daN///6cOXOGsWPHAk+mfxw4cIBu3brRrVs3xo8fj6WlJTdv3mT79u2vfO2iAFGEENli4cKFCqAcOXLkhfvUqlVLcXNzU6Kjo3XbUlJSlHLlyine3t5KamqqoiiKUq5cOaV9+/YvbOfevXsKoMyYMSNTMWo0GsXLy0spX768otFodNujo6MVNzc3pU6dOrpto0aNUqysrJRHjx7ptp0/f14BlJ9//lm3rXTp0krlypWV5ORkvWO1adNG8fT01B0n7f3p3bt3hmINCgpSgBfe9uzZo9u3fv36CqD8+++/em289957iomJiXLz5k1FURRl7ty5CqCsWLFCb7/vvvtOAZTNmzcriqIou3fvVgDl888/f2mMPj4+iqWlpa59RVGU+Ph4xcnJSRk0aJBu26t+n0IIIXLO4sWLFUCZO3euoija7zxbW1ulbt26evv169dPMTc3V86fP//CtiZOnKgAypYtW164z44dOxRA2bFjh972tO+1hQsX6ra9++67CqAsWLDgpa8hNTVVSU5OVm7evJnu+65Ro0ZKoUKFlIiIiFfGtHr1at22kJAQxczMTJkwYcJLjz1mzBgFUA4dOqS3/f3331dUKpVy6dIlRVEU5fTp0wqg/Prrr3r71ahRQ6lataru58mTJysmJibpzpf+/vtvBVDWr1+v2wYoDg4OyoMHD14aY5q084Hn3fr376/bL+2cpEOHDnrP37dvnwIokyZNUhRFUR4+fKhYWVkprVq10tsvODhYUavVSo8ePXTb/Pz8FD8/PyU+Pv6F8X311VcKoEydOlVv+5AhQxRLS0vdeeAPP/ygAHrnYEI8S4bWC5FLYmNjOXToEJ07d8bW1la33dTUlF69enH79m0uXboEQI0aNdiwYQNjxoxh586dxMfH67Xl5OSEn58f33//PT/++CMnTpzQDW97mUuXLhEaGkqvXr30rkrb2trSqVMnDh48qBtq2K9fP+Lj41m+fLluv4ULF6JWq3XF565evcrFixfp2bMnoL0CnnZr1aoVYWFhuteUplOnTpl52/jwww85cuRIululSpX09rOzs+Ott97S29ajRw9SU1PZvXs3ANu3b8fGxobOnTvr7Zc2aiBtKsGGDRsAGDp06Cvjq1SpEkWLFtX9bGlpib+/Pzdv3tRte9XvUwghRM6ZP38+VlZWvP3224D2O69Lly7s2bOHK1eu6PbbsGEDDRs2pEyZMi9sa8OGDfj7+9OkSZNsjfF5340REREMHjyYIkWKYGZmhrm5OT4+PgC6Yd1xcXHs2rWLrl274urq+sL2GzRoQMWKFZk1a5Zu29y5c1GpVAwcOPClsW3fvp2yZctSo0YNve19+vRBURRdL3H58uWpWrUqCxcu1O1z4cIFDh8+rDck/L///qNcuXJUqlRJ77yhefPmz52S0KhRIxwdHV8a49P8/Pyee94wbty4dPumnb+kqVOnDj4+PuzYsQPQ9ozHx8enG11YpEgRGjVqpDtvuHz5MteuXaN///5YWlq+MsZnz1cqVKhAQkICERERAFSvXh2Arl27smLFCkJCQjL24kWBIom8ELnk4cOHKIqCp6dnuse8vLwAdEOtZ86cyaeffsqaNWto2LAhTk5OtG/fXnfCkTZ/vXnz5kydOpUqVarg6urKBx98QHR09AtjSGv/RTGkpqby8OFDAAICAqhevbruC1mj0bB06VLatWuHk5MTgG7O4Mcff4y5ubnebciQIQDp5vI979gv4+3tTbVq1dLdnr4YAuDu7p7uuR4eHnqv+/79+3h4eKQrrufm5oaZmZluv7t372Jqaqp7/ss4Ozun26ZWq/WS9Vf9PoUQQuSMq1evsnv3blq3bo2iKDx69IhHjx7pLug+XdPk7t27r1wRJSP7ZJa1tbXeUHTQTitr1qwZ//zzD5988gnbtm3j8OHDHDx4EED3HfPw4UM0Gk2GYvrggw/Ytm0bly5dIjk5md9++43OnTu/8rvu/v37GTp3AW0nwIEDB3T1AtI6ALp3767b586dO5w+fTrdeYOdnR2Korz2eYOlpeVzzxvSLoI87Xmv3cPDQ++84UUxeHl56Z03QMZX1Hn23CGton7a77VevXqsWbOGlJQUevfujbe3N+XKlZPaOkKPJPJC5BJHR0dMTEwICwtL91hoaCgALi4uANjY2DBhwgQuXrxIeHg4c+bM4eDBg7Rt21b3HB8fH+bPn094eDiXLl1i5MiRzJ49m9GjR78whrQvjhfFYGJionfVu2/fvhw8eJALFy6wceNGwsLCdHPcno537Nixz736/bye85dVqH8dTxciShMeHg48ed3Ozs7cuXMHRVH09ouIiCAlJUX3elxdXdFoNLrnv66M/D6FEEJkvwULFqAoCn///TeOjo66W+vWrQFYtGiRriiqq6srt2/ffml7GdknrUf22SKqL1o7/Hnfi2fPnuXUqVN8//33DB8+nAYNGlC9evV0CaCTkxOmpqavjAm0o9ScnZ2ZNWsWK1euJDw8PEMjz5ydnTN07gLQvXt31Go1gYGBaDQalixZQvv27fXOLVxcXChfvvwLzxue7TnPqfMG4Lnf8+Hh4XrnDfDi86anzxuADP0eMqpdu3Zs27aNyMhIdu7cibe3Nz169NArTiwKNknkhcglNjY21KxZk3/++UevtzY1NZWlS5fi7e2Nv79/uue5u7vTp08funfvzqVLl55bZdff358vvviC8uXLc/z48RfGUKpUKQoXLsyff/6pl8zGxsayatUqXSX7NN27d8fS0pLAwEACAwMpXLgwzZo102uvZMmSnDp16rlXv6tVq4adnV2m36usiI6OTldR/s8//8TExERXdK5x48bExMSwZs0avf0WL16sexygZcuWgLZCf3bLyO9TCCHE69NoNCxatAg/Pz927NiR7vbRRx8RFhamm07VsmVLduzYkW5K2NNatmzJ5cuXX1p0rFixYgB6q7sAz1315EXSktdn1z6fN2+e3s9WVlbUr1+flStXvvBCQRpLS0sGDhzIokWL+PHHH6lUqRJvvPHGK2Np3Lgx58+fT3d+sXjxYlQqFQ0bNtRtc3R0pH379ixevJj//vuP8PDwdJXW27Rpw7Vr13B2dn7ueUPa+5cbnl1vfv/+/dy8eZMGDRoAULt2baysrFi6dKnefrdv32b79u268wZ/f3/8/PxYsGBBtqzG8zS1Wk39+vX57rvvADhx4kS2ti/yL6laL0Q22759e7rK5qCtMj958mSaNm1Kw4YN+fjjj7GwsGD2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T+Lt7a1L4p918uRJunTp8tJjZMSz7yvA3Llz+f3337l58ybx8fEkJSXppgpEREQQGhpK48aNX9jmgAED+PXXX/nkk0+IiIhg3bp1bNu27bVjFaKgiklM4cqdaK487mG/HKFN3sMiE174HE8HS0q62+H/OFkv6W5LSXc7bNWGT6MNH4GRK+JojZ3ajOjEFK7djaG0h72hQxJCZBOVSpVtw10N6dkT9mnTpjF9+nRmzJhB+fLlsbGxYcSIESQlJb20nWeLO6lUKlJTXz5f7OnnpFXcfvo5z1bhzuhc4edJe+7z2kzb1rJlS27evMm6devYunUrjRs3ZujQofzwww9UqVKFoKAgNmzYwNatW+natStNmjTh77//znJMIv+Qz7u+vPB5f/DgAWvWrCE5OZk5c+botms0GhYsWMB3332XrsDfs171uImJSbo4kpOT0+337Pu6YsUKRo4cybRp06hduzZ2dnZ8//33HDp0KEPHBejduzdjxozhwIEDHDhwgGLFilG3bt1XPk+Igi42MYUrEdpk/erjf6/ciSHkUfwLn+Nur37cu26H/+NkvaS7LfaWebdwZf7/RsrjTExUlPG05/CNB5wLiZJEXgiR5+3Zs4d27drxzjvvANoT7StXrlCmTJlcjaNUqVIcPnyYXr166bYdPXo0y+2VKFECCwsL9u7dS48ePQDtCfnRo0f1Cnm5urrSp08f+vTpQ926dRk9ejQ//PADAPb29nTr1o1u3brRuXNnWrRowYMHDzJd1VuIvCI/f97/+OMPvL29WbNmjd72bdu2MXnyZL755hsqVKjA7du3uXz58nN75StUqMC2bdv0hsE/zdXVVW81gKioKIKCgl75evbs2UOdOnX0Rhlcu3ZNd9/Ozo5ixYqxbds2GjZs+Nw2nJ2dad++PQsXLuTAgQO66QJCCK24pJTHiXrasHjt0PiXJeyudmptou5mh7/7k6TdwSrvJuwvIol8Lijr9TiRD42iU1VDRyOEEC9XokQJVq1axf79+3F0dOTHH38kPDw810/shw8fznvvvUe1atWoU6cOy5cv5/Tp03rzW1/k2WrYAGXLluX9999n9OjRODk5UbRoUaZOnUpcXBz9+/cHtPNyq1atSkBAAImJifz333+61z19+nQ8PT2pVKkSJiYmrFy5Eg8PDwoVKpStr1uI3JSfP+/z58+nc+fOlCtX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mzypX5vTjZklPWJC9OOSiIjUO7cl8j4+PiQmJpKcnMzll19efTw5OZnLLrvspK9JSkriiy++qHFs8eLF9O/fv3p9/G85nU5SUlLo2bOn64IXEZF60SrIl1adfTmnc6vqY0X2CrZl2qqn5W9Ot7E/twhbaQXFZQ725hRV7919KiF+3tVJ/fEJfqsgI/mPDLYSEWjFW8X3pJa0Pl5ERBqSW6fWT506lYkTJ9K/f3+SkpKYNWsWqamp1fvCP/LIIxw8eJB33nkHMCrUv/7660ydOpXbbruNn3/+mbfeeot58+ZVtzlt2jQGDx5MQkICNpuNV199lZSUFN544w23fEYREambAKsXiXFhJMaF1TheXFZBls3OIVsphwrsZNlKycw37h+ylRqPbaWUlleSX1JOfkk5Ow4VnvJ9TCYID7ASFWIlMsiXVscl/FHBvrQ6ej/M3wezWSOuUlPViHw3JfIiItIA3JrIX3311eTm5vLkk0+SkZFBjx49WLhwIXFxcQBkZGSQmppafX58fDwLFy7k/vvv54033iAmJoZXX321xh7yeXl53H777WRmZhISEkLfvn1ZunQpAwcObPDPJyIi9cffx4t2EV60iwg45TlOpxNbaQVZttKj0/ON5L76cUEph/JLySqwU1HpJKfQTk6hnU2cevcSb4vJmDkQbCT8kcFWWh1N9qtG+1sF+xLsq/X7zYWj0snWjKOF7mJU6E5EROqfW/eRb6y0V6+ISPNSWenkcHHZ0ZF8O5m2UmOk32avHtk/ZLOTW2TndHtNP28LkcFWOkcF8ebE/nWOUX2T67nqmu7KKuCCF5fi72Nh4xMjsWjGhoiI1IJH7CMvIiLSWJjNJiICjXXy3WNOfV65o5KcQjuHbHYy80vJKjiW8B86LvnPLymnpNzBvtxi/H3U1TZ1Vevju0YHK4kXEZEGoW8XIiIip8nbYiY6xI/oED/4nV1KS8sd1SP7mvjW9F3YLZKPJidRUak/axERaRhK5EVERFzM19tCbLg/seH+7g5FGoC/jxf924X98YkiIiIuon12RERERERERDyIEnkRERERERERD6JEXkRERERERMSDKJEXERERERER8SBK5EVEREREREQ8iBJ5EREREREREQ+iRF5ERERERETEgyiRFxEREREREfEgSuRFREREREREPIgSeREREREREREPokReRERERERExIMokRcRERERERHxIErkRURERERERDyIEnkRERERERERD+Ll7gAaI6fTCYDNZnNzJCIiIoaqPqmqj5K6U38vIiKNyZn09UrkT6KgoACAtm3bujkSERGRmgoKCggJCXF3GE2C+nsREWmMTqevNzn10/4JKisrSU9PJygoCJPJVKe2bDYbbdu2JS0tjeDgYBdFKLqurqdrWj90XV2vuV5Tp9NJQUEBMTExmM1aGecK6u8bN13T+qHr6nq6pq7XXK/pmfT1GpE/CbPZTJs2bVzaZnBwcLP6S9hQdF1dT9e0fui6ul5zvKYaiXct9feeQde0fui6up6uqes1x2t6un29ftIXERERERER8SBK5EVEREREREQ8iBL5ema1Wvnb3/6G1Wp1dyhNiq6r6+ma1g9dV9fTNZXGSH8vXU/XtH7ourqerqnr6Zr+MRW7ExEREREREfEgGpEXERERERER8SBK5EVEREREREQ8iBJ5EREREREREQ+iRF5ERERERETEgyiRr2czZswgPj4eX19fEhMT+emnn9wdkseaPn06AwYMICgoiFatWjF27Fi2b9/u7rCanOnTp2MymZgyZYq7Q/FoBw8e5Prrryc8PBx/f3/69OnDmjVr3B2WR6uoqOCxxx4jPj4ePz8/2rdvz5NPPkllZaW7Q5NmTn29a6m/r3/q611H/b1rqa8/fUrk69EHH3zAlClTePTRR1m3bh3Dhw9n9OjRpKamujs0j7RkyRLuuusufvnlF5KTk6moqGDEiBEUFRW5O7QmY/Xq1cyaNYtevXq5OxSPduTIEYYOHYq3tzdff/01W7Zs4Z///CctWrRwd2ge7bnnnuNf//oXr7/+Olu3buX555/nhRde4LXXXnN3aNKMqa93PfX39Ut9veuov3c99fWnT9vP1aNBgwbRr18/Zs6cWX2sa9eujB07lunTp7sxsqYhOzubVq1asWTJEs466yx3h+PxCgsL6devHzNmzODpp5+mT58+vPzyy+4OyyM9/PDDLF++XKNyLjZmzBgiIyN56623qo+NGzcOf39/3n33XTdGJs2Z+vr6p/7eddTXu5b6e9dTX3/6NCJfT8rKylizZg0jRoyocXzEiBGsWLHCTVE1Lfn5+QCEhYW5OZKm4a677uLiiy/mggsucHcoHm/BggX079+fq666ilatWtG3b1/+/e9/uzssjzds2DC+++47duzYAcD69etZtmwZF110kZsjk+ZKfX3DUH/vOurrXUv9veuprz99Xu4OoKnKycnB4XAQGRlZ43hkZCSZmZluiqrpcDqdTJ06lWHDhtGjRw93h+Px5s+fz9q1a1m9erW7Q2kS9uzZw8yZM5k6dSr/93//x6pVq7j33nuxWq3ccMMN7g7PYz300EPk5+fTpUsXLBYLDoeDZ555hmuvvdbdoUkzpb6+/qm/dx319a6n/t711NefPiXy9cxkMtV47HQ6TzgmZ+7uu+9mw4YNLFu2zN2heLy0tDTuu+8+Fi9ejK+vr7vDaRIqKyvp378/zz77LAB9+/Zl8+bNzJw5Ux17HXzwwQfMnTuX999/n+7du5OSksKUKVOIiYnhxhtvdHd40oypr68/6u9dQ319/VB/73rq60+fEvl6EhERgcViOeEX+aysrBN+uZczc88997BgwQKWLl1KmzZt3B2Ox1uzZg1ZWVkkJiZWH3M4HCxdupTXX38du92OxWJxY4SeJzo6mm7dutU41rVrVz7++GM3RdQ0PPjggzz88MNcc801APTs2ZP9+/czffp0de7iFurr65f6e9dRX18/1N+7nvr606c18vXEx8eHxMREkpOTaxxPTk5myJAhborKszmdTu6++24++eQTvv/+e+Lj490dUpNw/vnns3HjRlJSUqpv/fv357rrriMlJUUdey0MHTr0hK2SduzYQVxcnJsiahqKi4sxm2t2WxaLRVvSiNuor68f6u9dT319/VB/73rq60+fRuTr0dSpU5k4cSL9+/cnKSmJWbNmkZqayuTJk90dmke66667eP/99/n8888JCgqqHgEJCQnBz8/PzdF5rqCgoBPWHQYEBBAeHq71iLV0//33M2TIEJ599lnGjx/PqlWrmDVrFrNmzXJ3aB7tkksu4ZlnniE2Npbu3buzbt06XnzxRSZNmuTu0KQZU1/veurvXU99ff1Qf+966uvPgFPq1RtvvOGMi4tz+vj4OPv16+dcsmSJu0PyWMBJb2+//ba7Q2tyzj77bOd9993n7jA82hdffOHs0aOH02q1Ort06eKcNWuWu0PyeDabzXnfffc5Y2Njnb6+vs727ds7H330Uafdbnd3aNLMqa93LfX3DUN9vWuov3ct9fWnT/vIi4iIiIiIiHgQrZEXERERERER8SBK5EVEREREREQ8iBJ5EREREREREQ+iRF5ERERERETEgyiRFxEREREREfEgSuRFREREREREPIgSeREREREREREPokReRERERERExIMokReRRslkMvHZZ5+5OwwRERGpJ+rrRWpPibyInOCmm27CZDKdcBs1apS7QxMREREXUF8v4tm83B2AiDROo0aN4u23365xzGq1uikaERERcTX19SKeSyPyInJSVquVqKioGrfQ0FDAmAo3c+ZMRo8ejZ+fH/Hx8Xz44Yc1Xr9x40bOO+88/Pz8CA8P5/bbb6ewsLDGObNnz6Z79+5YrVaio6O5++67azyfk5PD5Zdfjr+/PwkJCSxYsKB+P7SIiEgzor5exHMpkReRWnn88ccZN24c69ev5/rrr+faa69l69atABQXFzNq1ChCQ0NZvXo1H374Id9++22NznvmzJncdddd3H777WzcuJEFCxbQsWPHGu8xbdo0xo8fz4YNG7jooou47rrrOHz4cIN+ThERkeZKfb1II+YUEfmNG2+80WmxWJwBAQE1bk8++aTT6XQ6AefkyZNrvGbQoEHOP/3pT06n0+mcNWuWMzQ01FlYWFj9/FdffeU0m83OzMxMp9PpdMbExDgfffTRU8YAOB977LHqx4WFhU6TyeT8+uuvXfY5RUREmiv19SKeTWvkReSkzj33XGbOnFnjWFhYWPX9pKSkGs8lJSWRkpICwNatW+nduzcBAQHVzw8dOpTKykq2b9+OyWQiPT2d888//3dj6NWrV/X9gIAAgoKCyMrKqu1HEhERkeOorxfxXErkReSkAgICTpj+9kdMJhMATqez+v7JzvHz8zut9ry9vU94bWVl5RnFJCIiIienvl7Ec2mNvIjUyi+//HLC4y5dugDQrVs3UlJSKCoqqn5++fLlmM1mOnXqRFBQEO3ateO7775r0JhFRETk9KmvF2m8NCIvIidlt9vJzMyscczLy4uIiAgAPvzwQ/r378+wYcN47733WLVqFW+99RYA1113HX/729+48cYbeeKJJ8jOzuaee+5h4sSJREZGAvDEE08wefJkWrVqxejRoykoKGD58uXcc889DftBRUREmin19SKeS4m8iJzUN998Q3R0dI1jnTt3Ztu2bYBRZXb+/PnceeedREVF8d5779GtWzcA/P39WbRoEffddx8DBgzA39+fcePG8eKLL1a3deONN1JaWspLL73EAw88QEREBFdeeWXDfUAREZFmTn29iOcyOZ1Op7uDEBHPYjKZ+PTTTxk7dqy7QxEREZF6oL5epHHTGnkRERERERERD6JEXkRERERERMSDaGq9iIiIiIiIiAfRiLyIiIiIiIiIB1EiLyIiIiIiIuJBlMiLiIiIiIiIeBAl8iIiIiIiIiIeRIm8iIiIiIiIiAdRIi8iIiIiIiLiQZTIi4iIiIiIiHgQJfIiIiIiIiIiHuT/AR2kKSrL7pqgAAAAAElFTkSuQmCC",
            "text/plain": [
              "<Figure size 1200x500 with 2 Axes>"
            ]
          },
          "metadata": {},
          "output_type": "display_data"
        }
      ],
      "source": [
        "## As a first small excercise, plot the training loss and the validation loss.\n",
        "## Also plot the training and validation accuracy.\n",
        "## Put the epochs in the x-axis.\n",
        "\n",
        "plt.figure(figsize=(12, 5))\n",
        "plt.subplot(1, 2, 1)\n",
        "plt.plot(train_losses, label='Training Loss')\n",
        "plt.plot(val_losses, label='Validation Loss')\n",
        "plt.title('Loss over Epochs')\n",
        "plt.xlabel('Epoch')\n",
        "plt.ylabel('Loss')\n",
        "plt.legend()\n",
        "\n",
        "plt.subplot(1, 2, 2)\n",
        "plt.plot(train_accuracies, label='Training Accuracy')\n",
        "plt.plot(val_accuracies, label='Validation Accuracy')\n",
        "plt.title('Accuracy over Epochs')\n",
        "plt.xlabel('Epoch')\n",
        "plt.ylabel('Accuracy (%)')\n",
        "plt.legend()\n",
        "\n",
        "plt.show()"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "# Excercise 1: Testing various activation functions."
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "The objective of this excercise is to investigate the impact of different activation functions on the performance of a two-hidden layer neural network using the MNIST dataset."
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 16,
      "metadata": {},
      "outputs": [],
      "source": [
        "# Define transformations\n",
        "transform = transforms.Compose([\n",
        "    transforms.ToTensor(),\n",
        "    transforms.Normalize((0.5,), (0.5,))\n",
        "])\n",
        "\n",
        "# Load training and validation datasets\n",
        "trainset = torchvision.datasets.MNIST(\n",
        "    root='./data', train=True, download=True, transform=transform)\n",
        "trainloader = torch.utils.data.DataLoader(\n",
        "    trainset, batch_size=64, shuffle=True)\n",
        "\n",
        "validationset = torchvision.datasets.MNIST(\n",
        "    root='./data', train=False, download=True, transform=transform)\n",
        "validationloader = torch.utils.data.DataLoader(\n",
        "    validationset, batch_size=64, shuffle=False)"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 17,
      "metadata": {},
      "outputs": [],
      "source": [
        "# Define a general network class where activation function can be specified\n",
        "class TwoHiddenLayerNN(nn.Module):\n",
        "    def __init__(self, activation_function):\n",
        "        super(TwoHiddenLayerNN, self).__init__()\n",
        "        self.fc1 = nn.Linear(28 * 28, 256)\n",
        "        self.fc2 = nn.Linear(256, 128)\n",
        "        self.fc3 = nn.Linear(128, 10)\n",
        "        self.activation_function = activation_function\n",
        "        \n",
        "    def forward(self, x):\n",
        "        x = x.view(-1, 28 * 28)\n",
        "        x = self.activation_function(self.fc1(x))\n",
        "        x = self.activation_function(self.fc2(x))\n",
        "        x = self.fc3(x)\n",
        "        return x\n",
        "#you will change the activation_function in order to compare how different \\sigma perform on this dataset"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "Below, using the examples above, train and validate your model for three different activation functions. Store all the results for the activation functions and the training and validation losses (for each epoch) properly. Also compute and store the training and validation accuracies for each epoch and each activation function."
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {},
      "outputs": [],
      "source": [
        "# Activation functions to test. We compare a ReLu, a Sigmoid and a Hyperbolic tangent.\n",
        "activation_functions = {\n",
        "    'ReLU': nn.ReLU(),\n",
        "    'Sigmoid': nn.Sigmoid(),\n",
        "    'Tanh': nn.Tanh()\n",
        "}\n",
        "\n",
        "results = {}\n",
        "\n",
        "#this is a code example, you can define a function that trains your model and outputs the values of the losses.\n",
        "#you can change this code accordingly to your preferences and your favourite approach.\n",
        "for name, activation_function in activation_functions.items():\n",
        "    print(f'\\nTraining with {name} activation function:')\n",
        "    train_losses, val_losses, train_acc, val_acc = train_model(activation_function)\n",
        "    results[name] = {\n",
        "        'train_losses': train_losses,\n",
        "        'val_losses': val_losses,\n",
        "        'train_acc': train_acc,\n",
        "        'val_acc': val_acc\n",
        "    }"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "Now plot the results. In a first plot, show the training and validation losses for all three activation functions with respect to the number of epochs. In a second plot show the training and validation accuracies for all the three activation functions used . Which activation function performed better?"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {},
      "outputs": [],
      "source": [
        "epochs_range = range(1, 16)\n",
        "\n",
        "# Plot Losses\n",
        "plt.figure(figsize=(12, 5))\n",
        "\n",
        "...\n",
        "\n",
        "plt.title('Training and Validation Loss with Different Activation Functions')\n",
        "plt.xlabel('Epochs')\n",
        "plt.ylabel('Loss')\n",
        "plt.legend()\n",
        "plt.show()\n",
        "\n",
        "# Plot Accuracies\n",
        "plt.figure(figsize=(12, 5))\n",
        "\n",
        "...\n",
        "\n",
        "plt.title('Training and Validation Accuracy with Different Activation Functions')\n",
        "plt.xlabel('Epochs')\n",
        "plt.ylabel('Accuracy (%)')\n",
        "plt.legend()\n",
        "plt.show()"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "# Excercise 2: Fit a sine function with a 2-hidden layers NN"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "Objective: Use a two-hidden layer neural network to approximate a sine function. Visualize the network's predictions compared to the actual function."
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {},
      "outputs": [],
      "source": [
        "import torch\n",
        "import torch.nn as nn\n",
        "import torch.optim as optim\n",
        "import numpy as np\n",
        "import matplotlib.pyplot as plt\n",
        "\n",
        "# Generate data as a sine function\n",
        "x = np.linspace(-2 * np.pi, 2 * np.pi, 1000)\n",
        "y = np.sin(x)\n",
        "\n",
        "# Convert to tensors as it is standard to do in pytoarch\n",
        "x_tensor = torch.tensor(x, dtype=torch.float32).unsqueeze(1)\n",
        "y_tensor = torch.tensor(y, dtype=torch.float32).unsqueeze(1)"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {},
      "outputs": [],
      "source": [
        "#define your model, in this case let's call it a sine approximator.\n",
        "#Note that this is just a 2-hidden layers neural networks with activation function Tanh\n",
        "#Note also that the final output is just a scalar since we want to fit a 1-dimensional function.\n",
        "class SineApproximator(nn.Module):\n",
        "    def __init__(self):\n",
        "        super(SineApproximator, self).__init__()\n",
        "        self.fc1 = nn.Linear(1, 50)\n",
        "        self.fc2 = nn.Linear(50, 50)\n",
        "        self.fc3 = nn.Linear(50, 1)\n",
        "        self.tanh = nn.Tanh()\n",
        "        \n",
        "    def forward(self, x):\n",
        "        x = self.tanh(self.fc1(x))\n",
        "        x = self.tanh(self.fc2(x))\n",
        "        x = self.fc3(x)\n",
        "        return x\n",
        "\n",
        "net = SineApproximator()\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {},
      "outputs": [],
      "source": [
        "#As a normal fit, using an MSE lost will be enough.\n",
        "criterion = nn.MSELoss()\n",
        "optimizer = optim.Adam(net.parameters(), lr=0.01)"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "Following the examples above, train your 2-hidden layer NN onto your data points (the sine function). "
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {},
      "outputs": [],
      "source": [
        "#use this code as a helper, since you may not be familiar with the commands you can use with pytoarch. \n",
        "epochs = 1000\n",
        "\n",
        "...\n",
        "    net.train()\n",
        "    optimizer.zero_grad()\n",
        "    outputs = net(x_tensor)\n",
        "    loss = criterion(outputs, y_tensor)\n",
        "    loss.backward()\n",
        "    optimizer.step()\n",
        "    losses.append(loss.item())\n",
        "..."
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {},
      "outputs": [],
      "source": [
        "# Plot the original sine function and the network's approximation\n",
        "net.eval()\n",
        "with torch.no_grad():\n",
        "    predicted = net(x_tensor).numpy()\n",
        "\n",
        "\n",
        "# Plot the training loss over epochs\n",
        "...\n",
        "\n",
        "#Plot the actual sine function and the neural network approximation\n",
        "..."
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "JkTerCpIeaFN"
      },
      "source": [
        "# Exercise 3: Searching for Supersymmetric Collisions with Neural Nets"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 1,
      "metadata": {},
      "outputs": [
        {
          "name": "stdout",
          "output_type": "stream",
          "text": [
            "  % Total    % Received % Xferd  Average Speed   Time    Time     Time  Current\n",
            "                                 Dload  Upload   Total   Spent    Left  Speed\n",
            "100  477M    0  477M    0     0   394k      0 --:--:--  0:20:38 --:--:--  460k    0   394k      0 --:--:--  0:00:15 --:--:--  235k 0     0   381k      0 --:--:--  0:00:16 --:--:--  230k0 --:--:--  0:00:18 --:--:--  235k     0   409k      0 --:--:--  0:00:32 --:--:--  811k 13.7M    0     0   424k      0 --:--:--  0:00:33 --:--:--  921k     0 --:--:--  0:00:46 --:--:--  780k 0 --:--:--  0:00:55 --:--:--  373k30.2M    0 30.2M    0     0   515k      0 --:--:--  0:01:00 --:--:--  426k    0     0   412k      0 --:--:--  0:01:33 --:--:-- 57841 0   390k      0 --:--:--  0:01:59 --:--:--  295k     0   384k      0 --:--:--  0:02:10 --:--:--  335k 0:02:15 --:--:--  408k   0     0   361k      0 --:--:--  0:03:02 --:--:--  487k    0   372k      0 --:--:--  0:03:09 --:--:--  597k     0   377k      0 --:--:--  0:03:16 --:--:--  522k    0 --:--:--  0:03:24 --:--:--  310kk      0 --:--:--  0:03:38 --:--:--  352k0  106M    0     0   360k      0 --:--:--  0:05:02 --:--:--  378k    0   360k      0 --:--:--  0:05:13 --:--:--  439k  118M    0     0   362k      0 --:--:--  0:05:35 --:--:--  387k64k      0 --:--:--  0:06:00 --:--:--  498k0     0   366k      0 --:--:--  0:06:02 --:--:--  609kM    0     0   366k      0 --:--:--  0:06:22 --:--:--  388k  363k      0 --:--:--  0:06:25 --:--:--  170k  0   362k      0 --:--:--  0:06:27 --:--:-- 63584    0     0   352k      0 --:--:--  0:06:51 --:--:--  248k  142M    0     0   351k      0 --:--:--  0:06:56 --:--:--  252k 0   350k      0 --:--:--  0:07:04 --:--:--  291k  0  145M    0     0   349k      0 --:--:--  0:07:08 --:--:--  229k0   348k      0 --:--:--  0:07:15 --:--:--  326kM    0     0   349k      0 --:--:--  0:07:22 --:--:--  444k   0     0   349k      0 --:--:--  0:07:54 --:--:--  477k 348k      0 --:--:--  0:08:11 --:--:--  371k08:18 --:--:--  207k  352k      0 --:--:--  0:09:06 --:--:--  394k    0 --:--:--  0:09:09 --:--:--  300k50k      0 --:--:--  0:09:15 --:--:--  246k--  381k  0     0   348k      0 --:--:--  0:09:35 --:--:--  256k 0:09:44 --:--:--  537k  0   348k      0 --:--:--  0:10:08 --:--:--  359k0     0   349k      0 --:--:--  0:10:12 --:--:--  550k0     0   351k      0 --:--:--  0:10:15 --:--:--  544k0     0   352k      0 --:--:--  0:10:30 --:--:--  377k    0     0   355k      0 --:--:--  0:10:35 --:--:--  819k   0   356k      0 --:--:--  0:10:37 --:--:--  657k 0     0   357k      0 --:--:--  0:10:43 --:--:--  498k    0     0   358k      0 --:--:--  0:10:52 --:--:--  359k--:--:--  0:11:08 --:--:--  233k  0     0   357k      0 --:--:--  0:11:10 --:--:--  224k  0     0   361k      0 --:--:--  0:11:18 --:--:--  905kk      0 --:--:--  0:11:47 --:--:--  155k--:--  0:11:55 --:--:--  202k --:--:--  0:12:08 --:--:--  167k   0     0   353k      0 --:--:--  0:12:27 --:--:--  428k0   353k      0 --:--:--  0:12:41 --:--:--  335k    0 --:--:--  0:13:04 --:--:--  308k  0 --:--:--  0:13:08 --:--:--  353k56k      0 --:--:--  0:13:36 --:--:--  459k55k      0 --:--:--  0:13:54 --:--:--  309k     0 --:--:--  0:13:57 --:--:--  334k0 --:--:--  0:14:03 --:--:--  393k    0 --:--:--  0:14:23 --:--:--  478k 364k      0 --:--:--  0:15:00 --:--:--  723k  0     0   366k      0 --:--:--  0:15:13 --:--:--  389k   0     0   365k      0 --:--:--  0:15:17 --:--:--  223k28M    0     0   365k      0 --:--:--  0:15:20 --:--:--  197k   363k      0 --:--:--  0:15:32 --:--:--  169k0   361k      0 --:--:--  0:15:42 --:--:--  251k     0   361k      0 --:--:--  0:15:49 --:--:--  270k0     0   360k      0 --:--:--  0:15:51 --:--:--  281k   0     0   360k      0 --:--:--  0:15:56 --:--:--  359k   360k      0 --:--:--  0:15:57 --:--:--  377k 0     0   360k      0 --:--:--  0:15:59 --:--:--  382k     0   359k      0 --:--:--  0:16:13 --:--:--  178k    0     0   361k      0 --:--:--  0:16:36 --:--:--  289k     0 --:--:--  0:16:58 --:--:--  127k0     0   357k      0 --:--:--  0:17:05 --:--:--  349k  0:17:10 --:--:--  578k   0     0   358k      0 --:--:--  0:17:11 --:--:--  600k  0     0   360k      0 --:--:--  0:17:19 --:--:--  636k  0 --:--:--  0:17:36 --:--:--  386k63k      0 --:--:--  0:17:44 --:--:--  550k   0     0   363k      0 --:--:--  0:17:48 --:--:--  379kM    0     0   366k      0 --:--:--  0:18:08 --:--:--  513k    0   367k      0 --:--:--  0:18:09 --:--:--  534k 0     0   368k      0 --:--:--  0:18:17 --:--:--  543k   0 --:--:--  0:18:33 --:--:--  576k  0     0   374k      0 --:--:--  0:18:45 --:--:--  661k  0     0   378k      0 --:--:--  0:19:03 --:--:--  785k 0     0   379k      0 --:--:--  0:19:06 --:--:--  686k 0     0   381k      0 --:--:--  0:19:18 --:--:--  639k    0   382k      0 --:--:--  0:19:22 --:--:--  669k   0 --:--:--  0:19:53 --:--:--  447k:--:--  303k 0     0   391k      0 --:--:--  0:20:05 --:--:--  544k0:20:37 --:--:--  426k\n"
          ]
        }
      ],
      "source": [
        "!curl -O https://archive.ics.uci.edu/ml/machine-learning-databases/00279/SUSY.csv.gz\n",
        "\n",
        "#If the former doesn't work, try this one below:\n",
        "# !wget https://archive.ics.uci.edu/ml/machine-learning-databases/00279/SUSY.csv.gz\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 6,
      "metadata": {},
      "outputs": [
        {
          "name": "stdout",
          "output_type": "stream",
          "text": [
            "gunzip: SUSY.csv.gz: unexpected end of file\n",
            "gunzip: SUSY.csv.gz: uncompress failed\n"
          ]
        }
      ],
      "source": [
        "!gunzip SUSY.csv.gz # also if you are using noto.epfl.ch with !gunzip \"./SUSY.csv.gz\"\n",
        "\n",
        "#!gunzip \"/content/SUSY.csv.gz\" #use this one if you are using google colab colab"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "R71paLH2e0JP"
      },
      "source": [
        "The SUSY dataset consists of 5 million simulated Monte Carlo samples\n",
        "of supersymmetric and non-supersymmetric collisions. The goal is to distinguish between a process\n",
        "where new supersymmetric particles are produced and a background process. The first 8 features are\n",
        "measurements of the final particle states, while the last 10 features are functions of the first 8 derived\n",
        "by physicists to help to discriminate the events."
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "STLQbWRcfK3j"
      },
      "outputs": [],
      "source": [
        "import numpy as np\n",
        "import torch\n",
        "from torch import nn\n",
        "from torch.utils.data import DataLoader\n",
        "from torchvision import datasets"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "WEyGgOF4fzXO"
      },
      "source": [
        "We provide the class `SUSY_Dataset` to load the train and test datasets."
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 19,
      "metadata": {
        "id": "OR1ddjzOfNVr"
      },
      "outputs": [],
      "source": [
        "class SUSY_Dataset(torch.utils.data.Dataset):\n",
        "    \"\"\"SUSY pytorch dataset.\"\"\"\n",
        "\n",
        "    def __init__(self, data_file, root_dir, dataset_size, train=True, transform=None, high_level_feats=None):\n",
        "        \"\"\"\n",
        "        Args:\n",
        "            data_file (string): Path to the csv file with annotations.\n",
        "            root_dir (string): Directory with all the images.\n",
        "            dataset_size (int): Size of the full dataset which is splitted in 80% for train and 20% for test.\n",
        "            train (bool, optional): If set to `True` load training data.\n",
        "            transform (callable, optional): Optional transform to be applied on a sample.\n",
        "            high_level_festures (bool, optional): If set to `True`, working with high-level features only.\n",
        "                                        If set to `False`, working with low-level features only.\n",
        "                                        Default is `None`: working with all features\n",
        "        \"\"\"\n",
        "\n",
        "        import pandas as pd\n",
        "\n",
        "        features=['SUSY','lepton 1 pT', 'lepton 1 eta', 'lepton 1 phi', 'lepton 2 pT', 'lepton 2 eta', 'lepton 2 phi',\n",
        "                'missing energy magnitude', 'missing energy phi', 'MET_rel', 'axial MET', 'M_R', 'M_TR_2', 'R', 'MT2',\n",
        "                'S_R', 'M_Delta_R', 'dPhi_r_b', 'cos(theta_r1)']\n",
        "\n",
        "        low_features=['lepton 1 pT', 'lepton 1 eta', 'lepton 1 phi', 'lepton 2 pT', 'lepton 2 eta', 'lepton 2 phi',\n",
        "                'missing energy magnitude', 'missing energy phi']\n",
        "\n",
        "        high_features=['MET_rel', 'axial MET', 'M_R', 'M_TR_2', 'R', 'MT2','S_R', 'M_Delta_R', 'dPhi_r_b', 'cos(theta_r1)']\n",
        "\n",
        "        # Number of datapoints to work with\n",
        "        df = pd.read_csv(root_dir+data_file, header=None,nrows=dataset_size,engine='python')\n",
        "        df.columns=features\n",
        "        Y = df['SUSY']\n",
        "        X = df[[col for col in df.columns if col!=\"SUSY\"]]\n",
        "\n",
        "        # Set training and test data size\n",
        "        train_size=int(0.8*dataset_size)\n",
        "        self.train=train\n",
        "\n",
        "        if self.train:\n",
        "            X=X[:train_size]\n",
        "            Y=Y[:train_size]\n",
        "            print(\"Training on {} examples\".format(train_size))\n",
        "        else:\n",
        "            X=X[train_size:]\n",
        "            Y=Y[train_size:]\n",
        "            print(\"Testing on {} examples\".format(dataset_size-train_size))\n",
        "\n",
        "        self.root_dir = root_dir\n",
        "        self.transform = transform\n",
        "\n",
        "        # make datasets using only the 8 low-level features and 10 high-level features\n",
        "        if high_level_feats is None:\n",
        "            self.data=(X.values.astype(np.float32),Y.values.astype(int))\n",
        "            print(\"Using both high and low level features\")\n",
        "        elif high_level_feats is True:\n",
        "            self.data=(X[high_features].values.astype(np.float32),Y.values.astype(int))\n",
        "            print(\"Using both high-level features only.\")\n",
        "        elif high_level_feats is False:\n",
        "            self.data=(X[low_features].values.astype(np.float32),Y.values.astype(int))\n",
        "            print(\"Using both low-level features only.\")\n",
        "\n",
        "    # override __len__ and __getitem__ of the Dataset() class\n",
        "\n",
        "    def __len__(self):\n",
        "        return len(self.data[1])\n",
        "\n",
        "    def __getitem__(self, idx):\n",
        "\n",
        "        sample=(self.data[0][idx,...],self.data[1][idx])\n",
        "\n",
        "        if self.transform:\n",
        "            sample=self.transform(sample)\n",
        "\n",
        "        return sample"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "tsmDk969fiNt"
      },
      "outputs": [],
      "source": [
        "training_data = SUSY_Dataset(\n",
        "    data_file='SUSY.csv',\n",
        "    root_dir='./',\n",
        "    dataset_size=2000,\n",
        "    train=True,\n",
        "    )\n",
        "\n",
        "test_data = SUSY_Dataset(\n",
        "    data_file='SUSY.csv',\n",
        "    root_dir='./',\n",
        "    dataset_size=2000,\n",
        "    train=False,\n",
        "    )"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "S7dPzGZbft31"
      },
      "source": [
        "1. To train our neural network with SGD, we want to pass the samples in batches. Build the train and\n",
        "test data loaders, setting the batch size to 100 and activating reshuffling at each epoch for the train\n",
        "data by setting `shuffle=True`."
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "_L4KiIxLgMtp"
      },
      "source": [
        "2. Define a fully connected ReLU neural network taking an 18-dimensional input, with two hidden layers with 200 neurons, one hidden layer with 100 neurons, and a final linear layer with two outputs."
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "pMH_7mPTgZPa"
      },
      "source": [
        "3. Using the cross-entropy loss and SGD with learning rate 1e-2, train the model for 100 epochs (if you are using noto.epfl.ch, you can train for 30 epochs only). For each epoch, print the training loss and the test accuracy."
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {},
      "outputs": [],
      "source": []
    }
  ],
  "metadata": {
    "colab": {
      "provenance": []
    },
    "kernelspec": {
      "display_name": "base",
      "language": "python",
      "name": "python3"
    },
    "language_info": {
      "codemirror_mode": {
        "name": "ipython",
        "version": 3
      },
      "file_extension": ".py",
      "mimetype": "text/x-python",
      "name": "python",
      "nbconvert_exporter": "python",
      "pygments_lexer": "ipython3",
      "version": "3.12.7"
    }
  },
  "nbformat": 4,
  "nbformat_minor": 0
}
