{"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"},"kaggle":{"accelerator":"gpu","dataSources":[{"sourceId":14774,"databundleVersionId":875431,"sourceType":"competition"},{"sourceId":2285981,"sourceType":"datasetVersion","datasetId":1377250}],"dockerImageVersionId":28772,"isInternetEnabled":false,"language":"python","sourceType":"notebook","isGpuEnabled":true}},"nbformat_minor":4,"nbformat":4,"cells":[{"cell_type":"markdown","source":"# Block1- Importing the necessary libraries","metadata":{}},{"cell_type":"code","source":"import json\nimport math\nimport os\n\nimport cv2\nfrom PIL import Image\nimport numpy as np\nfrom keras import layers\nfrom keras.applications.vgg16 import VGG16\nfrom keras.applications.vgg16 import preprocess_input\nfrom keras.callbacks import Callback, ModelCheckpoint\nfrom keras.preprocessing.image import ImageDataGenerator\nfrom keras.models import Sequential\nfrom keras.optimizers import Adam\nimport matplotlib.pyplot as plt\nimport pandas as pd\nfrom sklearn.model_selection import train_test_split\nfrom sklearn.metrics import cohen_kappa_score, accuracy_score\nimport scipy\nimport tensorflow as tf\nfrom tqdm import tqdm\n\n%matplotlib inline","metadata":{"execution":{"iopub.status.busy":"2021-06-11T06:46:29.640854Z","iopub.execute_input":"2021-06-11T06:46:29.641176Z","iopub.status.idle":"2021-06-11T06:46:29.652624Z","shell.execute_reply.started":"2021-06-11T06:46:29.641127Z","shell.execute_reply":"2021-06-11T06:46:29.651839Z"},"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"## Set random seed for reproducibility.","metadata":{}},{"cell_type":"code","source":"np.random.seed(2019)\ntf.set_random_seed(2019)","metadata":{"execution":{"iopub.status.busy":"2021-06-11T06:46:29.654248Z","iopub.execute_input":"2021-06-11T06:46:29.654786Z","iopub.status.idle":"2021-06-11T06:46:29.668467Z","shell.execute_reply.started":"2021-06-11T06:46:29.654615Z","shell.execute_reply":"2021-06-11T06:46:29.667666Z"},"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"# Block2- Loading & Exploration","metadata":{}},{"cell_type":"code","source":"train_df = pd.read_csv('../input/aptos2019-blindness-detection/train.csv')\ntest_df = pd.read_csv('../input/aptos2019-blindness-detection/test.csv')\nprint(train_df.shape)\nprint(test_df.shape)\ntrain_df.head()\ntest_df.head()","metadata":{"execution":{"iopub.status.busy":"2021-06-11T06:46:29.670174Z","iopub.execute_input":"2021-06-11T06:46:29.670719Z","iopub.status.idle":"2021-06-11T06:46:29.719523Z","shell.execute_reply.started":"2021-06-11T06:46:29.67044Z","shell.execute_reply":"2021-06-11T06:46:29.718757Z"},"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"# Block3- Visualization of the explored data","metadata":{}},{"cell_type":"code","source":"train_df['diagnosis'].hist()\ntrain_df['diagnosis'].value_counts()","metadata":{"execution":{"iopub.status.busy":"2021-06-11T06:46:29.720797Z","iopub.execute_input":"2021-06-11T06:46:29.721089Z","iopub.status.idle":"2021-06-11T06:46:29.936154Z","shell.execute_reply.started":"2021-06-11T06:46:29.721045Z","shell.execute_reply":"2021-06-11T06:46:29.932165Z"},"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"# BLock4- Displaying some Sample Images","metadata":{}},{"cell_type":"code","source":"def display_samples(df, columns=4, rows=3):\n    fig=plt.figure(figsize=(5*columns, 4*rows))\n\n    for i in range(columns*rows):\n        image_path = df.loc[i,'id_code']\n        image_id = df.loc[i,'diagnosis']\n        img = cv2.imread(f'../input/aptos2019-blindness-detection/train_images/{image_path}.png')\n        img = cv2.cvtColor(img, cv2.COLOR_BGR2RGB)\n        \n        fig.add_subplot(rows, columns, i+1)\n        plt.title(image_id)\n        plt.imshow(img)\n    \n    plt.tight_layout()\n\ndisplay_samples(train_df)","metadata":{"_kg_hide-input":true,"execution":{"iopub.status.busy":"2021-06-11T06:46:29.940355Z","iopub.execute_input":"2021-06-11T06:46:29.940665Z","iopub.status.idle":"2021-06-11T06:46:38.04492Z","shell.execute_reply.started":"2021-06-11T06:46:29.940612Z","shell.execute_reply":"2021-06-11T06:46:38.044072Z"},"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"# Block5- Resize Images\n\nWe will resize the images to 224x224, then create a single numpy array to hold the data.","metadata":{}},{"cell_type":"code","source":"def get_pad_width(im, new_shape, is_rgb=True):\n    pad_diff = new_shape - im.shape[0], new_shape - im.shape[1]\n    t, b = math.floor(pad_diff[0]/2), math.ceil(pad_diff[0]/2)\n    l, r = math.floor(pad_diff[1]/2), math.ceil(pad_diff[1]/2)\n    if is_rgb:\n        pad_width = ((t,b), (l,r), (0, 0))\n    else:\n        pad_width = ((t,b), (l,r))\n    return pad_width\n\ndef preprocess_image(image_path, desired_size=224):\n    im = Image.open(image_path)\n    im = im.resize((desired_size, )*2, resample=Image.LANCZOS)\n    \n    return im","metadata":{"execution":{"iopub.status.busy":"2021-06-11T06:46:38.047402Z","iopub.execute_input":"2021-06-11T06:46:38.047894Z","iopub.status.idle":"2021-06-11T06:46:38.062961Z","shell.execute_reply.started":"2021-06-11T06:46:38.047836Z","shell.execute_reply":"2021-06-11T06:46:38.062204Z"},"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"# Block6- Training\n## loading the train dataset\n","metadata":{}},{"cell_type":"code","source":"N = train_df.shape[0]\nx_train = np.empty((N, 224, 224, 3), dtype=np.uint8)\n\nfor i, image_id in enumerate(tqdm(train_df['id_code'])):\n    x_train[i, :, :, :] = preprocess_image(\n        f'../input/aptos2019-blindness-detection/train_images/{image_id}.png'\n    )","metadata":{"execution":{"iopub.status.busy":"2021-06-11T06:46:38.064314Z","iopub.execute_input":"2021-06-11T06:46:38.064845Z","iopub.status.idle":"2021-06-11T06:57:33.729607Z","shell.execute_reply.started":"2021-06-11T06:46:38.064794Z","shell.execute_reply":"2021-06-11T06:57:33.728672Z"},"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"# Block7-\n## loading the test dataset","metadata":{}},{"cell_type":"code","source":"N = test_df.shape[0]\nx_test = np.empty((N, 224, 224, 3), dtype=np.uint8)\n\nfor i, image_id in enumerate(tqdm(test_df['id_code'])):\n    x_test[i, :, :, :] = preprocess_image(\n        f'../input/aptos2019-blindness-detection/test_images/{image_id}.png'\n    )","metadata":{"execution":{"iopub.status.busy":"2021-06-11T06:57:33.731173Z","iopub.execute_input":"2021-06-11T06:57:33.731709Z","iopub.status.idle":"2021-06-11T06:59:37.032137Z","shell.execute_reply.started":"2021-06-11T06:57:33.731654Z","shell.execute_reply":"2021-06-11T06:59:37.031474Z"},"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"# Block8- Verfiying the shapes of the values loaded previously","metadata":{}},{"cell_type":"code","source":"y_train = pd.get_dummies(train_df['diagnosis']).values\n\nprint(x_train.shape)\nprint(y_train.shape)\nprint(x_test.shape)","metadata":{"execution":{"iopub.status.busy":"2021-06-11T06:59:37.033402Z","iopub.execute_input":"2021-06-11T06:59:37.033675Z","iopub.status.idle":"2021-06-11T06:59:37.044283Z","shell.execute_reply.started":"2021-06-11T06:59:37.033628Z","shell.execute_reply":"2021-06-11T06:59:37.042787Z"},"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"# Block9- ","metadata":{}},{"cell_type":"code","source":"y_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])\n\nprint(\"Original y_train:\", y_train.sum(axis=0))\nprint(\"Multilabel version:\", y_train_multi.sum(axis=0))","metadata":{"execution":{"iopub.status.busy":"2021-06-11T06:59:37.04661Z","iopub.execute_input":"2021-06-11T06:59:37.047089Z","iopub.status.idle":"2021-06-11T06:59:37.059643Z","shell.execute_reply.started":"2021-06-11T06:59:37.046889Z","shell.execute_reply":"2021-06-11T06:59:37.058684Z"},"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"Now we can split it into a training and validation set.","metadata":{}},{"cell_type":"markdown","source":"# Block10- Splitting into a training and validation set.","metadata":{}},{"cell_type":"code","source":"x_train, x_val, y_train, y_val = train_test_split(\n    x_train, y_train_multi, \n    test_size=0.15, \n    random_state=2019\n)","metadata":{"execution":{"iopub.status.busy":"2021-06-11T06:59:37.06106Z","iopub.execute_input":"2021-06-11T06:59:37.061376Z","iopub.status.idle":"2021-06-11T06:59:37.417641Z","shell.execute_reply.started":"2021-06-11T06:59:37.061304Z","shell.execute_reply":"2021-06-11T06:59:37.416919Z"},"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"# Block11- Mixup & Data Generator\n","metadata":{}},{"cell_type":"code","source":"class MixupGenerator():\n    def __init__(self, X_train, y_train, batch_size=32, alpha=0.2, shuffle=True, datagen=None):\n        self.X_train = X_train\n        self.y_train = y_train\n        self.batch_size = batch_size\n        self.alpha = alpha\n        self.shuffle = shuffle\n        self.sample_num = len(X_train)\n        self.datagen = datagen\n\n    def __call__(self):\n        while True:\n            indexes = self.__get_exploration_order()\n            itr_num = int(len(indexes) // (self.batch_size * 2))\n\n            for i in range(itr_num):\n                batch_ids = indexes[i * self.batch_size * 2:(i + 1) * self.batch_size * 2]\n                X, y = self.__data_generation(batch_ids)\n\n                yield X, y\n\n    def __get_exploration_order(self):\n        indexes = np.arange(self.sample_num)\n\n        if self.shuffle:\n            np.random.shuffle(indexes)\n\n        return indexes\n\n    def __data_generation(self, batch_ids):\n        _, h, w, c = self.X_train.shape\n        l = np.random.beta(self.alpha, self.alpha, self.batch_size)\n        X_l = l.reshape(self.batch_size, 1, 1, 1)\n        y_l = l.reshape(self.batch_size, 1)\n\n        X1 = self.X_train[batch_ids[:self.batch_size]]\n        X2 = self.X_train[batch_ids[self.batch_size:]]\n        X = X1 * X_l + X2 * (1 - X_l)\n\n        if self.datagen:\n            for i in range(self.batch_size):\n                X[i] = self.datagen.random_transform(X[i])\n                X[i] = self.datagen.standardize(X[i])\n\n        if isinstance(self.y_train, list):\n            y = []\n\n            for y_train_ in self.y_train:\n                y1 = y_train_[batch_ids[:self.batch_size]]\n                y2 = y_train_[batch_ids[self.batch_size:]]\n                y.append(y1 * y_l + y2 * (1 - y_l))\n        else:\n            y1 = self.y_train[batch_ids[:self.batch_size]]\n            y2 = self.y_train[batch_ids[self.batch_size:]]\n            y = y1 * y_l + y2 * (1 - y_l)\n\n        return X, y","metadata":{"execution":{"iopub.status.busy":"2021-06-11T06:59:37.419299Z","iopub.execute_input":"2021-06-11T06:59:37.419622Z","iopub.status.idle":"2021-06-11T06:59:37.436759Z","shell.execute_reply.started":"2021-06-11T06:59:37.419565Z","shell.execute_reply":"2021-06-11T06:59:37.43604Z"},"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"# Block12- ","metadata":{}},{"cell_type":"code","source":"BATCH_SIZE = 25\n\n\ndef create_datagen():\n    return ImageDataGenerator(\n        zoom_range=0.15,  # set range for random zoom\n        # set mode for filling points outside the input boundaries\n        fill_mode='constant',\n        cval=0.,  # value used for fill_mode = \"constant\"\n        horizontal_flip=True,  # randomly flip images\n        vertical_flip=True,  # randomly flip images\n    )\n\n# Using original generator\ndata_generator = create_datagen().flow(x_train, y_train, batch_size=BATCH_SIZE, seed=2019)\n# Using Mixup\nmixup_generator = MixupGenerator(x_train, y_train, batch_size=BATCH_SIZE, alpha=0.2, datagen=create_datagen())()","metadata":{"execution":{"iopub.status.busy":"2021-06-11T08:46:15.097228Z","iopub.execute_input":"2021-06-11T08:46:15.09755Z","iopub.status.idle":"2021-06-11T08:46:16.123908Z","shell.execute_reply.started":"2021-06-11T08:46:15.097499Z","shell.execute_reply":"2021-06-11T08:46:16.12313Z"},"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"code","source":"true_labels = np.array([1, 0, 1, 1, 0, 1])\npred_labels = np.array([1, 0, 0, 0, 0, 1])","metadata":{"execution":{"iopub.status.busy":"2021-06-11T08:46:19.274742Z","iopub.execute_input":"2021-06-11T08:46:19.275048Z","iopub.status.idle":"2021-06-11T08:46:19.283536Z","shell.execute_reply.started":"2021-06-11T08:46:19.274994Z","shell.execute_reply":"2021-06-11T08:46:19.28265Z"},"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"code","source":"accuracy_score(true_labels, pred_labels)","metadata":{"execution":{"iopub.status.busy":"2021-06-11T08:46:20.877999Z","iopub.execute_input":"2021-06-11T08:46:20.87837Z","iopub.status.idle":"2021-06-11T08:46:20.885782Z","shell.execute_reply.started":"2021-06-11T08:46:20.87831Z","shell.execute_reply":"2021-06-11T08:46:20.885025Z"},"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"code","source":"cohen_kappa_score(true_labels, pred_labels)","metadata":{"execution":{"iopub.status.busy":"2021-06-11T08:46:20.903344Z","iopub.execute_input":"2021-06-11T08:46:20.903568Z","iopub.status.idle":"2021-06-11T08:46:20.912072Z","shell.execute_reply.started":"2021-06-11T08:46:20.903526Z","shell.execute_reply":"2021-06-11T08:46:20.911237Z"},"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"# Block13- Creating keras callback for QWK","metadata":{}},{"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        _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('model.h5')\n\n        return","metadata":{"execution":{"iopub.status.busy":"2021-06-11T08:46:26.020758Z","iopub.execute_input":"2021-06-11T08:46:26.021067Z","iopub.status.idle":"2021-06-11T08:46:26.029321Z","shell.execute_reply.started":"2021-06-11T08:46:26.021015Z","shell.execute_reply":"2021-06-11T08:46:26.028521Z"},"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"# Block14- Model: VGG16","metadata":{}},{"cell_type":"code","source":"# densenet = DenseNet121(\n#     weights='../input/densenet-keras/DenseNet-BC-121-32-no-top.h5',\n#     include_top=False,\n#     input_shape=(224,224,3)\n# )\n\n\nvgg = VGG16(input_shape=(224,224,3), weights=None, include_top=False)","metadata":{"execution":{"iopub.status.busy":"2021-06-11T08:46:28.69275Z","iopub.execute_input":"2021-06-11T08:46:28.693067Z","iopub.status.idle":"2021-06-11T08:46:28.860511Z","shell.execute_reply.started":"2021-06-11T08:46:28.693008Z","shell.execute_reply":"2021-06-11T08:46:28.859818Z"},"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"# Block15- Building the model\n## Summarizing the model to get a birds eye view","metadata":{}},{"cell_type":"code","source":"def build_model():\n    model = Sequential()\n    model.add(vgg)\n    model.add(layers.GlobalAveragePooling2D())\n    model.add(layers.Dropout(0.5))\n    model.add(layers.Dense(5, activation='sigmoid'))\n    \n    model.compile(\n        loss='binary_crossentropy',\n        optimizer=Adam(lr=0.00005),\n        metrics=['accuracy']\n    )\n    \n    return model","metadata":{"execution":{"iopub.status.busy":"2021-06-11T08:46:31.085973Z","iopub.execute_input":"2021-06-11T08:46:31.086272Z","iopub.status.idle":"2021-06-11T08:46:31.092116Z","shell.execute_reply.started":"2021-06-11T08:46:31.08622Z","shell.execute_reply":"2021-06-11T08:46:31.091343Z"},"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"code","source":"model = build_model()\nmodel.summary()","metadata":{"execution":{"iopub.status.busy":"2021-06-11T08:46:39.774701Z","iopub.execute_input":"2021-06-11T08:46:39.775007Z","iopub.status.idle":"2021-06-11T08:46:39.887354Z","shell.execute_reply.started":"2021-06-11T08:46:39.774955Z","shell.execute_reply":"2021-06-11T08:46:39.886693Z"},"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"# Block16- Training & Evaluation","metadata":{}},{"cell_type":"code","source":"kappa_metrics = Metrics()\n\nhistory = model.fit_generator(\n    data_generator,\n    steps_per_epoch=x_train.shape[0] / BATCH_SIZE,\n    epochs=15,\n    validation_data=(x_val, y_val),\n    callbacks=[kappa_metrics])","metadata":{"execution":{"iopub.status.busy":"2021-06-11T08:46:42.25523Z","iopub.execute_input":"2021-06-11T08:46:42.255517Z","iopub.status.idle":"2021-06-11T08:55:28.638116Z","shell.execute_reply.started":"2021-06-11T08:46:42.255469Z","shell.execute_reply":"2021-06-11T08:55:28.636876Z"},"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"# Block17- Necessary plots to check accuracy","metadata":{}},{"cell_type":"code","source":"with open('history.json', 'w') as f:\n    json.dump(history.history, f)\n\nhistory_df = pd.DataFrame(history.history)\nhistory_df[['loss', 'val_loss']].plot()\nhistory_df[['acc', 'val_acc']].plot()","metadata":{"execution":{"iopub.status.busy":"2021-06-11T08:55:28.644319Z","iopub.execute_input":"2021-06-11T08:55:28.647479Z","iopub.status.idle":"2021-06-11T08:55:29.074923Z","shell.execute_reply.started":"2021-06-11T08:55:28.647426Z","shell.execute_reply":"2021-06-11T08:55:29.072572Z"},"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"code","source":"plt.plot(kappa_metrics.val_kappas)","metadata":{"execution":{"iopub.status.busy":"2021-06-11T08:55:29.076521Z","iopub.execute_input":"2021-06-11T08:55:29.076965Z","iopub.status.idle":"2021-06-11T08:55:29.22252Z","shell.execute_reply.started":"2021-06-11T08:55:29.076778Z","shell.execute_reply":"2021-06-11T08:55:29.221571Z"},"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"# Block18- Loading weights","metadata":{}},{"cell_type":"code","source":"model.load_weights('model.h5')\ny_val_pred = model.predict(x_val)\n\ndef compute_score_inv(threshold):\n    y1 = y_val_pred > threshold\n    y1 = y1.astype(int).sum(axis=1) - 1\n    y2 = y_val.sum(axis=1) - 1\n    score = cohen_kappa_score(y1, y2, weights='quadratic')\n    \n    return 1 - score\n\nsimplex = scipy.optimize.minimize(\n    compute_score_inv, 0.5, method='nelder-mead'\n)\n\nbest_threshold = simplex['x'][0]","metadata":{"execution":{"iopub.status.busy":"2021-06-11T08:55:29.223873Z","iopub.execute_input":"2021-06-11T08:55:29.224313Z","iopub.status.idle":"2021-06-11T08:55:30.994811Z","shell.execute_reply.started":"2021-06-11T08:55:29.224138Z","shell.execute_reply":"2021-06-11T08:55:30.993912Z"},"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"# Block19- PREDICTIONS","metadata":{}},{"cell_type":"code","source":"y_test = model.predict(x_test) > 0.5\ny_test = y_test.astype(int).sum(axis=1) - 1\n\ntest_df['diagnosis'] = y_test\ntest_df.to_csv('Output.csv',index=False)\nprint(\"Output File\")\ndisplay(test_df.head())","metadata":{"execution":{"iopub.status.busy":"2021-06-11T08:55:30.99677Z","iopub.execute_input":"2021-06-11T08:55:30.997202Z","iopub.status.idle":"2021-06-11T08:55:35.667106Z","shell.execute_reply.started":"2021-06-11T08:55:30.997155Z","shell.execute_reply":"2021-06-11T08:55:35.666464Z"},"trusted":true},"outputs":[],"execution_count":null}]}