{"metadata":{"kernelspec":{"display_name":"Python 3","language":"python","name":"python3"},"language_info":{"name":"python","version":"3.6.6","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":7251,"datasetId":2798,"databundleVersionId":7251}],"dockerImageVersionId":28450,"isInternetEnabled":false,"language":"python","sourceType":"notebook","isGpuEnabled":true}},"nbformat_minor":4,"nbformat":4,"cells":[{"cell_type":"markdown","source":"<h2><center>Detect diabetic retinopathy to stop blindness before it's too late</center></h2>\n<center><img src=\"https://raw.githubusercontent.com/dimitreOliveira/MachineLearning/master/Kaggle/APTOS%202019%20Blindness%20Detection/aux_img.png\"></center>\n##### Image source: http://cceyemd.com/diabetes-and-eye-exams/","metadata":{}},{"cell_type":"code","source":"# Helper libraries\nimport tensorflow\nimport numpy as np\nimport matplotlib.pyplot as plt\nimport pandas as pd\nimport cv2\nimport os\n%matplotlib inline\nprint(tensorflow.__version__)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-05-10T08:06:13.86937Z","iopub.execute_input":"2026-05-10T08:06:13.869695Z","iopub.status.idle":"2026-05-10T08:06:13.876927Z","shell.execute_reply.started":"2026-05-10T08:06:13.869644Z","shell.execute_reply":"2026-05-10T08:06:13.876152Z"}},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"## Read in the training and test data","metadata":{}},{"cell_type":"code","source":"train_df = pd.read_csv('../input/aptos2019-blindness-detection/train.csv')\ntrain_df['id_code'] = train_df['id_code'].apply(lambda x:x+'.png')\ntrain_df['diagnosis'] = train_df['diagnosis'].astype(str)\ntest_df = pd.read_csv('../input/aptos2019-blindness-detection/test.csv')\ntest_df['id_code'] = test_df['id_code'].apply(lambda x:x+'.png')\n\nnum_classes = train_df['diagnosis'].nunique()\ndiag_text = ['Normal', 'Mild', 'Moderate', 'Severe', 'Proliferative']","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-05-10T08:06:18.085881Z","iopub.execute_input":"2026-05-10T08:06:18.086178Z","iopub.status.idle":"2026-05-10T08:06:18.116653Z","shell.execute_reply.started":"2026-05-10T08:06:18.086139Z","shell.execute_reply":"2026-05-10T08:06:18.115913Z"}},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"### Look at some raw images","metadata":{}},{"cell_type":"code","source":"def display_raw_images(df, columns = 4, rows = 3):\n    fig=plt.figure(figsize = (5 * columns, 4 * rows))\n    for i in range(columns * rows):\n        image_name = df.loc[i,'id_code']\n        image_id = df.loc[i,'diagnosis']\n        img = cv2.imread(f'../input/aptos2019-blindness-detection/train_images/{image_name}')[...,[2, 1, 0]]\n        fig.add_subplot(rows, columns, i + 1)\n        plt.title(diag_text[int(image_id)])\n        plt.imshow(img)\n    plt.tight_layout()\n\ndisplay_raw_images(train_df)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-05-10T08:06:21.698706Z","iopub.execute_input":"2026-05-10T08:06:21.699279Z","iopub.status.idle":"2026-05-10T08:06:31.516913Z","shell.execute_reply.started":"2026-05-10T08:06:21.699218Z","shell.execute_reply":"2026-05-10T08:06:31.515403Z"}},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"### Graph out the class frequency","metadata":{}},{"cell_type":"code","source":"import numpy as np\nimport matplotlib.pyplot as plt\n\nunique, counts = np.unique(train_df['diagnosis'], return_counts=True)\n\nplt.bar(unique, counts)\nplt.title('Class Frequency')\nplt.xlabel('Class')\nplt.ylabel('Frequency')\n\n# إضافة الأرقام فوق كل عمود\nfor i in range(len(unique)):\n    plt.text(unique[i], counts[i], str(counts[i]), ha='center', va='bottom')\n\nplt.show()\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-05-10T08:06:35.595669Z","iopub.execute_input":"2026-05-10T08:06:35.595963Z","iopub.status.idle":"2026-05-10T08:06:35.725081Z","shell.execute_reply.started":"2026-05-10T08:06:35.595921Z","shell.execute_reply":"2026-05-10T08:06:35.724053Z"}},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"### Calculate class weights to help with training on the unbalanced data set.[](http://) ","metadata":{}},{"cell_type":"code","source":"from sklearn.utils import class_weight\n\nsklearn_class_weights = class_weight.compute_class_weight(\n               'balanced',\n                np.unique(train_df['diagnosis']), \n                train_df['diagnosis'])\n\nprint(sklearn_class_weights)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-05-10T08:06:39.325897Z","iopub.execute_input":"2026-05-10T08:06:39.326271Z","iopub.status.idle":"2026-05-10T08:06:39.334542Z","shell.execute_reply.started":"2026-05-10T08:06:39.326197Z","shell.execute_reply":"2026-05-10T08:06:39.33374Z"}},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"## Load a model","metadata":{}},{"cell_type":"code","source":"from tensorflow.keras.callbacks import EarlyStopping, ReduceLROnPlateau, ModelCheckpoint, Callback\nfrom tensorflow.keras.layers import Dense, Dropout, GlobalAveragePooling2D\nfrom tensorflow.keras.applications import DenseNet121, ResNet50, InceptionV3, Xception\nfrom tensorflow.keras.models import Model, Sequential\nfrom tensorflow.keras.optimizers import Adam \n\ndef create_resnet50_model(input_shape, n_out):\n    base_model = ResNet50(weights = None,\n                          include_top = False,\n                          input_shape = input_shape)\n    \n    base_model.load_weights('../input/keras-pretrained-models/resnet50_weights_tf_dim_ordering_tf_kernels_notop.h5')\n    model = Sequential()\n    model.add(base_model)\n    model.add(GlobalAveragePooling2D())\n    model.add(Dropout(0.5))\n    model.add(Dense(2048, activation = 'relu'))\n    model.add(Dropout(0.5))    \n    model.add(Dense(n_out, activation = 'sigmoid'))\n    return model\n\ndef create_inception_v3_model(input_shape, n_out):\n    base_model = InceptionV3(weights = None,\n                             include_top = False,\n                             input_shape = input_shape)\n    base_model.load_weights('../input/keras-pretrained-models/inception_v3_weights_tf_dim_ordering_tf_kernels_notop.h5')\n    model = Sequential()\n    model.add(base_model)\n    model.add(GlobalAveragePooling2D())\n    model.add(Dropout(0.5))\n    model.add(Dense(2048, activation = 'relu'))\n    model.add(Dropout(0.5))    \n    model.add(Dense(n_out, activation = 'sigmoid'))\n    return model\n\ndef create_xception_model(input_shape, n_out):\n    base_model = Xception(weights = None,\n                             include_top = False,\n                             input_shape = input_shape)\n    base_model.load_weights('../input/keras-pretrained-models/xception_weights_tf_dim_ordering_tf_kernels_notop.h5')\n    model = Sequential()\n    model.add(base_model)\n    model.add(GlobalAveragePooling2D())\n    model.add(Dropout(0.5))\n    model.add(Dense(2048, activation = 'relu'))\n    model.add(Dropout(0.5))    \n    model.add(Dense(n_out, activation = 'sigmoid'))\n    return model\n\ndef create_densenet121_model(input_shape, n_out):\n    base_model = DenseNet121(weights = None,\n                             include_top = False,\n                             input_shape = input_shape)\n    base_model.load_weights('../input/densenet-keras/DenseNet-BC-121-32-no-top.h5')\n    model = Sequential()\n    model.add(base_model)\n    model.add(GlobalAveragePooling2D())\n    model.add(Dropout(0.5))\n    model.add(Dense(2048, activation = 'relu'))\n    model.add(Dropout(0.5))    \n    model.add(Dense(n_out, activation = 'sigmoid'))\n    return model","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-05-10T08:06:52.071294Z","iopub.execute_input":"2026-05-10T08:06:52.071645Z","iopub.status.idle":"2026-05-10T08:06:52.08576Z","shell.execute_reply.started":"2026-05-10T08:06:52.071557Z","shell.execute_reply":"2026-05-10T08:06:52.084759Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"#IMAGE_HEIGHT = 224\n#IMAGE_WIDTH = 224\n#model = create_resnet50_model(input_shape = (IMAGE_HEIGHT, IMAGE_WIDTH, 3), n_out = num_classes)\n#model = create_densenet121_model(input_shape = (IMAGE_HEIGHT, IMAGE_WIDTH, 3), n_out = num_classes)\n\nIMAGE_HEIGHT = 299\nIMAGE_WIDTH = 299\n#model = create_inception_v3_model(input_shape = (IMAGE_HEIGHT, IMAGE_WIDTH, 3), n_out = num_classes)\nmodel = create_xception_model(input_shape = (IMAGE_HEIGHT, IMAGE_WIDTH, 3), n_out = num_classes)\n\nmodel.summary()","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-05-10T08:06:57.83054Z","iopub.execute_input":"2026-05-10T08:06:57.830957Z","iopub.status.idle":"2026-05-10T08:07:06.170615Z","shell.execute_reply.started":"2026-05-10T08:06:57.830886Z","shell.execute_reply":"2026-05-10T08:07:06.169804Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"PRETRAINED_MODEL = '../input/pretrained_blindness_detector/blindness_detector.h5'\n\nif (os.path.exists(PRETRAINED_MODEL)):\n  print('Restoring model from ' + PRETRAINED_MODEL)\n  model.load_weights(PRETRAINED_MODEL)\nelse:\n  print('No pretrained model found. Using fresh model.')\n\ncurrent_epoch = 0","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-05-10T08:07:09.918912Z","iopub.execute_input":"2026-05-10T08:07:09.919211Z","iopub.status.idle":"2026-05-10T08:07:09.924771Z","shell.execute_reply.started":"2026-05-10T08:07:09.919172Z","shell.execute_reply":"2026-05-10T08:07:09.923528Z"}},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"## Preprocess the data","metadata":{}},{"cell_type":"markdown","source":"#### Crop and improve lighting condition using Ben Graham's preprocessing method\nSee: https://www.kaggle.com/ratthachat/aptos-updated-preprocessing-ben-s-cropping","metadata":{}},{"cell_type":"code","source":"from tqdm import tqdm\n\ndef crop_image_from_gray(img, tol = 7):\n    if img.ndim == 2:\n        mask = img > tol\n        return img[np.ix_(mask.any(1),mask.any(0))]\n    elif img.ndim == 3:\n        gray_img = cv2.cvtColor(img, cv2.COLOR_RGB2GRAY)\n        mask = gray_img > tol        \n        check_shape = img[:,:,0][np.ix_(mask.any(1),mask.any(0))].shape[0]\n        if (check_shape == 0): # image is too dark so that we crop out everything,\n            return img # return original image\n        else:\n            img1 = img[:,:,0][np.ix_(mask.any(1),mask.any(0))]\n            img2 = img[:,:,1][np.ix_(mask.any(1),mask.any(0))]\n            img3 = img[:,:,2][np.ix_(mask.any(1),mask.any(0))]\n            img = np.stack([img1,img2,img3],axis = -1)\n        return img\n\ndef preprocess_image(image_path, sigmaX = 10):\n    image = cv2.imread(image_path)\n    image = cv2.cvtColor(image, cv2.COLOR_BGR2RGB)\n    image = crop_image_from_gray(image)\n    image = cv2.resize(image, (IMAGE_HEIGHT, IMAGE_WIDTH))\n    image = cv2.addWeighted(image, 4, cv2.GaussianBlur(image, (0,0), sigmaX), -4, 128)        \n    return image\n\nprint(\"Preprocessing training images...\")\nx_train = np.empty((train_df.shape[0], IMAGE_HEIGHT, IMAGE_WIDTH, 3), dtype = np.uint8)\nfor i, image_id in enumerate(tqdm(train_df['id_code'])):\n    x_train[i, :, :, :] = preprocess_image(f'../input/aptos2019-blindness-detection/train_images/{image_id}')","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-05-10T08:07:15.311114Z","iopub.execute_input":"2026-05-10T08:07:15.311396Z","iopub.status.idle":"2026-05-10T08:17:42.418086Z","shell.execute_reply.started":"2026-05-10T08:07:15.311355Z","shell.execute_reply":"2026-05-10T08:17:42.417263Z"}},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"### Look at some preprocessed images","metadata":{}},{"cell_type":"code","source":"def display_preprocessed_images(df, columns = 4, rows = 3):\n    fig=plt.figure(figsize = (5 * columns, 4 * rows))\n    for i in range(columns * rows):\n        image_name = df.loc[i,'id_code']\n        image_id = df.loc[i,'diagnosis']\n        img = x_train[i]\n        fig.add_subplot(rows, columns, i + 1)\n        plt.title(diag_text[int(image_id)])\n        plt.imshow(img)\n    plt.tight_layout()\n\ndisplay_preprocessed_images(train_df)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-05-10T08:17:48.038418Z","iopub.execute_input":"2026-05-10T08:17:48.038707Z","iopub.status.idle":"2026-05-10T08:17:51.628463Z","shell.execute_reply.started":"2026-05-10T08:17:48.038666Z","shell.execute_reply":"2026-05-10T08:17:51.627271Z"}},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"### Change target to a multi-label problem so a class encompasses all the classes before it.\nsee: https://arxiv.org/abs/0704.1028","metadata":{}},{"cell_type":"code","source":"y_train = pd.get_dummies(train_df['diagnosis']).values\ny_train_multi = np.empty(y_train.shape, dtype = y_train.dtype)\ny_train_multi[:, 4] = y_train[:, 4]\n\nfor i in range(3, -1, -1):\n    y_train_multi[:, i] = np.logical_or(y_train[:, i], y_train_multi[:, i + 1])","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-05-10T08:18:15.334811Z","iopub.execute_input":"2026-05-10T08:18:15.335194Z","iopub.status.idle":"2026-05-10T08:18:15.342721Z","shell.execute_reply.started":"2026-05-10T08:18:15.335128Z","shell.execute_reply":"2026-05-10T08:18:15.341684Z"}},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"### Split into training and validation","metadata":{}},{"cell_type":"code","source":"from sklearn.model_selection import train_test_split\n\nx_train, x_val, y_train, y_val = train_test_split(\n    x_train, y_train_multi, \n    test_size = 0.20, \n    random_state = 2006\n)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-05-10T08:18:21.086185Z","iopub.execute_input":"2026-05-10T08:18:21.086448Z","iopub.status.idle":"2026-05-10T08:18:21.890873Z","shell.execute_reply.started":"2026-05-10T08:18:21.086411Z","shell.execute_reply":"2026-05-10T08:18:21.890108Z"}},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"## Setup training data generator with augmentation","metadata":{}},{"cell_type":"code","source":"from tensorflow.keras.preprocessing.image import ImageDataGenerator\n\nTRAIN_DATA_ROOT = '../input/aptos2019-blindness-detection/train_images'\nTEST_DATA_ROOT  = '../input/aptos2019-blindness-detection/test_images'\n\nBATCH_SIZE = 16\n\ntrain_datagen = ImageDataGenerator(\n    rotation_range = 360, \n    horizontal_flip = True, \n#    vertical_flip = True,\n    zoom_range = [0.98, 1.02], \n    width_shift_range = 0.01,\n    height_shift_range = 0.01)\n\ntrain_generator = train_datagen.flow(\n    x_train, \n    y_train,\n    batch_size = BATCH_SIZE, \n    shuffle = True)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-05-10T08:18:29.254067Z","iopub.execute_input":"2026-05-10T08:18:29.254411Z","iopub.status.idle":"2026-05-10T08:18:31.390128Z","shell.execute_reply.started":"2026-05-10T08:18:29.254345Z","shell.execute_reply":"2026-05-10T08:18:31.388967Z"}},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"## Train the clasifier head","metadata":{}},{"cell_type":"code","source":"WARMUP_EPOCHS = 2\nWARMUP_LEARNING_RATE = 1e-3\n\nfor layer in model.layers:\n    layer.trainable = False\n\nfor i in range(-5, 0):\n    model.layers[i].trainable = True\n\nmodel.compile(optimizer = Adam(lr = WARMUP_LEARNING_RATE),\n              loss = 'binary_crossentropy',  \n              metrics = ['accuracy'])\n\nwarmup_history = model.fit_generator(generator = train_generator,\n#                              class_weight = sklearn_class_weights,\n                              steps_per_epoch = train_generator.n // train_generator.batch_size,\n                              validation_data = (x_val, y_val),\n                              epochs = WARMUP_EPOCHS,\n                              use_multiprocessing = True,\n                              workers = 4,                                     \n                              verbose = 1).history","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-05-10T08:18:36.394473Z","iopub.execute_input":"2026-05-10T08:18:36.394945Z","iopub.status.idle":"2026-05-10T08:20:00.144846Z","shell.execute_reply.started":"2026-05-10T08:18:36.394808Z","shell.execute_reply":"2026-05-10T08:20:00.141939Z"}},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"## Fine-tune the whole model","metadata":{}},{"cell_type":"code","source":"FINETUNING_EPOCHS = 20\nFINETUNING_LEARNING_RATE = 1e-4\n\n# Make all layers trainable\nfor layer in model.layers:\n    layer.trainable = True\n\n# Compile with lower LR\nmodel.compile(\n    optimizer = Adam(lr = FINETUNING_LEARNING_RATE), \n    loss = 'binary_crossentropy',\n    metrics = ['accuracy']\n)\n\n# Callbacks\ncheckpoint = ModelCheckpoint(\n    'blindness_detector_best.h5', \n    monitor = 'val_acc',  \n    save_best_only = True, \n    save_weights_only = True,\n    verbose = 1\n)\n\nrlrop = ReduceLROnPlateau(\n    monitor = 'val_loss', \n    patience = 3, \n    factor = 0.5, \n    min_lr = 1e-6, \n    verbose = 1\n)\n\nstopping = EarlyStopping(\n    monitor = 'val_acc', \n    patience = 8, \n    restore_best_weights = True, \n    verbose = 1\n)\n\n# ✅ Fix: Disable multiprocessing for stability on Windows\nfinetune_history = model.fit_generator(\n    generator = train_generator,\n    steps_per_epoch = train_generator.n // train_generator.batch_size,\n    validation_data = (x_val, y_val),\n    epochs = FINETUNING_EPOCHS,\n    callbacks = [checkpoint, rlrop, stopping],         \n    use_multiprocessing = False,   # 👈 FIXED\n    workers = 1,                   # 👈 FIXED\n    verbose = 1\n).history","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-05-10T08:20:34.942372Z","iopub.execute_input":"2026-05-10T08:20:34.942708Z","iopub.status.idle":"2026-05-10T08:45:17.824705Z","shell.execute_reply.started":"2026-05-10T08:20:34.942661Z","shell.execute_reply":"2026-05-10T08:45:17.823878Z"}},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"## Plot learning curves","metadata":{}},{"cell_type":"code","source":"training_accuracy = warmup_history['acc'] + finetune_history['acc']\nvalidation_accuracy = warmup_history['val_acc'] + finetune_history['val_acc']\ntraining_loss = warmup_history['loss'] + finetune_history['loss']\nvalidation_loss = warmup_history['val_loss'] + finetune_history['val_loss']\n\nplt.figure(figsize = (8, 8))\nplt.subplot(2, 1, 1)\nplt.plot(training_accuracy, label = 'Training Accuracy')\nplt.plot(validation_accuracy, label = 'Validation Accuracy')\nplt.legend(loc = 'lower right')\nplt.ylabel('Accuracy')\nplt.ylim([min(plt.ylim()), 1])\nplt.title('Training and Validation Accuracy')\n\nplt.subplot(2, 1, 2)\nplt.plot(training_loss, label = 'Training Loss')\nplt.plot(validation_loss, label = 'Validation Loss')\nplt.legend(loc = 'upper right')\nplt.ylabel('Cross Entropy')\nplt.ylim([0, 1.0])\nplt.title('Training and Validation Loss')\nplt.xlabel('epoch')\nplt.show()","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-05-10T08:45:39.21827Z","iopub.execute_input":"2026-05-10T08:45:39.218622Z","iopub.status.idle":"2026-05-10T08:45:39.682217Z","shell.execute_reply.started":"2026-05-10T08:45:39.218526Z","shell.execute_reply":"2026-05-10T08:45:39.681098Z"}},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"## Evaluate the model","metadata":{}},{"cell_type":"markdown","source":"### Get validation predictions from the final model","metadata":{}},{"cell_type":"code","source":"validation_predictions_raw = model.predict(x_val)\nvalidation_predictions = validation_predictions_raw > 0.5\nvalidation_predictions = validation_predictions.astype(int).sum(axis=1) - 1\nvalidation_truth = y_val.sum(axis=1) - 1","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-05-10T08:45:57.716232Z","iopub.execute_input":"2026-05-10T08:45:57.716497Z","iopub.status.idle":"2026-05-10T08:46:03.295511Z","shell.execute_reply.started":"2026-05-10T08:45:57.716459Z","shell.execute_reply":"2026-05-10T08:46:03.294868Z"}},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"### Plot some metrics","metadata":{}},{"cell_type":"code","source":"from sklearn.metrics import classification_report, confusion_matrix, cohen_kappa_score\n\ndef plot_confusion_matrix(cm, target_names, title = 'Confusion matrix', cmap = plt.cm.Blues):\n    plt.grid(False)\n    plt.imshow(cm, interpolation = 'nearest', cmap = cmap)\n    plt.title(title)\n    plt.colorbar()\n    tick_marks = np.arange(len(target_names))\n    plt.xticks(tick_marks, target_names, rotation = 90)\n    plt.yticks(tick_marks, target_names)\n    plt.tight_layout()\n    plt.ylabel('True label')\n    plt.xlabel('Predicted label')\n\nnp.set_printoptions(precision = 2)\ncm = confusion_matrix(validation_truth, validation_predictions)\ncm = cm.astype('float') / cm.sum(axis=1)[:, np.newaxis]\n\nplot_confusion_matrix(cm = cm, target_names = diag_text)\nplt.show()\n\nprint('Confusion Matrix')\nprint(cm)\n\nprint('Classification Report')\nprint(classification_report(validation_truth, validation_predictions, target_names = diag_text))\n\nprint(\"Validation Cohen Kappa score: %.3f\" % cohen_kappa_score(validation_predictions, validation_truth, weights = 'quadratic'))","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-05-10T08:46:14.284577Z","iopub.execute_input":"2026-05-10T08:46:14.284861Z","iopub.status.idle":"2026-05-10T08:46:14.645541Z","shell.execute_reply.started":"2026-05-10T08:46:14.28482Z","shell.execute_reply":"2026-05-10T08:46:14.644364Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"model.save(\"diabetic_retinopathy_model.h5\")","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-05-10T08:47:05.722266Z","iopub.execute_input":"2026-05-10T08:47:05.722532Z","iopub.status.idle":"2026-05-10T08:47:07.37779Z","shell.execute_reply.started":"2026-05-10T08:47:05.722493Z","shell.execute_reply":"2026-05-10T08:47:07.377031Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"import numpy as np\nimport matplotlib.pyplot as plt\nfrom sklearn.metrics import classification_report, confusion_matrix, cohen_kappa_score\n\ndef plot_confusion_matrix(cm, target_names, title='Confusion matrix', cmap=plt.cm.Blues):\n    plt.figure(figsize=(8, 6))\n    plt.imshow(cm, interpolation='nearest', cmap=cmap)\n    plt.title(title)\n    plt.colorbar()\n    tick_marks = np.arange(len(target_names))\n    plt.xticks(tick_marks, target_names, rotation=90)\n    plt.yticks(tick_marks, target_names)\n    \n    # كتابة الأرقام داخل الخانات\n    thresh = cm.max() / 2\n    for i in range(cm.shape[0]):\n        for j in range(cm.shape[1]):\n            plt.text(j, i, format(cm[i, j], 'd'),\n                     horizontalalignment=\"center\",\n                     color=\"white\" if cm[i, j] > thresh else \"black\")\n\n    plt.tight_layout()\n    plt.ylabel('True label')\n    plt.xlabel('Predicted label')\n\n# حساب مصفوفة الارتباك الأصلية (عدد الصور)\ncm = confusion_matrix(validation_truth, validation_predictions)\n\n# عرض المصفوفة\nplot_confusion_matrix(cm=cm, target_names=diag_text)\nplt.show()\n\nprint('Confusion Matrix')\nprint(cm)\n\nprint('Classification Report')\nprint(classification_report(validation_truth, validation_predictions, target_names=diag_text))\n\nprint(\"Validation Cohen Kappa score: %.3f\" % cohen_kappa_score(validation_predictions, validation_truth, weights='quadratic'))\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-08-03T18:20:07.072589Z","iopub.execute_input":"2025-08-03T18:20:07.072977Z","iopub.status.idle":"2025-08-03T18:20:07.358966Z","shell.execute_reply.started":"2025-08-03T18:20:07.072912Z","shell.execute_reply":"2025-08-03T18:20:07.358213Z"}},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"## Look at some predictions from the validation set","metadata":{}},{"cell_type":"code","source":"import os\nimport cv2\nimport numpy as np\nimport tensorflow as tf\nimport tensorflow.keras.backend as K\nimport matplotlib.pyplot as plt\nimport matplotlib.cm as cm\nfrom tensorflow.keras.models import load_model\nimport math\n\n# 1. تعريف متغيرات وإعدادات النموذج\nIMAGE_HEIGHT = 299\nIMAGE_WIDTH = 299\ndiag_text = ['Normal', 'Mild', 'Moderate', 'Severe', 'Proliferative']\n\n# تحميل النموذج المُدرّب\ntry:\n    model = load_model('/kaggle/working/my_model.h5')\n    print(\"Model loaded successfully!\")\nexcept Exception as e:\n    print(f\"Error loading model: {e}\")\n    exit()\n\n# 2. تعريف دوال معالجة الصورة\ndef crop_image_from_gray(img, tol=7):\n    if img.ndim == 2:\n        mask = img > tol\n        return img[np.ix_(mask.any(1), mask.any(0))]\n    elif img.ndim == 3:\n        gray_img = cv2.cvtColor(img, cv2.COLOR_RGB2GRAY)\n        mask = gray_img > tol\n        check_shape = img[:, :, 0][np.ix_(mask.any(1), mask.any(0))].shape[0]\n        if check_shape == 0:\n            return img\n        else:\n            img1 = img[:, :, 0][np.ix_(mask.any(1), mask.any(0))]\n            img2 = img[:, :, 1][np.ix_(mask.any(1), mask.any(0))]\n            img3 = img[:, :, 2][np.ix_(mask.any(1), mask.any(0))]\n            img = np.stack([img1, img2, img3], axis=-1)\n        return img\n\ndef preprocess_image(image_path, sigmaX=10):\n    image = cv2.imread(image_path)\n    if image is None:\n        return None\n    image = cv2.cvtColor(image, cv2.COLOR_BGR2RGB)\n    image = crop_image_from_gray(image)\n    image = cv2.resize(image, (IMAGE_HEIGHT, IMAGE_WIDTH))\n    image = cv2.addWeighted(image, 4, cv2.GaussianBlur(image, (0, 0), sigmaX), -4, 128)\n    return image\n\n# 3. دالة توليد الخريطة الحرارية (Grad-CAM)\ndef make_gradcam_heatmap(img_array, model, last_conv_layer_name, pred_index=None):\n    grad_function = K.function([model.inputs], [model.get_layer(last_conv_layer_name).output, model.output])\n    last_conv_layer_output_value, preds = grad_function([img_array])\n    if pred_index is None:\n        pred_index = np.argmax(preds[0])\n    last_conv_layer_output_tensor = model.get_layer(last_conv_layer_name).output\n    output_tensor = model.output[:, pred_index]\n    grads = K.gradients(output_tensor, last_conv_layer_output_tensor)[0]\n    pooled_grads = K.mean(grads, axis=(0, 1, 2))\n    get_grads_and_output = K.function([model.inputs], [pooled_grads, last_conv_layer_output_tensor[0]])\n    pooled_grads_value, last_conv_layer_output_value = get_grads_and_output([img_array])\n    for i in range(len(pooled_grads_value)):\n        last_conv_layer_output_value[:, :, i] *= pooled_grads_value[i]\n    heatmap = np.mean(last_conv_layer_output_value, axis=-1)\n    heatmap = np.maximum(heatmap, 0) / np.max(heatmap)\n    return heatmap\n\n# 4. دالة عرض شبكة من الخرائط الحرارية\ndef display_gradcam_grid(image_paths, true_labels, predicted_labels, model, last_conv_layer_name, num_rows, num_cols):\n    if not image_paths:\n        print(\"No successful predictions to display.\")\n        return\n\n    fig = plt.figure(figsize=(num_cols * 5, num_rows * 4))\n    \n    for i in range(num_rows * num_cols):\n        if i >= len(image_paths):\n            break\n            \n        img_path = image_paths[i]\n        true_label = true_labels[i]\n        predicted_label = predicted_labels[i]\n        \n        img_array = preprocess_image(img_path)\n        \n        if img_array is not None:\n            img_tensor = np.expand_dims(img_array, axis=0)\n            img_tensor = tf.cast(img_tensor, dtype=tf.float32) / 255.0\n\n            heatmap = make_gradcam_heatmap(img_tensor, model, last_conv_layer_name, pred_index=predicted_label)\n            \n            original_img = cv2.imread(img_path)\n            original_img = cv2.resize(original_img, (IMAGE_WIDTH, IMAGE_HEIGHT))\n            original_img = cv2.cvtColor(original_img, cv2.COLOR_BGR2RGB)\n            \n            heatmap = np.uint8(255 * heatmap)\n            jet = cm.get_cmap(\"jet\")\n            jet_colors = jet(np.arange(256))[:, :3]\n            jet_heatmap = jet_colors[heatmap]\n            jet_heatmap = tf.keras.preprocessing.image.array_to_img(jet_heatmap)\n            jet_heatmap = jet_heatmap.resize((original_img.shape[1], original_img.shape[0]))\n            jet_heatmap = tf.keras.preprocessing.image.img_to_array(jet_heatmap)\n            \n            superimposed_img = jet_heatmap * 0.4 + original_img\n            superimposed_img = tf.keras.preprocessing.image.array_to_img(superimposed_img)\n            \n            ax = fig.add_subplot(num_rows, num_cols, i + 1)\n            ax.imshow(superimposed_img)\n            ax.axis('off')\n            \n            color = 'blue'\n            \n            title = f\"Predicted: {diag_text[predicted_label]}\\nTrue: {diag_text[true_label]}\"\n            ax.set_title(title, color=color, fontsize=12)\n\n    plt.tight_layout()\n    plt.show()\n\n# 5. الجزء الرئيسي لتشغيل الكود\nif __name__ == '__main__':\n    last_conv_layer_name = \"block14_sepconv2_bn\"\n    image_dir = \"/kaggle/working/test_images_preprocessed/\"\n\n    if not os.path.isdir(image_dir):\n        print(f\"Error: Directory does not exist at {image_dir}\")\n        exit()\n    \n    all_files = [f for f in os.listdir(image_dir) if f.endswith('.png')]\n    # اختر عددًا كافيًا من الصور لزيادة فرصة إيجاد 10 نتائج صحيحة\n    selected_files = all_files[:50] \n\n    # ------------------ يجب عليك استبدال هذا الجزء ------------------\n    # هنا يجب أن يتم تحميل بياناتك الحقيقية\n    # مثال: true_labels = your_dataframe['label'].values\n    true_labels = np.random.randint(0, 5, size=len(selected_files))\n    \n    # الحصول على التوقعات الحقيقية من النموذج\n    # يجب عليك تجهيز الصور في دفعة واحدة ثم تشغيل model.predict\n    # مثال: predictions = model.predict(preprocessed_images)\n    #        predicted_labels = np.argmax(predictions, axis=-1)\n    predicted_labels = np.random.randint(0, 5, size=len(selected_files))\n    # --------------------------------------------------------------\n\n    image_paths_full = [os.path.join(image_dir, f) for f in selected_files]\n    \n    successful_image_paths = []\n    successful_true_labels = []\n    successful_predicted_labels = []\n\n    for i in range(len(predicted_labels)):\n        if predicted_labels[i] == true_labels[i]:\n            successful_image_paths.append(image_paths_full[i])\n            successful_true_labels.append(true_labels[i])\n            successful_predicted_labels.append(predicted_labels[i])\n            \n        if len(successful_image_paths) >= 10:\n            break\n            \n    print(f\"Number of successful predictions to display: {len(successful_image_paths)}\")\n    \n    if not successful_image_paths:\n        print(\"No successful predictions found to display. Please check your data and model performance.\")\n    else:\n        num_cols = 5\n        num_rows = 2\n\n        display_gradcam_grid(successful_image_paths, successful_true_labels, successful_predicted_labels, model, last_conv_layer_name, num_rows, num_cols)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-08-03T20:13:03.374624Z","iopub.execute_input":"2025-08-03T20:13:03.374904Z","iopub.status.idle":"2025-08-03T20:16:15.130957Z","shell.execute_reply.started":"2025-08-03T20:13:03.374863Z","shell.execute_reply":"2025-08-03T20:16:15.130084Z"}},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"## Make some predictions ","metadata":{}},{"cell_type":"markdown","source":"### Preprocess the test images","metadata":{}},{"cell_type":"code","source":"x_train = None\nx_val = None\nprint(\"Preprocessing test images...\")\n!mkdir 'test_images_preprocessed/'\nfor i, image_id in enumerate(tqdm(test_df['id_code'])):\n    image = preprocess_image(f'../input/aptos2019-blindness-detection/test_images/{image_id}')    \n    cv2.imwrite(f'./test_images_preprocessed/{image_id}', image)\n    ","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-08-03T18:20:08.369255Z","iopub.execute_input":"2025-08-03T18:20:08.369574Z","iopub.status.idle":"2025-08-03T18:22:41.945756Z","shell.execute_reply.started":"2025-08-03T18:20:08.369524Z","shell.execute_reply":"2025-08-03T18:22:41.944703Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"test_datagen = ImageDataGenerator()\ntest_generator = test_datagen.flow_from_dataframe(\n    dataframe = test_df,\n    directory = \"./test_images_preprocessed/\",\n    x_col = \"id_code\",\n    target_size = (IMAGE_HEIGHT, IMAGE_WIDTH),\n    batch_size = 1,\n    shuffle = False,\n    class_mode = None)\n\ny_test = model.predict_generator(test_generator) > 0.5\ny_test = y_test.astype(int).sum(axis = 1) - 1","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-08-03T18:22:41.947699Z","iopub.execute_input":"2025-08-03T18:22:41.947967Z","iopub.status.idle":"2025-08-03T18:23:09.42808Z","shell.execute_reply.started":"2025-08-03T18:22:41.947926Z","shell.execute_reply":"2025-08-03T18:23:09.427435Z"}},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"### Check out the class distribution in the predicitons compared to the traing data","metadata":{}},{"cell_type":"code","source":"unique, counts = np.unique(y_test, return_counts = True)\nplt.bar(unique, counts)\n\nunique, counts = np.unique(validation_truth, return_counts = True)\nplt.bar(unique, counts)\n\nplt.title('Class Frequency Training and Predictions')\nplt.xlabel('Class')\nplt.ylabel('Frequency')\nplt.show()","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-08-03T18:23:09.429175Z","iopub.execute_input":"2025-08-03T18:23:09.429387Z","iopub.status.idle":"2025-08-03T18:23:09.676359Z","shell.execute_reply.started":"2025-08-03T18:23:09.429349Z","shell.execute_reply":"2025-08-03T18:23:09.675276Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"model.save('my_model.h5')\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-08-03T19:31:01.444967Z","iopub.execute_input":"2025-08-03T19:31:01.445305Z","iopub.status.idle":"2025-08-03T19:32:26.863753Z","shell.execute_reply.started":"2025-08-03T19:31:01.445242Z","shell.execute_reply":"2025-08-03T19:32:26.863115Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"import tensorflow as tf\ntf.compat.v1.disable_eager_execution()\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-08-03T18:56:32.229902Z","iopub.execute_input":"2025-08-03T18:56:32.230231Z","iopub.status.idle":"2025-08-03T18:56:32.233925Z","shell.execute_reply.started":"2025-08-03T18:56:32.230171Z","shell.execute_reply":"2025-08-03T18:56:32.233157Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"import os\nimport cv2\nimport numpy as np\nimport tensorflow as tf\nimport tensorflow.keras.backend as K\nimport matplotlib.pyplot as plt\nimport matplotlib.cm as cm\nfrom tensorflow.keras.models import load_model\n\n# 1. Define variables and model settings\n# Make sure these match the settings used during your model's training\nIMAGE_HEIGHT = 299\nIMAGE_WIDTH = 299\n\n# Load your trained model from the provided path\ntry:\n    model = load_model('/kaggle/working/my_model.h5')\n    print(\"Model loaded successfully!\")\nexcept Exception as e:\n    print(f\"Error loading model: {e}\")\n    # Exit if the model cannot be loaded\n    exit()\n\n# 2. Define image preprocessing functions\ndef crop_image_from_gray(img, tol=7):\n    if img.ndim == 2:\n        mask = img > tol\n        return img[np.ix_(mask.any(1), mask.any(0))]\n    elif img.ndim == 3:\n        gray_img = cv2.cvtColor(img, cv2.COLOR_RGB2GRAY)\n        mask = gray_img > tol\n        check_shape = img[:, :, 0][np.ix_(mask.any(1), mask.any(0))].shape[0]\n        if check_shape == 0:\n            return img\n        else:\n            img1 = img[:, :, 0][np.ix_(mask.any(1), mask.any(0))]\n            img2 = img[:, :, 1][np.ix_(mask.any(1), mask.any(0))]\n            img3 = img[:, :, 2][np.ix_(mask.any(1), mask.any(0))]\n            img = np.stack([img1, img2, img3], axis=-1)\n        return img\n\ndef preprocess_image(image_path, sigmaX=10):\n    image = cv2.imread(image_path)\n    if image is None:\n        print(f\"Error: cv2.imread returned None for path: {image_path}\")\n        return None\n    image = cv2.cvtColor(image, cv2.COLOR_BGR2RGB)\n    image = crop_image_from_gray(image)\n    image = cv2.resize(image, (IMAGE_HEIGHT, IMAGE_WIDTH))\n    image = cv2.addWeighted(image, 4, cv2.GaussianBlur(image, (0, 0), sigmaX), -4, 128)\n    return image\n\n# 3. Define the Grad-CAM heatmap generation function\n# دالة توليد خريطة Grad-CAM المعدلة والمحسّنة\ndef make_gradcam_heatmap(img_array, model, last_conv_layer_name, pred_index=None):\n    # قم بإنشاء دالة Keras لربط المدخلات والمخرجات\n    # سنحصل على التنبؤات ومخرجات طبقة التلافيف الأخيرة في نفس الوقت\n    grad_function = K.function([model.inputs], [model.get_layer(last_conv_layer_name).output, model.output])\n    \n    # الحصول على القيم العددية\n    last_conv_layer_output_value, preds = grad_function([img_array])\n    \n    if pred_index is None:\n        pred_index = np.argmax(preds[0])\n    \n    # الحصول على مخرجات طبقة التلافيف الأخيرة\n    last_conv_layer_output_tensor = model.get_layer(last_conv_layer_name).output\n    \n    # الحصول على ناتج التنبؤ الخاص بالصنف الذي تم اختياره\n    output_tensor = model.output[:, pred_index]\n\n    # حساب التدرجات (gradients) باستخدام tf.gradients\n    grads = K.gradients(output_tensor, last_conv_layer_output_tensor)[0]\n\n    # حساب متوسط التدرجات لكل قناة\n    pooled_grads = K.mean(grads, axis=(0, 1, 2))\n    \n    # قم بإنشاء دالة Keras أخرى للحصول على القيم العددية للتدرجات ومخرجات الطبقة\n    get_grads_and_output = K.function([model.inputs], [pooled_grads, last_conv_layer_output_tensor[0]])\n    \n    # الحصول على القيم العددية\n    pooled_grads_value, last_conv_layer_output_value = get_grads_and_output([img_array])\n\n    # ضرب كل قناة في متوسط تدرجها\n    for i in range(len(pooled_grads_value)):\n        last_conv_layer_output_value[:, :, i] *= pooled_grads_value[i]\n        \n    # حساب الخريطة الحرارية\n    heatmap = np.mean(last_conv_layer_output_value, axis=-1)\n\n    # Normalization (تطبيع) الخريطة الحرارية\n    heatmap = np.maximum(heatmap, 0) / np.max(heatmap)\n    return heatmap\n# 4. Define the heatmap visualization function\ndef display_gradcam(img_path, heatmap, alpha=0.4):\n    img = cv2.imread(img_path)\n    img = cv2.resize(img, (IMAGE_WIDTH, IMAGE_HEIGHT))\n    img = cv2.cvtColor(img, cv2.COLOR_BGR2RGB)\n    heatmap = np.uint8(255 * heatmap)\n    jet = cm.get_cmap(\"jet\")\n    jet_colors = jet(np.arange(256))[:, :3]\n    jet_heatmap = jet_colors[heatmap]\n    jet_heatmap = tf.keras.preprocessing.image.array_to_img(jet_heatmap)\n    jet_heatmap = jet_heatmap.resize((img.shape[1], img.shape[0]))\n    jet_heatmap = tf.keras.preprocessing.image.img_to_array(jet_heatmap)\n    superimposed_img = jet_heatmap * alpha + img\n    superimposed_img = tf.keras.preprocessing.image.array_to_img(superimposed_img)\n    plt.imshow(superimposed_img)\n    plt.axis('off')\n    plt.show()\n\n# 5. Main execution block\nif __name__ == '__main__':\n    # Make sure the image path is correct\n    image_path = \"/kaggle/working/test_images_preprocessed/00836aaacf06.png\"\n\n    # Name of the last convolutional layer (for Xception)\n    last_conv_layer_name = \"block14_sepconv2_bn\"\n\n    # Preprocess the image\n    img_array = preprocess_image(image_path)\n\n    if img_array is not None:\n        img_array = np.array(img_array)\n        img_array = np.expand_dims(img_array, axis=0)\n        img_array = tf.cast(img_array, dtype=tf.float32) / 255.0\n\n        # Generate the heatmap\n        heatmap = make_gradcam_heatmap(img_array, model, last_conv_layer_name)\n\n        # Display the result\n        display_gradcam(image_path, heatmap)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-08-03T19:34:26.96285Z","iopub.execute_input":"2025-08-03T19:34:26.963124Z","iopub.status.idle":"2025-08-03T19:34:50.696289Z","shell.execute_reply.started":"2025-08-03T19:34:26.963084Z","shell.execute_reply":"2025-08-03T19:34:50.695047Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"import os\n\nimage_path = \"/kaggle/working/test_images_preprocessed/00836aaacf06.png\"\n\nif os.path.exists(image_path):\n    print(f\"File exists at: {image_path}\")\n    # هنا يمكنك استدعاء دالة المعالجة\n    # img_array = preprocess_image(image_path)\n    # ...\nelse:\n    print(f\"Error: File not found at: {image_path}\")","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-08-03T19:23:17.168937Z","iopub.execute_input":"2025-08-03T19:23:17.169274Z","iopub.status.idle":"2025-08-03T19:23:17.173833Z","shell.execute_reply.started":"2025-08-03T19:23:17.169211Z","shell.execute_reply":"2025-08-03T19:23:17.173112Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"import os\nimport cv2\nimport numpy as np\nimport tensorflow as tf\nimport tensorflow.keras.backend as K\nimport matplotlib.pyplot as plt\nimport matplotlib.cm as cm\n\n# 1. تعريف متغيرات وإعدادات النموذج\n# تأكد من أن هذه المتغيرات تتطابق مع المتغيرات المستخدمة في تدريب نموذجك\nIMAGE_HEIGHT = 299\nIMAGE_WIDTH = 299\n\n# قم بتحميل النموذج المدرب مسبقًا\n# إذا لم يكن لديك نموذج مُحمّل، ستحتاج إلى إضافته هنا.\n# مثال:\n# from tensorflow.keras.models import load_model\n# model = load_model('path_to_your_model.h5')\n\n# 2. تعريف دوال معالجة الصورة\ndef crop_image_from_gray(img, tol = 7):\n    if img.ndim == 2:\n        mask = img > tol\n        return img[np.ix_(mask.any(1),mask.any(0))]\n    elif img.ndim == 3:\n        gray_img = cv2.cvtColor(img, cv2.COLOR_RGB2GRAY)\n        mask = gray_img > tol\n        check_shape = img[:,:,0][np.ix_(mask.any(1),mask.any(0))].shape[0]\n        if (check_shape == 0):\n            return img\n        else:\n            img1 = img[:,:,0][np.ix_(mask.any(1),mask.any(0))]\n            img2 = img[:,:,1][np.ix_(mask.any(1),mask.any(0))]\n            img3 = img[:,:,2][np.ix_(mask.any(1),mask.any(0))]\n            img = np.stack([img1,img2,img3],axis = -1)\n        return img\n\ndef preprocess_image(image_path, sigmaX = 10):\n    image = cv2.imread(image_path)\n    if image is None:\n        print(f\"Error: cv2.imread returned None for path: {image_path}\")\n        return None\n    image = cv2.cvtColor(image, cv2.COLOR_BGR2RGB)\n    image = crop_image_from_gray(image)\n    image = cv2.resize(image, (IMAGE_HEIGHT, IMAGE_WIDTH))\n    image = cv2.addWeighted(image, 4, cv2.GaussianBlur(image, (0,0), sigmaX), -4, 128)\n    return image\n\n# 3. تعريف دالة توليد الخريطة الحرارية (Grad-CAM)\ndef make_gradcam_heatmap(img_array, model, last_conv_layer_name, pred_index=None):\n    grad_model = tf.keras.models.Model([model.inputs], [model.get_layer(last_conv_layer_name).output, model.output])\n    preds = grad_model.predict(img_array)\n    if pred_index is None:\n        pred_index = np.argmax(preds[0])\n    last_conv_layer_output = grad_model.get_layer(last_conv_layer_name).output\n    output_tensor = grad_model.output[:, pred_index]\n    grads = K.gradients(output_tensor, last_conv_layer_output)[0]\n    pooled_grads = K.mean(grads, axis=(0, 1, 2))\n    iterate = K.function([model.inputs], [pooled_grads, last_conv_layer_output[0]])\n    pooled_grads_value, last_conv_layer_output_value = iterate([img_array])\n    for i in range(len(pooled_grads_value)):\n        last_conv_layer_output_value[:, :, i] *= pooled_grads_value[i]\n    heatmap = np.mean(last_conv_layer_output_value, axis=-1)\n    heatmap = np.maximum(heatmap, 0) / np.max(heatmap)\n    return heatmap\n\n# 4. تعريف دالة عرض الخريطة الحرارية\ndef display_gradcam(img_path, heatmap, alpha=0.4):\n    img = cv2.imread(img_path)\n    img = cv2.resize(img, (IMAGE_WIDTH, IMAGE_HEIGHT))\n    img = cv2.cvtColor(img, cv2.COLOR_BGR2RGB)\n    heatmap = np.uint8(255 * heatmap)\n    jet = cm.get_cmap(\"jet\")\n    jet_colors = jet(np.arange(256))[:, :3]\n    jet_heatmap = jet_colors[heatmap]\n    jet_heatmap = tf.keras.preprocessing.image.array_to_img(jet_heatmap)\n    jet_heatmap = jet_heatmap.resize((img.shape[1], img.shape[0]))\n    jet_heatmap = tf.keras.preprocessing.image.img_to_array(jet_heatmap)\n    superimposed_img = jet_heatmap * alpha + img\n    superimposed_img = tf.keras.preprocessing.image.array_to_img(superimposed_img)\n    plt.imshow(superimposed_img)\n    plt.axis('off')\n    plt.show()\n\n# 5. الجزء الرئيسي لتشغيل الكود\nif __name__ == '__main__':\n    # تأكد من أن مسار الصورة صحيح\n    image_path = \"/kaggle/working/test_images_preprocessed/00836aaacf06.png\"\n\n    # اسم طبقة التلافيف الأخيرة (لنموذج Xception)\n    last_conv_layer_name = \"block14_sepconv2_bn\"\n\n    # قم بمعالجة الصورة\n    img_array = preprocess_image(image_path)\n\n    if img_array is not None:\n        img_array = np.array(img_array)\n        img_array = np.expand_dims(img_array, axis=0)\n        img_array = tf.cast(img_array, dtype=tf.float32) / 255.0\n\n        # توليد الخريطة الحرارية\n        try:\n            heatmap = make_gradcam_heatmap(img_array, model, last_conv_layer_name)\n            # عرض النتيجة\n            display_gradcam(image_path, heatmap)\n        except NameError:\n            print(\"Error: The 'model' variable is not defined. Please load your trained model first.\")","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-08-03T19:30:00.965364Z","iopub.execute_input":"2025-08-03T19:30:00.965638Z","iopub.status.idle":"2025-08-03T19:30:01.04165Z","shell.execute_reply.started":"2025-08-03T19:30:00.965598Z","shell.execute_reply":"2025-08-03T19:30:01.040509Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"import tensorflow as tf\nimport numpy as np\nimport cv2\nimport matplotlib.pyplot as plt\nimport os\nfrom tensorflow.keras.models import Sequential\nfrom tensorflow.keras.layers import GlobalAveragePooling2D, Dropout, Dense\nfrom tensorflow.keras.applications import Xception\n\ndef create_xception_model(input_shape, n_out):\n    base_model = Xception(weights=None,\n                         include_top=False,\n                         input_shape=input_shape)\n    base_model.load_weights('../input/keras-pretrained-models/xception_weights_tf_dim_ordering_tf_kernels_notop.h5')\n\n    model = Sequential()\n    model.add(base_model)\n    model.add(GlobalAveragePooling2D())\n    model.add(Dropout(0.5))\n    model.add(Dense(2048, activation='relu'))\n    model.add(Dropout(0.5))\n    model.add(Dense(n_out, activation='sigmoid'))\n    return model\n\nIMAGE_SIZE = (299, 299)\nNUM_CLASSES = 5\nWEIGHTS_PATH = '/kaggle/working/blindness_detector_best.h5'\nIMAGES_DIR = '/kaggle/working/test_images_preprocessed'\n\nmodel = create_xception_model(input_shape=(*IMAGE_SIZE, 3), n_out=NUM_CLASSES)\nmodel.load_weights(WEIGHTS_PATH)\nprint(\"Model loaded.\")\n\ndef make_gradcam_heatmap(img_array, model, last_conv_layer_name):\n    base_model = model.layers[0]\n    last_conv_layer = base_model.get_layer(last_conv_layer_name)\n\n    grad_model = tf.keras.models.Model(\n        inputs=model.input,\n        outputs=[last_conv_layer.output, model.output]\n    )\n\n    with tf.GradientTape() as tape:\n        conv_outputs, predictions = grad_model(img_array)\n        class_idx = tf.argmax(predictions[0])\n        loss = predictions[:, class_idx]\n\n    grads = tape.gradient(loss, conv_outputs)\n    pooled_grads = tf.reduce_mean(grads, axis=(0, 1, 2))\n\n    conv_outputs = conv_outputs[0]\n    heatmap = conv_outputs @ pooled_grads[..., tf.newaxis]\n    heatmap = tf.squeeze(heatmap)\n\n    heatmap = tf.maximum(heatmap, 0) / (tf.reduce_max(heatmap) + 1e-10)\n    return heatmap.numpy()\n\ndef display_gradcam(image_path, model, last_conv_layer_name):\n    img = cv2.imread(image_path)\n    img_rgb = cv2.cvtColor(img, cv2.COLOR_BGR2RGB)\n    img_resized = cv2.resize(img_rgb, IMAGE_SIZE)\n    img_array = np.expand_dims(img_resized, axis=0)\n    img_array = tf.keras.applications.xception.preprocess_input(img_array.astype(np.float32))\n\n    heatmap = make_gradcam_heatmap(img_array, model, last_conv_layer_name)\n\n    heatmap = cv2.resize(heatmap, (img.shape[1], img.shape[0]))\n    heatmap = np.uint8(255 * heatmap)\n    heatmap_color = cv2.applyColorMap(heatmap, cv2.COLORMAP_JET)\n\n    superimposed_img = cv2.addWeighted(img, 0.6, heatmap_color, 0.4, 0)\n\n    plt.figure(figsize=(10,4))\n    plt.subplot(1,3,1)\n    plt.title('Original Image')\n    plt.axis('off')\n    plt.imshow(img_rgb)\n\n    plt.subplot(1,3,2)\n    plt.title('Grad-CAM Heatmap')\n    plt.axis('off')\n    plt.imshow(heatmap, cmap='jet')\n\n    plt.subplot(1,3,3)\n    plt.title('Overlay')\n    plt.axis('off')\n    plt.imshow(cv2.cvtColor(superimposed_img, cv2.COLOR_BGR2RGB))\n    plt.show()\n\nlast_conv_layer_name = 'block14_sepconv2_act'\nimage_files = [f for f in os.listdir(IMAGES_DIR) if f.lower().endswith(('.png', '.jpg', '.jpeg'))][:5]\n\nfor img_file in image_files:\n    print(f\"Processing {img_file}\")\n    display_gradcam(os.path.join(IMAGES_DIR, img_file), model, last_conv_layer_name)\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-08-03T19:09:11.321966Z","iopub.execute_input":"2025-08-03T19:09:11.322258Z","iopub.status.idle":"2025-08-03T19:09:33.926432Z","shell.execute_reply.started":"2025-08-03T19:09:11.322217Z","shell.execute_reply":"2025-08-03T19:09:33.925191Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"print(model.input)\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-08-03T19:00:40.837162Z","iopub.execute_input":"2025-08-03T19:00:40.837483Z","iopub.status.idle":"2025-08-03T19:00:40.841694Z","shell.execute_reply.started":"2025-08-03T19:00:40.837425Z","shell.execute_reply":"2025-08-03T19:00:40.840924Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"base_model = model.layers[0]\nfor i, layer in enumerate(base_model.layers):\n    print(i, layer.name)\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-08-03T18:58:33.643826Z","iopub.execute_input":"2025-08-03T18:58:33.644097Z","iopub.status.idle":"2025-08-03T18:58:33.658272Z","shell.execute_reply.started":"2025-08-03T18:58:33.644056Z","shell.execute_reply":"2025-08-03T18:58:33.65737Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"import tensorflow as tf\nfrom tensorflow.keras.models import Model\nimport numpy as np\nimport cv2\nimport matplotlib.pyplot as plt\nimport os\nfrom tensorflow.keras.preprocessing import image\n\n# إعداد المسارات\nimg_dir = \"/kaggle/input/aptos2019-blindness-detection/train_images\"\nxception_layer = model.layers[0]  # طبقة Xception داخل Sequential\nlast_conv_layer_name = \"block14_sepconv2_act\"\n\n# دالة تجهيز الصورة\ndef get_img_array(img_path, size=(299,299)):\n    img = image.load_img(img_path, target_size=size)\n    array = image.img_to_array(img)\n    array = np.expand_dims(array, axis=0)\n    return tf.keras.applications.xception.preprocess_input(array)\n\n# دالة إنشاء خريطة Grad-CAM باستخدام نموذج Xception فقط\ndef make_gradcam_heatmap(img_array, xception_model, last_conv_layer_name):\n    grad_model = Model(\n        inputs=xception_model.input,\n        outputs=[xception_model.get_layer(last_conv_layer_name).output,\n                 xception_model.output]\n    )\n\n    with tf.GradientTape() as tape:\n        conv_outputs, predictions = grad_model(img_array)\n        pred_index = tf.argmax(predictions[0])\n        class_channel = tf.gather(predictions, pred_index, axis=1)  # تم تعديل هذا السطر\n\n    grads = tape.gradient(class_channel, conv_outputs)\n    pooled_grads = tf.reduce_mean(grads, axis=(0, 1, 2))\n\n    conv_outputs = conv_outputs[0]\n    heatmap = conv_outputs @ pooled_grads[..., tf.newaxis]\n    heatmap = tf.squeeze(heatmap)\n\n    heatmap = tf.maximum(heatmap, 0) / tf.reduce_max(heatmap + 1e-8)\n    return heatmap.numpy()\n\n\n# عرض الصورة مع الخريطة الحرارية\ndef display_gradcam(img_path, model, xception_model, last_conv_layer_name):\n    img_array = get_img_array(img_path)\n    heatmap = make_gradcam_heatmap(img_array, xception_model, last_conv_layer_name)\n\n    img = cv2.imread(img_path)\n    img = cv2.resize(img, (299, 299))\n\n    heatmap = cv2.resize(heatmap, (img.shape[1], img.shape[0]))\n    heatmap = np.uint8(255 * heatmap)\n    heatmap_color = cv2.applyColorMap(heatmap, cv2.COLORMAP_JET)\n\n    superimposed_img = cv2.addWeighted(img, 0.6, heatmap_color, 0.4, 0)\n\n    plt.figure(figsize=(6,6))\n    plt.imshow(cv2.cvtColor(superimposed_img, cv2.COLOR_BGR2RGB))\n    plt.axis('off')\n    plt.title(\"Grad-CAM\")\n    plt.show()\n\n# عرض أول 5 صور\nimage_files = [f for f in os.listdir(img_dir) if f.endswith(\".png\") or f.endswith(\".jpg\")][:5]\n\nfor img_name in image_files:\n    print(f\"🔍 Image: {img_name}\")\n    display_gradcam(os.path.join(img_dir, img_name), model, xception_layer, last_conv_layer_name)\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-08-03T18:44:24.947079Z","iopub.execute_input":"2025-08-03T18:44:24.947435Z","iopub.status.idle":"2025-08-03T18:44:26.550415Z","shell.execute_reply.started":"2025-08-03T18:44:24.947381Z","shell.execute_reply":"2025-08-03T18:44:26.549019Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"import numpy as np\nimport tensorflow as tf\nimport matplotlib.pyplot as plt\nimport cv2\nimport os\nfrom tensorflow.keras.preprocessing import image\nfrom tensorflow.keras.models import Model\n\n# إعداد المسار\nimg_dir = \"/kaggle/input/aptos2019-blindness-detection/train_images\"\n\n# تجهيز الصورة\ndef get_img_array(img_path, size=(299, 299)):\n    img = image.load_img(img_path, target_size=size)\n    array = image.img_to_array(img)\n    array = np.expand_dims(array, axis=0)\n    return tf.keras.applications.xception.preprocess_input(array)\n\n# خريطة Grad-CAM\ndef make_gradcam_heatmap(img_array, model):\n    # الوصول إلى نموذج Xception داخل النموذج التسلسلي\n    xception_model = model.get_layer(\"xception\")\n    last_conv_layer = xception_model.get_layer(\"block14_sepconv2_act\")\n\n    # نموذج تدريبي يعيد إخراج الطبقة الأخيرة المجمعة والنتيجة النهائية\n    grad_model = Model(\n        inputs=model.input,\n        outputs=[\n            last_conv_layer.output,\n            model.output\n        ]\n    )\n\n    with tf.GradientTape() as tape:\n        conv_outputs, predictions = grad_model(img_array)\n        pred_index = tf.argmax(predictions[0])\n        class_channel = predictions[:, pred_index]\n\n    grads = tape.gradient(class_channel, conv_outputs)\n    pooled_grads = tf.reduce_mean(grads, axis=(0, 1, 2))\n\n    conv_outputs = conv_outputs[0]\n    heatmap = conv_outputs @ pooled_grads[..., tf.newaxis]\n    heatmap = tf.squeeze(heatmap)\n\n    heatmap = tf.maximum(heatmap, 0) / tf.reduce_max(heatmap + 1e-8)\n    return heatmap.numpy()\n\n# عرض الصورة مع Grad-CAM\ndef display_gradcam(img_path, model):\n    img_array = get_img_array(img_path)\n    heatmap = make_gradcam_heatmap(img_array, model)\n\n    img = cv2.imread(img_path)\n    img = cv2.resize(img, (299, 299))\n\n    heatmap = cv2.resize(heatmap, (img.shape[1], img.shape[0]))\n    heatmap = np.uint8(255 * heatmap)\n    heatmap_color = cv2.applyColorMap(heatmap, cv2.COLORMAP_JET)\n\n    superimposed_img = cv2.addWeighted(img, 0.6, heatmap_color, 0.4, 0)\n\n    plt.figure(figsize=(6, 6))\n    plt.imshow(cv2.cvtColor(superimposed_img, cv2.COLOR_BGR2RGB))\n    plt.axis('off')\n    plt.title(\"Grad-CAM\")\n    plt.show()\n\n# عرض لأول 5 صور\nimage_files = [f for f in os.listdir(img_dir) if f.endswith(\".png\") or f.endswith(\".jpg\")][:5]\n\nfor img_name in image_files:\n    img_path = os.path.join(img_dir, img_name)\n    print(f\"🔍 Image: {img_name}\")\n    display_gradcam(img_path, model)\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-08-03T18:41:21.994242Z","iopub.execute_input":"2025-08-03T18:41:21.994581Z","iopub.status.idle":"2025-08-03T18:41:22.064726Z","shell.execute_reply.started":"2025-08-03T18:41:21.994524Z","shell.execute_reply":"2025-08-03T18:41:22.063383Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"","metadata":{"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"code","source":"validation_predictions_raw = model.predict(x_val)\nvalidation_predictions = validation_predictions_raw > 0.5\nvalidation_predictions = validation_predictions.astype(int).sum(axis=1) - 1\nvalidation_truth = y_val.sum(axis=1) - 1\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-08-03T18:23:09.678123Z","iopub.execute_input":"2025-08-03T18:23:09.678536Z","iopub.status.idle":"2025-08-03T18:23:10.010517Z","shell.execute_reply.started":"2025-08-03T18:23:09.678466Z","shell.execute_reply":"2025-08-03T18:23:10.009204Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"from sklearn.metrics import confusion_matrix\nimport seaborn as sns\nimport matplotlib.pyplot as plt\n\ncm = confusion_matrix(validation_truth, validation_predictions)\n\nplt.figure(figsize=(8,6))\nsns.heatmap(cm, annot=True, fmt='d', cmap=\"Blues\", xticklabels=diag_text, yticklabels=diag_text)\nplt.xlabel('Predicted Label')\nplt.ylabel('True Label')\nplt.title('Confusion Matrix (Raw Counts)')\nplt.show()\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-08-03T18:23:10.011539Z","iopub.status.idle":"2025-08-03T18:23:10.012216Z","shell.execute_reply":"2025-08-03T18:23:10.011754Z"}},"outputs":[],"execution_count":null}]}