{
 "cells": [
  {
   "cell_type": "markdown",
   "id": "a5a8f05e",
   "metadata": {},
   "source": [
    "## Question 4 (10 marks)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 1,
   "id": "8ddab76f",
   "metadata": {},
   "outputs": [],
   "source": [
    "import torch\n",
    "from ca_utils import ResNet, BasicBlock"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "id": "b52a47c6",
   "metadata": {},
   "outputs": [],
   "source": [
    "model = ResNet(block=BasicBlock, layers=[1, 1, 1], num_classes=10)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "15a25e00",
   "metadata": {},
   "source": [
    "### Load the Model"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "id": "af4de07b",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "ResNet(\n",
       "  (conv1): Conv2d(3, 16, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1), bias=False)\n",
       "  (bn1): BatchNorm2d(16, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)\n",
       "  (relu): ReLU(inplace=True)\n",
       "  (layer1): Sequential(\n",
       "    (0): BasicBlock(\n",
       "      (conv1): Conv2d(16, 16, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1), bias=False)\n",
       "      (bn1): BatchNorm2d(16, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)\n",
       "      (relu): ReLU(inplace=True)\n",
       "      (conv2): Conv2d(16, 16, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1), bias=False)\n",
       "      (bn2): BatchNorm2d(16, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)\n",
       "    )\n",
       "  )\n",
       "  (layer2): Sequential(\n",
       "    (0): BasicBlock(\n",
       "      (conv1): Conv2d(16, 32, kernel_size=(3, 3), stride=(2, 2), padding=(1, 1), bias=False)\n",
       "      (bn1): BatchNorm2d(32, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)\n",
       "      (relu): ReLU(inplace=True)\n",
       "      (conv2): Conv2d(32, 32, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1), bias=False)\n",
       "      (bn2): BatchNorm2d(32, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)\n",
       "      (downsample): Sequential(\n",
       "        (0): Conv2d(16, 32, kernel_size=(1, 1), stride=(2, 2), bias=False)\n",
       "        (1): BatchNorm2d(32, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)\n",
       "      )\n",
       "    )\n",
       "  )\n",
       "  (layer3): Sequential(\n",
       "    (0): BasicBlock(\n",
       "      (conv1): Conv2d(32, 64, kernel_size=(3, 3), stride=(2, 2), padding=(1, 1), bias=False)\n",
       "      (bn1): BatchNorm2d(64, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)\n",
       "      (relu): ReLU(inplace=True)\n",
       "      (conv2): Conv2d(64, 64, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1), bias=False)\n",
       "      (bn2): BatchNorm2d(64, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)\n",
       "      (downsample): Sequential(\n",
       "        (0): Conv2d(32, 64, kernel_size=(1, 1), stride=(2, 2), bias=False)\n",
       "        (1): BatchNorm2d(64, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)\n",
       "      )\n",
       "    )\n",
       "  )\n",
       "  (avgpool): AdaptiveAvgPool2d(output_size=1)\n",
       "  (fc): Linear(in_features=64, out_features=10, bias=True)\n",
       ")"
      ]
     },
     "execution_count": 3,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "checkpoint = torch.load(\"data/weights_resnet.pth\")\n",
    "model.load_state_dict(checkpoint)\n",
    "model.eval()"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "98c03b18",
   "metadata": {},
   "source": [
    "## Question 5 (15 marks)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "id": "3024a7a8",
   "metadata": {},
   "outputs": [],
   "source": [
    "import torchvision\n",
    "from torch.utils.data import DataLoader\n",
    "from torchvision import transforms"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 5,
   "id": "357891cd",
   "metadata": {
    "scrolled": false
   },
   "outputs": [],
   "source": [
    "image_transform = transforms.Compose(\n",
    "    [transforms.ToTensor(), transforms.Normalize((0.5, 0.5, 0.5), (0.5, 0.5, 0.5))])\n",
    "\n",
    "test_data = torchvision.datasets.ImageFolder('data/EXCV10/val/', transform=image_transform)\n",
    "test_loader = DataLoader(test_data, batch_size=64, shuffle=False, num_workers=4, pin_memory=True)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "0eb07988",
   "metadata": {},
   "source": [
    "## Method 1"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 6,
   "id": "b9d88037",
   "metadata": {},
   "outputs": [],
   "source": [
    "import numpy as np"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 7,
   "id": "6a30d88c",
   "metadata": {},
   "outputs": [],
   "source": [
    "def m1_test_cnn(model, test_loader):\n",
    "    device = torch.device('cuda' if torch.cuda.is_available() else 'cpu')\n",
    "    model.to(device)\n",
    "    model.eval()\n",
    "    correct = 0\n",
    "    total = 0\n",
    "    all_predicted_labels = []\n",
    "\n",
    "    with torch.no_grad():\n",
    "        for images, labels in test_loader:\n",
    "            images, labels = images.to(device), labels.to(device)\n",
    "            outputs = model(images)\n",
    "            _, predicted = torch.max(outputs.data, 1)\n",
    "            total += labels.size(0)\n",
    "            correct += (predicted == labels).sum().item()\n",
    "            all_predicted_labels.append(predicted.cpu().numpy())\n",
    "    accuracy = 100 * correct / total\n",
    "    all_predicted_labels = np.concatenate(all_predicted_labels)\n",
    "    return all_predicted_labels, accuracy"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 8,
   "id": "3fcb0a3a",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Test Accuracy: 67.85%\n"
     ]
    }
   ],
   "source": [
    "m1_predicted_labels, m1_test_accuracy = m1_test_cnn(model, test_loader)\n",
    "print(f'Test Accuracy: {m1_test_accuracy}%')"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "75272741",
   "metadata": {},
   "source": [
    "### Put Students' implementations here"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 9,
   "id": "47bd1202",
   "metadata": {},
   "outputs": [],
   "source": [
    "def test_cnn(model, test_loader):\n",
    "    all_predicted_labels, accuracy = 0, 0\n",
    "\n",
    "    return all_predicted_labels, accuracy"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 10,
   "id": "1b0db3bd",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Test Accuracy: 0%\n"
     ]
    }
   ],
   "source": [
    "predicted_labels, test_accuracy = test_cnn(model, test_loader)\n",
    "print(f'Test Accuracy: {test_accuracy}%')"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "cef7dc17",
   "metadata": {},
   "source": [
    "## Question 6 (6 marks)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 11,
   "id": "0990f3b2",
   "metadata": {},
   "outputs": [],
   "source": [
    "true_labels = []\n",
    "device = torch.device('cuda' if torch.cuda.is_available() else 'cpu')\n",
    "\n",
    "for images, labels in test_loader:\n",
    "    images, labels = images.to(device), labels.to(device)\n",
    "    true_labels.extend(labels.cpu().numpy())\n",
    "    \n",
    "true_labels = np.array(true_labels)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 12,
   "id": "8da35032",
   "metadata": {},
   "outputs": [],
   "source": [
    "def compute_confusion_matrix(true, predictions):\n",
    "    unique_labels = np.unique(np.concatenate((true, predictions)))\n",
    "\n",
    "    confusion_mat = np.zeros((len(unique_labels), len(unique_labels)), dtype=np.int64)\n",
    "\n",
    "    label_to_index = {label: index for index,\n",
    "                      label in enumerate(unique_labels)}\n",
    "\n",
    "    for t, p in zip(true, predictions):\n",
    "        t_index = label_to_index[t]\n",
    "        p_index = label_to_index[p]\n",
    "        confusion_mat[t_index][p_index] += 1\n",
    "\n",
    "    return confusion_mat"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 14,
   "id": "16b6f9e7",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "array([[168,   2,   5,   0,   6,   0,   2,   0,   6,  11],\n",
       "       [ 13, 108,   2,  18,  29,  16,   1,  13,   0,   0],\n",
       "       [  1,   1, 162,   0,   1,   0,   7,   0,   0,  28],\n",
       "       [  0,   7,   2,  74,  46,  40,   2,  26,   1,   2],\n",
       "       [  1,   2,   2,   6, 166,   9,   6,   8,   0,   0],\n",
       "       [  1,   3,   0,  11,  37, 108,  27,  12,   1,   0],\n",
       "       [  1,   0,   1,   0,  40,  30, 121,   4,   0,   3],\n",
       "       [  1,   7,   1,   6,  32,  24,   2, 127,   0,   0],\n",
       "       [ 11,   1,   2,   2,   1,   1,   0,   0, 153,  29],\n",
       "       [  4,   0,  13,   2,   5,   0,   1,   0,   5, 170]], dtype=int64)"
      ]
     },
     "execution_count": 14,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "compute_confusion_matrix(true_labels, m1_predicted_labels)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "1dce952c",
   "metadata": {},
   "outputs": [],
   "source": []
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "what",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.8.16"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 5
}
