├── Cnn Model.ipynb ├── Data Visualisation.ipynb ├── Handwritten Digit Recognition.pptx ├── Lenet5 Model.ipynb ├── Loading and preprocessing.ipynb ├── Mlp model.ipynb ├── Project_Report.docx └── README.md /Cnn Model.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "nbformat": 4, 3 | "nbformat_minor": 0, 4 | "metadata": { 5 | "colab": { 6 | "provenance": [] 7 | }, 8 | "kernelspec": { 9 | "name": "python3", 10 | "display_name": "Python 3" 11 | }, 12 | "language_info": { 13 | "name": "python" 14 | } 15 | }, 16 | "cells": [ 17 | { 18 | "cell_type": "code", 19 | "source": [ 20 | "#import necessary libraries\n", 21 | "import torch\n", 22 | "import torchvision\n", 23 | "import torchvision.transforms as transforms\n", 24 | "import matplotlib.pyplot as plt" 25 | ], 26 | "metadata": { 27 | "id": "R2DUG_zuqyfU" 28 | }, 29 | "execution_count": 1, 30 | "outputs": [] 31 | }, 32 | { 33 | "cell_type": "code", 34 | "source": [ 35 | "# Step 1: Download the MNIST dataset\n", 36 | "torchvision.datasets.MNIST(root='./data', train=True, download=True)\n", 37 | "torchvision.datasets.MNIST(root='./data', train=False, download=True)\n", 38 | "\n", 39 | "# Step 2: Load the raw MNIST dataset\n", 40 | "trainset = torchvision.datasets.MNIST(root='./data', train=True, download=True, transform=transforms.ToTensor())\n", 41 | "trainloader = torch.utils.data.DataLoader(trainset, batch_size=64, shuffle=True)" 42 | ], 43 | "metadata": { 44 | "colab": { 45 | "base_uri": "https://localhost:8080/" 46 | }, 47 | "id": "uTo0vmJNqyn2", 48 | "outputId": "e424b9f7-0de7-4387-d5b3-fa66cff60d9f" 49 | }, 50 | "execution_count": 2, 51 | "outputs": [ 52 | { 53 | "output_type": "stream", 54 | "name": "stdout", 55 | "text": [ 56 | "Downloading http://yann.lecun.com/exdb/mnist/train-images-idx3-ubyte.gz\n", 57 | "Failed to download (trying next):\n", 58 | "HTTP Error 403: Forbidden\n", 59 | "\n", 60 | "Downloading https://ossci-datasets.s3.amazonaws.com/mnist/train-images-idx3-ubyte.gz\n", 61 | "Downloading https://ossci-datasets.s3.amazonaws.com/mnist/train-images-idx3-ubyte.gz to ./data/MNIST/raw/train-images-idx3-ubyte.gz\n" 62 | ] 63 | }, 64 | { 65 | "output_type": "stream", 66 | "name": "stderr", 67 | "text": [ 68 | "100%|██████████| 9.91M/9.91M [00:00<00:00, 16.2MB/s]\n" 69 | ] 70 | }, 71 | { 72 | "output_type": "stream", 73 | "name": "stdout", 74 | "text": [ 75 | "Extracting ./data/MNIST/raw/train-images-idx3-ubyte.gz to ./data/MNIST/raw\n", 76 | "\n", 77 | "Downloading http://yann.lecun.com/exdb/mnist/train-labels-idx1-ubyte.gz\n", 78 | "Failed to download (trying next):\n", 79 | "HTTP Error 403: Forbidden\n", 80 | "\n", 81 | "Downloading https://ossci-datasets.s3.amazonaws.com/mnist/train-labels-idx1-ubyte.gz\n", 82 | "Downloading https://ossci-datasets.s3.amazonaws.com/mnist/train-labels-idx1-ubyte.gz to ./data/MNIST/raw/train-labels-idx1-ubyte.gz\n" 83 | ] 84 | }, 85 | { 86 | "output_type": "stream", 87 | "name": "stderr", 88 | "text": [ 89 | "100%|██████████| 28.9k/28.9k [00:00<00:00, 489kB/s]\n" 90 | ] 91 | }, 92 | { 93 | "output_type": "stream", 94 | "name": "stdout", 95 | "text": [ 96 | "Extracting ./data/MNIST/raw/train-labels-idx1-ubyte.gz to ./data/MNIST/raw\n", 97 | "\n", 98 | "Downloading http://yann.lecun.com/exdb/mnist/t10k-images-idx3-ubyte.gz\n", 99 | "Failed to download (trying next):\n", 100 | "HTTP Error 403: Forbidden\n", 101 | "\n", 102 | "Downloading https://ossci-datasets.s3.amazonaws.com/mnist/t10k-images-idx3-ubyte.gz\n", 103 | "Downloading https://ossci-datasets.s3.amazonaws.com/mnist/t10k-images-idx3-ubyte.gz to ./data/MNIST/raw/t10k-images-idx3-ubyte.gz\n" 104 | ] 105 | }, 106 | { 107 | "output_type": "stream", 108 | "name": "stderr", 109 | "text": [ 110 | "100%|██████████| 1.65M/1.65M [00:00<00:00, 4.48MB/s]\n" 111 | ] 112 | }, 113 | { 114 | "output_type": "stream", 115 | "name": "stdout", 116 | "text": [ 117 | "Extracting ./data/MNIST/raw/t10k-images-idx3-ubyte.gz to ./data/MNIST/raw\n", 118 | "\n", 119 | "Downloading http://yann.lecun.com/exdb/mnist/t10k-labels-idx1-ubyte.gz\n", 120 | "Failed to download (trying next):\n", 121 | "HTTP Error 403: Forbidden\n", 122 | "\n", 123 | "Downloading https://ossci-datasets.s3.amazonaws.com/mnist/t10k-labels-idx1-ubyte.gz\n", 124 | "Downloading https://ossci-datasets.s3.amazonaws.com/mnist/t10k-labels-idx1-ubyte.gz to ./data/MNIST/raw/t10k-labels-idx1-ubyte.gz\n" 125 | ] 126 | }, 127 | { 128 | "output_type": "stream", 129 | "name": "stderr", 130 | "text": [ 131 | "100%|██████████| 4.54k/4.54k [00:00<00:00, 2.51MB/s]\n" 132 | ] 133 | }, 134 | { 135 | "output_type": "stream", 136 | "name": "stdout", 137 | "text": [ 138 | "Extracting ./data/MNIST/raw/t10k-labels-idx1-ubyte.gz to ./data/MNIST/raw\n", 139 | "\n" 140 | ] 141 | } 142 | ] 143 | }, 144 | { 145 | "cell_type": "code", 146 | "source": [ 147 | "# Visualize the datasets\n", 148 | "def show_images(images, labels, label_header=\"True\"):\n", 149 | " figure = plt.figure(figsize=(10, 10))\n", 150 | " rows, cols = 1, 4\n", 151 | " for i in range(1, rows*cols+1):\n", 152 | " figure.add_subplot(rows, cols, i)\n", 153 | " plt.axis(False)\n", 154 | " plt.title(f\"{label_header}: {labels[i-1].item()}\")\n", 155 | " plt.imshow(images[i-1].permute(1, 2, 0), cmap='gray')\n", 156 | "\n", 157 | " plt.show()\n", 158 | "\n", 159 | "# Get a batch of images and show\n", 160 | "images, labels = next(iter(trainloader))\n", 161 | "show_images(images, labels, label_header=\"Raw\")" 162 | ], 163 | "metadata": { 164 | "colab": { 165 | "base_uri": "https://localhost:8080/", 166 | "height": 227 167 | }, 168 | "id": "2xjxfj1Uqyz0", 169 | "outputId": "a34f7083-fa50-4b7e-d02c-96dc19824bb0" 170 | }, 171 | "execution_count": 4, 172 | "outputs": [ 173 | { 174 | "output_type": "display_data", 175 | "data": { 176 | "text/plain": [ 177 | "
" 178 | ], 179 | "image/png": "iVBORw0KGgoAAAANSUhEUgAAAxsAAADSCAYAAAAi0d0oAAAAOXRFWHRTb2Z0d2FyZQBNYXRwbG90bGliIHZlcnNpb24zLjguMCwgaHR0cHM6Ly9tYXRwbG90bGliLm9yZy81sbWrAAAACXBIWXMAAA9hAAAPYQGoP6dpAAAdn0lEQVR4nO3dfZjNdf7H8fdhmEGFhJiQBltMSrkpZlzW6NKmS8UoRq3brFRaWTY3P91sbqtJN8RSQ7Gj2ESlkMWO2e7c5ZqkQoy7rDBuZtzO+fz+6HK2yfuT8x3nM3POzPNxXf7wOud8v+8zc94z5z1f8+YzxhgBAAAAgBArU9wFAAAAACiZGDYAAAAAOMGwAQAAAMAJhg0AAAAATjBsAAAAAHCCYQMAAACAEwwbAAAAAJxg2AAAAADgBMMGAAAAACcYNgAAAAA4wbDxC7NmzRKfzxf4ExUVJbGxsdK7d2/Zs2dPcZf3m7Zt2yYpKSlSo0YNqVChgjRs2FBGjRpV3GWhhIrUXvH7/TJp0iSpX7++xMTESNOmTSU9Pb24y0IJFYl98tRTTxWo+dd/MjMzi7tElDCR2CciIvv27ZMBAwZI/fr1pUKFChIXFyePP/64HDx4sLhLCztRxV1AOHrmmWekfv36cvLkSfnss89k1qxZsmbNGsnKypKYmJjiLu88GzdulHbt2klsbKwMHTpUqlWrJtnZ2bJr167iLg0lXKT1yqhRo2TChAny4IMPSosWLWTRokWSkpIiPp9PunfvXtzloYSKpD7p0qWLNGjQ4Lx85MiRcvz4cWnRokUxVIXSIJL65Pjx43LrrbdKbm6uDBo0SOrUqSNfffWVvPrqq7Jy5UpZt26dlCnDz/MDDALS0tKMiJgvv/yyQP7Xv/7ViIh5++23i6kyu/z8fBMfH29atWpl8vLyirsclBKR2Cu7d+825cqVMw8//HAg8/v9JjEx0Vx11VXm7NmzxVgdSqJI7BNNdna28fl85sEHHyzuUlACRWKfzJ0714iI+eCDDwrkY8aMMSJi1q9fX0yVhSfGriAkJiaKyM//VOmc06dPy5gxY+Tmm2+WypUrS6VKlSQxMVFWrlxZ4LE33XSTdOnSpUB2/fXXi8/nk02bNgWyt99+W3w+n3zzzTeBc/3yfDbLli2TrKwsefLJJ6VChQqSl5cn+fn5hX6uwMUI515ZtGiRnDlzRgYNGhTIfD6fPPTQQ7J792759NNPvT9hoBDCuU806enpYoyRnj17FurxQGGEc58cPXpURERq1qxZIK9Vq5aIiFSoUCHYp1kqMGwEYceOHSIiUrVq1UB29OhRmTlzprRr104mTpwoTz31lBw4cEA6duwoGzduDNwvMTFR1qxZE/j7oUOH5Ouvv5YyZcpIRkZGIM/IyJDq1avLddddJyIiSUlJkpSUdMHaPvnkExERiY6OlubNm0ulSpWkYsWK0r17dzl06NDFPG3As3DulQ0bNkilSpUCjzunZcuWgduBohDOfaKZO3eu1KlTR9q2bVuoxwOFEc590rZtWylTpow89thj8tlnn8nu3btlyZIlMnbsWLn77rvl2muvvchnX8IU96WVcHLuUt4nn3xiDhw4YHbt2mUWLFhgqlevbqKjo82uXbsC9z179qw5depUgccfPnzY1KxZ0/Tt2zeQzZ8/34iI2bx5szHGmMWLF5vo6GjTuXNnc9999wXu17RpU3PPPfcE/l6vXj1Tr169C9bcuXNnIyKmWrVqpmfPnmbBggXm//7v/0xUVJRp3bq18fv9hf1wAFaR2CudOnUy11xzzXl5bm6uERHzxBNPBP38gWBEYp/8WlZWlhERM3z4cM+PBYIRqX0yc+ZMU6VKFSMigT+9evUyZ86cKcyHoUTjF8QVHTp0KPD3q6++WubMmSNXXXVVICtbtqyULVtWRH7ecJOTkyN+v1+aN28u69evD9zv3GXAf//733LddddJRkaGtGjRQm677TYZP368iIjk5ORIVlaW9O7dO/C4cxP9hRw/flxERFq0aCFz5swREZGuXbtKxYoVZcSIEbJixYrzng8QKpHUKydOnJDo6Ojz8nO/eHjixImgjgN4FUl98mtz584VEeGfUMG5SOuT2NhYadmypdxxxx1Sr149ycjIkJdfflmuuOIKef75570+/RKNf0almDJliixfvlwWLFggd9xxh/z000/qm5TZs2dL06ZNJSYmRqpVqybVq1eXDz/8UI4cORK4T82aNaVhw4aBy3YZGRmSmJgobdu2lb1798r27dslMzNT/H5/oDm8OPfvAnv06FEgT0lJERGR//znP56PCQQr0nrl1KlT5+UnT54M3A64EEl98kvGGPnHP/4h8fHx0rRp04s6FnAhkdQnmZmZcuedd8rYsWPlsccek7vvvlte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\n" 180 | }, 181 | "metadata": {} 182 | } 183 | ] 184 | }, 185 | { 186 | "cell_type": "code", 187 | "source": [ 188 | "# Step 3: Preprocessing Step: Normalization and Data Augmentation\n", 189 | "transform_train = transforms.Compose([\n", 190 | " transforms.RandomRotation(10), # Randomly rotate the image by 10 degrees\n", 191 | " transforms.RandomAffine(0, translate=(0.1, 0.1)), # Random translation\n", 192 | " transforms.ToTensor(),\n", 193 | " transforms.Normalize((0.5,), (0.5,)) # Normalize to range [-1, 1]\n", 194 | "])\n", 195 | "\n", 196 | "transform_test = transforms.Compose([\n", 197 | " transforms.ToTensor(),\n", 198 | " transforms.Normalize((0.5,), (0.5,)) # Normalize the same way for test set\n", 199 | "])" 200 | ], 201 | "metadata": { 202 | "id": "PmgT8Dweqy-w" 203 | }, 204 | "execution_count": 5, 205 | "outputs": [] 206 | }, 207 | { 208 | "cell_type": "code", 209 | "source": [ 210 | "# Step 4: Load the MNIST dataset with preprocessing applied\n", 211 | "trainset = torchvision.datasets.MNIST(root='./data', train=True, transform=transform_train)\n", 212 | "trainloader = torch.utils.data.DataLoader(trainset, batch_size=64, shuffle=True)\n", 213 | "\n", 214 | "testset = torchvision.datasets.MNIST(root='./data', train=False, transform=transform_test)\n", 215 | "testloader = torch.utils.data.DataLoader(testset, batch_size=64, shuffle=False)\n", 216 | "\n", 217 | "# Visualize Some Preprocessed Images\n", 218 | "preprocessed_images, preprocessed_labels = next(iter(trainloader))\n", 219 | "show_images(preprocessed_images, preprocessed_labels, label_header=\"Preprocessed\")" 220 | ], 221 | "metadata": { 222 | "colab": { 223 | "base_uri": "https://localhost:8080/", 224 | "height": 227 225 | }, 226 | "id": "7q9n90u1rABY", 227 | "outputId": "090ed61c-95cd-4b91-f0a0-10282c9c80cf" 228 | }, 229 | "execution_count": 6, 230 | "outputs": [ 231 | { 232 | "output_type": "display_data", 233 | "data": { 234 | "text/plain": [ 235 | "
" 236 | ], 237 | "image/png": "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\n" 238 | }, 239 | "metadata": {} 240 | } 241 | ] 242 | }, 243 | { 244 | "cell_type": "code", 245 | "source": [ 246 | "#import necessary libraries\n", 247 | "import torch\n", 248 | "import torch.nn as nn\n", 249 | "import torch.optim as optim\n", 250 | "import torch.nn.functional as F\n", 251 | "from sklearn.metrics import accuracy_score, precision_score, recall_score, f1_score" 252 | ], 253 | "metadata": { 254 | "id": "VMoOj1tvrAPj" 255 | }, 256 | "execution_count": 7, 257 | "outputs": [] 258 | }, 259 | { 260 | "cell_type": "code", 261 | "source": [ 262 | "# Define the CNN model\n", 263 | "class CNN(nn.Module):\n", 264 | " def __init__(self):\n", 265 | " super(CNN, self).__init__()\n", 266 | " # Convolutional layers\n", 267 | " self.conv1 = nn.Conv2d(1, 32, kernel_size=3, padding=1) # 1 input channel (grayscale), 32 filters\n", 268 | " self.conv2 = nn.Conv2d(32, 64, kernel_size=3, padding=1) # 32 input channels, 64 filters\n", 269 | " self.pool = nn.MaxPool2d(2, 2) # Max pooling layer with 2x2 filter\n", 270 | " self.fc1 = nn.Linear(64 * 7 * 7, 128) # Fully connected layer\n", 271 | " self.fc2 = nn.Linear(128, 10) # Output layer for 10 classes\n", 272 | "\n", 273 | " def forward(self, x):\n", 274 | " x = self.pool(F.relu(self.conv1(x))) # Conv1 -> ReLU -> Pooling\n", 275 | " x = self.pool(F.relu(self.conv2(x))) # Conv2 -> ReLU -> Pooling\n", 276 | " x = x.view(-1, 64 * 7 * 7) # Flatten the tensor\n", 277 | " x = F.relu(self.fc1(x)) # FC1 -> ReLU\n", 278 | " x = self.fc2(x) # Output layer\n", 279 | " return x\n", 280 | "\n", 281 | "# Initialize model, criterion, and optimizer\n", 282 | "cnn_model = CNN()\n", 283 | "criterion = nn.CrossEntropyLoss() # Cross entropy loss\n", 284 | "optimizer = optim.Adam(cnn_model.parameters(), lr=0.001) # Adam optimizer" 285 | ], 286 | "metadata": { 287 | "id": "tg-ApIwJrAbn" 288 | }, 289 | "execution_count": 8, 290 | "outputs": [] 291 | }, 292 | { 293 | "cell_type": "code", 294 | "source": [ 295 | "# Training function\n", 296 | "def train_cnn(model, trainloader, criterion, optimizer, epochs=10):\n", 297 | " model.train() # Set the model to training mode\n", 298 | " for epoch in range(epochs):\n", 299 | " running_loss = 0.0\n", 300 | " correct = 0\n", 301 | " total = 0\n", 302 | " for images, labels in trainloader:\n", 303 | " optimizer.zero_grad() # Zero the parameter gradients\n", 304 | " outputs = model(images) # Forward pass\n", 305 | " loss = criterion(outputs, labels)\n", 306 | " loss.backward() # Backward pass and optimization\n", 307 | " optimizer.step()\n", 308 | " running_loss += loss.item() # Statistics\n", 309 | " _, predicted = torch.max(outputs.data, 1)\n", 310 | " total += labels.size(0)\n", 311 | " correct += (predicted == labels).sum().item()\n", 312 | "\n", 313 | " # Print statistics\n", 314 | " epoch_loss = running_loss / len(trainloader)\n", 315 | " accuracy = 100 * correct / total\n", 316 | " print(f\"Epoch [{epoch+1}/{epochs}], Loss: {epoch_loss:.4f}, Training Accuracy: {accuracy:.2f}%\")" 317 | ], 318 | "metadata": { 319 | "id": "I0C8cOJGrAmh" 320 | }, 321 | "execution_count": 9, 322 | "outputs": [] 323 | }, 324 | { 325 | "cell_type": "code", 326 | "source": [ 327 | "# Evaluation function\n", 328 | "def evaluate_cnn(model, testloader):\n", 329 | " model.eval() # Set the model to evaluation mode\n", 330 | " correct = 0\n", 331 | " total = 0\n", 332 | " all_labels = []\n", 333 | " all_preds = []\n", 334 | " with torch.no_grad(): # Disable gradient calculation for inference\n", 335 | " for images, labels in testloader:\n", 336 | " outputs = model(images)\n", 337 | " _, predicted = torch.max(outputs.data, 1)\n", 338 | " total += labels.size(0)\n", 339 | " correct += (predicted == labels).sum().item()\n", 340 | " all_labels.extend(labels.cpu().numpy()) # Convert lists to numpy arrays\n", 341 | " all_preds.extend(predicted.cpu().numpy())\n", 342 | "\n", 343 | " # Compute evaluation metrics\n", 344 | " accuracy = accuracy_score(all_labels, all_preds) * 100\n", 345 | " precision = precision_score(all_labels, all_preds, average=\"weighted\") * 100\n", 346 | " recall = recall_score(all_labels, all_preds, average=\"weighted\") * 100\n", 347 | " f1 = f1_score(all_labels, all_preds, average=\"weighted\") * 100\n", 348 | "\n", 349 | " print(f\"Test Accuracy: {accuracy:.2f}%\")\n", 350 | " print(f\"Precision: {precision:.2f}%\")\n", 351 | " print(f\"Recall: {recall:.2f}%\")\n", 352 | " print(f\"F1 Score: {f1:.2f}%\")" 353 | ], 354 | "metadata": { 355 | "id": "auMr89rbrkMa" 356 | }, 357 | "execution_count": 10, 358 | "outputs": [] 359 | }, 360 | { 361 | "cell_type": "code", 362 | "source": [ 363 | "# Train the CNN model\n", 364 | "train_cnn(cnn_model, trainloader, criterion, optimizer, epochs=10)\n", 365 | "\n", 366 | "# Evaluate the CNN model on the test set\n", 367 | "evaluate_cnn(cnn_model, testloader)" 368 | ], 369 | "metadata": { 370 | "colab": { 371 | "base_uri": "https://localhost:8080/" 372 | }, 373 | "id": "3_D5d5--rkmY", 374 | "outputId": "841faace-6bea-42c0-a52c-5faa47855304" 375 | }, 376 | "execution_count": 11, 377 | "outputs": [ 378 | { 379 | "output_type": "stream", 380 | "name": "stdout", 381 | "text": [ 382 | "Epoch [1/10], Loss: 0.2955, Training Accuracy: 90.74%\n", 383 | "Epoch [2/10], Loss: 0.0947, Training Accuracy: 97.08%\n", 384 | "Epoch [3/10], Loss: 0.0709, Training Accuracy: 97.84%\n", 385 | "Epoch [4/10], Loss: 0.0599, Training Accuracy: 98.17%\n", 386 | "Epoch [5/10], Loss: 0.0534, Training Accuracy: 98.37%\n", 387 | "Epoch [6/10], Loss: 0.0469, Training Accuracy: 98.56%\n", 388 | "Epoch [7/10], Loss: 0.0428, Training Accuracy: 98.66%\n", 389 | "Epoch [8/10], Loss: 0.0402, Training Accuracy: 98.73%\n", 390 | "Epoch [9/10], Loss: 0.0371, Training Accuracy: 98.81%\n", 391 | "Epoch [10/10], Loss: 0.0356, Training Accuracy: 98.88%\n", 392 | "Test Accuracy: 99.22%\n", 393 | "Precision: 99.22%\n", 394 | "Recall: 99.22%\n", 395 | "F1 Score: 99.22%\n" 396 | ] 397 | } 398 | ] 399 | } 400 | ] 401 | } -------------------------------------------------------------------------------- /Data Visualisation.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "nbformat": 4, 3 | "nbformat_minor": 0, 4 | "metadata": { 5 | "colab": { 6 | "provenance": [] 7 | }, 8 | "kernelspec": { 9 | "name": "python3", 10 | "display_name": "Python 3" 11 | }, 12 | "language_info": { 13 | "name": "python" 14 | } 15 | }, 16 | "cells": [ 17 | { 18 | "cell_type": "code", 19 | "source": [ 20 | "#import necessary libraries\n", 21 | "import torch\n", 22 | "import torchvision\n", 23 | "from torch import nn\n", 24 | "import torch.optim as optim\n", 25 | "import torchvision.transforms as transforms\n", 26 | "\n", 27 | "import matplotlib.pyplot as plt\n", 28 | "from tqdm.notebook import tqdm" 29 | ], 30 | "metadata": { 31 | "id": "_jO-FK2h_9bB" 32 | }, 33 | "execution_count": null, 34 | "outputs": [] 35 | }, 36 | { 37 | "cell_type": "code", 38 | "source": [ 39 | "# Step 1: Download the MNIST dataset\n", 40 | "torchvision.datasets.MNIST(root='./data', train=True, download=True)\n", 41 | "torchvision.datasets.MNIST(root='./data', train=False, download=True)\n", 42 | "\n", 43 | "# Load the raw MNIST dataset\n", 44 | "trainset = torchvision.datasets.MNIST(root='./data', train=True, download=True, transform=transforms.ToTensor())\n", 45 | "trainloader = torch.utils.data.DataLoader(trainset, batch_size=64, shuffle=True)" 46 | ], 47 | "metadata": { 48 | "id": "DUhp37Xx_9lW", 49 | "colab": { 50 | "base_uri": "https://localhost:8080/" 51 | }, 52 | "outputId": "d9df3e6f-8057-4145-e83b-06e4d52071f8" 53 | }, 54 | "execution_count": null, 55 | "outputs": [ 56 | { 57 | "output_type": "stream", 58 | "name": "stdout", 59 | "text": [ 60 | "Downloading http://yann.lecun.com/exdb/mnist/train-images-idx3-ubyte.gz\n", 61 | "Failed to download (trying next):\n", 62 | "\n", 63 | "\n", 64 | "Downloading https://ossci-datasets.s3.amazonaws.com/mnist/train-images-idx3-ubyte.gz\n", 65 | "Downloading https://ossci-datasets.s3.amazonaws.com/mnist/train-images-idx3-ubyte.gz to ./data/MNIST/raw/train-images-idx3-ubyte.gz\n" 66 | ] 67 | }, 68 | { 69 | "output_type": "stream", 70 | "name": "stderr", 71 | "text": [ 72 | "100%|██████████| 9912422/9912422 [00:00<00:00, 12862836.78it/s]\n" 73 | ] 74 | }, 75 | { 76 | "output_type": "stream", 77 | "name": "stdout", 78 | "text": [ 79 | "Extracting ./data/MNIST/raw/train-images-idx3-ubyte.gz to ./data/MNIST/raw\n", 80 | "\n", 81 | "Downloading http://yann.lecun.com/exdb/mnist/train-labels-idx1-ubyte.gz\n", 82 | "Failed to download (trying next):\n", 83 | "\n", 84 | "\n", 85 | "Downloading https://ossci-datasets.s3.amazonaws.com/mnist/train-labels-idx1-ubyte.gz\n", 86 | "Downloading https://ossci-datasets.s3.amazonaws.com/mnist/train-labels-idx1-ubyte.gz to ./data/MNIST/raw/train-labels-idx1-ubyte.gz\n" 87 | ] 88 | }, 89 | { 90 | "output_type": "stream", 91 | "name": "stderr", 92 | "text": [ 93 | "100%|██████████| 28881/28881 [00:00<00:00, 347254.87it/s]\n" 94 | ] 95 | }, 96 | { 97 | "output_type": "stream", 98 | "name": "stdout", 99 | "text": [ 100 | "Extracting ./data/MNIST/raw/train-labels-idx1-ubyte.gz to ./data/MNIST/raw\n", 101 | "\n", 102 | "Downloading http://yann.lecun.com/exdb/mnist/t10k-images-idx3-ubyte.gz\n", 103 | "Failed to download (trying next):\n", 104 | "\n", 105 | "\n", 106 | "Downloading https://ossci-datasets.s3.amazonaws.com/mnist/t10k-images-idx3-ubyte.gz\n", 107 | "Downloading https://ossci-datasets.s3.amazonaws.com/mnist/t10k-images-idx3-ubyte.gz to ./data/MNIST/raw/t10k-images-idx3-ubyte.gz\n" 108 | ] 109 | }, 110 | { 111 | "output_type": "stream", 112 | "name": "stderr", 113 | "text": [ 114 | "100%|██████████| 1648877/1648877 [00:00<00:00, 3206464.31it/s]\n" 115 | ] 116 | }, 117 | { 118 | "output_type": "stream", 119 | "name": "stdout", 120 | "text": [ 121 | "Extracting ./data/MNIST/raw/t10k-images-idx3-ubyte.gz to ./data/MNIST/raw\n", 122 | "\n", 123 | "Downloading http://yann.lecun.com/exdb/mnist/t10k-labels-idx1-ubyte.gz\n", 124 | "Failed to download (trying next):\n", 125 | "\n", 126 | "\n", 127 | "Downloading https://ossci-datasets.s3.amazonaws.com/mnist/t10k-labels-idx1-ubyte.gz\n", 128 | "Downloading https://ossci-datasets.s3.amazonaws.com/mnist/t10k-labels-idx1-ubyte.gz to ./data/MNIST/raw/t10k-labels-idx1-ubyte.gz\n" 129 | ] 130 | }, 131 | { 132 | "output_type": "stream", 133 | "name": "stderr", 134 | "text": [ 135 | "100%|██████████| 4542/4542 [00:00<00:00, 3414073.26it/s]\n" 136 | ] 137 | }, 138 | { 139 | "output_type": "stream", 140 | "name": "stdout", 141 | "text": [ 142 | "Extracting ./data/MNIST/raw/t10k-labels-idx1-ubyte.gz to ./data/MNIST/raw\n", 143 | "\n" 144 | ] 145 | } 146 | ] 147 | }, 148 | { 149 | "cell_type": "code", 150 | "source": [ 151 | "# Visualize the datasets\n", 152 | "def show_images(images, labels, label_header=\"True\"):\n", 153 | " figure = plt.figure(figsize=(10, 10))\n", 154 | " rows, cols = 3, 4\n", 155 | " for i in range(1, rows*cols+1):\n", 156 | " figure.add_subplot(rows, cols, i)\n", 157 | " plt.axis(False)\n", 158 | " plt.title(f\"{label_header}: {labels[i-1].item()}\")\n", 159 | " plt.imshow(images[i-1].permute(1, 2, 0), cmap='gray')\n", 160 | "\n", 161 | " plt.show()\n", 162 | "\n", 163 | "# Get a batch of images and show\n", 164 | "images, labels = next(iter(trainloader))\n", 165 | "show_images(images, labels, label_header=\"Raw\")" 166 | ], 167 | "metadata": { 168 | "colab": { 169 | "base_uri": "https://localhost:8080/", 170 | "height": 771 171 | }, 172 | "id": "WIo50iBS_9x9", 173 | "outputId": "48562b98-6926-4efc-f54f-46061bfa374b" 174 | }, 175 | "execution_count": null, 176 | "outputs": [ 177 | { 178 | "output_type": "display_data", 179 | "data": { 180 | "text/plain": [ 181 | "
" 182 | ], 183 | "image/png": "iVBORw0KGgoAAAANSUhEUgAAAxsAAALyCAYAAACy4sk3AAAAOXRFWHRTb2Z0d2FyZQBNYXRwbG90bGliIHZlcnNpb24zLjcuMSwgaHR0cHM6Ly9tYXRwbG90bGliLm9yZy/bCgiHAAAACXBIWXMAAA9hAAAPYQGoP6dpAABRPklEQVR4nO39e5zWdZ0//j+H88kVJRQFREQllSgPoKCDFHhcxcwTYKnbYU2r7+q6ZqZmuZ4rdT8eysJFd/GAkiZq5YHVGEVNcv24eNhKI0DKQERDQJR5//7ox3wkXm+ca5yXc13D/X678QeP67re79d1cb1m5sF75jl1RVEUAQAA0Mo6tPUCAACA9knZAAAAslA2AACALJQNAAAgC2UDAADIQtkAAACyUDYAAIAslA0AACALZQMAAMhC2QAAALJQNt7jxhtvjLq6uqY/nTp1iv79+8dJJ50Ur7zySlsvb6NeeumlmDx5cmy11VbRvXv32GmnneKcc85p62XRTtXyXlnn5ptvjrq6uujVq1dbL4V2qhb3ybe//e311vy3fx577LG2XiLtTC3uk4iI3/3ud3H00UfHFltsET169Ij99tsvHn744bZeVlXq1NYLqEYXXHBBDB48OFavXh1PPPFE3HjjjfHoo4/GvHnzolu3bm29vA0888wzMXbs2Ojfv3+cccYZ0adPn1iwYEEsXLiwrZdGO1dre2WdFStWxNe//vXo2bNnWy+FTUAt7ZPPfOYzseOOO26Qf/Ob34wVK1bEiBEj2mBVbApqaZ8sXLgwRo0aFR07dowzzzwzevbsGVOnTo0DDzwwZs2aFWPGjGnrJVaXgiZTp04tIqJ46qmn1svPOuusIiKK6dOnt9HKyq1du7YYNmxYsffeexcrV65s6+WwiajFvfJeZ511VjF06NDi+OOPL3r27NnWy6GdqvV9ss6CBQuKurq64ktf+lJbL4V2qBb3yamnnlp06tSpePHFF5uyt956qxg4cGCxxx57tOHKqpNvo2qG+vr6iPjrtyqts2bNmvjWt74Ve+65Z2y++ebRs2fPqK+v3+AS2h577BGf+cxn1ss+9rGPRV1dXTz77LNN2fTp06Ouri5eeOGFpnO993xlHnjggZg3b16cf/750b1791i5cmWsXbu2xc8VPohq3ivr/Pa3v40rr7wyrrjiiujUycVdPny1sE/e69Zbb42iKOL4449v0eOhJap5nzQ0NMTuu+8eQ4cObcp69OgREyZMiKeffjp++9vfVv6E2zFloxnmz58fERFbbLFFU/bmm2/GlClTYuzYsXHZZZfFt7/97ViyZEkcdNBB8cwzzzTdr76+Ph599NGmvy9btiyee+656NChQzQ0NDTlDQ0N0bdv39hll10iImLcuHExbty4913bQw89FBERXbt2jb322it69uwZPXr0iIkTJ8ayZcs+yNOGilXzXlnntNNOi09+8pNx6KGHtvBZwgdTC/vkvW6++eYYOHCgbw3hQ1XN++Ttt9+O7t27b5D36NEjIiJ+/etfV/Rc2722vrRSTdZdynvooYeKJUuWFAsXLixmzJhR9O3bt+jatWuxcOHCpvu+++67xdtvv73e419//fVi6623Lj7/+c83ZXfccUcREcXzzz9fFEVRzJw5s+jatWsxYcKE4rjjjmu63/Dhw4sjjzyy6e+DBg0qBg0a9L5rnjBhQhERRZ8+fYrjjz++mDFjRnHeeecVnTp1KkaPHl00Nja29OWAUrW4V4qiKO69996iU6dOxXPPPVcURVGceOKJvo2KbGp1n7zXvHnziogovv71r1f8WGiOWtwnhx9+eNG7d+/izTffXC8fNWpUERHF9773vYpeg/bO9xAkjB8/fr2/b7/99jFt2rQYMGBAU9axY8fo2LFjREQ0NjbG8uXLo7GxMfbaa694+umnm+637jLg7NmzY5dddomGhoYYMWJEHHDAAXHJJZdERMTy5ctj3rx5cdJJJzU9bl2jfz8rVqyIiIgRI0bEtGnTIiLiqKOOih49esTZZ58ds2bN2uD5QGuppb2yZs2aOP300+PLX/5y7Lrrri15utAitbRP/tbNN98cEeFbqMiulvbJKaecEvfcc08cd9xxcdFFF0XPnj3juuuui7lz50ZExKpVqyp+/u2Zb6NKuPbaa+PBBx+MGTNmxKGHHhpLly6Nrl27bnC/m266KYYPHx7dunWLPn36RN++feO+++6LN954o+k+W2+9dey0005Nl+0aGhqivr4+xowZE4sXL46XX345HnvssWhsbGzaHJVYdxlv0qRJ6+WTJ0+OiIg5c+ZUfExorlraK1deeWUsXbo0vvOd77T8CUML1NI+ea+iKOKWW26JYcOGxfDhwz/QseD91NI+OeSQQ+Lqq6+O2bNnxx577BFDhw6N++67Ly666KKICCPV/4aykTBy5MgYP358HHXUUTFz5swYNmxYTJ48uekqQkTEtGnT4qSTToohQ4bEDTfcEL/4xS/iwQcfjE996lPR2Ni43vH222+/aGhoiFWrVsWvf/3rqK+vj2HDhkXv3r2joaEhGhoaolevXrH77rtXvNZtt902Iv66sd5rq622ioiI119/veJjQnPVyl5544034sILL4wvfelL8eabb8b8+fNj/vz5sWLFiiiKIubPnx9//vOfW+U1gb9VK/vkbz322GPxhz/8wVUNPhS1tk+++tWvxquvvhpz5syJuXPnxosvvhibb755RETsvPPOLX8h2iFl43107NgxLrnkkli8eHFcc801TfmMGTNihx12iDvvvDM+97nPxUEHHRTjx4+P1atXb3CM+vr6WLBgQdx2222xdu3aGD16dHTo0KFpIzQ0NMTo0aObLg1WYs8994yI2OAX3yxevDgiIvr27VvxMaElqnmvvP7667FixYq4/PLLY/DgwU1/fvKTn8TKlStj8ODB8Y//+I8f+DWA91PN++RvrfvFl+uulMOHpVb2Sc+ePWPUqFGx5557RseOHeOhhx6K7t27x7777tviY7ZHykYzjB07NkaOHBlXXXVV0xt63ZuzKIqm+z355JPx+OOPb/D4dZfoLrvsshg+fHhT862vr49Zs2bF3LlzN7iM19zxa0cccUR07do1pk6dul6rnzJlSkREHHDAAZU8VfhAqnWvbLXVVnHXXXdt8OeTn/xkdOvWLe666644++yzW/7EoQLVuk/e65133ok77rgj9ttvv9huu+0qe4LQCmphn7zXnDlz4s4774wvfOELTefi/68tfzq92pT9Ypmi+H+TDX7wgx8URVEU//7v/15ERDFhwoTi+uuvL77xjW8UvXv3LnbbbbfkJIN+/foVEVF87Wtfa8oef/zxIiKKiCgeeeSR9e5fyeSQCy64oIiI4oADDiiuvfba4h//8R+Lurq6YtKkSc1/8lCBWt0rf8s0KnKq5X1yzz33FBFR/PCHP2z2Y6AlanGfzJ8/vxg5cmRx4YUXFlOmTClOP/30onv37sXuu+++wYQqikLZeI+NveHXrl1bDBkypBgyZEjx7rvvFo2NjcXFF19cDBo0qOjatWux++67F/fee29x4oknJt+oxxxzzAa/CXPNmjVFjx49ii5duhSrVq1a7/6VfGJobGwsrr766mLnnXcuOnfuXAwcOLA499xzizVr1lT0/KG5anWv/C1lg5xqeZ9MnDix6Ny5c/Haa681+zHQErW4T5YtW1YcccQRRb9+/YouXboUgwcPLs466yxFo0RdUbznWhQAAEAr8TMbAABAFsoGAACQhbIBAABkoWwAAABZKBsAAEAWygYAAJCFsgEAAGTRqbl3rKury7kO+MCq4VfG2CdUO/sE3l817JMIe4Xq15y94soGAACQhbIBAABkoWwAAABZKBsAAEAWygYAAJCFsgEAAGShbAAAAFkoGwAAQBbKBgAAkIWyAQAAZKFsAAAAWSgbAABAFsoGAACQhbIBAABkoWwAAABZKBsAAEAWndp6AeQzffr0ZH700Ucn8zvuuCOZT5w4sdXWBADApsOVDQAAIAtlAwAAyELZAAAAslA2AACALJQNAAAgC9Oo2oG99torme+///7JvCiKZH7//fe32poAAMCVDQAAIAtlAwAAyELZAAAAslA2AACALJQNAAAgi7qibDTR396xri73Wngf3bp1S+a/+c1vknnfvn2T+Ve/+tVkfsMNN7RsYVWimW/lrOyTtlf2PrjiiiuS+RlnnJFzOVXHPoH3Vw37JMJeofo1Z6+4sgEAAGShbAAAAFkoGwAAQBbKBgAAkIWyAQAAZGEaVQ057bTTkvn3vve9ZH7LLbck8xNOOKG1llRVqmF6SK3sk3322SeZv/LKK8l84cKFOZfTqip9H9TKv1lrsU8+uK233jqZT5kyJZnvsssuybxTp07J/JFHHknm8+bNS+ZTp05N5hERr732WultlKuGfRJR+3ulUmVTNE888cRkfu655ybz3//+98n84x//eMVrKvsa64ILLkjmK1asqPgctcw0KgAAoM0oGwAAQBbKBgAAkIWyAQAAZKFsAAAAWZhGVYV23HHHZP70008n87fffjuZDxkyJJm/+eabLVtYlauG6SG1sk/KXqtRo0Yl8yeeeCLnclpk4MCByXzBggUVHadW/s1ai33ywR155JHJ/M477/yQV/JXr776aultZZOtzjnnnGT+0ksvtcaSal417JOI2t8rZc4444xk/rWvfS2Zl328L1P2urXmv+vPfvazZP7Zz342mb/xxhutdu5qYhoVAADQZpQNAAAgC2UDAADIQtkAAACyUDYAAIAsTKNqI1tuuWXpbWXTQ3bbbbdkPmXKlGR+8sknV7yuWlYN00NqZZ+UTWxatGhRMh89enTO5bTIPvvsk8wff/zxio5TK/9mrcU+yeemm25K5h06pP9f78EHH0zmr7zySjIfNmxYMv+Xf/mX0jUNGDAgmb/88svJ/JOf/GQyr3TKW62rhn0SUTt7Zauttkrm06ZNS+Zjx45N5h07dkzmZe+/yy+/PJk3NDQk840p+xrrrLPOSuYf//jHk3nZ58snn3yy4jXVAtOoAACANqNsAAAAWSgbAABAFsoGAACQhbIBAABkYRpVG7n//vtLbxs/fnwyX7hwYTIfPnx4Mn/zzTcrX1gNq4bpIbWyT26//fZkfswxxyTzUaNGJfMnnnii1dZUqYEDBybzSqfm1Mq/WWuxT9qfHXbYofS2H//4x8n8U5/6VDKfOXNmMj/iiCMqX1gNq4Z9ElF9e6VsslrZxKYLL7ywouOXTdf8//6//y+Zv/322xUdvyX69++fzMs+19xxxx3J/Itf/GIyX7FiRcsWViVMowIAANqMsgEAAGShbAAAAFkoGwAAQBbKBgAAkEWntl5Ae1c2WWrs2LGlj1myZEkyP/jgg5P5pjZ1ig9fNU6jKltTmbJpblDrXn755dLbLrjggmReNo2qLO/du3cyX758+UbXRvvyuc99LplXOnXqD3/4QzK//PLLk/mHMXWqzLvvvlvR/cumOv72t79N5uedd17Fa6o1rmwAAABZKBsAAEAWygYAAJCFsgEAAGShbAAAAFmYRtVKunTpksy/+c1vJvOOHTuWHuu73/1uMn/xxRcrXxi0grLJT1deeeWHvBKgEm+88UZF9+/Vq1cy39jnLDYdO++8c6scZ8KECcn8pZdeapXjU11c2QAAALJQNgAAgCyUDQAAIAtlAwAAyELZAAAAsjCNqkJTp05N5vvss08y32mnnZL5rbfeWnqO73//+5UvDCrw+OOPJ/NjjjnmQ17Jh2fgwIFtvQQAImLZsmVtvYQNfOITn0jmF1100Ye7kHbIlQ0AACALZQMAAMhC2QAAALJQNgAAgCyUDQAAIAvTqCr0s5/9LJmfcMIJFR3n+uuvb43lQIu88sorFd2/bEpV2YSnhQsXVrym3KpxTZDbkUceWdH977///mT+xhtvJPPevXsn806dKvvyYvXq1cl8xYoVFR2H2nDXXXcl80MOOSSZt9b0qkGDBpXedv755yfzgw8+uFXOXY0TuD4srmwAAABZKBsAAEAWygYAAJCFsgEAAGShbAAAAFnUFUVRNOuOdXW511JVNt9882R+++23J/Nx48ZVdPwHHnig9LZDDz20omPxV818K2dV6/uk0tfwuOOOS+Zl+6Q1HXvsscl8+vTpFR2n1v/NKmWftD/9+/cvve2//uu/kvnOO++czOfOnZvM//SnPyXz+vr6ZF72ObTMI488ksw/+clPVnSc1lIN+ySi+vbKsGHDkvm1116bzPfbb7+Kjv/iiy8m88ceeyyZ33vvvcn8n/7pn5L5xz72sdJz9+nT531W98Fss802yfzPf/5z1vPm1py94soGAACQhbIBAABkoWwAAABZKBsAAEAWygYAAJCFsgEAAGRh9G2JvfbaK5k/8cQTybzsZSwb17axcXA/+tGPkvmpp55a+hiqY1Rhre+T73//+8n8n//5n5P5woULk3nZWNqy/VPm9NNPr/i2gQMHJvM77rgjmZettb2yT/Lp2bNnMv/Od76TzLfffvtkvt122yXzj370o8m8U6dOpWvq3r176W2t4Te/+U0y/9nPfpbM58+fn8zvuuuuZL5gwYIWreuDqoZ9ElE7e6XsvVw2Evfggw/OuJry121j/67PPfdcMl+1alUyL/s6sYzRtwAAAK1M2QAAALJQNgAAgCyUDQAAIAtlAwAAyMI0qhJ33nlnMp8wYUIyf/jhh5P55MmTk/lFF11Ueu7x48cn8z322COZL1++vPRYm5JqmB5S6/ukbJJT2VS1svtXo8cffzyZjx49+kNeSduyT/LZe++9k/mcOXOSeYcObff/fStWrEjmN9xwQzK/9dZbk/n//M//JPOVK1e2bGFVohr2SUT73SsjR45M5ueee24y32233So6ftnrNnPmzNLH3Hvvvcn8/PPPT+ZlU0XL3jv9+vVL5qZRAQAAtJCyAQAAZKFsAAAAWSgbAABAFsoGAACQRae2XkBbGzZsWDI/4ogjknnZT93PmzcvmS9ZsiSZ//d//3fpmr7whS8k89tvvz2Zl6111apVpeeAlIULFybzfffdN5kfffTRyfyKK65olfXccccdpbcNGDAgmY8aNaqi+0NrefLJJ5P5IYccksx79uxZ0fE//elPJ/MTTjih9DFvvvlmMi/7vPHII49UtCZoiV/96lfJvGzi54fhwAMPTOZlU+Ya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unXr1tbL28A555wTl156aXzpS1+KESNGxN133x2TJ0+Ourq6mDhxYlsvj3aslvbKwoULY9SoUdGxY8c488wzo2fPnjF16tQ48MADY9asWTFmzJi2XiLtVC3tk4iIc889N/r16xe777573H///W29HDYRtbZPnnnmmRg7dmz0798/zjjjjOjTp08sWLAgFi5c2NZLqz4FTaZOnVpERPHUU0+tl5911llFRBTTp09vo5WVW7RoUdG5c+fiK1/5SlPW2NhY1NfXFwMGDCjefffdNlwd7VUt7pVTTz216NSpU/Hiiy82ZW+99VYxcODAYo899mjDldFe1eI+KYqi+P3vf18URVEsWbKkiIji/PPPb9P10L7V4j5Zu3ZtMWzYsGLvvfcuVq5c2dbLqXq+jaoZ6uvrI+Kvl8vWWbNmTXzrW9+KPffcMzbffPPo2bNn1NfXb/AtGXvssUd85jOfWS/72Mc+FnV1dfHss882ZdOnT4+6urp44YUXms713vOVufvuu+Odd96JU089tSmrq6uLU045JRYtWhSPP/545U8YWqia90pDQ0PsvvvuMXTo0KasR48eMWHChHj66afjt7/9beVPGFqgmvdJRMT222/fkqcFraqa98kDDzwQ8+bNi/PPPz+6d+8eK1eujLVr17b4ubZ3ykYzzJ8/PyIitthii6bszTffjClTpsTYsWPjsssui29/+9uxZMmSOOigg+KZZ55pul99fX08+uijTX9ftmxZPPfcc9GhQ4doaGhoyhsaGqJv376xyy67RETEuHHjYty4ce+7tv/+7/+Onj17Nj1unZEjRzbdDh+Wat4rb7/9dnTv3n2DvEePHhER8etf/7qi5wotVc37BKpFNe+Thx56KCIiunbtGnvttVf07NkzevToERMnToxly5Z9kKfdLikbCW+88UYsXbo0Fi1aFD/5yU/iO9/5TnTt2jUOO+ywpvtsscUWMX/+/Pj+978fX/7yl+PMM8+MJ554Irbccsu4+uqrm+5XX18fS5YsaWrNjz32WHTp0iUOO+ywDd7w++23X8Vr/eMf/9j0Q3zvtc0220RExOLFiys+JjRXLe2VoUOHxrPPPht/+ctf1svXfUKq9h9EpHbV0j6BtlJL+2TdlfBjjz02PvrRj8aMGTPirLPOip/85Cdx+OGHR1EULX0Z2iU/IJ4wfvz49f6+/fbbx7Rp02LAgAFNWceOHaNjx44R8ddpUMuXL4/GxsbYa6+94umnn26637rLgLNnz45ddtklGhoaYsSIEXHAAQfEJZdcEhERy5cvj3nz5sVJJ53U9Lh1jf79rFq1Krp27bpBvu6HqVatWtWs40BL1NJeOeWUU+Kee+6J4447Li666KLo2bNnXHfddTF37tyIsFfIp5b2CbSVWtonK1asiIiIESNGxLRp0yIi4qijjooePXrE2WefHbNmzdrg+WzKXNlIuPbaa+PBBx+MGTNmxKGHHhpLly5NfkF/0003xfDhw6Nbt27Rp0+f6Nu3b9x3333xxhtvNN1n6623jp122qmpSTc0NER9fX2MGTMmFi9eHC+//HI89thj0djY2LQ5KtG9e/d4++23N8hXr17ddDvkUkt75ZBDDomrr746Zs+eHXvssUcMHTo07rvvvrjooosiIqJXr14tfBVg42ppn0BbqaV9su5rq0mTJq2XT548OSIi5syZU/Ex2zNlI2HkyJExfvz4OOqoo2LmzJkxbNiwmDx5clOTjYiYNm1anHTSSTFkyJC44YYb4he/+EU8+OCD8alPfSoaGxvXO95+++0XDQ0NsWrVqvj1r38d9fX1MWzYsOjdu3c0NDREQ0ND9OrVK3bfffeK17rNNtvEn/70pw0u2f3xj3+MiIhtt922Ba8ANE8t7ZWIiK9+9avx6quvxpw5c2Lu3Lnx4osvxuabbx4RETvvvHPLXwjYiFrbJ9AWammfrPvaauutt14v32qrrSIi4vXXX6/4mO2ZsvE+OnbsGJdcckksXrw4rrnmmqZ8xowZscMOO8Sdd94Zn/vc5+Kggw6K8ePHN11ReK/6+vpYsGBB3HbbbbF27doYPXp0dOjQoWkjNDQ0xOjRo5suDVbiE5/4RKxcubLp+xLXefLJJ5tuhw9Dte+VdXr27BmjRo2KPffcMzp27BgPPfRQdO/ePfbdd98WHxOaq1b2CbSlat8ne+65Z0Rs+LN+635Otm/fvhUfsz1TNpph7NixMXLkyLjqqqua3tDr3pzvvaLw5JNPJkfNrrtEd9lll8Xw4cOb/ie1vr4+Zs2aFXPnzt3gMl5zx68dccQR0blz57juuuuasqIo4oc//GH0798/Ro8eXeGzhZar5r2SMmfOnLjzzjvjC1/4QtO5ILda2yfQFqp5nxxxxBHRtWvXmDp16npXVKZMmRIREQcccEAlT7XdUzaa6cwzz4xXX301brzxxoiIOOyww+Lll1+OI488Mn70ox/F2WefHQcffHDsuuuuGzx2xx13jH79+sX//u//rvfGHjNmTMyfPz/WrFmzwRu+uePXBgwYEKeddlpce+21cfLJJ8eUKVPi8MMPj4aGhrj88sv9zxYfumrdK3/4wx9i7733josuuihuuOGG+Od//ucYP358DB8+PC6++OIP9qShQtW6TyIi/vM//zMuvPDCuOKKKyLirz9ke+GFF8aFF14Yf/jDH1r4jKFy1bpP+vXrF+ecc048+uijcfDBB8d1110XJ598clx66aUxadKkGDFixAd74u1NG/5CwapT9lssi+Kvvy1yyJAhxZAhQ4p33323aGxsLC6++OJi0KBBRdeuXYvdd9+9uPfee4sTTzyxGDRo0AaPP+aYYzb4TZhr1qwpevToUXTp0qVYtWrVevcfNGhQ8jgpa9eubVpLly5dit12262YNm1aRc8dKlGLe2XZsmXFEUccUfTr16/o0qVLMXjw4OKss84q3nzzzYqfPzRHLe6ToiiK/fffv4iI5J+HH364kpcA3let7pPGxsbi6quvLnbeeeeic+fOxcCBA4tzzz23WLNmTUXPf1NQVxSGAQMAAK3Pt1EBAABZKBsAAEAWygYAAJCFsgEAAGShbAAAAFkoGwAAQBbKBgAAkEWn5t6xrq4u5zrgA6uGXxljn1Dt7BN4f9WwTyLsFapfc/aKKxsAAEAWygYAAJCFsgEAAGShbAAAAFkoGwAAQBbKBgAAkIWyAQAAZKFsAAAAWSgbAABAFsoGAACQhbIBAABkoWwAAABZKBsAAEAWygYAAJCFsgEAAGShbAAAAFl0ausFAABAbltuuWXpbaecckoy33PPPZP5CSeckMxXrFhR+cLaOVc2AACALJQNAAAgC2UDAADIQtkAAACyUDYAAIAsTKPK7Nhjj03mRVGUPmafffZJ5qeddloyf/LJJ5P5lVdemczr6uqS+Zw5c5L5okWLkjkA1W233XZL5tdee20yP+yww5K5CTtUowkTJiTzww8/PJnX19eXHmunnXZK5mVfr02cODGZT5kypfQcmypXNgAAgCyUDQAAIAtlAwAAyELZAAAAslA2AACALOqKjY1Feu8dSyYYbWoqnRR1zDHHJPPGxsbSc3TokO6AZY9prfuXTaO68847k3nZtKu20sy3clb2CdXOPtm0/PznP0/mBxxwQEX5ww8/3GprqgXVsE8i7JX386c//SmZf+QjH6n4WAsXLkzms2fPTua33nprMv/FL35R8blrWXP2iisbAABAFsoGAACQhbIBAABkoWwAAABZKBsAAEAWndp6AbVmu+22S+ZlU6eefPLJZL527drSc+y7777J/IknnkjmHTt2TOZ77713Mi+bbjF69OiKjn/HHXck80WLFiVzOPHEE5P5F7/4xWRethc2Zvr06cl80qRJFR8Lat2BBx6YzJ977rlk/qtf/SrncqBFjj766GT+d3/3dxUdZ+rUqaW3XXrppcn8pZdequgcbMiVDQAAIAtlAwAAyELZAAAAslA2AACALJQNAAAgi7qiKIpm3bFkgtGmZsCAAcm8bPJT2TSqjdlnn32Sedk0qjJla7r99tuTeWNjYzLv0CHdSefMmZPM6+vrm7G61tfMt3JWm9o+6dOnTzL/3ve+l8wnT56czDt37txqa1qyZEkyHzJkSDJfsWJFq527Ftgn7U///v1Lb1uwYEEyL5sAt7FpPZuSatgnEZveXtlxxx2T+dNPP53Me/ToUdHxhw8fXnrb888/X9Gx+Kvm7BVXNgAAgCyUDQAAIAtlAwAAyELZAAAAslA2AACALDq19QJqzaJFiyrKjznmmGR+2mmnlZ5j1KhRybzsJ/7LJl5deeWVyXzfffdN5tOnT0/mAwcOTOajR4+u6DjHHXdcMqd2ffvb307mJ5544oe7kPfYfPPNk/lHPvKRZL6pTaOi/ZkwYULFj3n55ZczrASaZ9iwYcl8hx12SOY9e/ZM5q+//noyv+aaa5K5iVNtw5UNAAAgC2UDAADIQtkAAACyUDYAAIAslA0AACAL06gqtM8++yTzsulSZdOoGhsbS89RNnWq7DF77713Mh8xYkQyv+OOO5L5448/nswHDBhQ0XrK1k/t2mqrrZL5l7/85YqOs3r16mTevXv3ZP7HP/6x9Fj9+vVL5l26dEnmhx9+eDK/+uqrS88BtaBDh/L/N9zYbdBW5s2bl8wvuOCCZF72dcUPfvCDZH7ttde2bGFk4aMQAACQhbIBAABkoWwAAABZKBsAAEAWygYAAJDFJj+N6vvf/34yL5suVTbZo2wyU11dXUXHiYiYMWNGMi+bxvDkk08m8yuvvLL0HCkTJ05M5scee2wyL3sO2223XTIvm2q1aNGiZqyOtnTfffcl844dOybz3/3ud8n805/+dDIfOnRoMv/zn/9cuqaGhobS21I6ddrkP9zRTu2www6lty1fvjyZL1myJNNq4P39wz/8QzI/6KCDKjrOO++8k8y9v6uLKxsAAEAWygYAAJCFsgEAAGShbAAAAFkoGwAAQBabzHiW008/PZmXTZ0qmy5Vpuz+TzzxRDK/6qqrSo/1k5/8pKJz51Y2BavsOe+9994V5aZRVY9BgwYl82HDhiXzVatWJfOvfe1ryfz555+vKL/tttuSOWyKunTpkswPPfTQ0seUfXwt23PwYejWrVtFednXIQ888ECrrYl8XNkAAACyUDYAAIAslA0AACALZQMAAMhC2QAAALJod9OojjnmmGT+ve99L5nX1dUl8w4d0j3slVdeSeZz5sxJ5hMnTkzmtaS1XqOynOpx4oknJvOuXbsm88cffzyZ33///RWdt2PHjsl83333reg40J6NHj06me+0006lj3nhhRdyLQdabNKkSa1ynJdeeqmi+5dNVoyIuPXWWys61lNPPZXML7roomRe6VrbE1c2AACALJQNAAAgC2UDAADIQtkAAACyUDYAAIAs2t00qtNOOy2ZNzY2JvOyiUpl9z/22GOT+RNPPPH+i6typ59+ejIviiKZl71GZZO52sNr1N6VTZdas2ZNMh84cGAyL5te9fbbbyfzww47LJn3798/mbfE0qVLW+1YUCvmzZvX1kuADWyxxRbJvGz6ZZmrrroqmZdNndrYNKpKvx7cddddk3nZVMeyvfjxj3+8dE3thSsbAABAFsoGAACQhbIBAABkoWwAAABZKBsAAEAWNTuNap999knmo0aNSuZlE5XKJh+UTU5qDxOVyiYIHX300cm87DUqm9xQ6TQJqseDDz6YzBcsWJDMd9xxx2Q+ePDgZN6tW7dkfs011zRjdeubNWtWMh83blwyN42K9mpjH3Nnzpz5Ia4E1lc2UbB3797JfNmyZcn8V7/6VTI/7rjjKlpP2deCEeVTpzb2mErsttturXKcWuTKBgAAkIWyAQAAZKFsAAAAWSgbAABAFsoGAACQhbIBAABkUbOjb0877bRkXjairGykWdko20mTJrVoXbWgbGzwyJEjk3mlr+mVV17ZsoVRtX75y18m87LRt88//3yrnPfmm28uve2VV15J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Zaxdu7bFzxU+iGreK2W23377WLlyZaxZs6bFx4BKVPM+2XPPPaNXr17rZX369In6+vqmY8GHoZr3yd133x3vvPNOnHrqqU1ZXV1dnHLKKbFo0aJ4/PHHK3/C7Ziy0Qzz58+PiIgtttiiKXvzzTdjypQpMXbs2Ljsssvi29/+dixZsiQOOuigeOaZZ5ruV19fH48++mjT35ctWxbPPfdcdOjQIRoaGpryhoaG6Nu3b+yyyy4RETFu3LgYN27c+67toYceioiIrl27xl577RU9e/aMHj16xMSJE2PZsmUf5GlDxap5r6yzatWqWLp0acyfPz9uuummmDp1aowaNSq6d+/ewmcNlamFffK3/vSnP8VHPvKRFj8eKlXN++S///u/o2fPnk2PW2fkyJFNt/MebX1ppZqsu5T30EMPFUuWLCkWLlxYzJgxo+jbt2/RtWvXYuHChU33fffdd4u33357vce//vrrxdZbb118/vOfb8ruuOOOIiKK559/viiKopg5c2bRtWvXYsKECcVxxx3XdL/hw4cXRx55ZNPfBw0aVAwaNOh91zxhwoQiIoo+ffoUxx9/fDFjxozivPPOKzp16lSMHj26aGxsbOnLAaVqca+sc8kllxQR0fRn3LhxxYIFCyp9CeB91fI+ea/Zs2cXdXV1xXnnndeix8PG1OI++fu///tihx122CB/6623iogovvGNbzT7+W8K/IB4wt/+ANz2228f06ZNiwEDBjRlHTt2jI4dO0bEXycSLF++PBobG2OvvfaKp59+uul+6y4Dzp49O3bZZZdoaGiIESNGxAEHHBCXXHJJREQsX7485s2bFyeddFLT49Y1+vezYsWKiIgYMWJETJs2LSIijjrqqOjRo0ecffbZMWvWLD/QRza1tFfWmTRpUuy1116xZMmSuPfee+PVV1+NVatWVXQMqEQt7pN1/vznP8fkyZNj8ODB8fWvf71Fx4DmqKV9smrVqujatesG+bofZPc5ZX2+jSrh2muvjQcffDBmzJgRhx56aCxdujT5prrpppti+PDh0a1bt+jTp0/07ds37rvvvnjjjTea7rP11lvHTjvt1HTZrqGhIerr62PMmDGxePHiePnll+Oxxx6LxsbGps1RiXXf+jFp0qT18smTJ0dExJw5cyo+JjRXLe2VdQYNGhTjx4+PSZMmxc033xw77LBDjB8/3icHsqnFfRIR8dZbb8Vhhx0Wf/nLX+Luu+/e4Gc5oDXV0j7p3r17vP322xvkq1evbrqd/0fZSBg5cmSMHz8+jjrqqJg5c2YMGzYsJk+e3HQVISJi2rRpcdJJJ8WQIUPihhtuiF/84hfx4IMPxqc+9alobGxc73j77bdfNDQ0xKpVq+LXv/511NfXx7Bhw6J3797R0NAQDQ0N0atXr9h9990rXuu2224bEX/dWO+11VZbRUTE66+/XvExoblqaa+UOfroo2PhwoUxe/bsVjsmvFct7pM1a9bEZz7zmXj22Wfj7rvvjmHDhrX4WNActbRPttlmm/jTn/60we9o+uMf/xgR/+9rM/5K2XgfHTt2jEsuuSQWL14c11xzTVM+Y8aM2GGHHeLOO++Mz33uc3HQQQfF+PHjm1rte9XX18eCBQvitttui7Vr18bo0aOjQ4cOTRuhoaEhRo8e3XRpsBJ77rlnRMQGv/hm8eLFERHRt2/fio8JLVHte6XMuisa7/1fMcilFvZJY2NjnHDCCTFr1qy45ZZbYv/992/x84WWqPZ98olPfCJWrly5wYS2J598sul2/h9loxnGjh0bI0eOjKuuuqrpDb3uzfneVvvkk08mx52tu0R32WWXxfDhw2PzzTdvymfNmhVz587d4DJec8evHXHEEdG1a9eYOnXqeq1+ypQpERFxwAEHVPJU4QOp5r2yZMmSZH7DDTdEXV1d7LHHHs14hvDBVfM+iYj42te+FtOnT4/rrrtug/Gh8GGp5n1yxBFHROfOneO6665ryoqiiB/+8IfRv3//GD16dIXPtn1TNprpzDPPjFdffTVuvPHGiIg47LDD4uWXX44jjzwyfvSjH8XZZ58dBx98cOy6664bPHbHHXeMfv36xf/+7/+u98YeM2ZMzJ8/P9asWbPBG76549f69esX55xzTjz66KNx8MEHx3XXXRcnn3xyXHrppTFp0qQYMWLEB3viUKFq3SsXXXRRjBgxIs4777z48Y9/HJdddlmMHDky7rnnnvjqV78aO+644wd74lCBat0nV111VVx33XUxatSo6NGjR0ybNm29P2+99dYHe+JQgWrdJwMGDIjTTjstrr322jj55JNjypQpcfjhh0dDQ0NcfvnlrXr1vV1oy1FY1abst1gWxV9/U/eQIUOKIUOGFO+++27R2NhYXHzxxcWgQYOKrl27Frvvvntx7733FieeeGJybNoxxxyzwW/CXLNmTdGjR4+iS5cuxapVq9a7fyVjChsbG4urr7662HnnnYvOnTsXAwcOLM4999xizZo1FT1/aK5a3CsPPPBAcdhhhxXbbrtt0blz52KzzTYr9t1332Lq1KlGRJNFLe6TE088cb3R0H/75/e//32lLwNsVC3uk3VrW7eWLl26FLvttlsxbdq0ip77pqKuKP7mp1sAAABagW+jAgAAslA2AACALJQNAAAgC2UDAADIQtkAAACyUDYAAIAslA0AACCLTs29Y11dXc51wAdWDb8yxj6h2tkn8P6qYZ9E2CtUv+bsFVc2AACALJQNAAAgC2UDAADIQtkAAACyUDYAAIAslA0AACALZQMAAMhC2QAAALJQNgAAgCyUDQAAIItObb2AajVo0KBk/h//8R/JfOnSpcm8T58+yXzs2LEtWhcAANQKVzYAAIAslA0AACALZQMAAMhC2QAAALJQNgAAgCxMoyrxxS9+MZnvu+++yfy1115L5occckirrQmA6jVmzJhkft999yXzXr16JfNXX301mZdNQ3z66adL13TbbbeV3gbwYXBlAwAAyELZAAAAslA2AACALJQNAAAgC2UDAADIoq4oiqJZd6yry72WNtG3b99kXjYNpOzlWrhwYTI/+OCDk/mLL77YjNVRiWa+lbNqr/ukrfzd3/1d6W2f//znk/kVV1yRzO+5555kfsQRR1S+sBpmnzRf9+7dk/nZZ5+dzE899dRk3rt372Re9jpU+m/0+9//vvS2OXPmJPPLL788mT/33HMVnbu9qoZ9ElE7e6VW7LjjjqW3PfXUU8l88803T+YPPfRQMi/7OPC73/3ufVZXm5qzV1zZAAAAslA2AACALJQNAAAgC2UDAADIQtkAAACy2OSnUe23337J/Je//GUyr3Qa1T//8z8n87vuuqsZq6MS1TA9pL3uk0p17do1mX/qU59K5kceeWQyP/DAA0vPMXDgwIrWtGbNmmR+6KGHJvOHH364ouPXCvtkQ2Xv12uuuSaZ/8M//EOrnLe1plG1xDvvvJPMp06dmszLJuy0V9WwTyKqb6/Uim7duiXzmTNnlj5m3LhxyXz16tUVnePf//3fk/mXvvSl0nPXMtOoAACANqNsAAAAWSgbAABAFsoGAACQhbIBAABk0amtF/Bh6dmzZzI//fTTk3mlEyAWLFiQzPfYY49kbhoV7cGwYcOS+Y9//ONkPnLkyIqOv7F9WOm0mC5duiTzhx56KJl/4xvfSOY/+MEPkvmKFSsqWg/VY4sttkjmrTV1qsz111+fzN94441kfuaZZ7baucv2wyGHHJLMt9lmm2T+xz/+sdXWBJXabLPNkvntt9+ezLfbbrvSY82bNy+Zn3jiicn8kUce2fjiaOLKBgAAkIWyAQAAZKFsAAAAWSgbAABAFsoGAACQxSYzjeqjH/1oMj/iiCOSedmkm4suuiiZT5kyJZkvXbq0GauD6rb99tsn85///OfJfNttt22V87711lult82aNSuZ77TTThXlHTt2TOaXXXZZMh84cGAy/+Y3v5nMTamqfmXvsxdeeCGZ77LLLsn8+eefT+YTJkxI5vPnz0/mnTt3TuZXXnllMt9tt92SeUTE3XffnczLJjSWvb/PP//8ZH7eeecl8yVLlpSuCVrLCSeckMwPPPDAZP7ss8+WHuvQQw9N5mUT17zHm8+VDQAAIAtlAwAAyELZAAAAslA2AACALJQNAAAgi7qibOzS396xri73WrIqm7zxq1/9KpmXTRs55JBDkvn999/fsoXRapr5Vs6q1vdJmR133DGZT5s2LZmPGDEimS9fvjyZf+ELX0jmv/vd70rXNG/evNLbUg444IBkftNNNyXzfv36JfOy99mRRx6ZzGfOnNmM1X147JNNy1577ZXMn3rqqWTe2NhY0fF33333ZL6xqT+1oBr2SYS9ss6gQYOSedn7rFevXsl8Y5MSX3311YrWdOmllybzPn36JPMvfelLFR2/VjRnr7iyAQAAZKFsAAAAWSgbAABAFsoGAACQhbIBAABk0amtF/BhKZsUM3To0GRe9tP1n/70p5O5aVS0Z2VTocaOHZvMJ02alMxvvfXWZL569eoWrasSjz32WEX50UcfnXM58KGYO3duMr/33nuTednExTJl96/1aVRUl6985SvJvEOH9P+ZH3vsscm80olTG1M2KaxsumJ7nUbVHK5sAAAAWSgbAABAFsoGAACQhbIBAABkoWwAAABZbDLTqPbbb79kXjZNoCz/8Y9/3GprglpXNkVq6tSpH/JK/p9hw4Yl83/9139N5hMmTEjmZRPpli1blszLJnZBNXrhhReSeaXTqLp3794ay4GIiNhmm22S+cknn5zMf/vb3ybzn/zk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\n" 184 | }, 185 | "metadata": {} 186 | } 187 | ] 188 | }, 189 | { 190 | "cell_type": "markdown", 191 | "source": [], 192 | "metadata": { 193 | "id": "mWPjnMrWPm8C" 194 | } 195 | }, 196 | { 197 | "cell_type": "code", 198 | "source": [ 199 | "# Preprocessing Step: Normalization and Data Augmentation\n", 200 | "transform_train = transforms.Compose([\n", 201 | " transforms.RandomRotation(10), # Randomly rotate the image by 10 degrees\n", 202 | " transforms.RandomAffine(0, translate=(0.1, 0.1)), # Random translation\n", 203 | " transforms.ToTensor(),\n", 204 | " transforms.Normalize((0.5,), (0.5,)) # Normalize to range [-1, 1]\n", 205 | "])\n", 206 | "\n", 207 | "transform_test = transforms.Compose([\n", 208 | " transforms.ToTensor(),\n", 209 | " transforms.Normalize((0.5,), (0.5,)) # Normalize the same way for test set\n", 210 | "])" 211 | ], 212 | "metadata": { 213 | "id": "vRBLQe78AYkf" 214 | }, 215 | "execution_count": null, 216 | "outputs": [] 217 | } 218 | ] 219 | } -------------------------------------------------------------------------------- /Handwritten Digit Recognition.pptx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Navdeep-04/Handwritten_Digit_Recognition_with_LeNet5_using_Pytorch/c1f88f375f685e5eaf946c6585bc9fc43b7d4932/Handwritten Digit Recognition.pptx -------------------------------------------------------------------------------- /Lenet5 Model.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "nbformat": 4, 3 | "nbformat_minor": 0, 4 | "metadata": { 5 | "colab": { 6 | "provenance": [] 7 | }, 8 | "kernelspec": { 9 | "name": "python3", 10 | "display_name": "Python 3" 11 | }, 12 | "language_info": { 13 | "name": "python" 14 | } 15 | }, 16 | "cells": [ 17 | { 18 | "cell_type": "code", 19 | "source": [ 20 | "#import necessary libraries\n", 21 | "import torch\n", 22 | "import torchvision\n", 23 | "import torchvision.transforms as transforms\n", 24 | "import matplotlib.pyplot as plt" 25 | ], 26 | "metadata": { 27 | "id": "_jO-FK2h_9bB" 28 | }, 29 | "execution_count": 1, 30 | "outputs": [] 31 | }, 32 | { 33 | "cell_type": "code", 34 | "source": [ 35 | "# Step 1: Download the MNIST dataset\n", 36 | "torchvision.datasets.MNIST(root='./data', train=True, download=True)\n", 37 | "torchvision.datasets.MNIST(root='./data', train=False, download=True)\n", 38 | "\n", 39 | "# Step 2: Load the raw MNIST dataset\n", 40 | "trainset = torchvision.datasets.MNIST(root='./data', train=True, download=True, transform=transforms.ToTensor())\n", 41 | "trainloader = torch.utils.data.DataLoader(trainset, batch_size=64, shuffle=True)" 42 | ], 43 | "metadata": { 44 | "id": "zpKE0cMQCiLM", 45 | "colab": { 46 | "base_uri": "https://localhost:8080/" 47 | }, 48 | "outputId": "5c3cd622-8946-43db-f37d-2afde34036ea" 49 | }, 50 | "execution_count": 2, 51 | "outputs": [ 52 | { 53 | "output_type": "stream", 54 | "name": "stdout", 55 | "text": [ 56 | "Downloading http://yann.lecun.com/exdb/mnist/train-images-idx3-ubyte.gz\n", 57 | "Failed to download (trying next):\n", 58 | "HTTP Error 403: Forbidden\n", 59 | "\n", 60 | "Downloading https://ossci-datasets.s3.amazonaws.com/mnist/train-images-idx3-ubyte.gz\n", 61 | "Downloading https://ossci-datasets.s3.amazonaws.com/mnist/train-images-idx3-ubyte.gz to ./data/MNIST/raw/train-images-idx3-ubyte.gz\n" 62 | ] 63 | }, 64 | { 65 | "output_type": "stream", 66 | "name": "stderr", 67 | "text": [ 68 | "100%|██████████| 9.91M/9.91M [00:00<00:00, 15.9MB/s]\n" 69 | ] 70 | }, 71 | { 72 | "output_type": "stream", 73 | "name": "stdout", 74 | "text": [ 75 | "Extracting ./data/MNIST/raw/train-images-idx3-ubyte.gz to ./data/MNIST/raw\n", 76 | "\n", 77 | "Downloading http://yann.lecun.com/exdb/mnist/train-labels-idx1-ubyte.gz\n", 78 | "Failed to download (trying next):\n", 79 | "HTTP Error 403: Forbidden\n", 80 | "\n", 81 | "Downloading https://ossci-datasets.s3.amazonaws.com/mnist/train-labels-idx1-ubyte.gz\n", 82 | "Downloading https://ossci-datasets.s3.amazonaws.com/mnist/train-labels-idx1-ubyte.gz to ./data/MNIST/raw/train-labels-idx1-ubyte.gz\n" 83 | ] 84 | }, 85 | { 86 | "output_type": "stream", 87 | "name": "stderr", 88 | "text": [ 89 | "100%|██████████| 28.9k/28.9k [00:00<00:00, 537kB/s]\n" 90 | ] 91 | }, 92 | { 93 | "output_type": "stream", 94 | "name": "stdout", 95 | "text": [ 96 | "Extracting ./data/MNIST/raw/train-labels-idx1-ubyte.gz to ./data/MNIST/raw\n", 97 | "\n", 98 | "Downloading http://yann.lecun.com/exdb/mnist/t10k-images-idx3-ubyte.gz\n", 99 | "Failed to download (trying next):\n", 100 | "HTTP Error 403: Forbidden\n", 101 | "\n", 102 | "Downloading https://ossci-datasets.s3.amazonaws.com/mnist/t10k-images-idx3-ubyte.gz\n", 103 | "Downloading https://ossci-datasets.s3.amazonaws.com/mnist/t10k-images-idx3-ubyte.gz to ./data/MNIST/raw/t10k-images-idx3-ubyte.gz\n" 104 | ] 105 | }, 106 | { 107 | "output_type": "stream", 108 | "name": "stderr", 109 | "text": [ 110 | "100%|██████████| 1.65M/1.65M [00:00<00:00, 3.78MB/s]\n" 111 | ] 112 | }, 113 | { 114 | "output_type": "stream", 115 | "name": "stdout", 116 | "text": [ 117 | "Extracting ./data/MNIST/raw/t10k-images-idx3-ubyte.gz to ./data/MNIST/raw\n", 118 | "\n", 119 | "Downloading http://yann.lecun.com/exdb/mnist/t10k-labels-idx1-ubyte.gz\n", 120 | "Failed to download (trying next):\n", 121 | "HTTP Error 403: Forbidden\n", 122 | "\n", 123 | "Downloading https://ossci-datasets.s3.amazonaws.com/mnist/t10k-labels-idx1-ubyte.gz\n", 124 | "Downloading https://ossci-datasets.s3.amazonaws.com/mnist/t10k-labels-idx1-ubyte.gz to ./data/MNIST/raw/t10k-labels-idx1-ubyte.gz\n" 125 | ] 126 | }, 127 | { 128 | "output_type": "stream", 129 | "name": "stderr", 130 | "text": [ 131 | "100%|██████████| 4.54k/4.54k [00:00<00:00, 6.90MB/s]\n" 132 | ] 133 | }, 134 | { 135 | "output_type": "stream", 136 | "name": "stdout", 137 | "text": [ 138 | "Extracting ./data/MNIST/raw/t10k-labels-idx1-ubyte.gz to ./data/MNIST/raw\n", 139 | "\n" 140 | ] 141 | } 142 | ] 143 | }, 144 | { 145 | "cell_type": "code", 146 | "source": [ 147 | "# Visualize the datasets\n", 148 | "def show_images(images, labels, label_header=\"True\"):\n", 149 | " figure = plt.figure(figsize=(10, 10))\n", 150 | " rows, cols = 1, 4\n", 151 | " for i in range(1, rows*cols+1):\n", 152 | " figure.add_subplot(rows, cols, i)\n", 153 | " plt.axis(False)\n", 154 | " plt.title(f\"{label_header}: {labels[i-1].item()}\")\n", 155 | " plt.imshow(images[i-1].permute(1, 2, 0), cmap='gray')\n", 156 | "\n", 157 | " plt.show()\n", 158 | "\n", 159 | "# Get a batch of images and show\n", 160 | "images, labels = next(iter(trainloader))\n", 161 | "show_images(images, labels, label_header=\"Raw\")" 162 | ], 163 | "metadata": { 164 | "colab": { 165 | "base_uri": "https://localhost:8080/", 166 | "height": 227 167 | }, 168 | "id": "WIo50iBS_9x9", 169 | "outputId": "0394f31a-6779-4101-a3ee-9d6229a697c2" 170 | }, 171 | "execution_count": 3, 172 | "outputs": [ 173 | { 174 | "output_type": "display_data", 175 | "data": { 176 | "text/plain": [ 177 | "
" 178 | ], 179 | "image/png": "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\n" 180 | }, 181 | "metadata": {} 182 | } 183 | ] 184 | }, 185 | { 186 | "cell_type": "markdown", 187 | "source": [], 188 | "metadata": { 189 | "id": "mWPjnMrWPm8C" 190 | } 191 | }, 192 | { 193 | "cell_type": "code", 194 | "source": [ 195 | "# Step 3: Preprocessing Step: Normalization and Data Augmentation\n", 196 | "transform_train = transforms.Compose([\n", 197 | " transforms.RandomRotation(10), # Randomly rotate the image by 10 degrees\n", 198 | " transforms.RandomAffine(0, translate=(0.1, 0.1)), # Random translation\n", 199 | " transforms.ToTensor(),\n", 200 | " transforms.Normalize((0.5,), (0.5,)) # Normalize to range [-1, 1]\n", 201 | "])\n", 202 | "\n", 203 | "transform_test = transforms.Compose([\n", 204 | " transforms.ToTensor(),\n", 205 | " transforms.Normalize((0.5,), (0.5,)) # Normalize the same way for test set\n", 206 | "])" 207 | ], 208 | "metadata": { 209 | "id": "vRBLQe78AYkf" 210 | }, 211 | "execution_count": 4, 212 | "outputs": [] 213 | }, 214 | { 215 | "cell_type": "markdown", 216 | "source": [], 217 | "metadata": { 218 | "id": "zcj4_O0YCgja" 219 | } 220 | }, 221 | { 222 | "cell_type": "code", 223 | "source": [ 224 | "# Step 4: Load the MNIST dataset with preprocessing applied\n", 225 | "trainset = torchvision.datasets.MNIST(root='./data', train=True, transform=transform_train)\n", 226 | "trainloader = torch.utils.data.DataLoader(trainset, batch_size=64, shuffle=True)\n", 227 | "\n", 228 | "testset = torchvision.datasets.MNIST(root='./data', train=False, transform=transform_test)\n", 229 | "testloader = torch.utils.data.DataLoader(testset, batch_size=64, shuffle=False)\n", 230 | "\n", 231 | "# Visualize Some Preprocessed Images\n", 232 | "preprocessed_images, preprocessed_labels = next(iter(trainloader))\n", 233 | "show_images(preprocessed_images, preprocessed_labels, label_header=\"Preprocessed\")" 234 | ], 235 | "metadata": { 236 | "colab": { 237 | "base_uri": "https://localhost:8080/", 238 | "height": 227 239 | }, 240 | "id": "EvP-1L6s8pR4", 241 | "outputId": "51cf8b83-e51f-48ac-a264-ad999ac49459" 242 | }, 243 | "execution_count": 5, 244 | "outputs": [ 245 | { 246 | "output_type": "display_data", 247 | "data": { 248 | "text/plain": [ 249 | "
" 250 | ], 251 | "image/png": "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kYmJiTFNmjQx+fn5ld6/rqNO6kadaI4dO2aio6NNz549Pb5vXUOdUCfUSdWok7pZJ/7yMiqfNhu//4iNjTXr1q0rP67si7t//363+z/88MOmUaNG5siRI6agoMDtIywszNx3333lx8bGxpoWLVq4PfGMMWbixIlGRMxPP/3ktqelS5e6HffWW28ZETEffvihW3769GkTERFh0tPTjTHGfPXVV0ZEzLx58xw/72PHjhmXy2WeeeaZCvvOzMw0IlJe8L179zatW7c233//vbpWSUmJCQoKMmlpaeb48ePqMatXrzYiYj766KMK5+vfv7+Jj483xhiTn5+v/uNijDEdOnS44NcOPv3000ZETLNmzUxRUVF5/tlnnxkRMVOmTLmgdesK6qRu1MnvnT9/3gwcONAEBQWZrVu3emXN2ow6oU6ok6pRJ3WzTvyl2fDpNKoXX3xREhISJCAgQGJiYqR9+/YVXmcWEBDg9ho+kV8vz508eVKio6PVdY8cOeL2//Hx8eJyudyyhIQEERHZt2+fXHbZZeV5XFyc23H79+8XEZH27du75UFBQdKmTZvy28suRXbs2NHx8921a5cYY2TatGkybdo0x723bNlSnn76aRk2bJgkJCRIx44dZeDAgTJq1Cjp1KmTiIgEBwfLrFmz5PHHH5eYmBhJSUmRIUOGyF133VX++ezcuVNEfntN5u9FRES4fY7t2rWrcEz79u3dLiF6okGDBiIiMnToUAkLCyvPU1JSJC4uTj799NMLWreuoU70vdeWOvm98ePHy7p16+T111+Xzp07e2XNuoA60fdOneB/USf63mtrnfgLnzYb1157rXTr1q3SY4KDgysUQmlpqURHR8uyZcvU+0RFRV3wnsp+QLahtLRUREQmTJggAwYMUI+Jj48XEZFevXrJ7t275a9//ausX79eXnnlFZk3b5689NJLct9994mIyKOPPipDhw6V9957T3JycmTatGmSlZUlH330kXTp0qX8fG+88YZbYZcJCLD78Ldo0UJERGJiYircFh0dXeFNZdBRJxXVpjr5X5mZmbJo0SJ57rnnZNSoUZfsvLUBdVIRdYLfo04qqq114k9q5Gfdtm1b2bhxo/To0aNaT9KyzvZ/u+zvv/9eRKTKv9JYNv1ix44d0qZNm/L8zJkzsnfvXrnhhhvK9yQi8u2335Znv1d2/8DAQMdj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\n" 252 | }, 253 | "metadata": {} 254 | } 255 | ] 256 | }, 257 | { 258 | "cell_type": "code", 259 | "source": [ 260 | "# Mlp model\n", 261 | "import torch\n", 262 | "import torch.nn as nn\n", 263 | "import torch.optim as optim\n", 264 | "from sklearn.metrics import precision_score, recall_score, f1_score, accuracy_score" 265 | ], 266 | "metadata": { 267 | "id": "UrKMtie6a3u_" 268 | }, 269 | "execution_count": 7, 270 | "outputs": [] 271 | }, 272 | { 273 | "cell_type": "code", 274 | "source": [ 275 | "# Step 1: Define the MLP model\n", 276 | "class MLP(nn.Module):\n", 277 | " def __init__(self):\n", 278 | " super(MLP, self).__init__()\n", 279 | " # Flatten input (28x28) to 784\n", 280 | " self.flatten = nn.Flatten()\n", 281 | " # Define MLP layers\n", 282 | " self.fc1 = nn.Linear(28*28, 256) # First fully connected layer\n", 283 | " self.fc2 = nn.Linear(256, 128) # Second fully connected layer\n", 284 | " self.fc3 = nn.Linear(128, 64) # Third fully connected layer\n", 285 | " self.fc4 = nn.Linear(64, 10) # Output layer (10 classes)\n", 286 | " self.relu = nn.ReLU() # ReLU activation function\n", 287 | "\n", 288 | " def forward(self, x):\n", 289 | " x = self.flatten(x)\n", 290 | " x = self.relu(self.fc1(x))\n", 291 | " x = self.relu(self.fc2(x))\n", 292 | " x = self.relu(self.fc3(x))\n", 293 | " x = self.fc4(x) # No activation in the last layer (we'll use CrossEntropyLoss which combines softmax)\n", 294 | " return x\n", 295 | "\n", 296 | "# Step 2: Initialize model, loss function, and optimizer\n", 297 | "model = MLP()\n", 298 | "criterion = nn.CrossEntropyLoss() # Cross entropy loss combines softmax and loss calculation\n", 299 | "optimizer = optim.Adam(model.parameters(), lr=0.001) # Adam optimizer" 300 | ], 301 | "metadata": { 302 | "id": "PC4jNIEkBOTa" 303 | }, 304 | "execution_count": 8, 305 | "outputs": [] 306 | }, 307 | { 308 | "cell_type": "code", 309 | "source": [ 310 | "# Step 3: Training function\n", 311 | "def train(model, trainloader, criterion, optimizer, epochs=20):\n", 312 | " model.train() # Set the model to training mode\n", 313 | " for epoch in range(epochs):\n", 314 | " running_loss = 0.0\n", 315 | " correct = 0\n", 316 | " total = 0\n", 317 | " for images, labels in trainloader:\n", 318 | " # Zero the parameter gradients\n", 319 | " optimizer.zero_grad()\n", 320 | "\n", 321 | " # Forward pass\n", 322 | " outputs = model(images)\n", 323 | " loss = criterion(outputs, labels)\n", 324 | "\n", 325 | " # Backward pass and optimization\n", 326 | " loss.backward()\n", 327 | " optimizer.step()\n", 328 | "\n", 329 | " # Statistics\n", 330 | " running_loss += loss.item()\n", 331 | " _, predicted = torch.max(outputs.data, 1)\n", 332 | " total += labels.size(0)\n", 333 | " correct += (predicted == labels).sum().item()\n", 334 | "\n", 335 | " # Print statistics\n", 336 | " epoch_loss = running_loss / len(trainloader)\n", 337 | " accuracy = 100 * correct / total\n", 338 | " print(f\"Epoch [{epoch+1}/{epochs}], Loss: {epoch_loss:.4f}, Training Accuracy: {accuracy:.2f}%,\")" 339 | ], 340 | "metadata": { 341 | "id": "Cxy2QhBfbGau" 342 | }, 343 | "execution_count": 9, 344 | "outputs": [] 345 | }, 346 | { 347 | "cell_type": "code", 348 | "source": [ 349 | "# Step 4: Evaluation function\n", 350 | "def evaluate(model, testloader):\n", 351 | " model.eval() # Set the model to evaluation mode\n", 352 | " correct = 0\n", 353 | " total = 0\n", 354 | " all_labels = []\n", 355 | " all_preds = []\n", 356 | " with torch.no_grad(): # Disable gradient calculation for inference\n", 357 | " for images, labels in testloader:\n", 358 | " outputs = model(images)\n", 359 | " _, predicted = torch.max(outputs.data, 1)\n", 360 | " total += labels.size(0)\n", 361 | " correct += (predicted == labels).sum().item()\n", 362 | " all_labels.extend(labels.cpu().numpy()) # Convert lists to numpy arrays\n", 363 | " all_preds.extend(predicted.cpu().numpy())\n", 364 | "\n", 365 | " # Step 5: Compute evaluation metrics\n", 366 | " accuracy = accuracy_score(all_labels, all_preds) * 100\n", 367 | " precision = precision_score(all_labels, all_preds, average=\"weighted\") * 100\n", 368 | " recall = recall_score(all_labels, all_preds, average=\"weighted\") * 100\n", 369 | " f1 = f1_score(all_labels, all_preds, average=\"weighted\") * 100\n", 370 | "\n", 371 | " print(f\"Test Accuracy: {accuracy:.2f}%\")\n", 372 | " print(f\"Precision: {precision:.2f}%\")\n", 373 | " print(f\"Recall: {recall:.2f}%\")\n", 374 | " print(f\"F1 Score: {f1:.2f}%\")\n" 375 | ], 376 | "metadata": { 377 | "id": "2sITakLIbP_E" 378 | }, 379 | "execution_count": 10, 380 | "outputs": [] 381 | }, 382 | { 383 | "cell_type": "code", 384 | "source": [ 385 | "# Step 6: Train the model\n", 386 | "train(model, trainloader, criterion, optimizer, epochs=20)\n", 387 | "\n", 388 | "# Step 7: Evaluate the model on the test set\n", 389 | "evaluate(model, testloader)\n", 390 | "\n", 391 | "# save the model weights\n", 392 | "model_1 = MLP() # Create the model instance\n", 393 | "torch.save(model_1 ,\"mlp_mnist_weights.pth\")\n", 394 | "print(\"Mlp Model weights saved successfully.\")\n" 395 | ], 396 | "metadata": { 397 | "id": "9BkiM-dZbYdN", 398 | "colab": { 399 | "base_uri": "https://localhost:8080/" 400 | }, 401 | "outputId": "1199adc0-b76b-4570-e19a-813740324a6f" 402 | }, 403 | "execution_count": null, 404 | "outputs": [ 405 | { 406 | "output_type": "stream", 407 | "name": "stdout", 408 | "text": [ 409 | "Epoch [1/20], Loss: 0.2570, Training Accuracy: 91.98%,\n", 410 | "Epoch [2/20], Loss: 0.2157, Training Accuracy: 93.15%,\n", 411 | "Epoch [3/20], Loss: 0.1907, Training Accuracy: 93.89%,\n", 412 | "Epoch [4/20], Loss: 0.1749, Training Accuracy: 94.37%,\n", 413 | "Epoch [5/20], Loss: 0.1614, Training Accuracy: 94.88%,\n", 414 | "Epoch [6/20], Loss: 0.1570, Training Accuracy: 94.94%,\n", 415 | "Epoch [7/20], Loss: 0.1452, Training Accuracy: 95.41%,\n", 416 | "Epoch [8/20], Loss: 0.1430, Training Accuracy: 95.53%,\n", 417 | "Epoch [9/20], Loss: 0.1420, Training Accuracy: 95.50%,\n", 418 | "Epoch [10/20], Loss: 0.1297, Training Accuracy: 95.95%,\n", 419 | "Epoch [11/20], Loss: 0.1282, Training Accuracy: 95.88%,\n", 420 | "Epoch [12/20], Loss: 0.1219, Training Accuracy: 96.16%,\n", 421 | "Epoch [13/20], Loss: 0.1207, Training Accuracy: 96.16%,\n", 422 | "Epoch [14/20], Loss: 0.1147, Training Accuracy: 96.30%,\n", 423 | "Epoch [15/20], Loss: 0.1135, Training Accuracy: 96.46%,\n", 424 | "Epoch [16/20], Loss: 0.1135, Training Accuracy: 96.45%,\n", 425 | "Epoch [17/20], Loss: 0.1104, Training Accuracy: 96.53%,\n", 426 | "Epoch [18/20], Loss: 0.1061, Training Accuracy: 96.66%,\n", 427 | "Epoch [19/20], Loss: 0.1059, Training Accuracy: 96.68%,\n", 428 | "Epoch [20/20], Loss: 0.1042, Training Accuracy: 96.61%,\n", 429 | "Test Accuracy: 98.04%\n", 430 | "Precision: 98.05%\n", 431 | "Recall: 98.04%\n", 432 | "F1 Score: 98.04%\n", 433 | "Mlp Model weights saved successfully.\n" 434 | ] 435 | } 436 | ] 437 | }, 438 | { 439 | "cell_type": "code", 440 | "source": [ 441 | "import torch\n", 442 | "import torch.nn as nn\n", 443 | "import torch.optim as optim\n", 444 | "import torch.nn.functional as F\n", 445 | "from sklearn.metrics import accuracy_score, precision_score, recall_score, f1_score\n", 446 | "\n", 447 | "# Define the CNN model\n", 448 | "class CNN(nn.Module):\n", 449 | " def __init__(self):\n", 450 | " super(CNN, self).__init__()\n", 451 | " # Convolutional layer\n", 452 | " # 1 input channel (grayscale), 16 filters, kernel size 3x3, and padding of 1 to maintain size\n", 453 | " self.conv1 = nn.Conv2d(1, 16, kernel_size=3, padding=1)\n", 454 | " # Pooling layer to reduce spatial dimensions\n", 455 | " self.pool = nn.MaxPool2d(2, 2)\n", 456 | " # Fully connected layer\n", 457 | " # Input size is determined by the number of filters (16) and reduced image size (14x14 after pooling)\n", 458 | " self.fc1 = nn.Linear(16 * 14 * 14, 10) # Output is 10 classes (digits 0-9)\n", 459 | "\n", 460 | " def forward(self, x):\n", 461 | " # Apply the convolutional layer followed by ReLU activation and max pooling\n", 462 | " x = self.pool(F.relu(self.conv1(x)))\n", 463 | " # Flatten the output of the convolutional layer to pass it into the fully connected layer\n", 464 | " x = x.view(-1, 16 * 14 * 14)\n", 465 | " # Apply the fully connected layer\n", 466 | " x = self.fc1(x)\n", 467 | " return x\n", 468 | "\n", 469 | "# Initialize the model, loss function, and optimizer\n", 470 | "cnn_model = CNN()\n", 471 | "criterion = nn.CrossEntropyLoss() # Cross entropy for classification\n", 472 | "optimizer = optim.Adam(cnn_model.parameters(), lr=0.001) # Adam optimizer\n" 473 | ], 474 | "metadata": { 475 | "id": "irJIYVGWnehr" 476 | }, 477 | "execution_count": 11, 478 | "outputs": [] 479 | }, 480 | { 481 | "cell_type": "code", 482 | "source": [ 483 | "# Training function\n", 484 | "def train_cnn(model, trainloader, criterion, optimizer, epochs=20):\n", 485 | " model.train() # Set the model to training mode\n", 486 | " for epoch in range(epochs):\n", 487 | " running_loss = 0.0\n", 488 | " correct = 0\n", 489 | " total = 0\n", 490 | " for images, labels in trainloader:\n", 491 | " # Zero the gradients from the previous step\n", 492 | " optimizer.zero_grad()\n", 493 | " # Forward pass: compute predictions\n", 494 | " outputs = model(images)\n", 495 | " # Compute loss\n", 496 | " loss = criterion(outputs, labels)\n", 497 | " # Backward pass: compute gradients\n", 498 | " loss.backward()\n", 499 | " # Update the model parameters\n", 500 | " optimizer.step()\n", 501 | "\n", 502 | " # Track loss and accuracy\n", 503 | " running_loss += loss.item()\n", 504 | " _, predicted = torch.max(outputs.data, 1)\n", 505 | " total += labels.size(0)\n", 506 | " correct += (predicted == labels).sum().item()\n", 507 | "\n", 508 | " # Calculate epoch loss and accuracy\n", 509 | " epoch_loss = running_loss / len(trainloader)\n", 510 | " accuracy = 100 * correct / total\n", 511 | " print(f\"Epoch [{epoch+1}/{epochs}], Loss: {epoch_loss:.4f}, Training Accuracy: {accuracy:.2f}%\")" 512 | ], 513 | "metadata": { 514 | "id": "lXh5l0Ivn2dq" 515 | }, 516 | "execution_count": 12, 517 | "outputs": [] 518 | }, 519 | { 520 | "cell_type": "code", 521 | "source": [ 522 | "# Evaluation function\n", 523 | "def evaluate_cnn(model, testloader):\n", 524 | " model.eval() # Set the model to evaluation mode\n", 525 | " correct = 0\n", 526 | " total = 0\n", 527 | " all_labels = []\n", 528 | " all_preds = []\n", 529 | " with torch.no_grad(): # Disable gradient calculation for inference\n", 530 | " for images, labels in testloader:\n", 531 | " outputs = model(images)\n", 532 | " _, predicted = torch.max(outputs.data, 1)\n", 533 | " total += labels.size(0)\n", 534 | " correct += (predicted == labels).sum().item()\n", 535 | " all_labels.extend(labels.cpu().numpy())\n", 536 | " all_preds.extend(predicted.cpu().numpy())\n", 537 | "\n", 538 | " # Calculate evaluation metrics\n", 539 | " accuracy = accuracy_score(all_labels, all_preds) * 100\n", 540 | " precision = precision_score(all_labels, all_preds, average=\"weighted\") * 100\n", 541 | " recall = recall_score(all_labels, all_preds, average=\"weighted\") * 100\n", 542 | " f1 = f1_score(all_labels, all_preds, average=\"weighted\") * 100\n", 543 | "\n", 544 | " print(f\"Test Accuracy: {accuracy:.2f}%\")\n", 545 | " print(f\"Precision: {precision:.2f}%\")\n", 546 | " print(f\"Recall: {recall:.2f}%\")\n", 547 | " print(f\"F1 Score: {f1:.2f}%\")" 548 | ], 549 | "metadata": { 550 | "id": "617Edf7un8dR" 551 | }, 552 | "execution_count": 13, 553 | "outputs": [] 554 | }, 555 | { 556 | "cell_type": "code", 557 | "source": [ 558 | "# Train the CNN model\n", 559 | "train_cnn(cnn_model, trainloader, criterion, optimizer, epochs=20)\n", 560 | "\n", 561 | "# Evaluate the CNN model on the test set\n", 562 | "evaluate_cnn(cnn_model, testloader)\n", 563 | "\n", 564 | "# save the model weights\n", 565 | "model_2 = CNN() # Create the model instance\n", 566 | "torch.save(model_2 ,\"cnn_mnist_weights.pth\")\n", 567 | "print(\"Cnn Model weights saved successfully.\")" 568 | ], 569 | "metadata": { 570 | "colab": { 571 | "base_uri": "https://localhost:8080/" 572 | }, 573 | "id": "k8zRVNypirA6", 574 | "outputId": "119f2502-c164-45e3-afdf-f1a0378f3d9f" 575 | }, 576 | "execution_count": null, 577 | "outputs": [ 578 | { 579 | "output_type": "stream", 580 | "name": "stdout", 581 | "text": [ 582 | "Epoch [1/20], Loss: 0.5278, Training Accuracy: 84.32%\n", 583 | "Epoch [2/20], Loss: 0.2757, Training Accuracy: 91.60%\n", 584 | "Epoch [3/20], Loss: 0.2459, Training Accuracy: 92.52%\n", 585 | "Epoch [4/20], Loss: 0.2295, Training Accuracy: 92.91%\n", 586 | "Epoch [5/20], Loss: 0.2183, Training Accuracy: 93.30%\n", 587 | "Epoch [6/20], Loss: 0.2096, Training Accuracy: 93.71%\n", 588 | "Epoch [7/20], Loss: 0.2002, Training Accuracy: 94.01%\n", 589 | "Epoch [8/20], Loss: 0.1930, Training Accuracy: 94.20%\n", 590 | "Epoch [9/20], Loss: 0.1882, Training Accuracy: 94.36%\n", 591 | "Epoch [10/20], Loss: 0.1815, Training Accuracy: 94.48%\n", 592 | "Epoch [11/20], Loss: 0.1784, Training Accuracy: 94.58%\n", 593 | "Epoch [12/20], Loss: 0.1729, Training Accuracy: 94.77%\n", 594 | "Epoch [13/20], Loss: 0.1694, Training Accuracy: 94.91%\n", 595 | "Epoch [14/20], Loss: 0.1637, Training Accuracy: 95.01%\n", 596 | "Epoch [15/20], Loss: 0.1611, Training Accuracy: 95.12%\n", 597 | "Epoch [16/20], Loss: 0.1570, Training Accuracy: 95.22%\n", 598 | "Epoch [17/20], Loss: 0.1554, Training Accuracy: 95.34%\n", 599 | "Epoch [18/20], Loss: 0.1544, Training Accuracy: 95.44%\n", 600 | "Epoch [19/20], Loss: 0.1536, Training Accuracy: 95.42%\n", 601 | "Epoch [20/20], Loss: 0.1475, Training Accuracy: 95.50%\n", 602 | "Test Accuracy: 98.07%\n", 603 | "Precision: 98.08%\n", 604 | "Recall: 98.07%\n", 605 | "F1 Score: 98.07%\n", 606 | "Cnn Model weights saved successfully.\n" 607 | ] 608 | } 609 | ] 610 | }, 611 | { 612 | "cell_type": "code", 613 | "source": [ 614 | "#import necessary libraries\n", 615 | "import torch\n", 616 | "import torch.nn as nn\n", 617 | "import torch.optim as optim\n", 618 | "import torch.nn.functional as F\n", 619 | "from sklearn.metrics import accuracy_score, precision_score, recall_score, f1_score" 620 | ], 621 | "metadata": { 622 | "id": "1iRuhgzsm5-e" 623 | }, 624 | "execution_count": 14, 625 | "outputs": [] 626 | }, 627 | { 628 | "cell_type": "code", 629 | "source": [ 630 | "class LeNet5(nn.Module):\n", 631 | " def __init__(self):\n", 632 | " super(LeNet5, self).__init__()\n", 633 | " # Convolutional and pooling layers\n", 634 | " self.conv1 = nn.Conv2d(1, 6, kernel_size=5, stride=1, padding=2) # Input: 28x28, Output: 28x28\n", 635 | " self.pool1 = nn.AvgPool2d(kernel_size=2, stride=2) # Input: 28x28, Output: 14x14\n", 636 | " self.conv2 = nn.Conv2d(6, 16, kernel_size=5, stride=1) # Input: 14x14, Output: 10x10\n", 637 | " self.pool2 = nn.AvgPool2d(kernel_size=2, stride=2) # Input: 10x10, Output: 5x5\n", 638 | "\n", 639 | " # Fully connected layers\n", 640 | " self.fc1 = nn.Linear(16 * 5 * 5, 120) # Flattened to 16x5x5, Output: 120\n", 641 | " self.fc2 = nn.Linear(120, 84) # Output: 84\n", 642 | " self.fc3 = nn.Linear(84, 10) # Output: 10 (for 10 digits)\n", 643 | "\n", 644 | " def forward(self, x):\n", 645 | " x = F.relu(self.conv1(x))\n", 646 | " x = self.pool1(x)\n", 647 | " x = F.relu(self.conv2(x))\n", 648 | " x = self.pool2(x)\n", 649 | " x = x.view(-1, 16 * 5 * 5) # Flatten the tensor\n", 650 | " x = F.relu(self.fc1(x))\n", 651 | " x = F.relu(self.fc2(x))\n", 652 | " x = self.fc3(x) # No activation on the final layer\n", 653 | " return x\n" 654 | ], 655 | "metadata": { 656 | "id": "dG0fqaxjnB0o" 657 | }, 658 | "execution_count": 15, 659 | "outputs": [] 660 | }, 661 | { 662 | "cell_type": "code", 663 | "source": [ 664 | "# Initialize LeNet-5 model\n", 665 | "model_3 = LeNet5()\n", 666 | "criterion = nn.CrossEntropyLoss() # Cross entropy loss for multi-class classification\n", 667 | "optimizer = optim.Adam(model_3.parameters(), lr=0.001) # Adam optimizer\n", 668 | "\n", 669 | "# Training function\n", 670 | "def train_lenet5(model, trainloader, criterion, optimizer, epochs=20):\n", 671 | " model.train() # Set the model to training mode\n", 672 | " for epoch in range(epochs):\n", 673 | " running_loss = 0.0\n", 674 | " correct = 0\n", 675 | " total = 0\n", 676 | " for images, labels in trainloader:\n", 677 | " optimizer.zero_grad() # Zero the parameter gradients\n", 678 | " outputs = model(images) # Forward pass\n", 679 | " loss = criterion(outputs, labels)\n", 680 | " loss.backward() # Backward pass and optimization\n", 681 | " optimizer.step()\n", 682 | " running_loss += loss.item() # Statistics\n", 683 | " _, predicted = torch.max(outputs.data, 1)\n", 684 | " total += labels.size(0)\n", 685 | " correct += (predicted == labels).sum().item()\n", 686 | "\n", 687 | "\n", 688 | "\n", 689 | " # Print statistics\n", 690 | " epoch_loss = running_loss / len(trainloader)\n", 691 | " accuracy = 100 * correct / total\n", 692 | " print(f\"Epoch [{epoch+1}/{epochs}], Loss: {epoch_loss:.4f}, Training Accuracy: {accuracy:.2f}%\")\n" 693 | ], 694 | "metadata": { 695 | "id": "KEeO84lPnLyq" 696 | }, 697 | "execution_count": 16, 698 | "outputs": [] 699 | }, 700 | { 701 | "cell_type": "code", 702 | "source": [ 703 | "# Evaluation function\n", 704 | "def evaluate_lenet5(model, testloader):\n", 705 | " model.eval() # Set the model to evaluation mode\n", 706 | " correct = 0\n", 707 | " total = 0\n", 708 | " all_labels = []\n", 709 | " all_preds = []\n", 710 | " with torch.no_grad(): # Disable gradient calculation for inference\n", 711 | " for images, labels in testloader:\n", 712 | " outputs = model(images)\n", 713 | " _, predicted = torch.max(outputs.data, 1)\n", 714 | " total += labels.size(0)\n", 715 | " correct += (predicted == labels).sum().item()\n", 716 | " all_labels.extend(labels.cpu().numpy()) # Convert lists to numpy arrays\n", 717 | " all_preds.extend(predicted.cpu().numpy())\n", 718 | "\n", 719 | " # Compute evaluation metrics\n", 720 | " accuracy = accuracy_score(all_labels, all_preds) * 100\n", 721 | " precision = precision_score(all_labels, all_preds, average=\"weighted\") * 100\n", 722 | " recall = recall_score(all_labels, all_preds, average=\"weighted\") * 100\n", 723 | " f1 = f1_score(all_labels, all_preds, average=\"weighted\") * 100\n", 724 | "\n", 725 | " print(f\"Test Accuracy: {accuracy:.2f}%\")\n", 726 | " print(f\"Precision: {precision:.2f}%\")\n", 727 | " print(f\"Recall: {recall:.2f}%\")\n", 728 | " print(f\"F1 Score: {f1:.2f}%\")\n" 729 | ], 730 | "metadata": { 731 | "id": "ohO1mFbnnTyv" 732 | }, 733 | "execution_count": 17, 734 | "outputs": [] 735 | }, 736 | { 737 | "cell_type": "code", 738 | "source": [ 739 | "# Train the LeNet-5 model\n", 740 | "train_lenet5(model_3, trainloader, criterion, optimizer, epochs=20)\n", 741 | "\n", 742 | "# Evaluate the LeNet-5 model on the test set\n", 743 | "evaluate_lenet5(model_3, testloader)\n", 744 | "\n", 745 | "torch.save(model_3.state_dict(), \"lenet5_weights.pth\")\n", 746 | "print(\"Lenet5 Model weights saved successfully.\")" 747 | ], 748 | "metadata": { 749 | "colab": { 750 | "base_uri": "https://localhost:8080/" 751 | }, 752 | "id": "LEu1Ro1LYp9U", 753 | "outputId": "1ac083df-e612-404b-b3eb-e1a557dc5779" 754 | }, 755 | "execution_count": null, 756 | "outputs": [ 757 | { 758 | "output_type": "stream", 759 | "name": "stdout", 760 | "text": [ 761 | "Epoch [1/20], Loss: 0.0332, Training Accuracy: 98.94%\n", 762 | "Epoch [2/20], Loss: 0.0320, Training Accuracy: 98.97%\n", 763 | "Epoch [3/20], Loss: 0.0325, Training Accuracy: 98.95%\n", 764 | "Epoch [4/20], Loss: 0.0326, Training Accuracy: 98.93%\n", 765 | "Epoch [5/20], Loss: 0.0300, Training Accuracy: 99.10%\n", 766 | "Epoch [6/20], Loss: 0.0310, Training Accuracy: 99.02%\n", 767 | "Epoch [7/20], Loss: 0.0308, Training Accuracy: 99.00%\n", 768 | "Epoch [8/20], Loss: 0.0309, Training Accuracy: 99.04%\n", 769 | "Epoch [9/20], Loss: 0.0285, Training Accuracy: 99.12%\n", 770 | "Epoch [10/20], Loss: 0.0286, Training Accuracy: 99.11%\n", 771 | "Epoch [11/20], Loss: 0.0282, Training Accuracy: 99.11%\n", 772 | "Epoch [12/20], Loss: 0.0285, Training Accuracy: 99.10%\n", 773 | "Epoch [13/20], Loss: 0.0268, Training Accuracy: 99.16%\n", 774 | "Epoch [14/20], Loss: 0.0265, Training Accuracy: 99.13%\n", 775 | "Epoch [15/20], Loss: 0.0269, Training Accuracy: 99.15%\n", 776 | "Epoch [16/20], Loss: 0.0266, Training Accuracy: 99.15%\n", 777 | "Epoch [17/20], Loss: 0.0257, Training Accuracy: 99.16%\n", 778 | "Epoch [18/20], Loss: 0.0253, Training Accuracy: 99.21%\n", 779 | "Epoch [19/20], Loss: 0.0261, Training Accuracy: 99.12%\n", 780 | "Epoch [20/20], Loss: 0.0227, Training Accuracy: 99.28%\n", 781 | "Test Accuracy: 99.30%\n", 782 | "Precision: 99.30%\n", 783 | "Recall: 99.30%\n", 784 | "F1 Score: 99.30%\n", 785 | "Lenet5 Model weights saved successfully.\n" 786 | ] 787 | } 788 | ] 789 | }, 790 | { 791 | "cell_type": "code", 792 | "source": [ 793 | "import matplotlib.pyplot as plt\n", 794 | "import numpy as np\n", 795 | "\n", 796 | "def visualize_sample_image(model, testloader):\n", 797 | " # Set the model to evaluation mode\n", 798 | " model.eval()\n", 799 | "\n", 800 | " # Get a single batch of data from the testloader\n", 801 | " images, labels = next(iter(testloader))\n", 802 | "\n", 803 | " # Ensure images and labels are on the CPU\n", 804 | " images, labels = images.cpu(), labels.cpu()\n", 805 | "\n", 806 | " # Get the model's prediction for the first image in the batch\n", 807 | " outputs = model(images)\n", 808 | " _, predicted = torch.max(outputs, 1)\n", 809 | "\n", 810 | " # Select the first image in the batch\n", 811 | " image = images[0] # The first image in the batch\n", 812 | " true_label = labels[0].item() # Get the true label (first element in the batch)\n", 813 | " pred_label = predicted[0].item() # Get the predicted label (first element in the batch)\n", 814 | "\n", 815 | " # Convert the image from PyTorch tensor to NumPy array for visualization\n", 816 | " image = image.numpy() # Convert to numpy array (channel, height, width)\n", 817 | "\n", 818 | " # Handle grayscale image (LeNet input is typically grayscale, so we use the first channel)\n", 819 | " image = image[0] # We only need the first channel (grayscale image)\n", 820 | "\n", 821 | " # Plot the image and display the true and predicted labels\n", 822 | " plt.imshow(image, cmap='gray') # Display in grayscale\n", 823 | " plt.title(f\"True Label: {true_label}, Predicted: {pred_label}\")\n", 824 | " plt.axis('off') # Hide axis\n", 825 | " plt.show()\n", 826 | "\n", 827 | "# Visualize a sample image\n", 828 | "visualize_sample_image(model_3, testloader)\n" 829 | ], 830 | "metadata": { 831 | "colab": { 832 | "base_uri": "https://localhost:8080/", 833 | "height": 428 834 | }, 835 | "id": "JZ4GB5UWotv4", 836 | "outputId": "88466296-6128-48fd-948b-f4ba3896c029" 837 | }, 838 | "execution_count": 35, 839 | "outputs": [ 840 | { 841 | "output_type": "display_data", 842 | "data": { 843 | "text/plain": [ 844 | "
" 845 | ], 846 | "image/png": "iVBORw0KGgoAAAANSUhEUgAAAYUAAAGbCAYAAAAr/4yjAAAAOXRFWHRTb2Z0d2FyZQBNYXRwbG90bGliIHZlcnNpb24zLjguMCwgaHR0cHM6Ly9tYXRwbG90bGliLm9yZy81sbWrAAAACXBIWXMAAA9hAAAPYQGoP6dpAAAVnklEQVR4nO3ce5CVdf3A8c8GyM0bCIqhAgIa5a3Iy6gIJioqYwpElCbYqJlkOiYmNf6EEafRnDLNvMwUplKmEg1TmhBq/gHoaA0ghgJC3lBAwFDcBPb7+8PhMy67wJ6FZU1erxlmPIfn85wvZ/G8z3POw1NVSikBABHxmeZeAACfHKIAQBIFAJIoAJBEAYAkCgAkUQAgiQIASRQASKLADjNu3LioqqqKlStX7rB9jho1Krp3777D9vdpcO+990ZVVVUsXbo07xswYEAMGDCg2da0ufrWyP8GUWgiVVVVDfr11FNPNes6BwwYEIcddlizrqGpPPXUU1t97m+88cZG7bd79+619rPvvvtGv379YsqUKTv4T9C01q1bF+PGjWv2v4P12drP7dRTT23u5X2qtWzuBXxa3X///bVu33fffTF9+vQ69/fp02dnLmuX0qdPnzrPd8RHP5tp06bFaaed1uh9H3XUUfGDH/wgIiLefPPNuPvuu2PIkCFx5513xqWXXtro/TbWtGnTKp5Zt25djB8/PiLiE3WUEVH3/5+IiOeeey5+8YtfbNfPjW0ThSZy/vnn17o9e/bsmD59ep37N7du3bpo165dUy5tl7HffvvV+3yPHz8+evfuHUcffXSj9921a9da+77ggguiV69e8fOf/3yLUdiwYUPU1NTEbrvt1ujH3ZKm2Gdzqu/ntunI7xvf+EYzrGjX4eOjZrTpo5vnn38+TjrppGjXrl386Ec/ioiPDp/HjRtXZ6Z79+4xatSoWvetWbMmrrzyyjjwwAOjdevW0atXr7jpppuipqZmh6xz7ty5MWrUqDj44IOjTZs20aVLl/j2t78d77zzTr3br1y5MoYPHx577rln7LPPPnHFFVdEdXV1ne0eeOCB6Nu3b7Rt2zY6duwYI0aMiNdee22b61m2bFksWLAg1q9fX/Gf5dlnn41FixbFeeedV/Hs1nTp0iX69OkTS5YsiYiIpUuXRlVVVdxyyy1x6623Rs+ePaN169bx4osvRkTEggULYtiwYdGxY8do06ZNfPnLX46pU6fW2e/8+fPjK1/5SrRt2zYOOOCAmDBhQr0/1/q+U6iuro5x48bFIYccEm3atIn9998/hgwZEosXL46lS5dG586dI+KjSG76aObjf+d29BrffffdWLBgQbz77rsNfl43+e9//xuTJ0+O/v37xwEHHFDxPA3nSKGZvfPOO3HGGWfEiBEj4vzzz4/99tuvovl169ZF//7944033ojvfOc7cdBBB8XMmTNj7NixsWzZsrj11lu3e43Tp0+PV155JS688MLo0qVLzJ8/P+65556YP39+zJ49O6qqqmptP3z48OjevXv85Cc/idmzZ8dtt90Wq1evjvvuuy+3ufHGG+O6666L4cOHx0UXXRQrVqyI22+/PU466aT45z//GXvvvfcW1zN27Nj47W9/G0uWLKn4S+hJkyZFROzwKKxfvz5ee+212GeffWrdP3HixKiuro5LLrkkWrduHR07doz58+fHCSecEF27do1rr7022rdvHw899FCcc845MXny5Dj33HMjIuKtt96Kk08+OTZs2JDb3XPPPdG2bdttrmfjxo0xePDgmDFjRowYMSKuuOKKWLt2bUyfPj1eeOGFGDhwYNx5553x3e9+N84999wYMmRIREQcccQRERFNssYpU6bEhRdeGBMnTqzzxmZbHn300VizZs0O/7lRj8JOMXr06LL5092/f/8SEeWuu+6qs31ElOuvv77O/d26dSsjR47M2zfccENp3759efnll2ttd+2115YWLVqUV199davr6t+/f/nCF76w1W3WrVtX577f//73JSLK008/nfddf/31JSLK2WefXWvbyy67rEREmTNnTimllKVLl5YWLVqUG2+8sdZ28+bNKy1btqx1/8iRI0u3bt1qbTdy5MgSEWXJkiVbXffmNmzYUPbbb79yzDHHVDS3uW7dupXTTjutrFixoqxYsaLMmTOnjBgxokREufzyy0sppSxZsqRERNlzzz3L8uXLa82fcsop5fDDDy/V1dV5X01NTTn++ONL7969874rr7yyRER55pln8r7ly5eXvfbaq86fv3///qV///55+ze/+U2JiPKzn/2szvprampKKaWsWLFii3/PmmKNEydOLBFRJk6cWOfxtmXo0KGldevWZfXq1RXPUhkfHzWz1q1bx4UXXtjo+Ycffjj69esXHTp0iJUrV+avgQMHxsaNG+Ppp5/e7jV+/F1fdXV1rFy5Mo477riIiPjHP/5RZ/vRo0fXun355ZdHxEfv9iIi/vjHP0ZNTU0MHz681pq7dOkSvXv3jieffHKr67n33nujlFLxUcKMGTPi7bff3iHvNqdNmxadO3eOzp07x5FHHhkPP/xwfOtb34qbbrqp1nZDhw7Nj2kiIlatWhVPPPFEDB8+PNauXZt/9nfeeSdOP/30WLhwYbzxxhsR8dHzddxxx8UxxxyT8507d27Q+idPnhydOnXK5/7jNj+y21xTrXHUqFFRSqn4KOE///lP/OUvf4kzzzxzq0eQ7Bg+PmpmXbt23a4vCRcuXBhz586t9cLzccuXL2/0vjdZtWpVjB8/Ph588ME6+6vv8+HevXvXut2zZ8/4zGc+k+esL1y4MEopdbbbpFWrVtu95vpMmjQpWrRoEV//+te3e1/HHntsTJgwIaqqqqJdu3bRp0+fel+wevToUev2okWLopQS1113XVx33XX17nv58uXRtWvX+Pe//x3HHntsnd8/9NBDt7m+xYsXx6GHHhotW1b+v/jOWmNDTZ48Oaqrq310tJOIQjNryOfDH7dx48Zat2tqauLUU0+Na665pt7tDznkkEavbZPhw4fHzJkzY8yYMXHUUUfF7rvvHjU1NTFo0KAGfZm9+TvTmpqaqKqqisceeyxatGhRZ/vdd999u9e8uQ8++CCmTJkSAwcOrPh7m/p06tQpBg4cuM3tNv/5bnq+rr766jj99NPrnenVq9d2r297fNLWOGnSpNhrr71i8ODBO+0xd2Wi8AnVoUOHWLNmTa37Pvzww1i2bFmt+3r27Bnvvfdeg16gGmP16tUxY8aMGD9+fPzf//1f3r9w4cItzixcuLDWO+RFixZFTU1NftzTs2fPKKVEjx49dki0GmLq1Kmxdu3aZn+3efDBB0fER0dD2/qZdevWrd7n+aWXXtrm4/Ts2TOeeeaZWL9+/RaPvLb0MdLOWmNDLFu2LJ588skYNWpUtG7deofsk63zncInVM+ePet8H3DPPffUOVIYPnx4zJo1Kx5//PE6+1izZk1s2LBhu9ax6Z18KaXW/Vs7q+mOO+6odfv222+PiIgzzjgjIiKGDBkSLVq0iPHjx9fZbylli6e6btKYU1J/97vfRbt27fKsmeay7777xoABA+Luu++uE/iIiBUrVuR/n3nmmTF79ux49tlna/3+pjOotmbo0KGxcuXK+OUvf1nn9zY955v+Pczmbz6aao2NOSX1wQcfjJqammaP+a7EkcIn1EUXXRSXXnppDB06NE499dSYM2dOPP7449GpU6da240ZMyamTp0agwcPjlGjRkXfvn3j/fffj3nz5sUjjzwSS5curTOzuRUrVsSECRPq3N+jR48477zz4qSTToqbb7451q9fH127do1p06bl+fj1WbJkSZx99tkxaNCgmDVrVjzwwAPxzW9+M4488siI+Ch4EyZMiLFjx8bSpUvjnHPOiT322COWLFkSU6ZMiUsuuSSuvvrqLe6/0lNSV61aFY899lgMHTp0ix9NLV26NHr06BEjR46Me++9d5v73B533HFHnHjiiXH44YfHxRdfHAcffHC8/fbbMWvWrHj99ddjzpw5ERFxzTXXxP333x+DBg2KK664Ik/37NatW8ydO3erj3HBBRfEfffdF1dddVU8++yz0a9fv3j//ffjb3/7W1x22WXx1a9+Ndq2bRuf//zn4w9/+EMccsgh0bFjxzjssMPisMMOa5I1NuaU1EmTJsVnP/vZT9y/uP5Ua67TnnY1WzoldUung27cuLH88Ic/LJ06dSrt2rUrp59+elm0aFGdU1JLKWXt2rVl7NixpVevXmW33XYrnTp1Kscff3y55ZZbyocffrjVdW06Lba+X6ecckoppZTXX3+9nHvuuWXvvfcue+21V/na175W3nzzzTqnM246JfXFF18sw4YNK3vssUfp0KFD+d73vlc++OCDOo89efLkcuKJJ5b27duX9u3bl8997nNl9OjR5aWXXsptdsQpqXfddVeJiDJ16tQtbjNv3rwSEeXaa6/d5v66detWzjrrrK1us+mU1J/+9Kf1/v7ixYvLBRdcULp06VJatWpVunbtWgYPHlweeeSRWtvNnTu39O/fv7Rp06Z07dq13HDDDeXXv/71Nk9JLeWjU4l//OMflx49epRWrVqVLl26lGHDhpXFixfnNjNnzix9+/Ytu+22W52f545eY6WnpC5YsKBERLnqqqsatD07RlUpmx2/wy7oV7/6VVxzzTWxePHiHfJFNPyv8p0CRMSTTz4Z3//+9wWBXZ4jBQCSIwUAkigAkEQBgCQKAKQG/+O1bV1ZEYBPtoacV+RIAYAkCgAkUQAgiQIASRQASKIAQBIF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\n" 847 | }, 848 | "metadata": {} 849 | } 850 | ] 851 | } 852 | ] 853 | } -------------------------------------------------------------------------------- /Loading and preprocessing.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "nbformat": 4, 3 | "nbformat_minor": 0, 4 | "metadata": { 5 | "colab": { 6 | "provenance": [] 7 | }, 8 | "kernelspec": { 9 | "name": "python3", 10 | "display_name": "Python 3" 11 | }, 12 | "language_info": { 13 | "name": "python" 14 | } 15 | }, 16 | "cells": [ 17 | { 18 | "cell_type": "code", 19 | "source": [ 20 | "#import necessary libraries\n", 21 | "import torch\n", 22 | "import torchvision\n", 23 | "import torchvision.transforms as transforms\n", 24 | "import matplotlib.pyplot as plt" 25 | ], 26 | "metadata": { 27 | "id": "_jO-FK2h_9bB" 28 | }, 29 | "execution_count": 16, 30 | "outputs": [] 31 | }, 32 | { 33 | "cell_type": "code", 34 | "source": [ 35 | "# Step 1: Download the MNIST dataset\n", 36 | "torchvision.datasets.MNIST(root='./data', train=True, download=True)\n", 37 | "torchvision.datasets.MNIST(root='./data', train=False, download=True)\n", 38 | "\n", 39 | "# Step 2: Load the raw MNIST dataset\n", 40 | "trainset = torchvision.datasets.MNIST(root='./data', train=True, download=True, transform=transforms.ToTensor())\n", 41 | "trainloader = torch.utils.data.DataLoader(trainset, batch_size=64, shuffle=True)" 42 | ], 43 | "metadata": { 44 | "id": "DUhp37Xx_9lW" 45 | }, 46 | "execution_count": 17, 47 | "outputs": [] 48 | }, 49 | { 50 | "cell_type": "code", 51 | "source": [ 52 | "# Visualize the datasets\n", 53 | "def show_images(images, labels, label_header=\"True\"):\n", 54 | " figure = plt.figure(figsize=(10, 10))\n", 55 | " rows, cols = 3, 4\n", 56 | " for i in range(1, rows*cols+1):\n", 57 | " figure.add_subplot(rows, cols, i)\n", 58 | " plt.axis(False)\n", 59 | " plt.title(f\"{label_header}: {labels[i-1].item()}\")\n", 60 | " plt.imshow(images[i-1].permute(1, 2, 0), cmap='gray')\n", 61 | "\n", 62 | " plt.show()\n", 63 | "\n", 64 | "# Get a batch of images and show\n", 65 | "images, labels = next(iter(trainloader))\n", 66 | "show_images(images, labels, label_header=\"Raw\")" 67 | ], 68 | "metadata": { 69 | "colab": { 70 | "base_uri": "https://localhost:8080/", 71 | "height": 771 72 | }, 73 | "id": "WIo50iBS_9x9", 74 | "outputId": "97469e0d-469d-4ccd-ee6d-914b59a367aa" 75 | }, 76 | "execution_count": 18, 77 | "outputs": [ 78 | { 79 | "output_type": "display_data", 80 | "data": { 81 | "text/plain": [ 82 | "
" 83 | ], 84 | "image/png": "iVBORw0KGgoAAAANSUhEUgAAAxsAAALyCAYAAACy4sk3AAAAOXRFWHRTb2Z0d2FyZQBNYXRwbG90bGliIHZlcnNpb24zLjcuMSwgaHR0cHM6Ly9tYXRwbG90bGliLm9yZy/bCgiHAAAACXBIWXMAAA9hAAAPYQGoP6dpAABV90lEQVR4nO3deZyWZb0/8O+wb+aChApI7opKriTaqKVICSIumXIOSafU1MyOmrvmBqZletTcwqUklyI9crTMJc1xyQKOegzR45bgCm4oLixz//7o5xzJ64Z5xudinhne79eLP/zM81z39YzPxfCZm/lSVxRFEQAAAFXWobU3AAAAtE/KBgAAkIWyAQAAZKFsAAAAWSgbAABAFsoGAACQhbIBAABkoWwAAABZKBsAAEAWygYAAJCFsvEx11xzTdTV1TX96tSpU/Tr1y/GjRsXL774YmtvL2nmzJlx7LHHxhZbbBErrbRSrLnmmjFixIiYOnVqa2+NdsxZgWVri+ckIqKxsTHOPffcWGeddaJbt24xePDguP7661t7W7RTbfWcvPzyy3HwwQfHOuusE927d4/11lsvjjrqqHj99ddbe2s1p1Nrb6AWnXHGGbHOOuvEBx98EH/+85/jmmuuifvvvz8ef/zx6NatW2tvbwkTJ06MK6+8MvbZZ5847LDD4u23347LL788tttuu7j99ttj1113be0t0o45K7BsbemcREScdNJJ8aMf/SgOOuig2HbbbeOWW26JMWPGRF1dXey///6tvT3aqbZ0Tt59990YOnRozJ8/Pw477LAYMGBAPProo3HxxRfHPffcE9OmTYsOHXw/v0lBk6uvvrqIiOKvf/3rEvlxxx1XRERx4403ttLOyk2dOrV45513lsjmzp1b9OnTp9hhhx1aaVe0d84KLFtbPCezZ88uOnfuXBx++OFNWWNjY1FfX1/079+/WLRoUSvujvaoLZ6TX/3qV0VEFLfeeusS+amnnlpERDF9+vRW2lltUruaob6+PiIinnnmmaZswYIFceqpp8bWW28dK6+8cvTs2TPq6+vjnnvuWeK5W221Vey9995LZJtvvnnU1dXFY4891pTdeOONUVdXF0888UTTtT5+vTJbb7119OrVa4msd+/eUV9f37QWLC/OCixbLZ+TW265JRYuXBiHHXZYU1ZXVxeHHnpozJ49Ox566KHKXzC0QC2fk3nz5kVERN++fZfI11xzzYiI6N69e3Nf5gpB2WiG559/PiIiVl111aZs3rx5MXHixNh5553jnHPOidNOOy3mzJkTw4cPj0ceeaTpcfX19XH//fc3/fcbb7wRf/vb36JDhw7R0NDQlDc0NESfPn1ik002iYiIXXbZJXbZZZcW7/mVV16J1VdfvcXPh5ZwVmDZavmc/Pd//3f07Nmz6XkfGTJkSNPHYXmo5XOy4447RocOHeLII4+MP//5zzF79uz43e9+F+PHj4/Ro0fHxhtv/ClffTvT2rdWaslHt/LuuuuuYs6cOcWsWbOKyZMnF3369Cm6du1azJo1q+mxixYtKj788MMlnv/mm28Wffv2Lf7t3/6tKfvNb35TREQxY8aMoiiKYsqUKUXXrl2LUaNGFV//+tebHjd48OBir732avrvgQMHFgMHDmzR67jvvvuKurq64pRTTmnR82FZnBVYtrZ4TkaMGFGsu+66n8jnz59fRERx/PHHN/v1Q3O0xXNSFEUxceLEYpVVVikiounXgQceWCxcuLAln4Z2zQ+IJ/zzD4p+7nOfi0mTJkX//v2bso4dO0bHjh0j4h+TO956661obGyMbbbZJqZPn970uI9uA953332xySabRENDQ2y77bYxbNiwOPvssyMi4q233orHH388xo0b1/S8jxp9pV577bUYM2ZMrLPOOnHssce2aA1oLmcFlq0tnZP3338/unbt+on8ox/Qff/995u1DlSqLZ2TiIh+/frFkCFDYvfdd4+BAwdGQ0NDXHjhhbH66qvHT37yk0pffrvmr1El/OxnP4s777wzJk+eHLvvvnvMnTs3+ZvvL37xixg8eHB069YtevfuHX369Inbbrst3n777abH9O3bNzbYYIOm23YNDQ1RX18fO+64Y7z00kvx7LPPxgMPPBCNjY1Nh6Ol5s+fHyNHjox33nknbrnllk/8/XSoNmcFlq0tnZPu3bvHhx9++In8gw8+aPo45NCWzskDDzwQI0eOjPHjx8eRRx4Zo0ePjvPOOy9OPvnk+OlPfxozZsxo+SeiPWrtWyu1JDURYdGiRcV2221XrLXWWktMsrn22muLiChGjx5d/PKXvyxuv/324s477yy+/OUvf+IW3De/+c1i7bXXLt57772ic+fOxe9+97ti8eLFxSqrrFJcc801xXHHHVf06tXrU035+PDDD4vddtut6Nq1a3Hvvfe2eB1oDmcFlq0tnpNvf/vbRY8ePYrGxsYl8qeffrqIiOLCCy+seE1YmrZ4TsaOHVustdZan8inT59eRETx85//vOI12zN3NpahY8eOcfbZZ8dLL70UF198cVM+efLkWHfddeOmm26KsWPHxvDhw2PXXXdt+u7Px9XX18cLL7wQN9xwQyxevDi233776NChQ3zxi1+MhoaGaGhoiO23377p1mClGhsb4xvf+Ebcfffdcd1118VOO+3U4tcLLeWswLLV+jnZYost4r333vvEhLaHH3646eOQW62fk1dffTUWL178iXzhwoUREbFo0aKK12zPlI1m2HnnnWPIkCFxwQUXNL2hP3pzFkXR9LiHH344ORbwo1t055xzTgwePDhWXnnlpvzuu++OqVOnfuI2XnPHr0VEHHHEEXHjjTfGJZdc8olRb7A8OSuwbLV8Tvbcc8/o3LlzXHLJJU1ZURRx2WWXRb9+/WL77bev8NVCy9TyOdlwww3j1VdfjXvvvXeJ/Prrr4+IiC233LKZr3LFoGw00w9+8IN49dVX45prromIiJEjR8azzz4be+21V1xxxRVxwgknxFe+8pUYNGjQJ567/vrrxxprrBFPPvnkEm/sHXfcMZ5//vlYsGDBJ97wzR2/dsEFF8Qll1wSQ4cOjR49esSkSZOW+DV//vxP98KhQs4KLFutnpP+/fvH97///fjZz34WhxxySEycODH22GOPaGhoiHPPPbfFdxWhJWr1nHz3u9+Nnj17xh577BEnnnhiXH755TFmzJi44IILYtiwYfGFL3zh073w9qZV/xJXjSn7VyyLoigWL15crLfeesV6661XLFq0qGhsbCwmTJhQDBw4sOjatWux5ZZbFrfeemtx4IEHJsemfe1rX/vEv4S5YMGCokePHkWXLl2K999/f4nHN3f82oEHHrjE2LV//vXcc89V+mmAZXJWYNna4jn5aG8f7aVLly7FpptuWkyaNKmi1w7N1VbPycyZM4t99923GDBgQNG5c+di4MCBxTHHHFPMnz+/ote/Iqgrio/diwIAAKgSf40KAADIQtkAAACyUDYAAIAslA0AACALZQMAAMhC2QAAALJQNgAAgCw6NfeBdXV1OfcBn1ot/JMxzgm1zjmBZauFcxLhrFD7mnNW3NkAAACyUDYAAIAslA0AACALZQMAAMhC2QAAALJQNgAAgCyUDQAAIAtlAwAAyELZAAAAslA2AACALJQNAAAgC2UDAADIQtkAAACyUDYAAIAslA0AACALZQMAAMhC2QAAALJQNgAAgCyUDQAAIAtlAwAAyELZAAAAslA2AACALJQNAAAgC2UDAADIQtkAAACyUDYAAIAslA0AACALZQMAAMiiU2tvoLUNHz48me+zzz7LeSf/55lnnknmv/3tb5P5888/n8wXLVpUrS0BALRpvXv3Lv1Yjx49kvkll1ySzEeOHJnMGxsbk/n//u//JvPbbrstmR999NHJvC1yZwMAAMhC2QAAALJQNgAAgCyUDQAAIAtlAwAAyKKuKIqiWQ+sq8u9l6y22GKLZP7HP/4xma+88srJfNq0acm8Y8eOFV23mn73u98l88MOOyyZz5o1K+d2Wk0z38pZtfVzQvvnnKxYBgwYkMy33HLLZD5lypSc22kzauGcRDgrLbXddtsl8zPPPLP0OV/60pcqukbZ/5tqvXfOOOOMivLW0pzX684GAACQhbIBAABkoWwAAABZKBsAAEAWygYAAJBFp9bewPJy5JFHJvP58+cn83HjxiXz2267LZmXTaPaYYcdkvnee++dzCMihg4dmszLpofsvvvuyfyOO+5I5sOHD0/mL7zwQumeqG0bb7xxMv/lL39ZlfVzT93IvX5ExJAhQ6q2FtSSfffdt/Rjp59+ejLfcMMNk/l1112XzMumVG2++ebJvOzsXn311cn81VdfTeYffvhhMmfF8p3vfCeZjx07NpmXTaOq5teURx99NJk/9dRTyfzLX/5yMl9ttdWS+brrrpvM+/fvn8xnz56dzGuBOxsAAEAWygYAAJCFsgEAAGShbAAAAFkoGwAAQBZ1RTN/NL9sWkxbcffddyfzs88+O5nfddddObezVCuvvHIyP/PMM5P5t771rWTerVu3ZD5t2rRk3tan9VRzykRLtdY5+dd//ddkfs0111Rl/bJpa4sXL67K+h06pL/v0djYWJX1W3KNCRMmJPMf/ehHyfy9995r2caWsxX5nLR15513XjL//ve/X/qc3P+/qzVJ7qGHHkrmBxxwQDLPPXmnFs5JxIp3Vg466KBk/h//8R/JvEuXLsm87PP20ksvlV57r732SuavvPJKMn/77beT+UorrZTM77///mS+9tprJ/Oy1/D4448n87Kv9xMnTkzm77zzTjKvVHPOijsbAABAFsoGAACQhbIBAABkoWwAAABZKBsAAEAWK8w0qs9+9rPJ/K233krmCxYsyLib6rrtttuS+Ve+8pVk/uabbybz7bbbLpk//fTTLdvYclYL00Na65wsWrQomVdrmlPuaVG1OI2qTNnUtkceeaTSLbWKFfmctBXf/OY3k/nPfvazZN61a9fStdrKNKoyY8aMSea//vWvq7J+mVo4JxHt96wMGDAgmT///PNVWf+YY45J5ueff35V1m+JkSNHJvObbropmXfq1CmZV/re3HTTTZP5zJkzK1qnjGlUAABAq1E2AACALJQNAAAgC2UDAADIQtkAAACySP+oezv02muvtfYWshk9enQyf/fdd5P5qquumsyPOOKIZH7kkUe2aF/wzyZMmJDMyyZFHX/88Tm3A8vFyiuvnMzPOuusZH7YYYdVtH5rTizKfe2TTjopmeeeRkVeI0aMSOaVTlqaPn16Mi+b0rk8bLjhhsl87NixyfzDDz9M5h07dkzmZZ+j119/PZn37t07mS9P7mwAAABZKBsAAEAWygYAAJCFsgEAAGShbAAAAFmsMNOo2rOFCxcm87vvvjuZDx8+PJl/6UtfSuZdu3ZN5mUTFFj+yqZc/OIXv6jK+k888URF1y3z1FNPVfT4m266qfRjJ554YjIvm85WLddee20y33zzzbNel7arbLrUoYcemswrncizNNVcqzWu+/TTT1dlHdqnrbbaqtWuvcUWWyTzk08+OZlX+rXp0UcfTeZlX0cvueSSZP7AAw9UdN0c3NkAAACyUDYAAIAslA0AACALZQMAAMhC2QAAALIwjarE+uuvn8y7dOlSlfVnzZpV+rF33nmnKteYOnVqMi+bRrXpppsm85122imZ33HHHS3bGFV3/fXXJ/MPPvggmZ9wwgkVrf/kk08m80ceeaSidSq1tPX322+/itZqbGz8lLv5h0022aQq69B2de/ePZk///zzyfwzn/lMMi+b2DR37txk/vjjjyfz7bffPplHlE8TrJbf/va3ybxsr6+88koyL5uk89JLL7VsY9S0iRMnJvPdd9+9orzMKaeckswrnaAYEXHppZcm8zFjxiTznj17VrT+9OnTk3nZ1/Xzzz+/ovVrgTsbAABAFsoGAACQhbIBAABkoWwAAABZKBsAAEAWK8w0qlVXXTWZ//jHP07mBxxwQDLv1q1bVfbz17/+tfRjDzzwQDK/+eabk/lf/vKXquyJ9qfsPVOWt2dl06iqNaWK9meVVVZJ5r/+9a+T+eqrr57My6ZOzZkzJ5mvueaay97cx2yxxRalHyubrFgtkydPTubbbbddMv/5z39e0fqmUbVPixYtSubf+c53kvmECROSedl0qT333DOZn3feeaV72n///ZP5Gmuskczr6uqS+YcffpjML7zwwmR+1llnJfNqTSatBe5sAAAAWSgbAABAFsoGAACQhbIBAABkoWwAAABZ1BVlYzL++YElP3Vfa84888xkPnr06GQ+aNCgita//fbbk/lXvvKVitapprLJVmUTTfr375/M582bl8y/9KUvJfNHHnlk2Ztbjpr5Vs6qrZyT9uykk05K5qeffnoyr9Y0qi5dulRlndyck0/acccdk/nVV1+dzAcOHJjMy17X008/ncz322+/ZP7oo48m81q02mqrJfPbbrstmW+77bYVrT948OBkPmPGjIrWqVQtnJOI2jsrraXszy3Tp09P5r17907m1fz/etdddyXzc845J5nfc889Vbt2LWnO59SdDQAAIAtlAwAAyELZAAAAslA2AACALJQNAAAgC2UDAADIolNrb2BZVl555WT+4IMPJvN+/fol85VWWimZ77PPPsl85syZyfx///d/k/kGG2yQzMvsu+++pR/baaedkvmXv/zlZF7pKMEyzz33XDKvtRG3EFE+4vbYY49dzjuhrdhqq62S+e9///tk3q1bt4rWLxvHeswxxyTzWhxx27Nnz2Q+cuTIZH7DDTck87KR0osXL07mZWNBX3nllWTOimWjjTZK5r169cp+7euvvz6Zjx07Nvu12wt3NgAAgCyUDQAAIAtlAwAAyELZAAAAslA2AACALOqKoiia9cC6utx7SZoyZUoyHzFiRDJ/9dVXk/moUaOSedk0kIULFzZjd3l07do1mT/22GPJfP3116/KdV966aVkXl9fn8yff/75qly3Wpr5Vs6qtc5JbmUTao4//vhkfsIJJ1S0focO6e97lE20aYnc1+jYsWMynzx5cjI/9NBDk/ncuXOrsp8yK8I5KZti+Otf/zqZ77LLLhWt/8wzzyTzsomBL774YkXrV9OAAQOS+Xe/+91kPmzYsGQ+ePDgZF72/7LsfTZp0qRkPm7cuGTeWmrhnES0368pZcqmnk2YMCGZDxo0KJlX+r5cmvvuuy+Zl533FU1zPqfubAAAAFkoGwAAQBbKBgAAkIWyAQAAZKFsAAAAWXRq7Q0sS9lkgrKffj/yyCOT+dSpU6u2p2ro3r176cfOOOOMZF6tqVNl1lprrWR+0EEHJfNTTz01mS9evLhqe2L52muvvZL5VlttlcyPO+64ZF6tCU/VnEbVWtfYc889k/n8+fOT+THHHJPMc0+pak9OPvnkZF7p1Kknnngime++++7JvFpTp8qmaR144IHJvOw9FlF+dldaaaXKN5bw7rvvJvOzzjormZ933nlVuS5tQ9n7rOx98K1vfaui9cvef9ddd10yP/PMM0vXeuCBB5L5TjvtlMzL/gxU9me4FZk7GwAAQBbKBgAAkIWyAQAAZKFsAAAAWSgbAABAFjU/jaquri6Zl02jWrRoUVWu269fv2TesWPHZN6jR49kfvjhhyfzESNGlF574MCBy9jdksomoPzpT39K5mWTTsr2dPzxxyfzsik+ZZMYFi5cmMzJZ8cdd0zmBxxwQDIfPXp0Mu/Tp08yXx7TotqrMWPGJPOy30v222+/nNtpV5Y2nSll3rx5yfyrX/1qMp89e3ZF62+xxRbJfNiwYcn8u9/9bjIv+7pU9nUyovxrZaX++te/JvN//dd/TebPPPNMVa5L29C7d+9kfsoppyTzsqlT77zzTjL/n//5n2T+61//OplfdNFFyXxpU9jKfh8oO0NlU+lMo/okdzYAAIAslA0AACALZQMAAMhC2QAAALJQNgAAgCxqfhrVq6++mszLpuPsv//+yfy5555L5uPGjUvmZZMSyibFVFPZRIT/+q//SuYHH3xwMv/ggw+S+ZprrpnM//jHPybzDTfcMJmfeOKJyXzw4MHJvGz6zvz585M5zbfxxhsn86uvvjqZDxgwIOd2+BTKJoLRfOutt14yL5sq07Nnz2T++9//vir7KZswuDy+npS55JJLkvlll12WzMumS3344YdV2xO1b7PNNkvmv/nNb5L5BhtsUNH6ZVOn6uvrK1qnJZ566qlkvummmybz6dOn59xOu+LOBgAAkIWyAQAAZKFsAAAAWSgbAABAFsoGAACQRc1Pozr99NOT+cUXX5zM991334rySpVNM7n33nsrWue3v/1t6cceeuihZP7II49UdI0yL7/8cjL/whe+kMzvvvvuZL7VVlsl85EjRybz448/PpmfcsopyZxP7/XXX68oL1NXV5fMy85DpXKvHxHx5JNPJvOxY8dWtM61116bzDfZZJNk3tjYWNH6fHpl76cynTqlvxQOGjSoKtet1vv4zTffTOYzZswofc748eOT+R/+8Ieq7IkVy7//+78n80qnTt12223J/Nvf/nbFe6rESiutVPqxjTbaqKK1yiZ78knubAAAAFkoGwAAQBbKBgAAkIWyAQAAZKFsAAAAWdQVzRyTUel0j2opmxKyxRZbJPM999wzmZdNGbj66quT+Zw5c5J52adr2rRpybw92HDDDZN52UStSie4dOzYseI9pVRzclFLtdY5geZaEc7JU089lczXXXfdrNetdBrVhx9+mMwvu+yyZH7ppZcm86effroZu6MStXBOIlrva0rZJNCTTz65onW+8Y1vJPNf/epXFe8ppWy6VNmfBZe2/0onag0ZMiSZt+c/D6Y056y4swEAAGShbAAAAFkoGwAAQBbKBgAAkIWyAQAAZJEe9VRDFi1alMynTp1aUU7LlU12+f73v5/Mv/a1ryXziy66qFpbAii16667JvMzzzwzme+2225VuW7ZFKmyaVG33357Mn/99dersh9oqZdffjmZl00eKvtzwjvvvJPMN9tss2R+yimnNGN3/6dsgtTnP//5ZL60yUlz585N5scdd1wyX9GmTn0a7mwAAABZKBsAAEAWygYAAJCFsgEAAGShbAAAAFnUFUv70fyPP7CuLvde4FNp5ls5K+eEWuecwLLVwjmJaL2z8o1vfCOZn3HGGcm8f//+ybxsqlWHDunvdfft27cZu1u2xx57LJnfe++9pc+55JJLknnZNDn+oTlnxZ0NAAAgC2UDAADIQtkAAACyUDYAAIAslA0AACAL06hoN2pheohzQq1zTmDZauGcRNTeWRk2bFgy//3vf1/ROmWvq+zz/tRTTyXz2267LZnfeuutyfxPf/pTM3ZHJUyjAgAAWo2yAQAAZKFsAAAAWSgbAABAFsoGAACQhWlUtBu1MD3EOaHWOSewbLVwTiKcFWqfaVQAAECrUTYAAIAslA0AACALZQMAAMhC2QAAALJQNgAAgCyUDQAAIAtlAwAAyELZAAAAslA2AACALJQNAAAgC2UDAADIQtkAAACyUDYAAIAslA0AACALZQMAAMhC2QAAALKoK4qiaO1NAAAA7Y87GwAAQBbKBgAAkIWyAQAAZKFsAAAAWSgbAABAFsoGAACQhbIBAABkoWwAAABZKBsAAEAWygYAAJCFsgEAAGShbAAAAFkoGwAAQBbKBgAAkIWyAQAAZKFsAAAAWSgbAABAFsoGAACQhbIBAABkoWwAAABZKBsAAEAWygYAAJCFsgEAAGShbAAAAFkoGwAAQBbKBgAAkIWyAQAAZKFsAAAAWSgbAABAFsoGAACQhbIBAABkoWwAAABZKBsAAEAWygYAAJCFsgEAAGShbAAAAFkoGwAAQBbKBgAAkIWyAQAAZKFsAAAAWSgbAABAFsoGAACQhbIBAABkoWwAAABZKBsAAEAWygYAAJCFsgEAAGShbAAAAFkoGwAAQBbKBgAAkIWyAQAAZKFsAAAAWSgbAABAFsoGAACQhbIBAABkoWwAAABZKBsAAEAWygYAAJCFsgEAAGShbAAAAFkoGwAAQBbKBgAAkIWyAQAAZKFsAAAAWSgbAABAFsoGAACQhbIBAABkoWwAAABZKBsAAEAWygYAAJCFsgEAAGShbAAAAFkoGwAAQBbKBgAAkIWyAQAAZKFsAAAAWSgbAABAFsoGAACQhbIBAABkoWwAAABZKBsAAEAWygYAAJCFsvEx11xzTdTV1TX96tSpU/Tr1y/GjRsXL774YmtvL+n5559fYs8f/3XDDTe09vZop9riWfnIM888E2PGjInPfvaz0b1799hggw3ipJNOau1t0Q61xXMyc+bMOPbYY2OLLbaIlVZaKdZcc80YMWJETJ06tbW3RjvVFs9JRMTLL78cBx98cKyzzjrRvXv3WG+99eKoo46K119/vbW3VnM6tfYGatEZZ5wR66yzTnzwwQfx5z//Oa655pq4//774/HHH49u3bq19vaSDjjggNh9992XyIYOHdpKu2FF0dbOyiOPPBI777xz9OvXL44++ujo3bt3vPDCCzFr1qzW3hrtWFs6JxMnTowrr7wy9tlnnzjssMPi7bffjssvvzy22267uP3222PXXXdt7S3STrWlc/Luu+/G0KFDY/78+XHYYYfFgAED4tFHH42LL7447rnnnpg2bVp06OD7+U0Kmlx99dVFRBR//etfl8iPO+64IiKKG2+8sZV2Vu65554rIqL48Y9/3NpbYQXSFs/K4sWLi80226z4whe+ULz33nutvR1WAG3xnEydOrV45513lsjmzp1b9OnTp9hhhx1aaVe0Z23xnPzqV78qIqK49dZbl8hPPfXUIiKK6dOnt9LOapPa1Qz19fUR8Y+/fvGRBQsWxKmnnhpbb711rLzyytGzZ8+or6+Pe+65Z4nnbrXVVrH33nsvkW2++eZRV1cXjz32WFN24403Rl1dXTzxxBNN1/r49Zpj/vz5sWDBgoqeA9VUy2fljjvuiMcffzx++MMfRvfu3eO9996LxYsXt/i1QkvV8jnZeuuto1evXktkvXv3jvr6+qa1YHmo5XMyb968iIjo27fvEvmaa64ZERHdu3dv7stcISgbzfD8889HRMSqq67alM2bNy8mTpwYO++8c5xzzjlx2mmnxZw5c2L48OHxyCOPND2uvr4+7r///qb/fuONN+Jvf/tbdOjQIRoaGpryhoaG6NOnT2yyySYREbHLLrvELrvs0uw9nn766dGrV6/o1q1bbLvttnHHHXe08NVCy9XyWbnrrrsiIqJr166xzTbbRM+ePaNHjx6x//77xxtvvPFpXjZUpJbPSZlXXnklVl999RY/HypVy+dkxx13jA4dOsSRRx4Zf/7zn2P27Nnxu9/9LsaPHx+jR4+OjTfe+FO++namtW+t1JKPbuXdddddxZw5c4pZs2YVkydPLvr06VN07dq1mDVrVtNjFy1aVHz44YdLPP/NN98s+vbtW/zbv/1bU/ab3/ymiIhixowZRVEUxZQpU4quXbsWo0aNKr7+9a83PW7w4MHFXnvt1fTfAwcOLAYOHLjMPf/9738vdtttt+LSSy8tpkyZUlxwwQXF2muvXXTo0OETt/egWtriWRk1alQREUXv3r2Lf/mXfykmT55cnHLKKUWnTp2K7bffvmhsbGzppwOS2uI5SbnvvvuKurq64pRTTmnR82Fp2uo5mThxYrHKKqsUEdH068ADDywWLlzYkk9Du+YHxBP++QfgPve5z8WkSZOif//+TVnHjh2jY8eOERHR2NgYb731VjQ2NsY222wT06dPb3rcR7cB77vvvthkk02ioaEhtt122xg2bFicffbZERHx1ltvxeOPPx7jxo1ret5HjX5Z1l577fjDH/6wRDZ27NgYNGhQHH300TFixIhmv26oVFs6K++++25ERGy77bYxadKkiIjYZ599okePHnHCCSfE3Xff7YdfyaItnZN/9tprr8WYMWNinXXWiWOPPbZFa0BztLVz0q9fvxgyZEjsvvvuMXDgwGhoaIgLL7wwVl999fjJT35S6ctv1/w1qoSf/exnceedd8bkyZNj9913j7lz50bXrl0/8bhf/OIXMXjw4OjWrVv07t07+vTpE7fddlu8/fbbTY/p27dvbLDBBk237RoaGqK+vj523HHHeOmll+LZZ5+NBx54IBobG5sOx6e12mqrxTe/+c148sknY/bs2VVZE1La0ln56O/QHnDAAUvkY8aMiYiIBx98sOI1oTna0jn5uPnz58fIkSPjnXfeiVtuueUTP8sB1dSWzskDDzwQI0eOjPHjx8eRRx4Zo0ePjvPOOy9OPvnk+OlPfxozZsxo+SeiHVI2EoYMGRK77rpr7LPPPjFlypTYbLPNYsyYMU3fGY2ImDRpUowbNy7WW2+9uPLKK+P222+PO++8M7785S9HY2PjEut98YtfjIaGhnj//fdj2rRpUV9fH5tttlmsssoq0dDQEA0NDdGrV6/Ycsstq/YaBgwYEBHh76KTVVs6K2uttVZEfPIH+j772c9GRMSbb75Z8ZrQHG3pnHxkwYIFsffee8djjz0Wt9xyS2y22WYtXguaoy2dk8svvzz69u0b22yzzRL5qFGjoigK37z6J8rGMnTs2DHOPvvseOmll+Liiy9uyidPnhzrrrtu3HTTTTF27NgYPnx47LrrrvHBBx98Yo36+vp44YUX4oYbbojFixfH9ttvHx06dGg6CA0NDbH99ts33RqshmeffTYiIvr06VO1NWFpav2sbL311hERn/hHol566aWIcFZYPmr9nET846+nfOMb34i77747rrvuuthpp51a/HqhJWr9nLz66qvJaYYLFy6MiIhFixZVvGZ7pmw0w8477xxDhgyJCy64oOkN/dGbsyiKpsc9/PDD8dBDD33i+R/dojvnnHNi8ODBsfLKKzfld999d0ydOvUTt/GaO35tzpw5n8hefPHFuOqqq2Lw4MFNY9hgeajls7LnnntG165d4+qrr17iO2ATJ06MiIhhw4ZV8lKhxWr5nEREHHHEEXHjjTfGJZdc8onxobC81PI52XDDDePVV1+Ne++9d4n8+uuvj4io6t9UaRda9cfTa0zZPyxTFP832eDSSy8tiqIorrrqqiIiilGjRhWXX355cfzxxxerrLJKsemmmyYnGayxxhpFRBRHHHFEU/bQQw81TTC49957l3h8cycijBs3rqivry9OO+204oorrihOPPHEonfv3kWXLl2Ke+65p6LXD83VFs9KURTFGWecUUREMWzYsOJnP/tZcfDBBxd1dXXFAQcc0PwXD83UFs/J+eefX0REMXTo0OLaa6/9xK933323sk8CLENbPCczZ84sevbsWfTq1as44YQTissuu6w44IADmr6+sCRl42OW9oZfvHhxsd566xXrrbdesWjRoqKxsbGYMGFCMXDgwKJr167FlltuWdx6663FgQcemHyjfu1rX/vEv4S5YMGCokePHkWXLl2K999/f4nHN/cNf9111xU77rhj0adPn6JTp07F6quvXuy1117FtGnTKn790Fxt8awURVE0NjYWF110UbHhhhsWnTt3LgYMGFCcfPLJxYIFCyp6/dAcbfGcHHjggUuM8vznX88991ylnwZYqrZ4ToriH4Vj3333LQYMGFB07ty5GDhwYHHMMccU8+fPr+j1rwjqiuJj96IAAACqxM9sAAAAWSgbAABAFsoGAACQhbIBAABkoWwAAABZKBsAAEAWygYAAJBFp+Y+sK6uLuc+4FOrhX8yxjmh1jknsGy1cE4inBVqX3POijsbAABAFsoGAACQhbIBAABkoWwAAABZKBsAAEAWygYAAJCFsgEAAGShbAAAAFkoGwAAQBbKBgAAkIWyAQAAZKFsAAAAWSgbAABAFsoGAACQhbIBAABkoWwAAABZdGrtDQAsD+uvv34ynzhxYjJ/7733kvkvf/nLZH7DDTe0bGMA0I65swEAAGShbAAAAFkoGwAAQBbKBgAAkIWyAQAAZGEaFdCuDBo0KJnfdtttyXzttddO5jNmzEjmW2+9dTI3jQqgtu28886lHxs6dGhFa6211lrJ/OKLL07m8+bNS+Yvv/xyRddti9zZAAAAslA2AACALJQNAAAgC2UDAADIQtkAAACyqCuKomjWA+vqcu8FPpVmvpWzck6Wn89//vPJ/Lrrrkvm66+/fjIfPXp0Mv/973/fon3VOuek7Sp7D999992lzxkwYEBF1yj7f1M2YeeII46oaP22ohbOSYSzsizDhg1L5occckgyL3sfR0T88Y9/TOZl74VFixZVlJetv8cee5TuqS1ozllxZwMAAMhC2QAAALJQNgAAgCyUDQAAIAtlAwAAyKJTa28AoMzSJrGcfPLJyXzjjTdO5uecc04yb69Tp2i7vvjFLybzXr16JfP+/fuXrlXpVKWyx++yyy4VrQPV9KUvfSmZn3rqqcl86NChybxselVE+Tn64Q9/mMy7dOmSzMsmHJadobLzfv/99yfztsidDQAAIAtlAwAAyELZAAAAslA2AACALJQNAAAgC9OogJp1yCGHlH5sn332SeaTJ09O5ieeeGJV9gSVuuCCC5L5N7/5zWReNuWmsbGxWluCNuWII45I5ttvv30yX7RoUTI/9thjS6/x0ksvJfOlfR1KOf3005P5zjvvnMw7d+5c0fptkTsbAABAFsoGAACQhbIBAABkoWwAAABZKBsAAEAWdUVRFM16YF1d7r20Cdtss00ynzFjRjJ/7733cm6Hj2nmWzkr56RlevbsmcynT59e+pwFCxYk8+HDhyfzskkjKxrnJJ+yqVOHH354Mu/QIf/3+/7yl78k8yFDhlS0zuLFi5P5mDFjknnZVLi2ohbOSUT7PStlNt1002R+3333JfOyP3sdeeSRyXxpX1Ny+8xnPlPR4+fNm5dpJ9XVnLPizgYAAJCFsgEAAGShbAAAAFkoGwAAQBbKBgAAkEWn1t5Ardp4442T+cMPP5zMyyYi3HDDDcl8/PjxLdtYKzj44IMrevxBBx1Ules+8cQTyfwb3/hGVdandhx33HHJfIMNNih9zn777ZfMTZ0it3/5l39J5mW/N+WeOjV69OjSj7377rvJ/K677qroGh07dkzmXbt2rWgdWJqyyYTdunVL5hMmTEjmy2Pq1BZbbJHMu3TpUtE6O+ywQzI///zzK91SzXJnAwAAyELZAAAAslA2AACALJQNAAAgC2UDAADIoq4oiqJZD6yry72XVvGVr3wlmf/iF79I5n369EnmZZ/Gss/b0j7tZc8pm840c+bMZF42UWuTTTapaE+VvoayySuNjY1VeXzZVJRmvpWzaq/npFp22mmnZH7PPfck87/97W+la22++eZV2dOKxjlpvkqnEvbq1asq1509e3Yyv/LKK5P5ueeeW7rW1ltvnczvu+++ivb07LPPJvMtt9wymZdNwWorauGcRLSds1ItI0aMSObbbrttMp80aVIyf+6555L50iYcbrbZZsl8zJgxyXzOnDnJ/Nvf/nbpNVJuu+22ZD5q1KiK1mktzTkr7mwAAABZKBsAAEAWygYAAJCFsgEAAGShbAAAAFl0au0NLC977bVXMp88eXIyL/vp+rFjxybzsqklJ554YkXrL81GG21U0bXLrlFpfsUVVzRjd9VXNmWL2telS5dkfs011yTzsokrt99+e7W2BBX73e9+l8yrNXWqzC9/+ctkfsYZZ1S81pFHHvlptxMREQsXLkzmbX3qFLWlf//+yXzkyJHJ/Oijj07mU6ZMSeb7779/6bUfffTRZL7++usn8zPPPDOZv/rqq8n8oosuSuZlXxfbE3c2AACALJQNAAAgC2UDAADIQtkAAACyUDYAAIAs6opmjkUqmxZTawYOHJjM//KXvyTzPn36JPObbropme+7774t2xjZtWTCV7W1lXOS209+8pNk/u///u/J/IUXXkjmG264Yek1yqbjsHTOSfO9/fbbybzSaVSzZ89O5uPGjUvmDz30UDL/4IMPkvmBBx5Yeu2yCTg9e/YsfU7Kk08+mcwHDRpU0TptRS2ck4i2c1aqZeutt07mDz74YDLv1Kl6Q1VvvfXWZH7eeecl89deey2Zl02jevPNN1u2sRrXnLPizgYAAJCFsgEAAGShbAAAAFkoGwAAQBbKBgAAkEX1foy/RtTX1yfz3r17J/M5c+Yk86OOOqpqe4L2qmyizTe+8Y1kXjZZ5eKLL07mJk7Rmo4//vhkfv755yfzsik0e+65ZzJ/5JFHWrSvf/btb3+79GOVTp2C1lQ24em5555L5htssEFF6//hD38o/VjZOeXTc2cDAADIQtkAAACyUDYAAIAslA0AACALZQMAAMii3U2jeuKJJ5J52RScPn36JPNNNtkkmb/wwgst2xi0QyeffHIyX3311ZN5URTJ/Pvf/34yL5suFxExadKkZD558uTS50AlLr300mQ+bdq0ZP7GG28k86effroq+9luu+2S+eabb16V9Zfm5z//efZrwNVXX53MN9xww6qsX/ZnQfJyZwMAAMhC2QAAALJQNgAAgCyUDQAAIAtlAwAAyELZAAAAsqgrymZR/vMD28i4sB49eiTzX/7yl8l8r732SuZz5sxJ5tddd10ynzBhQjKfO3duMqf6mvlWzqqtnJNKrbLKKsn8gQceSOZlo6OXh7/97W/J/PTTT0/mK9qoXOek9vXu3TuZl30d+8pXvlK1az/77LPJfIcddkjmr732WtWuXUtq4ZxEtN+zcsIJJyTzst+nH3744WT++c9/PpmXvY+XNia6Y8eOpR+jXHPOijsbAABAFsoGAACQhbIBAABkoWwAAABZKBsAAEAW7W4aVaV++9vfJvPRo0cn87LPwxNPPJHMb7rppmQ+ceLE0j39/e9/L/0Y5Wphekh7PSfrr79+Mn/yySeTednnoWzy04knnpjMBw0aVLqnsgk8hxxySDJ/7LHHkvluu+2WzMsm0rV1zknt23PPPZN52deTpZkxY0YyP+aYY5L5O++8k8wffPDBiq/dltXCOYlov2elbLpUp06dkvnXvva1ZP7d7343mXfu3DmZH3bYYaV72nbbbZP59OnTS5+DaVQAAEArUjYAAIAslA0AACALZQMAAMhC2QAAALJI/9j/CmTs2LHJfOONN07m1157bTLfaKONknnZlJ2DDjqodE+HHnpoMr/55ptLnwM57bTTTsm8bFJK2eSn0047LZk//fTTFeUREVOmTEnmb7/9djI/7rjjkvn++++fzC+66KLSa0NOX/7yl6u21hprrJHMy6atlU3e6datWzL/whe+kMzLpgHdddddyRwiInr16pXM11133WR+1FFHJfOW/P697777JnPTqD49dzYAAIAslA0AACALZQMAAMhC2QAAALJQNgAAgCxW+GlU7733XjIvmz6w6aabJvO99tormY8fPz6Zl02vioj47W9/m8y32WabZG5SAtVSNl3qkEMOSeZFUSTzyy67LJnPmDGjZRurwNy5c7NfA6rhggsuSOZbbbVV1a6x2mqrJfPzzz8/mb/yyivJfKWVVkrmw4cPT+ZTp05N5mWTGK+55ppk/vvf/z6Z07aV/dnoqquuSub/8R//kczL/kz27LPPVryncePGJfOzzjormZf9+ZFPcmcDAADIQtkAAACyUDYAAIAslA0AACALZQMAAMiirigbJ/PPDyyZUlNrNt5442Q+c+bM5byTf+jRo0cyf/jhh0ufM2jQoGQ+YcKEZH7KKadUvrF2qJlv5azayjkpU7b/xYsXV7ROhw75v4+x5557JvObb745md99993JfPTo0cl8/vz5LdpXrXNO8imbSrj33nsn8z322COZl01+ag/KJvjssssuyfwvf/lLzu2UqoVzEtF+z0qZq6++Opnvu+++ybzsbJX9GevNN98svXbZ5/qoo45K5mXT5FY0zTkr7mwAAABZKBsAAEAWygYAAJCFsgEAAGShbAAAAFm0u2lUl112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FNOnT2+lndGetcWzMnv27KJz587F4Ycf3pQ1NjYW9fX1Rf/+/YtFixa14u5oj9riOTnssMOKTp06FTNnzmzK5s+fXwwYMKDYaqutWnFntFdt8Zw899xzRUQUP/7xj1t7K22Cb3k3Q319fUREPPPMM03ZggUL4tRTT42tt946Vl555ejZs2fU19d/4lbzVlttFXvvvfcS2eabbx51dXXx2GOPNWU33nhj1NXVxRNPPNF0rY9fr8y8efMiIqJv375L5GuuuWZERHTv3r25LxM+tVo+K7fcckssXLgwDjvssKasrq4uDj300Jg9e3Y89NBDlb9gaIFaPicNDQ2x5ZZbxkYbbdSU9ejRI0aNGhXTp0+P//3f/638BUML1PI5+bj58+fHggULKnrOikbZaIbnn38+IiJWXXXVpmzevHkxceLE2HnnneOcc86J0047LebMmRPDhw+PRx55pOlx9fX1cf/99zf99xtvvBF/+9vfokOHDtHQ0NCUNzQ0RJ8+fWKTTTaJiIhddtkldtlll2Xubccdd4wOHTrEkUceGX/+859j9uzZ8bvf/S7Gjx8fo0ePjo033vhTvnpovlo+K//93/8dPXv2bHreR4YMGdL0cVgeavmcfPjhh8lvUvXo0SMiIqZNm1bRa4WWquVz8pHTTz89evXqFd26dYttt9027rjjjha+2nautW+t1JKPbuXdddddxZw5c4pZs2YVkydPLvr06VN07dq1mDVrVtNjFy1aVHz44YdLPP/NN98s+vbtW/zbv/1bU/ab3/ymiIhixowZRVEUxZQpU4quXbsWo0aNKr7+9a83PW7w4MHFXnvt1fTfAwcOLAYOHNisfU+cOLFYZZVVioho+nXggQcWCxcubMmnAZapLZ6VESNGFOuuu+4n8vnz5xcRURx//PHNfv3QHG3xnOyxxx7FKqusUsybN2+JfOjQoUVEFD/5yU8q+hzAsrTFc/L3v/+92G233YpLL720mDJlSnHBBRcUa6+9dtGhQ4dP/LV2isIPiCfsuuuuS/z35z73uZg0aVL079+/KevYsWN07NgxIv4x4eatt96KxsbG2GabbWL69OlNj/voNuB9990Xm2yySTQ0NMS2224bw4YNi7PPPjsiIt566614/PHHY9y4cU3P+6jRN0e/fv1iyJAhsfvuu8fAgQOjoaEhLrzwwlh99dXjJz/5SaUvH5qtLZ2V999/P7p27fqJ/KMfPHz//febtQ5Uqi2dk0MPPTT+67/+K77+9a/H+PHjo2fPnnHJJZfE1KlTI8I5IZ+2dE7WXnvt+MMf/rBENnbs2Bg0aFAcffTRMWLEiGa/7hWBv0aV8LOf/SzuvPPOmDx5cuy+++4xd+7c5B9SfvGLX8TgwYOjW7du0bt37+jTp0/cdttt8fbbbzc9pm/fvrHBBhs03bZraGiI+vr62HHHHeOll16KZ599Nh544IFobGxsOhyVeOCBB2LkyJExfvz4OPLII2P06NFx3nnnxcknnxw//elPY8aMGS3/RMAytKWz0r179/jwww8/kX/wwQdNH4cc2tI5+epXvxoXXXRR3HfffbHVVlvFRhttFLfddluMHz8+IiJ69erVws8CLF1bOicpq622Wnzzm9+MJ598MmbPnl2VNdsLZSNhyJAhseuuu8Y+++wTU6ZMic022yzGjBkT7777btNjJk2aFOPGjYv11lsvrrzyyrj99tvjzjvvjC9/+cvR2Ni4xHpf/OIXo6GhId5///2YNm1a1NfXx2abbRarrLJKNDQ0RENDQ/Tq1Su23HLLivd6+eWXR9++fWObbbZZIh81alQURREPPvhgyz4J0Axt6aysueaa8corr0RRFEvkL7/8ckRErLXWWi34DMCytaVzEhHx3e9+N1599dV48MEHY+rUqTFz5sxYeeWVIyJiww03bPknApairZ2TlAEDBkTEP35GhP+jbCxDx44d4+yzz46XXnopLr744qZ88uTJse6668ZNN90UY8eOjeHDh8euu+7a9F3Sj6uvr48XXnghbrjhhli8eHFsv/320aFDh6aD0NDQENtvv33TrcFKvPrqq7F48eJP5AsXLoyIiEWLFlW8JrRErZ+VLbbYIt57772mqSMfefjhh5s+DrnV+jn5SM+ePWPo0KGx9dZbR8eOHeOuu+6K7t27xw477NDiNaG52so5+WfPPvtsRET06dOnamu2B8pGM+y8884xZMiQuOCCC5re0B+9OT/+XdKHH344OT7zo1t055xzTgwePLjpO0T19fVx9913x9SpUz9xG6+549c23HDDePXVV+Pee+9dIv/oX0WuZmOHZanls7LnnntG586d45JLLmnKiqKIyy67LPr16xfbb799ha8WWqaWz0nKgw8+GDfddFN861vfaroW5FbL52TOnDmfyF588cW46qqrYvDgwU3//AD/Xyv+cHrNKfuHZYri/yYbXHrppUVRFMVVV11VREQxatSo4vLLLy+OP/74YpVVVik23XTT5CSDNdZYo4iI4ogjjmjKHnrooabpUffee+8Sj2/uRISZM2cWPXv2LHr16lWccMIJxWWXXVYccMABRUQUw4YNq+wTAM3UFs9KURTFD37wgyIiioMPPrj4+c9/XowYMaKIiOJXv/pV8188NFNbPCfPP/98MWTIkOKss84qJk6cWPz7v/970b1792LLLbf8xIQqqIa2eE7GjRtX1NfXF6eddlpxxRVXFCeeeGLRu3fvokuXLsU999xT0etfESgbH7O0N/zixYuL9dZbr1hvvfWKRYsWFY2NjcWECROKgQMHFl27di223HLL4tZbby0OPPDA5Bv1a1/72if+JcwFCxYUPXr0KLp06VK8//77Szy+kj9AzZw5s9h3332LAQMGFJ07dy4GDhxYHHPMMcX8+fMrev3QXG31rCxevLhpL126dCk23XTTYtKkSRW9dmiutnhO3njjjWLPPfcs1lhjjaJLly7FOuusUxx33HGKBtm0xXNy3XXXFTvuuGPRp0+folOnTsXqq69e7LXXXsW0adMqfv0rgrqi+KeflgQAAKgCP7MBAABkoWwAAABZKBsAAEAWygYAAJCFsgEAAGShbAAAAFkoGwAAQBadmvvAurq6nPuAT60W/skY54Ra55zAstXCOYlwVqh9zTkr7mwAAABZKBsAAEAWygYAAJCFsgEAAGShbAAAAFkoGwAAQBbKBgAAkIWyAQAAZKFsAAAAWSgbAABAFsoGAACQhbIBAABkoWwAAABZKBsAAEAWygYAAJCFsgEAAGShbAAAAFkoGwAAQBbKBgAAkIWyAQAAZKFsAAAAWSgbAABAFp1aewMAAPDVr341mR9xxBHJ/Ctf+UpF6z/33HOlH3vwwQcrWqu1nHfeecn8kUceWb4bqYA7GwAAQBbKBgAAkIWyAQAAZKFsAAAAWSgbAABAFnVFURTNemBdXe691JQNN9wwmZ955pnJfL/99qvatffee+9kfvPNN1e0TocO6S7ZrVu3ZP7ee+9VtH6taeZbOasV7ZysiMqmpZT505/+lMxb67w5J7BstXBOIla8s/L+++8n8y5dulS0ziuvvJLMy/78ExGx6qqrJvPc74Wy/8dlk7OGDRuWzJ999tmq7akSzfn8uLMBAABkoWwAAABZKBsAAEAWygYAAJCFsgEAAGSxwk+j6t+/fzK///77k/naa6+dcztL9ZnPfCaZv/vuu8n88MMPT+Y//OEPk/kNN9yQzCdOnJjMH3vssWTeWmphekh7PSe1aNCgQcn84IMPznrdI444Ipk3NjYm8/PPPz+ZH3vssVXbUyWck9r3uc99Lpl/5zvfSeZrrrlm6Vpl0w1ffPHFZF72vpwyZUrpNdqjWjgnESveWSn7fbTs/0fZ7/dl79fOnTuXXrtHjx7L2N2S9thjj2T+4IMPJvPXX3+9ovXnzp2bzN96662K1snNNCoAAKDVKBsAAEAWygYAAJCFsgEAAGShbAAAAFmsMNOounTpkszPPPPMZP6DH/wg53Za5Lzzzkvm48ePT+Z/+ctfkvn6669f0XXLppaMHDkymT/66KMVrV8ttTA9pK2fk1pTNgktImL48OHJfI011si1nYiI6NAh/T2asikqCxcuTOazZs1K5qeeemoyv/HGG5uxu2VzTmrH9ttvn8zLJgOWTU989dVXS6/x97//PZkPGTIkmb///vvJvOz3+3vuuaf02m1ZLZyTiPZ7VjbeeONkPmPGjGRe9v9jo402SuZPP/10yzZGxUyjAgAAWo2yAQAAZKFsAAAAWSgbAABAFsoGAACQRafW3sDysvbaayfzak2deuutt5L5r371q2R+yCGHlK7VqVP6f8vhhx+ezOfPn5/MK506VaZfv37J/Fvf+lYy/973vleV69J27bTTTsl88ODBFa3zhS98ofRja621VjIvmwrVWjp37pzM11133WQ+adKkZF6taVTkUzY5qGyS0+TJk5N52deAsomE5557bumeunfvXtFa++yzTzI/4YQTknl7nUZFXltvvXVrb4HlyJ0NAAAgC2UDAADIQtkAAACyUDYAAIAslA0AACCLFWYaVW5XXXVVMj/mmGOS+axZs0rXmjBhQjIvmypy6qmnLmN3n85jjz2WzC+88MKs16X2bbPNNsm87DyUTYVrS6ZOnZrMX3zxxWS+xx575NwONaRs2tott9xS0To/+tGPkvmJJ55Y8Z7K3H333cm8bBpV2Vk/6aSTkvn48eNbtjFWCGWT28ryhx9+OJk//fTTVdsT+bizAQAAZKFsAAAAWSgbAABAFsoGAACQhbIBAABkYRpVlUyaNKmix5977rmlH3vppZeS+bXXXlvRNcrMmzcvmX/ve99L5v/5n/9Z0Tq0P2WTaP76178m88bGxpzbiYiIDh3S3yuZMWNGMn/ooYeS+cEHH1yV/fzHf/xHMi/bJ21Xv379kvkFF1xQ0TplE5tOO+20itZZbbXVSj/2xhtvJPOyM11mlVVWSebf//73k7lpVCzNVlttlcyLokjmc+fOzbkdMvNVEAAAyELZAAAAslA2AACALJQNAAAgC2UDAADIYoWZRjVr1qxkftdddyXzXXfdNed2lmr48OFVWadsUtCECROS+S233FKV69J27bTTTsn8qquuSuZlU6eWxzSqI488Mpnfd999yfyxxx6rynUHDRqUzOvr65P58vhcsHz1798/mZedn6eeeiqZn3HGGcl88eLFyXzUqFHJ/KKLLkrmEeVfB6r1dWbKlClVWYcVy0YbbVTR4//whz8k8969eyfzAw44IJmvvvrqFV03IuI3v/lNMt9hhx2S+c0335zM58yZU/G12wt3NgAAgCyUDQAAIAtlAwAAyELZAAAAslA2AACALFaYaVQffvhhMj/77LOTeaXTqL7zne9UlD/00EOlaw0ZMqSia7///vvJ/Oijj07m999/f0Xr0/587nOfS+Y33HBDMm/JBI+UhQsXJvO///3vyfyHP/xh6Vq//vWvq7KnSg0dOjSZb7755hWt89ZbbyXzww8/vNItkclaa62VzK+++uqK1jn//POTedl5KDN9+vRkPmDAgNLnLO1j1fDmm29mXR8iIo466qhkfuyxxybzfv36VXyNurq6ZH7KKadUtE7ZJKyf/vSnyfyOO+5I5mV/bm2L3NkAAACyUDYAAIAslA0AACALZQMAAMhC2QAAALJYYaZRlanWJI2yCVLf+973kvmgQYNK1yqbiFA2uWTfffdN5qZOUWafffZJ5tWaOlXmoosuSubHHXdc1uu2xJ577pnMr7jiimTe2NiYzMumTh188MHJ/Oabb1725lguttpqq2S+8cYbJ/PXX389mU+cOLEq+1mwYEEyL5tmExGx2267JfPXXnstmX/2s5+tfGOQ2cCBAyt6/JNPPpnMp06dWvqcsj97FUWRzJ977rlkXjaF9D//8z+T+WOPPZbMy6beXXjhhcm8lrmzAQAAZKFsAAAAWSgbAABAFsoGAACQhbIBAABkscJPo/qf//mfZH7mmWcm81NOOSWZb7HFFsn8ggsuaMm2kkaMGJHM77zzzqpdg/bl0EMPTeannnpq1utedtllyfz000/Pet2WKJs6VfYaKjV37txkburUimPx4sXJvH///sl87733Tubjxo1L5mVffyIiZs2alczL3vc33XRTMv/c5z6XzN97773Sa8NnPvOZZL7NNtsk87KJUGUuvvjiZH7GGWck87Lfj6tpwoQJyfynP/1pMj/ssMOSednX7yuvvDKZz58/vxm7ax3ubAAAAFkoGwAAQBbKBgAAkIWyAQAAZKFsAAAAWSgbAABAFnVFURTNemCF48jaurXXXjuZ33fffcl84MCBVbt22di0k046qWrXaI+a+VbOqrXOyVe/+tVkfuutt2a97vjx45N57tG6SzNo0KBkPnTo0GR+xRVXVLR+hw7p79E8/vjjyXy33XZL5i+//HJF162WFfmcVGrkyJHJfMqUKcl84cKFybyhoSGZ77TTTsm8Y8eOzdjd/3nggQdKP3bIIYck8+effz6Zv/vuuxVde8stt0zmjz76aEXr1JpaOCcRbeesVOp73/teMv/ud7+bzMu+1kyaNCmZl42bbk1du3ZN5mW/P2y99dbJvOzPgj/60Y9atrFPqTlnxZ0NAAAgC2UDAADIQtkAAACyUDYAAIAslA0AACAL06gqVDY1YIcddqjaNaZNm5bM99hjj2T+yiuvVO3abVktTA+ptWlUZVNzqqVz585Z12+JCy64IJkffvjhVVl/5syZyfxf/uVfkvljjz1WletWy4p8TqrlsssuS+Zlk5/KvP3228n86quvTua//e1vk/n9999f0XUjIg499NBkfskllyTzRx55JJmXTaNq62rhnES0/bNSqZVWWimZv/POO8t5J8tP2Zkr+/3kv//7v5P5NttsU7U9VcI0KgAAoNUoGwAAQBbKBgAAkIWyAQAAZKFsAAAAWXRq7Q3Uqu7duyfzbt26Zb/21ltvncyfeeaZZN6vX79k/tZbb1VrS9S4tdZaK+v6Bx10UNb1y5S9tyMi7rnnnmS+2mqrVXSNsnMyd+7cZL7bbrsl85dffrmi69J2fe9730vmN910UzIv+z39mmuuSebL471UNkGm0hwiIjp27JjMP/OZzyTzN998M5m356lTZZ566qmKHt+rV69MO8nHnQ0AACALZQMAAMhC2QAAALJQNgAAgCyUDQAAIAvTqEqMGDEimZdNFSlzww03JPNZs2aVPufoo49O5j169Ejmf/zjHytap2yKD23XFVdckcwbGxursn5rTVq67LLLSj+23nrrJfOy11w2derggw9O5jfffPPSN8cKa8GCBcn8jjvuqChvTZ06+fJP9ZxxxhnJvOz31z59+uTcTptS9me1Ms8//3yejWTkzgYAAJCFsgEAAGShbAAAAFkoGwAAQBbKBgAAkMUKP46ibKLNJZdcUpX1Tz311GT+9NNPlz6nd+/eyfxb3/pWMt9iiy2S+Re/+MVkbhoVlTr99NOT+ZFHHpnMFy9enMzLJpMMGTIkmW+zzTbN2N2SyiZY3Xjjjcn8/vvvr/ga0NaNGTOmtbdAG/SFL3whmZ9wwgnJ/L/+679ybqdNOfbYY5N5//79k/mbb76ZzMsmf9UydzYAAIAslA0AACALZQMAAMhC2QAAALJQNgAAgCxW+GlUK620UjJfffXVK1qnbMLTiy++WPGeJk2alMzLplGVGTt2bDI/88wzK94TtW3kyJHJ/NZbb63K+ttuu20y79Ah/f2KxsbGZD579uyKrjtixIjSj91+++0VrQW03K9//evW3gI1rCiKZN63b99kXjYJ9JlnnqnanlrLAQcckMzLpkiVfe4eeOCBZP7ggw+2bGOtyJ0NAAAgC2UDAADIQtkAAACyUDYAAIAslA0AACCLFX4aVbV07949me+xxx4Vr3Xuued+2u1ARJRPhWqt686ZMyeZjx8/PpnPmDGjansCWm7YsGHJ/Ec/+tFy3gmt6dFHH03m1113XTIfM2ZMMp82bVoyv+CCC5L51KlTk/nMmTOTednkww8++CCZL83GG2+czM8666xk/tWvfjWZd+7cOZlPnz49mVc6gbSWubMBAABkoWwAAABZKBsAAEAWygYAAJCFsgEAAGRhGlWVbLfddsn8hhtuWM47+T+XXnppq12b5etPf/pTMi+bonHNNdck87L3cZn58+cn8xdffDGZjxs3Lpk//PDDFV0XaJ4ddtghmW+00UYVrTNv3rxqbIc2rmya00EHHZTMy742nXfeecn81FNPTeZFUTRjd//nb3/7WzIv+5oVEVFXV5fM11577WTet2/fZF72OSqbwLX77rsn87lz5ybztsidDQAAIAtlAwAAyELZAAAAslA2AACALJQNAAAgi7qimT/iX/ZT+m1d586dk/lZZ52VzH/wgx/k3M5SLVq0KJn/+Mc/TuZlr+H999+v2p5qSaXTKnJoK+ekT58+yfyEE06oaJ0nn3wymV9++eUV74nlwzlZsZx55pnJ/KSTTkrmb775ZjIfPnx4Mp86dWrLNlbjauGcRLTfs7LWWmsl87L32Ze+9KWK1i+btrbNNtuUPqfscz1nzpxk/oc//CGZX3HFFcn8/vvvL712W9acs+LOBgAAkIWyAQAAZKFsAAAAWSgbAABAFsoGAACQxQo/japMx44dk/lBBx2UzE877bRk/tnPfrbiaz/wwAPJ/Iwzzkjmd955Z8XXaI9qYXrIinZOaHuckxVLpdOobr311mQ+atSoqu2pLaiFcxLhrFD7TKMCAABajbIBAABkoWwAAABZKBsAAEAWygYAAJBFp9beQK1avHhxMr/ssssqygGg1jz55JPJfOLEict5J0B7584GAACQhbIBAABkoWwAAABZKBsAAEAWygYAAJBFXVEURbMeWFeXey/wqTTzrZyVc0Ktc05g2WrhnEQ4K9S+5pwVdzYAAIAslA0AACALZQMAAMhC2QAAALJQNgAAgCyUDQAAIAtlAwAAyELZAAAAslA2AACALJQNAAAgC2UDAADIoq4oiqK1NwEAALQ/7mwAAABZKBsAAEAWygYAAJCFsgEAAGShbAAAAFkoGwAAQBbKBgAAkIWyAQAAZKFsAAAAWfw/SwyHsC5la/gAAAAASUVORK5CYII=\n" 85 | }, 86 | "metadata": {} 87 | } 88 | ] 89 | }, 90 | { 91 | "cell_type": "markdown", 92 | "source": [], 93 | "metadata": { 94 | "id": "mWPjnMrWPm8C" 95 | } 96 | }, 97 | { 98 | "cell_type": "code", 99 | "source": [ 100 | "# Step 3: Preprocessing Step: Normalization and Data Augmentation\n", 101 | "transform_train = transforms.Compose([\n", 102 | " transforms.RandomRotation(10), # Randomly rotate the image by 10 degrees\n", 103 | " transforms.RandomAffine(0, translate=(0.1, 0.1)), # Random translation\n", 104 | " transforms.ToTensor(),\n", 105 | " transforms.Normalize((0.5,), (0.5,)) # Normalize to range [-1, 1]\n", 106 | "])\n", 107 | "\n", 108 | "transform_test = transforms.Compose([\n", 109 | " transforms.ToTensor(),\n", 110 | " transforms.Normalize((0.5,), (0.5,)) # Normalize the same way for test set\n", 111 | "])" 112 | ], 113 | "metadata": { 114 | "id": "vRBLQe78AYkf" 115 | }, 116 | "execution_count": 19, 117 | "outputs": [] 118 | }, 119 | { 120 | "cell_type": "code", 121 | "source": [ 122 | "# Step 4: Load the MNIST dataset with preprocessing applied\n", 123 | "trainset = torchvision.datasets.MNIST(root='./data', train=True, transform=transform_train)\n", 124 | "trainloader = torch.utils.data.DataLoader(trainset, batch_size=64, shuffle=True)\n", 125 | "\n", 126 | "testset = torchvision.datasets.MNIST(root='./data', train=False, transform=transform_test)\n", 127 | "testloader = torch.utils.data.DataLoader(testset, batch_size=64, shuffle=False)\n", 128 | "\n", 129 | "# Visualize Some Preprocessed Images\n", 130 | "preprocessed_images, preprocessed_labels = next(iter(trainloader))\n", 131 | "show_images(preprocessed_images, preprocessed_labels, label_header=\"Preprocessed\")" 132 | ], 133 | "metadata": { 134 | "colab": { 135 | "base_uri": "https://localhost:8080/", 136 | "height": 771 137 | }, 138 | "id": "EvP-1L6s8pR4", 139 | "outputId": "2a1648b3-5647-4555-fa34-44903ce742aa" 140 | }, 141 | "execution_count": 20, 142 | "outputs": [ 143 | { 144 | "output_type": "display_data", 145 | "data": { 146 | "text/plain": [ 147 | "
" 148 | ], 149 | "image/png": "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/tq8devW2vzMmTPafPfu3drcVdhGBQAAAMBtGDYAAAAAGMGwAQAAAMAIhg0AAAAARjBsAAAAADDCz90FuJuzW6e2bt2qzV977TVt/vXXX2vzRYsWWV6jRYsW2vz555/X5myjgmlW2zh69epVwJUUnO+//96p4//2t78ZqgTIWWBgoOVj9957r1PnunbtmjY/cOCANrfadgXkpFy5ctp8zZo12jw6OtpkOTkaM2aMNrfaOmWlY8eO2txq65SV33//XZub3jp1O7izAQAAAMAIhg0AAAAARjBsAAAAADCCYQMAAACAEQwbAAAAAIzwuW1UcXFx2nz69Ona/O2339bmH374oTa32kZ18eLFPFT3p3Pnzjl1vIhIZGSk088BAPi26tWrWz42Z84cp861Z88ebf7kk09q8//+979OnR+FS9myZbX566+/rs3r1Kljshy5fv265WOlS5fW5lbbn6xY9aPV9kallFPn90bc2QAAAABgBMMGAAAAACMYNgAAAAAYwbABAAAAwAiGDQAAAABG+Nw2Kis//vijNrfasGHaggULLB/r0qWLNvf399fmVhsU8rPxCkD+HD161N0loJCqVKmS0885f/68Nn/ooYe0eU5bfAArVls0Y2JitLmrNjN9//332nzUqFGWz3F265QVq62omZmZLjm/N+LOBgAAAAAjGDYAAAAAGMGwAQAAAMAIhg0AAAAARjBsAAAAADCCYQMAAACAET63+nbt2rVO5e6yd+9ep59TtGhRbV6iRAltzupbIP+mT5/u1PGbNm0yVAmQsw0bNlg+9uGHH2pzqzWcO3bs0ObDhg1zui4UHsHBwdp8zpw52rxatWomy5H//Oc/2vybb75x2TVKlSqlzYcMGeKya/gK7mwAAAAAMIJhAwAAAIARDBsAAAAAjGDYAAAAAGAEwwYAAAAAI2xKKZWnA20207Xg/3nppZe0+fDhw7X5yy+/rM0nTZrkspq8QR4/lY2iT7xP8+bNtbmz26W85WNPnyAnn376qTaPj4/X5lZ90qJFC5fV5A6e0Cci3t8rEyZM0Objxo1zyfkvXLigzWNiYrT5kSNHnL5GlSpVtPnrr7+uza16xVk//fSTNu/QoYM2t3pfmJaXXuHOBgAAAAAjGDYAAAAAGMGwAQAAAMAIhg0AAAAARjBsAAAAADDCz90F+Iry5ctr85o1a2rzxx9/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\n" 150 | }, 151 | "metadata": {} 152 | } 153 | ] 154 | } 155 | ] 156 | } -------------------------------------------------------------------------------- /Project_Report.docx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Navdeep-04/Handwritten_Digit_Recognition_with_LeNet5_using_Pytorch/c1f88f375f685e5eaf946c6585bc9fc43b7d4932/Project_Report.docx -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Handwritten_Digit_Recognition_With_LeNet5_Using_Pytorch 2 | 3 | # Project Title 4 | Handwritten Digit Recognition with LeNet5 Model in PyTorch 5 | 6 | # Introduction 7 | Handwritten digit recognition is a fundamental problem in the field of computer vision and machine learning. In this project, we propose to implement the LeNet5 model using PyTorch to recognize handwritten digits from the MNIST dataset. The goal is to build an accurate digit recognition system that can classify digits with high accuracy. 8 | 9 | # Expected Deliverables 10 | 1. Implementation of various models for handwritten digit recognition, including MLP, CNN, and LeNet5. 11 | 2. Evaluation reports comparing the performance of different models in terms of accuracy and computational efficiency. 12 | 3. Visualizations of model predictions and evaluation metrics. 13 | 4. Documentation detailing the methodology, implementation details, and findings of the project 14 | --------------------------------------------------------------------------------