{"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":"## **RSNA Pneumonia Detection**\n\nPneumonia is an infection in one or both lungs. Bacteria, viruses, and fungi cause it. The infection causes inflammation in the air sacs in your lungs, which are called alveoli.\n\nCXRs are the most commonly performed diagnostic imaging study. A number of factors such as \npositioning of the patient and depth of inspiration can alter the appearance of the CXR, complicating \ninterpretation further. In addition, clinicians are faced with reading high volumes of images every shift.\n\nAutomating Pneumonia screening in chest radiographs, providing affected area details through bounding box.","metadata":{"id":"jbsUHUkcNgMg"}},{"cell_type":"markdown","source":"## **Objective:**\nThe objective of this project is to build an algorithm to locate the position of inflammation in a medical image. The algorithm needs to  locate lung opacities on chest radiographs automatically\n\nThe objective of the project is,\n* Learn to how to do build an Object Detection Model\n* Use transfer learning to fine-tune a model.\n* Learn to set the optimizers, loss functions, epochs, learning rate, batch size, checkpointing, early stopping etc.\n* Read different research papers of given domain to obtain the knowledge of advanced models for the given problem.\n\n\n#### Acknowledgment for the datasets: https://www.kaggle.com/c/rsna-pneumonia-detection-challenge/overview/acknowledgements","metadata":{"id":"XYm7TlOX1tgN"}},{"cell_type":"markdown","source":"### **1.0 Importing and installing the necessary Libraries**","metadata":{"id":"_6icbKjAIQiv"}},{"cell_type":"code","source":"!pip install tqdm\n!pip install pydicom\n!pip install -U albumentations","metadata":{"id":"rCqKX8LJXwX2","outputId":"9f175f42-f3c8-4f37-9f20-10883600d08b","trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"import tensorflow as tf\nfrom tensorflow import keras","metadata":{"id":"zvwFW9QrJJVk","trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"print('Tensforflow version:',tf.__version__)\nprint('Keras version:',keras.__version__)","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# Initialize the random number generator\nimport random\nrandom.seed(0)\n\n# Ignore the warnings\nimport warnings\nwarnings.filterwarnings(\"ignore\")","metadata":{"id":"P-zTGWRF2wnQ","trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"from glob import glob\nimport os\nimport time\nimport math\nimport fnmatch\nimport sys\n\nfrom zipfile import ZipFile\nfrom tqdm import tqdm_notebook\n\nimport numpy as np\nimport pandas as pd\n\nimport cv2\nimport matplotlib.pyplot as plt\nimport matplotlib.patches as patches \nfrom matplotlib.patches import Rectangle\nimport pydicom as dicom\nimport seaborn as sns\n\nfrom sklearn.utils import shuffle\nfrom skimage.measure import label, regionprops\n\nimport albumentations as A\n\n\nfrom tensorflow.keras.preprocessing.image import ImageDataGenerator\nfrom tensorflow.python.keras.utils.data_utils import Sequence\nfrom tensorflow.keras.layers import Conv2D, Input, Flatten, Dense, Dropout, Concatenate, BatchNormalization, Conv2DTranspose\nfrom tensorflow.keras.models import Model, Sequential, load_model\nimport tensorflow.keras.backend as K\nfrom tensorflow.keras.applications import VGG16\nfrom tensorflow.keras.applications.vgg16 import preprocess_input\n\nfrom tensorflow.keras.optimizers import Adam\nfrom tensorflow.keras.callbacks import ModelCheckpoint, EarlyStopping, ReduceLROnPlateau\nfrom tensorflow.keras.losses import binary_crossentropy\n","metadata":{"id":"R3Pf-mzZIQi5","trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"rootDir='/kaggle/input/'\nworkingDir='/kaggle/working/'\n# zipFilename=rootDir+'rsna-pneumonia-detection-challenge.zip'\ndatasetPath=rootDir+'rsna-pneumonia-detection-challenge/'\n","metadata":{"id":"FlR0Rw5ZOwhh","trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"The input folder contains 4 important information\n* stage_2_train_labels.csv - CSV file containing the patient id, bounding boxes and target label\n* stage_2_detailed_class_info.csv - CSV file containing the detail informaiton of patientid and the corresponding label\n* stage_2_train_images - directory contains train images in DICOM format\n* stage_2_test_images - directory contains test images in DICOM format","metadata":{"id":"NSHzxBkoIQi7"}},{"cell_type":"code","source":"trainImagesDir=datasetPath+'stage_2_train_images/'\ntestImagesDir=datasetPath+'stage_2_test_images/'\nsampleSubmission=datasetPath+'stage_2_sample_submission.csv'\nclassInfo=datasetPath+'stage_2_detailed_class_info.csv'\nrsnaLink=datasetPath+'GCP Credits Request Link - RSNA.txt'\ntrainLabels=datasetPath+'stage_2_train_labels.csv'\n","metadata":{"id":"btEyb0dOIQi8","trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"image_train_path = os.listdir(trainImagesDir)\nimage_test_path = os.listdir(testImagesDir)\nprint(\"Number of images in train set:\", len(image_train_path),\"\\nNumber of images in test set:\", len(image_test_path))","metadata":{"id":"nsQ5padnIQi9","outputId":"fc83b7e2-263e-4e9c-8b2c-dae5b4bc17fd","trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# Loading the data\n# There are two input files given - Detailed class info and train labels\nclass_info_df = pd.read_csv(classInfo)\ntrain_labels_df = pd.read_csv(trainLabels) ","metadata":{"id":"GObLdVDE3WTQ","trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"print(\"Detailed class info -  rows: {}, columns: {}\".format(class_info_df.shape[0], class_info_df.shape[1]))\nprint(\"Train labels -  rows: {}, columns: {}\".format(train_labels_df.shape[0], train_labels_df.shape[1]))","metadata":{"id":"BxrzZNb03KzL","outputId":"b808b49f-b49d-402f-e9cb-f49899f36837","trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"There are only 26683 images in the image directory, but the csv file contains 30227 rows. There are more rows than the images.","metadata":{"id":"q9_COwIk5IZn"}},{"cell_type":"code","source":"class_info_df.head(10)","metadata":{"id":"dPXjudVp4KDB","outputId":"7341d7df-862b-41e4-f8e5-d4f39069dc45","trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"train_labels_df.head(10)","metadata":{"id":"343oKZ1pIQi_","outputId":"338cf6e4-998b-4c4a-e277-16d83e355f55","trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"In Detailed class info dataset , the detailed information about the type of class associated with a certain patientId is given. It has 3 entries \"Lung Opacity\", \"Normal\" and \"No Lung Opacity/Not Normal\"\n\nThe CSV file contains PatientId, bounding box details with (x,y) coordinates and width and height that encapsulates the box. It also contains the Target variable. For target variable 0, the bounding box values has NaN values.\n","metadata":{"id":"fVfoZd0oIQi_"}},{"cell_type":"markdown","source":"If we look closely, there are duplicate entries for patientId in the csv files. We can observe row #4 and #5, row #8 and #9 have same patientId values, aka, the patient is identified with pneumonia at multiple areas in lungs\n\nCheck the unique patient ID in the train dataset","metadata":{"id":"oMaOVkdAIQjA"}},{"cell_type":"code","source":"print(\"Unique patientId in  train_class_df: \", train_labels_df['patientId'].nunique())","metadata":{"id":"fjoEVuzGARr7","outputId":"349e0ca4-80c5-4e66-b98d-53b89e98ebbc","trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"#### **Checking missing data in two datasets**","metadata":{"id":"TFwZ4Klz5sFp"}},{"cell_type":"code","source":"train_labels_df.info()","metadata":{"id":"rrmoRrKaIQjB","outputId":"0acffec1-d0c0-4183-8fa1-525e2a6263bf","trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"For the info of the data, we observe that of the total 30227 rows, 9555 rows has non null. So, all bounding boxes are either defined or not defined.","metadata":{"id":"1MZ0uLKRIQjB"}},{"cell_type":"code","source":"print(train_labels_df[train_labels_df.Target==0].shape[0])\nprint(train_labels_df[train_labels_df.Target==1].shape[0])","metadata":{"id":"OSltZzEaIQjC","outputId":"51b5f9c7-0010-4923-8de8-a530e19e8456","trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"We see from above that the total number of patientIds that are identified with Pneumonia are 9555 and it matches to the non null values. It can be inferred from this that all pneumonia data set has bounding boxes defined and for normal patients, no bounding boxes exist.","metadata":{"id":"sTMOHOJ-IQjC"}},{"cell_type":"code","source":"def missing_data(data):\n    total = data.isnull().sum().sort_values(ascending = False)\n    percent = (data.isnull().sum()/data.isnull().count()*100).sort_values(ascending = False)\n    return np.transpose(pd.concat([total, percent], axis=1, keys=['Total', 'Percent']))\nmissing_data(train_labels_df)","metadata":{"id":"TaRU7BYs5ySh","outputId":"9a4ca2de-76fe-4a69-f080-de74a5224b8c","trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"missing_data(class_info_df)","metadata":{"id":"fOrPX3Ww59yH","outputId":"62b882c2-ece0-492f-aab5-9809effa6eb7","trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"68.38% of values are missing for x,y, height and width in train labels for target 0 (not Lung opacity) in train labels dataset","metadata":{"id":"mK3AQyFV6SSs"}},{"cell_type":"code","source":"plt.rc('axes', labelsize=15)\nplt.rc('axes', titlesize=20)\nsns.set_palette('Set2')","metadata":{"id":"nN2eJOn67ewk","trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"f, ax = plt.subplots(1,1, figsize=(6,4))\ntotal = float(class_info_df.shape[0])\nsns.countplot(class_info_df['class'], order = class_info_df['class'].value_counts().index)\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":"I2ISqt1N6s_l","outputId":"812df04b-6788-474e-eabc-e2fd8982ca14","trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# More details on classes - No Lung Opacity / Not Normal, Lung Opacity, Normal\n\ndef 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 = data.shape[0]\n\n    # Count the number of items in each class\n    print(\"{:<30s}:   count(percentage)\".format(feature))\n    for i in range(len(label_counts)):\n        label = label_counts.index[i]\n        count = label_counts.values[i]\n        percent = round((count / total_samples) * 100, 2)\n        print(\"{:<30s}:   {}({}%)\".format(label, count, percent))\n\nget_feature_distribution(class_info_df, 'class')\n","metadata":{"id":"t8eTSkX96v-A","outputId":"5685acae-0cbb-4e74-8805-2dbb1ae09f68","trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"No Lung Opacity / Not Normal and Normal have together the same percent (68.39%) as the percent of missing values for target window in class details information.\n\nIn the train set, the percent of data with pneumonia is therefore 31.61%.","metadata":{"id":"mu4jkvAB8qkk"}},{"cell_type":"code","source":"train_labels_df.Target.unique()","metadata":{"id":"3gwAxD95IQjD","outputId":"ad6a56f7-ee71-4dc6-e6a8-603aaccdec1d","trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"The target has two classifications 0 and 1 namely Normal and Pneumonia","metadata":{"id":"K38YsiXDIQjD"}},{"cell_type":"markdown","source":"#### **Merging train labels and Detailed class info datasets to get more insights**","metadata":{"id":"RpR0m1SF90oo"}},{"cell_type":"code","source":"train_labels_df.shape[0], class_info_df.shape[0]","metadata":{"id":"8q6hTb-fQvlW","outputId":"ff7d50ba-affe-48f7-d80a-df3af599a1ba","trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# merging the two datasets (train and class detail info) using Patient ID as the merge criteria\ntrain_class_df = train_labels_df.merge(class_info_df, left_on='patientId', right_on='patientId', how='inner')","metadata":{"id":"3rihhjiG921Z","outputId":"2bce2476-0eb1-49bf-d8a7-1dbb11b280ee","trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"train_class_df.sample(5)","metadata":{"id":"5NoaF9Uc95Hw","outputId":"986cc31c-e35e-46cf-dcdf-68b1101b6333","trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"#plotting the number of examinations for each class detected, grouped by Target value\nfig, ax = plt.subplots(nrows=1,figsize=(12,6))\ntmp = train_class_df.groupby('Target')['class'].value_counts()\ndf = pd.DataFrame(data={'Freq': tmp.values}, index=tmp.index).reset_index()\nsns.barplot(ax=ax, x='Target', y='Freq', hue='class', data=df)\nplt.title(\"Chest examination - Frequency of Targets\")\nplt.show()","metadata":{"id":"R0KPaQuh97lH","outputId":"00d944cf-7948-46ab-8ec9-c9c0774930d1","trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"Plot frequency distribution graph for bounding box detection for Lung Opacity ","metadata":{"id":"rfxKxQen-4WV"}},{"cell_type":"markdown","source":"Exploring Dicom image files - Reading training & test files","metadata":{"id":"bYmLiMPH_iv4"}},{"cell_type":"markdown","source":"#### **Extracting a single image and processing DICOM information**","metadata":{"id":"ZFij71jtBQ3T"}},{"cell_type":"markdown","source":"It is observed that some useful information are available in the DICOM metadata with predictive values, for example:\n\nPatient sex, Patient age, Modality, Body part examined, View position, Rows & Columns, Pixel Spacing","metadata":{"id":"UJVtWrsUBxxF"}},{"cell_type":"code","source":"print('A maximum of {} areas are detected in Lungs for pneumonia patient'.format(max(train_labels_df.patientId.value_counts())))","metadata":{"id":"WrDhxKIqIQjH","outputId":"fab2d705-5c2d-4200-b535-629a4f5259d4","trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"## **Preprocess the dataset for model input**","metadata":{"id":"TiRtLsKQJvue"}},{"cell_type":"code","source":"def update_dataset(path, df1):\n    pid=[]\n    label=[]\n    bbox=[]\n\n    for name, group in df1.groupby(['patientId','Target']):\n        pid.append(path+group['patientId'].tolist()[0]+'.dcm')\n        label.append(group['Target'].tolist()[0])\n        if group['Target'].tolist()[0] == 1:\n            ibbox=[]\n            for row in group.iterrows():\n                ibbox.append([row[1]['x'], row[1]['y'], row[1]['width'], row[1]['height']])\n            bbox.append(ibbox)\n        else:\n            bbox.append([])\n    df = pd.DataFrame({'patientId':pid, 'bboxes': bbox, 'label':label})\n    return df","metadata":{"id":"zynLElMJIQjE","trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"We can observe that the non-null values are 9555 which matches to the patients that have pneumonia problem","metadata":{"id":"h3VpckVjIQjE"}},{"cell_type":"code","source":"df=update_dataset(trainImagesDir, train_labels_df)\nprint(df.shape)\ndf.head()","metadata":{"id":"sZudJPdpIQjF","trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"print('Total number of patients that are normal are {}'.format(df[df.label==0].shape[0]))\nprint('Total number of patients that have pneumonia are {}'.format(df[df.label==1].shape[0]))","metadata":{"id":"NMU248HSIQjF","trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"imgWidth=224\nimgHeight=224\nimgChannels=3\nimgSize=(imgHeight, imgWidth)\nbatchSize=64\nlabelDict={0:'normal', 1:'lung opacity'}","metadata":{"id":"ZTDb7JAHIQjG","trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# try:\n#     tpu = tf.distribute.cluster_resolver.TPUClusterResolver()\n#     tf.config.experimental_connect_to_cluster(tpu)\n#     tf.tpu.experimental.initialize_tpu_system(tpu)\n#     strategy = tf.distribute.experimental.TPUStrategy(tpu)\n# except ValueError:\n#     strategy = tf.distribute.get_strategy() # for CPU and single GPU\n#     print('Number of replicas:', strategy.num_replicas_in_sync)","metadata":{"id":"D43s0FH5IQjG","trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"def loadImage(row, axis):\n    image_path = row.patientId\n    img = dicom.dcmread(image_path).pixel_array\n    axis.imshow(img, cmap='gray')\n    lbl=labelDict.get(row.label)\n    bboxes=row.bboxes\n    for bbox in bboxes:\n        x=bbox[0]\n        y=bbox[1]\n        w=bbox[2]\n        h=bbox[3]\n        rect = patches.Rectangle((x,y), w, h, linewidth=2, edgecolor='red', fill=False)\n        axis.add_patch(rect)\n    axis.set_title(lbl)\n    ","metadata":{"id":"v2iU4XxHZS84","trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"def loadImages(df):\n    cols=5\n    rows=4\n    idx=0\n    f,axarr=plt.subplots(rows,cols,figsize=(18,10))\n    for r in range(rows):\n        for c in range(cols):\n            axis=axarr[r,c]\n            loadImage(df.iloc[idx], axis)\n            idx+=1\n    plt.tight_layout()","metadata":{"id":"btE4Aa3RIQjH","trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"loadImages(df)","metadata":{"id":"jrMyHgvLIQjI","trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"Let us print the image with maximum bounding boxes","metadata":{"id":"yKcH5vDJYqx2"}},{"cell_type":"code","source":"max_bbox_idx=np.argmax([len(x) for x in df.bboxes])\nf,axarry=plt.subplots(1,1,figsize=(5,5))\nloadImage(df.iloc[max_bbox_idx], axarry)","metadata":{"id":"WoxeTU9qYzbE","trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"c=math.ceil(df.shape[0]*0.7)\ntrain_df,val_df=df[:c],df[c:]\nprint(train_df.shape, val_df.shape)","metadata":{"id":"yy0m_y1QIQjK","trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# image transformer object\ntransform = A.Compose([\n        A.RandomRotate90(),\n        A.Flip(),\n        A.Transpose(),\n        A.OneOf([\n            A.IAAAdditiveGaussianNoise(),\n            A.GaussNoise(),\n        ], p=0.2),\n        A.OneOf([\n            A.MotionBlur(p=.2),\n            A.MedianBlur(blur_limit=3, p=0.1),\n            A.Blur(blur_limit=3, p=0.1),\n        ], p=0.2),\n        A.ShiftScaleRotate(shift_limit=0.0625, scale_limit=0.2, rotate_limit=45, p=0.2),\n        A.OneOf([\n            A.OpticalDistortion(p=0.3),\n            A.GridDistortion(p=.1),\n            A.IAAPiecewiseAffine(p=0.3),\n        ], p=0.2),\n        A.OneOf([\n            A.CLAHE(clip_limit=2),\n            A.IAASharpen(),\n            A.IAAEmboss(),\n            A.RandomBrightnessContrast(),            \n        ], p=0.3),\n        A.HueSaturationValue(p=0.3),\n    ])\n","metadata":{"id":"GPMLXN7KIc-J","trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"Need to identify the distribution (Pneumonia and normal) of the data used\nConsider a portion of the dataset for train (2000) and validation (25%) of train size","metadata":{}},{"cell_type":"code","source":"trainsize=2000\nvalsize=int(0.25*trainsize)\ntrainpartial=train_df[:trainsize]\nvalpartial=val_df[:valsize]\nprint('Distribution of labels in the train data are ', \n      (trainpartial.label.value_counts().values/trainpartial.label.value_counts().values.sum())*100)\nprint('Distribution of labels in the validation data are ', \n      (valpartial.label.value_counts().values/valpartial.label.value_counts().values.sum())*100)","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"The distribution of the data in both train and validation is good. Also, the distribution of same label data across the train adn test are also good to proceed","metadata":{}},{"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(float(y_true) * float(y_pred))\n    score = (intersection + 1.) / (tf.reduce_sum(float(y_true)) + tf.reduce_sum(float(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(float(y_true) * float(y_pred), axis=[1])\n    union = tf.reduce_sum(float(y_true),axis=[1]) + tf.reduce_sum(float(y_pred),axis=[1])\n    smooth = tf.ones(tf.shape(intersect))\n    return tf.reduce_mean((intersect + smooth) / (union - intersect + smooth))\n","metadata":{"id":"r-u6VnpVIp_p","trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"## **Mask R-CNN Model training**","metadata":{}},{"cell_type":"markdown","source":"Install Matterport's Mask-RCNN model from github.","metadata":{}},{"cell_type":"code","source":"!git clone https://www.github.com/matterport/Mask_RCNN.git\nos.chdir('Mask_RCNN')","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"!wget --quiet https://github.com/matterport/Mask_RCNN/releases/download/v2.0/mask_rcnn_coco.h5\n!ls -lh mask_rcnn_coco.h5","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# Root directory of the project\nmask_rcnn_dir = os.path.join(workingDir+\"Mask_RCNN/\")\nsys.path.append(mask_rcnn_dir)  # To find local version of the library\n# Path to trained weights file\nCOCO_WEIGHTS_PATH = os.path.join(mask_rcnn_dir, \"mask_rcnn_coco.h5\")\n# Directory to save logs and model checkpoints\nDEFAULT_LOGS_DIR = os.path.join(workingDir, \"logs\")","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"from mrcnn.config import Config\nfrom mrcnn import utils\nimport mrcnn.model as modellib\nfrom mrcnn import visualize\nfrom mrcnn.model import log\nfrom mrcnn.visualize import display_instances","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"class DetectorConfig(Config):\n    \"\"\"Configuration for training on the RSNA pneumonia dataset\n    Overrides values from the base Config\n    \"\"\"\n    \n    # Give the configuration a recognizable name  \n    NAME = 'maskrcnn'\n    \n    # Train on 1 GPU and 8 images per GPU.\n    GPU_COUNT = 1\n    IMAGES_PER_GPU = 8 \n    \n    BACKBONE = 'resnet50'\n    \n    NUM_CLASSES = 2  # a background + 1 pneumonia classes\n    \n    IMAGE_MIN_DIM = 256\n    IMAGE_MAX_DIM = 256\n    RPN_ANCHOR_SCALES = (32, 64, 128, 256)\n    TRAIN_ROIS_PER_IMAGE = 32\n    MAX_GT_INSTANCES = 3\n    DETECTION_MAX_INSTANCES = 5\n    DETECTION_MIN_CONFIDENCE = 0.9\n    DETECTION_NMS_THRESHOLD = 0.1\n\n    STEPS_PER_EPOCH = 50\n    \nconfig = DetectorConfig()\nconfig.display()","metadata":{"id":"_D7wYepoJCy8","trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"class DetectorDataset(utils.Dataset):\n    \"\"\"Dataset class for training on the RSNA pneumonia dataset.\n    \"\"\"\n\n    def __init__(self, imagePath, imageBBoxes, orig_height, orig_width):\n        super().__init__(self)\n        \n        # Add classes\n        self.add_class('pneumonia', 1, 'Lung Opacity')\n   \n        # add images \n        for i, fp in enumerate(imagePath):\n            bboxes = imageBBoxes[i]\n            self.add_image('pneumonia', image_id=i, path=fp, \n                           annotations=bboxes, orig_height=orig_height, orig_width=orig_width)\n            \n    def image_reference(self, image_id):\n        info = self.image_info[image_id]\n        return info['path']\n\n    def load_image(self, image_id):\n        info = self.image_info[image_id]\n        fp = info['path']\n        ds = pydicom.read_file(fp)\n        image = ds.pixel_array\n        if len(image.shape) != 3 or image.shape[2] != 3:\n            image = np.stack((image,) * 3, -1)\n        return image/255.0\n\n    def load_mask(self, image_id):\n        info = self.image_info[image_id]\n        bboxes = info['annotations']\n        count = len(bboxes)\n        if count == 0:\n            mask = np.zeros((info['orig_height'], info['orig_width'], 1), dtype=np.uint8)\n            class_ids = np.zeros((1,), dtype=np.int32)\n        else:\n            mask = np.zeros((info['orig_height'], info['orig_width'], count), dtype=np.uint8)\n            class_ids = np.zeros((count,), dtype=np.int32)\n            for i, a in enumerate(bboxes):\n                if a['Target'] == 1:\n                    x = int(a['x'])\n                    y = int(a['y'])\n                    w = int(a['width'])\n                    h = int(a['height'])\n                    mask_instance = mask[:, :, i].copy()\n                    cv2.rectangle(mask_instance, (x, y), (x+w, y+h), 1, -1)\n                    mask[:, :, i] = mask_instance\n                    class_ids[i] = 1\n        return mask.astype(np.bool), class_ids.astype(np.int32)","metadata":{"id":"mJBqx_W8JCma","trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# prepare the training dataset\ndataset_train = DetectorDataset(trainpartial.patientId.to_list(), trainpartial.bboxes.to_list(), 1024, 1024)\ndataset_train.prepare()","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# prepare the validation dataset\ndataset_val = DetectorDataset(valpartial.patientId.to_list(), valpartial.bboxes.to_list(), 1024, 1024)\ndataset_val.prepare()","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"maskrcnnModel = modellib.MaskRCNN(mode='training', config=config, model_dir=workingDir)","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# Train Mask-RCNN Model \nmaskrcnnHistory=maskrcnnModel.train(dataset_train, dataset_val, \n                                        learning_rate=config.LEARNING_RATE, \n                                        epochs=1, \n                                        layers='all'\n                                   )","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# select trained model \ndir_names = next(os.walk(maskrcnnModel.model_dir))[1]\nkey = config.NAME.lower()\ndir_names = filter(lambda f: f.startswith(key), dir_names)\ndir_names = sorted(dir_names)\n\nif not dir_names:\n    import errno\n    raise FileNotFoundError(\n        errno.ENOENT,\n        \"Could not find model directory under {}\".format(self.model_dir))\n    \nfps = []\n# Pick the last directory\nfor d in dir_names: \n    dir_name = os.path.join(maskrcnnModel.model_dir, d)\n    # Find the last checkpoint\n    checkpoints = next(os.walk(dir_name))[2]\n    checkpoints = filter(lambda f: f.startswith(\"mask_rcnn\"), checkpoints)\n    checkpoints = sorted(checkpoints)\n    if not checkpoints:\n        print('No weight files in {}'.format(dir_name))\n    else:\n        checkpoint = os.path.join(dir_name, checkpoints[-1])\n        fps.append(checkpoint)\n\nmaskrcnn_model_path = sorted(fps)[-1]\nprint('Found model {}'.format(maskrcnn_model_path))","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"class InferenceConfig(DetectorConfig):\n    GPU_COUNT = 1\n    IMAGES_PER_GPU = 1\n\ninference_config = InferenceConfig()\n\n# Recreate the model in inference mode\nmaskrcnnInfModel = modellib.MaskRCNN(mode='inference', \n                          config=inference_config,\n                          model_dir=workingDir)\n\n# Load trained weights (fill in path to trained weights here)\nassert model_path != \"\", \"Provide path to trained weights\"\nprint(\"Loading weights from \", maskrcnn_model_path)\nmaskrcnnInfModel.load_weights(maskrcnn_model_path, by_name=True)","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# Show few example of ground truth vs. predictions on the validation dataset\ndataset = dataset_val\nfig = plt.figure(figsize=(10, 30))\n\nfor i in range(4):\n    image_id = random.choice(dataset.image_ids)\n    original_image, image_meta, gt_class_id, gt_bbox, gt_mask = \n        modellib.load_image_gt(dataset_val, inference_config, image_id, use_mini_mask=False)\n    print(original_image.shape)\n    plt.subplot(6, 2, 2*i + 1)\n    visualize.display_instances(original_image, gt_bbox, gt_mask, gt_class_id, \n                                dataset.class_names, colors=['red'], ax=fig.axes[-1])\n    \n    plt.subplot(6, 2, 2*i + 2)\n    results = maskrcnnInfModel.detect([original_image])\n    r = results[0]\n    visualize.display_instances(original_image, r['rois'], r['masks'], r['class_ids'], \n                                dataset.class_names, r['scores'], colors=['green'], ax=fig.axes[-1])","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"","metadata":{},"execution_count":null,"outputs":[]}]}