{"cells":[{"metadata":{},"cell_type":"markdown","source":"# Detect diabetic retinopathy[](http://)"},{"metadata":{"_uuid":"d629ff2d2480ee46fbb7e2d37f6b5fab8052498a","_cell_guid":"79c7e3d0-c299-4dcb-8224-4455121ee9b0","trusted":true},"cell_type":"code","source":"import numpy as np\nimport pandas as pd\nimport os\nimport glob\nimport matplotlib.pyplot as plt\nimport cv2\nfrom tqdm import tqdm_notebook as tqdm\n%matplotlib inline\n \npd.set_option('display.max_rows', 10)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"base_data_folder = \"/kaggle/input/aptos2019-blindness-detection\"\ntrain_data_folder = os.path.join(base_data_folder, \"train_images\")\n\nprint(os.listdir(base_data_folder))","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"## Load train images"},{"metadata":{"trusted":true},"cell_type":"code","source":"train_files_names = sorted(os.listdir(train_data_folder))\ntrain_files_names[:6]","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"sorted(glob.glob(train_data_folder + '/*.png'))[:6]","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"train_images = []\nfor file in tqdm(sorted(glob.glob(train_data_folder + '/*.png'))):\n    image_bgr = cv2.imread(file, cv2.IMREAD_COLOR)\n    image_rgb = cv2.cvtColor(image_bgr, cv2.COLOR_BGR2RGB)\n    image_rgb = cv2.resize(image_rgb, dsize=None, fx = 0.15, fy=0.15, interpolation = cv2.INTER_AREA)\n    train_images.append(image_rgb)","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"## Load train labels"},{"metadata":{"trusted":true},"cell_type":"code","source":"train_labels = pd.read_csv(base_data_folder+\"/train.csv\")\ntrain_labels.sort_values(by='id_code', inplace = True)\ntrain_labels","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"y_data = train_labels['diagnosis']\ny_data[:5]","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"y_data.hist()\nprint(y_data.value_counts())","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"fig = plt.figure(figsize=(14,8))\n\nfor idx, image_rgb in enumerate(train_images[:10]):\n    fig.add_subplot(2, 5, idx+1)\n    plt.imshow(image_rgb)\n    plt.title(\"Label:{0}\".format(train_labels['diagnosis'][idx]))\n    plt.xlabel(train_labels['id_code'][idx])\n    plt.tight_layout()","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"## Image preprocessing"},{"metadata":{"trusted":true},"cell_type":"code","source":"def crop_image_from_gray(img,tol=7):\n    gray_img = cv2.cvtColor(img, cv2.COLOR_RGB2GRAY)\n    mask = gray_img > tol\n    \n    img1=img[:,:,0][np.ix_(mask.any(axis=1),mask.any(axis=0))]\n    img2=img[:,:,1][np.ix_(mask.any(axis=1),mask.any(axis=0))]\n    img3=img[:,:,2][np.ix_(mask.any(axis=1),mask.any(axis=0))]\n    img = np.stack([img1,img2,img3], axis=-1)\n    \n    return img","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"def circle_crop(img):\n    img = crop_image_from_gray(img)\n    height, width, depth = img.shape\n    largest_side = np.max((height, width))\n    \n    img_reshaped = cv2.resize(img, dsize=(largest_side, largest_side))\n                \n    length = img_reshaped.shape[0]\n    x = int(length/2)\n    y = int(length/2)\n    r = np.amin((x,y))    \n    \n    background = np.zeros_like(img_reshaped, dtype=np.uint8)\n    circle_mask = cv2.circle(background, (x,y), int(r), (255, 255, 255), thickness=-1)\n    \n    image = cv2.bitwise_and(img_reshaped, circle_mask)\n    \n    return image","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"X_data = []\nfor image_rgb in tqdm(train_images):\n    circle_img = circle_crop(image_rgb)\n    image_resized = cv2.resize(circle_img, dsize=(224, 224))\n    X_data.append(image_resized)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"fig = plt.figure(figsize=(14,8))\n\nfor idx, image in enumerate(X_data[:10]):\n    fig.add_subplot(2, 5, idx+1)\n    plt.imshow(image)\n    plt.title(\"Label:{0}\".format(train_labels['diagnosis'][idx]))\n    plt.xlabel(train_labels['id_code'][idx])\n    plt.tight_layout()","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"X_data_prepocessed = []\nfor image_rgb in tqdm(X_data):\n    blured = cv2.GaussianBlur(image_rgb, (9,9) ,15)\n    image = cv2.addWeighted(image_rgb, 5, blured, -5, 128)\n    X_data_prepocessed.append(image)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"X_data_prepocessed = np.array(X_data_prepocessed)\nX_data_prepocessed.shape","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"del train_images","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"fig = plt.figure(figsize=(14,8))\n\nfor idx, image in enumerate(X_data_prepocessed[:10]):\n    fig.add_subplot(2, 5, idx+1)\n    plt.imshow(image)\n    plt.title(\"Label:{0}\".format(train_labels['diagnosis'][idx]))\n    plt.xlabel(train_labels['id_code'][idx])\n    plt.tight_layout()","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"del X_data","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"## Split train and validation set"},{"metadata":{"trusted":true},"cell_type":"code","source":"from sklearn.model_selection import train_test_split\nX_train, X_valid, y_train, y_valid = train_test_split(X_data_prepocessed, y_data, test_size=0.2,\n                                                      stratify = y_data, random_state = 123456)\n\nprint(X_train.shape, y_train.shape)\nprint(X_valid.shape, y_valid.shape)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"from tensorflow.keras.utils import to_categorical\n\ny_train_onehot = to_categorical(y_train, num_classes=5, dtype='bool')\ny_valid_onehot = to_categorical(y_valid, num_classes=5, dtype='bool')\n\nprint(y_train_onehot.shape)\nprint(y_valid_onehot.shape)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"plt.hist(y_train)\nplt.hist(y_valid)\nplt.title(\"Train and Validation set Distribution\")\nplt.legend(['Train', 'Validation'])\nplt.show()","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"## Construct CNN model"},{"metadata":{"trusted":true},"cell_type":"code","source":"from tensorflow.keras import layers, models\nmodel = models.Sequential()","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"model.add(layers.Conv2D(filters = 32, kernel_size = (3, 3), activation = 'relu', padding = 'valid', input_shape = (224, 224, 3), name = 'Conv1-1'))\nmodel.add(layers.Conv2D(filters = 32, kernel_size = (3, 3), activation = 'relu', padding = 'same', name = 'Conv1-2'))\nmodel.add(layers.MaxPool2D(pool_size = (2, 2), strides = (2, 2), name = 'pool1'))","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"model.add(layers.Conv2D(filters = 64, kernel_size = (3, 3), activation = 'relu',padding = 'valid', name = 'Conv2-1'))\nmodel.add(layers.Conv2D(filters = 64, kernel_size = (3, 3), activation = 'relu',padding = 'same', name = 'Conv2-2'))\nmodel.add(layers.MaxPool2D(pool_size = (2, 2), strides = (2, 2), name = 'pool2'))","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"model.add(layers.Conv2D(filters = 128, kernel_size = (3, 3), activation = 'relu',padding = 'valid', name = 'Conv3-1'))\nmodel.add(layers.Conv2D(filters = 128, kernel_size = (3, 3), activation = 'relu',padding = 'same', name = 'Conv3-2'))\nmodel.add(layers.Conv2D(filters = 128, kernel_size = (3, 3), activation = 'relu',padding = 'same', name = 'Conv3-3'))\nmodel.add(layers.MaxPool2D(pool_size = (2, 2), strides = (2, 2), name = 'pool3'))","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"model.add(layers.Conv2D(filters = 256, kernel_size = (3, 3), activation = 'relu',padding = 'valid', name = 'Conv4-1'))\nmodel.add(layers.Conv2D(filters = 256, kernel_size = (3, 3), activation = 'relu',padding = 'same', name = 'Conv4-2'))\nmodel.add(layers.Conv2D(filters = 256, kernel_size = (3, 3), activation = 'relu',padding = 'same', name = 'Conv4-3'))\nmodel.add(layers.MaxPool2D(pool_size = (2, 2), strides = (2, 2), name = 'pool4'))","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"model.add(layers.Conv2D(filters = 512, kernel_size = (3, 3), activation = 'relu',padding = 'valid', name = 'Conv5-1'))\nmodel.add(layers.Conv2D(filters = 512, kernel_size = (3, 3), activation = 'relu',padding = 'same', name = 'Conv5-2'))\nmodel.add(layers.Conv2D(filters = 512, kernel_size = (3, 3), activation = 'relu',padding = 'same', name = 'Conv5-3'))\nmodel.add(layers.Conv2D(filters = 512, kernel_size = (3, 3), activation = 'relu',padding = 'same', name = 'Conv5-4'))\nmodel.add(layers.MaxPool2D(pool_size = (2, 2), strides = (2, 2), name = 'pool5'))","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"model.add(layers.Flatten())\nmodel.add(layers.Dropout(0.2))","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"model.add(layers.Dense(256, name='Dense1'))\nmodel.add(layers.BatchNormalization())\nmodel.add(layers.LeakyReLU(0.1))","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"model.add(layers.Dense(256, name='Dense2'))\nmodel.add(layers.BatchNormalization())\nmodel.add(layers.LeakyReLU(0.1))","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"model.add(layers.Dense(64, name='Dense3'))\nmodel.add(layers.BatchNormalization())\nmodel.add(layers.LeakyReLU(0.1))","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"model.add(layers.Dense(5, activation = 'softmax', name='Final')) # output layer","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"model.summary()","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"## train model"},{"metadata":{"trusted":true},"cell_type":"code","source":"from tensorflow.keras import optimizers\n\nmodel.compile(optimizer = optimizers.Adam(0.0001), loss = 'categorical_crossentropy', metrics=['acc'])","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"import time\nfrom tensorflow.keras.callbacks import ModelCheckpoint\n\ncallback_list = [ModelCheckpoint(filepath='cnn_checkpoint.h5',\n                                 monitor = 'val_loss',\n                                 save_best_only = True)]","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"BATCH_SIZE = 256\nnum_epochs = 64\n\nhistory = model.fit(X_train, y_train_onehot,\n                    batch_size = BATCH_SIZE,\n                    epochs = num_epochs,\n                    validation_data = (X_valid, y_valid_onehot),\n                    callbacks = callback_list)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"epochs = np.arange(1, len(history.history['loss']) + 1)\n\nplt.plot(epochs, history.history['loss'], label = 'Training')\nplt.plot(epochs, history.history['val_loss'], label = 'Validation')\nplt.title('Loss History Plot')\nplt.xlabel('Epochs')\nplt.ylabel('Loss')\nplt.legend()\nplt.show()\n\nplt.plot(epochs, history.history['acc'], label = 'Training')\nplt.plot(epochs, history.history['val_acc'], label = 'Validation')\nplt.title('Accuracy History Plot')\nplt.xlabel('Epochs')\nplt.ylabel('Accuracy')\nplt.legend()\nplt.show()","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"## save the optimal model"},{"metadata":{"trusted":true},"cell_type":"code","source":"model.save('cnn_model.h5')","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"## reload our optimal model"},{"metadata":{"trusted":true},"cell_type":"code","source":"from tensorflow.keras.models import load_model\n\nrestored_model = load_model('cnn_model.h5')\nrestored_model.load_weights('cnn_checkpoint.h5')","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"## Evaluate Model Performance\n"},{"metadata":{"trusted":true},"cell_type":"code","source":"restored_model.evaluate(X_valid, y_valid_onehot)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"y_pred = np.argmax(restored_model.predict(X_valid), axis = 1)\n\nprint('Predict:', y_pred[:10])\nprint('Validation:', np.array(y_valid[:10]))","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"from sklearn.metrics import confusion_matrix\nfrom sklearn.metrics import cohen_kappa_score\n\ncm = confusion_matrix(y_true = y_valid,\n                      y_pred = y_pred)\n\nkappa_score = cohen_kappa_score(y1 = y_valid,\n                                y2 = y_pred,\n                                weights='quadratic')\n\nprint(\"Confusion Matrix\")\nprint(cm)\nprint()\nprint(\"Shape :\", cm.shape)\nprint(\"Accurcy: {0:.2f}%\".format(np.trace(cm) / np.sum(cm)*100))\nprint(\"Quadratic Weighted Kappa Score:\", np.round(kappa_score, 4))","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"from sklearn.metrics import classification_report\n\nprint(classification_report(y_valid, y_pred, digits=4, target_names = ['No DR', 'Mild', 'Moderate', 'Severe', 'Proliferative DR']))","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"## Load Test Images"},{"metadata":{"trusted":true},"cell_type":"code","source":"test_data_folder = os.path.join(base_data_folder, \"test_images\")\ntest_files_names = sorted(os.listdir(test_data_folder))\ntest_files_names[:5]","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"sorted(glob.glob(test_data_folder + '/*.png'))[:5]","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"test_images = []\nfor file in tqdm(sorted(glob.glob(test_data_folder + '/*.png'))):\n    image_bgr = cv2.imread(file, cv2.IMREAD_COLOR)\n    image_rgb = cv2.cvtColor(image_bgr, cv2.COLOR_BGR2RGB)\n    image_resized = cv2.resize(image_rgb, dsize=None, fx=0.3, fy=0.3, interpolation = cv2.INTER_AREA)\n    test_images.append(image_resized)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"X_test = []\nfor image_rgb in tqdm(test_images):\n    circle_img = circle_crop(image_rgb)\n    image_resized = cv2.resize(circle_img, dsize=(224, 224))\n    X_test.append(image_resized)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"X_test_prepocessed = []\nfor image_rgb in tqdm(X_test):\n    blured = cv2.GaussianBlur(image_rgb, (9,9) ,15)\n    image = cv2.addWeighted(image_rgb, 5, blured, -5, 128)\n    X_test_prepocessed.append(image)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"fig = plt.figure(figsize=(14,8))\n\nfor idx, image_rgb in enumerate(test_images[:10]):\n    fig.add_subplot(2, 5, idx+1)\n    plt.imshow(image_rgb)\n    plt.xlabel(test_files_names[idx])\n    plt.tight_layout()","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"fig = plt.figure(figsize=(14,8))\n\nfor idx, image in enumerate(X_test[:10]):\n    fig.add_subplot(2, 5, idx+1)\n    plt.imshow(image)\n    plt.xlabel(test_files_names[idx])\n    plt.tight_layout()","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"fig = plt.figure(figsize=(14,8))\n\nfor idx, image in enumerate(X_test_prepocessed[:10]):\n    fig.add_subplot(2, 5, idx+1)\n    plt.imshow(image)\n    plt.xlabel(test_files_names[idx])\n    plt.tight_layout()","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"X_test = np.array(X_test_prepocessed)\nX_test.shape","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"del test_images","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"## Predict Test images"},{"metadata":{"trusted":true},"cell_type":"code","source":"test_image_labels = pd.DataFrame(columns = ['id_code'])\n\nfor i in test_files_names:\n    splited = i.split('.')[0]\n    temp = pd.DataFrame({'id_code':[splited]})\n    test_image_labels = pd.concat([test_image_labels, temp], ignore_index=True)\n\ntest_image_labels","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"preds = np.argmax(model.predict(X_test), axis = 1)\n\nprint('Predicted:', preds[:10])","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"test_image_labels['diagnosis'] = pd.Series(preds)\ntest_image_labels","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"## show test predictions"},{"metadata":{"trusted":true},"cell_type":"code","source":"fig = plt.figure(figsize=(14,8))\n\nfor idx, image in enumerate(X_test[:20]):\n    fig.add_subplot(4, 5, idx+1)\n    plt.imshow(image)\n    plt.title('diagnosed:{0}'.format(test_image_labels['diagnosis'][idx]))\n    plt.xlabel(test_image_labels['id_code'][idx])\n    plt.tight_layout()","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"plt.hist(test_image_labels['diagnosis'])\nplt.title('Predicted class distribution')\nplt.show()","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"## save the result"},{"metadata":{"trusted":true},"cell_type":"code","source":"test_image_labels.to_csv('submission.csv', index=False)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"!ls -al","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"![](http://)![](http://)<a href=\"./submission.csv\"> Download submission.csv File </a>"},{"metadata":{},"cell_type":"markdown","source":"![](http://)![](http://)<a href=\"./cnn_model.h5\"> Download cnn_model.h5 File </a>[](http://)\n![](http://)![](http://)<a href=\"./cnn_checkpoint.h5\"> Download cnn_checkpoint.h5 File </a>[](http://)"},{"metadata":{"trusted":true},"cell_type":"code","source":"","execution_count":null,"outputs":[]}],"metadata":{"kernelspec":{"language":"python","display_name":"Python 3","name":"python3"},"language_info":{"pygments_lexer":"ipython3","nbconvert_exporter":"python","version":"3.6.4","file_extension":".py","codemirror_mode":{"name":"ipython","version":3},"name":"python","mimetype":"text/x-python"}},"nbformat":4,"nbformat_minor":1}