{"cells":[{"metadata":{"_uuid":"8f2839f25d086af736a60e9eeb907d3b93b6e0e5","_cell_guid":"b1076dfc-b9ad-4769-8c92-a6c4dae69d19","trusted":true},"cell_type":"code","source":"# Imports\nimport numpy as np # linear algebra\nimport pandas as pd # data processing, CSV file I/O (e.g. pd.read_csv)\n\nfrom os import listdir\nfrom os.path import isfile, join\nimport matplotlib.pylab as plt\nimport os\nimport seaborn as sns\nfrom tqdm import tqdm\n\nfrom keras.applications import DenseNet121\nfrom keras.preprocessing.image import ImageDataGenerator\nfrom keras.callbacks import Callback, ModelCheckpoint\nfrom keras.preprocessing.image import ImageDataGenerator\nfrom keras.initializers import Constant\nfrom keras.models import Sequential\nfrom keras.optimizers import Adam\nfrom keras import layers\n\nimport os\n\n\n# Any results you write to the current directory are saved as output.","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"Set the input path of the data for easy access when importing the files."},{"metadata":{"trusted":true},"cell_type":"code","source":"INPUT_PATH = \"../input/rsna-intracranial-hemorrhage-detection/\"\nTRAIN_DIRECTORY = 'stage_1_train_images/'\nTEST_DIRECTORY = 'stage_1_test_images/'","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"train_dataframe = pd.read_csv(INPUT_PATH + \"stage_1_train.csv\")\ntrain_dataframe.head()","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"label = train_dataframe.Label.values","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"We need to separate the labels from the id in order to structure the data to better work with a CNN\n"},{"metadata":{},"cell_type":"markdown","source":"Reformat the CSV's"},{"metadata":{"trusted":true},"cell_type":"code","source":"train_dataframe['filename'] = train_dataframe['ID'].apply(lambda st: \"ID_\" + st.split('_')[1] + \".png\")\ntrain_dataframe['type'] = train_dataframe['ID'].apply(lambda st: st.split('_')[2])","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"train_dataframe.head()","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"We should reformat the data so that each column is a label, which will allow us to work with the data better in the CNN."},{"metadata":{"trusted":true},"cell_type":"code","source":"pivot_df = train_dataframe[['Label', 'filename', 'type']].drop_duplicates().pivot(\n    index='filename', columns='type', values='Label').reset_index()\nprint(pivot_df.shape)\npivot_df.head()","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"train_dir = INPUT_PATH + \"stage_1_train_images/\"\ntrain_files = os.listdir(train_dir)\ntrain_size = len(train_files)\ntrain_size","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"**Image Examples, loading images**"},{"metadata":{"trusted":true},"cell_type":"code","source":"#Get the training image directory\ntrain_images_directory = '../input/rsna-intracranial-hemorrhage-detection/stage_1_train_images/'\n#get the training images\ntrain_images = [file for file in listdir(train_images_directory) if isfile(join(train_images_directory,file))]\n#repeat for test images\ntest_images_directory = '../input/rsna-intracranial-hemorrhage-detection/stage_1_test_images/'\ntest_images = [file for file in listdir(test_images_directory) if isfile(join(test_images_directory, file))]\n#check some image filenames\nprint('5 Training Image Files', train_images[:5] )\n","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"I will take a random subset of the whole set to save some time while developing the model. 100k should be ok for now\n"},{"metadata":{"trusted":true},"cell_type":"code","source":"np.random.seed(42)\nsample_files = np.random.choice(train_files, 100000)\nsample_df = pivot_df[pivot_df.filename.apply(lambda x: x.replace('.png', '.dcm')).isin(sample_files)]","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"We need to do some Preprocessing before we can feed this into a NN. \n\nSource: https://www.kaggle.com/omission/eda-view-dicom-images-with-correct-windowing\n\nWe should rescale the data, resize the data, and convert to png\n\n"},{"metadata":{"trusted":true},"cell_type":"code","source":"def window_image(img, window_center,window_width, intercept, slope, rescale=True):\n\n    img = (img*slope +intercept)\n    img_min = window_center - window_width//2\n    img_max = window_center + window_width//2\n    img[img<img_min] = img_min\n    img[img>img_max] = img_max\n    \n    if rescale:\n        # Extra rescaling to 0-1, not in the original notebook\n        img = (img - img_min) / (img_max - img_min)\n    \n    return img\n    \ndef get_first_of_dicom_field_as_int(x):\n    #get x[0] as in int is x is a 'pydicom.multival.MultiValue', otherwise get int(x)\n    if type(x) == pydicom.multival.MultiValue:\n        return int(x[0])\n    else:\n        return int(x)\n\ndef get_windowing(data):\n    dicom_fields = [data[('0028','1050')].value, #window center\n                    data[('0028','1051')].value, #window width\n                    data[('0028','1052')].value, #intercept\n                    data[('0028','1053')].value] #slope\n    return [get_first_of_dicom_field_as_int(x) for x in dicom_fields]","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"from tqdm import tqdm\nimport pydicom\nimport cv2\ndef save_and_resize(filenames, load_dir):    \n    save_dir = '/kaggle/tmp/'\n    if not os.path.exists(save_dir):\n        os.makedirs(save_dir)\n\n    for filename in tqdm(filenames):\n        path = load_dir + filename\n        new_path = save_dir + filename.replace('.dcm', '.png')\n        \n        dcm = pydicom.dcmread(path)\n        window_center , window_width, intercept, slope = get_windowing(dcm)\n        img = dcm.pixel_array\n        img = window_image(img, window_center, window_width, intercept, slope)\n        \n        resized = cv2.resize(img, (224, 224))\n        res = cv2.imwrite(new_path, resized)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"#to save time with the commit I have commented this step out - it takes some time\n#TODO : Speed this up or look at working directly with the dicom images? \n\nsave_and_resize(filenames=sample_files, load_dir=INPUT_PATH + TRAIN_DIRECTORY)\n#save_and_resize(filenames=os.listdir(INPUT_PATH + TEST_DIRECTORY), load_dir=INPUT_PATH + TEST_DIRECTORY)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"#Lets try using DenseNet 121\n\ndensenet= DenseNet121(\n    weights = None,\n    include_top= False,\n    input_shape=(224,224,3)\n)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"def build_dense_model():\n    model = Sequential()\n    model.add(densenet)\n    model.add(layers.GlobalAveragePooling2D())\n    model.add(layers.Dense(6, activation='sigmoid', \n                           bias_initializer=Constant(value=-5.5)))\n    \n    model.compile(\n        loss='categorical_crossentropy',\n        optimizer=Adam(lr=0.001),\n        metrics=['accuracy']\n    )\n    \n    return model","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"model = build_dense_model()\nmodel.summary()","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"#This datagen is used for feeding in the train data. \n\nBATCH_SIZE = 64\n\ndef create_datagen():\n    return ImageDataGenerator(validation_split=0.15)\n\n\ndef create_flow(datagen, subset):\n    return datagen.flow_from_dataframe(\n        pivot_df, \n        directory='/kaggle/tmp/',\n        x_col='filename', \n        y_col=['any', 'epidural', 'intraparenchymal', \n               'intraventricular', 'subarachnoid', 'subdural'],\n        class_mode='multi_output',\n        target_size=(224, 224),\n        batch_size=BATCH_SIZE,\n        subset=subset\n    )\n\n# Using original generator\ndata_generator = create_datagen()\ntrain_gen = create_flow(data_generator, 'training')\nval_gen = create_flow(data_generator, 'validation')\n","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"checkpoint = ModelCheckpoint(\n    'model.h5', \n    monitor='val_loss', \n    verbose=0, \n    save_best_only=True, \n    save_weights_only=False,\n    mode='auto'\n)\n\ntotal_steps = sample_files.shape[0] / BATCH_SIZE\n\nhistory = model.fit_generator(\n    train_gen,\n    steps_per_epoch=2000,\n    validation_data=val_gen,\n    validation_steps=total_steps * 0.15,\n    callbacks=[checkpoint],\n    epochs=5\n)","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":1}