{"cells":[{"metadata":{},"cell_type":"markdown","source":"# Overview\n\nPneumonia is an infection in one or both lungs. The infection causes inflammation in the air sacs in your lungs, which are called **alveoli**. The alveoli fill with fluid or pus, making it difficult to breathe.\n\n![Pneumonia Inflammation](https://www.physio-pedia.com/images/9/94/Pneumonia_Inflammation.jpg)\n","execution_count":null},{"metadata":{},"cell_type":"markdown","source":"\nDoctors or radiologiests conduct a physical exam and use **CXR**(chest x-ray) to examin and detect pneumonia. In CXR it shows opacity in the reagion.\n\n![Pneumonia CXRs](https://ars.els-cdn.com/content/image/1-s2.0-S0092867418301545-figs6_lrg.jpg)\n\n\n* There are multiple causes of opacity n CXR other than pneumonia like;\n    * fluid overload (pulmonary edema)\n    * bleeding\n    * volume loss (atelectasis or collapse)\n    * lung cancer\n    * post-radiation or surgical changes\n    * Outside of the lungs, fluid in the pleural space (pleural effusion) \n\nA number of factors such as positioning of the patient and depth of inspiration can alter the appearance of the CXR.\n\n\n\nPneumonia opacity can occour in different reagions of chest and the opacity can be of different kinds. This makes it the problem of detection(regression) as well as recognition(classification). For such purpose we can think of using the pre-existing models like 'Faster R-CNN' or 'Yolo'.\n\n![Types and Regions](http://adigaskell.org/wp-content/uploads/2017/11/pneumonia-xray.jpg)\n\n\n","execution_count":null},{"metadata":{},"cell_type":"markdown","source":"## Table of Contents\n\n**- MileStone 1**\n- Pre-Processing,-Data-Visualisation,-EDA-and-Model-Building\n- Exploring-the-given-Data-files,-classes-and-images-of-different-classes\n- Imports\n- Load-images\n- Load-Labels\n- Load-Classes\n- Show-bounding-box-on-the-image-to-identify-pneumonia\n- Dealing-with-missing-values\n- Get-Target-Labels-and-Classes-into-one-dataset\n- Visualisation-of-different-classes\n- Show-image-of-class-'No-Lung-Opacity-/-Not-Normal\n- Show-image-of-class-'Normal'\n- Show-image-of-class-'Lung-Opacity'\n- Show-images-with-multiple-bounding-boxes-as-applicable\n- Analysis-from-the-visualisation-of-different-classes\n \n**- MileStone 2** \n- Build-Model\n       \n\n   ","execution_count":null},{"metadata":{},"cell_type":"markdown","source":"# Milestone 1: Pre-Processing, Data Visualisation, EDA and Model Building","execution_count":null},{"metadata":{},"cell_type":"markdown","source":"## Exploring the given Data files, classes and images of different classes.","execution_count":null},{"metadata":{},"cell_type":"markdown","source":"### Imports\n[Back to top](#Table-of-Contents)","execution_count":null},{"metadata":{"_uuid":"8f2839f25d086af736a60e9eeb907d3b93b6e0e5","_cell_guid":"b1076dfc-b9ad-4769-8c92-a6c4dae69d19","trusted":true},"cell_type":"code","source":"import numpy as np \nimport pandas as pd\nimport matplotlib.pyplot as plt\nfrom matplotlib.patches import Rectangle\nimport seaborn as sns\nimport gc\nimport glob\nimport os\nimport cv2\nimport pydicom\n\nimport warnings\nwarnings.simplefilter(action = 'ignore')","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"> ### Load Files\n","execution_count":null},{"metadata":{"trusted":true},"cell_type":"code","source":"detailed_df = pd.read_csv('/kaggle/input/rsna-pneumonia-detection-challenge/stage_2_detailed_class_info.csv')\ntrain_df = pd.read_csv('/kaggle/input/rsna-pneumonia-detection-challenge/stage_2_train_labels.csv')\n","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"\ndetailed_df.shape","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"\ntrain_df.shape","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"detailed_df.head()\n","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"train_df.head()\n","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"Merging the data tables detailed_df and train_df¶\n","execution_count":null},{"metadata":{"trusted":true},"cell_type":"code","source":"df = pd.concat([train_df,detailed_df[\"class\"]],axis=1,sort=False)\n\n# df = pd.merge(left = detailed_df, right = train_df, how = 'left', on = 'patientId')\ndf = df.drop_duplicates()\ndf.info()","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"Summary on the values, types and null values:¶\n","execution_count":null},{"metadata":{"trusted":true},"cell_type":"code","source":"df.shape\n","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"df.isnull().sum()","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"Distribution of classes\n\nThe following output shows that the nearly 2/3 of the patients do not have pneumonia (with target value = 0) and 1/3 of the patients have pneumonia (with target value =1)","execution_count":null},{"metadata":{"trusted":true},"cell_type":"code","source":"pd.pivot_table(df,index=[\"Target\"], values=['patientId'], aggfunc='count')","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"Distribution of patients in each class\nThere are 9555 patients in the category 'Lung Opacity' and 11821 in 'No Lung Opacity / Not Normal' category and 8851 are in Normal category","execution_count":null},{"metadata":{"trusted":true},"cell_type":"code","source":"pd.pivot_table(df,index=[\"class\"], values=['patientId'], aggfunc='count')","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"The classes \"No Lung Opacity / Not Normal\", \"Normal\", and \"Lung Opacity\" are in the proportion of 39%, 29% and 32% respectively","execution_count":null},{"metadata":{"trusted":true},"cell_type":"code","source":"df[\"class\"].value_counts().plot(kind='pie',autopct='%1.0f%%', shadow=True, subplots=False)","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"It is also clear from the below output that the patients who do not have pnuemonia do not have the bounding box coordinates","execution_count":null},{"metadata":{"trusted":true},"cell_type":"code","source":"pd.pivot_table(df,index=[\"Target\"], aggfunc='count')\n","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"Count of patients having single row and more than single rows¶\n","execution_count":null},{"metadata":{"trusted":true},"cell_type":"code","source":"df['patientId'].value_counts().value_counts()\n","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"Patients who do not have pneumonia has only one record in the table¶\n","execution_count":null},{"metadata":{"trusted":true},"cell_type":"code","source":"df[df['Target'] == 0]['patientId'].value_counts().value_counts()\n","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"sns.countplot(x = 'class', hue = 'Target', data = df)\n","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"Preprocessing - Filling the null values\n","execution_count":null},{"metadata":{"trusted":true},"cell_type":"code","source":"df.fillna(0.0)\n","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"Correlation between the variables\nThere is a strong Correlation between height and width variables","execution_count":null},{"metadata":{"trusted":true},"cell_type":"code","source":"df.corr()\n","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"sns.jointplot(x = 'width', y = 'height', data = df, kind=\"reg\")\n","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"## EDA with the header values from the dataframe\n* Creating a data frame with all of their appropriate header values from the dicom file takes long time as there are 30277 records. Hence, the EDA analysis is done on a subset of randomly chosen 1000 records by keeping the same proportion of the classes. (i.e) The classes Not Normal, Normal, Lunge Opacity are in a proportion 39%, 29%, and 32% respectively.\n\n* Number of rows of Not Normal class = 39% of 1000 = 390 rows\n* Number of rows of Normal class = 29% of 1000 = 290 rows\n* Number of rows of Lunge Opacity class = 32% of 1000 = 320 rows","execution_count":null},{"metadata":{"trusted":true},"cell_type":"code","source":"#df_Not_Normal = df[df['class']=='No Lung Opacity / Not Normal'].sample(n=390)\n#df_Normal = df[df['class']=='Normal'].sample(n=290)\n#df_Lunge_Opacity = df[df['class']=='Lung Opacity'].sample(n=320)\n#frames = [df_Not_Normal, df_Normal, df_Lunge_Opacity]\n\n#dicom_df = pd.concat(frames)\ndicom_df=df\ndicom_df.shape","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"from tqdm import tqdm\ndef process_dicom_data(data_df):\n    for n, pid in tqdm(enumerate(data_df['patientId'].unique())):        \n        dcm_file = '/kaggle/input/rsna-pneumonia-detection-challenge/stage_2_train_images/%s.dcm' % pid\n        dcm_data = pydicom.read_file(dcm_file)        \n        idx = (data_df['patientId']==dcm_data.PatientID)\n        data_df.loc[idx,'Modality'] = dcm_data.Modality\n        data_df.loc[idx,'PatientAge'] = pd.to_numeric(dcm_data.PatientAge)\n        data_df.loc[idx,'PatientSex'] = dcm_data.PatientSex\n        data_df.loc[idx,'BodyPartExamined'] = dcm_data.BodyPartExamined\n        data_df.loc[idx,'ViewPosition'] = dcm_data.ViewPosition\n        \n    return data_df","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"dicom_df = process_dicom_data(dicom_df)\n","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"dicom_df = dicom_df.astype({\"PatientAge\": int})\ndicom_df.fillna(0.0, inplace=True)\ndicom_df.head()","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"> There are 995 unique patient rows exist\n> ","execution_count":null},{"metadata":{"trusted":true},"cell_type":"code","source":"dicom_df.nunique()\n","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"## Now Visualizing the data along with their dicom header values\n","execution_count":null},{"metadata":{},"cell_type":"markdown","source":"Patient's age proportion in the detection\n","execution_count":null},{"metadata":{"trusted":true},"cell_type":"code","source":"plt.figure(figsize = (30, 10))\nsns.countplot(x = 'PatientAge', hue = 'Target', data = dicom_df)","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"Patient's gender proportion in the detection\n","execution_count":null},{"metadata":{"trusted":true},"cell_type":"code","source":"sns.countplot(x = 'PatientSex', hue = 'Target', data = dicom_df)\n","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"With respect to view proportion\n","execution_count":null},{"metadata":{"trusted":true},"cell_type":"code","source":"sns.countplot(x = 'ViewPosition', hue = 'Target', data = dicom_df);\n","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"dicom_df = dicom_df.drop('Target', axis=1)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"dicom_df['PatientSex'].astype('category')\ndicom_df['ViewPosition'].astype('category')\ndicom_df['PatientSex'] = np.where(dicom_df[\"PatientSex\"].str.contains(\"M\"), 1, 0)\ndicom_df['ViewPosition'] = np.where(dicom_df[\"ViewPosition\"].str.contains(\"AP\"), 1, 0)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"dicom_df.head()\n","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"Apart from the correlation between the width and height,there is no strong correlation between the other variables in the dataframe","execution_count":null},{"metadata":{"trusted":true},"cell_type":"code","source":"dicom_df.corr()\n","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"**Visualizing the dicom images**\n","execution_count":null},{"metadata":{"trusted":true},"cell_type":"code","source":"def show_dicom_image(data_df):\n        img_data = list(data_df.T.to_dict().values())\n        f, ax = plt.subplots(2,2, figsize=(16,18))\n        for i,data_row in enumerate(img_data):\n            pid = data_row['patientId']\n            dcm_file = '/kaggle/input/rsna-pneumonia-detection-challenge/stage_2_train_images/%s.dcm' % pid\n            dcm_data = pydicom.read_file(dcm_file)                    \n            ax[i//2, i%2].imshow(dcm_data.pixel_array, cmap=plt.cm.bone)\n            ax[i//2, i%2].set_title('ID: {}\\n Age: {} Sex: {}'.format(\n                data_row['patientId'],dcm_data.PatientAge, dcm_data.PatientSex))\n","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"show_dicom_image(df[df['Target']==1].sample(n=4))\n","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"> Showing some random dicom images of a patient who do not have Pnuemonia, however with class No Lung Opacity / Not Normal","execution_count":null},{"metadata":{"trusted":true},"cell_type":"code","source":"show_dicom_image(df[ (df['Target']==0) & (df['class']=='No Lung Opacity / Not Normal')].sample(n=4))","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"> Showing some random dicom images of a patients who do not have Pnuemonia, however with class Normal","execution_count":null},{"metadata":{"trusted":true},"cell_type":"code","source":"show_dicom_image(df[ (df['Target']==0) & (df['class']=='Normal')].sample(n=4))\n","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"def show_dicome_with_boundingbox(data_df):\n    img_data = list(data_df.T.to_dict().values())\n    f, ax = plt.subplots(2,2, figsize=(16,18))\n    for i,data_row in enumerate(img_data):\n        pid = data_row['patientId']\n        dcm_file = '/kaggle/input/rsna-pneumonia-detection-challenge/stage_2_train_images/%s.dcm' % pid\n        dcm_data = pydicom.read_file(dcm_file)                    \n        ax[i//2, i%2].imshow(dcm_data.pixel_array, cmap=plt.cm.bone)\n        ax[i//2, i%2].set_title('ID: {}\\n Age: {} Sex: {}'.format(\n                data_row['patientId'],dcm_data.PatientAge, dcm_data.PatientSex))\n        rows = data_df[data_df['patientId']==data_row['patientId']]\n        box_data = list(rows.T.to_dict().values())        \n        for j, row in enumerate(box_data):            \n            x,y,width,height = row['x'], row['y'],row['width'],row['height']\n            rectangle = Rectangle(xy=(x,y),width=width, height=height, color=\"red\",alpha = 0.1)\n            ax[i//2, i%2].add_patch(rectangle)    ","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"show_dicome_with_boundingbox(df[df['Target']==1].sample(n=4))\n","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"# MileStone 2\n# **Model Building**","execution_count":null},{"metadata":{},"cell_type":"markdown","source":"","execution_count":null},{"metadata":{"trusted":true},"cell_type":"code","source":"import os\nimport csv\nimport random\nimport pydicom\nimport numpy as np\nimport pandas as pd\nfrom skimage import measure\nfrom skimage.transform import resize\nimport matplotlib.patches as patches\nimport tensorflow as tf\nfrom tensorflow import keras\n","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"# Load pneumonia locations\n\nTable contains [filename : pneumonia location] pairs per row.\n\nIf a filename contains multiple pneumonia, the table contains multiple rows with the same filename but different pneumonia locations.\nIf a filename contains no pneumonia it contains a single row with an empty pneumonia location.\nThe code below loads the table and transforms it into a dictionary.\n\nThe dictionary uses the filename as key and a list of pneumonia locations in that filename as value.\nIf a filename is not present in the dictionary it means that it contains no pneumonia.","execution_count":null},{"metadata":{"trusted":true},"cell_type":"code","source":"pneumonia_locations = {}\n# load table\nwith open(os.path.join('/kaggle/input/rsna-pneumonia-detection-challenge/stage_2_train_labels.csv'), mode='r') as infile:\n    # open reader\n    reader = csv.reader(infile)\n    # skip header\n    next(reader, None)\n    # loop through rows\n    for rows in reader:\n        # retrieve information\n        filename = rows[0]\n        location = rows[1:5]\n        pneumonia = rows[5]\n        # if row contains pneumonia add label to dictionary\n        # which contains a list of pneumonia locations per filename\n        if pneumonia == '1':\n            # convert string to float to int\n            location = [int(float(i)) for i in location]\n            # save pneumonia location in dictionary\n            if filename in pneumonia_locations:\n                pneumonia_locations[filename].append(location)\n            else:\n                pneumonia_locations[filename] = [location]","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"## Load image filenames ","execution_count":null},{"metadata":{"trusted":true},"cell_type":"code","source":"# load and shuffle filenames\nfolder = '/kaggle/input/rsna-pneumonia-detection-challenge/stage_2_train_images'\nfilenames = os.listdir(folder)\nrandom.shuffle(filenames)\n# split into train and validation filenames\nn_valid_samples = 2560\ntrain_filenames = filenames[n_valid_samples:]\nvalid_filenames = filenames[:n_valid_samples]\nprint('n train samples', len(train_filenames))\nprint('n valid samples', len(valid_filenames))\nn_train_samples = len(filenames) - n_valid_samples","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"## Data generator\n\n\nThe dataset is too large to fit into memory, so we need to create a generator that loads data on the fly.\n\nThe generator takes in some filenames, batch_size and other parameters.\n\nThe generator outputs a random batch of numpy images and numpy masks.","execution_count":null},{"metadata":{"trusted":true},"cell_type":"code","source":"class generator(keras.utils.Sequence):    \n    def __init__(self, folder, filenames, pneumonia_locations=None, batch_size=32, image_size=256, shuffle=True, augment=False, predict=False):\n        self.folder = folder\n        self.filenames = filenames\n        self.pneumonia_locations = pneumonia_locations\n        self.batch_size = batch_size\n        self.image_size = image_size\n        self.shuffle = shuffle\n        self.augment = augment\n        self.predict = predict\n        self.on_epoch_end()\n        \n    def __load__(self, filename):\n        # load dicom file as numpy array\n        img = pydicom.dcmread(os.path.join(self.folder, filename)).pixel_array\n        # create empty mask\n        msk = np.zeros(img.shape)\n        # get filename without extension\n        filename = filename.split('.')[0]\n        # if image contains pneumonia\n        if filename in self.pneumonia_locations:\n            # loop through pneumonia\n            for location in self.pneumonia_locations[filename]:\n                # add 1's at the location of the pneumonia\n                x, y, w, h = location\n                msk[y:y+h, x:x+w] = 1\n        # resize both image and mask\n        img = resize(img, (self.image_size, self.image_size), mode='reflect')\n        msk = resize(msk, (self.image_size, self.image_size), mode='reflect') > 0.5\n        # if augment then horizontal flip half the time\n        if self.augment and random.random() > 0.5:\n            img = np.fliplr(img)\n            msk = np.fliplr(msk)\n        # add trailing channel dimension\n        img = np.expand_dims(img, -1)\n        msk = np.expand_dims(msk, -1)\n        return img, msk\n    \n    def __loadpredict__(self, filename):\n        # load dicom file as numpy array\n        img = pydicom.dcmread(os.path.join(self.folder, filename)).pixel_array\n        # resize image\n        img = resize(img, (self.image_size, self.image_size), mode='reflect')\n        # add trailing channel dimension\n        img = np.expand_dims(img, -1)\n        return img\n        \n    def __getitem__(self, index):\n        # select batch\n        filenames = self.filenames[index*self.batch_size:(index+1)*self.batch_size]\n        # predict mode: return images and filenames\n        if self.predict:\n            # load files\n            imgs = [self.__loadpredict__(filename) for filename in filenames]\n            # create numpy batch\n            imgs = np.array(imgs)\n            return imgs, filenames\n        # train mode: return images and masks\n        else:\n            # load files\n            items = [self.__load__(filename) for filename in filenames]\n            # unzip images and masks\n            imgs, msks = zip(*items)\n            # create numpy batch\n            imgs = np.array(imgs)\n            msks = np.array(msks)\n            return imgs, msks\n        \n    def on_epoch_end(self):\n        if self.shuffle:\n            random.shuffle(self.filenames)\n        \n    def __len__(self):\n        if self.predict:\n            # return everything\n            return int(np.ceil(len(self.filenames) / self.batch_size))\n        else:\n            # return full batches only\n            return int(len(self.filenames) / self.batch_size)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"# define iou or jaccard loss function\ndef iou_loss(y_true, y_pred):\n    #print(y_true)\n    y_true=tf.cast(y_true, tf.float32)\n    y_pred=tf.cast(y_pred, tf.float32)\n    y_true = tf.reshape(y_true, [-1])\n    y_pred = tf.reshape(y_pred, [-1])\n   \n    intersection = tf.reduce_sum(y_true * y_pred)\n    score = (intersection + 1.) / (tf.reduce_sum(y_true) + tf.reduce_sum(y_pred) - intersection + 1.)\n    return 1 - score\n\n# combine bce loss and iou loss\ndef iou_bce_loss(y_true, y_pred):\n    return 0.5 * keras.losses.binary_crossentropy(y_true, y_pred) + 0.5 * iou_loss(y_true, y_pred)\n\n# mean iou as a metric\ndef mean_iou(y_true, y_pred):\n    y_pred = tf.round(y_pred)\n    intersect = tf.reduce_sum(y_true * y_pred, axis=[1, 2, 3])\n    union = tf.reduce_sum(y_true, axis=[1, 2, 3]) + tf.reduce_sum(y_pred, axis=[1, 2, 3])\n    smooth = tf.ones(tf.shape(intersect))\n    return tf.reduce_mean((intersect + smooth) / (union - intersect + smooth))\n\ndef create_downsample(channels, inputs):\n    x = keras.layers.BatchNormalization(momentum=0.9)(inputs)\n    x = keras.layers.LeakyReLU(0)(x)\n    x = keras.layers.Conv2D(channels, 1, padding='same', use_bias=False)(x)\n    x = keras.layers.MaxPool2D(2)(x)\n    return x\n\ndef create_resblock(channels, inputs):\n    x = keras.layers.BatchNormalization(momentum=0.9)(inputs)\n    x = keras.layers.LeakyReLU(0)(x)\n    x = keras.layers.Conv2D(channels, 3, padding='same', use_bias=False)(x)\n    x = keras.layers.BatchNormalization(momentum=0.9)(x)\n    x = keras.layers.LeakyReLU(0)(x)\n    x = keras.layers.Conv2D(channels, 3, padding='same', use_bias=False)(x)\n    return keras.layers.add([x, inputs])\n\ndef create_network(input_size, channels, n_blocks=2, depth=4):\n    # input\n    inputs = keras.Input(shape=(input_size, input_size, 1))\n    x = keras.layers.Conv2D(channels, 3, padding='same', use_bias=False)(inputs)\n    # residual blocks\n    for d in range(depth):\n        channels = channels * 2\n        x = create_downsample(channels, x)\n        for b in range(n_blocks):\n            x = create_resblock(channels, x)\n    # output\n    x = keras.layers.BatchNormalization(momentum=0.9)(x)\n    x = keras.layers.LeakyReLU(0)(x)\n    x = keras.layers.Conv2D(1, 1, activation='sigmoid')(x)\n    outputs = keras.layers.UpSampling2D(2**depth)(x)\n    model = keras.Model(inputs=inputs, outputs=outputs)\n    return model\n","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"BATCH_SIZE = 128\nIMAGE_SIZE = 128","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"model = create_network(input_size=IMAGE_SIZE, channels=32, n_blocks=2, depth=4)\nmodel.compile(optimizer='adam', loss=iou_bce_loss, metrics=['accuracy', mean_iou])\n\n# cosine learning rate annealing\ndef cosine_annealing(x):\n    lr = 0.0001\n    epochs = 3\n    return lr*(np.cos(np.pi*x/epochs)+1.)/2\n\n\nlearning_rate = tf.keras.callbacks.LearningRateScheduler(cosine_annealing)\n\n# create train and validation generators\nfolder = '/kaggle/input/rsna-pneumonia-detection-challenge/stage_2_train_images'\ntrain_gen = generator(folder, train_filenames, pneumonia_locations, batch_size=BATCH_SIZE, image_size=IMAGE_SIZE, shuffle=True, augment=False, predict=False)\nvalid_gen = generator(folder, valid_filenames, pneumonia_locations, batch_size=BATCH_SIZE, image_size=IMAGE_SIZE, shuffle=False, predict=False)\n\nprint(model.summary())\n","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"EPOCHS=3\nMULTI_PROCESSING = True \n\nhistory = model.fit_generator(train_gen, validation_data=valid_gen, callbacks=[learning_rate], epochs=EPOCHS, workers=4, use_multiprocessing=True)\n","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"# Plot Accuracy / Loss","execution_count":null},{"metadata":{"trusted":true},"cell_type":"code","source":"plt.figure(figsize=(12,4))\nplt.subplot(131)\nplt.plot(history.epoch, history.history[\"loss\"], label=\"Train loss\")\nplt.plot(history.epoch, history.history[\"val_loss\"], label=\"Valid loss\")\nplt.legend()\nplt.subplot(132)\nplt.plot(history.epoch, history.history[\"accuracy\"], label=\"Train accuracy\")\nplt.plot(history.epoch, history.history[\"val_accuracy\"], label=\"Valid accuracy\")\nplt.legend()\nplt.subplot(133)\nplt.plot(history.epoch, history.history[\"mean_iou\"], label=\"Train iou\")\nplt.plot(history.epoch, history.history[\"val_mean_iou\"], label=\"Valid iou\")\nplt.legend()\nplt.show()\n","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"# Predict test images","execution_count":null},{"metadata":{"trusted":true},"cell_type":"code","source":"i=0\nfor imgs, msks in valid_gen:    \n    # predict batch of images\n    preds = model.predict(imgs)\n    # create figure\n    f, axarr = plt.subplots(4, 8, figsize=(20,15))\n    axarr = axarr.ravel()\n    axidx = 0\n    # loop through batch\n    for img, msk, pred in zip(imgs, msks, preds):\n        i=i+1\n        #exit after 32 images\n        if i>32:\n            break\n        # plot image\n        axarr[axidx].imshow(img[:, :, 0])\n        # threshold true mask\n        comp = msk[:, :, 0] > 0.5\n        # apply connected components\n        comp = measure.label(comp)\n        # apply bounding boxes\n        predictionString = ''\n        for region in measure.regionprops(comp):\n            # retrieve x, y, height and width\n            y, x, y2, x2 = region.bbox\n            height = y2 - y\n            width = x2 - x\n            axarr[axidx].add_patch(patches.Rectangle((x,y),width,height,linewidth=2,edgecolor='b',facecolor='none'))\n        # threshold predicted mask\n        comp = pred[:, :, 0] > 0.5\n        # apply connected components\n        comp = measure.label(comp)\n        # apply bounding boxes\n        predictionString = ''\n        for region in measure.regionprops(comp):\n            # retrieve x, y, height and width\n            y, x, y2, x2 = region.bbox\n            height = y2 - y\n            width = x2 - x\n            axarr[axidx].add_patch(patches.Rectangle((x,y),width,height,linewidth=2,edgecolor='r',facecolor='none'))\n        axidx += 1\n    plt.show()\n    # only plot one batch\n    break","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"folder = '/kaggle/input/rsna-pneumonia-detection-challenge/stage_2_test_images'\ntest_filenames = os.listdir(folder)\nprint('n test samples:', len(test_filenames))\n\n# create test generator with predict flag set to True\ntest_gen = generator(folder, test_filenames, None, batch_size=25, image_size=128, shuffle=False, predict=True)\n\n# create submission dictionary\nsubmission_dict = {}\n# loop through testset\nfor imgs, filenames in tqdm(test_gen):\n    # predict batch of images\n    preds = model.predict(imgs)\n    # loop through batch\n    for pred, filename in zip(preds, filenames):\n        # resize predicted mask\n        pred = resize(pred, (1024, 1024), mode='reflect')\n        # threshold predicted mask\n        comp = pred[:, :, 0] > 0.5\n        # apply connected components\n        comp = measure.label(comp)\n        # apply bounding boxes\n        predictionString = ''\n        for region in measure.regionprops(comp):\n            # retrieve x, y, height and width\n            y, x, y2, x2 = region.bbox\n            height = y2 - y\n            width = x2 - x\n            # proxy for confidence score\n            conf = np.mean(pred[y:y+height, x:x+width])\n            # add to predictionString\n            predictionString += str(conf) + ' ' + str(x) + ' ' + str(y) + ' ' + str(width) + ' ' + str(height) + ' '\n        # add filename and predictionString to dictionary\n        filename = filename.split('.')[0]\n        submission_dict[filename] = predictionString\n    # stop if we've got them all\n    if len(submission_dict) >= len(test_filenames):\n        break\n\n# save dictionary as csv file\nsub = pd.DataFrame.from_dict(submission_dict,orient='index')\nsub.index.names = ['patientId']\nsub.columns = ['PredictionString']\nsub.to_csv('submission.csv')","execution_count":null,"outputs":[]},{"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":4}