{"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":"none","dataSources":[{"sourceId":29653,"databundleVersionId":2420395,"sourceType":"competition"}],"dockerImageVersionId":31040,"isInternetEnabled":true,"language":"python","sourceType":"notebook","isGpuEnabled":false}},"nbformat_minor":4,"nbformat":4,"cells":[{"cell_type":"code","source":"import os\nimport numpy as np\nimport pandas as pd\nimport pydicom\nimport tensorflow as tf\nfrom tensorflow.keras import layers, models, applications\nfrom sklearn.model_selection import train_test_split\nimport cv2\nimport matplotlib.pyplot as plt\nfrom sklearn.metrics import classification_report, confusion_matrix, roc_curve, auc\nimport seaborn as sns","metadata":{"_uuid":"8f2839f25d086af736a60e9eeb907d3b93b6e0e5","_cell_guid":"b1076dfc-b9ad-4769-8c92-a6c4dae69d19","trusted":true,"execution":{"iopub.status.busy":"2025-05-30T02:58:39.577534Z","iopub.execute_input":"2025-05-30T02:58:39.579148Z","iopub.status.idle":"2025-05-30T02:58:40.456669Z","shell.execute_reply.started":"2025-05-30T02:58:39.579117Z","shell.execute_reply":"2025-05-30T02:58:40.455574Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# Path dataset\npath = '/kaggle/input/rsna-miccai-brain-tumor-radiogenomic-classification/'\ntrain_labels = pd.read_csv(path + 'train_labels.csv')\n\n# Konfigurasi\nIMG_SIZE = 128\nBATCH_SIZE = 32\nEPOCHS = 15\nMODALITY = 'FLAIR'\nNUM_SLICES = 16\nTEST_SIZE = 0.15\nVAL_SIZE = 0.15   ","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-05-30T02:59:13.114120Z","iopub.execute_input":"2025-05-30T02:59:13.115571Z","iopub.status.idle":"2025-05-30T02:59:13.125789Z","shell.execute_reply.started":"2025-05-30T02:59:13.115535Z","shell.execute_reply":"2025-05-30T02:59:13.124461Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# Fungsi untuk membaca dan memproses gambar DICOM\ndef load_dicom_image(filepath, img_size=IMG_SIZE):\n    dicom = pydicom.dcmread(filepath)\n    img = dicom.pixel_array.astype(float)\n    img = (img - img.min()) / (img.max() - img.min()) * 255\n    img = cv2.resize(img.astype(np.uint8), (img_size, img_size))\n    return np.stack([img]*3, axis=-1)  # Convert to 3-channel\n\n# Fungsi untuk memuat data pasien\ndef load_patient_data(patient_id, num_slices=NUM_SLICES):\n    patient_path = os.path.join(path, 'train', str(patient_id).zfill(5), MODALITY)\n    if not os.path.exists(patient_path): \n        return None\n    \n    dicom_files = sorted([f for f in os.listdir(patient_path) if f.endswith('.dcm')])\n    if not dicom_files: \n        return None\n    \n    step = max(1, len(dicom_files) // num_slices)\n    selected_files = dicom_files[::step][:num_slices]\n    \n    slices = []\n    for filename in selected_files:\n        img = load_dicom_image(os.path.join(patient_path, filename))\n        slices.append(img)\n    \n    # Padding jika slice kurang\n    while len(slices) < num_slices:\n        slices.append(np.zeros((IMG_SIZE, IMG_SIZE, 3), dtype=np.uint8))\n    \n    return np.array(slices)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-05-30T02:59:52.412050Z","iopub.execute_input":"2025-05-30T02:59:52.412505Z","iopub.status.idle":"2025-05-30T02:59:52.423894Z","shell.execute_reply.started":"2025-05-30T02:59:52.412475Z","shell.execute_reply":"2025-05-30T02:59:52.422760Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# Membuat dataset\nX, y = [], []\nprint(\"Memuat data training...\")\nfor idx, row in train_labels.iterrows():\n    patient_data = load_patient_data(row['BraTS21ID'])\n    if patient_data is not None:\n        X.append(patient_data)\n        y.append(row['MGMT_value'])\n\nX = np.array(X, dtype=np.float32) / 255.0  # Normalisasi\ny = np.array(y, dtype=np.float32)\nprint(f\"Shape data: {X.shape}, Distribusi kelas: MGMT+={sum(y==1)}, MGMT-={sum(y==0)}\")","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-05-30T03:00:12.962804Z","iopub.execute_input":"2025-05-30T03:00:12.963667Z","iopub.status.idle":"2025-05-30T03:00:54.470123Z","shell.execute_reply.started":"2025-05-30T03:00:12.963636Z","shell.execute_reply":"2025-05-30T03:00:54.469288Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# Split data menjadi train, validation, dan test\n# train (85%) dan test (15%)\nX_train_val, X_test, y_train_val, y_test = train_test_split(X, y, test_size=TEST_SIZE, stratify=y, random_state=42)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-05-30T03:01:29.797549Z","iopub.execute_input":"2025-05-30T03:01:29.797957Z","iopub.status.idle":"2025-05-30T03:01:30.953336Z","shell.execute_reply.started":"2025-05-30T03:01:29.797932Z","shell.execute_reply":"2025-05-30T03:01:30.952254Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# Bagi train_val menjadi train dan validation\nval_ratio = VAL_SIZE / (1 - TEST_SIZE)\nX_train, X_val, y_train, y_val = train_test_split(\n    X_train_val, y_train_val, test_size=val_ratio, stratify=y_train_val, random_state=42\n)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-05-30T03:02:02.077287Z","iopub.execute_input":"2025-05-30T03:02:02.078304Z","iopub.status.idle":"2025-05-30T03:02:03.123907Z","shell.execute_reply.started":"2025-05-30T03:02:02.078246Z","shell.execute_reply":"2025-05-30T03:02:03.123162Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"print(f\"\\nSplit Dataset:\")\nprint(f\"Train:      {X_train.shape[0]} sampel ({(X_train.shape[0]/len(X))*100:.1f}%)\")\nprint(f\"Validation: {X_val.shape[0]} sampel ({(X_val.shape[0]/len(X))*100:.1f}%)\")\nprint(f\"Test:       {X_test.shape[0]} sampel ({(X_test.shape[0]/len(X))*100:.1f}%)\")","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-05-30T03:02:13.537338Z","iopub.execute_input":"2025-05-30T03:02:13.538467Z","iopub.status.idle":"2025-05-30T03:02:13.545333Z","shell.execute_reply.started":"2025-05-30T03:02:13.538433Z","shell.execute_reply":"2025-05-30T03:02:13.544370Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# 1. MODEL 3D CNN SEDERHANA\ndef build_3d_cnn(input_shape=(NUM_SLICES, IMG_SIZE, IMG_SIZE, 3)):\n    model = models.Sequential([\n        layers.Conv3D(32, (3, 3, 3), activation='relu', padding='same', input_shape=input_shape),\n        layers.BatchNormalization(),\n        layers.MaxPooling3D((2, 2, 2)),\n        layers.Dropout(0.3),\n        \n        layers.Conv3D(64, (3, 3, 3), activation='relu', padding='same'),\n        layers.BatchNormalization(),\n        layers.MaxPooling3D((2, 2, 2)),\n        layers.Dropout(0.4),\n        \n        layers.Conv3D(128, (3, 3, 3), activation='relu', padding='same'),\n        layers.BatchNormalization(),\n        layers.MaxPooling3D((2, 2, 2)),\n        layers.Dropout(0.5),\n        \n        layers.GlobalAveragePooling3D(),\n        layers.Dense(256, activation='relu'),\n        layers.Dropout(0.5),\n        layers.Dense(1, activation='sigmoid')\n    ])\n    \n    model.compile(\n        optimizer=tf.keras.optimizers.Adam(learning_rate=1e-4),\n        loss='binary_crossentropy',\n        metrics=['accuracy', tf.keras.metrics.AUC(name='auc')]\n    )\n    return model","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-05-30T03:02:51.582819Z","iopub.execute_input":"2025-05-30T03:02:51.583156Z","iopub.status.idle":"2025-05-30T03:02:51.591864Z","shell.execute_reply.started":"2025-05-30T03:02:51.583134Z","shell.execute_reply":"2025-05-30T03:02:51.590234Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# 2. MODEL 3D EFFICIENTNET B0\ndef build_3d_efficientnet(input_shape=(NUM_SLICES, IMG_SIZE, IMG_SIZE, 3)):\n    base_model = applications.EfficientNetB0(\n        include_top=False,\n        weights='imagenet',\n        input_shape=(IMG_SIZE, IMG_SIZE, 3)\n    )\n    \n    # Freeze initial layers\n    for layer in base_model.layers[:100]:\n        layer.trainable = False\n    \n    inputs = layers.Input(shape=input_shape)\n    slice_outputs = []\n    \n    for i in range(NUM_SLICES):\n        slice = layers.Lambda(lambda x: x[:, i, :, :, :])(inputs)\n        x = base_model(slice)\n        x = layers.GlobalAveragePooling2D()(x)\n        slice_outputs.append(x)\n    \n    x = layers.Concatenate(axis=1)(slice_outputs)\n    x = layers.Reshape((NUM_SLICES, -1))(x)\n    x = layers.Bidirectional(layers.LSTM(64, return_sequences=True))(x)\n    x = layers.Bidirectional(layers.LSTM(32))(x)\n    x = layers.Dense(128, activation='relu')(x)\n    x = layers.Dropout(0.5)(x)\n    outputs = layers.Dense(1, activation='sigmoid')(x)\n    \n    model = models.Model(inputs, outputs)\n    model.compile(\n        optimizer=tf.keras.optimizers.Adam(learning_rate=1e-4),\n        loss='binary_crossentropy',\n        metrics=['accuracy', tf.keras.metrics.AUC(name='auc')]\n    )\n    return model","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-05-30T03:03:21.377587Z","iopub.execute_input":"2025-05-30T03:03:21.377944Z","iopub.status.idle":"2025-05-30T03:03:21.387898Z","shell.execute_reply.started":"2025-05-30T03:03:21.377924Z","shell.execute_reply":"2025-05-30T03:03:21.386687Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# 3. MODEL 3D RESNET50\ndef build_3d_resnet(input_shape=(NUM_SLICES, IMG_SIZE, IMG_SIZE, 3)):\n    def residual_block(x, filters, stride=1):\n        shortcut = x\n        \n        x = layers.Conv3D(filters, (3, 3, 3), strides=stride, padding='same')(x)\n        x = layers.BatchNormalization()(x)\n        x = layers.ReLU()(x)\n        \n        x = layers.Conv3D(filters, (3, 3, 3), padding='same')(x)\n        x = layers.BatchNormalization()(x)\n        \n        if stride != 1 or shortcut.shape[-1] != filters:\n            shortcut = layers.Conv3D(filters, (1, 1, 1), strides=stride)(shortcut)\n            shortcut = layers.BatchNormalization()(shortcut)\n        \n        x = layers.Add()([x, shortcut])\n        x = layers.ReLU()(x)\n        return x\n    \n    inputs = layers.Input(shape=input_shape)\n    x = layers.Conv3D(64, (7, 7, 7), strides=(2, 2, 2), padding='same')(inputs)\n    x = layers.BatchNormalization()(x)\n    x = layers.ReLU()(x)\n    x = layers.MaxPooling3D((3, 3, 3), strides=(2, 2, 2), padding='same')(x)\n    \n    x = residual_block(x, 64)\n    x = residual_block(x, 64)\n    x = residual_block(x, 128, stride=2)\n    x = residual_block(x, 128)\n    x = residual_block(x, 256, stride=2)\n    x = residual_block(x, 256)\n    \n    x = layers.GlobalAveragePooling3D()(x)\n    x = layers.Dense(256, activation='relu')(x)\n    x = layers.Dropout(0.5)(x)\n    outputs = layers.Dense(1, activation='sigmoid')(x)\n    \n    model = models.Model(inputs, outputs)\n    model.compile(\n        optimizer=tf.keras.optimizers.Adam(learning_rate=1e-4),\n        loss='binary_crossentropy',\n        metrics=['accuracy', tf.keras.metrics.AUC(name='auc')]\n    )\n    return model\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-05-30T03:06:08.137935Z","iopub.execute_input":"2025-05-30T03:06:08.138312Z","iopub.status.idle":"2025-05-30T03:06:08.149095Z","shell.execute_reply.started":"2025-05-30T03:06:08.138290Z","shell.execute_reply":"2025-05-30T03:06:08.148163Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# FUNGSI EVALUASI MODEL\ndef evaluate_model(model, X_test, y_test, name):\n    print(f\"\\n{'='*50}\")\n    print(f\"Evaluasi Model {name} pada Data Test\")\n    print(f\"{'='*50}\")\n    \n    # Prediksi\n    y_pred = model.predict(X_test)\n    y_pred_bin = (y_pred > 0.5).astype(int)\n    \n    # Classification Report\n    print(\"\\nClassification Report (Test Set):\")\n    print(classification_report(y_test, y_pred_bin))\n    \n    # Confusion Matrix\n    cm = confusion_matrix(y_test, y_pred_bin)\n    plt.figure(figsize=(8, 6))\n    sns.heatmap(cm, annot=True, fmt='d', cmap='Blues', \n                xticklabels=['Unmethylated', 'Methylated'], \n                yticklabels=['Unmethylated', 'Methylated'])\n    plt.xlabel('Predicted')\n    plt.ylabel('True')\n    plt.title(f'{name} - Confusion Matrix (Test Set)')\n    plt.savefig(f'{name}_cm_test.png')\n    plt.show()\n    \n    # ROC Curve\n    fpr, tpr, _ = roc_curve(y_test, y_pred)\n    roc_auc = auc(fpr, tpr)\n    \n    plt.figure()\n    plt.plot(fpr, tpr, color='darkorange', lw=2, label=f'ROC curve (area = {roc_auc:.2f})')\n    plt.plot([0, 1], [0, 1], color='navy', lw=2, linestyle='--')\n    plt.xlim([0.0, 1.0])\n    plt.ylim([0.0, 1.05])\n    plt.xlabel('False Positive Rate')\n    plt.ylabel('True Positive Rate')\n    plt.title(f'{name} - ROC Curve (Test Set)')\n    plt.legend(loc=\"lower right\")\n    plt.savefig(f'{name}_roc_test.png')\n    plt.show()\n    \n    return roc_auc","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-05-30T03:06:12.626547Z","iopub.execute_input":"2025-05-30T03:06:12.626884Z","iopub.status.idle":"2025-05-30T03:06:12.636433Z","shell.execute_reply.started":"2025-05-30T03:06:12.626864Z","shell.execute_reply":"2025-05-30T03:06:12.635236Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# TRAINING DAN VALIDASI MODEL\ndef train_and_evaluate(model, name, X_train, y_train, X_val, y_val, X_test, y_test):\n    print(f\"\\n{'='*50}\")\n    print(f\"Training {name} Model\")\n    print(f\"{'='*50}\")\n    model.summary()\n    \n    # Callback\n    callbacks = [\n        tf.keras.callbacks.EarlyStopping(patience=5, restore_best_weights=True, monitor='val_auc', mode='max'),\n        tf.keras.callbacks.ReduceLROnPlateau(factor=0.1, patience=3, monitor='val_loss'),\n        tf.keras.callbacks.ModelCheckpoint(f'best_{name}.h5', save_best_only=True, monitor='val_auc', mode='max')\n    ]\n    \n    # Class weighting\n    class_weight = {0: 1., 1: len(y_train[y_train==0])/len(y_train[y_train==1])}\n    \n    # Training\n    history = model.fit(\n        X_train, y_train,\n        validation_data=(X_val, y_val),\n        epochs=EPOCHS,\n        batch_size=BATCH_SIZE,\n        callbacks=callbacks,\n        class_weight=class_weight\n    )\n    \n    # Plot training history\n    plt.figure(figsize=(12, 8))\n    \n    plt.subplot(2, 2, 1)\n    plt.plot(history.history['loss'], label='Train Loss')\n    plt.plot(history.history['val_loss'], label='Validation Loss')\n    plt.title(f'{name} - Loss Curve')\n    plt.legend()\n    \n    plt.subplot(2, 2, 2)\n    plt.plot(history.history['auc'], label='Train AUC')\n    plt.plot(history.history['val_auc'], label='Validation AUC')\n    plt.title(f'{name} - AUC Curve')\n    plt.legend()\n    \n    plt.subplot(2, 2, 3)\n    plt.plot(history.history['accuracy'], label='Train Accuracy')\n    plt.plot(history.history['val_accuracy'], label='Validation Accuracy')\n    plt.title(f'{name} - Accuracy Curve')\n    plt.legend()\n    \n    plt.tight_layout()\n    plt.savefig(f'{name}_training_curves.png')\n    plt.show()\n    \n    # Evaluasi pada validation set\n    val_loss, val_acc, val_auc = model.evaluate(X_val, y_val, verbose=0)\n    print(f\"\\nValidation Metrics ({name}):\")\n    print(f\"Loss:     {val_loss:.4f}\")\n    print(f\"Accuracy: {val_acc:.4f}\")\n    print(f\"AUC:      {val_auc:.4f}\")\n    \n    # Evaluasi pada test set\n    test_auc = evaluate_model(model, X_test, y_test, name)\n    \n    return model, history, val_auc, test_auc","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-05-30T03:06:16.744463Z","iopub.execute_input":"2025-05-30T03:06:16.744788Z","iopub.status.idle":"2025-05-30T03:06:16.756533Z","shell.execute_reply.started":"2025-05-30T03:06:16.744766Z","shell.execute_reply":"2025-05-30T03:06:16.755267Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# =============================\n# TRAIN DAN EVALUASI SEMUA MODEL\n# =============================\nresults = []\n\n# Bangun dan latih model\nmodels_dict = {\n    \"3D_CNN\": build_3d_cnn(),\n    \"3D_EfficientNet\": build_3d_efficientnet(),\n    \"3D_ResNet\": build_3d_resnet()\n}\n\nfor name, model in models_dict.items():\n    trained_model, history, val_auc, test_auc = train_and_evaluate(\n        model, name, X_train, y_train, X_val, y_val, X_test, y_test\n    )\n    results.append({\n        'Model': name,\n        'Validation AUC': val_auc,\n        'Test AUC': test_auc\n    })\n    trained_model.save(f\"{name}_model.h5\")\n\n# Tampilkan ringkasan hasil\nresults_df = pd.DataFrame(results)\nprint(\"\\nRingkasan Hasil Evaluasi Model:\")\nprint(results_df)\n\n# Plot perbandingan performa model\nplt.figure(figsize=(10, 6))\nplt.bar(results_df['Model'], results_df['Validation AUC'], alpha=0.7, label='Validation AUC')\nplt.bar(results_df['Model'], results_df['Test AUC'], alpha=0.7, label='Test AUC')\nplt.ylabel('AUC Score')\nplt.title('Perbandingan Performa Model')\nplt.ylim(0.5, 1.0)\nplt.legend()\nplt.grid(axis='y', linestyle='--', alpha=0.7)\nplt.savefig('model_comparison.png')\nplt.show()","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-05-30T03:06:57.394470Z","iopub.execute_input":"2025-05-30T03:06:57.395729Z","iopub.status.idle":"2025-05-30T06:47:49.947094Z","shell.execute_reply.started":"2025-05-30T03:06:57.395675Z","shell.execute_reply":"2025-05-30T06:47:49.945886Z"}},"outputs":[],"execution_count":null}]}