{"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_minor":4,"nbformat":4,"cells":[{"cell_type":"markdown","source":"**It is important to see if our model is able to understand the difference between chest X-ray images with and without opacities. Therefore, in this notebook, I will try to maximize the accuracy of this binary classification task.**\n\n**If you are interested to see what model is learning (where is the model looking at), See this notebook where I implemented [GRADCAM](https://www.kaggle.com/sinamhd9/where-s-your-model-looking-at-grad-cam)**","metadata":{}},{"cell_type":"markdown","source":"# Imports","metadata":{}},{"cell_type":"code","source":"import pandas as pd\nimport numpy as np\nimport warnings\nwarnings.filterwarnings(\"ignore\")\nfrom glob import glob\nfrom tqdm.notebook import tqdm\nfrom ast import literal_eval\nimport os\nimport matplotlib.pyplot as plt\nimport matplotlib\nmatplotlib.rcParams.update({'font.size': 22})\nfrom sklearn.metrics import accuracy_score\nfrom skimage import exposure\nfrom tensorflow.keras import layers\nfrom tensorflow.keras.utils import plot_model\nimport cv2\nfrom matplotlib.patches import Rectangle\nfrom keras.preprocessing.image import ImageDataGenerator\nfrom tensorflow.keras.applications import DenseNet169, DenseNet121, DenseNet201, VGG19, Xception\nfrom tensorflow.keras.models import Model\nfrom tensorflow.keras.layers import Dense, Flatten, Conv2D, MaxPooling2D, Dropout, GlobalAveragePooling2D\nfrom tensorflow.keras.optimizers import Adam\nfrom tensorflow.keras import models\nfrom tensorflow.keras.callbacks import ReduceLROnPlateau, ModelCheckpoint, EarlyStopping\nimport tensorflow.keras.backend as K\nfrom tensorflow.math import confusion_matrix","metadata":{"execution":{"iopub.status.busy":"2021-06-11T17:02:35.496442Z","iopub.execute_input":"2021-06-11T17:02:35.49702Z","iopub.status.idle":"2021-06-11T17:02:42.678136Z","shell.execute_reply.started":"2021-06-11T17:02:35.496988Z","shell.execute_reply":"2021-06-11T17:02:42.677096Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# Data manipulations","metadata":{}},{"cell_type":"code","source":"df_image = pd.read_csv('../input/siim-covid19-detection/train_image_level.csv')\ndisplay(df_image.head(3))\nprint(df_image.shape)","metadata":{"execution":{"iopub.status.busy":"2021-06-11T17:02:42.679653Z","iopub.execute_input":"2021-06-11T17:02:42.679949Z","iopub.status.idle":"2021-06-11T17:02:42.763117Z","shell.execute_reply.started":"2021-06-11T17:02:42.679921Z","shell.execute_reply":"2021-06-11T17:02:42.762109Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"df_study = pd.read_csv('../input/siim-covid19-detection/train_study_level.csv')\ndisplay(df_study.head(3))\nprint(df_study.shape)","metadata":{"execution":{"iopub.status.busy":"2021-06-11T17:02:42.764645Z","iopub.execute_input":"2021-06-11T17:02:42.764988Z","iopub.status.idle":"2021-06-11T17:02:42.793214Z","shell.execute_reply.started":"2021-06-11T17:02:42.764945Z","shell.execute_reply":"2021-06-11T17:02:42.792329Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"df_sampleSub = pd.read_csv('../input/siim-covid19-detection/sample_submission.csv')\ndisplay(df_sampleSub.head(3))\nprint(df_sampleSub.shape)","metadata":{"execution":{"iopub.status.busy":"2021-06-11T17:02:42.79467Z","iopub.execute_input":"2021-06-11T17:02:42.794958Z","iopub.status.idle":"2021-06-11T17:02:42.819016Z","shell.execute_reply.started":"2021-06-11T17:02:42.79493Z","shell.execute_reply":"2021-06-11T17:02:42.818102Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"df_study['id'] = df_study['id'].str.replace('_study',\"\")\ndf_study.rename({'id': 'StudyInstanceUID'},axis=1, inplace=True)\ndf_study.head(3)","metadata":{"execution":{"iopub.status.busy":"2021-06-11T17:02:43.070681Z","iopub.execute_input":"2021-06-11T17:02:43.071078Z","iopub.status.idle":"2021-06-11T17:02:43.093816Z","shell.execute_reply.started":"2021-06-11T17:02:43.071045Z","shell.execute_reply":"2021-06-11T17:02:43.092874Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"df_train = df_image.merge(df_study, on='StudyInstanceUID')\ndf_train.head(3)","metadata":{"execution":{"iopub.status.busy":"2021-06-11T17:02:45.773617Z","iopub.execute_input":"2021-06-11T17:02:45.774028Z","iopub.status.idle":"2021-06-11T17:02:45.807776Z","shell.execute_reply.started":"2021-06-11T17:02:45.77399Z","shell.execute_reply":"2021-06-11T17:02:45.807097Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# train_dir_jpg = '../input/covid-jpg-512/train'\n# train_dir_origin ='../input/siim-covid19-detection/train'\n# paths_original = []\n# paths_jpg = []\n# for _, row in tqdm(df_train.iterrows()):\n#     image_id = row['id'].split('_')[0]\n#     study_id = row['StudyInstanceUID']\n#     image_path_jpg = glob(f'{train_dir_jpg}/{image_id}.jpg')\n#     image_path_original = glob(f'{train_dir_origin}/{study_id}/*/{image_id}.dcm')\n#     paths_jpg.append(image_path_jpg)\n#     paths_original.append(image_path_original)","metadata":{"execution":{"iopub.status.busy":"2021-06-11T17:02:32.440408Z","iopub.status.idle":"2021-06-11T17:02:32.440865Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# df_train['path'] = paths_jpg\n# df_train['origin'] = paths_original\n# df_train.head(3)","metadata":{"execution":{"iopub.status.busy":"2021-06-11T17:02:32.445765Z","iopub.status.idle":"2021-06-11T17:02:32.446224Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"df_train.loc[df_train['Negative for Pneumonia']==1, 'study_label'] = 'negative'\ndf_train.loc[df_train['Typical Appearance']==1, 'study_label'] = 'typical'\ndf_train.loc[df_train['Indeterminate Appearance']==1, 'study_label'] = 'indeterminate'\ndf_train.loc[df_train['Atypical Appearance']==1, 'study_label'] = 'atypical'\ndf_train.drop(['Negative for Pneumonia','Typical Appearance', 'Indeterminate Appearance', 'Atypical Appearance'], axis=1, inplace=True)\ndf_train['id'] = df_train['id'].str.replace('_image', '.jpg')\ndf_train['image_label'] = df_train['label'].str.split().apply(lambda x : x[0])\ndf_train.head(3)","metadata":{"execution":{"iopub.status.busy":"2021-06-11T17:02:50.93981Z","iopub.execute_input":"2021-06-11T17:02:50.940309Z","iopub.status.idle":"2021-06-11T17:02:51.166608Z","shell.execute_reply.started":"2021-06-11T17:02:50.940278Z","shell.execute_reply":"2021-06-11T17:02:51.165474Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"df_size = pd.read_csv('../input/covid-jpg-512/size.csv')\ndf_size.head(3)","metadata":{"execution":{"iopub.status.busy":"2021-06-11T17:02:53.441614Z","iopub.execute_input":"2021-06-11T17:02:53.44201Z","iopub.status.idle":"2021-06-11T17:02:53.480218Z","shell.execute_reply.started":"2021-06-11T17:02:53.441953Z","shell.execute_reply":"2021-06-11T17:02:53.479058Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"df_train = df_train.merge(df_size, on='id')\ndf_train.head(3)","metadata":{"execution":{"iopub.status.busy":"2021-06-11T17:02:53.919405Z","iopub.execute_input":"2021-06-11T17:02:53.919759Z","iopub.status.idle":"2021-06-11T17:02:53.947451Z","shell.execute_reply.started":"2021-06-11T17:02:53.919728Z","shell.execute_reply":"2021-06-11T17:02:53.946176Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"import seaborn as sns\n\nplt.figure()\nsns.countplot(df_train['image_label'], palette='husl')\nplt.axis='tight'\n\nplt.figure(figsize=(10, 5))\nsns.countplot(df_train['study_label'], palette='husl')\nplt.axis='tight'\nplt.show()","metadata":{"execution":{"iopub.status.busy":"2021-06-11T17:17:56.731674Z","iopub.execute_input":"2021-06-11T17:17:56.732059Z","iopub.status.idle":"2021-06-11T17:17:56.972344Z","shell.execute_reply.started":"2021-06-11T17:17:56.732023Z","shell.execute_reply":"2021-06-11T17:17:56.971144Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"def preprocess_image(img):\n    equ_img = exposure.equalize_adapthist(img/255, clip_limit=0.05, kernel_size=24)\n    return equ_img\n\ntrain_dir ='../input/covid-jpg-512/train'\ndf_opa = df_train[df_train['image_label']=='opacity'].reset_index()\nfig, axs = plt.subplots(5, 3, figsize=(10,20))\nfig.subplots_adjust(hspace=.2, wspace=.2)\nn=5\nfor i in range(n):\n    img = cv2.imread(os.path.join(train_dir, df_opa['id'][i]))\n    img_histeq = (exposure.equalize_hist(img/255))\n    img_proc = preprocess_image(img)\n    axs[i, 0].imshow(img)\n    axs[i, 1].imshow(img_histeq)\n    axs[i, 2].imshow(img_proc)\n    axs[i, 0].axis('off')\n    axs[i, 1].axis('off')\n    axs[i, 2].axis('off')\n    boxes = literal_eval(df_opa['boxes'][i])\n    for box in boxes:\n        axs[i, 0].add_patch(Rectangle((box['x']*(512/df_opa['dim1'][i]), box['y']*(512/df_opa['dim0'][i])), box['width']*(512/df_opa['dim1'][i]), box['height']*(512/df_opa['dim0'][i]), fill=0, color='y', linewidth=3))\n        axs[i, 1].add_patch(Rectangle((box['x']*(512/df_opa['dim1'][i]), box['y']*(512/df_opa['dim0'][i])), box['width']*(512/df_opa['dim1'][i]), box['height']*(512/df_opa['dim0'][i]), fill=0, color='b', linewidth=3))\n        axs[i, 2].add_patch(Rectangle((box['x']*(512/df_opa['dim1'][i]), box['y']*(512/df_opa['dim0'][i])), box['width']*(512/df_opa['dim1'][i]), box['height']*(512/df_opa['dim0'][i]), fill=0, color='r', linewidth=3))\n    \nplt.show()","metadata":{"execution":{"iopub.status.busy":"2021-06-11T17:53:21.702811Z","iopub.execute_input":"2021-06-11T17:53:21.703534Z","iopub.status.idle":"2021-06-11T17:53:24.141007Z","shell.execute_reply.started":"2021-06-11T17:53:21.703499Z","shell.execute_reply":"2021-06-11T17:53:24.14029Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# Visualization","metadata":{}},{"cell_type":"code","source":"n = 20\ntrain_dir = '../input/covid-jpg-512/train'\nfig, axs = plt.subplots(4, 5, figsize=(20,20))\nfig.subplots_adjust(hspace=.2, wspace=.2)\naxs = axs.ravel()\nfor i in range(n):\n    img = cv2.imread(os.path.join(train_dir, df_train['id'][i]))\n    axs[i].imshow(img)\n    if type(df_train['boxes'][i])==str:\n        boxes = literal_eval(df_train['boxes'][i])\n        for box in boxes:\n            axs[i].add_patch(Rectangle((box['x']*(512/df_train['dim1'][i]), box['y']*(512/df_train['dim0'][i])), box['width']*(512/df_train['dim1'][i]), box['height']*(512/df_train['dim0'][i]), fill=0, color='y', linewidth=2))\n            axs[i].set_title(df_train['study_label'][i])\n    else:\n        axs[i].set_title(df_train['study_label'][i])","metadata":{"execution":{"iopub.status.busy":"2021-06-09T06:47:06.890642Z","iopub.execute_input":"2021-06-09T06:47:06.891207Z","iopub.status.idle":"2021-06-09T06:47:10.522945Z","shell.execute_reply.started":"2021-06-09T06:47:06.891144Z","shell.execute_reply":"2021-06-09T06:47:10.521913Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# PreProcessing","metadata":{}},{"cell_type":"code","source":"def preprocess_image(img):\n    equ_img = (exposure.equalize_hist(img/255))\n    return equ_img\n\nim= cv2.imread(train_dir+'/'+df_train['id'][0])\nim2 = preprocess_image(im)\nres = np.concatenate((im/255, im2), axis=1)\nplt.imshow(res)\nplt.show()","metadata":{"execution":{"iopub.status.busy":"2021-06-09T06:47:10.524899Z","iopub.execute_input":"2021-06-09T06:47:10.525402Z","iopub.status.idle":"2021-06-09T06:47:10.869452Z","shell.execute_reply.started":"2021-06-09T06:47:10.52537Z","shell.execute_reply":"2021-06-09T06:47:10.868286Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# ImageGenerators and Augmentations","metadata":{}},{"cell_type":"code","source":"img_size = 299\nbatch_size = 16\n\nimage_generator = ImageDataGenerator(\n        validation_split=0.2,\n        #rotation_range=20,\n        horizontal_flip = True,\n        zoom_range = 0.1,\n        #shear_range = 0.1,\n        brightness_range = [0.8, 1.1],\n        fill_mode='nearest',\n        preprocessing_function=preprocess_image\n)\n\nimage_generator_valid = ImageDataGenerator(validation_split=0.2,preprocessing_function=preprocess_image)\n\ntrain_generator = image_generator.flow_from_dataframe(\n        dataframe = df_train,\n        directory='../input/covid-jpg-512/train',\n        x_col = 'id',\n        y_col =  'image_label',  \n        target_size=(img_size, img_size),\n        batch_size=batch_size,\n        subset='training', seed = 23) \n\nvalid_generator=image_generator_valid.flow_from_dataframe(\n    dataframe = df_train,\n    directory='../input/covid-jpg-512/train',\n    x_col = 'id',\n    y_col = 'image_label',\n    target_size=(img_size, img_size),\n    batch_size=batch_size,\n    subset='validation', shuffle=False, seed=23) ","metadata":{"execution":{"iopub.status.busy":"2021-06-09T06:47:26.788366Z","iopub.execute_input":"2021-06-09T06:47:26.788729Z","iopub.status.idle":"2021-06-09T06:47:48.589729Z","shell.execute_reply.started":"2021-06-09T06:47:26.7887Z","shell.execute_reply":"2021-06-09T06:47:48.588249Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"for j in range(2):\n    aug_images = [train_generator[0][0][j] for i in range(5)]\n    fig, axes = plt.subplots(1, 5, figsize=(24,24))\n    axes = axes.flatten()\n    for img, ax in zip(aug_images, axes):\n        ax.imshow(img)\n        ax.axis('off')\nplt.tight_layout()\nplt.show()","metadata":{"execution":{"iopub.status.busy":"2021-06-09T06:47:48.592045Z","iopub.execute_input":"2021-06-09T06:47:48.592431Z","iopub.status.idle":"2021-06-09T06:47:55.407922Z","shell.execute_reply.started":"2021-06-09T06:47:48.592399Z","shell.execute_reply":"2021-06-09T06:47:55.406643Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# Architecture","metadata":{}},{"cell_type":"code","source":"pre_model = Xception(weights='imagenet', \n                  include_top = False, \n                  input_shape=(img_size, img_size, 3))\npre_model.trainable=True","metadata":{"execution":{"iopub.status.busy":"2021-06-09T06:48:00.488312Z","iopub.execute_input":"2021-06-09T06:48:00.488667Z","iopub.status.idle":"2021-06-09T06:48:03.415033Z","shell.execute_reply.started":"2021-06-09T06:48:00.488638Z","shell.execute_reply":"2021-06-09T06:48:03.414161Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"x = pre_model.output\nx = GlobalAveragePooling2D()(x)\noutput = Dense(2, activation='softmax')(x)\nmodel = Model(pre_model.input, output)\n#model.summary()","metadata":{"execution":{"iopub.status.busy":"2021-06-09T06:48:08.073705Z","iopub.execute_input":"2021-06-09T06:48:08.074433Z","iopub.status.idle":"2021-06-09T06:48:08.175977Z","shell.execute_reply.started":"2021-06-09T06:48:08.074376Z","shell.execute_reply":"2021-06-09T06:48:08.171575Z"},"collapsed":true,"jupyter":{"outputs_hidden":true},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"#plot_model(model)","metadata":{"execution":{"iopub.status.busy":"2021-06-07T03:49:18.435003Z","iopub.execute_input":"2021-06-07T03:49:18.435333Z","iopub.status.idle":"2021-06-07T03:49:19.545043Z","shell.execute_reply.started":"2021-06-07T03:49:18.435304Z","shell.execute_reply":"2021-06-07T03:49:19.539047Z"},"collapsed":true,"jupyter":{"outputs_hidden":true},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"model.compile(Adam(lr=1e-3),loss='binary_crossentropy',metrics='accuracy')","metadata":{"execution":{"iopub.status.busy":"2021-06-09T06:48:24.517091Z","iopub.execute_input":"2021-06-09T06:48:24.517457Z","iopub.status.idle":"2021-06-09T06:48:24.537841Z","shell.execute_reply.started":"2021-06-09T06:48:24.517427Z","shell.execute_reply":"2021-06-09T06:48:24.536579Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"rlr = ReduceLROnPlateau(monitor = 'val_loss', factor = 0.1, patience = 2, verbose = 1, \n                                min_delta = 1e-4, min_lr = 1e-6, mode = 'min')\nes = EarlyStopping(monitor = 'val_loss', min_delta = 1e-4, patience = 5, mode = 'min', \n                    restore_best_weights = True, verbose = 1)\n\nckp = ModelCheckpoint('model.h5',monitor = 'val_loss',\n                      verbose = 0, save_best_only = True, mode = 'min')\n\nhistory = model.fit(\n      train_generator,\n      epochs=25,\n      validation_data=valid_generator,\n      callbacks=[es,rlr, ckp],\n      verbose=1)\n\nK.clear_session()","metadata":{"execution":{"iopub.status.busy":"2021-06-09T06:48:25.352086Z","iopub.execute_input":"2021-06-09T06:48:25.352526Z","iopub.status.idle":"2021-06-09T06:49:20.955524Z","shell.execute_reply.started":"2021-06-09T06:48:25.352491Z","shell.execute_reply":"2021-06-09T06:49:20.95293Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"actual =  valid_generator.labels\npreds = np.argmax(model.predict(valid_generator), axis=1)\ncfmx = confusion_matrix(actual, preds)\nacc = accuracy_score(actual, preds)\nprint ('Test Accuracy:', acc )\nprint('Confusion matrix:', cfmx)","metadata":{"execution":{"iopub.status.busy":"2021-06-07T05:27:31.761675Z","iopub.execute_input":"2021-06-07T05:27:31.762042Z","iopub.status.idle":"2021-06-07T05:28:31.281823Z","shell.execute_reply.started":"2021-06-07T05:27:31.762004Z","shell.execute_reply":"2021-06-07T05:28:31.280967Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"hist = pd.DataFrame(history.history)\nfig, (ax1, ax2) = plt.subplots(figsize=(12,12),nrows=2, ncols=1)\nhist['loss'].plot(ax=ax1,c='k',label='training loss')\nhist['val_loss'].plot(ax=ax1,c='r',linestyle='--', label='validation loss')\nax1.legend()\nhist['accuracy'].plot(ax=ax2,c='k',label='training accuracy')\nhist['val_accuracy'].plot(ax=ax2,c='r',linestyle='--',label='validation accuracy')\nax2.legend()\nplt.show()","metadata":{"execution":{"iopub.status.busy":"2021-06-07T05:28:31.284976Z","iopub.execute_input":"2021-06-07T05:28:31.285241Z","iopub.status.idle":"2021-06-07T05:28:31.597832Z","shell.execute_reply.started":"2021-06-07T05:28:31.285215Z","shell.execute_reply":"2021-06-07T05:28:31.597052Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"","metadata":{},"execution_count":null,"outputs":[]}]}