{"cells":[{"metadata":{"papermill":{"duration":0.042443,"end_time":"2020-10-06T14:31:40.941439","exception":false,"start_time":"2020-10-06T14:31:40.898996","status":"completed"},"tags":[]},"cell_type":"markdown","source":"# Imports"},{"metadata":{"_cell_guid":"b1076dfc-b9ad-4769-8c92-a6c4dae69d19","_uuid":"8f2839f25d086af736a60e9eeb907d3b93b6e0e5","execution":{"iopub.execute_input":"2020-10-06T14:31:41.030096Z","iopub.status.busy":"2020-10-06T14:31:41.029412Z","iopub.status.idle":"2020-10-06T14:31:42.371605Z","shell.execute_reply":"2020-10-06T14:31:42.370866Z"},"papermill":{"duration":1.389397,"end_time":"2020-10-06T14:31:42.371727","exception":false,"start_time":"2020-10-06T14:31:40.98233","status":"completed"},"tags":[],"trusted":true},"cell_type":"code","source":"import glob, pylab, pandas as pd\nimport pydicom, numpy as np\nfrom os import listdir\nfrom os.path import isfile, join\nimport matplotlib.pylab as plt\nimport os\nimport scipy\nimport seaborn as sns\nimport pickle\nimport math\nimport category_encoders as ce\nfrom sklearn.preprocessing import LabelEncoder \nfrom sklearn.preprocessing import OneHotEncoder \nfrom sklearn.compose import ColumnTransformer ","execution_count":null,"outputs":[]},{"metadata":{"papermill":{"duration":0.039472,"end_time":"2020-10-06T14:31:42.537738","exception":false,"start_time":"2020-10-06T14:31:42.498266","status":"completed"},"tags":[]},"cell_type":"markdown","source":"# **Loading the dataset**"},{"metadata":{"_cell_guid":"79c7e3d0-c299-4dcb-8224-4455121ee9b0","_uuid":"d629ff2d2480ee46fbb7e2d37f6b5fab8052498a","execution":{"iopub.execute_input":"2020-10-06T14:31:42.623107Z","iopub.status.busy":"2020-10-06T14:31:42.62248Z","iopub.status.idle":"2020-10-06T14:31:43.381128Z","shell.execute_reply":"2020-10-06T14:31:43.381636Z"},"papermill":{"duration":0.804026,"end_time":"2020-10-06T14:31:43.381803","exception":false,"start_time":"2020-10-06T14:31:42.577777","status":"completed"},"tags":[],"trusted":true},"cell_type":"code","source":"# Loading the dataset\n!ls ../input/rsna-intracranial-hemorrhage-detection/rsna-intracranial-hemorrhage-detection","execution_count":null,"outputs":[]},{"metadata":{"papermill":{"duration":0.040885,"end_time":"2020-10-06T14:31:43.464271","exception":false,"start_time":"2020-10-06T14:31:43.423386","status":"completed"},"tags":[]},"cell_type":"markdown","source":"> ### Read train csv file"},{"metadata":{"execution":{"iopub.execute_input":"2020-10-06T14:31:43.556917Z","iopub.status.busy":"2020-10-06T14:31:43.556165Z","iopub.status.idle":"2020-10-06T14:31:47.119689Z","shell.execute_reply":"2020-10-06T14:31:47.118831Z"},"papermill":{"duration":3.613862,"end_time":"2020-10-06T14:31:47.119833","exception":false,"start_time":"2020-10-06T14:31:43.505971","status":"completed"},"tags":[],"trusted":true},"cell_type":"code","source":"train_csv_file = pd.read_csv('../input/rsna-intracranial-hemorrhage-detection/rsna-intracranial-hemorrhage-detection/stage_2_train.csv')","execution_count":null,"outputs":[]},{"metadata":{"execution":{"iopub.execute_input":"2020-10-06T14:31:47.315117Z","iopub.status.busy":"2020-10-06T14:31:47.314465Z","iopub.status.idle":"2020-10-06T14:31:47.318329Z","shell.execute_reply":"2020-10-06T14:31:47.317832Z"},"papermill":{"duration":0.059102,"end_time":"2020-10-06T14:31:47.318455","exception":false,"start_time":"2020-10-06T14:31:47.259353","status":"completed"},"tags":[],"trusted":true},"cell_type":"code","source":"# size of training set\nprint(train_csv_file.shape)\nprint(train_csv_file.head)","execution_count":null,"outputs":[]},{"metadata":{"papermill":{"duration":0.042434,"end_time":"2020-10-06T14:31:47.4052","exception":false,"start_time":"2020-10-06T14:31:47.362766","status":"completed"},"tags":[]},"cell_type":"markdown","source":"# **Visualization**"},{"metadata":{"execution":{"iopub.execute_input":"2020-10-06T14:31:47.496338Z","iopub.status.busy":"2020-10-06T14:31:47.495634Z","iopub.status.idle":"2020-10-06T14:31:47.505879Z","shell.execute_reply":"2020-10-06T14:31:47.506366Z"},"papermill":{"duration":0.058375,"end_time":"2020-10-06T14:31:47.50653","exception":false,"start_time":"2020-10-06T14:31:47.448155","status":"completed"},"tags":[],"trusted":true},"cell_type":"code","source":"# Checking if label exists in all dataset\ntrain_csv_file.Label.isnull().sum()","execution_count":null,"outputs":[]},{"metadata":{"execution":{"iopub.execute_input":"2020-10-06T14:31:47.599063Z","iopub.status.busy":"2020-10-06T14:31:47.598431Z","iopub.status.idle":"2020-10-06T14:31:48.018673Z","shell.execute_reply":"2020-10-06T14:31:48.019104Z"},"papermill":{"duration":0.47039,"end_time":"2020-10-06T14:31:48.019281","exception":false,"start_time":"2020-10-06T14:31:47.548891","status":"completed"},"tags":[],"trusted":true},"cell_type":"code","source":"sns.countplot(train_csv_file.Label)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"train_csv_file.head","execution_count":null,"outputs":[]},{"metadata":{"execution":{"iopub.execute_input":"2020-10-06T14:32:16.932427Z","iopub.status.busy":"2020-10-06T14:32:16.581029Z","iopub.status.idle":"2020-10-06T14:32:22.453864Z","shell.execute_reply":"2020-10-06T14:32:22.453338Z"},"papermill":{"duration":5.925165,"end_time":"2020-10-06T14:32:22.453979","exception":false,"start_time":"2020-10-06T14:32:16.528814","status":"completed"},"tags":[],"trusted":true},"cell_type":"code","source":"# Get count of 0/1 for each subtype\nsubtype_counts = train_csv_file.groupby(\"Sub-type\").Label.value_counts().unstack()\n# print(subtype_counts)\n# \n# loc -> selects rows with same label\n# get count for ones for each sub-type / the total number of ones\nsubtype_counts = subtype_counts.loc[:, 1] / train_df.groupby(\"Sub-type\").size() * 100\n# print()\n# print(subtype_counts)\n# train_df.head()\nmulti_target_count = train_df.groupby(\"Image_ID\").Label.sum()\n\nfig, ax = plt.subplots(1,3,figsize=(20,5))\n\nsns.countplot(train_df.Label, ax=ax[0], palette=\"Reds\")\nax[0].set_xlabel(\"Binary label\")\nax[0].set_title(\"How often do we observe a positive label?\");\n\nsns.countplot(multi_target_count, ax=ax[1])\nax[1].set_xlabel(\"Number of targets per image\")\nax[1].set_ylabel(\"Frequency\")\nax[1].set_title(\"Multi-Hot occurences\")\n\nsns.barplot(x=subtype_counts.index, y=subtype_counts.values, ax=ax[2], palette=\"Set2\")\nplt.xticks(rotation=45); \nax[2].set_title(\"How much binary imbalance do we have?\")\nax[2].set_ylabel(\"% of positive occurences (1)\");","execution_count":null,"outputs":[]},{"metadata":{"papermill":{"duration":0.04552,"end_time":"2020-10-06T14:32:22.544905","exception":false,"start_time":"2020-10-06T14:32:22.499385","status":"completed"},"tags":[]},"cell_type":"markdown","source":"**Observation:**\n1. Number of positive examples is relatively low\n2. Probability of having more than one hemorrhage is lower\n3. Epidural class (label) has the least number of examples which will cause a slight problem "},{"metadata":{"papermill":{"duration":0.045296,"end_time":"2020-10-06T14:32:30.988707","exception":false,"start_time":"2020-10-06T14:32:30.943411","status":"completed"},"tags":[]},"cell_type":"markdown","source":"## What does pixel spacing mean? \n"},{"metadata":{"papermill":{"duration":0.046153,"end_time":"2020-10-06T14:32:37.935043","exception":false,"start_time":"2020-10-06T14:32:37.88889","status":"completed"},"tags":[]},"cell_type":"markdown","source":"*all pixel spacing related Attributes are encoded as the physical distance between the centers of each two-dimensional pixel, specified by two numeric values.The first value is the row spacing in mm, that is the spacing between the centers of adjacent rows, or vertical spacing.The second value is the column spacing in mm, that is the spacing between the centers of adjacent columns, or horizontal spacing.*\n\nConsequently it's related to the physical distance."},{"metadata":{"papermill":{"duration":0.042729,"end_time":"2020-10-06T14:31:48.10526","exception":false,"start_time":"2020-10-06T14:31:48.062531","status":"completed"},"tags":[]},"cell_type":"markdown","source":"> # **Creating pd table**"},{"metadata":{"trusted":true},"cell_type":"code","source":"duplicates_to_remove = [56340, 56341, 56342, 56343, 56344, 56345, 56346, 56347, 56348, 56349, 56350, 56351, 1171824, 1171825, 1171826, 1171827,\n 1171828, 1171829, 1171830, 1171831, 1171832, 1171833, 1171834, 1171835, 3705306, 3705307, 3705308, 3705309, 3705310,\n 3705311, 3705312, 3705313, 3705314, 3705315, 3705316, 3705317, 3842472, 3842473, 3842474, 3842475, 3842476, 3842477,\n 3842478, 3842479, 3842480, 3842481, 3842482, 3842483]\n","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"train_csv_file.shape\n# Output :  (4516842, 2)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"train_csv_file = train_csv_file.drop(index=duplicates_to_remove)\ntrain_csv_file = train_csv_file.reset_index(drop=True)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"train_csv_file.shape\n# Output : (4516794, 2)\n","execution_count":null,"outputs":[]},{"metadata":{"execution":{"iopub.execute_input":"2020-10-06T14:31:48.474837Z","iopub.status.busy":"2020-10-06T14:31:48.47414Z","iopub.status.idle":"2020-10-06T14:32:00.667675Z","shell.execute_reply":"2020-10-06T14:32:00.668569Z"},"papermill":{"duration":12.424712,"end_time":"2020-10-06T14:32:00.668766","exception":false,"start_time":"2020-10-06T14:31:48.244054","status":"completed"},"tags":[],"trusted":true},"cell_type":"code","source":"# IDs = train_csv_file['ID'].str.rsplit(\"_\", n=1, expand=True)[0]\n\n# print(IDs[0:10])","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"## **Creating one row in the dataframe for each image**"},{"metadata":{"trusted":true},"cell_type":"code","source":"# Creating 1 row for each img\n# Create new train Dataframe for training resnet with multilabel data\n\ndf_train_multilbl = pd.DataFrame(\n    columns=['ID','epidural', 'intraparenchymal', 'intraventricular', 'subarachnoid', 'subdural', 'any'])\n\n# cnt = 1\nfor img_idx in range(500000,750000):\n# for img_idx in range(18):\n    if img_idx%10000==0:\n        print(img_idx)\n    k = img_idx*6\n    ID_col_val =  train_csv_file.iloc[k]['ID']\n    img_name = 'ID_' + ID_col_val.split('_')[1] \n    imgID = ID_col_val.split('_')[1]\n    if len(ID_col_val.split('_')) == 3:\n#         print(cnt)\n#         cnt += 1\n        epidural_lbl = train_csv_file.iloc[k]['Label']\n        intraparenchymal_lbl = train_csv_file.iloc[k+1]['Label']\n        intraventricular_lbl = train_csv_file.iloc[k+2]['Label']\n        subarachnoid_lbl = train_csv_file.iloc[k+3]['Label']\n        subdural_lbl = train_csv_file.iloc[k+4]['Label']\n        any_lbl = train_csv_file.iloc[k+5]['Label']\n        df_train_multilbl = df_train_multilbl.append(\n            {'ID': img_name, \n             'epidural': epidural_lbl, \n             'intraparenchymal': intraparenchymal_lbl, \n             'intraventricular': intraventricular_lbl, \n             'subarachnoid': subarachnoid_lbl, \n             'subdural': subdural_lbl, \n             'any': any_lbl}, ignore_index=True)\n\nprint(df_train_multilbl.shape)\ndf_train_multilbl.head(10)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"filename = 'pickled_ds3'\ndf_train_multilbl.to_pickle(filename)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"df1 = pd.read_pickle('../input/dataframe/pickled_ds')\ndf2 = pd.read_pickle('../input/dataset/pickled_ds2')\ndf3 = pd.read_pickle('../input/dataset/pickled_ds3')","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"df_train_multilbl = pd.concat([df1, df2,df3])","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"print(df_train_multilbl.shape)\nprint(df_train_multilbl.head)","execution_count":null,"outputs":[]},{"metadata":{"papermill":{"duration":0.049093,"end_time":"2020-10-06T14:33:02.064816","exception":false,"start_time":"2020-10-06T14:33:02.015723","status":"completed"},"tags":[]},"cell_type":"markdown","source":"### **Converting np.array into a df**"},{"metadata":{"execution":{"iopub.execute_input":"2020-10-06T14:33:02.170439Z","iopub.status.busy":"2020-10-06T14:33:02.169785Z","iopub.status.idle":"2020-10-06T14:33:06.840476Z","shell.execute_reply":"2020-10-06T14:33:06.839908Z"},"papermill":{"duration":4.726641,"end_time":"2020-10-06T14:33:06.840605","exception":false,"start_time":"2020-10-06T14:33:02.113964","status":"completed"},"tags":[],"trusted":true},"cell_type":"code","source":"# # Order :  any,epidural,intraparenchymal,intraventricular,subarachnoid,subdural\n# dataset = pd.DataFrame({'Image_ID': result[:, 0],'Any':result[:, 1],'Epidural':result[:, 2],'Intraparenchymal':result[:, 3],\n#                         'Intraventricular':result[:, 4],'Subarachnoid':result[:, 5],'Subdural':result[:, 6],'Label': result[:, 7]})\n\n# print(dataset.head)","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"## **Selecting subset from dataset**"},{"metadata":{"trusted":true},"cell_type":"code","source":" df_train_multilbl.loc[(df_train_multilbl[\"epidural\"] == 1)].shape","execution_count":null,"outputs":[]},{"metadata":{"execution":{"iopub.execute_input":"2020-10-06T14:33:07.603152Z","iopub.status.busy":"2020-10-06T14:33:07.399843Z","iopub.status.idle":"2020-10-06T14:33:10.443793Z","shell.execute_reply":"2020-10-06T14:33:10.443098Z"},"papermill":{"duration":3.387548,"end_time":"2020-10-06T14:33:10.443912","exception":false,"start_time":"2020-10-06T14:33:07.056364","status":"completed"},"tags":[],"trusted":true},"cell_type":"code","source":"#-H- Take 3000 of each and 15000 of any\nepidural = df_train_multilbl.loc[(df_train_multilbl[\"epidural\"] == 1)][0:3136]\nintraparenchymal = df_train_multilbl.loc[(df_train_multilbl[\"intraparenchymal\"] == 1)][0:3136]\nintraventricular = df_train_multilbl.loc[(df_train_multilbl[\"intraventricular\"] == 1)][0:3136]\nsubarachnoid = df_train_multilbl.loc[(df_train_multilbl[\"subarachnoid\"] == 1)][0:3136]\nsubdural = df_train_multilbl.loc[(df_train_multilbl[\"subdural\"] == 1)][0:3136]\nno_label = df_train_multilbl.loc[(df_train_multilbl[\"any\"] == 0)][0:9000]\n","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"print(epidural.shape)\nprint(intraparenchymal.shape)\nprint(intraventricular.shape)\nprint(subarachnoid.shape)\nprint(subdural.shape)\nprint(no_label.shape)","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"### **Concatenating 5 subtypes & any = 0**"},{"metadata":{"execution":{"iopub.execute_input":"2020-10-06T14:33:10.552355Z","iopub.status.busy":"2020-10-06T14:33:10.549475Z","iopub.status.idle":"2020-10-06T14:33:10.574142Z","shell.execute_reply":"2020-10-06T14:33:10.574847Z"},"papermill":{"duration":0.081387,"end_time":"2020-10-06T14:33:10.575042","exception":false,"start_time":"2020-10-06T14:33:10.493655","status":"completed"},"tags":[],"trusted":true},"cell_type":"code","source":"selected_ds=pd.concat([epidural, intraparenchymal,intraventricular,subarachnoid,subdural,no_label])\nselected_ds.shape\nprint(selected_ds.head)","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"### **Removing Duplicates from selected_ds**"},{"metadata":{"trusted":true},"cell_type":"code","source":"selected_ds.drop_duplicates(subset =\"ID\", keep = False, inplace = True) \nselected_ds.shape\n# before dropping [23000 rows x 7 columns]>\n# after dropping (17455, 7)","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"### **Saving all needed Images_ID**"},{"metadata":{"execution":{"iopub.execute_input":"2020-10-06T14:33:12.165459Z","iopub.status.busy":"2020-10-06T14:33:12.164621Z","iopub.status.idle":"2020-10-06T14:33:12.168591Z","shell.execute_reply":"2020-10-06T14:33:12.167759Z"},"papermill":{"duration":0.092509,"end_time":"2020-10-06T14:33:12.168715","exception":false,"start_time":"2020-10-06T14:33:12.076206","status":"completed"},"tags":[],"trusted":true},"cell_type":"code","source":"images_id = selected_ds['ID']\nprint(len(images_id))","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"# # Save IDS nparray\n# with open('images_id.npy', 'wb') as f:\n#     np.save(f, images_id)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"import random\n# selected_ds is the df of all data\nl = [ i for i in range(0,selected_ds.shape[0])]\nl_shuffled = random.sample(l, len(l))\nlength = len(l_shuffled)\n# indices of training\nind_train = l_shuffled[0:(math.ceil(0.8*length))]\n# indices of validation\nind_valid = l_shuffled[(math.ceil(0.8*length)):(math.ceil(0.9*length))]\n# indices of testing\nind_test = l_shuffled[(math.ceil(0.9*length)):]","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"print(len(ind_train))\nprint(len(ind_valid))\nprint(len(ind_test))","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"## **Preprocessing Functions**"},{"metadata":{"papermill":{"duration":0.065802,"end_time":"2020-10-06T14:33:15.403146","exception":false,"start_time":"2020-10-06T14:33:15.337344","status":"completed"},"tags":[]},"cell_type":"markdown","source":"## Rescale to HU:\nThe Hounsfield unit (HU) is a relative quantitative measurement of radio density used by radiologists in the interpretation of computed tomography (CT) images. The absorption/attenuation coefficient of radiation within a tissue is used during CT reconstruction to produce a grayscale image.\n\nFor rescaling : We will just need to multiply the values by the slope (dicom.RescaleSlope) and add the intercept (dicom.RescaleIntercept)."},{"metadata":{"execution":{"iopub.execute_input":"2020-10-06T14:33:15.540939Z","iopub.status.busy":"2020-10-06T14:33:15.539896Z","iopub.status.idle":"2020-10-06T14:33:15.542918Z","shell.execute_reply":"2020-10-06T14:33:15.54233Z"},"papermill":{"duration":0.071512,"end_time":"2020-10-06T14:33:15.543039","exception":false,"start_time":"2020-10-06T14:33:15.471527","status":"completed"},"tags":[],"trusted":true},"cell_type":"code","source":"def image_to_hu(dicom):\n\n    image = dicom.pixel_array.astype(np.float64)\n         \n    # Convert to Hounsfield units (HU)\n    intercept = dicom.RescaleIntercept\n    slope = dicom.RescaleSlope\n    \n    if slope != 1:\n        image = slope * image.astype(np.float64)\n        image = image.astype(np.float64)\n        \n    image += np.float64(intercept)\n    \n    image[image < -1024] = -1024 # Setting values smaller than air, to air.\n    # Values smaller than -1024, are probably just outside the scanner.\n    return image","execution_count":null,"outputs":[]},{"metadata":{"papermill":{"duration":0.061348,"end_time":"2020-10-06T14:33:15.666367","exception":false,"start_time":"2020-10-06T14:33:15.605019","status":"completed"},"tags":[]},"cell_type":"markdown","source":"## **Windowing**"},{"metadata":{"papermill":{"duration":0.061311,"end_time":"2020-10-06T14:33:15.789566","exception":false,"start_time":"2020-10-06T14:33:15.728255","status":"completed"},"tags":[]},"cell_type":"markdown","source":"Although, we can interpret the values in the image now, we cannot really see anything in the image. But now we can look at a certain value range, which we now is interesting. Typically this is done by a process called windowing, where the image is basically clipped to a certain value range. Which is defined as:\n\nWindowLength ± WindowWidth2 \n\nA range in Hounsfield Units that might be interesting to look at is a width of 80 and a center of 40, described as useful for analyses of brains (source: https://radiopaedia.org/articles/windowing-ct), as well as a width of 130 and a center of 50."},{"metadata":{"execution":{"iopub.execute_input":"2020-10-06T14:33:15.922252Z","iopub.status.busy":"2020-10-06T14:33:15.921461Z","iopub.status.idle":"2020-10-06T14:33:15.92442Z","shell.execute_reply":"2020-10-06T14:33:15.923881Z"},"papermill":{"duration":0.073376,"end_time":"2020-10-06T14:33:15.924542","exception":false,"start_time":"2020-10-06T14:33:15.851166","status":"completed"},"tags":[],"trusted":true},"cell_type":"code","source":"def image_windowed(image, custom_center=50, custom_width=130, out_side_val=False):\n    '''\n    Important thing to note in this function: The image migth be changed in place!\n    '''\n    # see: https://www.kaggle.com/allunia/rsna-ih-detection-eda-baseline\n    min_value = custom_center - (custom_width/2)\n    max_value = custom_center + (custom_width/2)\n    \n    # Including another value for values way outside the range, to (hopefully) make segmentation processes easier. \n    out_value_min = custom_center - custom_width\n    out_value_max = custom_center + custom_width\n    \n    if out_side_val:\n        image[np.logical_and(image < min_value, image > out_value_min)] = min_value\n        image[np.logical_and(image > max_value, image < out_value_max)] = max_value\n        image[image < out_value_min] = out_value_min\n        image[image > out_value_max] = out_value_max\n    \n    else:\n        image[image < min_value] = min_value\n        image[image > max_value] = max_value\n    \n    return image","execution_count":null,"outputs":[]},{"metadata":{"papermill":{"duration":0.06163,"end_time":"2020-10-06T14:33:16.047949","exception":false,"start_time":"2020-10-06T14:33:15.986319","status":"completed"},"tags":[]},"cell_type":"markdown","source":"## Resample images : "},{"metadata":{"papermill":{"duration":0.062053,"end_time":"2020-10-06T14:33:16.172058","exception":false,"start_time":"2020-10-06T14:33:16.110005","status":"completed"},"tags":[]},"cell_type":"markdown","source":"Slice Thickness: 2.500000\nPixel Spacing (row, col): (0.722656, 0.722656) \n\nThis means we have 2.5 mm slices, and each voxel represents 0.7 mm.\n\nBecause a CT slice is typically reconstructed at 512 x 512 voxels, each slice represents approximately 370 mm of data in length and width.\n\nUsing the metadata from the DICOM we can figure out the size of each voxel as the slice thickness. It would be useful to ensure that each slice is resampled in 1x1x1 mm pixels and slices."},{"metadata":{"execution":{"iopub.execute_input":"2020-10-06T14:33:16.303991Z","iopub.status.busy":"2020-10-06T14:33:16.303089Z","iopub.status.idle":"2020-10-06T14:33:16.305887Z","shell.execute_reply":"2020-10-06T14:33:16.305255Z"},"papermill":{"duration":0.072258,"end_time":"2020-10-06T14:33:16.306034","exception":false,"start_time":"2020-10-06T14:33:16.233776","status":"completed"},"tags":[],"trusted":true},"cell_type":"code","source":"def image_resample(image, dicom_header, new_spacing=[1,1]):\n    # Code from https://www.raddq.com/dicom-processing-segmentation-visualization-in-python/\n    # Adapted to work for pixels.\n    spacing = map(float, dicom_header.PixelSpacing)\n    spacing = np.array(list(spacing))\n    resize_factor = spacing / new_spacing\n    new_real_shape = image.shape * resize_factor\n    new_shape = np.round(new_real_shape)\n    real_resize_factor = new_shape / image.shape\n    new_spacing = spacing / real_resize_factor\n    \n    image = scipy.ndimage.interpolation.zoom(image, real_resize_factor)\n    \n    return image","execution_count":null,"outputs":[]},{"metadata":{"papermill":{"duration":0.061434,"end_time":"2020-10-06T14:33:16.431642","exception":false,"start_time":"2020-10-06T14:33:16.370208","status":"completed"},"tags":[]},"cell_type":"markdown","source":"## Cropping images:"},{"metadata":{"papermill":{"duration":0.062402,"end_time":"2020-10-06T14:33:16.555999","exception":false,"start_time":"2020-10-06T14:33:16.493597","status":"completed"},"tags":[]},"cell_type":"markdown","source":"numpy.nonzero()function is used to Compute the indices of the elements that are non-zero.\n\nIt returns a tuple of arrays, one for each dimension of arr, containing the indices of the non-zero elements in that dimension."},{"metadata":{"execution":{"iopub.execute_input":"2020-10-06T14:33:16.687204Z","iopub.status.busy":"2020-10-06T14:33:16.686361Z","iopub.status.idle":"2020-10-06T14:33:16.689221Z","shell.execute_reply":"2020-10-06T14:33:16.688692Z"},"papermill":{"duration":0.071504,"end_time":"2020-10-06T14:33:16.689336","exception":false,"start_time":"2020-10-06T14:33:16.617832","status":"completed"},"tags":[],"trusted":true},"cell_type":"code","source":"def image_crop(image):\n    # Based on this stack overflow post: https://stackoverflow.com/questions/26310873/how-do-i-crop-an-image-on-a-white-background-with-python\n    # mask is a matrix with pixels = 0 (black) will be set to 1\n    mask = image == 0\n\n    # Find the bounding box of those pixels\n    # now the inside of the image is the inverted and the outside is zeros \n    coords = np.array(np.nonzero(~mask))\n    top_left = np.min(coords, axis=1)\n    bottom_right = np.max(coords, axis=1)\n\n    out = image[top_left[0]:bottom_right[0],\n                top_left[1]:bottom_right[1]]\n    \n    return out","execution_count":null,"outputs":[]},{"metadata":{"papermill":{"duration":0.061479,"end_time":"2020-10-06T14:33:16.812637","exception":false,"start_time":"2020-10-06T14:33:16.751158","status":"completed"},"tags":[]},"cell_type":"markdown","source":"## **Padding**"},{"metadata":{"papermill":{"duration":0.061233,"end_time":"2020-10-06T14:33:16.935637","exception":false,"start_time":"2020-10-06T14:33:16.874404","status":"completed"},"tags":[]},"cell_type":"markdown","source":"Bring images back to equal spacing\nPading the images puts the brain in the center and keeps the resampled voxel dimensions. A further thing to test out, might be to resize the images to fill out the whole space."},{"metadata":{"execution":{"iopub.execute_input":"2020-10-06T14:33:17.066489Z","iopub.status.busy":"2020-10-06T14:33:17.065794Z","iopub.status.idle":"2020-10-06T14:33:17.068729Z","shell.execute_reply":"2020-10-06T14:33:17.068067Z"},"papermill":{"duration":0.071563,"end_time":"2020-10-06T14:33:17.068842","exception":false,"start_time":"2020-10-06T14:33:16.997279","status":"completed"},"tags":[],"trusted":true},"cell_type":"code","source":"def image_pad(image, new_height = 512, new_width = 512):\n    # based on https://stackoverflow.com/questions/26310873/how-do-i-crop-an-image-on-a-white-background-with-python\n    height, width = image.shape\n\n    # make canvas\n    im_bg = np.zeros((new_height, new_width))\n\n    # Your work: Compute where it should be\n    pad_left = int( (new_width - width) / 2)\n    pad_top = int( (new_height - height) / 2)\n\n    im_bg[pad_top:pad_top + height,\n          pad_left:pad_left + width] = image\n\n    return im_bg","execution_count":null,"outputs":[]},{"metadata":{"papermill":{"duration":0.066725,"end_time":"2020-10-06T14:33:17.198709","exception":false,"start_time":"2020-10-06T14:33:17.131984","status":"completed"},"tags":[]},"cell_type":"markdown","source":"## Resize to same dimensions:"},{"metadata":{"execution":{"iopub.execute_input":"2020-10-06T14:33:17.329469Z","iopub.status.busy":"2020-10-06T14:33:17.328738Z","iopub.status.idle":"2020-10-06T14:33:17.556187Z","shell.execute_reply":"2020-10-06T14:33:17.55548Z"},"papermill":{"duration":0.29534,"end_time":"2020-10-06T14:33:17.556315","exception":false,"start_time":"2020-10-06T14:33:17.260975","status":"completed"},"tags":[],"trusted":true},"cell_type":"code","source":"# image here is ds.pixel_array.\nfrom skimage.transform import resize\ndef resize_image(img, IMG_PX_SIZE=32):\n#     print(img.shape)\n    resized_img = resize(img, (IMG_PX_SIZE, IMG_PX_SIZE))\n#     print(resized_img.shape)\n    return resized_img","execution_count":null,"outputs":[]},{"metadata":{"papermill":{"duration":0.052567,"end_time":"2020-10-06T14:33:12.274283","exception":false,"start_time":"2020-10-06T14:33:12.221716","status":"completed"},"tags":[]},"cell_type":"markdown","source":"# **Dealing with DOCIM**"},{"metadata":{"execution":{"iopub.execute_input":"2020-10-06T14:33:12.520844Z","iopub.status.busy":"2020-10-06T14:33:12.511156Z","iopub.status.idle":"2020-10-06T14:33:12.525196Z","shell.execute_reply":"2020-10-06T14:33:12.524274Z"},"papermill":{"duration":0.080402,"end_time":"2020-10-06T14:33:12.52536","exception":false,"start_time":"2020-10-06T14:33:12.444958","status":"completed"},"tags":[],"trusted":true},"cell_type":"code","source":"# Get list of paths for total_imgs\n# images_id = train_images_dir + id + .dcm \ntrain_images_dir = '../input/rsna-intracranial-hemorrhage-detection/rsna-intracranial-hemorrhage-detection/stage_2_train/'\nimg_paths = []\nfor image_id in images_id:\n    file = train_images_dir+image_id+'.dcm'\n    img_paths.append(file)\n    \nprint(len(img_paths))","execution_count":null,"outputs":[]},{"metadata":{"execution":{"iopub.execute_input":"2020-10-06T14:33:12.646631Z","iopub.status.busy":"2020-10-06T14:33:12.645864Z","iopub.status.idle":"2020-10-06T14:33:12.724725Z","shell.execute_reply":"2020-10-06T14:33:12.724057Z"},"papermill":{"duration":0.145559,"end_time":"2020-10-06T14:33:12.724844","exception":false,"start_time":"2020-10-06T14:33:12.579285","status":"completed"},"tags":[],"trusted":true},"cell_type":"code","source":"# Reading  docim images\n# + Preprocessing\n# m = 10\nimg_list = []\nfor path in img_paths:\n    ds = pydicom.dcmread(path)\n    im = ds.pixel_array\n    # Hounsfield     \n    im = image_to_hu(ds)\n    # Windowing\n    im = image_windowed(im)\n    # Resampling\n    im = image_resample(im, ds)\n    # Cropping    \n#     im = image_crop(im)\n#     # Padding\n#     im = image_pad(im)\n    # Resizing\n    im = resize_image(im,64)\n    img_list.append(im)\n\nimg_array = np.asarray(img_list) \nprint('done reading images')\nprint(img_array.shape)","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"## **Converting Images to 3 Channels**"},{"metadata":{"trusted":true},"cell_type":"code","source":"#convert to 3 channels\nimg_array = np.repeat(img_array[..., np.newaxis], 3, -1)\nimg_array.shape","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"## **Creating train/validation/test images and labels**"},{"metadata":{"trusted":true},"cell_type":"code","source":"selected_ds = selected_ds.drop('ID', axis=1)\nselected_ds = selected_ds.drop('any', axis=1)","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"**Convert to numpy float32**"},{"metadata":{"trusted":true},"cell_type":"code","source":"img_array = np.asarray(img_array).astype(np.float32)\nselected_ds = np.asarray(selected_ds).astype(np.float32)\n","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"selected_ds.shape","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"#After reading img_array\ntrain_images = [img_array[i] for i in ind_train]\nvalid_images = [img_array[i] for i in ind_valid]\ntest_images = [img_array[i] for i in ind_test]\n\ntrain_labels = [selected_ds[i] for i in ind_train]\nvalid_labels = [selected_ds[i] for i in ind_valid]\ntest_labels = [selected_ds[i] for i in ind_test]","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"train_labels = np.asarray(train_labels).astype(np.float32)\ntrain_images = np.asarray(train_images).astype(np.float32)\nvalid_labels = np.asarray(train_labels).astype(np.float32)\nvalid_images = np.asarray(train_images).astype(np.float32)\ntest_labels = np.asarray(train_labels).astype(np.float32)\ntest_images = np.asarray(train_images).astype(np.float32)","execution_count":null,"outputs":[]},{"metadata":{"execution":{"iopub.execute_input":"2020-10-06T14:33:13.09237Z","iopub.status.busy":"2020-10-06T14:33:13.091696Z","iopub.status.idle":"2020-10-06T14:33:13.094607Z","shell.execute_reply":"2020-10-06T14:33:13.094036Z"},"papermill":{"duration":0.062469,"end_time":"2020-10-06T14:33:13.094757","exception":false,"start_time":"2020-10-06T14:33:13.032288","status":"completed"},"tags":[],"trusted":true},"cell_type":"code","source":"for i in range(0,5):\n    plt.imshow(img_list[i],cmap=plt.cm.bone)\n    plt.figure(i+1)\n\nplt.show()","execution_count":null,"outputs":[]},{"metadata":{"papermill":{"duration":0.061775,"end_time":"2020-10-06T14:33:17.680331","exception":false,"start_time":"2020-10-06T14:33:17.618556","status":"completed"},"tags":[]},"cell_type":"markdown","source":"# **Building a Neural Network**"},{"metadata":{"trusted":true},"cell_type":"code","source":"from keras.applications import ResNet50,ResNet101\nfrom tensorflow import Tensor\nfrom keras import layers\nfrom keras.models import Sequential\nfrom keras.optimizers import Adam\nfrom tensorflow.keras.layers import Input, Conv2D, ReLU, BatchNormalization,\\\n                                    Add, AveragePooling2D, Flatten, Dense\nfrom tensorflow.keras.models import Model\n\nfrom keras.models import Sequential\nfrom keras.layers import Dense, Dropout, Flatten\nfrom keras.layers import Conv2D, MaxPooling2D, BatchNormalization\n","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"1. **Turn internet on to download densenet (or any pretrained weights) because it's off by default on Kaggle**\n"},{"metadata":{},"cell_type":"markdown","source":"> *In the context of transfer learning, standard architectures designed for ImageNet with corresponding pretrained weights are fine-tuned on medical tasks ranging from interpreting chest x-rays and identifying eye diseases, to early detection of Alzheimer’s disease.*\n> *Most published deep learning models for healthcare data analysis are pretrained on ImageNet, Cifar10, etc. Pretraining most times does not necessarily need to be done on dataset of similar domain but just to give a model a general context about objects. This has been proven to fasten convergence of deep models than training from scratch.*"},{"metadata":{"trusted":true},"cell_type":"code","source":"resnet = ResNet101(\n    weights='imagenet',\n    include_top=False,\n    input_shape=(64,64,3),\n)","execution_count":null,"outputs":[]},{"metadata":{"execution":{"iopub.execute_input":"2020-10-06T14:33:17.809313Z","iopub.status.busy":"2020-10-06T14:33:17.808619Z","iopub.status.idle":"2020-10-06T14:33:17.811404Z","shell.execute_reply":"2020-10-06T14:33:17.81078Z"},"papermill":{"duration":0.069124,"end_time":"2020-10-06T14:33:17.81152","exception":false,"start_time":"2020-10-06T14:33:17.742396","status":"completed"},"tags":[],"trusted":true},"cell_type":"code","source":"# Initializations\nBATCH_SIZE = 32\nEPOCHS = 5\nlearning_rate=1e-3\n","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"# Resnet pretrained - AvgPool - Flatten - FC - Sigmoid\ndef build_model():\n    model = Sequential()\n    model.add(resnet)\n    model.add(layers.GlobalAveragePooling2D())\n    model.add(layers.Dropout(0.5))\n    model.add(layers.Dense(5, activation='sigmoid'))\n    model.compile(loss='binary_crossentropy',optimizer=Adam(lr=learning_rate), metrics=['accuracy'])\n    \n    return model","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"# fit the keras model on the dataset\nmodel = build_model()\nmodel.fit(train_images, train_labels, epochs=EPOCHS, batch_size=BATCH_SIZE)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"# evaluate the keras model\n_, accuracy = model.evaluate(valid_images, valid_labels)\nprint('Accuracy: %.2f' % (accuracy*100))","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"## **Second NN Model**"},{"metadata":{"trusted":true},"cell_type":"code","source":"\nmodel2 = Sequential()\nmodel2.add(Conv2D(32, kernel_size=(3, 3), activation='relu', input_shape=(64,64,3)))\nmodel2.add(BatchNormalization())\n\nmodel2.add(Conv2D(32, kernel_size=(3, 3), activation='relu'))\nmodel2.add(BatchNormalization())\nmodel2.add(MaxPooling2D(pool_size=(2, 2)))\n\nmodel2.add(Conv2D(64, kernel_size=(3, 3), activation='relu'))\nmodel2.add(BatchNormalization())\nmodel2.add(Dropout(0.25))\n\nmodel2.add(Conv2D(128, kernel_size=(3, 3), activation='relu'))\nmodel2.add(BatchNormalization())\nmodel2.add(Dropout(0.25))\n\n\nmodel2.add(Conv2D(256, kernel_size=(3, 3), activation='relu'))\nmodel2.add(BatchNormalization())\nmodel2.add(MaxPooling2D(pool_size=(2, 2)))\nmodel2.add(Dropout(0.25))\n\n\nmodel2.add(Flatten())\n\nmodel2.add(Dense(512, activation='relu'))\nmodel2.add(BatchNormalization())\nmodel2.add(Dropout(0.25))\n\nmodel2.add(Dense(128, activation='relu'))\nmodel2.add(BatchNormalization())\nmodel2.add(Dropout(0.5))\n\n\nmodel2.add(Dense(5, activation='sigmoid'))\n\nmodel2.compile(loss='binary_crossentropy',optimizer=Adam(lr=learning_rate), metrics=['accuracy'])\n","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"model2.fit(train_images, train_labels, epochs=EPOCHS, batch_size=BATCH_SIZE)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"# evaluate the keras model\n_, accuracy = model2.evaluate(valid_images, valid_labels)\nprint('Accuracy: %.2f' % (accuracy*100))","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"## NOTES : \n### pre-trained Model:\n1. using batch size = 32 and epoch = 5 ,image is 32x32 accuracy:15% and loss : 0.6  TOO MUCH \n\n* Binary cross-entropy is for multi-label classifications, whereas categorical cross entropy is for multi-class classification where each example belongs to a single class.\n\n2. increase size = 64 * 64 and removing padding and cropping  and use binary cross entropy instead of categorical:\n    loss decreased to : 0.2 and accuracy increased but 5% \n3. Shuffled data splitting and added more epidural examples (3000) any=0 (8000) Loss : 0.3262 Training Accuracy:35% Dev Acc:23%\n4. Added more data (136 images for each type of hemorrhage) acc = 27 % (first epoch) --> no change\n5. Using resnet101 instad of resnet50 acc increased to 37% , dev acc :31%\n\n\n### Implemented Model: \n1. batch size =32, epochs= 5 accuracy:30% and loss: 0.3495  dev acc :61%\n2. add 1 more layer accuracy:30%, dev acc: 42%\n3. decreased dense layer dropout to 0.25 instead 0.5 and removed dropout from conv layer accuracy:32%, dev acc:42%\n\n\n\nTODO :\n1. Reading more data as epidural hemorrhage is just 900 **--DONE--**\n2. Don't save numpy array **--DONE--**\n3. Shuffle data after preprocessing ( cancel sorting) **--DONE--**\n4. Check Cropping and Padding **--( better without )--**\n5. Change imagenet to a different pretrained \n6. Create model"},{"metadata":{"trusted":true},"cell_type":"code","source":"# make probability predictions with the model\npredictions = model.predict(test_images)\npredictions=(predictions>0.5).astype(int)\n\n","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"predictions2 = model2.predict(test_images)\npredictions2=(predictions2>0.5).astype(int)\n\n","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"from sklearn.metrics import accuracy_score,precision_score,recall_score,f1_score\n","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"#model 1 test accuracy\naccuracy = accuracy_score(test_labels, predictions)\nprint('Accuracy: %f' % accuracy*100)\n\n#Accuracy: 0.532738\n","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"#model 2 test accuracy\naccuracy2 = accuracy_score(test_labels, predictions2)\nprint('Accuracy: %f' % accuracy2)\n\n#Accuracy: 0.477249\n","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}