{"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":[{"sourceId":14774,"databundleVersionId":875431,"sourceType":"competition"},{"sourceId":7251,"sourceType":"datasetVersion","datasetId":2798}],"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":"2025-07-17T16:15:56.775135Z","iopub.execute_input":"2025-07-17T16:15:56.775351Z","iopub.status.idle":"2025-07-17T16:15:58.141983Z","shell.execute_reply.started":"2025-07-17T16:15:56.775311Z","shell.execute_reply":"2025-07-17T16:15:58.141050Z"}},"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":"2025-07-17T16:15:58.143858Z","iopub.execute_input":"2025-07-17T16:15:58.144175Z","iopub.status.idle":"2025-07-17T16:15:58.172177Z","shell.execute_reply.started":"2025-07-17T16:15:58.144120Z","shell.execute_reply":"2025-07-17T16:15:58.171294Z"}},"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":"2025-07-17T16:15:58.173761Z","iopub.execute_input":"2025-07-17T16:15:58.174086Z","iopub.status.idle":"2025-07-17T16:16:05.823107Z","shell.execute_reply.started":"2025-07-17T16:15:58.174024Z","shell.execute_reply":"2025-07-17T16:16:05.821712Z"}},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"### Graph out the class frequency","metadata":{}},{"cell_type":"code","source":"unique, counts = np.unique(train_df['diagnosis'], return_counts=True)\nplt.bar(unique, counts)\nplt.title('Class Frequency')\nplt.xlabel('Class')\nplt.ylabel('Frequency')\nplt.show()","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-07-17T16:16:05.824915Z","iopub.execute_input":"2025-07-17T16:16:05.825156Z","iopub.status.idle":"2025-07-17T16:16:06.061061Z","shell.execute_reply.started":"2025-07-17T16:16:05.825117Z","shell.execute_reply":"2025-07-17T16:16:06.059787Z"}},"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":"2025-07-17T16:16:06.066652Z","iopub.execute_input":"2025-07-17T16:16:06.067149Z","iopub.status.idle":"2025-07-17T16:16:06.422387Z","shell.execute_reply.started":"2025-07-17T16:16:06.067076Z","shell.execute_reply":"2025-07-17T16:16:06.421526Z"}},"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":"2025-07-17T16:16:06.426469Z","iopub.execute_input":"2025-07-17T16:16:06.426816Z","iopub.status.idle":"2025-07-17T16:16:06.449098Z","shell.execute_reply.started":"2025-07-17T16:16:06.426752Z","shell.execute_reply":"2025-07-17T16:16:06.447937Z"}},"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":"2025-07-17T16:16:06.450593Z","iopub.execute_input":"2025-07-17T16:16:06.450997Z","iopub.status.idle":"2025-07-17T16:16:16.578240Z","shell.execute_reply.started":"2025-07-17T16:16:06.450936Z","shell.execute_reply":"2025-07-17T16:16:16.577335Z"}},"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":"2025-07-17T16:16:16.579632Z","iopub.execute_input":"2025-07-17T16:16:16.579966Z","iopub.status.idle":"2025-07-17T16:16:16.585243Z","shell.execute_reply.started":"2025-07-17T16:16:16.579906Z","shell.execute_reply":"2025-07-17T16:16:16.584487Z"}},"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":"2025-07-17T16:16:16.586448Z","iopub.execute_input":"2025-07-17T16:16:16.586755Z","iopub.status.idle":"2025-07-17T16:26:00.216828Z","shell.execute_reply.started":"2025-07-17T16:16:16.586701Z","shell.execute_reply":"2025-07-17T16:26:00.215950Z"}},"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":"2025-07-17T16:26:00.218104Z","iopub.execute_input":"2025-07-17T16:26:00.218401Z","iopub.status.idle":"2025-07-17T16:26:03.867705Z","shell.execute_reply.started":"2025-07-17T16:26:00.218345Z","shell.execute_reply":"2025-07-17T16:26:03.866199Z"}},"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":"2025-07-17T16:26:03.868824Z","iopub.execute_input":"2025-07-17T16:26:03.869069Z","iopub.status.idle":"2025-07-17T16:26:03.877202Z","shell.execute_reply.started":"2025-07-17T16:26:03.869026Z","shell.execute_reply":"2025-07-17T16:26:03.876494Z"}},"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":"2025-07-17T16:26:03.878350Z","iopub.execute_input":"2025-07-17T16:26:03.878628Z","iopub.status.idle":"2025-07-17T16:26:04.857037Z","shell.execute_reply.started":"2025-07-17T16:26:03.878574Z","shell.execute_reply":"2025-07-17T16:26:04.856034Z"}},"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":"2025-07-17T16:26:04.858922Z","iopub.execute_input":"2025-07-17T16:26:04.859188Z","iopub.status.idle":"2025-07-17T16:26:07.462772Z","shell.execute_reply.started":"2025-07-17T16:26:04.859144Z","shell.execute_reply":"2025-07-17T16:26:07.462065Z"}},"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":"2025-07-17T16:26:07.464357Z","iopub.execute_input":"2025-07-17T16:26:07.464633Z","iopub.status.idle":"2025-07-17T16:28:03.903352Z","shell.execute_reply.started":"2025-07-17T16:26:07.464577Z","shell.execute_reply":"2025-07-17T16:28:03.893106Z"}},"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":"2025-07-17T16:28:03.912261Z","iopub.execute_input":"2025-07-17T16:28:03.916988Z","iopub.status.idle":"2025-07-17T16:47:45.143402Z","shell.execute_reply.started":"2025-07-17T16:28:03.916874Z","shell.execute_reply":"2025-07-17T16:47:45.142484Z"}},"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":"2025-07-17T16:47:45.145124Z","iopub.execute_input":"2025-07-17T16:47:45.145383Z","iopub.status.idle":"2025-07-17T16:47:45.630202Z","shell.execute_reply.started":"2025-07-17T16:47:45.145326Z","shell.execute_reply":"2025-07-17T16:47:45.629083Z"}},"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":"2025-07-17T16:47:45.632290Z","iopub.execute_input":"2025-07-17T16:47:45.633077Z","iopub.status.idle":"2025-07-17T16:47:51.100659Z","shell.execute_reply.started":"2025-07-17T16:47:45.633000Z","shell.execute_reply":"2025-07-17T16:47:51.099608Z"}},"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":"2025-07-17T16:47:51.102240Z","iopub.execute_input":"2025-07-17T16:47:51.102551Z","iopub.status.idle":"2025-07-17T16:47:51.485468Z","shell.execute_reply.started":"2025-07-17T16:47:51.102496Z","shell.execute_reply":"2025-07-17T16:47:51.483969Z"}},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"## Look at some predictions from the validation set","metadata":{}},{"cell_type":"code","source":"def plot_image(prediction_array, predicted_label, true_label, img):\n    plt.grid(False)\n    plt.xticks([])\n    plt.yticks([])\n    plt.imshow(img, cmap = plt.cm.binary)\n    if predicted_label == true_label:\n        color = 'blue'\n    else:\n        color = 'red'\n    plt.xlabel(\"{} {:2.0f}% ({})\".format(diag_text[predicted_label], 100 * np.max(prediction_array), diag_text[true_label]), color = color)\n\ndef plot_prediction(prediction_array, predicted_label, true_label):\n    plt.grid(False)\n    plt.xticks([])\n    plt.yticks([])\n    thisplot = plt.bar(range(5), prediction_array, color = \"#777777\")\n    plt.ylim([0, 1]) \n    thisplot[predicted_label].set_color('red')\n    thisplot[true_label].set_color('blue')\n  \n# Plot some validation images, their predicted label, and the true label\n# Color correct predictions in blue, incorrect predictions in red\nplt.figure(figsize=(24, 6))\nnum_cols = 4\nnum_rows = 4\nfor i in range(num_rows * num_cols):\n    plt.subplot(num_rows, 2 * num_cols, 2 * i + 1)\n    plot_image(validation_predictions_raw[i], validation_predictions[i], validation_truth[i], x_val[i])\n    plt.subplot(num_rows, 2 * num_cols, 2 * i + 2)\n    plot_prediction(validation_predictions_raw[i], validation_predictions[i], validation_truth[i])\nplt.show() ","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-07-17T16:47:51.487595Z","iopub.execute_input":"2025-07-17T16:47:51.488042Z","iopub.status.idle":"2025-07-17T16:47:52.679205Z","shell.execute_reply.started":"2025-07-17T16:47:51.487976Z","shell.execute_reply":"2025-07-17T16:47:52.678132Z"}},"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-07-17T16:47:52.680548Z","iopub.execute_input":"2025-07-17T16:47:52.681010Z","iopub.status.idle":"2025-07-17T16:50:09.948613Z","shell.execute_reply.started":"2025-07-17T16:47:52.680944Z","shell.execute_reply":"2025-07-17T16:50:09.947611Z"}},"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-07-17T16:50:09.950971Z","iopub.execute_input":"2025-07-17T16:50:09.951345Z","iopub.status.idle":"2025-07-17T16:50:39.469804Z","shell.execute_reply.started":"2025-07-17T16:50:09.951271Z","shell.execute_reply":"2025-07-17T16:50:39.468650Z"}},"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-07-17T16:50:39.471440Z","iopub.execute_input":"2025-07-17T16:50:39.471843Z","iopub.status.idle":"2025-07-17T16:50:39.739181Z","shell.execute_reply.started":"2025-07-17T16:50:39.471775Z","shell.execute_reply":"2025-07-17T16:50:39.735465Z"}},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"## COMPLETED","metadata":{}}]}