{"cells":[{"metadata":{"_uuid":"8f2839f25d086af736a60e9eeb907d3b93b6e0e5","_cell_guid":"b1076dfc-b9ad-4769-8c92-a6c4dae69d19","trusted":true},"cell_type":"code","source":"# Input data files are available in the \"../input/\" directory.\n# For example, running this (by clicking run or pressing Shift+Enter) will list all files under the input directory\n# import os\n# for dirname, _, filenames in os.walk('/kaggle/input'):\n#     for filename in filenames:\n#         print(os.path.join(dirname, filename))","execution_count":null,"outputs":[]},{"metadata":{"_uuid":"d629ff2d2480ee46fbb7e2d37f6b5fab8052498a","_cell_guid":"79c7e3d0-c299-4dcb-8224-4455121ee9b0","trusted":true},"cell_type":"code","source":"import os\nimport shutil\nimport numpy as np\nimport pandas as pd\nimport matplotlib.pyplot as plt\nimport matplotlib.patches as patches\nimport cv2 as cv\nfrom numpy.random import seed\nseed(45)\n\nfrom sklearn.utils import shuffle\nfrom sklearn.metrics import confusion_matrix\nfrom sklearn.model_selection import train_test_split\nimport tensorflow as tf\nfrom tensorflow.keras.callbacks import ModelCheckpoint, ReduceLROnPlateau, EarlyStopping\nfrom tensorflow.keras.models import Sequential\nfrom tensorflow.keras.layers import Dense, Conv2D, Flatten, Dropout, MaxPooling2D\nfrom tensorflow.keras.preprocessing.image import ImageDataGenerator\n\n%matplotlib inline","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"train_dirname = '/kaggle/input/histopathologic-cancer-detection/train'","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"# Dataset exploration"},{"metadata":{"trusted":true},"cell_type":"code","source":"train_labels = pd.read_csv('/kaggle/input/histopathologic-cancer-detection/train_labels.csv')\ntrain_labels.head()","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"train_labels['label'].value_counts()","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"Data is not entirely balanced, there is more negative samples than positive, by about 30 percent"},{"metadata":{"trusted":true},"cell_type":"code","source":"positive_samples = train_labels.loc[train_labels['label'] == 1].sample(4)\nnegative_samples = train_labels.loc[train_labels['label'] == 0].sample(4)\npositive_images = []\nnegative_images = []\nfor sample in positive_samples['id']:\n    path = os.path.join(train_dirname, sample+'.tif')\n    img = cv.imread(path)\n    positive_images.append(img)\n        \nfor sample in negative_samples['id']:\n    path = os.path.join(train_dirname, sample+'.tif')\n    img = cv.imread(path)\n    negative_images.append(img)\n\nfig,axis = plt.subplots(2,4,figsize=(20,8))\nfig.suptitle('Dataset samples presentation plot',fontsize=20)\nfor i,img in enumerate(positive_images):\n    axis[0,i].imshow(img)\n    rect = patches.Rectangle((32,32),32,32,linewidth=4,edgecolor='g',facecolor='none', linestyle=':', capstyle='round')\n    axis[0,i].add_patch(rect)\naxis[0,0].set_ylabel('Positive samples', size='large')\nfor i,img in enumerate(negative_images):\n    axis[1,i].imshow(img)\n    rect = patches.Rectangle((32,32),32,32,linewidth=4,edgecolor='r',facecolor='none', linestyle=':', capstyle='round')\n    axis[1,i].add_patch(rect)\naxis[1,0].set_ylabel('Negative samples', size='large')\n    ","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"# Splitting dataset"},{"metadata":{},"cell_type":"markdown","source":"## Creating a suitable folder structure"},{"metadata":{"trusted":true},"cell_type":"code","source":"preprocessed_dir= \"train_for_tf\" \nos.mkdir(preprocessed_dir)   \nvalidation_dir = 'val_dir'\ntraining_dir = 'train_dir'\ntest_dir = 'test_dir'\npositive_label_dir = 'positive'\nnegative_label_dir = 'negative'\nos.mkdir(os.path.join(preprocessed_dir,validation_dir))\nos.mkdir(os.path.join(preprocessed_dir,training_dir))\nos.mkdir(os.path.join(preprocessed_dir,test_dir))\nos.mkdir(os.path.join(preprocessed_dir,validation_dir,positive_label_dir))\nos.mkdir(os.path.join(preprocessed_dir,validation_dir,negative_label_dir))\nos.mkdir(os.path.join(preprocessed_dir,training_dir,positive_label_dir))\nos.mkdir(os.path.join(preprocessed_dir,training_dir,negative_label_dir))\nos.mkdir(os.path.join(preprocessed_dir,test_dir,positive_label_dir))\nos.mkdir(os.path.join(preprocessed_dir,test_dir,negative_label_dir))","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"# Setting up learning constants"},{"metadata":{"trusted":true},"cell_type":"code","source":"IMG_SIZE = 224\nIMG_CHANNELS = 3\nTRAIN_SIZE=8000\n# TRAIN_SIZE=89000\nBATCH_SIZE = 18\nEPOCHS = 30","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"## Balancing the dataset"},{"metadata":{"trusted":true},"cell_type":"code","source":"train_neg = train_labels[train_labels['label']==0].sample(TRAIN_SIZE,random_state=45)\ntrain_pos = train_labels[train_labels['label']==1].sample(TRAIN_SIZE,random_state=45)\n\ntrain_data = pd.concat([train_neg, train_pos], axis=0).reset_index(drop=True)\n\ntrain_data = shuffle(train_data)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"train_data['label'].value_counts()\ntrain_data.head()","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"## Splitting the dataset"},{"metadata":{"trusted":true},"cell_type":"code","source":"y = train_data['label']\ntrain_df, val_df = train_test_split(train_data, test_size=0.3, random_state=45, stratify=y)\ny = val_df['label']\nval_df, test_df = train_test_split(val_df, test_size=0.5, random_state=45, stratify=y)\nprint(train_df.shape)\nprint(val_df.shape)\nprint(test_df.shape)","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"## Copying splitted data to respective directories"},{"metadata":{"trusted":true},"cell_type":"code","source":"for sample in train_df.iterrows():\n    source = os.path.join(train_dirname, sample[1]['id']+'.tif')\n    if sample[1]['label'] == 0:\n        label = 'positive'\n    else:\n        label = 'negative'\n    target = os.path.join(preprocessed_dir,training_dir,label,sample[1]['id']+'.tif')\n    shutil.copyfile(source, target)\n    \nfor sample in val_df.iterrows():\n    source = os.path.join(train_dirname, sample[1]['id']+'.tif')\n    if sample[1]['label'] == 0:\n        label = 'positive'\n    else:\n        label = 'negative'\n    target = os.path.join(preprocessed_dir,validation_dir,label,sample[1]['id']+'.tif')\n    shutil.copyfile(source, target)\n\nfor sample in test_df.iterrows():\n    source = os.path.join(train_dirname, sample[1]['id']+'.tif')\n    if sample[1]['label'] == 0:\n        label = 'positive'\n    else:\n        label = 'negative'\n    target = os.path.join(preprocessed_dir,test_dir,label,sample[1]['id']+'.tif')\n    shutil.copyfile(source, target)","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"## Check if copied correctly"},{"metadata":{"trusted":true},"cell_type":"code","source":"print(len(os.listdir('train_for_tf/train_dir/positive')))\nprint(len(os.listdir('train_for_tf/train_dir/negative')))\nprint(len(os.listdir('train_for_tf/val_dir/positive')))\nprint(len(os.listdir('train_for_tf/val_dir/negative')))\nprint(len(os.listdir('train_for_tf/test_dir/positive')))\nprint(len(os.listdir('train_for_tf/test_dir/negative')))","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"## Prepare image generators paths"},{"metadata":{"trusted":true},"cell_type":"code","source":"TRAIN_PATH = 'train_for_tf/train_dir'\nVAL_PATH = 'train_for_tf/val_dir'\nTEST_PATH = 'train_for_tf/test_dir'\ntotal_train = len(os.listdir('train_for_tf/train_dir/positive')) + len(os.listdir('train_for_tf/train_dir/negative'))\ntotal_val = len(os.listdir('train_for_tf/val_dir/positive')) + len(os.listdir('train_for_tf/val_dir/negative'))\ntotal_test = len(os.listdir('train_for_tf/test_dir/positive')) + len(os.listdir('train_for_tf/test_dir/negative'))","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"## Image generators for the simple CNN model"},{"metadata":{"trusted":true},"cell_type":"code","source":"train_image_generator = ImageDataGenerator(rescale=1./255)\ntrain_data_gen = train_image_generator.flow_from_directory(batch_size=BATCH_SIZE,\n                                                           directory=TRAIN_PATH,\n                                                           shuffle=True,\n                                                           target_size=(IMG_SIZE, IMG_SIZE),\n                                                           class_mode='binary')\n\nvalidation_image_generator = ImageDataGenerator(rescale=1./255) # Generator for our validation data\nval_data_gen = validation_image_generator.flow_from_directory(batch_size=BATCH_SIZE,\n                                                              directory=VAL_PATH,\n                                                              target_size=(IMG_SIZE,IMG_SIZE),\n                                                              class_mode='binary')\n\ntest_image_generator = ImageDataGenerator(rescale=1./255) # Generator for our validation data\ntest_data_gen = test_image_generator.flow_from_directory(batch_size=1,\n                                                              directory=TEST_PATH,\n                                                              target_size=(IMG_SIZE,IMG_SIZE),\n                                                              class_mode='binary',shuffle=False)","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"## Create a simple model"},{"metadata":{"trusted":true},"cell_type":"code","source":"simple_model = Sequential([\n    Conv2D(16, 3, padding='same', activation='relu', input_shape=(IMG_SIZE, IMG_SIZE ,3)),\n    MaxPooling2D(),\n    Dropout(0.3),\n    Conv2D(32, 3, padding='same', activation='relu'),\n    MaxPooling2D(),\n    Dropout(0.3),\n    Conv2D(64, 3, padding='same', activation='relu'),\n    MaxPooling2D(),\n    Dropout(0.3),\n    Flatten(),\n    Dense(512, activation='relu'),\n    Dense(1)\n])\n\nsimple_model.compile(optimizer='adam',\n              loss=tf.keras.losses.BinaryCrossentropy(from_logits=True),\n              metrics=['accuracy'])\n\nsimple_model.summary()","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"## Train simple model"},{"metadata":{"trusted":true},"cell_type":"code","source":"EPOCHS = 15\ncheckpoint_filepath = 'checkpoint_simple_model.hdf5'\ncheckpoint = ModelCheckpoint(checkpoint_filepath, monitor='val_accuracy', verbose=1, \n                             save_best_only=True, mode='max')\n\nreduce_lr = ReduceLROnPlateau(monitor='val_accuracy', factor=0.5, patience=2, \n                                   verbose=1, mode='max', min_lr=0.00001)\n                              \nearly_stop = EarlyStopping(\n    monitor='val_accuracy', min_delta=0, patience=5, verbose=0, mode='auto',\n    baseline=None, restore_best_weights=True\n)                             \ncallbacks_list = [checkpoint, reduce_lr, early_stop]\n\nsimple_history = simple_model.fit_generator(train_data_gen, steps_per_epoch=total_train//BATCH_SIZE, \n                    validation_data=val_data_gen,\n                    validation_steps=total_val//BATCH_SIZE,\n                    epochs=EPOCHS, verbose=1,\n                   callbacks=callbacks_list)","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"## Image generators for the ResNet CNN model"},{"metadata":{"trusted":true},"cell_type":"code","source":"resnet50_train_image_generator = ImageDataGenerator(preprocessing_function=tf.keras.applications.resnet50.preprocess_input)\nresnet50_train_data_gen = resnet50_train_image_generator.flow_from_directory(batch_size=BATCH_SIZE,\n                                                           directory=TRAIN_PATH,\n                                                           shuffle=True,\n                                                           target_size=(IMG_SIZE, IMG_SIZE),\n                                                           class_mode='binary')\nresnet50_validation_image_generator = ImageDataGenerator(preprocessing_function=tf.keras.applications.resnet50.preprocess_input)\nresnet50_val_data_gen = resnet50_validation_image_generator.flow_from_directory(batch_size=BATCH_SIZE,\n                                                              directory=VAL_PATH,\n                                                              target_size=(IMG_SIZE,IMG_SIZE),\n                                                              class_mode='binary')\nresnet50_test_image_generator = ImageDataGenerator(preprocessing_function=tf.keras.applications.resnet50.preprocess_input)\nresnet50_test_data_gen = resnet50_test_image_generator.flow_from_directory(batch_size=1,\n                                                              directory=TEST_PATH,\n                                                              target_size=(IMG_SIZE,IMG_SIZE),\n                                                            class_mode='binary',shuffle=False)","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"## Create ResNet Model"},{"metadata":{"trusted":true},"cell_type":"code","source":"from tensorflow.keras.applications.resnet50 import ResNet50\n\ndropout_fc = 0.3\n\nresnet50_base_model = ResNet50(weights = 'imagenet', include_top = False,pooling = max, input_shape = (IMG_SIZE,IMG_SIZE,3))\nresnet50_model = Sequential([\n    resnet50_base_model,\n    Flatten(),\n    Dense(128, activation='relu'),\n    Dropout(dropout_fc),\n    Dense(1,activation=\"sigmoid\")\n])\nresnet50_model.compile(optimizer='adam',\n              loss=tf.keras.losses.BinaryCrossentropy(from_logits=True),\n              metrics=['accuracy'])\n\nresnet50_model.summary()","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"## Train ResNet50 model"},{"metadata":{"trusted":true},"cell_type":"code","source":"EPOCHS = 30\n# needs generator that zero centers the data, without rescaling\nresnet50_filepath = \"checkpoint_resnet50_model.h5\"\ncheckpoint = ModelCheckpoint(resnet50_filepath, monitor='val_accuracy', verbose=1, \n                             save_best_only=True, mode='max')\n\nreduce_lr = ReduceLROnPlateau(monitor='val_accuracy', factor=0.5, patience=2, \n                                   verbose=1, mode='max', min_lr=0.00001)\n                              \nearly_stop = EarlyStopping(\n    monitor='val_accuracy', min_delta=0, patience=5, verbose=0, mode='auto',\n    baseline=None, restore_best_weights=True\n)                             \ncallbacks_list = [checkpoint, reduce_lr, early_stop]\n\nresnet50_history = resnet50_model.fit_generator(resnet50_train_data_gen, steps_per_epoch=total_train//BATCH_SIZE, \n                    validation_data=resnet50_val_data_gen,\n                    validation_steps=total_val//BATCH_SIZE,\n                    epochs=EPOCHS, verbose=1,\n                   callbacks=callbacks_list)","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"### Create image generators for MobileNetV2"},{"metadata":{"trusted":true},"cell_type":"code","source":"#mobilenetv2_train_image_generator = ImageDataGenerator(preprocessing_function=tf.keras.applications.mobilenet_v2.preprocess_input)\n#mobilenetv2_train_data_gen = mobilenetv2_train_image_generator.flow_from_directory(batch_size=BATCH_SIZE,\n #                                                          directory=TRAIN_PATH,\n  #                                                         shuffle=True,\n   #                                                        target_size=(IMG_SIZE, IMG_SIZE),\n    #                                                       class_mode='binary')\n#mobilenetv2_validation_image_generator = ImageDataGenerator(preprocessing_function=tf.keras.applications.mobilenet_v2.preprocess_input) # Generator for our validation data\n#mobilenetv2_val_data_gen = mobilenetv2_validation_image_generator.flow_from_directory(batch_size=BATCH_SIZE,\n #                                                             directory=VAL_PATH,\n  #                                                            target_size=(IMG_SIZE,IMG_SIZE),\n   #                                                           class_mode='binary')\n#mobilenetv2_test_image_generator = ImageDataGenerator(preprocessing_function=tf.keras.applications.mobilenet_v2.preprocess_input) # Generator for our validation data\n#mobilenetv2_test_data_gen = mobilenetv2_test_image_generator.flow_from_directory(batch_size=1,\n #                                                             directory=TEST_PATH,\n  #                                                            target_size=(IMG_SIZE,IMG_SIZE),\n   #                                                           class_mode='binary',shuffle=False)","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"## Create MobileNetV2 model"},{"metadata":{"trusted":true},"cell_type":"code","source":"#from tensorflow.keras.applications.mobilenet_v2 import MobileNetV2\n\n#dropout_fc = 0.3\n#mobilenetv2_base_model = MobileNetV2(weights = 'imagenet', include_top = False, pooling = max, input_shape = (IMG_SIZE,IMG_SIZE,3))\n#mobilenetv2_model = Sequential([\n #   mobilenetv2_base_model,\n  #  Flatten(),\n   # Dense(128, activation='relu'),\n    #Dropout(dropout_fc),\n  #  Dense(1,activation=\"sigmoid\")\n#])\n#mobilenetv2_model.compile(optimizer='adam',\n #             loss=tf.keras.losses.BinaryCrossentropy(from_logits=True),\n  #            metrics=['accuracy'])\n\n#mobilenetv2_model.summary()","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"## Train MobileNetV2 model"},{"metadata":{"trusted":true},"cell_type":"code","source":"#EPOCHS = 50\n#mobilenetv2_filepath = \"mobilenetv2_model.h5\"\n#checkpoint = ModelCheckpoint(mobilenetv2_filepath, monitor='val_accuracy', verbose=1, \n #                            save_best_only=True, mode='max')\n#\n#reduce_lr = ReduceLROnPlateau(monitor='val_accuracy', factor=0.5, patience=2, \n #                                  verbose=1, mode='max', min_lr=0.00001)\n                              \n#early_stop = EarlyStopping(\n #   monitor='val_accuracy', min_delta=0, patience=5, verbose=0, mode='auto',\n  #  baseline=None, restore_best_weights=True\n#)                             \n#callbacks_list = [checkpoint, reduce_lr, early_stop]\n\n#mobilenetv2_history = mobilenetv2_model.fit_generator(mobilenetv2_train_data_gen, steps_per_epoch=total_train//BATCH_SIZE, \n #                   validation_data=mobilenetv2_val_data_gen,\n  #                  validation_steps=total_val//BATCH_SIZE,\n   #                 epochs=EPOCHS, verbose=1,\n    #               callbacks=callbacks_list)","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"## Training process plots"},{"metadata":{"trusted":true},"cell_type":"code","source":"plt.figure(figsize=(20,5))\nplt.subplot(221)\nplt.plot(resnet50_history.history['loss'], color='orange', label=\"training_loss\")\nplt.plot(resnet50_history.history['val_loss'], color='blue', label=\"validation_loss\")\nplt.legend(loc='best')\nplt.title('training plot -  - ResNet50')\nplt.xlabel('epoch')\nplt.savefig(\"training.png\", bbox_inches='tight')\n\nplt.subplot(222)\nplt.plot(resnet50_history.history['accuracy'], color='orange', label=\"training_accuracy\")\nplt.plot(resnet50_history.history['val_accuracy'], color='blue',label=\"validation_accuracy\")\nplt.legend(loc='best')\nplt.title('validation plot - ResNet50')\nplt.xlabel('epoch')\nplt.savefig(\"validation.png\", bbox_inches='tight')\nplt.show()\nplt.figure(figsize=(20,5))\nplt.subplot(223)\n#plt.plot(mobilenetv2_history.history['loss'], color='orange', label=\"training_loss\")\n#plt.plot(mobilenetv2_history.history['val_loss'], color='blue', label=\"validation_loss\")\n#plt.legend(loc='best')\n#plt.title('training plot -  - MobileNetV2')\n#plt.xlabel('epoch')\n#plt.savefig(\"training.png\", bbox_inches='tight')\n\n#plt.subplot(224)\n#plt.plot(mobilenetv2_history.history['accuracy'], color='orange', label=\"training_accuracy\")\n#plt.plot(mobilenetv2_history.history['val_accuracy'], color='blue',label=\"validation_accuracy\")\n#plt.legend(loc='best')\n#plt.title('validation plot - MobileNetV2')\n#plt.xlabel('epoch')\n#plt.savefig(\"validation.png\", bbox_inches='tight')\n#plt.show()","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"## Area Under the Receiver Operating Characteristic curve"},{"metadata":{"trusted":true},"cell_type":"code","source":"from sklearn.metrics import roc_curve, auc, roc_auc_score\nimport matplotlib.pyplot as plt\n\n# make a prediction resnet50\nresnet50_model_predictions = resnet50_model.predict_generator(resnet50_test_data_gen, steps=total_test, verbose=1)\nfpr_resnet50, tpr_resnet50, thresholds_resnet50 = roc_curve(resnet50_test_data_gen.classes, resnet50_model_predictions)\nresnet50_model_auc = roc_auc_score(resnet50_test_data_gen.classes, resnet50_model_predictions)\nprint(f'ResNet50 AUC = {resnet50_model_auc}')\n\n# make a prediction MobileNetV2\n#mobilenetv2_model_predictions = mobilenetv2_model.predict_generator(mobilenetv2_test_data_gen, steps=total_test, verbose=1)\n#fpr_mobilenetv2, tpr_mobilenetv2, thresholds_mobilenetv2 = roc_curve(mobilenetv2_test_data_gen.classes, mobilenetv2_model_predictions)\n#mobilenetv2_model_auc = roc_auc_score(mobilenetv2_test_data_gen.classes, mobilenetv2_model_predictions)\n#print(f'MobileNetV2 AUC = {mobilenetv2_model_auc}')","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"plt.figure(figsize=(20,5))\nplt.subplot(121)\nplt.plot([0, 1], [0, 1], 'k--')\nplt.plot(fpr_resnet50, tpr_resnet50, label='area = {:.4f}'.format(resnet50_model_auc))\nplt.xlabel('false positive rate')\nplt.ylabel('true positive rate')\nplt.title('ResNet50 ROC curve')\nplt.legend(loc='best')\nplt.show()\nplt.figure(figsize=(20,5))\nplt.subplot(121)\nplt.plot([0, 1], [0, 1], 'k--')\nplt.plot(fpr_mobilenetv2, tpr_mobilenetv2, label='area = {:.4f}'.format(mobilenetv2_model_auc))\nplt.xlabel('false positive rate')\nplt.ylabel('true positive rate')\nplt.title('MobileNetV2 ROC curve')\nplt.legend(loc='best')\nplt.show()","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"## "}],"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}