{"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":[{"sourceType":"competition","sourceId":14774,"databundleVersionId":875431},{"sourceType":"datasetVersion","sourceId":2822650,"datasetId":1715304,"databundleVersionId":2869088},{"sourceType":"datasetVersion","sourceId":187731,"datasetId":80814,"databundleVersionId":198687},{"sourceType":"datasetVersion","sourceId":12928588,"datasetId":8180962,"databundleVersionId":13582845},{"sourceType":"kernelVersion","sourceId":17835088}],"dockerImageVersionId":31089,"isInternetEnabled":true,"language":"python","sourceType":"notebook","isGpuEnabled":true}},"nbformat_minor":4,"nbformat":4,"cells":[{"cell_type":"code","source":"!pip install -U keras","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-09-11T08:06:32.246854Z","iopub.execute_input":"2025-09-11T08:06:32.247522Z","iopub.status.idle":"2025-09-11T08:06:38.284869Z","shell.execute_reply.started":"2025-09-11T08:06:32.247497Z","shell.execute_reply":"2025-09-11T08:06:38.284157Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"import os, random, math, gc, warnings\nwarnings.filterwarnings(\"ignore\")\nimport tensorflow as tf\nimport os, cv2, keras, numpy as np, pandas as pd\n#from keras.applications.densenet import DenseNet121\nfrom tensorflow.keras.applications import EfficientNetB4\nfrom tensorflow.keras.preprocessing.image import ImageDataGenerator\nfrom keras.callbacks import Callback, EarlyStopping, ReduceLROnPlateau, ModelCheckpoint\nfrom sklearn.model_selection import train_test_split\nfrom sklearn.metrics import cohen_kappa_score, confusion_matrix, classification_report\nfrom sklearn.utils.class_weight import compute_class_weight\nimport matplotlib.pyplot as plt\nfrom tensorflow.keras import optimizers\nprint(\"TF:\", tf.__version__)\nprint(\"GPU:\", tf.config.list_physical_devices('GPU'))\nprint(os.listdir(\"../input\"))\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-09-11T08:08:02.292373Z","iopub.execute_input":"2025-09-11T08:08:02.293229Z","iopub.status.idle":"2025-09-11T08:08:02.301332Z","shell.execute_reply.started":"2025-09-11T08:08:02.293198Z","shell.execute_reply":"2025-09-11T08:08:02.300569Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# -----------------------------\n# 1. Load Data\n# -----------------------------\nimg_size = 224\nbatch_size = 32\ndata_path = \"/kaggle/input/aptos2019-blindness-detection\"\n\ntrain_data = pd.read_csv(f\"{data_path}/train.csv\")\ntrain_data[\"filename\"] = train_data[\"id_code\"].map(lambda x: os.path.join(f\"{data_path}/train_images\", x+\".png\"))","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-09-11T08:08:11.313197Z","iopub.execute_input":"2025-09-11T08:08:11.313481Z","iopub.status.idle":"2025-09-11T08:08:11.329974Z","shell.execute_reply.started":"2025-09-11T08:08:11.313459Z","shell.execute_reply":"2025-09-11T08:08:11.329062Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# -----------------------------\n# 2. Preprocessing (Gamma + CLAHE + Contrast)\n# -----------------------------\ndef preprocess_image(img_path, gamma=1.5):\n    img = cv2.imread(img_path)\n    img = cv2.resize(img, (img_size, img_size))\n    \n    # Gamma correction\n    img_yuv = cv2.cvtColor(img, cv2.COLOR_BGR2YUV)\n    img_yuv[:,:,0] = np.power(img_yuv[:,:,0] / 255.0, gamma) * 255.0\n    img = cv2.cvtColor(img_yuv, cv2.COLOR_YUV2BGR)\n    \n    # Contrast Enhancement\n    img = cv2.convertScaleAbs(img, alpha=1.2, beta=0)\n    \n    # CLAHE\n    lab = cv2.cvtColor(img, cv2.COLOR_BGR2LAB)\n    l, a, b = cv2.split(lab)\n    clahe = cv2.createCLAHE(clipLimit=2.0, tileGridSize=(8, 8))\n    l = clahe.apply(l)\n    img = cv2.merge((l, a, b))\n    img = cv2.cvtColor(img, cv2.COLOR_LAB2BGR)\n    \n    return img.astype(np.float32) / 255.0\n\ndef load_images(df, img_size, n_classes):\n    df = df.reset_index(drop=True)  # 🔹 Reset index to 0...len-1\n    X = np.zeros((len(df), img_size, img_size, 3))\n    y = np.zeros((len(df), n_classes))\n    \n    for i, row in df.iterrows():\n        X[i] = preprocess_image(row[\"filename\"])\n        y[i, row[\"diagnosis\"]] = 1  # one-hot encoding\n    \n    return X, y\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-09-11T08:08:14.755586Z","iopub.execute_input":"2025-09-11T08:08:14.756205Z","iopub.status.idle":"2025-09-11T08:08:14.763175Z","shell.execute_reply.started":"2025-09-11T08:08:14.756182Z","shell.execute_reply":"2025-09-11T08:08:14.762403Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# -----------------------------\n# 3. Train-Val Split\n# -----------------------------\ntrain_df, val_df = train_test_split(train_data, test_size=0.2, stratify=train_data[\"diagnosis\"], random_state=42)\nX_train, Y_train = load_images(train_df, img_size, 5)\nX_val, Y_val = load_images(val_df, img_size, 5)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-09-11T08:08:18.084819Z","iopub.execute_input":"2025-09-11T08:08:18.0854Z","iopub.status.idle":"2025-09-11T08:14:19.487135Z","shell.execute_reply.started":"2025-09-11T08:08:18.085381Z","shell.execute_reply":"2025-09-11T08:14:19.48642Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# -----------------------------\n# 4. Class Weights\n# -----------------------------\ny_train_labels = np.argmax(Y_train, axis=1)\nclass_weights = compute_class_weight(\"balanced\", classes=np.unique(y_train_labels), y=y_train_labels)\nclass_weights = dict(enumerate(class_weights))\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-09-11T08:14:45.355314Z","iopub.execute_input":"2025-09-11T08:14:45.355843Z","iopub.status.idle":"2025-09-11T08:14:45.36169Z","shell.execute_reply.started":"2025-09-11T08:14:45.355822Z","shell.execute_reply":"2025-09-11T08:14:45.360968Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# -----------------------------\n# 5. Mixup Data Generator\n# -----------------------------\nfrom tensorflow.keras.preprocessing.image import ImageDataGenerator\ndatagen = ImageDataGenerator(horizontal_flip=True, vertical_flip=True, zoom_range=0.2)\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-09-11T08:14:48.417699Z","iopub.execute_input":"2025-09-11T08:14:48.418227Z","iopub.status.idle":"2025-09-11T08:14:48.421993Z","shell.execute_reply.started":"2025-09-11T08:14:48.418202Z","shell.execute_reply":"2025-09-11T08:14:48.42128Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"def mixup_generator(X, y, batch_size, alpha=0.2):\n    n = len(X)\n    while True:\n        idx = np.random.permutation(n)\n        X1, X2 = X[idx[:batch_size]], X[idx[batch_size:2*batch_size]]\n        y1, y2 = y[idx[:batch_size]], y[idx[batch_size:2*batch_size]]\n        l = np.random.beta(alpha, alpha, batch_size)\n        X_batch = l[:, None, None, None]*X1 + (1-l)[:, None, None, None]*X2\n        y_batch = l[:, None]*y1 + (1-l)[:, None]*y2\n        yield X_batch, y_batch\n\ntrain_gen = mixup_generator(X_train, Y_train, batch_size)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-09-11T08:14:52.439526Z","iopub.execute_input":"2025-09-11T08:14:52.440123Z","iopub.status.idle":"2025-09-11T08:14:52.445098Z","shell.execute_reply.started":"2025-09-11T08:14:52.440101Z","shell.execute_reply":"2025-09-11T08:14:52.444385Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# -----------------------------\n# 6. Build DenseNet121 Model\n# -----------------------------\n#base_model = DenseNet121(include_top=False, weights=\"imagenet\", input_shape=(img_size, img_size, 3))\n#x = keras.layers.GlobalAveragePooling2D()(base_model.output)\n#x = keras.layers.Dense(256, activation=\"relu\", kernel_regularizer=keras.regularizers.l2(1e-4))(x)\n#out = keras.layers.Dense(5, activation=\"softmax\")(x)\n#model = keras.models.Model(inputs=base_model.input, outputs=out)\n\n#for layer in base_model.layers[:-50]:\n    #layer.trainable = False  # Freeze most layers first\n\n#model.compile(optimizers.Adam(1e-4), loss=\"categorical_crossentropy\", metrics=[\"accuracy\"])","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-09-07T17:30:05.758181Z","iopub.execute_input":"2025-09-07T17:30:05.758477Z","iopub.status.idle":"2025-09-07T17:30:07.563646Z","shell.execute_reply.started":"2025-09-07T17:30:05.758453Z","shell.execute_reply":"2025-09-07T17:30:07.562976Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"base_model = EfficientNetB4(include_top=False, weights=\"imagenet\", input_shape=(img_size, img_size, 3))\nx = keras.layers.GlobalAveragePooling2D()(base_model.output)\nx = keras.layers.Dense(256, activation=\"relu\", kernel_regularizer=keras.regularizers.l2(1e-4))(x)\nout = keras.layers.Dense(5, activation=\"softmax\")(x)\nmodel = keras.models.Model(inputs=base_model.input, outputs=out)\n\nfor layer in base_model.layers[:-50]:\n    layer.trainable = False  # Freeze most layers first (adjust -50 if needed for EfficientNet)\n\nmodel.compile(optimizers.Adam(1e-4), loss=\"categorical_crossentropy\", metrics=[\"accuracy\"])","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-09-11T08:15:34.774345Z","iopub.execute_input":"2025-09-11T08:15:34.775167Z","iopub.status.idle":"2025-09-11T08:15:42.59259Z","shell.execute_reply.started":"2025-09-11T08:15:34.775122Z","shell.execute_reply":"2025-09-11T08:15:42.592054Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"\n# Print model summary like in your screenshot\nmodel.summary()","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-09-11T08:20:44.434343Z","iopub.execute_input":"2025-09-11T08:20:44.434625Z","iopub.status.idle":"2025-09-11T08:20:44.797131Z","shell.execute_reply.started":"2025-09-11T08:20:44.434605Z","shell.execute_reply":"2025-09-11T08:20:44.79631Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# -----------------------------\n# 7. Callbacks\n# -----------------------------\ncallbacks = [\n    EarlyStopping(patience=10, restore_best_weights=True),\n    ReduceLROnPlateau(monitor=\"val_loss\", factor=0.5, patience=3, min_lr=1e-6),\n    ModelCheckpoint(\"best_model.h5\", save_best_only=True, monitor=\"val_accuracy\", mode=\"max\")\n]","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-09-11T08:22:29.613317Z","iopub.execute_input":"2025-09-11T08:22:29.613867Z","iopub.status.idle":"2025-09-11T08:22:29.617751Z","shell.execute_reply.started":"2025-09-11T08:22:29.613846Z","shell.execute_reply":"2025-09-11T08:22:29.616982Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# -----------------------------\n# 8. Training\n# -----------------------------\nsteps_per_epoch = len(X_train)//batch_size\nval_steps = len(X_val)//batch_size\n\nhistory = model.fit(train_gen,\n                    validation_data=(X_val, Y_val),\n                    epochs=50,\n                    steps_per_epoch=steps_per_epoch,\n                    validation_steps=val_steps,\n                    callbacks=callbacks)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-09-11T08:22:41.236289Z","iopub.execute_input":"2025-09-11T08:22:41.23656Z","iopub.status.idle":"2025-09-11T08:33:04.876253Z","shell.execute_reply.started":"2025-09-11T08:22:41.23654Z","shell.execute_reply":"2025-09-11T08:33:04.875364Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# -----------------------------\n# 9. Test Prediction & Distribution\n# -----------------------------\ntest_data = pd.read_csv(f\"{data_path}/test.csv\")\ntest_data[\"filename\"] = test_data[\"id_code\"].map(lambda x: os.path.join(f\"{data_path}/test_images\", x+\".png\"))\n\nX_test = np.array([preprocess_image(f) for f in test_data[\"filename\"]])\npreds = model.predict(X_test)\ntest_data[\"diagnosis\"] = np.argmax(preds, axis=1)\n\n# Prediction distribution graph\nplt.figure(figsize=(6,4))\ntest_data[\"diagnosis\"].hist(bins=5)\nplt.title(\"Prediction Distribution on Test Data\")\nplt.xlabel(\"Class\")\nplt.ylabel(\"Count\")\nplt.show()","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-09-07T17:27:06.240519Z","iopub.execute_input":"2025-09-07T17:27:06.24146Z","iopub.status.idle":"2025-09-07T17:28:37.338224Z","shell.execute_reply.started":"2025-09-07T17:27:06.241424Z","shell.execute_reply":"2025-09-07T17:28:37.337451Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# Save submission\ntest_data[[\"id_code\",\"diagnosis\"]].to_csv(\"submission.csv\", index=False)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-09-07T17:28:43.050991Z","iopub.execute_input":"2025-09-07T17:28:43.051262Z","iopub.status.idle":"2025-09-07T17:28:43.059474Z","shell.execute_reply.started":"2025-09-07T17:28:43.051241Z","shell.execute_reply":"2025-09-07T17:28:43.05887Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"from sklearn.metrics import confusion_matrix, classification_report\nimport seaborn as sns\nimport matplotlib.pyplot as plt\n\n# -----------------------------\n# 10. Confusion Matrix & Classification Report\n# -----------------------------\n# Predictions on validation set\nval_preds = model.predict(X_val)\nval_pred_classes = np.argmax(val_preds, axis=1)\nval_true_classes = np.argmax(Y_val, axis=1)\n\n# Confusion Matrix\ncm = confusion_matrix(val_true_classes, val_pred_classes)\nplt.figure(figsize=(6,5))\nsns.heatmap(cm, annot=True, fmt=\"d\", cmap=\"Blues\", xticklabels=range(5), yticklabels=range(5))\nplt.xlabel(\"Predicted\")\nplt.ylabel(\"Actual\")\nplt.title(\"Confusion Matrix on Validation Data\")\nplt.show()\n\n# Classification Report\nreport = classification_report(val_true_classes, val_pred_classes, target_names=[f\"Class {i}\" for i in range(5)])\nprint(\"Classification Report:\\n\")\nprint(report)\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-09-07T17:28:46.618982Z","iopub.execute_input":"2025-09-07T17:28:46.619549Z","iopub.status.idle":"2025-09-07T17:28:54.811747Z","shell.execute_reply.started":"2025-09-07T17:28:46.619526Z","shell.execute_reply":"2025-09-07T17:28:54.810996Z"}},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"End of First code!","metadata":{}},{"cell_type":"markdown","source":"Start of 2nd Code:","metadata":{}},{"cell_type":"code","source":"!pip install -U scikit-learn==1.2.2 imbalanced-learn==0.10.1","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-09-09T18:05:00.405352Z","iopub.execute_input":"2025-09-09T18:05:00.405994Z","iopub.status.idle":"2025-09-09T18:05:05.176459Z","shell.execute_reply.started":"2025-09-09T18:05:00.405969Z","shell.execute_reply":"2025-09-09T18:05:05.175554Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"import os, random, math, gc, warnings\nwarnings.filterwarnings(\"ignore\")\nimport tensorflow as tf\nimport os, cv2, keras, numpy as np, pandas as pd\nfrom keras.applications.densenet import DenseNet121\nfrom tensorflow.keras.preprocessing.image import ImageDataGenerator\nfrom keras.callbacks import EarlyStopping, ReduceLROnPlateau, ModelCheckpoint\nfrom sklearn.model_selection import train_test_split\nfrom sklearn.metrics import cohen_kappa_score, confusion_matrix, classification_report, roc_curve, auc\nfrom sklearn.utils.class_weight import compute_class_weight\nimport matplotlib.pyplot as plt\nimport seaborn as sns\nfrom sklearn.preprocessing import label_binarize\nfrom tensorflow.keras import optimizers\n\nprint(\"TF:\", tf.__version__)\nprint(\"GPU:\", tf.config.list_physical_devices('GPU'))","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-09-11T07:18:39.593556Z","iopub.execute_input":"2025-09-11T07:18:39.593774Z","iopub.status.idle":"2025-09-11T07:18:53.777391Z","shell.execute_reply.started":"2025-09-11T07:18:39.593751Z","shell.execute_reply":"2025-09-11T07:18:53.776707Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# -----------------------------\n# 1. Load Data\n# -----------------------------\nimg_size = 224\nbatch_size = 32\ndata_path = \"/kaggle/input/aptos2019-blindness-detection\"\n\ntrain_data = pd.read_csv(f\"{data_path}/train.csv\")\ntrain_data[\"filename\"] = train_data[\"id_code\"].map(lambda x: os.path.join(f\"{data_path}/train_images\", x+\".png\"))","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-09-11T07:19:22.258137Z","iopub.execute_input":"2025-09-11T07:19:22.258995Z","iopub.status.idle":"2025-09-11T07:19:22.287844Z","shell.execute_reply.started":"2025-09-11T07:19:22.258966Z","shell.execute_reply":"2025-09-11T07:19:22.287315Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# -----------------------------\n# 2. Preprocessing (Tunable)\n# -----------------------------\ndef crop_retina(img, threshold=10):\n    gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)\n    mask = gray > threshold\n    coords = np.argwhere(mask)\n    if len(coords) == 0:\n        return img\n    y_min, x_min = coords.min(axis=0)\n    y_max, x_max = coords.max(axis=0)\n    cropped = img[y_min:y_max+1, x_min:x_max+1]\n    return cv2.resize(cropped, (img_size, img_size))\n\ndef ben_graham_preprocess(img, sigmaX=5):  # Reduced sigmaX to avoid over-blur\n    img = cv2.addWeighted(img, 4, cv2.GaussianBlur(img, (0,0), sigmaX), -4, 128)\n    return img\n\ndef preprocess_image(img_path, gamma=1.2, use_crop=True, use_ben=True):  # Tuned gamma; flags to disable\n    img = cv2.imread(img_path)\n    img = cv2.resize(img, (img_size, img_size))\n    if use_crop:\n        img = crop_retina(img)\n    # Gamma correction\n    img_yuv = cv2.cvtColor(img, cv2.COLOR_BGR2YUV)\n    img_yuv[:,:,0] = np.power(img_yuv[:,:,0] / 255.0, gamma) * 255.0\n    img = cv2.cvtColor(img_yuv, cv2.COLOR_YUV2BGR)\n    # Contrast Enhancement\n    img = cv2.convertScaleAbs(img, alpha=1.2, beta=0)\n    # CLAHE\n    lab = cv2.cvtColor(img, cv2.COLOR_BGR2LAB)\n    l, a, b = cv2.split(lab)\n    clahe = cv2.createCLAHE(clipLimit=2.0, tileGridSize=(8, 8))\n    l = clahe.apply(l)\n    img = cv2.merge((l, a, b))\n    img = cv2.cvtColor(img, cv2.COLOR_LAB2BGR)\n    if use_ben:\n        img = ben_graham_preprocess(img)\n    return img.astype(np.float32) / 255.0\n\ndef load_images(df, img_size, n_classes):\n    df = df.reset_index(drop=True)\n    X = np.zeros((len(df), img_size, img_size, 3))\n    y = np.zeros((len(df), n_classes))\n    for i, row in df.iterrows():\n        X[i] = preprocess_image(row[\"filename\"])\n        y[i, row[\"diagnosis\"]] = 1\n    return X, y","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-09-11T07:20:09.203481Z","iopub.execute_input":"2025-09-11T07:20:09.203762Z","iopub.status.idle":"2025-09-11T07:20:09.212962Z","shell.execute_reply.started":"2025-09-11T07:20:09.203741Z","shell.execute_reply":"2025-09-11T07:20:09.2122Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# -----------------------------\n# 3. Train-Val Split\n# -----------------------------\ntrain_df, val_df = train_test_split(train_data, test_size=0.2, stratify=train_data[\"diagnosis\"], random_state=42)\nX_train, Y_train = load_images(train_df, img_size, 5)\nX_val, Y_val = load_images(val_df, img_size, 5)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-09-11T07:20:27.591715Z","iopub.execute_input":"2025-09-11T07:20:27.592Z","iopub.status.idle":"2025-09-11T07:28:09.123493Z","shell.execute_reply.started":"2025-09-11T07:20:27.591977Z","shell.execute_reply":"2025-09-11T07:28:09.122866Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# -----------------------------\n# 4. Manual Oversampling (Tuned: Lower multiplier; optional disable)\n# -----------------------------\ndef manual_oversample(X, y, class_counts, multiplier=1, enable=True):  # Reduced multiplier; add enable flag\n    if not enable:\n        return X, y\n    X_resampled = X.copy()\n    y_resampled = y.copy()\n    max_count = max(class_counts)\n    for cls in range(5):\n        if class_counts[cls] < max_count:\n            cls_indices = np.where(np.argmax(y, axis=1) == cls)[0]\n            n_samples = min(int((max_count - class_counts[cls]) * multiplier), len(cls_indices) * multiplier)\n            sampled_indices = np.random.choice(cls_indices, size=n_samples, replace=True)\n            X_resampled = np.concatenate([X_resampled, X[sampled_indices]], axis=0)\n            y_resampled = np.concatenate([y_resampled, y[sampled_indices]], axis=0)\n    return X_resampled, y_resampled\n\nclass_counts = np.sum(Y_train, axis=0)\nX_train_resampled, Y_train_resampled = manual_oversample(X_train, Y_train, class_counts, multiplier=1, enable=True)  # Try enable=False to test without","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-09-11T07:41:41.455971Z","iopub.execute_input":"2025-09-11T07:41:41.456342Z","iopub.status.idle":"2025-09-11T07:41:49.493283Z","shell.execute_reply.started":"2025-09-11T07:41:41.456317Z","shell.execute_reply":"2025-09-11T07:41:49.492538Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# -----------------------------\n# 5. Class Weights\n# -----------------------------\ny_train_labels = np.argmax(Y_train_resampled, axis=1)  # Use resampled for weights\nclass_weights = compute_class_weight(\"balanced\", classes=np.unique(y_train_labels), y=y_train_labels)\nclass_weights = dict(enumerate(class_weights))","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-09-11T07:42:03.920076Z","iopub.execute_input":"2025-09-11T07:42:03.920341Z","iopub.status.idle":"2025-09-11T07:42:03.9281Z","shell.execute_reply.started":"2025-09-11T07:42:03.920321Z","shell.execute_reply":"2025-09-11T07:42:03.927189Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# -----------------------------\n# 6. Mixup Data Generator\n# -----------------------------\ndatagen = ImageDataGenerator(\n    horizontal_flip=True,\n    vertical_flip=True,\n    zoom_range=0.2,\n    rotation_range=30,\n    shear_range=0.2,\n    brightness_range=[0.8, 1.2],\n    channel_shift_range=20.0,\n    fill_mode='nearest'\n)\n\ndef mixup_generator(X, y, batch_size, alpha=0.2):\n    n = len(X)\n    while True:\n        idx = np.random.permutation(n)\n        start = 0\n        while start < n:\n            end = min(start + batch_size, n)\n            X1, X2 = X[idx[start:end]], X[idx[(start + batch_size) % n : (start + batch_size) % n + (end - start)]]\n            y1, y2 = y[idx[start:end]], y[idx[(start + batch_size) % n : (start + batch_size) % n + (end - start)]]\n            l = np.random.beta(alpha, alpha, end - start)\n            X_batch = l[:, None, None, None] * X1 + (1 - l)[:, None, None, None] * X2\n            y_batch = l[:, None] * y1 + (1 - l)[:, None] * y2\n            yield X_batch, y_batch\n            start = end\n\ntrain_gen = mixup_generator(X_train_resampled, Y_train_resampled, batch_size)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-09-11T07:42:25.21987Z","iopub.execute_input":"2025-09-11T07:42:25.22016Z","iopub.status.idle":"2025-09-11T07:42:25.22649Z","shell.execute_reply.started":"2025-09-11T07:42:25.220138Z","shell.execute_reply":"2025-09-11T07:42:25.225789Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# -----------------------------\n# 7. Build DenseNet121 Model (Switched to Adam; less unfreeze)\n# -----------------------------\nbase_model = DenseNet121(include_top=False, weights=\"imagenet\", input_shape=(img_size, img_size, 3))\nx = keras.layers.GlobalAveragePooling2D()(base_model.output)\nx = keras.layers.Dense(256, activation=\"relu\", kernel_regularizer=keras.regularizers.l2(1e-4))(x)\nx = keras.layers.Dropout(0.5)(x)\nout = keras.layers.Dense(5, activation=\"softmax\")(x)\nmodel = keras.models.Model(inputs=base_model.input, outputs=out)\n\nfor layer in base_model.layers[:-50]:  # Reduced to 50 for stability\n    layer.trainable = False\n\nmodel.compile(optimizers.Adam(learning_rate=1e-4), loss=\"categorical_crossentropy\", metrics=[\"accuracy\"])  # Back to Adam\nmodel.summary()","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-09-11T07:42:49.537435Z","iopub.execute_input":"2025-09-11T07:42:49.5377Z","iopub.status.idle":"2025-09-11T07:42:56.43181Z","shell.execute_reply.started":"2025-09-11T07:42:49.537682Z","shell.execute_reply":"2025-09-11T07:42:56.431028Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# -----------------------------\n# 8. Train Model with Callbacks (Increased epochs)\n# -----------------------------\ncallbacks = [\n    EarlyStopping(monitor='val_loss', patience=7, restore_best_weights=True),  # Increased patience\n    ReduceLROnPlateau(monitor='val_loss', factor=0.2, patience=3, min_lr=1e-6),\n    ModelCheckpoint('best_model.keras', monitor='val_accuracy', save_best_only=True)\n]\n\nsteps_per_epoch = len(X_train_resampled) // batch_size\nhistory = model.fit(train_gen, steps_per_epoch=steps_per_epoch, epochs=75,  # Increased\n                    validation_data=(X_val, Y_val),\n                    callbacks=callbacks)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-09-11T07:47:58.764179Z","iopub.execute_input":"2025-09-11T07:47:58.764503Z","iopub.status.idle":"2025-09-11T07:48:57.871692Z","shell.execute_reply.started":"2025-09-11T07:47:58.764482Z","shell.execute_reply":"2025-09-11T07:48:57.870239Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# -----------------------------\n# 9. Evaluate Model\n# -----------------------------\nval_preds = model.predict(X_val)\nval_preds_classes = np.argmax(val_preds, axis=1)\nval_true = np.argmax(Y_val, axis=1)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-09-09T18:32:32.369197Z","iopub.execute_input":"2025-09-09T18:32:32.369557Z","iopub.status.idle":"2025-09-09T18:32:57.746442Z","shell.execute_reply.started":"2025-09-09T18:32:32.369533Z","shell.execute_reply":"2025-09-09T18:32:57.745861Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# Quadratic Kappa\nkappa = cohen_kappa_score(val_true, val_preds_classes, weights='quadratic')\nprint(f\"Quadratic Kappa: {kappa}\")\n\n# Classification Report\nprint(classification_report(val_true, val_preds_classes, target_names=['No DR', 'Mild', 'Moderate', 'Severe', 'Proliferative']))\n\n# Confusion Matrix\nplt.figure(figsize=(8,6))\ncm = confusion_matrix(val_true, val_preds_classes)\nsns.heatmap(cm, annot=True, fmt='d', cmap='Blues', xticklabels=[0,1,2,3,4], yticklabels=[0,1,2,3,4])\nplt.xlabel('Predicted')\nplt.ylabel('True')\nplt.title('Confusion Matrix')\nplt.show()\n\n# ROC Curve\nplt.figure(figsize=(10,8))\nval_true_bin = label_binarize(val_true, classes=[0,1,2,3,4])\nfor i in range(5):\n    fpr, tpr, _ = roc_curve(val_true_bin[:, i], val_preds[:, i])\n    roc_auc = auc(fpr, tpr)\n    plt.plot(fpr, tpr, label=f'Class {i} (AUC = {roc_auc:.2f})')\nplt.plot([0,1], [0,1], 'k--')\nplt.xlabel('False Positive Rate')\nplt.ylabel('True Positive Rate')\nplt.title('ROC Curve')\nplt.legend()\nplt.show()\n\n# Prediction Histogram\nplt.figure(figsize=(10,5))\nfor i in range(5):\n    plt.hist(val_preds[val_true == i, i], bins=20, alpha=0.5, label=f'Class {i}')\nplt.xlabel('Predicted Probability')\nplt.ylabel('Count')\nplt.title('Prediction Confidence by Class')\nplt.legend()\nplt.show()","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-09-09T18:34:05.136329Z","iopub.execute_input":"2025-09-09T18:34:05.136651Z","iopub.status.idle":"2025-09-09T18:34:05.924685Z","shell.execute_reply.started":"2025-09-09T18:34:05.136625Z","shell.execute_reply":"2025-09-09T18:34:05.920158Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"","metadata":{"trusted":true},"outputs":[],"execution_count":null}]}