{"cells":[{"metadata":{"_uuid":"8f2839f25d086af736a60e9eeb907d3b93b6e0e5","_cell_guid":"b1076dfc-b9ad-4769-8c92-a6c4dae69d19","trusted":true,"collapsed":true},"cell_type":"code","source":"# This Python 3 environment comes with many helpful analytics libraries installed\n# It is defined by the kaggle/python docker image: https://github.com/kaggle/docker-python\n# For example, here's several helpful packages to load in \n\nimport numpy as np # linear algebra\nimport pandas as pd # data processing, CSV file I/O (e.g. pd.read_csv)\nfrom PIL import Image\nfrom keras.preprocessing import image as Kimage\nfrom keras.utils import np_utils\nfrom keras.applications.xception import Xception, preprocess_input\nfrom keras.layers import Conv2D, MaxPooling2D, GlobalAveragePooling2D\nfrom keras.layers import Dropout, Flatten, Dense\nfrom keras.models import Sequential\nfrom keras.preprocessing.image import ImageDataGenerator\nfrom keras.callbacks import ModelCheckpoint  \nfrom keras import optimizers\n\nfrom tqdm import tqdm\nimport pydicom\nfrom sklearn.model_selection import train_test_split\nimport matplotlib.pyplot as plt\n\n# Input data files are available in the \"../input/\" directory.\n# For example, running this (by clicking run or pressing Shift+Enter) will list the files in the input directory\n\nimport os\nprint(os.listdir(\"../input/\"))\n\n# Any results you write to the current directory are saved as output.","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"collapsed":true,"_uuid":"6c9a54c8bf7b169e13b80df398701dbc3e3dbcfa"},"cell_type":"code","source":"model_type = 'FC1024'\ndropout = 0.2\noptimizer_type = 'Adam'\nlearning_rate = 1e-4\nAugmentation_Indicator = False\nepochs = 20\nbatch_size = 8\ntransfer_learning = True\nrandom_state = 1607","execution_count":null,"outputs":[]},{"metadata":{"_cell_guid":"79c7e3d0-c299-4dcb-8224-4455121ee9b0","_uuid":"d629ff2d2480ee46fbb7e2d37f6b5fab8052498a","trusted":true,"collapsed":true},"cell_type":"code","source":"# Load train labels\ninput_data = pd.read_csv(\"../input/stage_1_detailed_class_info.csv\")\ninput_data['img_path'] = '../input/stage_1_train_images/' + input_data['patientId'] + '.dcm'\n\n# Convert class into categorical variable\ninput_data['class'] = pd.Categorical(input_data['class'])\ninput_data['target'] = input_data['class'].cat.codes\n\n# Start with around 1500 - 2000 images \n# This step is not needed when it is going to be trained with full resources \nremove, input_data  = train_test_split(input_data, \n                                test_size=0.01, \n                                random_state=random_state,\n                                stratify=input_data['class'])\n\nprint('Total images taken: {}'.format(input_data.shape[0]))\ninput_data.head()","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"_uuid":"c739373465e3979cef34d8734725c83eaa96555f","collapsed":true},"cell_type":"code","source":"# Split train and test images\ntrain, test = train_test_split(input_data, \n                                test_size=0.20, \n                                random_state=random_state,\n                                stratify=input_data['class'])\n\n# Split train and validation images\ntrain, valid = train_test_split(train, \n                                test_size=0.20, \n                                random_state=random_state,\n                                stratify=train['class'])\n\nprint('Total train images taken: {}'.format(train.shape[0]))\nprint('Total validation images taken: {}'.format(valid.shape[0]))\nprint('Total test images taken: {}'.format(test.shape[0]))\n","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"_uuid":"238baf68557c4b15e822eb56aa6a944ea4cc1605","collapsed":true},"cell_type":"code","source":"# Show the class balance in train images\nfig = plt.figure(figsize=(4,4), dpi=100)\nax = plt.subplot(111)\ncolors = ['#ff9999','#66b3ff','#99ff99','#ffcc99']\ntrain['class'].value_counts().plot(kind='pie', ax=ax, autopct='%1.1f%%', \n                                   startangle=90, fontsize=10, colors = colors)\n","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"_uuid":"4fa9b93b43a5bf88538fd8d12aafac4671eaa387","collapsed":true},"cell_type":"code","source":"ax = plt.subplot(111)\ntrain['class'].value_counts().plot(kind='bar', ax=ax, color=colors)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"_uuid":"2a9c0ce65edcc647a02e841c6ba5979937248554","collapsed":true},"cell_type":"code","source":"\"\"\"fig, axs = plt.subplots(1,2, dpi=120, figsize=(4,4))\ncolors = ['#ff9999','#66b3ff','#99ff99','#ffcc99']\ntrain['class'].value_counts().plot(kind='pie', ax=axs[0], autopct='%1.1f%%', \n                                   startangle=90, fontsize=10, colors = colors)\ntrain['class'].value_counts().plot(kind='bar', ax=axs[1], color=colors)\n#plt.legend(loc=\"right\", fontsize=10)\n#fig.subplots_adjust(wspace=2)\"\"\"","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"_uuid":"e6f46cc3bd3e1133f27a33cd9f958e419a6ed1c2","collapsed":true},"cell_type":"code","source":"for i, row in enumerate(train.head().values):\n    image_name = row[0]\n    pneumonia_class = row[1]\n    image_path = row[2]\n    ds = pydicom.dcmread(image_path)\n    plt.figure()\n    plt.imshow(ds.pixel_array, cmap=plt.cm.bone)\n    plt.title(pneumonia_class)\n    #print(pneumonia_class)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"_uuid":"dcd9c8b169ac739a4b90450cb4422762bc4d4e9b","collapsed":true},"cell_type":"code","source":"\"\"\"# Print sample images\nim_per_row = 4\nlength = train.head().values.shape[0]\n#fig, ax = plt.subplots(2, im_per_row, figsize=(6,6), dpi=100)\nfig = plt.figure()\nj = 1\nfor i, row in enumerate(train.head().values):\n    image = row[0]\n    pneumonia_class = row[1]\n    ds = pydicom.dcmread('../input/stage_1_train_images/'+image+'.dcm')\n    fig.add_subplot(j,4,i+1, sharex=True)\n    plt.imshow(ds.pixel_array, cmap=plt.cm.bone)\n    plt.title(pneumonia_class)\n    if i % length == 0:\n        j+=1\n    #print(pneumonia_class)\"\"\"","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"_uuid":"687c3481f736c930d4423bd112a2e53f083e2971","collapsed":true},"cell_type":"code","source":"def load_dicom_image(img_path):\n    img_arr = pydicom.read_file(img_path).pixel_array\n    img_arr = img_arr/img_arr.max()\n    slice_value = (255*img_arr).clip(0, 255).astype(np.uint8)\n    img = Image.fromarray(slice_value)\n    Kimage.pil_image = img\n    return Kimage.pil_image\n\n# Convert 3D tensors to 4D tensors where each 4D tensor is a different image\ndef path_to_tensor(img_path):\n    # Read the dcm image using pydicom\n    img = load_dicom_image(img_path)\n    # convert PIL.Image.Image type to 3D tensor\n    x = Kimage.img_to_array(img)\n    # Since it is a grayscale image convert into three channels\n    x = np.squeeze(np.repeat(x[:, :, np.newaxis], 3, axis=2), axis=3)\n    # convert 3D tensor to 4D tensor with shape and return 4D tensor\n    return np.expand_dims(x, axis=0)\n\ndef paths_to_tensor(img_paths):\n    list_of_tensors = [preprocess_input(path_to_tensor(img_path)) for img_path in tqdm(img_paths)]\n    return np.vstack(list_of_tensors)\n","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"_uuid":"a9c2d47fe98177041fc8146eddabe9181f9b2356","collapsed":true},"cell_type":"code","source":"# Load all the tensors and re-scale the data\ntrain_tensors = paths_to_tensor(train['img_path'])\nvalid_tensors = paths_to_tensor(valid['img_path'])\ntest_tensors = paths_to_tensor(test['img_path'])\n","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"_uuid":"e4de2cede9a208738e0822c04fb21cc75b4d13fe","collapsed":true},"cell_type":"code","source":"# Load all the targets\ntrain_targets = np_utils.to_categorical(np.array(train['target']), 3)\nvalid_targets = np_utils.to_categorical(np.array(valid['target']), 3)\ntest_targets = np_utils.to_categorical(np.array(test['target']), 3)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"_uuid":"7b086f793831289024a74e93a48adee8f04482fc","collapsed":true},"cell_type":"code","source":"test_tensors.shape","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"_uuid":"c8dbf2ddf49b947aee0a5a6666149039d98697a9","collapsed":true},"cell_type":"code","source":"if transfer_learning:\n    # Load Xception model from keras\n    base_model = Xception(input_shape=(1024, 1024, 3), weights='imagenet', include_top=False)\n    base_model.trainable = False\n    input_shape=base_model.get_output_shape_at(0)[1:]\n    learning_name = 'XceptionTransferLearning'\nelse:\n    input_shape=(1024, 1024, 3)\n    learning_name = 'OwnCNN'","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"_uuid":"38d92c81eb6eaa6bb8b04d1279b507bd8d083dbf","collapsed":true},"cell_type":"code","source":"if model_type == 'FC1024':\n    # Build the final layer of the model\n    model = Sequential()\n\n    model.add(Conv2D(filters=1024, kernel_size=2, padding='same', activation='relu', input_shape=input_shape))\n    model.add(MaxPooling2D(pool_size=2))\n    model.add(Dropout(dropout))\n    model.add(Conv2D(filters=512, kernel_size=2, padding='same', activation='tanh'))\n    model.add(Dropout(dropout))\n    model.add(MaxPooling2D(pool_size=2))\n    model.add(Conv2D(filters=256, kernel_size=2, padding='same', activation='relu'))\n    model.add(Dropout(dropout))\n    model.add(MaxPooling2D(pool_size=2))\n    model.add(Conv2D(filters=256, kernel_size=2, padding='same', activation='relu'))\n    model.add(Dropout(dropout))\n    model.add(MaxPooling2D(pool_size=2))\n    model.add(Conv2D(filters=256, kernel_size=2, padding='same', activation='relu'))\n    model.add(GlobalAveragePooling2D())\n    model.add(Dense(3, activation='softmax'))\n\n    model.summary()\nelif model_type == 'FC16':\n    model = Sequential()\n\n    model.add(Conv2D(filters=16, kernel_size=2, padding='same', activation='relu', input_shape=input_shape))\n    model.add(MaxPooling2D(pool_size=2))\n    model.add(Dropout(dropout))\n    model.add(Conv2D(filters=32, kernel_size=2, padding='same', activation='tanh'))\n    model.add(Dropout(dropout))\n    model.add(MaxPooling2D(pool_size=2))\n    model.add(Conv2D(filters=64, kernel_size=2, padding='same', activation='relu'))\n    model.add(Dropout(dropout))\n    model.add(MaxPooling2D(pool_size=2))\n    model.add(Conv2D(filters=64, kernel_size=2, padding='same', activation='relu'))\n    model.add(Dropout(dropout))\n    model.add(MaxPooling2D(pool_size=2))\n    model.add(Conv2D(filters=64, kernel_size=2, padding='same', activation='relu'))\n    model.add(GlobalAveragePooling2D())\n    model.add(Dense(3, activation='softmax'))\n\n    model.summary()\nelse:\n    model = Sequential()\n    model.add(GlobalAveragePooling2D(input_shape=input_shape))\n    model.add(Dense(3, activation='softmax'))\n\n    model.summary()","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"_uuid":"19797656c84e9b970897ffa125545e990d590592","collapsed":true},"cell_type":"code","source":"if transfer_learning:# Combine pre-trained model and customized final layers\n    final_model = Sequential(name='Pneumonia Classifier')\n    final_model.add(base_model)\n    final_model.add(model)\nelse:\n    final_model = model\n    \nfinal_model.summary()","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"_uuid":"72ebbfcae094d7e9af04236a4dae413659b5e9ec","collapsed":true},"cell_type":"code","source":"# Compile the model\nif optimizer_type == 'SGD':\n    optimizer=optimizers.SGD(lr=learning_rate, momentum=0.9)\nelif optimizer_type == 'Adam':\n    optimizer = optimizers.Adam(lr=learning_rate)\nelse:\n    optimizer = optimizers.RMSprop()\n    \nfinal_model.compile(optimizer=optimizer, loss='categorical_crossentropy', metrics=['categorical_accuracy'])","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"_uuid":"82486188faee0df46f0510e92dcd893ccb532854","collapsed":true},"cell_type":"code","source":"# create and configure augmented image generator\ndatagen_train = ImageDataGenerator(\n        rotation_range=25,\n        width_shift_range=0.2,\n        height_shift_range=0.2,\n        shear_range=0.2,\n        zoom_range=0.2,\n        horizontal_flip=True,\n        fill_mode='nearest')\n\n# create and configure augmented image generator\ndatagen_valid = ImageDataGenerator(\n        rotation_range=25,\n        width_shift_range=0.2,\n        height_shift_range=0.2,\n        shear_range=0.2,\n        zoom_range=0.2,\n        horizontal_flip=True,\n        fill_mode='nearest')\n# fit augmented image generator on data\ndatagen_train.fit(train_tensors)\ndatagen_valid.fit(valid_tensors)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"_uuid":"13e51e7aba72f023f49f2afb42531d45ff0e776c","collapsed":true},"cell_type":"code","source":"os.mkdir('/kaggle/working/saved-models')","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"_uuid":"9a33c3d260378d959ede385082750d39784ea55e","collapsed":true},"cell_type":"code","source":"if Augmentation_Indicator:\n    model_weights_name = 'weights.best.{}_wAug_{}_{}_{}_{}_{}_{}.hd5'.format(learning_name, model_type, dropout, optimizer_type,learning_rate, epochs, batch_size)\nelse:\n    model_weights_name = 'weights.best.{}_woAug_{}_{}_{}_{}_{}_{}.hd5'.format(learning_name, model_type, dropout, optimizer_type,learning_rate, epochs, batch_size)\nprint(model_weights_name)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"_uuid":"2a367d60e61c5e790aa5f8dbe4acf2dbf27e495b","collapsed":true},"cell_type":"code","source":"from keras.callbacks import ModelCheckpoint  \n\ncheckpointer = ModelCheckpoint(filepath='/kaggle/working/saved-models/{}'.format(model_weights_name), \n                               verbose=1, save_best_only=True)\n\nif Augmentation_Indicator:\n    final_model.fit_generator(datagen_train.flow(train_tensors, train_targets, batch_size=batch_size),\n                                                steps_per_epoch=train_tensors.shape[0] // batch_size,\n                                                epochs=epochs, verbose=1, callbacks=[checkpointer],\n                                                validation_data=datagen_valid.flow(valid_tensors, valid_targets, batch_size=batch_size),\n                                                validation_steps=valid_tensors.shape[0] // batch_size)\nelse:\n    final_model.fit(train_tensors, train_targets, \n              validation_data=(valid_tensors, valid_targets),\n              epochs=epochs, batch_size=batch_size, callbacks=[checkpointer], verbose=1)\n\n\n","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"_uuid":"8eae36666aef41e37b667444e70c7a3cdbb2470e","collapsed":true},"cell_type":"code","source":"final_model.load_weights('/kaggle/working/saved-models/{}'.format(model_weights_name))","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"_uuid":"9efa70a6ae9653cf102db36f5b864d4103aa96be","collapsed":true},"cell_type":"code","source":"# get index of predicted value for each image in test set\npredictions = [np.argmax(final_model.predict(np.expand_dims(tensor, axis=0))) for tensor in test_tensors]\n\n# report test accuracy\ntest_accuracy = 100*np.sum(np.array(predictions)==np.argmax(test_targets, axis=1))/len(predictions)\nprint('Test accuracy: %.4f%%' % test_accuracy)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"_uuid":"1ed3a8b17fdf420c8be1062071e0ab01c53ffd15","collapsed":true},"cell_type":"code","source":"from sklearn.metrics import classification_report\ntarget_names = ['Lung Opacity', 'No Lung Opacity / Not Normal', 'Normal']\nprint(classification_report(np.array(predictions), np.argmax(test_targets, axis=1), target_names = target_names))","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"_uuid":"ad537c1055a0d368d36acafb87a18e64575b7176","collapsed":true},"cell_type":"code","source":"test_accuracy_dict = {}\nfor model_weights in os.listdir('/kaggle/working/saved-models/'):\n    print(model_weights)\n    test_accuracy_dict[model_weights] = test_accuracy","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"_uuid":"5843344723a424599641cc20f6c49886f659fc65","collapsed":true},"cell_type":"code","source":"test_accuracy_dict","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"collapsed":true,"_uuid":"6abfcfd694dfa3e58d365835cb1cdbf6f17173f9"},"cell_type":"code","source":"","execution_count":null,"outputs":[]}],"metadata":{"kernelspec":{"display_name":"Python 3","language":"python","name":"python3"},"language_info":{"name":"python","version":"3.6.4","mimetype":"text/x-python","codemirror_mode":{"name":"ipython","version":3},"pygments_lexer":"ipython3","nbconvert_exporter":"python","file_extension":".py"}},"nbformat":4,"nbformat_minor":1}