{"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":"# Overview\n\nThe aim of the project is the detection of bounding boxes corresponding to the diagnosis of pneumonia (e.g. lung infection) on chest radiographs.\n\nI have used Google Colab to do this project, in turn explore the possibilites of Colab","metadata":{"id":"IuoqPDzCW2F2"}},{"cell_type":"markdown","source":"## Data Loading","metadata":{"id":"ARBhoNRfbNcU"}},{"cell_type":"code","source":"# Install Kaggle to play directely data from Kaggle\n\n# !pip install -q kaggle","metadata":{"id":"fQpiy-oPFv23"},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# Load the Kaggle Account API for authentication\n\n# from google.colab import files\n# files.upload()","metadata":{"id":"_OIuTX3pGQ_P","outputId":"0b9986c6-25b1-4b98-fbee-404a699e843b"},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# Make Kaggle folder\n\n# !mkdir ~/.kaggle","metadata":{"id":"WVCcQDypGzni"},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# Copy kaggle.json to root folder\n\n# !cp kaggle.json ~/.kaggle/","metadata":{"id":"SA2-C4VYHCQl"},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# Give modification rights to API\n\n# !chmod 600 ~/.kaggle/kaggle.json","metadata":{"id":"fKebesDuHUWQ"},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# Download the Data to your folder\n\n# ! kaggle competitions download -c rsna-pneumonia-detection-challenge","metadata":{"id":"hK2IeJ7rJEpy","outputId":"5bb030bb-de76-4df9-9cd3-8a517a91d237"},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# Unzip the Data\n\n# !unzip rsna-pneumonia-detection-challenge.zip","metadata":{"id":"kHwvicg_KxzC"},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"The several key items in this folder:\n\nstage_1_train_labels.csv: CSV file containing training set patientIds and labels (including bounding boxes)\n\nstage_1_detailed_class_info.csv: CSV file containing detailed labels (explored further below)\n\nstage_1_train_images/: directory containing training set raw image (DICOM) files\n\nstage_1_test_images/: directory containing testing set raw image (DICOM) files","metadata":{"id":"ayyqcW3RcmId"}},{"cell_type":"code","source":"# Install pydicom to access DICOM data\n\n# !pip install pydicom","metadata":{"id":"KuHebFB3GExE","outputId":"5cf013e1-dda6-47b0-c3ec-f21c83ce8905"},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# Import all the required Libraries\n\nimport os\nimport csv\nimport random\nimport pydicom as dcm\nimport numpy as np\nimport pandas as pd\nfrom skimage import io\nfrom skimage import measure\nfrom skimage.transform import resize\n\nimport glob\nimport tensorflow as tf\n\nfrom matplotlib import pyplot as plt\nimport matplotlib.patches as patches\n\nimport matplotlib\nfrom tqdm import tqdm_notebook\nfrom matplotlib.patches import Rectangle\nimport seaborn as sns\n%matplotlib inline \nIS_LOCAL = False","metadata":{"id":"l_yQHzfCF8C4"},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"from tensorflow import keras","metadata":{"id":"AFL3uU1JGSD1"},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"from pathlib import Path","metadata":{"id":"ecN3HkIfTL5-"},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"import warnings\nwarnings.filterwarnings('ignore')","metadata":{"id":"GU7kep3vXwDD"},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"import os\ncurrent_dir=!pwd\ncurrent_dir=current_dir[0]\nos.environ['KAGGLE_CONFIG_DIR']=current_dir","metadata":{"id":"tG2uKAA_GXsL"},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"### Let's go ahead and explore CSV files:","metadata":{"id":"yOBliuD2da8H"}},{"cell_type":"code","source":"# Patient who is Noraml, Target = 0\n\nclass_info_df = pd.read_csv('stage_2_detailed_class_info.csv')\ntrain_labels_df = pd.read_csv('stage_2_train_labels.csv') \nprint(train_labels_df.iloc[0])","metadata":{"id":"kysqzP_qX01N","outputId":"d60bfa31-fd5b-43a5-9e2c-4e038d964bb4"},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# Patient who has Pneumonia, Target = 1, and has bounding box\n\nprint(train_labels_df.iloc[4])","metadata":{"id":"nBX6Ll1wX60K","outputId":"1e6c45cf-61d5-4ee8-c59a-641cd77cb342"},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"f, ax = plt.subplots(1,1, figsize=(6,4))\ntotal = float(len(class_info_df))\nsns.countplot(class_info_df['class'],order = class_info_df['class'].value_counts().index, palette='Set3')\nfor p in ax.patches:\n    height = p.get_height()\n    ax.text(p.get_x()+p.get_width()/2.,\n            height + 3,\n            '{:1.2f}%'.format(100*height/total),\n            ha=\"center\") \nplt.show()","metadata":{"id":"Q_166bxjWwuF","outputId":"7e331447-1625-47a7-de97-b544da2db64c"},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"def get_feature_distribution(data, feature):\n    # Get the count for each label\n    label_counts = data[feature].value_counts()\n\n    # Get total number of samples\n    total_samples = len(data)\n\n    # Count the number of items in each class\n    print(\"Feature: {}\".format(feature))\n    for i in range(len(label_counts)):\n        label = label_counts.index[i]\n        count = label_counts.values[i]\n        percent = int((count / total_samples) * 10000) / 100\n        print(\"{:<30s}:   {} or {}%\".format(label, count, percent))\n\nget_feature_distribution(class_info_df, 'class')","metadata":{"id":"U5qJ-j8MXIPY","outputId":"6b67c2eb-f182-4f22-81b4-fc3cbff086e7"},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"train_class_df = train_labels_df.merge(class_info_df, left_on='patientId', right_on='patientId', how='inner')","metadata":{"id":"LIf3CUB7XZux"},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"fig, ax = plt.subplots(nrows=1,figsize=(12,6))\ntmp = train_class_df.groupby('Target')['class'].value_counts()\ndf = pd.DataFrame(data={'Exams': tmp.values}, index=tmp.index).reset_index()\nsns.barplot(ax=ax,x = 'Target', y='Exams',hue='class',data=df, palette='Set3')\nplt.title(\"Chest exams class and Target\")\nplt.show()","metadata":{"id":"lbIWVgCuXOBV","outputId":"099622f4-32c6-4efc-ef75-f965423204d0"},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"target1 = train_class_df[train_class_df['Target']==1]\nsns.set_style('whitegrid')\nplt.figure()\nfig, ax = plt.subplots(2,2,figsize=(12,12))\nsns.distplot(target1['x'],kde=True,bins=50, color=\"red\", ax=ax[0,0])\nsns.distplot(target1['y'],kde=True,bins=50, color=\"blue\", ax=ax[0,1])\nsns.distplot(target1['width'],kde=True,bins=50, color=\"green\", ax=ax[1,0])\nsns.distplot(target1['height'],kde=True,bins=50, color=\"magenta\", ax=ax[1,1])\nlocs, labels = plt.xticks()\nplt.tick_params(axis='both', which='major', labelsize=12)\nplt.show()","metadata":{"id":"TzdWVDvDXfKX","outputId":"d5dfd594-6737-49db-ccaf-8f4a150c1dcf"},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"fig, ax = plt.subplots(1,1,figsize=(7,7))\ntarget_sample = target1.sample(2000)\ntarget_sample['xc'] = target_sample['x'] + target_sample['width'] / 2\ntarget_sample['yc'] = target_sample['y'] + target_sample['height'] / 2\nplt.title(\"Centers of Lung Opacity rectangles (brown) over rectangles (yellow)\\nSample size: 2000\")\ntarget_sample.plot.scatter(x='xc', y='yc', xlim=(0,1024), ylim=(0,1024), ax=ax, alpha=0.8, marker=\".\", color=\"brown\")\nfor i, crt_sample in target_sample.iterrows():\n    ax.add_patch(Rectangle(xy=(crt_sample['x'], crt_sample['y']),\n                width=crt_sample['width'],height=crt_sample['height'],alpha=3.5e-3, color=\"yellow\"))\nplt.show()\n","metadata":{"id":"Teylg8n9X42t","outputId":"2fcfac3d-d547-4c14-c921-a09c29887b76"},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# Reding the Dicom info\n\npatientId = train_labels_df['patientId'][0]\ndcm_file = f'stage_2_train_images/{patientId}.dcm'\ndcm_data = dcm.read_file(dcm_file)\n\nprint(dcm_data)","metadata":{"id":"s_NzAm7nX_Mk","outputId":"7c0ce0bc-8578-4e85-aa63-211267a191ff"},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"im = dcm_data.pixel_array\nprint(type(im))\nprint(im.dtype)\nprint(im.shape)","metadata":{"id":"0J6tOvE0YMbl","outputId":"9abb0576-a4d4-40cd-eac9-472e25155e99"},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# Print Image\n\nplt.imshow(im)#, cmap=pylab.cm.gist_gray)\nplt.gray()\nplt.axis('off')","metadata":{"id":"CxAiLv3NYRHH","outputId":"b0a3eed1-6ea1-4d86-bd59-e0777e34067f"},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# Method to parse the bounding boxes\n\ndef parse_data(df):\n    \"\"\"\n    Method to read a CSV file (Pandas dataframe) and parse the \n    data into the following nested dictionary:\n\n      parsed = {\n        \n        'patientId-00': {\n            'dicom': path/to/dicom/file,\n            'label': either 0 or 1 for normal or pnuemonia, \n            'boxes': list of box(es)\n        },\n        'patientId-01': {\n            'dicom': path/to/dicom/file,\n            'label': either 0 or 1 for normal or pnuemonia, \n            'boxes': list of box(es)\n        }, ...\n\n      }\n\n    \"\"\"\n    # --- Define lambda to extract coords in list [y, x, height, width]\n    extract_box = lambda row: [row['y'], row['x'], row['height'], row['width']]\n\n    parsed = {}\n    for n, row in df.iterrows():\n        # --- Initialize patient entry into parsed \n        pid = row['patientId']\n        if pid not in parsed:\n            parsed[pid] = {\n                'dicom': 'stage_2_train_images/%s.dcm' % pid,\n                'label': row['Target'],\n                'boxes': []}\n\n        # --- Add box if opacity is present\n        if parsed[pid]['label'] == 1:\n            parsed[pid]['boxes'].append(extract_box(row))\n\n    return parsed","metadata":{"id":"BJk1ZHSmYy3Q"},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# Parse the bounding box\n\nparsed = parse_data(train_labels_df)","metadata":{"id":"iYbdWFFDY9VZ"},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"print(parsed['00436515-870c-4b36-a041-de91049b9ab4'])","metadata":{"id":"QVlltBdJZBhV","outputId":"83d9218e-994e-49c3-9647-5a7c11164c34"},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# Define the method to Draw the bounding box\n\ndef draw(data):\n    \"\"\"\n    Method to draw single patient with bounding box(es) if present \n\n    \"\"\"\n    # --- Open DICOM file\n    d = dcm.read_file(data['dicom'])\n    im = d.pixel_array\n\n    # --- Convert from single-channel grayscale to 3-channel RGB\n    im = np.stack([im] * 3, axis=2)\n\n    # --- Add boxes with random color if present\n    for box in data['boxes']:\n        rgb = np.floor(np.random.rand(3) * 256).astype('int')\n        im = overlay_box(im=im, box=box, rgb=rgb, stroke=6)\n\n    plt.imshow(im)\n    plt.gray()\n    plt.axis('off')\n\ndef overlay_box(im, box, rgb, stroke=1):\n    \"\"\"\n    Method to overlay single box on image\n\n    \"\"\"\n    # --- Convert coordinates to integers\n    box = [int(b) for b in box]\n    \n    # --- Extract coordinates\n    y1, x1, height, width = box\n    y2 = y1 + height\n    x2 = x1 + width\n\n    im[y1:y1 + stroke, x1:x2] = rgb\n    im[y2:y2 + stroke, x1:x2] = rgb\n    im[y1:y2, x1:x1 + stroke] = rgb\n    im[y1:y2, x2:x2 + stroke] = rgb\n\n    return im","metadata":{"id":"uPCnAJp4ZBoG"},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# Draw the bounding box\n\ndraw(parsed['00436515-870c-4b36-a041-de91049b9ab4'])","metadata":{"id":"nt1O1JjrZMJ8","outputId":"634c5f2a-946a-4aa9-dd8b-b04f38ff615c"},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"df_detailed = pd.read_csv('stage_2_detailed_class_info.csv')\nprint(df_detailed.iloc[0])","metadata":{"id":"ugC3i_NKZX_b","outputId":"cac66e58-c737-41af-bcd0-cd30b5fbb4ab"},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"patientId = df_detailed['patientId'][0]\ndraw(parsed[patientId])","metadata":{"id":"yQwDvlafZdBP","outputId":"a4f608b2-38e0-4280-c4ca-a95e5eca6c19"},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"summary = {}\nfor n, row in df_detailed.iterrows():\n    if row['class'] not in summary:\n        summary[row['class']] = 0\n    summary[row['class']] += 1\n    \nprint(summary)","metadata":{"id":"2egqwf_HZg5K","outputId":"b70dbde9-fa8f-4cd2-834a-3335c3a83b7d"},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"### Exploration of images","metadata":{"id":"ghU3Tj_8f1jI"}},{"cell_type":"code","source":"# empty dictionary\npneumonia_locations = {}\n# load table\nwith open(os.path.join('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]","metadata":{"id":"kJSaP7TeGZ8I"},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"train_path = os.listdir(Path('stage_2_train_images'))\ntest_path = os.listdir(Path('stage_2_test_images'))","metadata":{"id":"EhUQQK29S-Pr"},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# load and shuffle filenames\nfolder = '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","metadata":{"id":"fyYyx3cKGZ_Z","outputId":"f54be3bc-b396-457c-fe8c-a38d33b7636c"},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"def show_dicom_images(data):\n    img_data = list(data.T.to_dict().values())\n    f, ax = plt.subplots(3,3, figsize=(16,18))\n    for i,data_row in enumerate(img_data):\n        patientImage = data_row['patientId']+'.dcm'\n        imagePath = os.path.join(\"stage_2_train_images/\",patientImage)\n        data_row_img_data = dcm.read_file(imagePath)\n        modality = data_row_img_data.Modality\n        age = data_row_img_data.PatientAge\n        sex = data_row_img_data.PatientSex\n        data_row_img = dcm.dcmread(imagePath)\n        ax[i//3, i%3].imshow(data_row_img.pixel_array, cmap=plt.cm.bone) \n        ax[i//3, i%3].axis('off')\n        ax[i//3, i%3].set_title('ID: {}\\nModality: {} Age: {} Sex: {} Target: {}\\nClass: {}\\nWindow: {}:{}:{}:{}'.format(\n                data_row['patientId'],\n                modality, age, sex, data_row['Target'], data_row['class'], \n                data_row['x'],data_row['y'],data_row['width'],data_row['height']))\n    plt.show()","metadata":{"id":"AMD9QozOKkG7"},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"show_dicom_images(train_class_df[train_class_df['Target']==1].sample(9))","metadata":{"id":"oaNfcE65YhRm","outputId":"8c4e34df-dfe2-45b9-f489-33638f32b16d"},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"def show_dicom_images_with_boxes(data):\n    img_data = list(data.T.to_dict().values())\n    f, ax = plt.subplots(3,3, figsize=(16,18))\n    for i,data_row in enumerate(img_data):\n        patientImage = data_row['patientId']+'.dcm'\n        imagePath = os.path.join(\"stage_2_train_images/\",patientImage)\n        data_row_img_data = dcm.read_file(imagePath)\n        modality = data_row_img_data.Modality\n        age = data_row_img_data.PatientAge\n        sex = data_row_img_data.PatientSex\n        data_row_img = dcm.dcmread(imagePath)\n        ax[i//3, i%3].imshow(data_row_img.pixel_array, cmap=plt.cm.bone) \n        ax[i//3, i%3].axis('off')\n        ax[i//3, i%3].set_title('ID: {}\\nModality: {} Age: {} Sex: {} Target: {}\\nClass: {}'.format(\n                data_row['patientId'],modality, age, sex, data_row['Target'], data_row['class']))\n        rows = train_class_df[train_class_df['patientId']==data_row['patientId']]\n        box_data = list(rows.T.to_dict().values())\n        for j, row in enumerate(box_data):\n            ax[i//3, i%3].add_patch(Rectangle(xy=(row['x'], row['y']),\n                        width=row['width'],height=row['height'], \n                        color=\"yellow\",alpha = 0.1))   \n    plt.show()","metadata":{"id":"GyOBJ9UDojiT"},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"show_dicom_images_with_boxes(train_class_df[train_class_df['Target']==1].sample(9))","metadata":{"id":"TyzbHCSBLF-v","outputId":"78348078-1cb4-428c-e610-1c8bc38c0d43"},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"vars = ['Modality', 'PatientAge', 'PatientSex', 'BodyPartExamined', 'ViewPosition', 'ConversionType', 'Rows', 'Columns', 'PixelSpacing']\n\ndef process_dicom_data(data_df, data_path):\n    for var in vars:\n        data_df[var] = None\n    image_names = os.listdir(data_path)\n    for i, img_name in tqdm_notebook(enumerate(image_names)):\n        imagePath = os.path.join(data_path,img_name)\n        data_row_img_data = dcm.read_file(imagePath)\n        idx = (data_df['patientId']==data_row_img_data.PatientID)\n        data_df.loc[idx,'Modality'] = data_row_img_data.Modality\n        data_df.loc[idx,'PatientAge'] = pd.to_numeric(data_row_img_data.PatientAge)\n        data_df.loc[idx,'PatientSex'] = data_row_img_data.PatientSex\n        data_df.loc[idx,'BodyPartExamined'] = data_row_img_data.BodyPartExamined\n        data_df.loc[idx,'ViewPosition'] = data_row_img_data.ViewPosition\n        data_df.loc[idx,'ConversionType'] = data_row_img_data.ConversionType\n        data_df.loc[idx,'Rows'] = data_row_img_data.Rows\n        data_df.loc[idx,'Columns'] = data_row_img_data.Columns  \n        data_df.loc[idx,'PixelSpacing'] = str.format(\"{:4.3f}\",data_row_img_data.PixelSpacing[0]) ","metadata":{"id":"gXjFTSbBZRxz"},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"process_dicom_data(train_class_df,'stage_2_train_images')","metadata":{"id":"CD4h_ninZX_L","outputId":"02c27a0a-e2b1-4453-803b-df77385a44d4"},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"tmp = train_class_df.groupby(['Target', 'PatientAge'])['patientId'].count()\ndf = pd.DataFrame(data={'Exams': tmp.values}, index=tmp.index).reset_index()\ntmp = df.groupby(['Exams','Target', 'PatientAge']).count()\ndf2 = pd.DataFrame(data=tmp.values, index=tmp.index).reset_index()","metadata":{"id":"kVj1oj2VZFRA"},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"tmp = train_class_df.groupby(['class', 'PatientAge'])['patientId'].count()\ndf1 = pd.DataFrame(data={'Exams': tmp.values}, index=tmp.index).reset_index()\ntmp = df1.groupby(['Exams','class', 'PatientAge']).count()\ndf3 = pd.DataFrame(data=tmp.values, index=tmp.index).reset_index()","metadata":{"id":"eltW5sQAa_VX"},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"fig, (ax) = plt.subplots(nrows=1,figsize=(16,6))\nsns.barplot(ax=ax, x = 'PatientAge', y='Exams', hue='Target',data=df2)\nplt.title(\"Train set: Chest exams Age and Target\")\nplt.xticks(rotation=90)\nplt.show()","metadata":{"id":"-ry0lj03bDEZ","outputId":"6823d4b3-f4f2-4d63-bbdf-299707ad43e0"},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"fig, (ax) = plt.subplots(nrows=1,figsize=(16,6))\nsns.barplot(ax=ax, x = 'PatientAge', y='Exams', hue='class',data=df3)\nplt.title(\"Train set: Chest exams Age and class\")\nplt.xticks(rotation=90)\nplt.show()","metadata":{"id":"e8vDqX7BbGaH","outputId":"e915aec1-0e74-4a5e-e7e8-6ac27678ee00"},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"tmp = train_class_df.groupby(['Target', 'PatientSex'])['patientId'].count()\ndf = pd.DataFrame(data={'Exams': tmp.values}, index=tmp.index).reset_index()\ntmp = df.groupby(['Exams','Target', 'PatientSex']).count()\ndf2 = pd.DataFrame(data=tmp.values, index=tmp.index).reset_index()\nfig, ax = plt.subplots(nrows=1,figsize=(6,6))\nsns.barplot(ax=ax, x = 'PatientSex', y='Exams', hue='Target',data=df2)\nplt.title(\"Train set: Patient Sex and Target\")\nplt.show()","metadata":{"id":"rxxmxrvTbOFQ","outputId":"7c4ee2ec-6d0a-48e3-d3c4-456a9627133c"},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"tmp = train_class_df.groupby(['class', 'PatientSex'])['patientId'].count()\ndf1 = pd.DataFrame(data={'Exams': tmp.values}, index=tmp.index).reset_index()\ntmp = df1.groupby(['Exams','class', 'PatientSex']).count()\ndf3 = pd.DataFrame(data=tmp.values, index=tmp.index).reset_index()\nfig, (ax) = plt.subplots(nrows=1,figsize=(6,6))\nsns.barplot(ax=ax, x = 'PatientSex', y='Exams', hue='class',data=df3)\nplt.title(\"Train set: Patient Sex and class\")\nplt.show()","metadata":{"id":"NdqJLx3xbUV_","outputId":"5b9463c1-992f-4c6c-ca24-f5538751672c"},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"## Data generator¶","metadata":{"id":"pbEs76EfgIOF"}},{"cell_type":"code","source":"class generator(keras.utils.Sequence):\n    \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 = dcm.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 = dcm.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)","metadata":{"id":"Yg9aXq6hGaHK"},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"BATCH_SIZE = 32\nIMAGE_SIZE = 256","metadata":{"id":"XogOg89wGaK1"},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"## Network","metadata":{"id":"9k_QEiOwgNQJ"}},{"cell_type":"code","source":"def 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])\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(256, 1, activation=None)(x)\n    x = keras.layers.BatchNormalization(momentum=0.9)(x)\n    x = keras.layers.LeakyReLU(0)(x)\n    x = keras.layers.Conv2DTranspose(128, (8,8), (4,4), padding=\"same\", activation=None)(x)\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-2))(x)\n    model = keras.Model(inputs=inputs, outputs=outputs)\n    return model","metadata":{"id":"GfHA9jXEGu4a"},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"## Evaluate the model","metadata":{"id":"E2kmqBi-gYdU"}},{"cell_type":"code","source":"def iou_loss(y_true, y_pred):\n    y_true = tf.reshape(y_true, [-1])\n    y_pred = tf.reshape(y_pred, [-1])\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    y_true =tf.cast(y_true,dtype=tf.float32)\n    y_pred =tf.cast(y_pred,dtype=tf.float32)\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_true = y_true.astype('float32')\n    #y_pred = y_pred.astype('float32')\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\n# create network and compiler\nmodel = create_network(input_size=IMAGE_SIZE, channels=32, n_blocks=2, depth=4)\nmodel.compile(optimizer='adam',\n              loss=iou_bce_loss,\n              metrics=['accuracy', mean_iou])\n# cosine learning rate annealing\ndef cosine_annealing(x):\n    lr = 0.001\n    epochs = 20\n    return lr*(np.cos(np.pi*x/epochs)+1.)/2\nlearning_rate = tf.keras.callbacks.LearningRateScheduler(cosine_annealing)\n\n# create train and validation generators\nfolder = 'stage_2_train_images'\ntrain_gen = generator(folder, train_filenames, pneumonia_locations, batch_size=BATCH_SIZE, image_size=IMAGE_SIZE, shuffle=True, augment=True, predict=False)\nvalid_gen = generator(folder, valid_filenames, pneumonia_locations, batch_size=BATCH_SIZE, image_size=IMAGE_SIZE, shuffle=False, predict=False)\n","metadata":{"id":"SkqwFAwsGu7o"},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"## Train network","metadata":{"id":"BH68XgTfgfBB"}},{"cell_type":"code","source":"history = model.fit(train_gen, validation_data=valid_gen, callbacks=[learning_rate], epochs=5, shuffle=True)","metadata":{"id":"ToTYwHq_Gu-v","outputId":"ec830935-1ce3-4119-f4f5-e43fde15615e"},"execution_count":null,"outputs":[]},{"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()","metadata":{"id":"WnjzLu-vTzaA","outputId":"ab5be4b3-42a2-4127-b0f6-0235c828674a"},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"for 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        # 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,facecolor='none'))\n        axidx += 1\n    plt.show()\n    # only plot one batch\n    break","metadata":{"id":"bPvf8UFaGvBf","outputId":"6322ee83-219d-481f-b9e5-9719f6148a30"},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"len(test_gen)","metadata":{"id":"bo66K-DzgGnL","outputId":"bab5bd80-d856-4756-8cc3-e132f0783bac"},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"folder = 'stage_2_test_images'\ntest_filenames = os.listdir(folder)\nprint('n test samples:', len(test_filenames))","metadata":{"id":"JDGVgJT_cxw0","outputId":"af2ad5a0-6d9d-449b-bc7a-740a6182e158"},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"\n\n# create test generator with predict flag set to True\ntest_gen = generator(folder, test_filenames, None, batch_size=25, image_size=256, shuffle=False, predict=True)\n\n# create submission dictionary\nsubmission_dict = {}\n# loop through testset\nfor imgs, filenames in 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')","metadata":{"id":"tL7ejrPmGvEn"},"execution_count":null,"outputs":[]}]}