{"metadata":{"kernelspec":{"language":"python","display_name":"Python 3","name":"python3"},"language_info":{"name":"python","version":"3.11.13","mimetype":"text/x-python","codemirror_mode":{"name":"ipython","version":3},"pygments_lexer":"ipython3","nbconvert_exporter":"python","file_extension":".py"},"kaggle":{"accelerator":"nvidiaTeslaT4","dataSources":[{"sourceId":3649,"databundleVersionId":46718,"sourceType":"competition"}],"dockerImageVersionId":31089,"isInternetEnabled":true,"language":"python","sourceType":"notebook","isGpuEnabled":true}},"nbformat_minor":4,"nbformat":4,"cells":[{"cell_type":"markdown","source":"# **question 1**","metadata":{}},{"cell_type":"code","source":"# This Python 3 environment comes with many helpful analytics libraries installed\n# It is defined by the kaggle/python Docker image: https://github.com/kaggle/docker-python\n# For example, here's several helpful packages to load\n\nimport numpy as np # linear algebra\nimport pandas as pd # data processing, CSV file I/O (e.g. pd.read_csv)\n\n# Input data files are available in the read-only \"../input/\" directory\n# For example, running this (by clicking run or pressing Shift+Enter) will list all files under the input directory\n\nimport os\nfor dirname, _, filenames in os.walk('/kaggle/input'):\n    for filename in filenames:\n        print(os.path.join(dirname, filename))\n\n# You can write up to 20GB to the current directory (/kaggle/working/) that gets preserved as output when you create a version using \"Save & Run All\" \n# You can also write temporary files to /kaggle/temp/, but they won't be saved outside of the current session\n1","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-10-16T23:25:28.026534Z","iopub.execute_input":"2025-10-16T23:25:28.026751Z","iopub.status.idle":"2025-10-16T23:25:29.086631Z","shell.execute_reply.started":"2025-10-16T23:25:28.026728Z","shell.execute_reply":"2025-10-16T23:25:29.086059Z"}},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"created account on kaggle\n","metadata":{}},{"cell_type":"markdown","source":"downloading the dataset cifar10 ","metadata":{}},{"cell_type":"code","source":"!pip -q install py7zr\nimport py7zr\nimport glob\nimport shutil\n\n# Find archive\ncandidates = glob.glob('/kaggle/input/**/test.7z', recursive=True)\narchive_path = candidates[0]\n\nshutil.rmtree('test', ignore_errors=True)\nos.makedirs('test', exist_ok=True)\n\n#extracting all these to /test folder\nwith py7zr.SevenZipFile(archive_path, mode='r') as z:\n    z.extractall(path='test')","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-10-16T23:25:29.087312Z","iopub.execute_input":"2025-10-16T23:25:29.087606Z","iopub.status.idle":"2025-10-16T23:27:34.987678Z","shell.execute_reply.started":"2025-10-16T23:25:29.087588Z","shell.execute_reply":"2025-10-16T23:27:34.987039Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"\n#repeat for train set to path /train\ncandidates = glob.glob('/kaggle/input/**/train.7z', recursive=True)\narchive_path = candidates[0]\n\nshutil.rmtree('train', ignore_errors=True)\nos.makedirs('train', exist_ok=True)\nwith py7zr.SevenZipFile(archive_path, mode='r') as z:\n    z.extractall(path='train')\n\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-10-16T23:27:34.989277Z","iopub.execute_input":"2025-10-16T23:27:34.989606Z","iopub.status.idle":"2025-10-16T23:27:55.587865Z","shell.execute_reply.started":"2025-10-16T23:27:34.989586Z","shell.execute_reply":"2025-10-16T23:27:55.587329Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"import os\nimport torch\n\nfrom PIL import Image # For images\nfrom torch.utils.data import Dataset, DataLoader \nfrom torchvision import transforms # For data transformations\n\n#defining tramsforms\nCIFAR10_MEAN = (0.4914, 0.4822, 0.4465)\nCIFAR10_STD = (0.2023, 0.1994, 0.2010)\n\ntransform = transforms.Compose([transforms.ToTensor(), transforms.Normalize((0.5,0.5,0.5),(0.5,0.5,0.5))])\n\ntrain_transforms = transforms.Compose([\n    # Pad the image, then take a random 32x32 crop\n    transforms.RandomCrop(32, padding=4), \n    # Randomly flip the image horizontally (common for objects like cars, birds)\n    transforms.RandomHorizontalFlip(),\n    # Slightly change brightness, contrast, saturation\n    transforms.ColorJitter(brightness=0.2, contrast=0.2, saturation=0.2), \n    # Convert image to a PyTorch tensor\n    transforms.ToTensor(),\n    # Normalize with pre-calculated CIFAR-10 specific values\n    transforms.Normalize(CIFAR10_MEAN, CIFAR10_STD),\n])\n\n# 2. Transforms for the VALIDATION dataset (no augmentation, just normalization)\nval_transforms = transforms.Compose([\n    transforms.ToTensor(),\n    transforms.Normalize(CIFAR10_MEAN, CIFAR10_STD),\n])\n\nbatch_size = 4   \n\n#had to create a custom dataset to handle this data\n\nimport os\nfrom PIL import Image\nfrom torch.utils.data import Dataset\n\n\nlabels_df=pd.read_csv(\"../input/cifar-10/trainLabels.csv\", index_col=\"id\")\n\n\n#for train set into dataset obj\nclass myDataset(Dataset):\n    def __init__(self, labels_df=None, image_dir=\"train/train\", transform=None):\n        self.image_dir = image_dir\n        self.transform = transform\n        self.labels_df = labels_df\n        if self.labels_df is not None:\n            self.label_map = {label: idx for idx, label in enumerate(sorted(labels_df['label'].unique()))}\n\n    def __len__(self):\n        return len(self.labels_df) if self.labels_df is not None else len(os.listdir(self.image_dir))\n\n    def __getitem__(self, idx):\n        filename = f\"{idx + 1}.png\"\n        image_path = os.path.join(self.image_dir, filename)\n        image = Image.open(image_path).convert(\"RGB\")\n        if self.transform:\n            image = self.transform(image)\n\n        if self.labels_df is not None:\n            label = self.labels_df.iloc[idx]['label']\n            label = torch.tensor(self.label_map[label], dtype=torch.long)\n            return image, label\n        else:\n            return image","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-10-16T23:27:55.588504Z","iopub.execute_input":"2025-10-16T23:27:55.588704Z","iopub.status.idle":"2025-10-16T23:28:03.178967Z","shell.execute_reply.started":"2025-10-16T23:27:55.588687Z","shell.execute_reply":"2025-10-16T23:28:03.178435Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"train_dataset = myDataset(labels_df=labels_df,transform=train_transforms)\ntest_dataset = myDataset(image_dir=\"test/test\",transform=transform)\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-10-16T23:28:03.179740Z","iopub.execute_input":"2025-10-16T23:28:03.180028Z","iopub.status.idle":"2025-10-16T23:28:03.186891Z","shell.execute_reply.started":"2025-10-16T23:28:03.179978Z","shell.execute_reply":"2025-10-16T23:28:03.186233Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"import copy\nfrom torch.utils.data import random_split, DataLoader, Subset\n\n# 1. Load the full dataset (use train transforms as a starting point)\nfull_dataset = myDataset(labels_df=labels_df, image_dir=\"train/train\", transform=train_transforms)\n\n# 2. Perform the split\ntotal_size = len(full_dataset)\nval_size = int(total_size * 0.1) \ntrain_size = total_size - val_size\nlengths = [train_size, val_size]\n\n# This creates two Subset objects\ntrain_subset, val_subset_indices = random_split(\n    full_dataset, \n    lengths, \n    generator=torch.Generator().manual_seed(42)\n)\n\n# 3. Create a *separate copy* of the dataset for validation and apply the validation transforms\n# This is required because both Subset objects initially reference the SAME full_dataset object.\nval_dataset_final = copy.deepcopy(full_dataset)\nval_dataset_final.transform = val_transforms\n\n# Recreate the validation subset using the *newly copied* and transformed dataset instance\nval_subset = Subset(val_dataset_final, val_subset_indices.indices)\n\n# Note: The 'train_subset' still uses the original 'full_dataset' with 'train_transforms'\n\n# 4. Create DataLoaders (using BATCH_SIZE=32 is recommended for modern CNNs with BatchNorm)\nBATCH_SIZE = 4\n\ntrain_loader = DataLoader(train_subset, batch_size=BATCH_SIZE, shuffle=True)\nval_loader = DataLoader(val_subset, batch_size=BATCH_SIZE, shuffle=False)\ntest_loader = DataLoader(test_dataset, batch_size=BATCH_SIZE, shuffle=False)\n\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-10-16T23:28:03.188326Z","iopub.execute_input":"2025-10-16T23:28:03.188534Z","iopub.status.idle":"2025-10-16T23:28:03.225509Z","shell.execute_reply.started":"2025-10-16T23:28:03.188518Z","shell.execute_reply":"2025-10-16T23:28:03.224836Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"import matplotlib.pyplot as plt\nimport torchvision.transforms.functional as TF\n\ndef show_image_from_dataset(dataset, idx):\n    image, label = dataset[idx]\n\n    # If it's a tensor, convert back to PIL for display\n    if isinstance(image, torch.Tensor):\n        image = TF.to_pil_image(image)\n\n    plt.imshow(image)\n    plt.title(f\"Label: {label}\")\n    plt.axis('off')\n    plt.show()\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-10-16T23:28:03.226330Z","iopub.execute_input":"2025-10-16T23:28:03.226624Z","iopub.status.idle":"2025-10-16T23:28:03.231187Z","shell.execute_reply.started":"2025-10-16T23:28:03.226607Z","shell.execute_reply":"2025-10-16T23:28:03.230480Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"#for i in range(50,55):  # Check first 5\n#    show_image_from_dataset(train_dataset, i)\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-10-16T23:28:03.231853Z","iopub.execute_input":"2025-10-16T23:28:03.232064Z","iopub.status.idle":"2025-10-16T23:28:03.242083Z","shell.execute_reply.started":"2025-10-16T23:28:03.232046Z","shell.execute_reply":"2025-10-16T23:28:03.241526Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"\nimage, label = train_dataset[0]\nprint(\"Label:\", label)\nprint(\"Image size:\", image.size)  # If it's PIL","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-10-16T23:28:03.244568Z","iopub.execute_input":"2025-10-16T23:28:03.244776Z","iopub.status.idle":"2025-10-16T23:28:03.310613Z","shell.execute_reply.started":"2025-10-16T23:28:03.244756Z","shell.execute_reply":"2025-10-16T23:28:03.309932Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"#!ls test/test/\n\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-10-16T23:28:03.311494Z","iopub.execute_input":"2025-10-16T23:28:03.311727Z","iopub.status.idle":"2025-10-16T23:28:03.314548Z","shell.execute_reply.started":"2025-10-16T23:28:03.311709Z","shell.execute_reply":"2025-10-16T23:28:03.313955Z"}},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"data preprocessing (normalizing)","metadata":{}},{"cell_type":"code","source":"import matplotlib.pyplot as plt\nimport matplotlib.image as mpimg\n\ndef view_image(image_path):\n    \"\"\"\n    Loads and displays an image in a Kaggle notebook.\n\n    Args:\n        image_path (str): The file path to the image.\n    \"\"\"\n    try:\n        img = mpimg.imread(image_path)\n        plt.imshow(img)\n        plt.axis('off')  \n        plt.show()\n    except FileNotFoundError:\n        print(f\"Error: Image not found at {image_path}\")\n    except Exception as e:\n        print(f\"An error occurred while displaying the image: {e}\")\n        \n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-10-16T23:28:03.315205Z","iopub.execute_input":"2025-10-16T23:28:03.315433Z","iopub.status.idle":"2025-10-16T23:28:03.325709Z","shell.execute_reply.started":"2025-10-16T23:28:03.315414Z","shell.execute_reply":"2025-10-16T23:28:03.325062Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"import os\n\nimage_dir = 'train/train'\nfiles = sorted([f for f in os.listdir(image_dir) if f.endswith(('.png', '.jpg', '.jpeg'))])\nfor i, f in enumerate(files[:10]):\n    print(i, f)\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-10-16T23:28:03.326331Z","iopub.execute_input":"2025-10-16T23:28:03.326563Z","iopub.status.idle":"2025-10-16T23:28:03.376530Z","shell.execute_reply.started":"2025-10-16T23:28:03.326547Z","shell.execute_reply":"2025-10-16T23:28:03.376029Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"#val_curve = [10,15,16,30,40]\n\n#val_x = np.linspace(1, len(train_losses), len(val_curve))\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-10-16T23:28:03.377132Z","iopub.execute_input":"2025-10-16T23:28:03.377363Z","iopub.status.idle":"2025-10-16T23:28:03.380212Z","shell.execute_reply.started":"2025-10-16T23:28:03.377343Z","shell.execute_reply":"2025-10-16T23:28:03.379697Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"for x in range(100,106):\n    print(labels_df.iloc[x-1])\n    view_image(f\"train/train/{x}.png\")\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-10-16T23:28:03.380796Z","iopub.execute_input":"2025-10-16T23:28:03.380969Z","iopub.status.idle":"2025-10-16T23:28:03.650840Z","shell.execute_reply.started":"2025-10-16T23:28:03.380955Z","shell.execute_reply":"2025-10-16T23:28:03.650285Z"},"collapsed":true,"jupyter":{"outputs_hidden":true}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"#the normalization happened as transforms defined as a parameter during downloading the dataset\n\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-10-16T23:28:03.651553Z","iopub.execute_input":"2025-10-16T23:28:03.651813Z","iopub.status.idle":"2025-10-16T23:28:03.655068Z","shell.execute_reply.started":"2025-10-16T23:28:03.651784Z","shell.execute_reply":"2025-10-16T23:28:03.654451Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# Grab one batch from your train loader\ndataiter = iter(train_loader)\nimages, labels = next(dataiter)\n\nprint(\"Images shape:\", images.shape)\nprint(\"Labels shape:\", labels.shape)\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-10-16T23:28:03.655803Z","iopub.execute_input":"2025-10-16T23:28:03.656048Z","iopub.status.idle":"2025-10-16T23:28:03.680549Z","shell.execute_reply.started":"2025-10-16T23:28:03.656020Z","shell.execute_reply":"2025-10-16T23:28:03.680032Z"}},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"cnn model construction\n* input layer\n* conv 32 filters 3 kernel size ReLU activation\n* max2dpooling  2x2\n* flatten layer\n* linnear layer with 128 units and ReLU activation\n* output layer [10 units, softmax activation]\n  ","metadata":{}},{"cell_type":"code","source":"from torch import nn\n\n#myseqmodel = nn.Sequential(\n#    nn.Conv2d(3,32,3),\n#    nn.ReLU(),\n#    nn.MaxPool2d(2,2),\n#    nn.Flatten(),\n#    nn.Linear(32*15*15, 128),\n#    nn.ReLU(),\n#    nn.Linear(128,10),\n    #nn.Softmax(dim=1)\n#)\n\nmyseqmodel = nn.Sequential(\n     # Stage 1\n    nn.Conv2d(3, 32, 3, padding=1),\n    nn.BatchNorm2d(32), # Added Batch Normalization\n    nn.ReLU(),\n    nn.MaxPool2d(2, 2), # Output size: 16x16\n\n    # Stage 2\n    nn.Conv2d(32, 64, 3, padding=1),\n    nn.BatchNorm2d(64),\n    nn.ReLU(),\n    nn.MaxPool2d(2, 2), # Output size: 8x8\n\n    # Stage 3\n    nn.Conv2d(64, 128, 3, padding=1),\n    nn.BatchNorm2d(128),\n    nn.ReLU(),\n    nn.MaxPool2d(2, 2), # Output size: 4x4\n    \n    # Stage 4 (Adding another stage for more depth, within sequential limits)\n    nn.Conv2d(128, 256, 3, padding=1),\n    nn.BatchNorm2d(256),\n    nn.ReLU(),\n    nn.MaxPool2d(2, 2), # Output size: 2x2. We must adjust the linear layer input size below.\n\n    nn.Flatten(),\n  \n    nn.Linear(256 * 2 * 2, 512), \n    nn.BatchNorm1d(512),\n    nn.ReLU(),\n    nn.Dropout(0.5),\n    nn.Linear(512, 10)\n)\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-10-16T23:28:03.681225Z","iopub.execute_input":"2025-10-16T23:28:03.681490Z","iopub.status.idle":"2025-10-16T23:28:03.696527Z","shell.execute_reply.started":"2025-10-16T23:28:03.681474Z","shell.execute_reply":"2025-10-16T23:28:03.695986Z"}},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"training\n* crossentropy loss\n* adam optimizer\n* 10 epochs\n* display the loss on training and validation data\n  ","metadata":{}},{"cell_type":"code","source":"#defining the above parameters\nimport torch\nfrom torch import optim\nepochs = 50\ncriterion = nn.CrossEntropyLoss()\noptimizer = optim.Adam(myseqmodel.parameters(), lr=0.005)\n\n\n\ntrain_losses, val_losses = [], []\ntrain_accs, val_accs = [], []\nval_aucs = []\n\n\ndevice= torch.device(\"cuda\")\nmyseqmodel.to(device)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-10-16T23:28:03.697336Z","iopub.execute_input":"2025-10-16T23:28:03.697614Z","iopub.status.idle":"2025-10-16T23:28:03.966048Z","shell.execute_reply.started":"2025-10-16T23:28:03.697596Z","shell.execute_reply":"2025-10-16T23:28:03.965333Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"","metadata":{"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"code","source":"\n#training loop\n\n\n\nfor epoch in range(epochs):\n\n    myseqmodel.train()\n    \n    running_loss, correct,total= 0.0,0,0\n    val_running_loss, val_correct, val_total = 0.0, 0, 0 \n    for  inputs, labels in train_loader:\n        \n        inputs, labels = inputs.to(device),labels.to(device)\n\n        #zero gradients\n        optimizer.zero_grad()\n\n        #forward pass\n        outputs = myseqmodel(inputs)\n\n        #compute loss\n        loss = criterion(outputs, labels)\n\n        #backward + optimize\n        loss.backward()\n\n        #update weights\n        optimizer.step()\n        \n        running_loss += loss.item()\n\n        _,predicted = outputs.max(1) #highest probability class\n        total += labels.size(0)\n        correct += predicted.eq(labels).sum().item()\n\n\n    train_loss = running_loss / len(train_loader)\n    train_acc = 100 * correct / total\n    train_losses.append(train_loss)\n    train_accs.append(train_acc)\n\n    #validation\n    myseqmodel.eval()\n\n    with torch.no_grad():\n        for inputs,labels in val_loader:\n            inputs, labels = inputs.to(device), labels.to(device)\n\n            outputs = myseqmodel(inputs)\n            loss = criterion(outputs, labels)\n            val_running_loss += loss.item()\n            _,predicted = outputs.max(1)\n            val_total += labels.size(0)\n            val_correct+= predicted.eq(labels).sum().item()\n\n    epoch_val_loss= val_running_loss / len(val_loader)\n    epoch_val_acc = 100* val_correct / val_total\n    val_losses.append(epoch_val_loss)\n    val_accs.append(epoch_val_acc)\n\n    print(f\"Epoch {epoch+1}/{epochs} | Tr Loss: {train_loss:.4f} - Tr Acc: {train_acc:.2f}% | Val Loss: {epoch_val_loss:.4f} - Val Acc: {epoch_val_acc:.2f}%\")\n\n\n        \nprint(\"training finished\")\n        ","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-10-16T23:28:03.966841Z","iopub.execute_input":"2025-10-16T23:28:03.967361Z"}},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"evaluation\n* plot the training and validation accuracy/loss over epochs\n* report the test accuracy on the test set","metadata":{}},{"cell_type":"code","source":"\n#plt.plot(train_accs, label='Train Accuracy')\n\n#plt.plot(val_x, val_curve, label='Validation accuracy', color='red')\n\n#plt.legend(); plt.show()\n","metadata":{"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"code","source":"\"\"\"\nmyseqmodel.eval()   #evaluation mode\nrunning_loss, correct, total, val_loss = 0,0,0,0\nall_probs, all_labels=[],[]\n\n\nwith torch.no_grad():\n    for inputs in test_loader:\n        inputs = inputs.to(device)\n        outputs = myseqmodel(inputs)\n        _, predicted = torch.max(outputs, 1)\n        \n        \n        val_loss +=loss.item()\n        _,predicted = outputs.max(1)\n        total+=labels.size(0)\n        correct+= predicted.eq(labels).sum().item()\n\n    val_loss = running_loss / len(test_loader)\n    val_acc = 100 * correct / total\n    val_losses.append(val_loss)\n    val_accs.append(val_acc)\n    \"\"\"","metadata":{"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"code","source":"print(predicted.shape, labels.shape)\n","metadata":{"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"code","source":"batch = next(iter(test_loader))\nprint(type(batch))\nprint(len(batch))\n\n","metadata":{"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"code","source":"\n# Inference\n\ndevice = torch.device(\"cuda\" if torch.cuda.is_available() else \"cpu\")\nmyseqmodel = myseqmodel.to(device)  # \nmyseqmodel.eval()\n\npredictions = []\nimage_ids = list(range(1, len(predictions) + 1))\n\n\nwith torch.no_grad():\n    for images in test_loader:  # only one output\n        images = images.to(device)\n        outputs = myseqmodel(images)\n        _, preds = torch.max(outputs, 1)\n        predictions.extend(preds.cpu().numpy())\n\n# map back to labels\nidx_to_label = {v: k for k, v in train_dataset.label_map.items()}\n\n","metadata":{"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# Build sequential IDs to match predictions\nimage_ids = list(range(1, len(predictions) + 1))\n\n# Map prediction indices to class labels\nlabels = [idx_to_label[int(p)] for p in predictions]\n\n# Create submission DataFrame\nsubmission = pd.DataFrame({\n    \"id\": image_ids,\n    \"label\": labels\n})\n\n# Save to CSV\nsubmission.to_csv(\"submission.csv\", index=False)\n\nsubmission","metadata":{"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"code","source":"submission.label.value_counts()","metadata":{"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"code","source":"print(\"Predictions:\", len(predictions))\nprint(\"Image IDs:\", len(image_ids))\n","metadata":{"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"code","source":"import matplotlib.pyplot as plt\nimport numpy as np \n\n# --- Start of the corrected plotting script ---\n\n# DYNAMICALLY determine how many epochs actually completed based on the shortest list\nactual_epochs_completed = min(len(train_losses), len(val_losses), len(train_accs), len(val_accs))\n\nepochs_range = range(1, actual_epochs_completed + 1)\n\n# Ensure all lists match this length exactly before plotting\ntrain_losses = train_losses[:actual_epochs_completed]\nval_losses = val_losses[:actual_epochs_completed]\ntrain_accs = train_accs[:actual_epochs_completed]\nval_accs = val_accs[:actual_epochs_completed]\n\n\n# Plot Loss (this will now work correctly)\nplt.figure(figsize=(12, 5))\nplt.subplot(1, 2, 1)\nplt.plot(epochs_range, train_losses, label='Training Loss')\nplt.plot(epochs_range, val_losses, label='Validation Loss')\nplt.title('Loss over Epochs')\nplt.xlabel('Epoch')\nplt.ylabel('Loss')\nplt.legend()\nplt.grid(True)\n\n# Plot Accuracy (this will also work correctly now)\nplt.subplot(1, 2, 2)\nplt.plot(epochs_range, train_accs, label='Training Accuracy')\nplt.plot(epochs_range, val_accs, label='Validation Accuracy')\nplt.title('Accuracy over Epochs')\nplt.xlabel('Epoch')\nplt.ylabel('Accuracy (%)')\nplt.legend()\nplt.grid(True)\n\nplt.tight_layout()\nplt.show()\n\n","metadata":{"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"submission\n* save the trained model\n* generate predfictions on the test data\n* submit your predictions to the competition\n* record your score","metadata":{}},{"cell_type":"code","source":"torch.save(myseqmodel.state_dict(), \"seqmodelv1.pth\")\n\"model saved\"","metadata":{"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"deliverables 7th october\n* link to kaggle submission\n* python code\n* explanation of how the cnn model works, architecture and performance","metadata":{}},{"cell_type":"markdown","source":"# **question 2**","metadata":{}},{"cell_type":"markdown","source":"# **summarize the components of a cnn**\n","metadata":{}},{"cell_type":"markdown","source":"**convolution layer**","metadata":{}},{"cell_type":"markdown","source":"This is the core building block of a CNN. It performs the feature extraction.\nFunction: Applies a set of learnable filters (kernels) to the input image. Each filter slides over the image, performing a dot product with the local pixels it covers.\nPurpose: Detects features such as edges, textures, corners, or specific shapes. As the network deepens, later convolution layers detect more complex patterns built from the simpler features detected in earlier layers.\nKey Hyperparameters:\nKernel Size: The spatial extent of the filter (e.g., 3x3 or 5x5).\nStride: The number of pixels the filter shifts across the image after each operation.\nPadding: Adding extra pixels around the image border to control the spatial size of the output feature map. ","metadata":{}},{"cell_type":"markdown","source":"**pooling layer**","metadata":{}},{"cell_type":"markdown","source":"Pooling layers perform down-sampling on the feature maps produced by the convolution layers.\nFunction: Reduces the spatial dimensions (height and width) of the feature map while keeping the depth (number of channels) unchanged.\nPurpose:\nReduces computation: Fewer parameters need to be processed in subsequent layers.\nProvides translational invariance: Makes the model slightly robust to where a feature appears in the image (e.g., a cat is a cat whether it's in the top left or center of the frame).\nCommon Type: Max Pooling, which takes the maximum value from the window it covers (e.g., a 2x2 window with a stride of 2).","metadata":{}},{"cell_type":"markdown","source":"**fully connected layer**","metadata":{}},{"cell_type":"markdown","source":"These layers are typically added at the end of the CNN architecture.\nFunction: Takes the high-level features extracted by the convolution and pooling layers and flattens them into a single vector.\nPurpose: Uses these aggregated features to perform the final classification task (e.g., determining the probability that the image is a car, a dog, or a plane). ","metadata":{}},{"cell_type":"markdown","source":"# **describe the full architecture of a cnn**","metadata":{}},{"cell_type":"markdown","source":"explain how cnns are applied to image recognition. specifically how they detect objects in images","metadata":{}},{"cell_type":"markdown","source":"1. Input: The Image as Numbers\n\nEvery image is a grid of pixel values.\n\nA color image (RGB) is a 3D tensor: height × width × 3 (for red, green, blue channels).\n\nExample: a 256×256×3 image is just 196,608 numbers.\n\nCNNs don’t see cats or cars — they see this numeric grid and learn patterns through layers.\n\n2. Convolutional Layers: Pattern Detectors\n\nThe convolution operation is the foundation.\nIt works like a small window (a filter or kernel) sliding across the image.\n\nEach filter learns to detect a specific visual pattern — for example:\n\nEdges (horizontal, vertical)\n\nCorners\n\nColor transitions\n\nLater layers: textures, shapes, object parts\n\nMathematically, each filter is a matrix that’s multiplied and summed with a small region of the image. The output is a feature map, showing where that pattern appears.\n\nOver many layers, the CNN builds a hierarchy:\n\nEarly layers → local low-level features (edges, gradients)\n\nMid layers → object parts (eyes, wheels, leaves)\n\nDeep layers → abstract concepts (faces, animals, cars)\n\nThis hierarchy is key: CNNs compose complexity.\n\n3. Activation Functions: Nonlinear Perception\n\nAfter each convolution, a nonlinear function (usually ReLU) is applied:\n\nf(x)=max(0,x)\n\nThis helps the network capture nonlinear relationships — real-world patterns aren’t just linear.\n\n4. Pooling Layers: Spatial Reduction\n\nPooling layers (like max pooling) compress feature maps:\n\nA 2×2 max-pool takes the largest value in each small region.\n\nThis reduces spatial size but keeps the most important information.\n\nResult: fewer parameters, less computation, and more robustness to shifts (so the network doesn’t panic if a cat’s ear moves two pixels to the left).\n\n5. Deep Feature Hierarchies\n\nStacking multiple convolution + activation + pooling layers creates deep feature hierarchies:\n\nLayer 1 might detect edges.\n\nLayer 5 might respond strongly to “eye-like” patterns.\n\nLayer 10 might respond to “face-like” arrangements of eyes and nose.\n\nEach neuron in deeper layers has a receptive field that corresponds to a larger region of the original image. Eventually, entire objects can be represented.\n\n6. Fully Connected Layers: Decision Making\n\nAfter all that spatial feature extraction, the CNN flattens the feature maps and feeds them into fully connected (dense) layers.\nThese act as a classifier:\n\nThey interpret “what” the detected patterns likely mean.\n\nExample: high activation for “fur texture + whisker shape + ear pattern” → “cat”.\n\nThe final layer (usually a softmax) outputs probabilities for each possible class.\n\n7. Backpropagation: Learning What to See\n\nDuring training:\n\nThe CNN makes predictions on labeled images.\n\nThe loss (error) between prediction and ground truth is computed.\n\nGradients flow backward, adjusting filter weights so they better detect relevant features.\n\nOver many iterations, the CNN learns filters that specialize in detecting meaningful structures across thousands of examples.\n\n8. Object Detection (vs. Classification)\n\nBasic CNNs classify the entire image (e.g., “there’s a cat somewhere”).\nFor object detection (locating multiple objects), CNNs are extended with architectures like:\n\nR-CNN, Fast/Faster R-CNN: region proposals + classification.\n\nYOLO (You Only Look Once): predicts bounding boxes and labels in one pass.\n\nSSD (Single Shot Multibox Detector): similar to YOLO but with multi-scale feature maps.\n\nThese models output not only what objects are present but also where they are — bounding boxes around each one.","metadata":{}},{"cell_type":"markdown","source":"visualization. sketch a basic cnn architecture used for image classification indicating the flow of data through convolution, pooling, and fully connected layers ","metadata":{}},{"cell_type":"markdown","source":"differences between cnns and traditional feed forward neural network","metadata":{}},{"cell_type":"markdown","source":"# **question 3**\nbuild a simple feed forward neural network to classify the mnist handwritten digits dataset","metadata":{}},{"cell_type":"markdown","source":"load and preprocess the dataset \n* normalize\n* split into train and test sets","metadata":{}},{"cell_type":"markdown","source":"model architecture\n* feed forward neural network\n* input layer\n* one hidden layer eg [128 neurons and ReLU]\n* output layer with 10 neurons for each digit 0-9\n* using softmax","metadata":{}},{"cell_type":"markdown","source":"training \n* sdg optimizer\n* cross entropy loss function\n* 5 epochs\n","metadata":{}},{"cell_type":"markdown","source":"evaluation:  record accuracy and loss during printing\n  ","metadata":{}},{"cell_type":"markdown","source":"report final accuracy and suggest improvements to the model architecture (eg modifying hidden layer numbers, increasing neurons, experimenting with different optimizers)","metadata":{}},{"cell_type":"code","source":"","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-11-04T06:37:19.721942Z","iopub.execute_input":"2025-11-04T06:37:19.722155Z","iopub.status.idle":"2025-11-04T06:38:31.001799Z","shell.execute_reply.started":"2025-11-04T06:37:19.722117Z","shell.execute_reply":"2025-11-04T06:38:31.001007Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# MNIST Feedforward Network in PyTorch\nimport torch\nimport torch.nn as nn\nimport torch.optim as optim\nfrom torchvision import datasets, transforms\nfrom torch.utils.data import DataLoader\nimport matplotlib.pyplot as plt\nfrom sklearn.metrics import confusion_matrix, ConfusionMatrixDisplay\nimport numpy as np\n\n# 1. Data loading & normalization\ntransform = transforms.Compose([\n    transforms.ToTensor(),\n    transforms.Normalize((0.1307,), (0.3081,))\n])\ntrain_dataset = datasets.MNIST(root='./data', train=True, transform=transform, download=True)\ntest_dataset  = datasets.MNIST(root='./data', train=False, transform=transform, download=True)\ntrain_loader = DataLoader(train_dataset, batch_size=64, shuffle=True)\ntest_loader  = DataLoader(test_dataset, batch_size=1000, shuffle=False)\n\n# 2. Model definition\nclass FeedForwardNet(nn.Module):\n    def __init__(self):\n        super().__init__()\n        self.fc1 = nn.Linear(28*28, 128)\n        self.relu = nn.ReLU()\n        self.fc2 = nn.Linear(128, 10)\n        self.softmax = nn.Softmax(dim=1)\n    def forward(self, x):\n        x = x.view(-1, 28*28)\n        x = self.relu(self.fc1(x))\n        x = self.softmax(self.fc2(x))\n        return x\n\nmodel = FeedForwardNet()\ncriterion = nn.CrossEntropyLoss()\noptimizer = optim.SGD(model.parameters(), lr=0.01)\nepochs = 5\n\ntrain_losses, test_losses, train_accs, test_accs = [], [], [], []\n\n# 3. Training loop\nfor epoch in range(epochs):\n    model.train()\n    correct, total, train_loss = 0, 0, 0\n    for images, labels in train_loader:\n        optimizer.zero_grad()\n        outputs = model(images)\n        loss = criterion(outputs, labels)\n        loss.backward()\n        optimizer.step()\n        train_loss += loss.item()\n        _, predicted = outputs.max(1)\n        total += labels.size(0)\n        correct += (predicted == labels).sum().item()\n    train_acc = 100 * correct / total\n    train_losses.append(train_loss / len(train_loader))\n    train_accs.append(train_acc)\n\n    # Evaluation\n    model.eval()\n    correct, total, test_loss = 0, 0, 0\n    with torch.no_grad():\n        for images, labels in test_loader:\n            outputs = model(images)\n            loss = criterion(outputs, labels)\n            test_loss += loss.item()\n            _, predicted = outputs.max(1)\n            total += labels.size(0)\n            correct += (predicted == labels).sum().item()\n    test_acc = 100 * correct / total\n    test_losses.append(test_loss / len(test_loader))\n    test_accs.append(test_acc)\n\n    print(f\"Epoch [{epoch+1}/{epochs}] \"\n          f\"Train Loss: {train_losses[-1]:.4f}, Acc: {train_acc:.2f}% | \"\n          f\"Test Loss: {test_losses[-1]:.4f}, Acc: {test_acc:.2f}%\")\n\n# 4. Final accuracy\nprint(f\"\\nFinal Test Accuracy: {test_accs[-1]:.2f}%\")\n\n# 5. Suggestions for improvement\nprint(\"\"\"\nModel Improvement Suggestions:\n- Add more hidden layers or increase neurons.\n- Try Adam optimizer for adaptive learning.\n- Add Dropout or BatchNorm to prevent overfitting.\n- Use more epochs or learning rate scheduling.\n- Consider CNNs for spatial pattern recognition.\n\"\"\")\n\n# 6. Visualization\n# Loss and Accuracy\nplt.figure(figsize=(10,4))\nplt.subplot(1,2,1)\nplt.plot(train_losses, label='Train Loss')\nplt.plot(test_losses, label='Test Loss')\nplt.title('Loss Curve'); plt.legend()\n\nplt.subplot(1,2,2)\nplt.plot(train_accs, label='Train Accuracy')\nplt.plot(test_accs, label='Test Accuracy')\nplt.title('Accuracy Curve'); plt.legend()\nplt.show()\n\n# Confusion Matrix\nmodel.eval()\nall_preds, all_labels = [], []\nwith torch.no_grad():\n    for images, labels in test_loader:\n        preds = model(images).argmax(dim=1)\n        all_preds.extend(preds.cpu().numpy())\n        all_labels.extend(labels.cpu().numpy())\n\ncm = confusion_matrix(all_labels, all_preds)\nConfusionMatrixDisplay(cm, display_labels=range(10)).plot(cmap='Blues')\nplt.title(\"Confusion Matrix\")\nplt.show()\n\n# Show sample predictions\nfig, axes = plt.subplots(2,5, figsize=(10,4))\nfor i, ax in enumerate(axes.flat):\n    img, label = test_dataset[i]\n    with torch.no_grad():\n        pred = model(img.unsqueeze(0)).argmax(dim=1).item()\n    ax.imshow(img.squeeze(), cmap='gray')\n    ax.set_title(f\"T:{label}, P:{pred}\")\n    ax.axis('off')\nplt.show()\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-11-04T06:42:18.389661Z","iopub.execute_input":"2025-11-04T06:42:18.390255Z","iopub.status.idle":"2025-11-04T06:43:29.501648Z","shell.execute_reply.started":"2025-11-04T06:42:18.390228Z","shell.execute_reply":"2025-11-04T06:43:29.501038Z"}},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"# **question 4**","metadata":{}},{"cell_type":"markdown","source":"demonstrate how activation functions can mimic logical functions \n\n\na neuron with two binary inputs x1 and x2, \n\nequal weights w1=w2=1 \n\nand a bias b=-15\n\n","metadata":{}},{"cell_type":"markdown","source":"constreuct a truth table of the neuron when the step (threshold function is applied. \nWhat logical gate does this neuron implement?","metadata":{}},{"cell_type":"markdown","source":"replace the step function with the sigmoid activation function. using inputs (0,0), (0,1), (1,0), (1,1) compute the output values and comment on how the truth table differs from the step function case\n","metadata":{}},{"cell_type":"markdown","source":"discuss why continous activation functions\n* sigmoid\n* tanh\n* ReLU\n  are preferred over step functions in training deep neural networks","metadata":{}}]}