{
 "cells": [
  {
   "cell_type": "code",
   "execution_count": 1,
   "id": "54b3b908-05a3-45e7-a924-733a5d6f23b5",
   "metadata": {},
   "outputs": [
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "/opt/anaconda3/envs/yt38/lib/python3.8/site-packages/tqdm/auto.py:21: TqdmWarning: IProgress not found. Please update jupyter and ipywidgets. See https://ipywidgets.readthedocs.io/en/stable/user_install.html\n",
      "  from .autonotebook import tqdm as notebook_tqdm\n"
     ]
    }
   ],
   "source": [
    "import torch\n",
    "import torchvision.transforms as transforms\n",
    "from torchvision.datasets import ImageFolder\n",
    "from torch.utils.data import DataLoader\n",
    "import natsort\n",
    "import pandas as pd\n",
    "\n",
    "from torch.utils.data import random_split\n",
    "\n",
    "# Define transformations\n",
    "transform = transforms.Compose([\n",
    "    transforms.Resize((128, 128)),\n",
    "    transforms.RandomHorizontalFlip(),\n",
    "    transforms.ToTensor(),\n",
    "    transforms.Normalize(mean=[0.5, 0.5, 0.5], std=[0.5, 0.5, 0.5])\n",
    "])\n",
    "\n",
    "# Load datasets\n",
    "dataset = ImageFolder(root='image_dataset/train', transform=transform)\n",
    "\n",
    "# Split the dataset into training and validation sets\n",
    "train_size = int(0.8 * len(dataset))\n",
    "val_size = len(dataset) - train_size\n",
    "train_dataset, val_dataset = random_split(dataset, [train_size, val_size])\n",
    "\n",
    "train_loader = DataLoader(train_dataset, batch_size=32, shuffle=True, num_workers=4)\n",
    "val_loader = DataLoader(val_dataset, batch_size=32, shuffle=False, num_workers=4)\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "7b1c1e9d-d182-4e1b-8798-e999688365b8",
   "metadata": {},
   "outputs": [],
   "source": []
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "id": "636e31e8-74f7-41a2-aff3-b879079039e2",
   "metadata": {},
   "outputs": [],
   "source": [
    "import torch.nn as nn\n",
    "import torch.nn.functional as F\n",
    "\n",
    "class CNN(nn.Module):\n",
    "    def __init__(self):\n",
    "        super(CNN, self).__init__()\n",
    "        \n",
    "        self.conv1 = nn.Conv2d(3, 32, kernel_size=3, padding=1)\n",
    "        self.pool1 = nn.MaxPool2d(kernel_size=2, stride=2)\n",
    "        self.drop1 = nn.Dropout(0.25)\n",
    "        \n",
    "        self.conv2 = nn.Conv2d(32, 64, kernel_size=3, padding=1)\n",
    "        self.pool2 = nn.MaxPool2d(kernel_size=2, stride=2)\n",
    "        self.drop2 = nn.Dropout(0.25)\n",
    "        \n",
    "        self.fc1 = nn.Linear(64 * 32 * 32, 128)\n",
    "        self.drop3 = nn.Dropout(0.5)\n",
    "        \n",
    "        self.fc2 = nn.Linear(128, 1)\n",
    "        \n",
    "    def forward(self, x):\n",
    "        x = self.pool1(F.relu(self.conv1(x)))\n",
    "        x = self.drop1(x)\n",
    "        \n",
    "        x = self.pool2(F.relu(self.conv2(x)))\n",
    "        x = self.drop2(x)\n",
    "        \n",
    "        x = x.view(x.size(0), -1)  # Flatten the tensor\n",
    "        x = F.relu(self.fc1(x))\n",
    "        x = self.drop3(x)\n",
    "        \n",
    "        x = torch.sigmoid(self.fc2(x))\n",
    "        \n",
    "        return x\n",
    "\n",
    "model = CNN()\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "id": "87fcde07-fb84-436b-90e5-a8df136795e2",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Epoch 1/30, Train Loss: 0.46245299945859347, Train Acc: 84.41%, Val Loss: 0.3201679476471834, Val Acc: 87.08%\n",
      "Epoch 2/30, Train Loss: 0.3345890543040107, Train Acc: 86.55%, Val Loss: 0.3240554627290992, Val Acc: 87.67%\n",
      "Epoch 3/30, Train Loss: 0.3158165231347084, Train Acc: 87.34%, Val Loss: 0.30789710780562357, Val Acc: 87.44%\n",
      "Epoch 4/30, Train Loss: 0.300326307906824, Train Acc: 87.95%, Val Loss: 0.3017796882709792, Val Acc: 88.55%\n",
      "Epoch 5/30, Train Loss: 0.2906287999056718, Train Acc: 88.99%, Val Loss: 0.276630834957888, Val Acc: 88.70%\n",
      "Epoch 6/30, Train Loss: 0.2763007117983173, Train Acc: 89.02%, Val Loss: 0.30686893556700195, Val Acc: 87.59%\n",
      "Epoch 7/30, Train Loss: 0.2707182551131529, Train Acc: 89.23%, Val Loss: 0.2511260166417721, Val Acc: 90.40%\n",
      "Epoch 8/30, Train Loss: 0.2600594243144288, Train Acc: 90.08%, Val Loss: 0.2610361373355222, Val Acc: 89.22%\n",
      "Epoch 9/30, Train Loss: 0.24589865286012783, Train Acc: 90.15%, Val Loss: 0.25044416120752344, Val Acc: 89.88%\n",
      "Epoch 10/30, Train Loss: 0.2479813086635926, Train Acc: 90.28%, Val Loss: 0.2550330535443716, Val Acc: 89.81%\n",
      "Epoch 11/30, Train Loss: 0.23855500657330542, Train Acc: 90.76%, Val Loss: 0.27043886166499104, Val Acc: 89.66%\n",
      "Epoch 12/30, Train Loss: 0.23202947262017165, Train Acc: 90.80%, Val Loss: 0.250461588158857, Val Acc: 90.77%\n",
      "Epoch 13/30, Train Loss: 0.22955049620393445, Train Acc: 90.54%, Val Loss: 0.242682334035635, Val Acc: 90.32%\n",
      "Epoch 14/30, Train Loss: 0.22401612015331493, Train Acc: 90.98%, Val Loss: 0.24712302132921163, Val Acc: 90.18%\n",
      "Epoch 15/30, Train Loss: 0.21338020346182235, Train Acc: 91.54%, Val Loss: 0.24882407122573189, Val Acc: 90.92%\n",
      "Epoch 16/30, Train Loss: 0.20937890991130295, Train Acc: 91.78%, Val Loss: 0.24268587280151455, Val Acc: 90.69%\n",
      "Epoch 17/30, Train Loss: 0.2007110228871598, Train Acc: 92.13%, Val Loss: 0.24427369748090588, Val Acc: 90.69%\n",
      "Epoch 18/30, Train Loss: 0.1974057096768828, Train Acc: 92.00%, Val Loss: 0.23782077492323034, Val Acc: 91.14%\n",
      "Epoch 19/30, Train Loss: 0.18967843130230905, Train Acc: 92.57%, Val Loss: 0.2550580800445967, Val Acc: 90.25%\n",
      "Epoch 20/30, Train Loss: 0.18783107524847284, Train Acc: 92.66%, Val Loss: 0.24865721023186696, Val Acc: 90.32%\n",
      "Epoch 21/30, Train Loss: 0.16403598020620205, Train Acc: 93.22%, Val Loss: 0.2711003647987233, Val Acc: 90.69%\n",
      "Epoch 22/30, Train Loss: 0.17865508509909406, Train Acc: 93.18%, Val Loss: 0.24852845380299313, Val Acc: 90.40%\n",
      "Epoch 23/30, Train Loss: 0.1624818333698546, Train Acc: 93.42%, Val Loss: 0.26031956702557413, Val Acc: 90.77%\n",
      "Epoch 24/30, Train Loss: 0.1638621051357511, Train Acc: 93.33%, Val Loss: 0.2544470603556134, Val Acc: 89.81%\n",
      "Epoch 25/30, Train Loss: 0.16026853454463622, Train Acc: 93.75%, Val Loss: 0.2610155753791332, Val Acc: 90.62%\n",
      "Epoch 26/30, Train Loss: 0.1448831561021507, Train Acc: 93.96%, Val Loss: 0.26332052091006625, Val Acc: 90.69%\n",
      "Epoch 27/30, Train Loss: 0.14002515101147925, Train Acc: 94.18%, Val Loss: 0.2790124806640453, Val Acc: 90.10%\n",
      "Epoch 28/30, Train Loss: 0.13404157268540823, Train Acc: 94.66%, Val Loss: 0.30317048080871967, Val Acc: 89.73%\n",
      "Epoch 29/30, Train Loss: 0.13780355061787894, Train Acc: 94.73%, Val Loss: 0.28609054713228416, Val Acc: 90.32%\n",
      "Epoch 30/30, Train Loss: 0.1313903414616909, Train Acc: 94.81%, Val Loss: 0.2909093671153451, Val Acc: 89.96%\n",
      "Finished Training\n"
     ]
    }
   ],
   "source": [
    "import torch.optim as optim\n",
    "\n",
    "criterion = nn.BCELoss()\n",
    "optimizer = optim.Adam(model.parameters(), lr=0.001)\n",
    "\n",
    "# Train the model\n",
    "num_epochs = 30\n",
    "\n",
    "for epoch in range(num_epochs):\n",
    "    model.train()\n",
    "    running_loss = 0.0\n",
    "    correct_train = 0\n",
    "    total_train = 0\n",
    "    \n",
    "    # Training loop\n",
    "    for i, (inputs, labels) in enumerate(train_loader):\n",
    "        optimizer.zero_grad()\n",
    "        outputs = model(inputs).squeeze(1)\n",
    "        \n",
    "        loss = criterion(outputs, labels.float())\n",
    "        loss.backward()\n",
    "        \n",
    "        optimizer.step()\n",
    "        running_loss += loss.item()\n",
    "\n",
    "        # Calculate accuracy\n",
    "        predicted = (outputs > 0.5).float()\n",
    "        total_train += labels.size(0)\n",
    "        correct_train += (predicted == labels.float()).sum().item()\n",
    "\n",
    "    train_accuracy = 100 * correct_train / total_train\n",
    "\n",
    "    # Validation loop\n",
    "    model.eval()\n",
    "    val_loss = 0.0\n",
    "    correct_val = 0\n",
    "    total_val = 0\n",
    "    with torch.no_grad():\n",
    "        for i, (inputs, labels) in enumerate(val_loader):\n",
    "            outputs = model(inputs).squeeze(1)\n",
    "            loss = criterion(outputs, labels.float())\n",
    "            val_loss += loss.item()\n",
    "\n",
    "            # Calculate accuracy\n",
    "            predicted = (outputs > 0.5).float()\n",
    "            total_val += labels.size(0)\n",
    "            correct_val += (predicted == labels.float()).sum().item()\n",
    "\n",
    "    val_accuracy = 100 * correct_val / total_val\n",
    "\n",
    "    print(f\"Epoch {epoch+1}/{num_epochs}, Train Loss: {running_loss/len(train_loader)}, Train Acc: {train_accuracy:.2f}%, Val Loss: {val_loss/len(val_loader)}, Val Acc: {val_accuracy:.2f}%\")\n",
    "\n",
    "print(\"Finished Training\")\n"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "8a03ab72-810b-4d14-94f3-da75eda5512e",
   "metadata": {},
   "source": [
    "# Inference"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 27,
   "id": "19686601-fd6a-4050-bc64-4962de1db430",
   "metadata": {},
   "outputs": [],
   "source": [
    "model.eval()\n",
    "\n",
    "predictions_list = []\n",
    "\n",
    "# Define your transformation here\n",
    "transform = transforms.Compose([\n",
    "    transforms.Resize((128, 128)),\n",
    "    transforms.ToTensor(),\n",
    "    transforms.Normalize(mean=[0.5, 0.5, 0.5], std=[0.5, 0.5, 0.5])\n",
    "])"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 25,
   "id": "94eda2f1-fc8c-43f8-a816-495b0b983e38",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "2958"
      ]
     },
     "execution_count": 25,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "test_files = os.listdir('image_dataset/test')\n",
    "test_files = natsort.natsorted(test_files)\n",
    "len(test_files)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 28,
   "id": "3eebba95-226b-404d-a0ce-eb71b45517e5",
   "metadata": {},
   "outputs": [],
   "source": [
    "# Loop through each image in the test folder\n",
    "for image_file in test_files:\n",
    "    if image_file.endswith('.png'):\n",
    "        image_path = os.path.join('image_dataset/test', image_file)\n",
    "        image = Image.open(image_path).convert('RGB')\n",
    "        image = transform(image).unsqueeze(0)  # Add a batch dimension\n",
    "\n",
    "        with torch.no_grad():\n",
    "            outputs = model(image).squeeze(1)\n",
    "            predicted = (outputs > 0.5).float()\n",
    "            predictions_list.append(predicted.cpu().item())"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 30,
   "id": "03467488-1733-4345-bfae-c1f7fa121464",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "2958"
      ]
     },
     "execution_count": 30,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "len(predictions_list)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 33,
   "id": "5693a7e6-d7dc-4f2d-a245-9a94b55be76f",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Predictions saved to 1897_submit.csv\n"
     ]
    }
   ],
   "source": [
    "# Load the sample CSV\n",
    "csv_test = pd.read_csv('1897_output_sample.csv')\n",
    "\n",
    "# Update the 'ClassID' column with our predictions\n",
    "csv_test['ClassID'] = predictions_list\n",
    "\n",
    "# Save the modified CSV as the submission file\n",
    "csv_test.to_csv('1897_submit.csv', sep=',', index=False)\n",
    "\n",
    "print(\"Predictions saved to 1897_submit.csv\")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "20fde69a-d5f2-4574-ade9-1d4f637e7a00",
   "metadata": {},
   "outputs": [],
   "source": []
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "yt38",
   "language": "python",
   "name": "yt38"
  },
  "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.0"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 5
}
