{"metadata":{"kernelspec":{"language":"python","display_name":"Python 3","name":"python3"},"language_info":{"name":"python","version":"3.11.11","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":24800,"datasetId":1042002,"databundleVersionId":1831594},{"sourceType":"datasetVersion","sourceId":12057336,"datasetId":7588675,"databundleVersionId":12581489},{"sourceType":"datasetVersion","sourceId":1810938,"datasetId":1075803,"databundleVersionId":1848422},{"sourceType":"modelInstanceVersion","sourceId":438484,"databundleVersionId":12739238,"modelInstanceId":357737}],"dockerImageVersionId":31040,"isInternetEnabled":true,"language":"python","sourceType":"notebook","isGpuEnabled":true}},"nbformat_minor":4,"nbformat":4,"cells":[{"cell_type":"code","source":"import os\nimport pandas as pd\nimport numpy as np\nimport matplotlib.pyplot as plt\nimport cv2\nfrom PIL import Image\nfrom tqdm.notebook import tqdm\nimport pydicom\nimport torch\nfrom PIL import Image\nimport os\nfrom tqdm import tqdm\nfrom sklearn.model_selection import train_test_split\nfrom PIL import Image\nimport os\nimport torch","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-06-17T23:18:16.686994Z","iopub.execute_input":"2025-06-17T23:18:16.687252Z","iopub.status.idle":"2025-06-17T23:18:19.252073Z","shell.execute_reply.started":"2025-06-17T23:18:16.687232Z","shell.execute_reply":"2025-06-17T23:18:19.251294Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"\n\n# Base directory (adjust if necessary)\nPNG_FOLDER = \"/kaggle/input/vinbigdata-chest-xray-resized-png-1024x1024/train\"\n\n\nBASE_DIR_csv = \"/kaggle/input/csv-data\"\nTRAIN_CSV = os.path.join(BASE_DIR_csv, \"train.csv\")\n\n# Load CSVs\ntrain_df = pd.read_csv(TRAIN_CSV)\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-06-17T23:18:21.97137Z","iopub.execute_input":"2025-06-17T23:18:21.971802Z","iopub.status.idle":"2025-06-17T23:18:22.132284Z","shell.execute_reply.started":"2025-06-17T23:18:21.971779Z","shell.execute_reply":"2025-06-17T23:18:22.131647Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"unique_scans = train_df[\"image_id\"].nunique()\nprint(f\"Number of unique chest X-ray scans in train.csv: {unique_scans}\")\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-06-17T23:18:24.956485Z","iopub.execute_input":"2025-06-17T23:18:24.957335Z","iopub.status.idle":"2025-06-17T23:18:24.982522Z","shell.execute_reply.started":"2025-06-17T23:18:24.957301Z","shell.execute_reply":"2025-06-17T23:18:24.981532Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# Group by class_name and count unique image_ids\nunique_per_class = train_df.groupby(\"class_name\")[\"image_id\"].nunique().sort_values(ascending=False)\n\n# Convert to DataFrame for display\nunique_per_class_df = unique_per_class.reset_index()\nunique_per_class_df.columns = [\"Class Name\", \"Unique Scan Count\"]\n\n# Display\nprint(unique_per_class_df)\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-06-17T23:18:26.896074Z","iopub.execute_input":"2025-06-17T23:18:26.896339Z","iopub.status.idle":"2025-06-17T23:18:26.93823Z","shell.execute_reply.started":"2025-06-17T23:18:26.896319Z","shell.execute_reply":"2025-06-17T23:18:26.937471Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"\n\n# Just check the first few images in the training folder\nsample_images = os.listdir(PNG_FOLDER)[:5]\n\nfor img_file in sample_images:\n    img_path = os.path.join(PNG_FOLDER, img_file)\n    with Image.open(img_path) as img:\n        print(f\"{img_file}: mode = {img.mode}\")","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-06-17T23:18:29.07517Z","iopub.execute_input":"2025-06-17T23:18:29.075847Z","iopub.status.idle":"2025-06-17T23:18:29.628117Z","shell.execute_reply.started":"2025-06-17T23:18:29.075816Z","shell.execute_reply":"2025-06-17T23:18:29.627306Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"\ntorch.cuda.empty_cache()\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-06-04T12:12:59.129731Z","iopub.execute_input":"2025-06-04T12:12:59.130271Z","iopub.status.idle":"2025-06-04T12:12:59.133889Z","shell.execute_reply.started":"2025-06-04T12:12:59.130248Z","shell.execute_reply":"2025-06-04T12:12:59.133203Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# =============== CONFIG ===============\n\nSEED = 21\n\n# =============== LOAD CSV ===============\ndf = pd.read_csv(TRAIN_CSV)\nprint(f\"before binary label (total_images ) : {len(df)}\")\n# =============== CREATE BINARY LABELS PER IMAGE ===============\n# Mark as \"abnormal\" if the image has any class_id != 14\nimg_label_df = df.groupby(\"image_id\")[\"class_id\"].apply(\n    lambda x: \"abnormal\" if (x != 14).any() else \"normal\"\n).reset_index()\nimg_label_df[\"binary_label\"] = (img_label_df[\"class_id\"] == \"abnormal\").astype(int)\n\nprint(f\"after binary label : {len(img_label_df)}\")\nprint(img_label_df.head(4))\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-06-17T23:18:32.05774Z","iopub.execute_input":"2025-06-17T23:18:32.058264Z","iopub.status.idle":"2025-06-17T23:18:33.183936Z","shell.execute_reply.started":"2025-06-17T23:18:32.058241Z","shell.execute_reply":"2025-06-17T23:18:33.183161Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"\n# =============== STRATIFIED SPLIT ON IMAGE_ID TO AVOID LEAKAGE ===============\ntrain_ids, val_ids = train_test_split(\n    img_label_df[\"image_id\"],\n    test_size=0.2,\n    stratify=img_label_df[\"binary_label\"],\n    random_state=SEED\n)\n\nprint(f\"train_ids_len : {len(train_ids)} , val_ids_len : {len(val_ids)} \")\ntrain_labels = img_label_df[img_label_df[\"image_id\"].isin(train_ids)][\"binary_label\"]\nval_labels = img_label_df[img_label_df[\"image_id\"].isin(val_ids)][\"binary_label\"]\nprint(\"-----------------------------------------------------------------------------------------\")\nprint(\"before Balance \")\nprint(\"Train set class distribution:\\n\", train_labels.value_counts())\nprint(\"Validation set class distribution:\\n\", val_labels.value_counts())\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-06-17T23:18:34.505148Z","iopub.execute_input":"2025-06-17T23:18:34.5054Z","iopub.status.idle":"2025-06-17T23:18:34.530717Z","shell.execute_reply.started":"2025-06-17T23:18:34.505382Z","shell.execute_reply":"2025-06-17T23:18:34.529918Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"import os\nimport pandas as pd\nimport numpy as np\nfrom sklearn.model_selection import train_test_split\n\n\n# Filter to get rows from the original DataFrame for full info\ntrain_df_all = img_label_df[img_label_df[\"image_id\"].isin(train_ids)].reset_index(drop=True)\nval_df_all = img_label_df[img_label_df[\"image_id\"].isin(val_ids)].reset_index(drop=True)\n\nprint(f\"train_df_all :{len(train_df_all)}\")\nprint(f\"val_df_all : {len(val_df_all)} \")\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-06-17T23:18:36.653086Z","iopub.execute_input":"2025-06-17T23:18:36.653341Z","iopub.status.idle":"2025-06-17T23:18:36.665949Z","shell.execute_reply.started":"2025-06-17T23:18:36.653321Z","shell.execute_reply":"2025-06-17T23:18:36.665205Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"\n# =============== BALANCE BOTH TRAIN AND VAL SETS ===============\ndef balance_dataframe(df, seed=SEED):\n    normal = df[df[\"binary_label\"] == 0]\n    abnormal = df[df[\"binary_label\"] == 1]\n    n_samples = min(len(normal), len(abnormal))\n    balanced = pd.concat([\n        normal.sample(n=n_samples, random_state=seed),\n        abnormal.sample(n=n_samples, random_state=seed)\n    ])\n    return balanced.sample(frac=1, random_state=seed).reset_index(drop=True)\n\nbalanced_train_df = balance_dataframe(train_df_all)\nbalanced_val_df = balance_dataframe(val_df_all)\n\n\n# =============== REPORT DISTRIBUTIONS ===============\nprint(\"-----------------------------------------------------------------------------------------\")\nprint()\nprint(\"After Balance \")\nprint(\"Balanced Train Set:\\n\", balanced_train_df[\"binary_label\"].value_counts())\nprint(\"Balanced Validation Set:\\n\", balanced_val_df[\"binary_label\"].value_counts())\nprint(balanced_train_df.head(3))","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-06-17T23:18:38.5391Z","iopub.execute_input":"2025-06-17T23:18:38.539382Z","iopub.status.idle":"2025-06-17T23:18:38.55733Z","shell.execute_reply.started":"2025-06-17T23:18:38.539357Z","shell.execute_reply":"2025-06-17T23:18:38.556612Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"\n# =============== ADD PNG PATHS ===============\n# Build full PNG path using the image_id + \".png\"\nbalanced_train_df[\"png_path\"] = balanced_train_df[\"image_id\"].apply(\n    lambda x: os.path.join(PNG_FOLDER, f\"{x}.png\")\n)\nbalanced_train_df = balanced_train_df[balanced_train_df[\"png_path\"].map(os.path.exists)].reset_index(drop=True)\n\nbalanced_val_df[\"png_path\"] = balanced_val_df[\"image_id\"].apply(\n    lambda x: os.path.join(PNG_FOLDER, f\"{x}.png\")\n)\nbalanced_val_df = balanced_val_df[balanced_val_df[\"png_path\"].map(os.path.exists)].reset_index(drop=True)\n\n# =============== FINAL REPORT ===============\nprint(\"----------------------------------------------------\")\nprint(\"Final DataFrame Columns:\", balanced_train_df.columns)\nprint(f\"Final balanced_train_df: {len(balanced_train_df)}\")\nprint(f\"Final balanced_val_df: {len(balanced_val_df)}\")","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-06-17T23:18:41.102941Z","iopub.execute_input":"2025-06-17T23:18:41.103183Z","iopub.status.idle":"2025-06-17T23:19:07.969387Z","shell.execute_reply.started":"2025-06-17T23:18:41.103165Z","shell.execute_reply":"2025-06-17T23:19:07.968763Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"print(balanced_train_df[\"png_path\"].head(3).tolist())","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-06-17T21:27:01.609558Z","iopub.execute_input":"2025-06-17T21:27:01.610316Z","iopub.status.idle":"2025-06-17T21:27:01.614691Z","shell.execute_reply.started":"2025-06-17T21:27:01.610284Z","shell.execute_reply":"2025-06-17T21:27:01.614018Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"import os\nfrom PIL import Image\nimport numpy as np\nfrom tqdm import tqdm\n\n# Get image paths from the balanced training set dont use val avoid (data leakage)\nimage_paths = balanced_train_df[\"png_path\"].values\n\nsums = np.zeros(3)\nsqs = np.zeros(3)\nn_images = len(image_paths)\n\nfor path in tqdm(image_paths, desc=\"Calculating mean/std\"):\n    img = Image.open(path).convert(\"RGB\").resize((256, 256))\n    img = np.array(img) / 255.0  # Normalize pixel values to [0, 1]\n    \n    # Accumulate per-channel mean and squared mean\n    sums += img.mean(axis=(0, 1))\n    sqs += (img ** 2).mean(axis=(0, 1))\n\n# Final RGB mean and std\nmean = sums / n_images\nstd = np.sqrt(sqs / n_images - mean ** 2)\n\nprint(\"Mean:\", mean)\nprint(\"Std:\", std)\n\n#olldddddd\n# Mean: [0.54862876 0.54862876 0.54862876]\n# Std: [0.2669181 0.2669181 0.2669181]\n\n#new final resized \n# Mean: [0.54820246 0.54820246 0.54820246]\n# Std: [0.26657398 0.26657398 0.26657398]","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-06-17T23:19:52.904925Z","iopub.execute_input":"2025-06-17T23:19:52.905203Z","iopub.status.idle":"2025-06-17T23:19:58.3197Z","shell.execute_reply.started":"2025-06-17T23:19:52.905184Z","shell.execute_reply":"2025-06-17T23:19:58.31885Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"BATCH_SIZE = 32\nNUM_WORKERS = 1\nEPOCHS = 30          # For demo; increase for real runs\nLR = 6e-5\nDEVICE = \"cuda\" if torch.cuda.is_available() else \"cpu\"\nSEED = 21\nIMG_SIZE = 256     #  input size\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-06-17T23:20:06.163475Z","iopub.execute_input":"2025-06-17T23:20:06.164028Z","iopub.status.idle":"2025-06-17T23:20:06.168037Z","shell.execute_reply.started":"2025-06-17T23:20:06.164007Z","shell.execute_reply":"2025-06-17T23:20:06.167217Z"}},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"","metadata":{}},{"cell_type":"code","source":"\n\nfrom torch.utils.data import Dataset, DataLoader\nfrom torchvision import transforms\nfrom PIL import Image\n\nmy_mean= [0.54820246 ,0.54820246 ,0.54820246]\nmy_std= [0.26657398 ,0.26657398 ,0.26657398]\n\n\n# =============== DATASET AND DATALOADER ===============\nclass VinBigDataset(Dataset):\n    def __init__(self, df, transform=None):\n        self.df = df.reset_index(drop=True)\n        self.transform = transform\n\n    def __len__(self):\n        return len(self.df)\n\n    def __getitem__(self, idx):\n        path = self.df.loc[idx, \"png_path\"]\n        img = Image.open(path)\n        label = self.df.loc[idx, \"binary_label\"]\n        if self.transform:\n            img = self.transform(img)\n        return img, label\n\n# Transforms\ntrain_transform = transforms.Compose([\n    transforms.Lambda(lambda img: img.convert(\"RGB\")),  # Convert to RGB (3 channels)\n    transforms.RandomResizedCrop(IMG_SIZE, scale=(0.8, 1.0)),\n    transforms.ColorJitter(brightness=0.2, contrast=0.2, saturation=0.2),\n    transforms.ToTensor(),\n     transforms.Normalize(mean=my_mean, std=my_std),\n     transforms.Resize((IMG_SIZE, IMG_SIZE))\n])\nval_transform = transforms.Compose([\n   transforms.Lambda(lambda img: img.convert(\"RGB\")),\n    transforms.Resize((IMG_SIZE, IMG_SIZE)),\n    transforms.ToTensor(),\n    transforms.Normalize(mean=my_mean, std=my_std)\n])\n\ntrain_set = VinBigDataset(balanced_train_df, transform=train_transform)\nval_set = VinBigDataset(balanced_val_df, transform=val_transform)\n\ntrain_loader = DataLoader(train_set, batch_size=BATCH_SIZE, shuffle=True, num_workers=NUM_WORKERS)\nval_loader = DataLoader(val_set, batch_size=BATCH_SIZE, shuffle=False, num_workers=NUM_WORKERS)\n\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-06-17T23:20:09.220919Z","iopub.execute_input":"2025-06-17T23:20:09.221172Z","iopub.status.idle":"2025-06-17T23:20:09.230763Z","shell.execute_reply.started":"2025-06-17T23:20:09.221152Z","shell.execute_reply":"2025-06-17T23:20:09.230014Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# # =============== MODEL ===============\nfrom torch import nn\nfrom torchvision import models\nfrom torch.optim.lr_scheduler import ReduceLROnPlateau  # Import scheduler\nfrom torch.optim.lr_scheduler import CosineAnnealingWarmRestarts\n# # model = models.densenet121(weights=\"IMAGENET1K_V1\")\n# # in_features = model.classifier.in_features  # get number of input features to final layer\n\n# # # Replace the classifier (final layer)\n# # model.classifier = nn.Sequential(\n# #     nn.Dropout(0.5),            # add dropout for regularization\n# #     nn.Linear(in_features, 2)   # output layer with 2 classes\n# # )\n\n\n\n# Load pretrained ResNet101\nmodel = models.resnet101(weights=\"IMAGENET1K_V1\")\n\n# Get number of input features to the final FC layer\nin_features = model.fc.in_features  # ResNet uses .fc, not .classifier\n\n# Replace the final fully connected layer with Dropout + Linear\nmodel.fc = nn.Sequential(\n    nn.Dropout(0.5),             # Dropout for regularization\n    nn.Linear(in_features, 2)    # Binary classification (2 classes)\n)\n\n# Move model to device (CPU or GPU)\nmodel = model.to(DEVICE)\n\n\n\n\ncriterion = nn.CrossEntropyLoss(label_smoothing=0.1)\noptimizer = torch.optim.AdamW(model.parameters(), lr=LR, weight_decay=1e-4)\n\n# Scheduler\nscheduler = CosineAnnealingWarmRestarts(optimizer, T_0=5, T_mult=2)\n# # =============== LOSS, OPTIM ===============\n# criterion = torch.nn.CrossEntropyLoss()\n# optimizer = torch.optim.AdamW(model.parameters(), lr=LR, weight_decay=1e-4)\n\n\n\nimport timm\n# from torch import nn\n\n# # Load Swin Transformer (e.g., swin_base_patch4_window7_224)\n# model = timm.create_model(\"swin_base_patch4_window7_224\", pretrained=True, num_classes=2)\n# model = timm.create_model(\"swin_base_patch4_window12_384\", pretrained=True, num_classes=2)\n\n# import timm\n# import torch.nn as nn\n\n# NUM_CLASSES = 2  \n\n\n# # Load model\n# model = timm.create_model(\"efficientnet_b0\", pretrained=True, num_classes=NUM_CLASSES)\n\n# model = model.to(\"cuda\" if torch.cuda.is_available() else \"cpu\")\n\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-06-17T23:20:13.347868Z","iopub.execute_input":"2025-06-17T23:20:13.348123Z","iopub.status.idle":"2025-06-17T23:20:20.248591Z","shell.execute_reply.started":"2025-06-17T23:20:13.348102Z","shell.execute_reply":"2025-06-17T23:20:20.247932Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# Just an explanation (not executable code):\n# x = lam * x1 + (1 - lam) * x2  \n# y = lam * y1 + (1 - lam) * y2\n\n# Actual code:\nimport torch.nn.functional as F\nimport random\nimport numpy as np\n\ndef mixup_data(x, y, alpha=1.0):\n    if alpha > 0:\n        lam = np.random.beta(alpha, alpha)\n    else:\n        lam = 1.0\n    batch_size = x.size()[0]\n    index = torch.randperm(batch_size).to(x.device)\n\n    mixed_x = lam * x + (1 - lam) * x[index, :]\n    y_a, y_b = y, y[index]\n    return mixed_x, y_a, y_b, lam\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-06-17T23:20:55.840431Z","iopub.execute_input":"2025-06-17T23:20:55.840912Z","iopub.status.idle":"2025-06-17T23:20:55.845584Z","shell.execute_reply.started":"2025-06-17T23:20:55.84089Z","shell.execute_reply":"2025-06-17T23:20:55.84492Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"\n# =============== TRAINING LOOP ===============\nfrom sklearn.metrics import accuracy_score\n\ndef train_one_epoch(model, loader, optimizer, criterion, alpha=0.4):\n    model.train()\n    running_loss = 0\n    all_preds, all_labels = [], []\n    for imgs, labels in tqdm(loader):\n        imgs, labels = imgs.to(DEVICE), labels.to(DEVICE)\n        \n        # Apply Mixup\n        imgs, targets_a, targets_b, lam = mixup_data(imgs, labels, alpha)\n\n        optimizer.zero_grad()\n        outputs = model(imgs)\n        \n        # Mixup loss: weighted loss between two targets\n        loss = lam * criterion(outputs, targets_a) + (1 - lam) * criterion(outputs, targets_b)\n\n        loss.backward()\n        optimizer.step()\n\n        running_loss += loss.item() * imgs.size(0)\n\n        # Use max prediction for metrics\n        preds = outputs.argmax(1).detach().cpu().numpy()\n        all_preds.extend(preds)\n        all_labels.extend(labels.cpu().numpy())  # original labels for metrics\n    epoch_loss = running_loss / len(loader.dataset)\n    acc = accuracy_score(all_labels, all_preds)\n    return epoch_loss, acc\n\n\ndef eval_one_epoch(model, loader, criterion):\n    model.eval()\n    running_loss = 0\n    all_preds, all_labels = [], []\n    with torch.no_grad():\n        for imgs, labels in loader:\n            imgs, labels = imgs.to(DEVICE), labels.to(DEVICE)\n            outputs = model(imgs)\n            loss = criterion(outputs, labels)\n            running_loss += loss.item() * imgs.size(0)\n            preds = outputs.argmax(1).detach().cpu().numpy()\n            all_preds.extend(preds)\n            all_labels.extend(labels.cpu().numpy())\n    epoch_loss = running_loss / len(loader.dataset)\n    acc = accuracy_score(all_labels, all_preds)\n    return epoch_loss, acc, all_preds, all_labels\n\ntrain_losses, val_losses, train_accs, val_accs = [], [], [], []\nbest_val_loss = float('inf')\nfor epoch in range(EPOCHS):\n    print(f\"Epoch {epoch+1}/{EPOCHS}\")\n    \n    tr_loss, tr_acc = train_one_epoch(model, train_loader, optimizer, criterion)\n    val_loss, val_acc, val_preds, val_labels = eval_one_epoch(model, val_loader, criterion)\n\n    train_losses.append(tr_loss)\n    val_losses.append(val_loss)\n    train_accs.append(tr_acc)\n    val_accs.append(val_acc)\n\n        # Step the scheduler AFTER each epoch (for warm restarts)\n    scheduler.step()\n\n    print(f\"  Train loss: {tr_loss:.4f}, acc: {tr_acc:.4f}\")\n    print(f\"  Val   loss: {val_loss:.4f}, acc: {val_acc:.4f}\")\n  \n    # Save model if validation loss improves\n    if val_loss < best_val_loss:\n        best_val_loss = val_loss\n        print(\"  🔥 Best model so far. Saving...\")\n        torch.save(model.state_dict(), \"best_model_weights_resnet101_FINAL.pth\")  # Save only weights\n        torch.save(model, \"best_model_full_resnet101_FINAL.pth\")  # save full model\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-06-17T23:21:02.773518Z","iopub.execute_input":"2025-06-17T23:21:02.774275Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"print(f\"Train loss: {train_losses[-2]:.4f}, acc: {train_accs[-2]:.4f}\")\nprint(f\"Val   loss: {val_losses[-2]:.4f}, acc: {val_accs[-2]:.4f}\")\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-06-15T18:34:00.107945Z","iopub.execute_input":"2025-06-15T18:34:00.108207Z","iopub.status.idle":"2025-06-15T18:34:00.112781Z","shell.execute_reply.started":"2025-06-15T18:34:00.108182Z","shell.execute_reply":"2025-06-15T18:34:00.112002Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"DEVICE = \"cuda\" if torch.cuda.is_available() else \"cpu\"\nmodel_loaded = torch.load(\"/kaggle/input/resnet101_normal_vs_abnormal/pytorch/default/1/best_model_full_resnet101_NDL_ (1).pth\", weights_only=False)\nmodel_loaded = model_loaded.to(DEVICE)\n# model_loaded.eval()","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-06-17T21:24:13.097237Z","iopub.execute_input":"2025-06-17T21:24:13.097968Z","iopub.status.idle":"2025-06-17T21:24:13.358251Z","shell.execute_reply.started":"2025-06-17T21:24:13.097946Z","shell.execute_reply":"2025-06-17T21:24:13.357462Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"import torch\nfrom sklearn.metrics import confusion_matrix, classification_report\nimport matplotlib.pyplot as plt\nimport numpy as np\nimport pandas as pd\n\nDEVICE = torch.device(\"cuda\" if torch.cuda.is_available() else \"cpu\")\nmodel_loaded.to(DEVICE)\nmodel_loaded.eval()\n\n# Get image_ids from the validation DataFrame\nimage_ids_val = balanced_val_df[\"image_id\"].values\n\nval_preds = []\nval_labels = []\nval_image_ids = []\nval_loss_total = 0.0\nval_correct = 0\nval_samples = 0\n\ncriterion = torch.nn.CrossEntropyLoss()\n\ni = 0  # to index image_ids_val\n\nwith torch.no_grad():\n    for images, labels in val_loader:\n        images = images.to(DEVICE)\n        labels = labels.to(DEVICE)\n        \n        outputs = model_loaded(images)\n        loss = criterion(outputs, labels)\n        val_loss_total += loss.item() * images.size(0)\n\n        preds = torch.argmax(outputs, dim=1)\n\n        val_preds.extend(preds.cpu().numpy())\n        val_labels.extend(labels.cpu().numpy())\n        val_image_ids.extend(image_ids_val[i:i+len(images)])  # append batch of image_ids\n        i += len(images)\n\n        val_correct += (preds == labels).sum().item()\n        val_samples += labels.size(0)\n\n# Compute metrics\nval_loss_avg = val_loss_total / val_samples\nval_accuracy = val_correct / val_samples\n\nprint(f\"Val loss: {val_loss_avg:.4f}, Val accuracy: {val_accuracy:.4f}\")\n\n# Confusion matrix\ncm = confusion_matrix(val_labels, val_preds)\nprint(\"Classification Report:\")\nprint(classification_report(val_labels, val_preds, target_names=[\"Normal\", \"Abnormal\"]))\n\n# Plot\nplt.figure(figsize=(5, 5))\nplt.imshow(cm, cmap=\"Blues\")\nplt.title(\"Confusion Matrix\")\nplt.xlabel(\"Predicted\")\nplt.ylabel(\"True\")\nplt.xticks([0, 1], [\"Normal\", \"Abnormal\"])\nplt.yticks([0, 1], [\"Normal\", \"Abnormal\"])\nfor i in range(2):\n    for j in range(2):\n        plt.text(j, i, cm[i, j], ha=\"center\", va=\"center\", color=\"red\")\nplt.tight_layout()\nplt.show()\n\n# Create DataFrame for all predictions\nresults_df = pd.DataFrame({\n    \"image_id\": val_image_ids,\n    \"true_label\": val_labels,\n    \"pred_label\": val_preds\n})\n\n# Filter wrong predictions\nwrong_df = results_df[results_df[\"true_label\"] != results_df[\"pred_label\"]]\nprint(\"\\nWrong Predictions:\")\nprint(wrong_df.head())\n\n# Save wrong predictions\nwrong_df.to_csv(\"wrong_image_ids.csv\", index=False)\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-06-17T21:27:18.779081Z","iopub.execute_input":"2025-06-17T21:27:18.779843Z","iopub.status.idle":"2025-06-17T21:28:13.160282Z","shell.execute_reply.started":"2025-06-17T21:27:18.779808Z","shell.execute_reply":"2025-06-17T21:28:13.159626Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"print(len(wrong_df))","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-06-17T21:30:16.771779Z","iopub.execute_input":"2025-06-17T21:30:16.772444Z","iopub.status.idle":"2025-06-17T21:30:16.777131Z","shell.execute_reply.started":"2025-06-17T21:30:16.772417Z","shell.execute_reply":"2025-06-17T21:30:16.776414Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# Re-load predictions (if needed)\nwrong_df = pd.read_csv(\"wrong_image_ids.csv\")\n\n# Check duplicates in CSV before merging\ncsv_path = \"/kaggle/input/csv-data/train.csv\"\ndf = pd.read_csv(csv_path)\n\n# Drop duplicates for correct merge\ndf_unique = df[[\"image_id\", \"class_name\"]].drop_duplicates(\"image_id\")\n\n# Safe merge (avoid row multiplication)\nwrong_df = wrong_df.merge(df_unique, on=\"image_id\", how=\"left\")\n\n# Now group correctly\nwrong_normal = wrong_df[wrong_df[\"true_label\"] == 0]\nwrong_abnormal = wrong_df[wrong_df[\"true_label\"] == 1]\n\nprint(\"Wrong predictions total:\", len(wrong_df))\nprint(\"Wrong predictions — True Normal:\", len(wrong_normal))\nprint(\"Wrong predictions — True Abnormal:\", len(wrong_abnormal))\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-06-17T21:30:20.623382Z","iopub.execute_input":"2025-06-17T21:30:20.62365Z","iopub.status.idle":"2025-06-17T21:30:20.739744Z","shell.execute_reply.started":"2025-06-17T21:30:20.623632Z","shell.execute_reply":"2025-06-17T21:30:20.739117Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"import os\nimport shutil\nfrom tqdm import tqdm\n\n# 1. Define your image source directory\nimage_folder = PNG_FOLDER  # change if your images are elsewhere\n\n# 2. Create output folders\nos.makedirs(\"wrong_normal_images\", exist_ok=True)\nos.makedirs(\"wrong_abnormal_images\", exist_ok=True)\n\n# 3. Copy images for wrong_normal\nfor image_id in tqdm(wrong_normal[\"image_id\"]):\n    src = os.path.join(image_folder, image_id + \".png\")  # adjust if it's .jpg or another format\n    dst = os.path.join(\"wrong_normal_images\", image_id + \".png\")\n    if os.path.exists(src):\n        shutil.copy(src, dst)\n\n# 4. Copy images for wrong_abnormal\nfor image_id in tqdm(wrong_abnormal[\"image_id\"]):\n    src = os.path.join(image_folder, image_id + \".png\")\n    dst = os.path.join(\"wrong_abnormal_images\", image_id + \".png\")\n    if os.path.exists(src):\n        shutil.copy(src, dst)\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-06-17T21:33:03.082241Z","iopub.execute_input":"2025-06-17T21:33:03.082947Z","iopub.status.idle":"2025-06-17T21:33:03.273848Z","shell.execute_reply.started":"2025-06-17T21:33:03.082921Z","shell.execute_reply":"2025-06-17T21:33:03.273224Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"import os\n\n# Define paths\nnormal_dir = \"wrong_normal_images\"\nabnormal_dir = \"wrong_abnormal_images\"\n\n# Count PNG files in each\nnormal_count = len([f for f in os.listdir(normal_dir) if f.endswith(\".png\")])\nabnormal_count = len([f for f in os.listdir(abnormal_dir) if f.endswith(\".png\")])\n\nprint(f\"🟢 wrong_normal_images folder: {normal_count} images\")\nprint(f\"🔴 wrong_abnormal_images folder: {abnormal_count} images\")\n\n# Optional: confirm they match the DataFrame lengths\nprint(f\"(Expected: {len(wrong_normal)} normal, {len(wrong_abnormal)} abnormal)\")\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-06-17T21:33:53.481374Z","iopub.execute_input":"2025-06-17T21:33:53.482103Z","iopub.status.idle":"2025-06-17T21:33:53.488135Z","shell.execute_reply.started":"2025-06-17T21:33:53.482079Z","shell.execute_reply":"2025-06-17T21:33:53.487469Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# Zip the folders\n!zip -r wrong_normal_images.zip wrong_normal_images\n!zip -r wrong_abnormal_images.zip wrong_abnormal_images\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-06-17T21:37:14.559084Z","iopub.execute_input":"2025-06-17T21:37:14.559648Z","iopub.status.idle":"2025-06-17T21:37:16.697731Z","shell.execute_reply.started":"2025-06-17T21:37:14.559628Z","shell.execute_reply":"2025-06-17T21:37:16.697013Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"import matplotlib.pyplot as plt\nfrom PIL import Image\nimport os\nimport math\n\n# Path to image folder\nimages_folder = \"/kaggle/input/vinbigdata-chest-xray-resized-png-1024x1024/train\"\n\n# Total images to display\ntotal = len(wrong_normal)\ncols = 5\nrows = math.ceil(total / cols)\n\nplt.figure(figsize=(cols * 4, rows * 4))\nfor i, row in enumerate(wrong_normal.itertuples()):\n    img_path = os.path.join(images_folder, row.image_id + \".png\")\n    img = Image.open(img_path).convert(\"RGB\")\n    \n    plt.subplot(rows, cols, i + 1)\n    plt.imshow(img)\n    plt.title(f\"True: {row.class_name}\\nPred: Abnormal\", fontsize=9)\n    plt.axis(\"off\")\n\nplt.suptitle(\"Misclassified — True: Normal\", fontsize=18)\nplt.tight_layout(rect=[0, 0.03, 1, 0.95])\nplt.show()\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-06-17T21:30:32.457881Z","iopub.execute_input":"2025-06-17T21:30:32.458161Z","iopub.status.idle":"2025-06-17T21:30:46.992896Z","shell.execute_reply.started":"2025-06-17T21:30:32.458142Z","shell.execute_reply":"2025-06-17T21:30:46.992065Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"import os\nimport matplotlib.pyplot as plt\nfrom PIL import Image\nimport math\n\n# Folder containing images\nimages_folder = \"/kaggle/input/vinbigdata-chest-xray-resized-png-1024x1024/train\"\n\n# Number of images to plot\ntotal = len(wrong_abnormal)\ncols = 5\nrows = math.ceil(total / cols)\n\nplt.figure(figsize=(cols * 4, rows * 4))\n\nfor i, row in enumerate(wrong_abnormal.itertuples()):\n    img_path = os.path.join(images_folder, row.image_id + \".png\")\n    img = Image.open(img_path).convert(\"RGB\")\n\n    plt.subplot(rows, cols, i + 1)\n    plt.imshow(img)\n    plt.title(f\"True: {row.class_name}\\nPred: Normal\", fontsize=9)\n    plt.axis(\"off\")\n\nplt.suptitle(\"All Misclassified Images — True: Abnormal\", fontsize=18)\nplt.tight_layout(rect=[0, 0.03, 1, 0.95])\nplt.show()\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-06-15T19:34:29.041766Z","iopub.execute_input":"2025-06-15T19:34:29.042057Z","iopub.status.idle":"2025-06-15T19:34:40.723683Z","shell.execute_reply.started":"2025-06-15T19:34:29.042036Z","shell.execute_reply":"2025-06-15T19:34:40.722569Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"\nassert (wrong_abnormal[\"true_label\"] == 1).all()\n\n\nabnormal_error_counts = wrong_abnormal[\"class_name\"].value_counts().reset_index()\nabnormal_error_counts.columns = [\"class_name\", \"num_wrong_predictions\"]\n\n\nprint(abnormal_error_counts)\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-06-15T19:36:17.760437Z","iopub.execute_input":"2025-06-15T19:36:17.761083Z","iopub.status.idle":"2025-06-15T19:36:17.768809Z","shell.execute_reply.started":"2025-06-15T19:36:17.76106Z","shell.execute_reply":"2025-06-15T19:36:17.768106Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"\ncsv_path = \"/kaggle/input/csv-data/train.csv\"\ndf = pd.read_csv(csv_path)\ndf_unique = df[[\"image_id\", \"class_name\"]].drop_duplicates(\"image_id\")\n\n\nresults_df = results_df.merge(df_unique, on=\"image_id\", how=\"left\")\n\n# -----------------------------------\n\nwrong_df = results_df[results_df[\"true_label\"] != results_df[\"pred_label\"]]\nwrong_abnormal = wrong_df[wrong_df[\"true_label\"] == 1]\nwrong_counts = wrong_abnormal[\"class_name\"].value_counts().reset_index()\nwrong_counts.columns = [\"class_name\", \"num_wrong_predictions\"]\n\n# -----------------------------------\n\ncorrect_abnormal = results_df[\n    (results_df[\"true_label\"] == 1) & (results_df[\"pred_label\"] == 1)\n]\ncorrect_counts = correct_abnormal[\"class_name\"].value_counts().reset_index()\ncorrect_counts.columns = [\"class_name\", \"num_correct_predictions\"]\n\n# -----------------------------------\n\nsummary_df = pd.merge(correct_counts, wrong_counts, on=\"class_name\", how=\"outer\").fillna(0)\nsummary_df[[\"num_correct_predictions\", \"num_wrong_predictions\"]] = summary_df[[\"num_correct_predictions\", \"num_wrong_predictions\"]].astype(int)\n\n\nprint(summary_df.sort_values(by=\"class_name\").reset_index(drop=True))\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-06-15T19:42:03.724756Z","iopub.execute_input":"2025-06-15T19:42:03.725461Z","iopub.status.idle":"2025-06-15T19:42:03.841393Z","shell.execute_reply.started":"2025-06-15T19:42:03.725438Z","shell.execute_reply":"2025-06-15T19:42:03.840749Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"import pandas as pd\n\n# Load full dataset\ncsv_path = \"/kaggle/input/csv-data/train.csv\"\ndf = pd.read_csv(csv_path)\n\n\ndf_unique = df[[\"image_id\", \"class_name\"]].drop_duplicates(\"image_id\")\n\n\ntrain_ids = balanced_train_df[\"image_id\"].values\nval_ids = balanced_val_df[\"image_id\"].values\n\n\ndf_unique[\"set\"] = df_unique[\"image_id\"].apply(\n    lambda x: \"train\" if x in train_ids else \"val\" if x in val_ids else \"other\"\n)\n\npivot_table = pd.pivot_table(\n    df_unique,\n    index=\"class_name\",\n    columns=\"set\",\n    aggfunc=\"size\",\n    fill_value=0\n).reset_index()\n\n\npivot_table = pivot_table.rename(columns={\"train\": \"train_count\", \"val\": \"val_count\"})\n\n\nprint(pivot_table)\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-06-15T19:52:58.784083Z","iopub.execute_input":"2025-06-15T19:52:58.784678Z","iopub.status.idle":"2025-06-15T19:53:01.906535Z","shell.execute_reply.started":"2025-06-15T19:52:58.784655Z","shell.execute_reply":"2025-06-15T19:53:01.905701Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"import pandas as pd\n\n# ---- [1] Load Dataset + Unique image/class\ncsv_path = \"/kaggle/input/csv-data/train.csv\"\ndf = pd.read_csv(csv_path)\ndf_unique = df[[\"image_id\", \"class_name\"]].drop_duplicates(subset=\"image_id\")\n\n# ---- [2] Assign train / val to each image\ntrain_ids = set(balanced_train_df[\"image_id\"].values)\nval_ids = set(balanced_val_df[\"image_id\"].values)\n\ndf_unique[\"set\"] = df_unique[\"image_id\"].apply(\n    lambda x: \"train\" if x in train_ids else \"val\" if x in val_ids else \"other\"\n)\n\n# ---- [3] Compute train and val counts per class\npivot_table = pd.pivot_table(\n    df_unique,\n    index=\"class_name\",\n    columns=\"set\",\n    aggfunc=\"size\",\n    fill_value=0\n).reset_index()\n\npivot_table = pivot_table.rename(columns={\"train\": \"train_count\", \"val\": \"val_count\"})\n\n# ---- [4] Add class_name info to prediction results\nresults_df = results_df.merge(df_unique[[\"image_id\", \"class_name\"]], on=\"image_id\", how=\"left\")\n\n# ---- [5] Wrong predictions for abnormal class (true=1, pred=0)\nwrong_df = results_df[results_df[\"true_label\"] != results_df[\"pred_label\"]]\nwrong_abnormal = wrong_df[wrong_df[\"true_label\"] == 1]\nwrong_counts = wrong_abnormal[\"class_name\"].value_counts().reset_index()\nwrong_counts.columns = [\"class_name\", \"num_wrong_predictions\"]\n\n# ---- [6] Correct predictions for abnormal class (true=1, pred=1)\ncorrect_abnormal = results_df[\n    (results_df[\"true_label\"] == 1) & (results_df[\"pred_label\"] == 1)\n]\ncorrect_counts = correct_abnormal[\"class_name\"].value_counts().reset_index()\ncorrect_counts.columns = [\"class_name\", \"num_correct_predictions\"]\n\n# ---- [7] Merge correct + wrong counts\nperformance_df = pd.merge(correct_counts, wrong_counts, on=\"class_name\", how=\"outer\").fillna(0)\nperformance_df[[\"num_correct_predictions\", \"num_wrong_predictions\"]] = performance_df[\n    [\"num_correct_predictions\", \"num_wrong_predictions\"]\n].astype(int)\n\n# ---- [8] Merge with pivot_table to add train/val count\nsummary_df = pd.merge(pivot_table, performance_df, on=\"class_name\", how=\"outer\").fillna(0)\nsummary_df[[\"train_count\", \"val_count\", \"num_correct_predictions\", \"num_wrong_predictions\"]] = summary_df[\n    [\"train_count\", \"val_count\", \"num_correct_predictions\", \"num_wrong_predictions\"]\n].astype(int)\n\n# ---- [9] Final result\nsummary_df = summary_df.sort_values(\"class_name\").reset_index(drop=True)\nprint(summary_df)\n\n# ---- [Optional] Save to CSV\nsummary_df.to_csv(\"class_prediction_summary.csv\", index=False)\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-06-15T19:56:52.78625Z","iopub.execute_input":"2025-06-15T19:56:52.786545Z","iopub.status.idle":"2025-06-15T19:56:52.901876Z","shell.execute_reply.started":"2025-06-15T19:56:52.786527Z","shell.execute_reply":"2025-06-15T19:56:52.901224Z"}},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"**# Complete training on saved model**# ","metadata":{}},{"cell_type":"code","source":"# import torch\n# from torch import nn\n# from torch.utils.data import DataLoader\n# from sklearn.metrics import accuracy_score\n# from tqdm import tqdm\n# import timm\n\n# # ============ CONFIGURATION ============\n# DEVICE = torch.device(\"cuda\" if torch.cuda.is_available() else \"cpu\")\n# LR = 5e-5\n# EPOCHS = 30  # Update this based on how many total epochs you want\n# start_epoch = 15  # Change this to the last saved epoch + 1\n# best_val_loss = float('inf')\n\n# # ============ LOAD SAVED MODEL ============\n# model_swin = torch.load(\"/kaggle/working/best_model_full_Swin_Model_.pth\" , weights_only=False)\n# model_swin = model_swin.to(DEVICE)\n  \n# # ============ LOSS AND OPTIMIZER ============\n# criterion = nn.CrossEntropyLoss()\n# optimizer = torch.optim.AdamW(model_swin.parameters(), lr=LR, weight_decay=1e-4)\n\n# # ============ TRAINING AND EVAL FUNCTIONS ============\n# def train_one_epoch(model, loader, optimizer, criterion):\n#     model.train()\n#     running_loss = 0\n#     all_preds, all_labels = [], []\n#     for imgs, labels in tqdm(loader):\n#         imgs, labels = imgs.to(DEVICE), labels.to(DEVICE)\n#         optimizer.zero_grad()\n#         outputs = model(imgs)\n#         loss = criterion(outputs, labels)\n#         loss.backward()\n#         optimizer.step()\n#         running_loss += loss.item() * imgs.size(0)\n#         preds = outputs.argmax(1).detach().cpu().numpy()\n#         all_preds.extend(preds)\n#         all_labels.extend(labels.cpu().numpy())\n#     epoch_loss = running_loss / len(loader.dataset)\n#     acc = accuracy_score(all_labels, all_preds)\n#     return epoch_loss, acc\n\n# def eval_one_epoch(model, loader, criterion):\n#     model.eval()\n#     running_loss = 0\n#     all_preds, all_labels = [], []\n#     with torch.no_grad():\n#         for imgs, labels in loader:\n#             imgs, labels = imgs.to(DEVICE), labels.to(DEVICE)\n#             outputs = model(imgs)\n#             loss = criterion(outputs, labels)\n#             running_loss += loss.item() * imgs.size(0)\n#             preds = outputs.argmax(1).detach().cpu().numpy()\n#             all_preds.extend(preds)\n#             all_labels.extend(labels.cpu().numpy())\n#     epoch_loss = running_loss / len(loader.dataset)\n#     acc = accuracy_score(all_labels, all_preds)\n#     return epoch_loss, acc, all_preds, all_labels\n\n\n# # ============ RESUME TRAINING ============\n# train_losses, val_losses, train_accs, val_accs = [], [], [], []\n\n# for epoch in range(start_epoch, EPOCHS):\n#     print(f\"Epoch {epoch+1}/{EPOCHS}\")\n    \n#     tr_loss, tr_acc = train_one_epoch(model_swin, train_loader, optimizer, criterion)\n#     val_loss, val_acc, val_preds, val_labels = eval_one_epoch(model_swin, val_loader, criterion)\n\n#     train_losses.append(tr_loss)\n#     val_losses.append(val_loss)\n#     train_accs.append(tr_acc)\n#     val_accs.append(val_acc)\n\n#     print(f\"  Train loss: {tr_loss:.4f}, acc: {tr_acc:.4f}\")\n#     print(f\"  Val   loss: {val_loss:.4f}, acc: {val_acc:.4f}\")\n\n#     if val_loss < best_val_loss:\n#         best_val_loss = val_loss\n#         print(\"  🔥 Best model so far. Saving...\")\n#         torch.save(model_swin.state_dict(), \"best_model_weights_Swin_Model_second_.pth\")\n#         torch.save(model_swin, \"best_model_full_Swin_Model_second_.pth\")\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-06-15T19:12:41.551704Z","iopub.execute_input":"2025-06-15T19:12:41.552024Z","iopub.status.idle":"2025-06-15T19:12:41.557938Z","shell.execute_reply.started":"2025-06-15T19:12:41.551997Z","shell.execute_reply":"2025-06-15T19:12:41.557234Z"}},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"**Loaded Model**","metadata":{}},{"cell_type":"code","source":"import torch\nfrom torchvision import transforms\nfrom PIL import Image\n\n# Set device\nDEVICE = torch.device(\"cuda\" if torch.cuda.is_available() else \"cpu\")\n\n# # Your normalization values used in training (example)\n# Mean: [0.54862876 0.54862876 0.54862876]\n# Std: [0.2669181 0.2669181 0.2669181]\n\n# Define transformations (same as used during training)\ntransform = transforms.Compose([\n    transforms.Resize((256, 256)),  # Adjust size if your model uses another input size\n    transforms.ToTensor(),\n    transforms.Normalize(mean=my_mean, std=my_std)\n])\n\n\n\n# Label map\nlabel_map = {0: \"Normal\", 1: \"Abnormal\"}\n\n# Function to load and preprocess image\ndef load_image(image_path):\n    img = Image.open(image_path).convert('RGB')\n    img = transform(img)\n    img = img.unsqueeze(0)  # add batch dimension\n    return img\n\n# Function to predict class from image path\ndef predict_image(model, image_path, device):\n    img_tensor = load_image(image_path).to(device)\n    with torch.no_grad():\n        output = model(img_tensor)\n        pred = torch.argmax(output, dim=1).item()\n    return pred\n\n# Example usage:\nimage_path = \"/kaggle/input/vinbigdata-chest-xray-resized-png-1024x1024/train/d3637a1935a905b3c326af31389cb846.png\"  # <-- change to your image path\n\npredicted_class = predict_image(model_loaded, image_path, DEVICE)\nprint(f\"Prediction: {label_map[predicted_class]}\")\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-06-15T19:13:07.948079Z","iopub.execute_input":"2025-06-15T19:13:07.948387Z","iopub.status.idle":"2025-06-15T19:13:08.003757Z","shell.execute_reply.started":"2025-06-15T19:13:07.948363Z","shell.execute_reply":"2025-06-15T19:13:08.002864Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"import os\nimport pandas as pd\nimport matplotlib.pyplot as plt\nimport numpy as np\nimport random\nfrom PIL import Image\n\n# Path to CSV and images folder\ntrain_csv_path = \"/kaggle/input/csv-data/train.csv\"  # adjust if needed\nimages_folder = \"/kaggle/input/vinbigdata-chest-xray-resized-png-1024x1024/train\"  # adjust if needed\n\ndf_train = pd.read_csv(train_csv_path)\n\n# Sample 30 random rows\nsample_df = df_train.sample(n=30).reset_index(drop=True)\n\ndef load_image(image_path):\n    img = Image.open(image_path).convert('RGB')\n    img_t = transform(img)# Transformed tensor (normalized, resized, etc.)\n    img_t = img_t.unsqueeze(0)\n    return img, img_t\n\ndef predict_image(model, img_tensor, device):\n    img_tensor = img_tensor.to(device)\n    with torch.no_grad():\n        output = model(img_tensor)\n        pred = torch.argmax(output, dim=1).item()\n    return pred\n\nplt.figure(figsize=(20, 15))\nfor i, row in sample_df.iterrows():\n    # Construct full image path\n    img_path = os.path.join(images_folder, row[\"image_id\"] + \".png\")  # add extension if missing\n\n    true_class_name = row[\"class_name\"]\n    true_binary_label = row[\"class_id\"]\n\n    # Load image & tensor\n    img, img_tensor = load_image(img_path)\n\n    # Predict use the loaded  model \n    pred_label = predict_image(model_loaded, img_tensor, DEVICE)\n    pred_class_name = label_map[pred_label]\n\n    plt.subplot(5, 6, i + 1)\n    plt.imshow(img)\n    plt.title(f\"True: {true_class_name}\\nPred: {pred_class_name}\", fontsize=9)\n    plt.axis(\"off\")\n\nplt.tight_layout()\nplt.show()\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-06-15T18:41:35.914141Z","iopub.execute_input":"2025-06-15T18:41:35.914417Z","iopub.status.idle":"2025-06-15T18:41:42.067683Z","shell.execute_reply.started":"2025-06-15T18:41:35.914395Z","shell.execute_reply":"2025-06-15T18:41:42.066953Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-06-15T19:07:25.057474Z","iopub.execute_input":"2025-06-15T19:07:25.058098Z","iopub.status.idle":"2025-06-15T19:07:25.163283Z","shell.execute_reply.started":"2025-06-15T19:07:25.058072Z","shell.execute_reply":"2025-06-15T19:07:25.162508Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"\n# ------------ Display Wrong Normal Images ------------\nplt.figure(figsize=(18, 12))\nfor i, (_, row) in enumerate(wrong_normal.head(12).iterrows()):\n    img_path = os.path.join(images_folder, row[\"image_id\"] + \".png\")\n    img = Image.open(img_path).convert(\"RGB\")\n\n    plt.subplot(3, 4, i + 1)\n    plt.imshow(img)\n    plt.title(f\"True: Normal\\nPred: Abnormal\", fontsize=10)\n    plt.axis(\"off\")\n\nplt.suptitle(\"Wrong Predictions — True Label is Normal\", fontsize=16)\nplt.tight_layout(rect=[0, 0.03, 1, 0.95])\nplt.show()\n\n# ------------ Display Wrong Abnormal Images ------------\nplt.figure(figsize=(18, 12))\nfor i, (_, row) in enumerate(wrong_abnormal.head(12).iterrows()):\n    img_path = os.path.join(images_folder, row[\"image_id\"] + \".png\")\n    img = Image.open(img_path).convert(\"RGB\")\n\n    plt.subplot(3, 4, i + 1)\n    plt.imshow(img)\n    plt.title(f\"True: {row['class_name']}\\nPred: Normal\", fontsize=10)\n    plt.axis(\"off\")\n\nplt.suptitle(\"Wrong Predictions — True Label is Abnormal\", fontsize=16)\nplt.tight_layout(rect=[0, 0.03, 1, 0.95])\nplt.show()\n","metadata":{"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"**LOAD MODEL AND EVALUATE**","metadata":{}},{"cell_type":"code","source":"import torch\nfrom PIL import Image\nfrom torchvision import transforms\nimport pydicom\nimport numpy as np\n\n# Set device\nDEVICE = torch.device(\"cuda\" if torch.cuda.is_available() else \"cpu\")\n\n# Normalization values used in training\nmean = [0.54821104, 0.54821104, 0.54821104]\nstd = [0.26668723, 0.26668723, 0.26668723]\n\n# Label map\nlabel_map = {0: \"Normal\", 1: \"Abnormal\"}\n\n# Function to load full model\ndef load_full_model(model_path, device):\n    model = torch.load(model_path, map_location=device, weights_only=False)\n    model.eval()\n    return model\n\n# Convert DICOM image to PIL RGB\ndef dicom_to_pil(dicom_path):\n    ds = pydicom.dcmread(dicom_path)\n    img = ds.pixel_array.astype(np.float32)\n\n    # Normalize to [0, 255]\n    img -= img.min()\n    img /= (img.max() + 1e-6)\n    img *= 255.0\n    img = img.astype(np.uint8)\n\n    return Image.fromarray(img).convert(\"RGB\")\n\n# Predict from DICOM image path\ndef predict_dicom(model, dicom_path, mean, std, device):\n    transform = transforms.Compose([\n        transforms.Resize((256, 256)),\n        transforms.ToTensor(),\n        transforms.Normalize(mean=mean, std=std)\n    ])\n\n    pil_img = dicom_to_pil(dicom_path)\n    img_tensor = transform(pil_img).unsqueeze(0).to(device)\n\n    with torch.no_grad():\n        output = model(img_tensor)\n        pred = torch.argmax(output, dim=1).item()\n\n    return pred","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-06-08T12:03:53.757762Z","iopub.execute_input":"2025-06-08T12:03:53.758028Z","iopub.status.idle":"2025-06-08T12:03:53.765623Z","shell.execute_reply.started":"2025-06-08T12:03:53.758009Z","shell.execute_reply":"2025-06-08T12:03:53.764861Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"#normal\n# \"/kaggle/input/vinbigdata-chest-xray-abnormalities-detection/train/00053190460d56c53cc3e57321387478.dicom\"\n\n\n\n# Load model\nmodel_path = \"/kaggle/working/best_model_full_resnet101_NDL_.pth\"\nmodel_loaded = load_full_model(model_path, DEVICE)\n\n# Predict from DICOM\ndicom_path = \"/kaggle/input/vinbigdata-chest-xray-abnormalities-detection/train/0061cf6d35e253b6e7f03940592cc35e.dicom\"\npredicted_class = predict_dicom(model_loaded, dicom_path, mean, std, DEVICE)\n\nprint(f\"Prediction: {label_map[predicted_class]}\")","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-06-08T12:06:10.169816Z","iopub.execute_input":"2025-06-08T12:06:10.170303Z","iopub.status.idle":"2025-06-08T12:06:10.58239Z","shell.execute_reply.started":"2025-06-08T12:06:10.170279Z","shell.execute_reply":"2025-06-08T12:06:10.581676Z"}},"outputs":[],"execution_count":null}]}