{"metadata":{"kernelspec":{"language":"python","display_name":"Python 3","name":"python3"},"language_info":{"name":"python","version":"3.11.13","mimetype":"text/x-python","codemirror_mode":{"name":"ipython","version":3},"pygments_lexer":"ipython3","nbconvert_exporter":"python","file_extension":".py"},"kaggle":{"accelerator":"gpu","dataSources":[{"sourceId":11848,"databundleVersionId":862157,"sourceType":"competition"}],"dockerImageVersionId":31193,"isInternetEnabled":true,"language":"python","sourceType":"notebook","isGpuEnabled":true}},"nbformat_minor":4,"nbformat":4,"cells":[{"cell_type":"code","source":"# This Python 3 environment comes with many helpful analytics libraries installed\n# It is defined by the kaggle/python Docker image: https://github.com/kaggle/docker-python\n# For example, here's several helpful packages to load\n\nimport numpy as np # linear algebra\nimport pandas as pd # data processing, CSV file I/O (e.g. pd.read_csv)\n\n# Input data files are available in the read-only \"../input/\" directory\n# For example, running this (by clicking run or pressing Shift+Enter) will list all files under the input directory\n\nimport os\nfor dirname, _, filenames in os.walk('/kaggle/input'):\n    for filename in filenames:\n        print(os.path.join(dirname, filename))\n\n# You can write up to 20GB to the current directory (/kaggle/working/) that gets preserved as output when you create a version using \"Save & Run All\" \n# You can also write temporary files to /kaggle/temp/, but they won't be saved outside of the current session","metadata":{"_uuid":"8f2839f25d086af736a60e9eeb907d3b93b6e0e5","_cell_guid":"b1076dfc-b9ad-4769-8c92-a6c4dae69d19","trusted":true},"outputs":[],"execution_count":null},{"cell_type":"code","source":"!pip install -q efficientnet_pytorch\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-11-30T11:39:48.824920Z","iopub.execute_input":"2025-11-30T11:39:48.825216Z","iopub.status.idle":"2025-11-30T11:39:51.966531Z","shell.execute_reply.started":"2025-11-30T11:39:48.825193Z","shell.execute_reply":"2025-11-30T11:39:51.965763Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"import os\nimport numpy as np\nimport pandas as pd\nfrom tqdm import tqdm\nfrom sklearn.model_selection import StratifiedKFold\nfrom sklearn.metrics import roc_auc_score\n\nimport torch\nimport torch.nn as nn\nfrom torch.utils.data import Dataset, DataLoader\nimport torchvision.transforms as T\nimport torchvision.models as models\nfrom efficientnet_pytorch import EfficientNet\nfrom PIL import Image\n\n# -----------------------------\n\n# Configuration\n\n# -----------------------------\n\nDATA_DIR = '/kaggle/input/histopathologic-cancer-detection/'\nBATCH_SIZE = 64\nIMG_SIZE = 96\nNUM_FOLDS = 5\nDEVICE = 'cuda' if torch.cuda.is_available() else 'cpu'\nSEED = 42\n\ntorch.manual_seed(SEED)\nnp.random.seed(SEED)\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-11-30T11:40:12.943156Z","iopub.execute_input":"2025-11-30T11:40:12.943931Z","iopub.status.idle":"2025-11-30T11:40:16.873809Z","shell.execute_reply.started":"2025-11-30T11:40:12.943899Z","shell.execute_reply":"2025-11-30T11:40:16.872997Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"class HistoDataset(Dataset):\n    def __init__(self, df, transform=None):\n        self.df = df\n        self.transform = transform\n\n    def __len__(self):\n        return len(self.df)\n\n    def __getitem__(self, idx):\n        row = self.df.iloc[idx]\n        if 'label' in row:\n            img_path = os.path.join(DATA_DIR, 'train', row['id'] + '.tif')\n        else:\n            img_path = os.path.join(DATA_DIR, 'test', row['id'])\n        img = Image.open(img_path).convert('RGB')\n        label = torch.tensor(row['label'], dtype=torch.float32) if 'label' in row else torch.tensor(0.0)\n        if self.transform:\n            img = self.transform(img)\n        return img, label\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-11-30T11:40:20.076362Z","iopub.execute_input":"2025-11-30T11:40:20.077264Z","iopub.status.idle":"2025-11-30T11:40:20.083080Z","shell.execute_reply.started":"2025-11-30T11:40:20.077234Z","shell.execute_reply":"2025-11-30T11:40:20.082124Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# Strong Train-Time Augmentations\n\ntrain_transform = T.Compose([\nT.RandomHorizontalFlip(),\nT.RandomVerticalFlip(),\nT.RandomRotation(20),\nT.ColorJitter(brightness=0.3, contrast=0.3, saturation=0.3),\nT.RandomResizedCrop(IMG_SIZE, scale=(0.9,1.0), ratio=(0.9,1.1)),\nT.ToTensor(),\nT.Normalize(mean=[0.485,0.456,0.406], std=[0.229,0.224,0.225])\n])\n\n# Minimal TTA Transform\n\ntta_transform = T.Compose([\nT.ToTensor(),\nT.Normalize(mean=[0.485,0.456,0.406], std=[0.229,0.224,0.225])\n])\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-11-30T11:40:25.558855Z","iopub.execute_input":"2025-11-30T11:40:25.559604Z","iopub.status.idle":"2025-11-30T11:40:25.565032Z","shell.execute_reply.started":"2025-11-30T11:40:25.559577Z","shell.execute_reply":"2025-11-30T11:40:25.564214Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"def get_model(model_name='efficientnet_b3'):\n    if model_name == 'efficientnet_b3':\n        model = EfficientNet.from_pretrained('efficientnet-b3', num_classes=1)\n    elif model_name == 'densenet121':\n        model = models.densenet121(pretrained=True)\n        model.classifier = nn.Linear(model.classifier.in_features, 1)\n    elif model_name == 'resnet50':\n        model = models.resnet50(pretrained=True)\n        model.fc = nn.Linear(model.fc.in_features, 1)\n    return model.to(DEVICE)\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-11-30T11:40:27.352024Z","iopub.execute_input":"2025-11-30T11:40:27.352578Z","iopub.status.idle":"2025-11-30T11:40:27.357073Z","shell.execute_reply.started":"2025-11-30T11:40:27.352552Z","shell.execute_reply":"2025-11-30T11:40:27.356325Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"def train_fold(model, train_loader, val_loader, epochs=5, lr=1e-4):\n    criterion = nn.BCEWithLogitsLoss()\n    optimizer = torch.optim.Adam(model.parameters(), lr=lr)\n\n    for epoch in range(epochs):\n        model.train()\n        for imgs, labels in train_loader:\n            imgs, labels = imgs.to(DEVICE), labels.to(DEVICE).unsqueeze(1)\n            optimizer.zero_grad()\n            out = model(imgs)\n            loss = criterion(out, labels)\n            loss.backward()\n            optimizer.step()\n\n    # Validation AUC\n    model.eval()\n    all_preds, all_labels = [], []\n    with torch.no_grad():\n        for imgs, labels in val_loader:\n            imgs, labels = imgs.to(DEVICE), labels.to(DEVICE).unsqueeze(1)\n            preds = torch.sigmoid(model(imgs))\n            all_preds.append(preds.cpu().numpy())\n            all_labels.append(labels.cpu().numpy())\n    auc = roc_auc_score(np.vstack(all_labels), np.vstack(all_preds))\n    return model, auc\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-11-30T11:40:28.872373Z","iopub.execute_input":"2025-11-30T11:40:28.873287Z","iopub.status.idle":"2025-11-30T11:40:28.879528Z","shell.execute_reply.started":"2025-11-30T11:40:28.873254Z","shell.execute_reply":"2025-11-30T11:40:28.878916Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"df = pd.read_csv(os.path.join(DATA_DIR, 'train_labels.csv'))\nskf = StratifiedKFold(n_splits=NUM_FOLDS, shuffle=True, random_state=SEED)\n\nmodels_dict = {'efficientnet_b3': [], 'densenet121': [], 'resnet50': []}\n\nfor model_name in models_dict.keys():\n    fold = 0\n    for train_idx, val_idx in skf.split(df, df['label']):\n        fold += 1\n        print(f\"Training {model_name} Fold {fold}\")\n        \n        train_df, val_df = df.iloc[train_idx], df.iloc[val_idx]\n        train_ds = HistoDataset(train_df, transform=train_transform)\n        val_ds = HistoDataset(val_df, transform=tta_transform)\n        \n        train_loader = DataLoader(train_ds, batch_size=BATCH_SIZE, shuffle=True, num_workers=2)\n        val_loader = DataLoader(val_ds, batch_size=BATCH_SIZE, shuffle=False, num_workers=2)\n        \n        model = get_model(model_name)\n        model, auc = train_fold(model, train_loader, val_loader, epochs=5)\n        print(f\"Fold {fold} AUC: {auc:.4f}\")\n        \n        models_dict[model_name].append(model)\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-11-30T11:40:34.995056Z","iopub.execute_input":"2025-11-30T11:40:34.995635Z","iopub.status.idle":"2025-11-30T19:34:00.151609Z","shell.execute_reply.started":"2025-11-30T11:40:34.995612Z","shell.execute_reply":"2025-11-30T19:34:00.150566Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"def predict_tta(models_list, df_test, tta_times=5):\n    all_preds = []\n    test_ds = HistoDataset(df_test, transform=tta_transform)\n    test_loader = DataLoader(test_ds, batch_size=BATCH_SIZE, shuffle=False, num_workers=2)\n\n    for model in models_list:\n        model.eval()\n        preds = []\n\n        with torch.no_grad():\n            for imgs, _ in test_loader:\n                imgs = imgs.to(DEVICE)\n\n                tta_pred = torch.zeros(imgs.size(0), 1).to(DEVICE)\n                for _ in range(tta_times):\n                    tta_pred += torch.sigmoid(model(imgs))\n\n                tta_pred /= tta_times\n                preds.append(tta_pred.cpu().numpy())\n\n        all_preds.append(np.vstack(preds))\n\n    return np.mean(np.array(all_preds), axis=0)\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-11-30T19:43:04.414131Z","iopub.execute_input":"2025-11-30T19:43:04.414643Z","iopub.status.idle":"2025-11-30T19:43:04.420572Z","shell.execute_reply.started":"2025-11-30T19:43:04.414621Z","shell.execute_reply":"2025-11-30T19:43:04.419832Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"df_test = pd.DataFrame({'id': [f for f in os.listdir(os.path.join(DATA_DIR, 'test')) if f.endswith('.tif')]})\n\nfinal_preds = []\nweights = {'efficientnet_b3': 0.4, 'densenet121': 0.35, 'resnet50': 0.25}\n\nfor model_name, model_list in models_dict.items():\n    preds = predict_tta(model_list, df_test, tta_times=5)\n    final_preds.append(preds * weights[model_name])\n\nfinal_preds = np.sum(final_preds, axis=0)\n\ndf_submission = pd.DataFrame({\n    'id': [f.replace('.tif', '') for f in df_test['id']],\n    'label': final_preds.flatten()\n})\n\ndf_submission.to_csv('submission.csv', index=False)\nprint(\"Submission saved!\")\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-11-30T19:43:43.882499Z","iopub.execute_input":"2025-11-30T19:43:43.883173Z","iopub.status.idle":"2025-11-30T20:17:19.781376Z","shell.execute_reply.started":"2025-11-30T19:43:43.883152Z","shell.execute_reply":"2025-11-30T20:17:19.780480Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"","metadata":{"trusted":true},"outputs":[],"execution_count":null}]}