{"metadata":{"kernelspec":{"language":"python","display_name":"Python 3","name":"python3"},"language_info":{"name":"python","version":"3.12.12","mimetype":"text/x-python","codemirror_mode":{"name":"ipython","version":3},"pygments_lexer":"ipython3","nbconvert_exporter":"python","file_extension":".py"},"kaggle":{"accelerator":"nvidiaTeslaT4","dataSources":[{"sourceType":"competition","sourceId":10338,"databundleVersionId":862042,"isSourceIdPinned":false}],"dockerImageVersionId":31329,"isInternetEnabled":true,"language":"python","sourceType":"notebook","isGpuEnabled":true}},"nbformat_minor":4,"nbformat":4,"cells":[{"cell_type":"code","source":"import os\nimport numpy as np\nimport pandas as pd\nfrom pathlib import Path\nfrom sklearn.model_selection import train_test_split\nfrom sklearn.metrics import confusion_matrix, classification_report\n\nimport torch\nimport torch.nn as nn\nimport torch.optim as optim\nfrom torch.utils.data import Dataset, DataLoader\n\nimport torchvision.transforms as transforms\nimport torchvision.models as models\n\nimport pydicom\nimport cv2\nfrom tqdm import tqdm","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-04-14T12:32:00.360440Z","iopub.execute_input":"2026-04-14T12:32:00.360736Z","iopub.status.idle":"2026-04-14T12:32:14.082605Z","shell.execute_reply.started":"2026-04-14T12:32:00.360701Z","shell.execute_reply":"2026-04-14T12:32:14.081896Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"DATA_DIR = Path(\"/kaggle/input/competitions/rsna-pneumonia-detection-challenge\")\n\nLABEL_CSV = DATA_DIR / \"stage_2_train_labels.csv\"\nIMG_DIR = DATA_DIR / \"stage_2_train_images\"","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-04-14T12:33:22.178945Z","iopub.execute_input":"2026-04-14T12:33:22.179578Z","iopub.status.idle":"2026-04-14T12:33:22.183794Z","shell.execute_reply.started":"2026-04-14T12:33:22.179539Z","shell.execute_reply":"2026-04-14T12:33:22.183095Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"df = pd.read_csv(LABEL_CSV)\n\n# Convert to binary classification\ndf['Target'] = df['Target'].astype(int)\n\n# Group by patientId (important!)\ndf = df.groupby('patientId')['Target'].max().reset_index()","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-04-14T12:33:23.834267Z","iopub.execute_input":"2026-04-14T12:33:23.835242Z","iopub.status.idle":"2026-04-14T12:33:23.963771Z","shell.execute_reply.started":"2026-04-14T12:33:23.835204Z","shell.execute_reply":"2026-04-14T12:33:23.963086Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"train_df, temp_df = train_test_split(df, test_size=0.36, stratify=df['Target'], random_state=42)\n\nval_df, test_df = train_test_split(temp_df, test_size=0.555, stratify=temp_df['Target'], random_state=42)\n\nprint(len(train_df), len(val_df), len(test_df))","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-04-14T12:33:25.546309Z","iopub.execute_input":"2026-04-14T12:33:25.546769Z","iopub.status.idle":"2026-04-14T12:33:25.577313Z","shell.execute_reply.started":"2026-04-14T12:33:25.546737Z","shell.execute_reply":"2026-04-14T12:33:25.576449Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"class RSNADataset(Dataset):\n    def __init__(self, df, img_dir, transform=None):\n        self.df = df\n        self.img_dir = img_dir\n        self.transform = transform\n\n    def __len__(self):\n        return len(self.df)\n\n    def __getitem__(self, idx):\n        patient_id = self.df.iloc[idx]['patientId']\n        label = self.df.iloc[idx]['Target']\n\n        dcm_path = self.img_dir / f\"{patient_id}.dcm\"\n        dicom = pydicom.dcmread(dcm_path)\n\n        img = dicom.pixel_array.astype(np.float32)\n\n        # Normalize\n        img = (img - img.min()) / (img.max() - img.min() + 1e-5)\n\n        # Convert to 3-channel\n        img = np.stack([img]*3, axis=-1)\n\n        img = (img * 255).astype(np.uint8)\n\n        if self.transform:\n            img = self.transform(img)\n\n        return img, torch.tensor(label, dtype=torch.float32)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-04-14T12:33:27.203742Z","iopub.execute_input":"2026-04-14T12:33:27.204597Z","iopub.status.idle":"2026-04-14T12:33:27.210855Z","shell.execute_reply.started":"2026-04-14T12:33:27.204554Z","shell.execute_reply":"2026-04-14T12:33:27.210018Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"train_transform = transforms.Compose([\n    transforms.ToPILImage(),\n    transforms.Resize((224, 224)),\n    transforms.RandomHorizontalFlip(),\n    transforms.RandomRotation(10),\n    transforms.ToTensor(),\n])\n\nval_transform = transforms.Compose([\n    transforms.ToPILImage(),\n    transforms.Resize((224, 224)),\n    transforms.ToTensor(),\n])","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-04-14T12:33:31.530849Z","iopub.execute_input":"2026-04-14T12:33:31.531160Z","iopub.status.idle":"2026-04-14T12:33:31.537289Z","shell.execute_reply.started":"2026-04-14T12:33:31.531131Z","shell.execute_reply":"2026-04-14T12:33:31.536372Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"train_ds = RSNADataset(train_df, IMG_DIR, train_transform)\nval_ds   = RSNADataset(val_df, IMG_DIR, val_transform)\ntest_ds  = RSNADataset(test_df, IMG_DIR, val_transform)\n\ntrain_loader = DataLoader(train_ds, batch_size=32, shuffle=True, num_workers=2)\nval_loader   = DataLoader(val_ds, batch_size=32, shuffle=False, num_workers=2)\ntest_loader  = DataLoader(test_ds, batch_size=32, shuffle=False, num_workers=2)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-04-14T12:33:33.162800Z","iopub.execute_input":"2026-04-14T12:33:33.163608Z","iopub.status.idle":"2026-04-14T12:33:33.169261Z","shell.execute_reply.started":"2026-04-14T12:33:33.163574Z","shell.execute_reply":"2026-04-14T12:33:33.168410Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"device = torch.device(\"cuda\" if torch.cuda.is_available() else \"cpu\")\n\nmodel = models.resnet18(weights=\"IMAGENET1K_V1\")\nmodel.fc = nn.Linear(model.fc.in_features, 1)\nmodel = model.to(device)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-04-14T12:33:35.682314Z","iopub.execute_input":"2026-04-14T12:33:35.683103Z","iopub.status.idle":"2026-04-14T12:33:36.955592Z","shell.execute_reply.started":"2026-04-14T12:33:35.683069Z","shell.execute_reply":"2026-04-14T12:33:36.954574Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"pos_weight = torch.tensor([df['Target'].value_counts()[0] / df['Target'].value_counts()[1]]).to(device)\n\ncriterion = nn.BCEWithLogitsLoss(pos_weight=pos_weight)\noptimizer = optim.Adam(model.parameters(), lr=1e-4)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-04-14T12:33:41.802991Z","iopub.execute_input":"2026-04-14T12:33:41.803737Z","iopub.status.idle":"2026-04-14T12:33:41.815713Z","shell.execute_reply.started":"2026-04-14T12:33:41.803702Z","shell.execute_reply":"2026-04-14T12:33:41.814927Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"from sklearn.metrics import accuracy_score, roc_auc_score\ndef eval_model(loader):\n    model.eval()\n    total_loss = 0\n\n    all_probs = []\n    all_preds = []\n    all_targets = []\n\n    with torch.no_grad():\n        for imgs, labels in loader:\n            imgs, labels = imgs.to(device), labels.to(device)\n\n            outputs = model(imgs).squeeze()\n            loss = criterion(outputs, labels)\n\n            total_loss += loss.item()\n\n            probs = torch.sigmoid(outputs)\n\n            preds = (probs > 0.3).float()\n\n            all_probs.extend(probs.cpu().numpy())\n            all_preds.extend(preds.cpu().numpy())\n            all_targets.extend(labels.cpu().numpy())\n\n    acc = accuracy_score(all_targets, all_preds)\n    auc = roc_auc_score(all_targets, all_probs)\n\n    return total_loss / len(loader), acc, auc","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-04-14T12:51:53.078868Z","iopub.execute_input":"2026-04-14T12:51:53.079606Z","iopub.status.idle":"2026-04-14T12:51:53.087826Z","shell.execute_reply.started":"2026-04-14T12:51:53.079562Z","shell.execute_reply":"2026-04-14T12:51:53.086912Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"def train_epoch(loader):\n    model.train()\n    total_loss = 0\n\n    all_probs = []\n    all_preds = []\n    all_targets = []\n\n    for imgs, labels in tqdm(loader):\n        imgs, labels = imgs.to(device), labels.to(device)\n\n        optimizer.zero_grad()\n\n        outputs = model(imgs).squeeze()\n        loss = criterion(outputs, labels)\n\n        loss.backward()\n        optimizer.step()\n\n        total_loss += loss.item()\n\n        probs = torch.sigmoid(outputs)\n        preds = (probs > 0.3).float()\n\n        all_probs.extend(probs.detach().cpu().numpy())\n        all_preds.extend(preds.detach().cpu().numpy())\n        all_targets.extend(labels.detach().cpu().numpy())\n\n    acc = accuracy_score(all_targets, all_preds)\n    auc = roc_auc_score(all_targets, all_probs)\n\n    return total_loss / len(loader), acc, auc","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-04-14T12:51:56.101094Z","iopub.execute_input":"2026-04-14T12:51:56.101556Z","iopub.status.idle":"2026-04-14T12:51:56.108045Z","shell.execute_reply.started":"2026-04-14T12:51:56.101523Z","shell.execute_reply":"2026-04-14T12:51:56.107262Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"EPOCHS = 15\n\nprint(f\"{'Epoch':<6}{'Tr Loss':<10}{'Tr Acc':<10}{'Tr AUC':<10}{'Va Loss':<10}{'Va Acc':<10}{'Va AUC':<10}\")\n\nfor epoch in range(EPOCHS):\n    tr_loss, tr_acc, tr_auc = train_epoch(train_loader)\n    va_loss, va_acc, va_auc = eval_model(val_loader)\n\n    print(f\"{epoch+1:<6}{tr_loss:.4f}   {tr_acc:.4f}   {tr_auc:.4f}   {va_loss:.4f}   {va_acc:.4f}   {va_auc:.4f}\")","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-04-14T12:51:58.881011Z","iopub.execute_input":"2026-04-14T12:51:58.881830Z","iopub.status.idle":"2026-04-14T13:49:07.742919Z","shell.execute_reply.started":"2026-04-14T12:51:58.881778Z","shell.execute_reply":"2026-04-14T13:49:07.741565Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"_, preds, targets = eval_model(test_loader)\n\ncm = confusion_matrix(targets, preds)\n\nprint(\"Confusion Matrix:\\n\", cm)\n\nprint(\"\\nClassification Report:\\n\")\nprint(classification_report(targets, preds))","metadata":{"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"code","source":"","metadata":{"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"code","source":"","metadata":{"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"code","source":"","metadata":{"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"code","source":"","metadata":{"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"code","source":"","metadata":{"trusted":true},"outputs":[],"execution_count":null}]}