{"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":"nvidiaTeslaT4","dataSources":[{"sourceId":29653,"databundleVersionId":2420395,"sourceType":"competition"}],"dockerImageVersionId":31154,"isInternetEnabled":false,"language":"python","sourceType":"notebook","isGpuEnabled":true}},"nbformat_minor":4,"nbformat":4,"cells":[{"cell_type":"code","source":"import pandas as pd\nimport numpy as np\nimport os\nimport pydicom\nimport torch\nimport torch.nn as nn\nimport torch.optim as optim\nfrom torch.utils.data import Dataset, DataLoader\nfrom sklearn.model_selection import train_test_split\nfrom sklearn.metrics import roc_auc_score, accuracy_score, precision_score, recall_score, f1_score\nfrom skimage.transform import resize\nimport warnings\nwarnings.filterwarnings('ignore')\n\nclass SimpleMRIDataset(Dataset):\n    \"\"\"Simplified dataset for MRI data with basic preprocessing.\"\"\"\n\n    def __init__(self, df, data_dir, target_size=(32, 32, 32)):\n        self.df = df\n        self.data_dir = data_dir\n        self.target_size = target_size\n\n    def __len__(self):\n        return len(self.df)\n\n    def __getitem__(self, idx):\n        row = self.df.iloc[idx]\n        patient_id = str(row['BraTS21ID']).zfill(5)\n        patient_path = os.path.join(self.data_dir, patient_id)\n\n        # Load all 4 modalities\n        modalities = ['FLAIR', 'T1w', 'T1wCE', 'T2w']\n        volume_data = []\n\n        for modality in modalities:\n            modality_path = os.path.join(patient_path, modality)\n            dicom_files = sorted([f for f in os.listdir(modality_path) if f.endswith('.dcm')])\n\n            if len(dicom_files) == 0:\n                volume = np.zeros(self.target_size, dtype=np.float32)\n            else:\n                try:\n                    middle_idx = len(dicom_files) // 2\n                    dicom_file = os.path.join(modality_path, dicom_files[middle_idx])\n                    ds = pydicom.dcmread(dicom_file)\n                    slice_data = ds.pixel_array.astype(np.float32)\n                    slice_resized = resize(slice_data, self.target_size[:2], preserve_range=True)\n                    volume = np.repeat(slice_resized[:, :, np.newaxis], self.target_size[2], axis=2)\n                    volume = (volume - np.mean(volume)) / (np.std(volume) + 1e-8)\n                except:\n                    volume = np.zeros(self.target_size, dtype=np.float32)\n\n            volume_data.append(volume)\n\n        multi_modal_volume = np.stack(volume_data, axis=0)\n        return torch.FloatTensor(multi_modal_volume), torch.FloatTensor([row['MGMT_value']])\n\nclass Simple3DCNN(nn.Module):\n    \"\"\"Simplified 3D CNN for better performance.\"\"\"\n\n    def __init__(self, in_channels=4, num_classes=1):\n        super(Simple3DCNN, self).__init__()\n\n        self.features = nn.Sequential(\n            nn.Conv3d(in_channels, 32, kernel_size=3, padding=1),\n            nn.BatchNorm3d(32),\n            nn.ReLU(inplace=True),\n            nn.MaxPool3d(2),\n            nn.Conv3d(32, 64, kernel_size=3, padding=1),\n            nn.BatchNorm3d(64),\n            nn.ReLU(inplace=True),\n            nn.MaxPool3d(2),\n            nn.Conv3d(64, 128, kernel_size=3, padding=1),\n            nn.BatchNorm3d(128),\n            nn.ReLU(inplace=True),\n            nn.AdaptiveAvgPool3d(4)\n        )\n\n        self.classifier = nn.Sequential(\n            nn.Dropout(0.3),\n            nn.Linear(128 * 4 * 4 * 4, 256),\n            nn.ReLU(inplace=True),\n            nn.Dropout(0.2),\n            nn.Linear(256, 64),\n            nn.ReLU(inplace=True),\n            nn.Dropout(0.1),\n            nn.Linear(64, num_classes)\n        )\n\n    def forward(self, x):\n        features = self.features(x)\n        features = features.view(features.size(0), -1)\n        output = self.classifier(features)\n        return output\n\ndef build_and_train_model(train_df, val_df, train_data_dir):\n    \"\"\"Build and train the 3D CNN model.\"\"\"\n    device = torch.device('cuda' if torch.cuda.is_available() else 'cpu')\n\n    train_dataset = SimpleMRIDataset(train_df, train_data_dir)\n    val_dataset = SimpleMRIDataset(val_df, train_data_dir)\n\n    batch_size = 8\n    train_loader = DataLoader(train_dataset, batch_size=batch_size, shuffle=True, num_workers=0)\n    val_loader = DataLoader(val_dataset, batch_size=batch_size, shuffle=False, num_workers=0)\n\n    model = Simple3DCNN(in_channels=4, num_classes=1)\n    model = model.to(device)\n\n    criterion = nn.BCEWithLogitsLoss()\n    optimizer = optim.Adam(model.parameters(), lr=1e-3)\n\n    num_epochs = 10\n    best_val_auc = 0.0\n    best_model_state = None\n\n    for epoch in range(num_epochs):\n        # Training\n        model.train()\n        train_loss = 0.0\n        train_preds = []\n        train_labels = []\n\n        for images, labels in train_loader:\n            images = images.to(device)\n            labels = labels.to(device)\n\n            optimizer.zero_grad()\n            outputs = model(images)\n            loss = criterion(outputs, labels)\n            loss.backward()\n            optimizer.step()\n\n            train_loss += loss.item()\n\n            with torch.no_grad():\n                preds = torch.sigmoid(outputs).cpu().numpy()\n                train_preds.extend(preds.flatten())\n                train_labels.extend(labels.cpu().numpy().flatten())\n\n        # Validation\n        model.eval()\n        val_loss = 0.0\n        val_preds = []\n        val_labels = []\n\n        with torch.no_grad():\n            for images, labels in val_loader:\n                images = images.to(device)\n                labels = labels.to(device)\n\n                outputs = model(images)\n                loss = criterion(outputs, labels)\n                val_loss += loss.item()\n\n                preds = torch.sigmoid(outputs).cpu().numpy()\n                val_preds.extend(preds.flatten())\n                val_labels.extend(labels.cpu().numpy().flatten())\n\n        # Calculate metrics\n        val_preds = np.array(val_preds)\n        val_labels = np.array(val_labels)\n        val_auc = roc_auc_score(val_labels, val_preds)\n\n        if val_auc > best_val_auc:\n            best_val_auc = val_auc\n            best_model_state = model.state_dict().copy()\n\n    if best_model_state is not None:\n        model.load_state_dict(best_model_state)\n\n    return model, best_val_auc\n\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-10-23T14:01:42.421159Z","iopub.status.idle":"2025-10-23T14:01:42.421511Z","shell.execute_reply.started":"2025-10-23T14:01:42.421322Z","shell.execute_reply":"2025-10-23T14:01:42.421340Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"if __name__ == \"__main__\":\n    # Load data\n    train_labels_path = '/kaggle/input/rsna-miccai-brain-tumor-radiogenomic-classification/train_labels.csv'\n    train_data_dir = '/kaggle/input/rsna-miccai-brain-tumor-radiogenomic-classification/train'\n    test_data_dir = '/kaggle/input/rsna-miccai-brain-tumor-radiogenomic-classification/test'\n\n    train_labels = pd.read_csv(train_labels_path)\n\n    # Exclude problematic cases\n    exclude_ids = ['00109', '00123', '00709']\n    train_labels = train_labels[~train_labels['BraTS21ID'].astype(str).isin(exclude_ids)]\n\n    # Split data\n    train_df, val_df = train_test_split(\n        train_labels, test_size=0.2, random_state=42, stratify=train_labels['MGMT_value']\n    )\n\n    # Train model\n    model, best_val_auc = build_and_train_model(train_df, val_df, train_data_dir)\n\n    # Generate validation predictions\n    device = torch.device('cuda' if torch.cuda.is_available() else 'cpu')\n    model.eval()\n\n    val_dataset = SimpleMRIDataset(val_df, train_data_dir)\n    val_loader = DataLoader(val_dataset, batch_size=8, shuffle=False, num_workers=0)\n\n    val_predictions = []\n    patient_ids = []\n\n    with torch.no_grad():\n        for i, (images, labels) in enumerate(val_loader):\n            images = images.to(device)\n            outputs = model(images)\n            probs = torch.sigmoid(outputs).cpu().numpy().flatten()\n\n            start_idx = i * val_loader.batch_size\n            end_idx = min(start_idx + len(probs), len(val_df))\n            batch_patient_ids = val_df.iloc[start_idx:end_idx]['BraTS21ID'].values\n\n            for patient_id, prob in zip(batch_patient_ids, probs):\n                patient_ids.append(str(patient_id).zfill(5))\n                val_predictions.append(float(prob))\n\n    val_predictions_df = pd.DataFrame({\n        'BraTS21ID': patient_ids,\n        'MGMT_value': val_predictions\n    })\n    val_predictions_df.to_csv('validation_predictions.csv', index=False)\n\n    # Generate test predictions\n    test_patient_ids = sorted([f for f in os.listdir(test_data_dir) if os.path.isdir(os.path.join(test_data_dir, f))])\n\n    test_predictions = []\n    for patient_id in test_patient_ids:\n        patient_path = os.path.join(test_data_dir, patient_id)\n\n        try:\n            modalities = ['FLAIR', 'T1w', 'T1wCE', 'T2w']\n            volume_data = []\n\n            for modality in modalities:\n                modality_path = os.path.join(patient_path, modality)\n                dicom_files = sorted([f for f in os.listdir(modality_path) if f.endswith('.dcm')])\n\n                if len(dicom_files) == 0:\n                    volume = np.zeros((32, 32, 32), dtype=np.float32)\n                else:\n                    try:\n                        middle_idx = len(dicom_files) // 2\n                        dicom_file = os.path.join(modality_path, dicom_files[middle_idx])\n                        ds = pydicom.dcmread(dicom_file)\n                        slice_data = ds.pixel_array.astype(np.float32)\n                        slice_resized = resize(slice_data, (32, 32), preserve_range=True)\n                        volume = np.repeat(slice_resized[:, :, np.newaxis], 32, axis=2)\n                        volume = (volume - np.mean(volume)) / (np.std(volume) + 1e-8)\n                    except:\n                        volume = np.zeros((32, 32, 32), dtype=np.float32)\n\n                volume_data.append(volume)\n\n            multi_modal_volume = np.stack(volume_data, axis=0)\n            image_tensor = torch.FloatTensor(multi_modal_volume).unsqueeze(0).to(device)\n\n            with torch.no_grad():\n                output = model(image_tensor)\n                prob = torch.sigmoid(output).cpu().numpy()[0, 0]\n\n            test_predictions.append({'BraTS21ID': patient_id, 'MGMT_value': float(prob)})\n\n        except:\n            test_predictions.append({'BraTS21ID': patient_id, 'MGMT_value': 0.5})\n\n    test_predictions_df = pd.DataFrame(test_predictions)\n    test_predictions_df.to_csv('submission.csv', index=False)\n\n    print(f\"Best validation ROC-AUC: {best_val_auc:.4f}\")\n    print(f\"Validation predictions saved: {len(val_predictions_df)} patients\")\n    print(f\"Test predictions saved: {len(test_predictions_df)} patients\")","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-10-23T14:01:48.145461Z","iopub.execute_input":"2025-10-23T14:01:48.146098Z","iopub.status.idle":"2025-10-23T14:09:18.483168Z","shell.execute_reply.started":"2025-10-23T14:01:48.146068Z","shell.execute_reply":"2025-10-23T14:09:18.482404Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"","metadata":{"trusted":true},"outputs":[],"execution_count":null}]}