{"cells":[{"metadata":{"_uuid":"8f2839f25d086af736a60e9eeb907d3b93b6e0e5","_cell_guid":"b1076dfc-b9ad-4769-8c92-a6c4dae69d19","trusted":true,"_kg_hide-input":true,"_kg_hide-output":true},"cell_type":"code","source":"import os\nimport cv2\nimport random\nimport warnings\nimport numpy as np\nimport pandas as pd\nimport seaborn as sns\nimport matplotlib.pyplot as plt\nfrom sklearn.metrics import confusion_matrix, cohen_kappa_score\nfrom keras.models import Model\nfrom keras import optimizers, applications\nfrom keras.preprocessing.image import ImageDataGenerator\nfrom keras.callbacks import EarlyStopping, ReduceLROnPlateau\nfrom keras.layers import Dense, Dropout, GlobalAveragePooling2D, Input\nfrom tqdm import tqdm\n# Set seeds to make the experiment more reproducible.\nfrom tensorflow import set_random_seed\ndef seed_everything(seed=0):\n    random.seed(seed)\n    os.environ['PYTHONHASHSEED'] = str(seed)\n    np.random.seed(seed)\n    set_random_seed(0)\nseed_everything()\n\n%matplotlib inline\nsns.set(style=\"whitegrid\")\nwarnings.filterwarnings(\"ignore\")","execution_count":null,"outputs":[]},{"metadata":{"_kg_hide-output":true},"cell_type":"markdown","source":"## Load data"},{"metadata":{"_cell_guid":"79c7e3d0-c299-4dcb-8224-4455121ee9b0","_uuid":"d629ff2d2480ee46fbb7e2d37f6b5fab8052498a","trusted":true,"_kg_hide-input":false},"cell_type":"code","source":"train = pd.read_csv('../input/aptos2019-blindness-detection/train.csv')\ntest = pd.read_csv('../input/aptos2019-blindness-detection/test.csv')","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"# EDA\n\n## Data overview"},{"metadata":{"_kg_hide-input":true,"trusted":true},"cell_type":"code","source":"print('Number of train samples: ', train.shape[0])\nprint('Number of test samples: ', test.shape[0])\ndisplay(train.head())","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"## Label class distribution\n\nAs we can see we have an unbalanced database, we have two times more class 0 than 2, and classes 1, 2 and 4 each have less than half of the class 2 data."},{"metadata":{"_kg_hide-input":true,"trusted":true},"cell_type":"code","source":"f, ax = plt.subplots(figsize=(14, 8.7))\nax = sns.countplot(x=\"diagnosis\", data=train, palette=\"GnBu_d\")\nsns.despine()\nplt.show()","execution_count":null,"outputs":[]},{"metadata":{"_kg_hide-input":true,"trusted":true},"cell_type":"code","source":"sns.set_style(\"white\")\ncount = 1\nplt.figure(figsize=[20, 20])\nfor img_name in train['id_code'][:15]:\n    img = cv2.imread(\"../input/aptos2019-blindness-detection/train_images/%s.png\" % img_name)[...,[2, 1, 0]]\n    plt.subplot(5, 5, count)\n    plt.imshow(img)\n    plt.title(\"Image %s\" % count)\n    count += 1\n    \nplt.show()","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"# Model parameters"},{"metadata":{"trusted":true},"cell_type":"code","source":"# Model parameters\nBATCH_SIZE = 8\nEPOCHS = 20\nWARMUP_EPOCHS = 2\nLEARNING_RATE = 1e-4\nWARMUP_LEARNING_RATE = 1e-3\nHEIGHT = 512\nWIDTH = 512\nCANAL = 3\nN_CLASSES = train['diagnosis'].nunique()\nES_PATIENCE = 5\nRLROP_PATIENCE = 3\nDECAY_DROP = 0.5","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"# Preprocecss data\ntrain[\"id_code\"] = train[\"id_code\"].apply(lambda x: x + \".png\")\ntest[\"id_code\"] = test[\"id_code\"].apply(lambda x: x + \".png\")\ntrain['diagnosis'] = train['diagnosis'].astype('str')\ntrain.head()","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"## Data generator"},{"metadata":{"_kg_hide-input":true,"trusted":true},"cell_type":"code","source":"train_datagen=ImageDataGenerator(\n    rescale=1./255, \n    validation_split=0.20,\n    shear_range=0.1,zoom_range=0.1, horizontal_flip=True,\n    rotation_range=10.,\n    fill_mode='reflect',\n    width_shift_range = 0.1, \n    height_shift_range = 0.1\n)\n\ntrain_generator=train_datagen.flow_from_dataframe(\n    dataframe=train,\n    directory=\"../input/aptos2019-blindness-detection/train_images/\",\n    x_col=\"id_code\",\n    y_col=\"diagnosis\",\n    batch_size=BATCH_SIZE,\n    class_mode=\"other\",\n    target_size=(HEIGHT, WIDTH),\n    subset='training')\n\nvalid_generator=train_datagen.flow_from_dataframe(\n    dataframe=train,\n    directory=\"../input/aptos2019-blindness-detection/train_images/\",\n    x_col=\"id_code\",\n    y_col=\"diagnosis\",\n    batch_size=BATCH_SIZE,\n    class_mode=\"other\",    \n    target_size=(HEIGHT, WIDTH),\n    subset='validation')\n\ntest_datagen = ImageDataGenerator(rescale=1./255,\n    shear_range=0.1,zoom_range=0.1, horizontal_flip=True,\n    rotation_range=10.,\n    fill_mode='reflect',\n    width_shift_range = 0.1, \n    height_shift_range = 0.1)\n\ntest_generator = test_datagen.flow_from_dataframe(  \n        dataframe=test,\n        directory = \"../input/aptos2019-blindness-detection/test_images/\",\n        x_col=\"id_code\",\n        target_size=(HEIGHT, WIDTH),\n        batch_size=1,\n        shuffle=False,\n        class_mode=None)\ncomplete_datagen = ImageDataGenerator(rescale=1./255,\n    shear_range=0.1,zoom_range=0.1, horizontal_flip=True,\n    rotation_range=10.,\n    fill_mode='reflect',\n    width_shift_range = 0.1, \n    height_shift_range = 0.1)\ncomplete_generator = complete_datagen.flow_from_dataframe(  \n        dataframe=train,\n        directory = \"../input/aptos2019-blindness-detection/train_images/\",\n        x_col=\"id_code\",\n        target_size=(HEIGHT, WIDTH),\n        batch_size=1,\n        shuffle=False,\n        class_mode=None)","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"# Model"},{"metadata":{"trusted":true},"cell_type":"code","source":"def create_model(input_shape, n_out):\n    input_tensor = Input(shape=input_shape)\n    base_model = applications.ResNet50(weights=None, \n                                       include_top=False,\n                                       input_tensor=input_tensor)\n    base_model.load_weights('../input/resnet50/resnet50_weights_tf_dim_ordering_tf_kernels_notop.h5')\n\n    x = GlobalAveragePooling2D()(base_model.output)\n    x = Dropout(0.5)(x)\n    x = Dense(2048, activation='relu')(x)\n    x = Dropout(0.5)(x)\n    final_output = Dense(1, activation='linear', name='final_output')(x)\n    model = Model(input_tensor, final_output)\n    return model","execution_count":null,"outputs":[]},{"metadata":{"_kg_hide-output":true,"trusted":true},"cell_type":"code","source":"model = create_model(input_shape=(HEIGHT, WIDTH, CANAL), n_out=N_CLASSES)\n\nfor layer in model.layers:\n    layer.trainable = False\n\nfor i in range(-5, 0):\n    model.layers[i].trainable = True\n\nmetric_list = ['mse','mae']\noptimizer = optimizers.Adam(lr=WARMUP_LEARNING_RATE)\nmodel.compile(optimizer=optimizer, loss=\"mse\",  metrics=metric_list)\nmodel.summary()","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"# Train top layers"},{"metadata":{"trusted":true,"_kg_hide-output":true},"cell_type":"code","source":"STEP_SIZE_TRAIN = train_generator.n//train_generator.batch_size\nSTEP_SIZE_VALID = valid_generator.n//valid_generator.batch_size\n\nhistory_warmup = model.fit_generator(generator=train_generator,\n                              steps_per_epoch=STEP_SIZE_TRAIN,\n                              validation_data=valid_generator,\n                              validation_steps=STEP_SIZE_VALID,\n                              epochs=WARMUP_EPOCHS,\n                              verbose=1).history","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"# Fine-tune the complete model"},{"metadata":{"_kg_hide-output":true,"trusted":true},"cell_type":"code","source":"for layer in model.layers:\n    layer.trainable = True\n\nes = EarlyStopping(monitor='val_loss', mode='min', patience=ES_PATIENCE, restore_best_weights=True, verbose=1)\nrlrop = ReduceLROnPlateau(monitor='val_loss', mode='min', patience=RLROP_PATIENCE, factor=DECAY_DROP, min_lr=1e-6, verbose=1)\n\ncallback_list = [es, rlrop]\noptimizer = optimizers.Adam(lr=LEARNING_RATE)\nmodel.compile(optimizer=optimizer, loss=\"mse\",  metrics=metric_list)\nmodel.summary()","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"_kg_hide-output":true},"cell_type":"code","source":"history_finetunning = model.fit_generator(generator=train_generator,\n                              steps_per_epoch=STEP_SIZE_TRAIN,\n                              validation_data=valid_generator,\n                              validation_steps=STEP_SIZE_VALID,\n                              epochs=EPOCHS,\n                              callbacks=callback_list,\n                              verbose=1).history","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"# Model loss graph "},{"metadata":{"_kg_hide-input":true,"trusted":true},"cell_type":"code","source":"history = {'loss': history_warmup['loss'] + history_finetunning['loss'], \n           'val_loss': history_warmup['val_loss'] + history_finetunning['val_loss']}\n\nsns.set_style(\"whitegrid\")\n\n\nplt.plot(history['loss'], label='Train loss')\nplt.plot(history['val_loss'], label='Validation loss')\nplt.legend(loc='best')\nplt.title('Loss')\n\n\nplt.xlabel('Epochs')\nsns.despine()\nplt.show()","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"# Model Evaluation"},{"metadata":{"trusted":true},"cell_type":"code","source":"complete_generator.reset()\nSTEP_SIZE_COMPLETE = complete_generator.n//complete_generator.batch_size\ntrain_predict_cont = model.predict_generator(complete_generator, steps=STEP_SIZE_COMPLETE)\n\n","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"coef = [0.5, 1.5, 2.5, 3.6]\ndef devide_catagory(test_preds):\n    for i, pred in enumerate(test_preds):\n        if pred < coef[0]:\n            test_preds[i] = 0\n        elif pred >= coef[0] and pred < coef[1]:\n            test_preds[i] = 1\n        elif pred >= coef[1] and pred < coef[2]:\n            test_preds[i] = 2\n        elif pred >= coef[2] and pred < coef[3]:\n            test_preds[i] = 3\n        else:\n            test_preds[i] = 4\n    return test_preds","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"train_predict=devide_catagory(train_predict_cont)","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"1. ## Confusion Matrix"},{"metadata":{"trusted":true,"_kg_hide-input":true},"cell_type":"code","source":"labels = ['0 - No DR', '1 - Mild', '2 - Moderate', '3 - Severe', '4 - Proliferative DR']\ncnf_matrix = confusion_matrix(train['diagnosis'].astype('int'), train_predict)\ncnf_matrix_norm = cnf_matrix.astype('float') / cnf_matrix.sum(axis=1)[:, np.newaxis]\ndf_cm = pd.DataFrame(cnf_matrix_norm, index=labels, columns=labels)\nplt.figure(figsize=(16, 7))\nsns.heatmap(df_cm, annot=True, fmt='.2f', cmap=\"Blues\")\nplt.show()","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"## Quadratic Weighted Kappa"},{"metadata":{"trusted":true},"cell_type":"code","source":"train_predict_cont.reshape(train_predict_cont.shape[0])","execution_count":null,"outputs":[]},{"metadata":{"_kg_hide-input":true,"trusted":true},"cell_type":"code","source":"print(\"Train Cohen Kappa score: %.3f\" % cohen_kappa_score(train_predict, train['diagnosis'].astype('int'), weights='quadratic'))","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"# Apply model to test set and output predictions"},{"metadata":{"trusted":true},"cell_type":"code","source":"tta_steps = 10\npredictions = []\nSTEP_SIZE_TEST = test_generator.n//test_generator.batch_size\nfor i in tqdm(range(tta_steps)):\n    test_generator.reset()\n    preds = model.predict_generator(test_generator,steps=STEP_SIZE_TEST)\n    predictions.append(preds)\npredict = np.mean(predictions, axis=0)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"predict=devide_catagory(predict)\npredict=predict.reshape(test_generator.n)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"filenames = test_generator.filenames\nresults = pd.DataFrame({'id_code':filenames, 'diagnosis':predict.astype(int)})\nresults['id_code'] = results['id_code'].map(lambda x: str(x)[:-4])\nresults.to_csv('submission.csv',index=False)\nresults.head(10)","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"## Predictions class distribution"},{"metadata":{"_kg_hide-input":true,"trusted":true},"cell_type":"code","source":"f, ax = plt.subplots(figsize=(14, 8.7))\nax = sns.countplot(x=\"diagnosis\", data=results, palette=\"GnBu_d\")\nsns.despine()\nplt.show()","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}