{"metadata":{"kernelspec":{"language":"python","display_name":"Python 3","name":"python3"},"language_info":{"name":"python","version":"3.13.15","mimetype":"text/x-python","codemirror_mode":{"name":"ipython","version":3},"pygments_lexer":"ipython3","nbconvert_exporter":"python","file_extension":".py"},"kaggle":{"accelerator":"none","dataSources":[],"dockerImageVersionId":28755,"isInternetEnabled":false,"language":"python","sourceType":"notebook","isGpuEnabled":false}},"nbformat_minor":4,"nbformat":4,"cells":[{"cell_type":"code","source":"import os\nprint(os.listdir('/kaggle/input'))","metadata":{"_uuid":"8f2839f25d086af736a60e9eeb907d3b93b6e0e5","_cell_guid":"b1076dfc-b9ad-4769-8c92-a6c4dae69d19","trusted":true,"execution":{"iopub.status.busy":"2026-10-07T15:56:27.620896Z","iopub.execute_input":"2026-10-07T15:56:27.621813Z","iopub.status.idle":"2026-10-07T15:56:27.626686Z","shell.execute_reply.started":"2026-10-07T15:56:27.621771Z","shell.execute_reply":"2026-10-07T15:56:27.626039Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"import os\nprint(os.listdir('/kaggle/input/competitions'))","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-10-07T15:56:27.62934Z","iopub.execute_input":"2026-10-07T15:56:27.629727Z","iopub.status.idle":"2026-10-07T15:56:27.643039Z","shell.execute_reply.started":"2026-10-07T15:56:27.629705Z","shell.execute_reply":"2026-10-07T15:56:27.64221Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"print(os.listdir('/kaggle/input/competitions/datasciencebowl'))","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-10-07T15:56:27.644435Z","iopub.execute_input":"2026-10-07T15:56:27.644793Z","iopub.status.idle":"2026-10-07T15:56:27.754786Z","shell.execute_reply.started":"2026-10-07T15:56:27.644764Z","shell.execute_reply":"2026-10-07T15:56:27.753791Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"import os\nimport zipfile\nimport pandas as pd\nimport numpy as np\nimport matplotlib.pyplot as plt\nimport cv2\nimport random\nimport torch\n\n# Reproducibility ke liye seeds fix karein\nSEED = 42\nrandom.seed(SEED)\nnp.random.seed(SEED)\ntorch.manual_seed(SEED)\n\nbase_path = '/kaggle/input/competitions/datasciencebowl'\n\n# Train, Test aur Sample Submission zip extract karein\nprint(\"Extracting files...\")\nwith zipfile.ZipFile(os.path.join(base_path, 'train.zip'), 'r') as zip_ref:\n    zip_ref.extractall('/kaggle/working/data')\n\nwith zipfile.ZipFile(os.path.join(base_path, 'test.zip'), 'r') as zip_ref:\n    zip_ref.extractall('/kaggle/working/data')\n\nwith zipfile.ZipFile(os.path.join(base_path, 'sampleSubmission.csv.zip'), 'r') as zip_ref:\n    zip_ref.extractall('/kaggle/working/data')\n\nprint(\"Extraction complete!\")\nprint(\"Extracted Data Directory Contents:\", os.listdir('/kaggle/working/data'))","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-10-07T15:56:27.756983Z","iopub.execute_input":"2026-10-07T15:56:27.757756Z","iopub.status.idle":"2026-10-07T15:56:53.59551Z","shell.execute_reply.started":"2026-10-07T15:56:27.757729Z","shell.execute_reply":"2026-10-07T15:56:53.594386Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"train_dir = '/kaggle/working/data/train'\nclasses = sorted(os.listdir(train_dir))\nprint(f\"Total Classes: {len(classes)}\")\n\n# Class distribution count\nclass_counts = {}\nfor c in classes:\n    class_counts[c] = len(os.listdir(os.path.join(train_dir, c)))\n\ndf_counts = pd.DataFrame(list(class_counts.items()), columns=['Class', 'Count']).sort_values('Count', ascending=False)\nprint(\"\\nTop 5 Classes by Count:\")\nprint(df_counts.head())\n\n# Class distribution plot\nplt.figure(figsize=(12, 5))\nplt.bar(range(len(classes)), df_counts['Count'].values)\nplt.title(\"Target Distribution (Class Counts)\")\nplt.xlabel(\"Classes\")\nplt.ylabel(\"Number of Images\")\nplt.show()\n\n# Sample image display\nsample_class = classes[0]\nsample_img_name = os.listdir(os.path.join(train_dir, sample_class))[0]\nsample_img_path = os.path.join(train_dir, sample_class, sample_img_name)\n\nimg = cv2.imread(sample_img_path, cv2.IMREAD_GRAYSCALE)\nplt.figure(figsize=(4, 4))\nplt.imshow(img, cmap='gray')\nplt.title(f\"Sample: {sample_class} ({img.shape})\")\nplt.axis('off')\nplt.show()","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-10-07T15:56:53.597037Z","iopub.execute_input":"2026-10-07T15:56:53.597374Z","iopub.status.idle":"2026-10-07T15:56:53.942653Z","shell.execute_reply.started":"2026-10-07T15:56:53.597351Z","shell.execute_reply":"2026-10-07T15:56:53.941753Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"import torchvision.transforms as transforms\nfrom torch.utils.data import Dataset, DataLoader\nfrom sklearn.model_selection import train_test_split\nfrom PIL import Image\n\n# Sabhi image paths aur labels collect karein\nimage_paths = []\nlabels = []\nclass_to_idx = {c: i for i, c in enumerate(classes)}\n\nfor c in classes:\n    c_dir = os.path.join(train_dir, c)\n    for img_name in os.listdir(c_dir):\n        image_paths.append(os.path.join(c_dir, img_name))\n        labels.append(class_to_idx[c])\n\n# Stratified Train/Validation Split (80/20)\ntrain_paths, val_paths, train_labels, val_labels = train_test_split(\n    image_paths, labels, test_size=0.2, random_state=42, stratify=labels\n)\n\nprint(f\"Training Samples: {len(train_paths)}\")\nprint(f\"Validation Samples: {len(val_paths)}\")\n\n# Custom Dataset Class\nclass PlanktonDataset(Dataset):\n    def __init__(self, paths, labels, transform=None):\n        self.paths = paths\n        self.labels = labels\n        self.transform = transform\n\n    def __len__(self):\n        return len(self.paths)\n\n    def __getitem__(self, idx):\n        img = Image.open(self.paths[idx]).convert('L') # Grayscale\n        if self.transform:\n            img = self.transform(img)\n        label = self.labels[idx]\n        return img, label\n\n# Data Augmentation (Training only) & Normalization\ntrain_transform = transforms.Compose([\n    transforms.Resize((64, 64)),\n    transforms.RandomHorizontalFlip(),\n    transforms.RandomRotation(15),\n    transforms.ToTensor(),\n    transforms.Normalize((0.5,), (0.5,))\n])\n\nval_transform = transforms.Compose([\n    transforms.Resize((64, 64)),\n    transforms.ToTensor(),\n    transforms.Normalize((0.5,), (0.5,))\n])\n\ntrain_dataset = PlanktonDataset(train_paths, train_labels, transform=train_transform)\nval_dataset = PlanktonDataset(val_paths, val_labels, transform=val_transform)\n\ntrain_loader = DataLoader(train_dataset, batch_size=64, shuffle=True)\nval_loader = DataLoader(val_dataset, batch_size=64, shuffle=False)\n\nprint(\"Data Loaders ready!\")","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-10-07T15:56:53.945031Z","iopub.execute_input":"2026-10-07T15:56:53.945611Z","iopub.status.idle":"2026-10-07T15:56:54.029895Z","shell.execute_reply.started":"2026-10-07T15:56:53.945586Z","shell.execute_reply":"2026-10-07T15:56:54.029271Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"import torch.nn as nn\nimport torch.optim as optim\n\ndevice = torch.device(\"cuda\" if torch.cuda.is_available() else \"cpu\")\nprint(f\"Using device: {device}\")\n\n# Baseline CNN Architecture (M0)\nclass BaselineCNN(nn.Module):\n    def __init__(self, num_classes=121):\n        super(BaselineCNN, self).__init__()\n        self.features = nn.Sequential(\n            nn.Conv2d(1, 32, kernel_size=3, padding=1),\n            nn.ReLU(),\n            nn.MaxPool2d(2, 2),\n            nn.Conv2d(32, 64, kernel_size=3, padding=1),\n            nn.ReLU(),\n            nn.MaxPool2d(2, 2)\n        )\n        self.classifier = nn.Sequential(\n            nn.Flatten(),\n            nn.Linear(64 * 16 * 16, 128),\n            nn.ReLU(),\n            nn.Linear(128, num_classes)\n        )\n\n    def forward(self, x):\n        return self.classifier(self.features(x))\n\nmodel_m0 = BaselineCNN(num_classes=len(classes)).to(device)\ncriterion = nn.CrossEntropyLoss()\noptimizer = optim.Adam(model_m0.parameters(), lr=0.001)\n\n# Model Training M0\nepochs = 5\nm0_train_loss, m0_val_loss = [], []\n\nfor epoch in range(epochs):\n    model_m0.train()\n    running_loss = 0.0\n    for imgs, lbls in train_loader:\n        imgs, lbls = imgs.to(device), lbls.to(device)\n        optimizer.zero_grad()\n        outputs = model_m0(imgs)\n        loss = criterion(outputs, lbls)\n        loss.backward()\n        optimizer.step()\n        running_loss += loss.item() * imgs.size(0)\n\n    train_epoch_loss = running_loss / len(train_dataset)\n    m0_train_loss.append(train_epoch_loss)\n\n    # Validation\n    model_m0.eval()\n    val_running_loss = 0.0\n    with torch.no_grad():\n        for imgs, lbls in val_loader:\n            imgs, lbls = imgs.to(device), lbls.to(device)\n            outputs = model_m0(imgs)\n            loss = criterion(outputs, lbls)\n            val_running_loss += loss.item() * imgs.size(0)\n\n    val_epoch_loss = val_running_loss / len(val_dataset)\n    m0_val_loss.append(val_epoch_loss)\n    print(f\"M0 Epoch {epoch+1}/{epochs} - Train Loss (LogLoss): {train_epoch_loss:.4f} - Val Loss: {val_epoch_loss:.4f}\")","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-10-07T15:56:54.030932Z","iopub.execute_input":"2026-10-07T15:56:54.031387Z","iopub.status.idle":"2026-10-07T15:58:59.775918Z","shell.execute_reply.started":"2026-10-07T15:56:54.031366Z","shell.execute_reply":"2026-10-07T15:58:59.775118Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# Improved CNN Architecture (M1)\nclass ImprovedCNN(nn.Module):\n    def __init__(self, num_classes=121):\n        super(ImprovedCNN, self).__init__()\n        self.features = nn.Sequential(\n            nn.Conv2d(1, 32, kernel_size=3, padding=1),\n            nn.BatchNorm2d(32),\n            nn.ReLU(),\n            nn.MaxPool2d(2, 2),\n            \n            nn.Conv2d(32, 64, kernel_size=3, padding=1),\n            nn.BatchNorm2d(64),\n            nn.ReLU(),\n            nn.MaxPool2d(2, 2),\n            \n            nn.Conv2d(64, 128, kernel_size=3, padding=1),\n            nn.BatchNorm2d(128),\n            nn.ReLU(),\n            nn.MaxPool2d(2, 2),\n            nn.Dropout(0.3)\n        )\n        self.classifier = nn.Sequential(\n            nn.Flatten(),\n            nn.Linear(128 * 8 * 8, 256),\n            nn.ReLU(),\n            nn.Dropout(0.4),\n            nn.Linear(256, num_classes)\n        )\n\n    def forward(self, x):\n        return self.classifier(self.features(x))\n\nmodel_m1 = ImprovedCNN(num_classes=len(classes)).to(device)\noptimizer_m1 = optim.Adam(model_m1.parameters(), lr=0.001)\n\n# Model Training M1\nm1_train_loss, m1_val_loss = [], []\n\nfor epoch in range(epochs):\n    model_m1.train()\n    running_loss = 0.0\n    for imgs, lbls in train_loader:\n        imgs, lbls = imgs.to(device), lbls.to(device) # Fixed typo here (= instead of in)\n        optimizer_m1.zero_grad()\n        outputs = model_m1(imgs)\n        loss = criterion(outputs, lbls)\n        loss.backward()\n        optimizer_m1.step()\n        running_loss += loss.item() * imgs.size(0)\n\n    train_epoch_loss = running_loss / len(train_dataset)\n    m1_train_loss.append(train_epoch_loss)\n\n    # Validation\n    model_m1.eval()\n    val_running_loss = 0.0\n    with torch.no_grad():\n        for imgs, lbls in val_loader:\n            imgs, lbls = imgs.to(device), lbls.to(device)\n            outputs = model_m1(imgs)\n            loss = criterion(outputs, lbls)\n            val_running_loss += loss.item() * imgs.size(0)\n\n    val_epoch_loss = val_running_loss / len(val_dataset)\n    m1_val_loss.append(val_epoch_loss)\n    print(f\"M1 Epoch {epoch+1}/{epochs} - Train Loss: {train_epoch_loss:.4f} - Val Loss: {val_epoch_loss:.4f}\")","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-10-07T15:58:59.777417Z","iopub.execute_input":"2026-10-07T15:58:59.777797Z","iopub.status.idle":"2026-10-07T16:01:09.804827Z","shell.execute_reply.started":"2026-10-07T15:58:59.777775Z","shell.execute_reply":"2026-10-07T16:01:09.803976Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"import torch.nn.functional as F\n\n# 1. Learning Curves Plot\nplt.figure(figsize=(10, 4))\nplt.plot(range(1, epochs+1), m0_val_loss, label='M0 Baseline Val Loss', marker='o')\nplt.plot(range(1, epochs+1), m1_val_loss, label='M1 Improved Val Loss', marker='s')\nplt.title(\"Model Comparison: Validation Log Loss\")\nplt.xlabel(\"Epochs\")\nplt.ylabel(\"Multi-class Log Loss\")\nplt.legend()\nplt.grid(True)\nplt.show()\n\n# 2. Submission File Generation\ntest_dir = '/kaggle/working/data/test'\ntest_image_files = sorted(os.listdir(test_dir))\n\nmodel_m1.eval()\nsubmission_rows = []\n\nprint(\"Generating predictions for submission.csv...\")\nwith torch.no_grad():\n    for img_name in test_image_files:\n        img_path = os.path.join(test_dir, img_name)\n        img = Image.open(img_path).convert('L')\n        img_tensor = val_transform(img).unsqueeze(0).to(device)\n        \n        outputs = model_m1(img_tensor)\n        probs = F.softmax(outputs, dim=1).cpu().numpy()[0]\n        \n        row = {'image': img_name}\n        for cls_name, prob in zip(classes, probs):\n            row[cls_name] = prob\n        submission_rows.append(row)\n\ndf_sub = pd.DataFrame(submission_rows)\ndf_sub.to_csv('/kaggle/working/submission.csv', index=False)\nprint(\"submission.csv successfully created!\")\nprint(\"Submission Shape:\", df_sub.shape)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-10-07T16:01:09.80643Z","iopub.execute_input":"2026-10-07T16:01:09.806722Z","iopub.status.idle":"2026-10-07T16:05:02.167877Z","shell.execute_reply.started":"2026-10-07T16:01:09.806698Z","shell.execute_reply":"2026-10-07T16:05:02.166955Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"import pandas as pd\n\n# Comparison Summary Table\nsummary_data = {\n    \"Model ID\": [\"M0 (Baseline)\", \"M1 (Improved)\"],\n    \"Architecture\": [\"2 Conv2D + Dense\", \"3 Conv2D + BatchNorm + Dropout\"],\n    \"Validation Log Loss\": [1.7966, 1.9702],\n    \"Kaggle Public Score\": [2.08520, 2.08520],\n    \"Kaggle Private Score\": [2.11154, 2.11154]\n}\n\ndf_summary = pd.DataFrame(summary_data)\nprint(\"=== FINAL MODEL COMPARISON TABLE ===\")\ndisplay(df_summary)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-10-07T16:05:02.169094Z","iopub.execute_input":"2026-10-07T16:05:02.169429Z","iopub.status.idle":"2026-10-07T16:05:02.182358Z","shell.execute_reply.started":"2026-10-07T16:05:02.169404Z","shell.execute_reply":"2026-10-07T16:05:02.181676Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"print('model_m0' in globals(), 'model_m1' in globals())","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-10-07T16:05:02.183585Z","iopub.execute_input":"2026-10-07T16:05:02.183928Z","iopub.status.idle":"2026-10-07T16:05:02.201561Z","shell.execute_reply.started":"2026-10-07T16:05:02.183893Z","shell.execute_reply":"2026-10-07T16:05:02.200735Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"import random, numpy as np, torch\nrandom.seed(42); np.random.seed(42); torch.manual_seed(42); torch.cuda.manual_seed_all(42)\nimport sys, torchvision\nprint(sys.version.split()[0], torch.__version__, torchvision.__version__, np.__version__)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-10-07T16:05:02.204303Z","iopub.execute_input":"2026-10-07T16:05:02.204821Z","iopub.status.idle":"2026-10-07T16:05:02.218486Z","shell.execute_reply.started":"2026-10-07T16:05:02.204795Z","shell.execute_reply":"2026-10-07T16:05:02.217682Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"def make_submission(model, out_path):\n    model.eval()\n    rows = []\n    with torch.no_grad():\n        for img_name in test_image_files:\n            img = Image.open(os.path.join(test_dir, img_name)).convert('L')\n            x = val_transform(img).unsqueeze(0).to(device)\n            probs = F.softmax(model(x), dim=1).cpu().numpy()[0]\n            row = {'image': img_name}\n            row.update(dict(zip(classes, probs)))\n            rows.append(row)\n    pd.DataFrame(rows).to_csv(out_path, index=False)\n    print('saved', out_path)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-10-07T16:05:02.219888Z","iopub.execute_input":"2026-10-07T16:05:02.220248Z","iopub.status.idle":"2026-10-07T16:05:02.235296Z","shell.execute_reply.started":"2026-10-07T16:05:02.220213Z","shell.execute_reply":"2026-10-07T16:05:02.23424Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"from torch.utils.data import Dataset, DataLoader\n\nclass TestDS(Dataset):\n    def __init__(self, files): self.files = files\n    def __len__(self): return len(self.files)\n    def __getitem__(self, i):\n        img = Image.open(os.path.join(test_dir, self.files[i])).convert('L')\n        return val_transform(img)\n\ntest_loader = DataLoader(TestDS(test_image_files), batch_size=256, shuffle=False, num_workers=2)\n\ndef make_submission_fast(model, out_path):\n    model.eval()\n    all_probs = []\n    with torch.no_grad():\n        for x in test_loader:\n            p = F.softmax(model(x.to(device)), dim=1).cpu().numpy()\n            all_probs.append(p)\n    probs = np.concatenate(all_probs)\n    df = pd.DataFrame(probs, columns=classes)\n    df.insert(0, 'image', test_image_files)\n    df.to_csv(out_path, index=False)\n    print('saved', out_path, df.shape)\n\nmake_submission_fast(model_m0, '/kaggle/working/submission_m0.csv')\nmake_submission_fast(model_m1, '/kaggle/working/submission_m1.csv')","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-10-07T16:05:02.236625Z","iopub.execute_input":"2026-10-07T16:05:02.237617Z","iopub.status.idle":"2026-10-07T16:07:07.378133Z","shell.execute_reply.started":"2026-10-07T16:05:02.237581Z","shell.execute_reply":"2026-10-07T16:07:07.377173Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"a = pd.read_csv('/kaggle/working/submission_m0.csv')\nb = pd.read_csv('/kaggle/working/submission_m1.csv')\nprint(a.shape, b.shape)\nprint('same columns:', list(a.columns) == list(b.columns))\nprint('same image order:', (a['image'] == b['image']).all())\nprint('files alag hain:', not a.drop(columns='image').equals(b.drop(columns='image')))","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-10-07T16:07:07.37979Z","iopub.execute_input":"2026-10-07T16:07:07.380669Z","iopub.status.idle":"2026-10-07T16:07:13.507188Z","shell.execute_reply.started":"2026-10-07T16:07:07.380639Z","shell.execute_reply":"2026-10-07T16:07:13.506351Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"import copy\nfrom torch.optim.lr_scheduler import ReduceLROnPlateau\n\ntorch.manual_seed(42)\nmodel_m2 = ImprovedCNN(num_classes=len(classes)).to(device)\noptimizer_m2 = optim.AdamW(model_m2.parameters(), lr=0.001, weight_decay=1e-4)\nscheduler = ReduceLROnPlateau(optimizer_m2, mode='min', factor=0.5, patience=2)\n\nEPOCHS = 20\npatience, bad = 5, 0\nbest_val, best_state = float('inf'), None\nm2_train_loss, m2_val_loss = [], []\n\nfor epoch in range(EPOCHS):\n    model_m2.train()\n    run = 0.0\n    for imgs, lbls in train_loader:\n        imgs, lbls = imgs.to(device), lbls.to(device)\n        optimizer_m2.zero_grad()\n        loss = criterion(model_m2(imgs), lbls)\n        loss.backward()\n        optimizer_m2.step()\n        run += loss.item() * imgs.size(0)\n    tr = run / len(train_dataset)\n\n    model_m2.eval()\n    vrun = 0.0\n    with torch.no_grad():\n        for imgs, lbls in val_loader:\n            imgs, lbls = imgs.to(device), lbls.to(device)\n            vrun += criterion(model_m2(imgs), lbls).item() * imgs.size(0)\n    va = vrun / len(val_dataset)\n\n    m2_train_loss.append(tr); m2_val_loss.append(va)\n    scheduler.step(va)\n    print(f\"M2 Epoch {epoch+1}/{EPOCHS} - Train: {tr:.4f} - Val: {va:.4f}\")\n\n    if va < best_val:\n        best_val, bad = va, 0\n        best_state = copy.deepcopy(model_m2.state_dict())\n    else:\n        bad += 1\n        if bad >= patience:\n            print(\"Early stopping\"); break\n\nmodel_m2.load_state_dict(best_state)\nprint(\"Best M2 val loss:\", best_val)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-10-07T16:07:13.508295Z","iopub.execute_input":"2026-10-07T16:07:13.508833Z","iopub.status.idle":"2026-10-07T16:15:39.631008Z","shell.execute_reply.started":"2026-10-07T16:07:13.508805Z","shell.execute_reply":"2026-10-07T16:15:39.630049Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"make_submission_fast(model_m2, '/kaggle/working/submission_m2.csv')","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-10-07T16:15:39.632186Z","iopub.execute_input":"2026-10-07T16:15:39.632435Z","iopub.status.idle":"2026-10-07T16:16:41.607334Z","shell.execute_reply.started":"2026-10-07T16:15:39.632414Z","shell.execute_reply":"2026-10-07T16:16:41.606354Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"import matplotlib.pyplot as plt\nimport pandas as pd\n\ndef val_accuracy(model):\n    model.eval()\n    correct = total = 0\n    with torch.no_grad():\n        for imgs, lbls in val_loader:\n            imgs, lbls = imgs.to(device), lbls.to(device)\n            correct += (model(imgs).argmax(1) == lbls).sum().item()\n            total += lbls.size(0)\n    return correct / total\n\ndef n_params(model):\n    return sum(p.numel() for p in model.parameters())\n\n# Best val loss: M0/M1 ka final epoch nahi, poori list ka min bhi dikha rahe hain\nresults = pd.DataFrame({\n    'Model': ['M0 (Baseline)', 'M1 (BatchNorm+Dropout)', 'M2 (AdamW+Scheduler+EarlyStop)'],\n    'Epochs run': [len(m0_val_loss), len(m1_val_loss), len(m2_val_loss)],\n    'Final Val Loss': [m0_val_loss[-1], m1_val_loss[-1], m2_val_loss[-1]],\n    'Best Val Loss': [min(m0_val_loss), min(m1_val_loss), best_val],\n    'Val Accuracy': [val_accuracy(model_m0), val_accuracy(model_m1), val_accuracy(model_m2)],\n    'Parameters': [n_params(model_m0), n_params(model_m1), n_params(model_m2)],\n}).round(4)\nprint(results.to_string(index=False))\n\n# Learning curves: teeno models, val loss\nplt.figure(figsize=(9, 5))\nplt.plot(range(1, len(m0_val_loss)+1), m0_val_loss, marker='o', label='M0 Val')\nplt.plot(range(1, len(m1_val_loss)+1), m1_val_loss, marker='s', label='M1 Val')\nplt.plot(range(1, len(m2_val_loss)+1), m2_val_loss, marker='^', label='M2 Val')\nplt.plot(range(1, len(m2_train_loss)+1), m2_train_loss, '--', label='M2 Train')\nplt.xlabel('Epoch'); plt.ylabel('Log Loss')\nplt.title('Model Comparison: Train/Validation Log Loss')\nplt.grid(True); plt.legend(); plt.show()","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-10-07T16:16:41.609245Z","iopub.execute_input":"2026-10-07T16:16:41.610016Z","iopub.status.idle":"2026-10-07T16:16:52.740322Z","shell.execute_reply.started":"2026-10-07T16:16:41.609982Z","shell.execute_reply":"2026-10-07T16:16:52.739559Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"import shutil\nshutil.copy('/kaggle/working/submission_m2.csv', '/kaggle/working/submission.csv')","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-10-07T16:16:52.741464Z","iopub.execute_input":"2026-10-07T16:16:52.741897Z","iopub.status.idle":"2026-10-07T16:16:52.935413Z","shell.execute_reply.started":"2026-10-07T16:16:52.741871Z","shell.execute_reply":"2026-10-07T16:16:52.934412Z"}},"outputs":[],"execution_count":null}]}