{"cells":[{"metadata":{},"cell_type":"markdown","source":"#                               500 no disease 1000 disease (unbalanced)"},{"metadata":{"_uuid":"d629ff2d2480ee46fbb7e2d37f6b5fab8052498a","_cell_guid":"79c7e3d0-c299-4dcb-8224-4455121ee9b0","trusted":true},"cell_type":"code","source":"import pandas as pd\nimport numpy as np\nfrom numpy.random import seed\nseed(101)\n\nimport tensorflow as tf\n\nfrom tensorflow import keras\nfrom tensorflow.keras.preprocessing.image import ImageDataGenerator\nfrom tensorflow.keras.layers import Conv2D, MaxPooling2D\nfrom tensorflow.keras.layers import Dense, Dropout, Flatten, Activation\nfrom tensorflow.keras.models import Sequential\nfrom tensorflow.keras.callbacks import EarlyStopping, ReduceLROnPlateau, ModelCheckpoint\nfrom tensorflow.keras.optimizers import Adam\n\nimport os\nimport cv2\n\nfrom sklearn.utils import shuffle\nfrom sklearn.metrics import confusion_matrix\nfrom sklearn.model_selection import train_test_split\nimport itertools\nimport shutil\nimport matplotlib.pyplot as plt\n%matplotlib inline","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"# Setting Some Pre-Requisites\nSAMPLE_SIZE = 500\nSAMPLE_SIZE1 = 1000","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"Labels as per csv file\n\n0 = no met tissue\n\n1 = has met tissue."},{"metadata":{"trusted":true},"cell_type":"code","source":"# Creating a dataframe of all the training images\n\ndf_data = pd.read_csv('../input/histopathologic-cancer-detection/train_labels.csv')\n\n# removing this image because it caused a training error previously\ndf_data[df_data['id'] != 'dd6dfed324f9fcb6f93f46f32fc800f2ec196be2']\n\n# removing this image because it's black\ndf_data[df_data['id'] != '9369c7278ec8bcc6c880d99194de09fc2bd4efbe']\n\n\nprint(df_data.shape)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"# Create the Train and Validation Sets\n\n#Un Balanced 0-500 1-1000\n\ndf_0=df_data[df_data['label']==0].sample(SAMPLE_SIZE,random_state=101)\ndf_1=df_data[df_data['label']==1].sample(SAMPLE_SIZE1,random_state=101)\n\n# concat the dataframes\ndf_data = pd.concat([df_0, df_1], axis=0).reset_index(drop=True)\n# shuffle\ndf_data = shuffle(df_data)\n\ndf_data['label'].value_counts()","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"# Going to split 20% of the training set into a validation set"},{"metadata":{"trusted":true},"cell_type":"code","source":"# Now, for the train-test split\n\n# stratify=y creates a balanced validation set.\ny = df_data['label']\n\ndf_train, df_val = train_test_split(df_data, test_size=0.20, random_state=101, stratify=y)\n\nprint(df_train.shape)\nprint(df_val.shape)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"df_train['label'].value_counts()\n","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"df_val['label'].value_counts()","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"Increasing the size of the image results in a much higher performance"},{"metadata":{"trusted":true},"cell_type":"code","source":"\nIMAGE_SIZE = 196\nIMAGE_CHANNELS = 3","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"# Create a new directory\nbase_dir = 'base_dir'\nos.mkdir(base_dir)\n\n\n#[CREATE FOLDERS INSIDE THE BASE DIRECTORY]\n\n# now we create 2 folders inside 'base_dir':\n\n# train_dir\n    # a_no_met_tissue\n    # b_has_met_tissue\n\n# val_dir\n    # a_no_met_tissue\n    # b_has_met_tissue\n\n\n\n# create a path to 'base_dir' to which we will join the names of the new folders\n# train_dir\ntrain_dir = os.path.join(base_dir, 'train_dir')\nos.mkdir(train_dir)\n\n# val_dir\nval_dir = os.path.join(base_dir, 'val_dir')\nos.mkdir(val_dir)\n\n\n\n# [CREATE FOLDERS INSIDE THE TRAIN AND VALIDATION FOLDERS]\n# Inside each folder we create seperate folders for each class\n\n# create new folders inside train_dir\nno_met_tissue = os.path.join(train_dir, 'a_no_met_tissue')\nos.mkdir(no_met_tissue)\nhas_met_tissue = os.path.join(train_dir, 'b_has_met_tissue')\nos.mkdir(has_met_tissue)\n\n\n# create new folders inside val_dir\nno_met_tissue = os.path.join(val_dir, 'a_no_met_tissue')\nos.mkdir(no_met_tissue)\nhas_met_tissue = os.path.join(val_dir, 'b_has_met_tissue')\nos.mkdir(has_met_tissue)\n","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"Transfer the images into the folders"},{"metadata":{"trusted":true},"cell_type":"code","source":"# Set the id as the index in df_data\ndf_data.set_index('id', inplace=True ) ","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"# Get a list of train and val images\ntrain_list = list(df_train['id'])\nval_list = list(df_val['id'])\n\n\n# Transfer the train images\n\nfor image in train_list:\n    \n    # the id in the csv file does not have the .tif extension therefore we add it here\n    fname_tif = image + '.tif'\n    # get the label for a certain image\n    target = df_data.loc[image,'label']\n    \n    # these must match the folder names\n    if target == 0:\n        label = 'a_no_met_tissue'\n    if target == 1:\n        label = 'b_has_met_tissue'\n    \n    # source path to image\n    src = os.path.join('../input/histopathologic-cancer-detection/train', fname_tif)\n    # change the new file name to png\n    fname_png = image + '.png'\n    # destination path to image\n    dst = os.path.join(train_dir, label, fname_png)\n\n    \n    # read the file as an array\n    cv2_image = cv2.imread(src)\n    # save the image at the destination as a png file\n    cv2.imwrite(dst, cv2_image)\n    \n    \n# Transfer the val images\n\nfor image in val_list:\n    \n    # the id in the csv file does not have the .tif extension therefore we add it here\n    fname_tif = image + '.tif'\n    # get the label for a certain image\n    target = df_data.loc[image,'label']\n    \n    # these must match the folder names\n    if target == 0:\n        label = 'a_no_met_tissue'\n    if target == 1:\n        label = 'b_has_met_tissue'\n    \n\n    # source path to image\n    src = os.path.join('../input/histopathologic-cancer-detection/train', fname_tif)\n    # change the new file name to png\n    fname_png = image + '.png'\n    # destination path to image\n    dst = os.path.join(val_dir, label, fname_png)\n\n    \n    # read the file as an array\n    cv2_image = cv2.imread(src)\n    # save the image at the destination as a png file\n    cv2.imwrite(dst, cv2_image)\n \n\n","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"# Set up the generators\ntrain_path = 'base_dir/train_dir'\nvalid_path = 'base_dir/val_dir'\ntest_path = '../input/histopathologic-cancer-detection/test'\n\nnum_train_samples = len(df_train)\nnum_val_samples = len(df_val)\ntrain_batch_size = 10\nval_batch_size = 10\n\n\ntrain_steps = np.ceil(num_train_samples / train_batch_size)\nval_steps = np.ceil(num_val_samples / val_batch_size)\n\n\n\ndatagen = ImageDataGenerator(rescale=1.0/255)\n\ntrain_gen = datagen.flow_from_directory(train_path,\n                                        target_size=(IMAGE_SIZE,IMAGE_SIZE),\n                                        batch_size=train_batch_size,\n                                        class_mode='categorical')\n\nval_gen = datagen.flow_from_directory(valid_path,\n                                        target_size=(IMAGE_SIZE,IMAGE_SIZE),\n                                        batch_size=val_batch_size,\n                                        class_mode='categorical')\n\n# Note: shuffle=False causes the test dataset to not be shuffled\ntest_gen = datagen.flow_from_directory(valid_path,\n                                        target_size=(IMAGE_SIZE,IMAGE_SIZE),\n                                        batch_size=1,\n                                        class_mode='categorical',\n                                        shuffle=False)","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"# MODEL"},{"metadata":{"trusted":true},"cell_type":"code","source":"\nkernel_size = (3,3)\npool_size= (2,2)\nfirst_filters = 32\nsecond_filters = 64\nthird_filters = 128\n\ndropout_conv = 0.3\ndropout_dense = 0.3\n\n\nmodel = Sequential()\nmodel.add(Conv2D(first_filters, kernel_size, activation = 'relu', input_shape = (196, 196, 3)))\nmodel.add(Conv2D(first_filters, kernel_size, activation = 'relu'))\nmodel.add(Conv2D(first_filters, kernel_size, activation = 'relu'))\nmodel.add(MaxPooling2D(pool_size = pool_size)) \nmodel.add(Dropout(dropout_conv))\n\nmodel.add(Conv2D(second_filters, kernel_size, activation ='relu'))\nmodel.add(Conv2D(second_filters, kernel_size, activation ='relu'))\nmodel.add(Conv2D(second_filters, kernel_size, activation ='relu'))\nmodel.add(MaxPooling2D(pool_size = pool_size))\nmodel.add(Dropout(dropout_conv))\n\nmodel.add(Conv2D(third_filters, kernel_size, activation ='relu'))\nmodel.add(Conv2D(third_filters, kernel_size, activation ='relu'))\nmodel.add(Conv2D(third_filters, kernel_size, activation ='relu'))\nmodel.add(MaxPooling2D(pool_size = pool_size))\nmodel.add(Dropout(dropout_conv))\n\nmodel.add(Flatten())\nmodel.add(Dense(256, activation = \"relu\"))\nmodel.add(Dropout(dropout_dense))\nmodel.add(Dense(2, activation = \"softmax\"))\n\nmodel.summary()\n","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"raw","source":"Train the model\n"},{"metadata":{"trusted":true},"cell_type":"code","source":"model.compile(Adam(lr=0.0001), loss='binary_crossentropy', \n              metrics=['accuracy'])","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"# Get the labels that are associated with each index\nprint(val_gen.class_indices)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"filepath = \"model.h5\"\ncheckpoint = ModelCheckpoint(filepath, monitor='val_acc', verbose=1, \n                             save_best_only=True, mode='max')\n\nreduce_lr = ReduceLROnPlateau(monitor='val_acc', factor=0.5, patience=2, \n                                   verbose=1, mode='max', min_lr=0.00001)\n                              \n                              \ncallback_list = [checkpoint, reduce_lr]\n\nhistory = model.fit_generator(train_gen, steps_per_epoch=train_steps, \n                    validation_data=val_gen,\n                    validation_steps=val_steps,\n                    epochs=30, verbose=1,\n                   callbacks =callback_list)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"# Here the best epoch will be used.\n\nval_loss, val_acc = \\\nmodel.evaluate_generator(test_gen, \n                        steps=len(df_val))\n\nprint('val_loss:', val_loss)\nprint('val_acc:', val_acc)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"epochs = [i for i in range(1, len(history.history['loss'])+1)]\n\nplt.plot(epochs, history.history['loss'], color='blue', label=\"training_loss\")\nplt.plot(epochs, history.history['val_loss'], color='red', label=\"validation_loss\")\nplt.legend(loc='best')\nplt.title('Loss')\nplt.xlabel('epoch')\nplt.show()\n\nplt.plot(epochs, history.history['accuracy'], color='blue', label=\"training_accuracy\")\nplt.plot(epochs, history.history['val_accuracy'], color='red',label=\"validation_accuracy\")\nplt.legend(loc='best')\nplt.title('Accuracy')\nplt.xlabel('epoch')\nplt.show()\n","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"# **Validation And Analysis**"},{"metadata":{},"cell_type":"markdown","source":"Make a prediction on the val set\n\nWe need these predictions to calculate the AUC score."},{"metadata":{"trusted":true},"cell_type":"code","source":"# make a prediction\npredictions = model.predict_generator(test_gen, steps=len(df_val), verbose=1)","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"A note on Keras class index values\n\nKeras assigns it's own index value (here 0 and 1) to the classes. It infers the classes based on the folder structure. Important: These index values may not match the index values we were given in the train_labels.csv file.\n\nI've used 'a' and 'b' folder name pre-fixes to get keras to assign index values to match what was in the train_labels.csv file - I guessed that keras is assigning the index value based on folder name alphabetical order."},{"metadata":{"trusted":true},"cell_type":"code","source":"# Put the predictions into a dataframe.\n# The columns need to be oredered to match the output of the previous cell\n\ndf_preds = pd.DataFrame(predictions, columns=['no_met_tissue', 'has_met_tissue'])\n\ndf_preds.head()","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"What is the AUC Score?"},{"metadata":{"trusted":true},"cell_type":"code","source":"# Get the true labels\ny_true = test_gen.classes\n\n# Get the predicted labels as probabilities\ny_pred = df_preds['has_met_tissue']","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"from sklearn.metrics import roc_auc_score\n\nroc_auc_score(y_true, y_pred)","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"MAKE A TEST SET PREDICTION"},{"metadata":{"trusted":true},"cell_type":"code","source":"# This outputs the file names in the sequence in which \n# the generator processed the test images.\ntest_filenames = test_gen.filenames\n\n# add the filenames to the dataframe\ndf_preds['file_names'] = test_filenames\n\ndf_preds.head()","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"# Create an id column\n\n# A file name now has this format: \n# test_images/00006537328c33e284c973d7b39d340809f7271b.tif\n\n# This function will extract the id:\n# 00006537328c33e284c973d7b39d340809f7271b\n\n\ndef extract_id(x):\n    \n    # split into a list\n    a = x.split('/')\n    # split into a list\n    b = a[1].split('.')\n    extracted_id = b[0]\n    \n    return extracted_id\n\ndf_preds['id'] = df_preds['file_names'].apply(extract_id)\n\ndf_preds.head()","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"# Get the predicted labels.\n# We were asked to predict a probability that the image has tumor tissue\nimport numpy as np\ny_pred = np.round(y_pred)\n\n# get the id column\nimage_id = df_preds['id']","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"\n\nsubmission = pd.DataFrame({'id':image_id, \n                           'label':y_pred, \n                          }).set_index('id')\n\nsubmission.to_csv('patch_preds.csv', columns=['label']) \nsubmission.head()","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}