{"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":"gpu","dataSources":[{"sourceId":29653,"databundleVersionId":2420395,"sourceType":"competition"},{"sourceId":12336294,"sourceType":"datasetVersion","datasetId":7776564}],"dockerImageVersionId":31040,"isInternetEnabled":false,"language":"python","sourceType":"notebook","isGpuEnabled":true}},"nbformat_minor":4,"nbformat":4,"cells":[{"cell_type":"code","source":"import numpy as np \nimport pandas as pd \nimport matplotlib.pyplot as plt \nimport torch.nn as nn \nimport torch \nfrom  torch.utils.data import Dataset, DataLoader \nfrom torchvision.transforms import Resize\nimport pydicom\nimport glob\nimport os\nimport cv2\nfrom sklearn.metrics import accuracy_score, roc_auc_score\nimport torchvision.transforms as transforms","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-07-01T04:43:01.095565Z","iopub.execute_input":"2025-07-01T04:43:01.095839Z","iopub.status.idle":"2025-07-01T04:43:01.100712Z","shell.execute_reply.started":"2025-07-01T04:43:01.095820Z","shell.execute_reply":"2025-07-01T04:43:01.099782Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"BASE_PATH = '/kaggle/input/rsna-miccai-brain-tumor-radiogenomic-classification/train'\ntest_path = '/kaggle/input/rsna-miccai-brain-tumor-radiogenomic-classification/test'\n\nrequired_slices = 32","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-07-01T04:43:01.101767Z","iopub.execute_input":"2025-07-01T04:43:01.101974Z","iopub.status.idle":"2025-07-01T04:43:01.117749Z","shell.execute_reply.started":"2025-07-01T04:43:01.101951Z","shell.execute_reply":"2025-07-01T04:43:01.117032Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"label_df = pd.read_csv('/kaggle/input/rsna-miccai-brain-tumor-radiogenomic-classification/train_labels.csv')\nlabel_df['MGMT_value'].value_counts()","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-07-01T04:43:01.118902Z","iopub.execute_input":"2025-07-01T04:43:01.119114Z","iopub.status.idle":"2025-07-01T04:43:01.151241Z","shell.execute_reply.started":"2025-07-01T04:43:01.119099Z","shell.execute_reply":"2025-07-01T04:43:01.150586Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"patient_ids = [x for x in label_df['BraTS21ID'].tolist() if x not in ['00109','00123','00709']]\nlen(patient_ids)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-07-01T04:43:01.152362Z","iopub.execute_input":"2025-07-01T04:43:01.152909Z","iopub.status.idle":"2025-07-01T04:43:01.157702Z","shell.execute_reply.started":"2025-07-01T04:43:01.152892Z","shell.execute_reply":"2025-07-01T04:43:01.157040Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"label_df['BraTS21ID'] = label_df['BraTS21ID'].apply(lambda x:f\"{int(x):05d}\")\nlabel_df[label_df['MGMT_value']==0]","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-07-01T04:43:01.158332Z","iopub.execute_input":"2025-07-01T04:43:01.158624Z","iopub.status.idle":"2025-07-01T04:43:01.179109Z","shell.execute_reply.started":"2025-07-01T04:43:01.158609Z","shell.execute_reply":"2025-07-01T04:43:01.178382Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"label_dict = label_df.set_index('BraTS21ID')['MGMT_value'].to_dict()","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-07-01T04:43:01.180591Z","iopub.execute_input":"2025-07-01T04:43:01.181059Z","iopub.status.idle":"2025-07-01T04:43:01.194054Z","shell.execute_reply.started":"2025-07-01T04:43:01.181044Z","shell.execute_reply":"2025-07-01T04:43:01.193478Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"sub_df = pd.read_csv('/kaggle/input/rsna-miccai-brain-tumor-radiogenomic-classification/sample_submission.csv')\ntest_ids = sub_df['BraTS21ID'].tolist()\ntest_ids = [str(x).zfill(5) for x in test_ids]","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-07-01T04:43:01.194712Z","iopub.execute_input":"2025-07-01T04:43:01.194949Z","iopub.status.idle":"2025-07-01T04:43:01.213676Z","shell.execute_reply.started":"2025-07-01T04:43:01.194918Z","shell.execute_reply":"2025-07-01T04:43:01.212961Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"from torchvision import transforms\nimport torch\n\ndef get_training_transform():\n    return transforms.Compose([\n        transforms.RandomHorizontalFlip(p=0.5),\n        transforms.RandomRotation(degrees=10),\n        transforms.ColorJitter(brightness=0.2, contrast=0.2),\n        transforms.GaussianBlur(kernel_size=3),\n    ])","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-07-01T04:43:01.214296Z","iopub.execute_input":"2025-07-01T04:43:01.214469Z","iopub.status.idle":"2025-07-01T04:43:01.219140Z","shell.execute_reply.started":"2025-07-01T04:43:01.214436Z","shell.execute_reply":"2025-07-01T04:43:01.218569Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"class BrDataset(Dataset):\n    def __init__(self,base_path,patient_ids,label_dict,resize = (128,128),transform = None):\n        self.base_path = base_path \n        self.patient_ids = patient_ids \n        self.label_dict = label_dict \n        self.modalities = ['FLAIR','T1w']\n        self.resize = Resize(resize) \n        self.transform = transform \n\n    def load_slices(self, case_id, modality):\n        paths = sorted(glob.glob(os.path.join(self.base_path, case_id, modality, '*.dcm')),\n                       key=lambda x: int(pydicom.dcmread(x).InstanceNumber))\n        slices = []\n        for path in paths:\n            dcm = pydicom.dcmread(path)\n            image = dcm.pixel_array.astype('float32')\n            slices.append(image)\n    \n        num_slices = len(slices)\n    \n        if num_slices < required_slices:\n            pad_needed = required_slices - num_slices\n            start = pad_needed // 2\n            end = pad_needed - start\n            h, w = slices[0].shape\n            zero_slice = torch.zeros(h, w)\n            slices = [zero_slice] * start + slices + [zero_slice] * end\n        else:\n            mid = num_slices // 2\n            start = mid - required_slices // 2\n            slices = slices[start:start + required_slices]\n    \n        volume = torch.stack([torch.tensor(s, dtype=torch.float32) for s in slices])  # [D, H, W]\n    \n        # ✅ Resize to uniform shape\n        volume = self.resize(volume.unsqueeze(0)).squeeze(0)  # [D, H, W] -> [1, D, H, W] -> back\n    \n        return volume\n        # num_cols = 4 \n        # num_rows = 8\n        # fig, axis = plt.subplots(nrows=num_rows, ncols=num_cols, figsize=(num_cols * 3, num_rows * 3))\n\n        # for i in range(num_rows * num_cols):\n        #     row = i // num_cols\n        #     col = i % num_cols\n        #     ax = axis[row][col]\n        #     ax.imshow(slices[i], cmap='gray')\n        #     ax.axis('off')  # remove axis ticks\n        \n        # plt.subplots_adjust(wspace=0.05, hspace=0.05)\n        # plt.show()\n\n    def __len__(self):\n        return len(self.patient_ids)\n\n    def __getitem__(self,idx):\n        case_id = str(self.patient_ids[idx]).zfill(5)\n        vol = []\n        for modality in self.modalities:\n            # print(f\"{'='*10} {modality} {'='*10}\\n\\n\")\n            volume = self.load_slices(case_id,modality)\n            vol.append(volume)\n        vol = torch.stack(vol)\n\n        if self.transform:\n            transformed_vol = []\n            for modality_vol in vol:  # shape: [D, H, W]\n                transformed_slices = []\n                for slice_img in modality_vol:\n                    img = transforms.ToPILImage()(slice_img.unsqueeze(0))\n                    img = self.transform(img)\n                    img_tensor = transforms.ToTensor()(img).squeeze(0)\n                    transformed_slices.append(img_tensor)\n                transformed_vol.append(torch.stack(transformed_slices))\n            vol = torch.stack(transformed_vol)  # [2, D, H, W]\n\n        if self.label_dict is not None:\n            label = torch.tensor(self.label_dict[case_id], dtype=torch.long)\n            return vol, label\n        else:\n            return vol, case_id","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-07-01T04:43:01.219883Z","iopub.execute_input":"2025-07-01T04:43:01.220343Z","iopub.status.idle":"2025-07-01T04:43:01.237162Z","shell.execute_reply.started":"2025-07-01T04:43:01.220322Z","shell.execute_reply":"2025-07-01T04:43:01.236630Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"train_transform = get_training_transform()\n\ntrain_dataset = BrDataset(\n    base_path=BASE_PATH,\n    patient_ids=patient_ids,\n    label_dict=label_dict,\n    resize=(128,128),\n    transform=train_transform\n)\nx,y = train_dataset[2]","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-07-01T04:43:01.238031Z","iopub.execute_input":"2025-07-01T04:43:01.238653Z","iopub.status.idle":"2025-07-01T04:43:01.900695Z","shell.execute_reply.started":"2025-07-01T04:43:01.238630Z","shell.execute_reply":"2025-07-01T04:43:01.899914Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"x.shape","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-07-01T04:43:01.901556Z","iopub.execute_input":"2025-07-01T04:43:01.901805Z","iopub.status.idle":"2025-07-01T04:43:01.907420Z","shell.execute_reply.started":"2025-07-01T04:43:01.901779Z","shell.execute_reply":"2025-07-01T04:43:01.906797Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"import matplotlib.pyplot as plt\n\ndef plot_modalities(x, title_prefix=\"Modality\"):\n    num_modalities, num_slices, height, width = x.shape\n    num_cols = 8\n    num_rows = num_slices // num_cols\n\n    for m in range(num_modalities):\n        fig, axes = plt.subplots(num_rows, num_cols, figsize=(num_cols * 2, num_rows * 2))\n        fig.suptitle(f\"{title_prefix} {m+1}\", fontsize=16)\n\n        for i in range(num_slices):\n            row = i // num_cols\n            col = i % num_cols\n            ax = axes[row][col]\n            ax.imshow(x[m, i].cpu(), cmap=\"gray\")\n            ax.axis(\"off\")\n\n        plt.tight_layout()\n        plt.show()\n\n# Usage\nplot_modalities(x)\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-07-01T04:43:01.909339Z","iopub.execute_input":"2025-07-01T04:43:01.909568Z","iopub.status.idle":"2025-07-01T04:43:03.918711Z","shell.execute_reply.started":"2025-07-01T04:43:01.909552Z","shell.execute_reply":"2025-07-01T04:43:03.917940Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# import timm\n# model = timm.create_model('efficientnet_b0', pretrained=True)\n# torch.save(model.state_dict(), 'efficientnet_b0_offline.pth')\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-07-01T04:43:03.919476Z","iopub.execute_input":"2025-07-01T04:43:03.919721Z","iopub.status.idle":"2025-07-01T04:43:03.923159Z","shell.execute_reply.started":"2025-07-01T04:43:03.919702Z","shell.execute_reply":"2025-07-01T04:43:03.922478Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"import torch\nimport torch.nn as nn\nimport torch.nn.functional as F\nimport timm  # You need to have timm installed\n\nclass brclassifier(nn.Module):\n    def __init__(self, hidden_size=256, num_classes=2):\n        super().__init__()\n        # Load efficientnet_b0 from timm (pretrained=True will NOT try to download if weights are already cached)\n        # self.backbone = timm.create_model('efficientnet_b0', pretrained=True, features_only=True)\n        self.backbone = timm.create_model(\n            'efficientnet_b0',\n            pretrained=False,  # Disable download\n            features_only=True\n        )\n        # Load saved weights\n        state_dict = torch.load('/kaggle/input/effnet0-weights/efficientnet_b0_offline.pth', map_location='cpu')\n        self.backbone.load_state_dict(state_dict, strict=False)\n        \n        self.pool = nn.AdaptiveAvgPool2d(1)\n        self.backbone_out_dim = self.backbone.feature_info[-1]['num_chs']  # usually 1280\n\n        self.lstm = nn.LSTM(\n            input_size=self.backbone_out_dim,\n            hidden_size=hidden_size,\n            num_layers=1,\n            batch_first=True,\n            bidirectional=True\n        )\n        self.dropout = nn.Dropout(p=0.3)\n        self.classifier = nn.Linear(hidden_size * 2, num_classes)\n\n    def forward(self, x):\n        B, C, D, H, W = x.shape\n        features = []\n\n        for d in range(D):\n            flair_slice = x[:, 0, d]\n            t1w_slice = x[:, 1, d]\n            avg_slice = (flair_slice + t1w_slice) / 2.0\n            img = torch.stack([flair_slice, t1w_slice, avg_slice], dim=1)  # [B, 3, H, W]\n            img = F.interpolate(img, size=(224, 224), mode='bilinear')    # Resize\n\n            feats = self.backbone(img)[-1]  # Get last feature map\n            pooled = self.pool(feats).view(B, -1)  # [B, 1280]\n            features.append(pooled)\n\n        features = torch.stack(features, dim=1)  # [B, D, 1280]\n        lstm_out, _ = self.lstm(features)\n        final_feat = lstm_out[:, -1]  # [B, 2*hidden]\n\n        return self.classifier(self.dropout(final_feat))\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-07-01T04:43:03.923979Z","iopub.execute_input":"2025-07-01T04:43:03.924175Z","iopub.status.idle":"2025-07-01T04:43:03.941560Z","shell.execute_reply.started":"2025-07-01T04:43:03.924160Z","shell.execute_reply":"2025-07-01T04:43:03.940861Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"def train_one_fold(model, train_loader, val_loader, optimizer, criterion, device, fold=0, num_epochs=5, patience=2):\n    best_auc = 0\n    best_model_wts = None\n    epochs_no_improve = 0\n\n    for epoch in range(num_epochs):\n        print(f\"\\nEpoch {epoch + 1}/{num_epochs}\")\n\n        model.train()\n        train_loss = 0\n        for inputs, labels in tqdm(train_loader):\n            inputs = inputs.to(device)\n            labels = labels.to(device)\n\n            optimizer.zero_grad()\n            outputs = model(inputs)\n            loss = criterion(outputs, labels)\n            loss.backward()\n            optimizer.step()\n            train_loss += loss.item()\n\n        print(f\"Train Loss: {train_loss / len(train_loader):.4f}\")\n\n        model.eval()\n        val_preds, val_labels = [], []\n        with torch.no_grad():\n            for inputs, labels in val_loader:\n                inputs = inputs.to(device)\n                labels = labels.to(device)\n                outputs = model(inputs)\n                probs = F.softmax(outputs, dim=1)[:, 1]\n                val_preds.extend(probs.cpu().numpy())\n                val_labels.extend(labels.cpu().numpy())\n\n        val_auc = roc_auc_score(val_labels, val_preds)\n        val_cls = (np.array(val_preds) > 0.5).astype(int)\n        val_acc = accuracy_score(val_labels, val_cls)\n\n        print(f\"Val Accuracy: {val_acc:.4f} | Val AUC: {val_auc:.4f}\")\n        scheduler.step(val_auc)\n        \n        if val_auc > best_auc:\n            print(\"Saving best model...\")\n            best_auc = val_auc\n            best_model_wts = model.state_dict()\n            epochs_no_improve = 0\n            torch.save(best_model_wts, f\"best_model_fold{fold}.pt\")\n        else:\n            epochs_no_improve += 1\n            if epochs_no_improve >= patience:\n                print(\"Early stopping!\")\n                break\n\n    return best_auc","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-07-01T04:43:03.942146Z","iopub.execute_input":"2025-07-01T04:43:03.942387Z","iopub.status.idle":"2025-07-01T04:43:03.959073Z","shell.execute_reply.started":"2025-07-01T04:43:03.942365Z","shell.execute_reply":"2025-07-01T04:43:03.958503Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"import warnings \nwarnings.filterwarnings('ignore')\nfrom sklearn.model_selection import StratifiedKFold\nfrom tqdm import tqdm\nfrom torch.optim.lr_scheduler import ReduceLROnPlateau\nskf = StratifiedKFold(n_splits=3, shuffle=True, random_state=42)\nall_test_preds = []\n\nfor fold, (train_idx, val_idx) in enumerate(skf.split(label_df['BraTS21ID'], label_df['MGMT_value'])):\n    train_ids = [patient_ids[i] for i in train_idx]\n    val_ids = [patient_ids[i] for i in val_idx]\n\n    train_dataset = BrDataset(BASE_PATH, train_ids, label_dict, resize=(128, 128), transform=train_transform)\n    val_dataset = BrDataset(BASE_PATH, val_ids, label_dict, resize=(128, 128), transform=None)\n    test_dataset = BrDataset(test_path, test_ids, label_dict=None, resize=(128, 128), transform=None)\n    \n    train_loader = DataLoader(train_dataset, batch_size=4, shuffle=True, num_workers=2)\n    val_loader = DataLoader(val_dataset, batch_size=4, shuffle=False, num_workers=2)\n    test_loader = DataLoader(test_dataset, batch_size=4, shuffle=False, num_workers=2)\n    \n    device = torch.device(\"cuda\" if torch.cuda.is_available() else \"cpu\")\n    model = brclassifier().to(device)\n    optimizer = torch.optim.Adam(model.parameters(), lr=1e-4)\n    criterion = nn.CrossEntropyLoss()\n    scheduler = ReduceLROnPlateau(optimizer, mode='max', factor=0.5, patience=1, verbose=True)\n\n    best_auc = train_one_fold(model, train_loader, val_loader, optimizer, criterion, device)\n    print(f\"\\nFold {fold+1} AUC: {best_auc:.4f}\")\n\n    model.eval()\n    fold_preds = []\n    with torch.no_grad():\n        for inputs,_ in test_loader:\n            inputs = inputs.to(device)\n            outputs = model(inputs)\n            probs = torch.softmax(outputs, dim=1)[:, 1].cpu().numpy()\n            fold_preds.extend(probs)\n\n    all_test_preds.append(fold_preds)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-07-01T04:43:03.959797Z","iopub.execute_input":"2025-07-01T04:43:03.960004Z","iopub.status.idle":"2025-07-01T04:43:22.410024Z","shell.execute_reply.started":"2025-07-01T04:43:03.959989Z","shell.execute_reply":"2025-07-01T04:43:22.408829Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"final_results = np.mean(all_test_preds,axis=0)\nsub_df['MGMT_value'] = final_results\n\nsub_df.to_csv('/kaggle/working/submission.csv',index=False)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-07-01T04:43:22.410962Z","iopub.status.idle":"2025-07-01T04:43:22.411258Z","shell.execute_reply.started":"2025-07-01T04:43:22.411119Z","shell.execute_reply":"2025-07-01T04:43:22.411136Z"}},"outputs":[],"execution_count":null}]}