{"cells":[{"metadata":{"trusted":true},"cell_type":"code","source":"import os\nimport sys\n\nprint(os.listdir(\"../input/efficientnet/efficientnet-master/efficientnet-master/efficientnet\"))\nsys.path.append(os.path.abspath('../input/efficientnet/efficientnet-master/efficientnet-master/'))","execution_count":null,"outputs":[]},{"metadata":{"_uuid":"8f2839f25d086af736a60e9eeb907d3b93b6e0e5","_cell_guid":"b1076dfc-b9ad-4769-8c92-a6c4dae69d19","trusted":true},"cell_type":"code","source":"import numpy as np\nimport pandas as pd\nfrom PIL import Image\nimport cv2\nimport math\n\nimport matplotlib.pyplot as plt\n\nfrom keras.preprocessing.image import ImageDataGenerator\n\nfrom keras.layers import Conv2D, Dense, Dropout, BatchNormalization, Input, Flatten, MaxPooling2D, Activation, GlobalAveragePooling2D\nfrom keras.models import Sequential, Model\nfrom keras.utils import np_utils\nfrom keras.optimizers import Adam\nfrom keras.callbacks import EarlyStopping, ModelCheckpoint, Callback, LearningRateScheduler\n\nimport tensorflow as tf\n\nfrom sklearn.model_selection import train_test_split\nfrom sklearn.metrics import cohen_kappa_score\n\nfrom efficientnet import EfficientNetB5\n\nprint(os.listdir(\"../input\"))","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"## Explore Data"},{"metadata":{"_cell_guid":"79c7e3d0-c299-4dcb-8224-4455121ee9b0","_uuid":"d629ff2d2480ee46fbb7e2d37f6b5fab8052498a","trusted":true},"cell_type":"code","source":"train_df = pd.read_csv('../input/aptos2019-blindness-detection/train.csv')\ntrain_df_ex = pd.read_csv('../input/diabetic-retinopathy-resized/trainLabels.csv')","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"print(train_df.shape)\ntrain_df.head()","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"print(train_df_ex.shape)\ntrain_df_ex.head()","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"#check NaNs\nprint('Train')\nprint(train_df.isnull().sum())\nprint(\"=====\")\nprint('Train Extra')\nprint(train_df_ex.isnull().sum())","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"#Distribution of diagnosis\nprint(train_df['diagnosis'].value_counts())\ntrain_df['diagnosis'].value_counts().plot(kind='bar')\nplt.show()","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"#Distribution of diagnosis\nprint(train_df_ex['level'].value_counts())\ntrain_df_ex['level'].value_counts().plot(kind='bar')\nplt.show()","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"#show samples of fundus images\nsample_nos = [4]\n\nfor no in sample_nos:\n    sample_train_id = train_df['id_code'][no]\n    sample_train_diagnosis = train_df['diagnosis'][no]\n    result = \"Diagnosis=\"+str(sample_train_diagnosis)\n\n    sample_image = Image.open('../input/aptos2019-blindness-detection/train_images/'+sample_train_id+'.png')\n    img_list = np.asarray(sample_image)\n    print(img_list.shape)\n    plt.imshow(img_list)\n    plt.title(\"Diagnosis=\"+str(sample_train_diagnosis))\n    plt.show()\n","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"#show samples of fundus images\nsample_nos = [4]\n\nfor no in sample_nos:\n    sample_train_id = train_df_ex['image'][no]\n    sample_train_diagnosis = train_df_ex['level'][no]\n    result = \"Diagnosis=\"+str(sample_train_diagnosis)\n\n    sample_image = Image.open('../input/diabetic-retinopathy-resized/resized_train/resized_train/'+sample_train_id+'.jpeg')\n    img_list = np.asarray(sample_image)\n    print(img_list.shape)\n    plt.imshow(img_list)\n    plt.title(\"Diagnosis=\"+str(sample_train_diagnosis))\n    plt.show()","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"* There are bias in dataset. -> Try taking balance by data augmenting.\n* The shape of each image is different. -> Reshape each image to the same appropriate size."},{"metadata":{},"cell_type":"markdown","source":"### There are duplicated images with different labels\n"},{"metadata":{"trusted":true},"cell_type":"code","source":"dup_info = pd.read_csv('../input/aptos2019-duplicated-images-info/duplicated_info.csv')\ndup_info.head()","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"#add id_code info (extracting from path)\ndup_info['id_code'] = [s.split('/')[3].split('.')[0] for s in dup_info['path'].values]\ndup_info.head()","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"dup_info['diagnosis'].value_counts()","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"train_df_new = train_df.copy()\nfor code in dup_info['id_code']:\n    train_df_new = train_df_new[train_df_new['id_code'] != code]\nprint(train_df_new.shape)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"train_df_new['diagnosis'].value_counts()","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"### Retrieve some data from extra train dataset"},{"metadata":{"trusted":true},"cell_type":"code","source":"ex_0 = pd.DataFrame(train_df_ex[train_df_ex['level'] == 0].sample(frac=1, random_state=42)[:500])\nex_1 = pd.DataFrame(train_df_ex[train_df_ex['level'] == 1].sample(frac=1, random_state=42)[:600])\nex_2 = pd.DataFrame(train_df_ex[train_df_ex['level'] == 2].sample(frac=1, random_state=42)[:900])\nex_3 = pd.DataFrame(train_df_ex[train_df_ex['level'] == 3].sample(frac=1, random_state=42)[:300])\nex_4 = pd.DataFrame(train_df_ex[train_df_ex['level'] == 4].sample(frac=1, random_state=42)[:100])\n\nprint(ex_0.shape)\nprint(ex_1.shape)\nprint(ex_2.shape)\nprint(ex_3.shape)\nprint(ex_4.shape)\n\n\n","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"\nex_df = pd.concat([ex_0, ex_1, ex_2, ex_3, ex_4])\nprint(ex_df.shape)\n\ndel ex_0\ndel ex_1\ndel ex_2\ndel ex_3\ndel ex_4\n","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"### Image Decolorization & Cropping & preprocessing etc."},{"metadata":{"trusted":true},"cell_type":"code","source":"IMG_SIZE = 256\nNUM_CLASSES = 5\nINPUT_SHAPE = (IMG_SIZE, IMG_SIZE, 3)\n\nBATCH_SIZE = 24\nEPOCHS = 80\n\nWEIGHTS_PATH = '../input/efficientnet-keras-weights-b0b5/efficientnet-b5_imagenet_1000_notop.h5'","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"def crop_image1(img,tol=7):\n    # img is image data\n    # tol  is tolerance\n        \n    mask = img>tol\n    return img[np.ix_(mask.any(1),mask.any(0))]\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        \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    #         print(img1.shape,img2.shape,img3.shape)\n            img = np.stack([img1,img2,img3],axis=-1)\n        \n        return img\n\n","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"ex_df = ex_df.reset_index()\nex_df.head()","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"sample_no = 100\n\nsample_train_id = train_df['id_code'][sample_no]\nsample_train_diagnosis = train_df['diagnosis'][sample_no]\n\n#sample_train_id = ex_df['image'][sample_no]\n#sample_train_diagnosis = ex_df['level'][sample_no]\nresult = \"Diagnosis=\"+str(sample_train_diagnosis)\n\n\nsample_img = cv2.imread('../input/aptos2019-blindness-detection/train_images/'+sample_train_id+'.png')\n#sample_img = cv2.imread('../input/diabetic-retinopathy-resized/resized_train/resized_train/'+sample_train_id+'.jpeg')\n\ndef resize_decolor(image, sigmaX=10):\n    image = cv2.cvtColor(image, cv2.COLOR_BGR2RGB)\n    image = crop_image_from_gray(image)\n    image = cv2.resize(image, (IMG_SIZE, IMG_SIZE))\n    image = cv2.addWeighted (image,4, cv2.GaussianBlur( image , (0,0) , sigmaX) ,-4 ,128)\n    return image\n\n#img = cv2.blur(sample_img, (5, 5))\nimg = resize_decolor(sample_img)\nprint(img.shape)\n\nplt.imshow(img)\nplt.title(result)\nplt.show()","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"### Data Preprocessing"},{"metadata":{"trusted":true},"cell_type":"code","source":"X_imgs = []\ny_diagnosis = []\nid_zeros = 0\nfor key, row in train_df_new.sample(frac=1, random_state=42).iterrows():\n    code = row['id_code']\n    diagnosis = row['diagnosis']\n    \n    if diagnosis == 0:\n        id_zeros += 1\n        if id_zeros > 500:\n            continue\n    \n    image_data = cv2.imread('../input/aptos2019-blindness-detection/train_images/'+code+'.png')\n    img = resize_decolor(image_data)\n    \n    X_imgs.append(img)\n    y_diagnosis.append(diagnosis)\n\nprint(len(X_imgs))\nprint(len(y_diagnosis))\n    ","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"for key, row in ex_df.sample(frac=1, random_state=42).iterrows():\n    code = row['image']\n    diagnosis = row['level']\n    \n    image_data = cv2.imread('../input/diabetic-retinopathy-resized/resized_train/resized_train/' + code + '.jpeg')\n    img = resize_decolor(image_data)\n    \n    X_imgs.append(img)\n    y_diagnosis.append(diagnosis)\n    \n\nprint(len(X_imgs))\nprint(len(y_diagnosis))\n","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"X_imgs = np.array(X_imgs)\ny_diagnosis = np.array(y_diagnosis)\n\nprint(X_imgs.shape)\nprint(y_diagnosis.shape)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"pd.Series(y_diagnosis).value_counts()","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"y_diagnosis_cat = np_utils.to_categorical(y_diagnosis, NUM_CLASSES)\ny_multi = np.empty(y_diagnosis_cat.shape, dtype=y_diagnosis.dtype)\ny_multi[:, 4] = y_diagnosis_cat[:, 4]\n\nfor i in range(3, -1, -1):\n    y_multi[:, i] = np.logical_or(y_diagnosis_cat[:, i], y_multi[:, i+1])\n    \nprint(y_multi.sum(axis=0))","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"tr_imgs, val_imgs, tr_y, val_y = train_test_split(X_imgs, y_multi, test_size = 0.1, random_state = 42)\ntrain_imgs, cv_imgs, train_y, cv_y = train_test_split(tr_imgs, tr_y, test_size = 0.1, random_state = 42)\n\ndel X_imgs\ndel tr_imgs\ndel tr_y\n\nprint(train_imgs.shape)\nprint(cv_imgs.shape)\nprint(val_imgs.shape)\nprint(train_y.shape)\nprint(cv_y.shape)\nprint(val_y.shape)","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"### Define Model"},{"metadata":{"trusted":true},"cell_type":"code","source":"tf.set_random_seed(0)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"def efficientnet_model(file_path, input_shape, num_classes):\n    input_tensor = Input(shape=input_shape)\n    model = Sequential()\n    base_model = EfficientNetB5(include_top=False,\n                             weights=None,\n                             input_tensor=input_tensor)\n    base_model.load_weights(file_path)\n    \n    for layer in base_model.layers:\n        layer.trainable = False\n        \n        # unfreeze batch_norm layers\n        if layer.name.startswith('batch_normalization'):\n            layer.trainable = True\n        if layer.name.endswith('bn'):\n            layer.trainable = True\n    \n    \n    model.add(base_model)\n    model.add(GlobalAveragePooling2D())\n    model.add(Dropout(0.5))\n    model.add(Dense(512))\n    model.add(Activation('relu'))\n    model.add(BatchNormalization())\n    model.add(Dropout(0.5))\n    model.add(Dense(256))\n    model.add(Activation('relu'))\n    model.add(BatchNormalization())\n    model.add(Dropout(0.4))\n    model.add(Dense(128))\n    model.add(Activation('relu'))\n    model.add(BatchNormalization())\n    model.add(Dropout(0.4))\n    model.add(Dense(num_classes, activation='sigmoid'))\n\n    \n    return model\n\n","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"np.random.seed(42)\nmodel = efficientnet_model(WEIGHTS_PATH, INPUT_SHAPE, NUM_CLASSES)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"model.compile(loss = 'binary_crossentropy',\n             optimizer = Adam(lr=0.001),\n             metrics = ['accuracy'])\nmodel.summary()","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"EARLY_STOPPING = EarlyStopping(monitor='val_loss', patience=25, verbose=1, mode='auto')\n\nMODEL_CHECKPOINT = ModelCheckpoint(filepath = 'effnet_best_acc_model.h5',\n                                  monitor='val_acc',\n                                  verbose=1,\n                                  save_best_only=True,\n                                  save_weights_only=False,\n                                  mode='max',\n                                  period=1)\n\ndef step_decay(epoch):\n    x = 0.001\n    if epoch >= 20: x = 0.00075\n    return x\n\nLR_DECAY = LearningRateScheduler(step_decay)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"class Metrics(Callback):\n    def on_train_begin(self, logs={}):\n        self.val_kappas = []\n\n    def on_epoch_end(self, epoch, logs={}):\n        X_val, y_val = self.validation_data[:2]\n        y_val = y_val.sum(axis=1) - 1\n        \n        y_pred = self.model.predict(X_val) > 0.5\n        y_pred = y_pred.astype(int).sum(axis=1) - 1\n        \n\n        _val_kappa = cohen_kappa_score(\n            y_val, \n            y_pred, \n            weights='quadratic'\n        )\n\n        self.val_kappas.append(_val_kappa)\n\n        print(f\"val_kappa: {_val_kappa:.4f}\")\n        \n        if _val_kappa == max(self.val_kappas):\n            print(\"Validation Kappa has improved. Saving model.\")\n            self.model.save('best_kappa_model.h5')\n\n        return","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"kappa_metrics = Metrics()","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"augmentation_params = {\n    'rescale':1./255,\n    'rotation_range': 20,\n    'zoom_range': 0.05,\n    'vertical_flip': True,\n    'horizontal_flip': True,\n    'width_shift_range': 0.05\n}","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"traingen = ImageDataGenerator(**augmentation_params)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"cv_imgs = cv_imgs / 255.","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"history = model.fit_generator(traingen.flow(train_imgs, train_y, batch_size = BATCH_SIZE),\n                    steps_per_epoch = len(train_imgs)//BATCH_SIZE,\n                    epochs = EPOCHS,\n                    verbose = 1,\n                    validation_data = (cv_imgs, cv_y),\n                    callbacks=[EARLY_STOPPING, MODEL_CHECKPOINT, kappa_metrics, LR_DECAY])","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"del cv_imgs","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"import matplotlib.pyplot as plt\n\n#plot loss history & kappa\nfig = plt.figure(figsize=(8, 6))\nplt.plot(history.history['acc'], color='r', label='acc')\nplt.plot(history.history['val_acc'], label='val_acc')\nplt.legend()\n\nplt.xlabel(\"epoch\")\nplt.ylabel(\"loss\")\n\nplt.vlines(np.argmax(history.history['val_acc']), 0.5, 1)\nplt.title(np.max(history.history['val_acc']))\n\nplt.show()\n\nplt.plot(kappa_metrics.val_kappas)\nplt.vlines(np.argmax(kappa_metrics.val_kappas), 0.5, 1.0)\nplt.title('kappa score')\nplt.show()","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"model.save('aptos_effnet_model.h5', include_optimizer=False)\nnp.save('val_imgs.npy', val_imgs)\nnp.save('val_y.npy', val_y)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"from IPython.display import FileLink\nFileLink('effnet_best_acc_model.h5')","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"FileLink('best_kappa_model.h5')","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"FileLink('val_imgs.npy')","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"FileLink('val_y.npy')","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"","execution_count":null,"outputs":[]}],"metadata":{"kernelspec":{"display_name":"Python 3","language":"python","name":"python3"},"language_info":{"name":"python","version":"3.6.4","mimetype":"text/x-python","codemirror_mode":{"name":"ipython","version":3},"pygments_lexer":"ipython3","nbconvert_exporter":"python","file_extension":".py"}},"nbformat":4,"nbformat_minor":1}