{"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":"# Metastatic tissue identifier with Convolutional Neural Networks:\n\nWelcome folks!, in the current project we will implement a CNN by scratch to classify images of tissues as cancerous or not, for this we have to make use of the **Histopathologic Cancer Detection** competition dataset which contains over 220 thousand images for training set and 57458 unseen images to classify and submit.\n\nHaving said that, let's get started!","metadata":{}},{"cell_type":"markdown","source":"Firstly, we have to import the main libraries to perform EDA as follows:","metadata":{}},{"cell_type":"code","source":"pip install visualkeras","metadata":{"execution":{"iopub.status.busy":"2022-03-07T18:38:19.616059Z","iopub.execute_input":"2022-03-07T18:38:19.616788Z","iopub.status.idle":"2022-03-07T18:38:29.859737Z","shell.execute_reply.started":"2022-03-07T18:38:19.616684Z","shell.execute_reply":"2022-03-07T18:38:29.858936Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"import os\nimport numpy as np\nimport pandas as pd\nimport seaborn as sns\nimport matplotlib.pyplot as plt\nimport cv2\nimport visualkeras\nimport tensorflow as tf","metadata":{"execution":{"iopub.status.busy":"2022-03-07T18:38:29.861717Z","iopub.execute_input":"2022-03-07T18:38:29.862194Z","iopub.status.idle":"2022-03-07T18:38:35.401412Z","shell.execute_reply.started":"2022-03-07T18:38:29.862152Z","shell.execute_reply":"2022-03-07T18:38:35.400610Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"## Exploratory Data Analysis:\n\nNow, we will print the files available in the main directory so as to know the distribution of images. ","metadata":{}},{"cell_type":"code","source":"os.listdir('../input/histopathologic-cancer-detection')","metadata":{"execution":{"iopub.status.busy":"2022-03-07T18:38:35.402800Z","iopub.execute_input":"2022-03-07T18:38:35.403050Z","iopub.status.idle":"2022-03-07T18:38:35.415504Z","shell.execute_reply.started":"2022-03-07T18:38:35.403016Z","shell.execute_reply":"2022-03-07T18:38:35.414574Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"Let's print the file name of the first five images in the training dataset:","metadata":{}},{"cell_type":"code","source":"os.listdir('../input/histopathologic-cancer-detection/train')[:5]","metadata":{"execution":{"iopub.status.busy":"2022-03-07T18:38:35.417613Z","iopub.execute_input":"2022-03-07T18:38:35.417885Z","iopub.status.idle":"2022-03-07T18:38:39.525003Z","shell.execute_reply.started":"2022-03-07T18:38:35.417851Z","shell.execute_reply":"2022-03-07T18:38:39.524277Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"In order to know the exact number of images in each folder we will print the length of the list containing the file names as can be seen below:","metadata":{}},{"cell_type":"code","source":"len(os.listdir('../input/histopathologic-cancer-detection/train'))","metadata":{"execution":{"iopub.status.busy":"2022-03-07T18:38:39.526107Z","iopub.execute_input":"2022-03-07T18:38:39.526377Z","iopub.status.idle":"2022-03-07T18:38:39.696436Z","shell.execute_reply.started":"2022-03-07T18:38:39.526321Z","shell.execute_reply":"2022-03-07T18:38:39.695595Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"len(os.listdir('../input/histopathologic-cancer-detection/test'))","metadata":{"execution":{"iopub.status.busy":"2022-03-07T18:38:39.697887Z","iopub.execute_input":"2022-03-07T18:38:39.698153Z","iopub.status.idle":"2022-03-07T18:38:40.238835Z","shell.execute_reply.started":"2022-03-07T18:38:39.698116Z","shell.execute_reply":"2022-03-07T18:38:40.238143Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"Perfect, the dataset author gives a csv file containing the images id's and their respective category in two columns, let's print it in the next line:","metadata":{}},{"cell_type":"code","source":"df=pd.read_csv('../input/histopathologic-cancer-detection/train_labels.csv')\ndf.head()","metadata":{"execution":{"iopub.status.busy":"2022-03-07T18:38:40.240226Z","iopub.execute_input":"2022-03-07T18:38:40.240730Z","iopub.status.idle":"2022-03-07T18:38:40.580964Z","shell.execute_reply.started":"2022-03-07T18:38:40.240692Z","shell.execute_reply":"2022-03-07T18:38:40.580224Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"The next step is to plot the distribution of categories as proportions just to know if the data is balanced or not.","metadata":{}},{"cell_type":"code","source":"df.label.value_counts()","metadata":{"execution":{"iopub.status.busy":"2022-03-07T18:38:46.173849Z","iopub.execute_input":"2022-03-07T18:38:46.174116Z","iopub.status.idle":"2022-03-07T18:38:46.188600Z","shell.execute_reply.started":"2022-03-07T18:38:46.174086Z","shell.execute_reply":"2022-03-07T18:38:46.187692Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"sns.set(style='whitegrid')\npie_chart=pd.DataFrame(df['label'].replace(0,'Non-cancerous tissue').replace(1,'Cancerous tissue').value_counts())\npie_chart.reset_index(inplace=True)\npie_chart.plot(kind='pie', title='Category Images',y = 'label', \n             autopct='%1.1f%%', shadow=False, labels=pie_chart['index'], legend = False, fontsize=14, figsize=(18,8))","metadata":{"execution":{"iopub.status.busy":"2022-03-07T18:39:19.027723Z","iopub.execute_input":"2022-03-07T18:39:19.028070Z","iopub.status.idle":"2022-03-07T18:39:19.200100Z","shell.execute_reply.started":"2022-03-07T18:39:19.028025Z","shell.execute_reply":"2022-03-07T18:39:19.199307Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"Evidently the dataset is unbalanced and for this task I prefer to undersample to the lowest number which corresponds to 89117 avoiding sidetracked predictions in our future model, as my main purpose is to make you understand better the process we will simplify the number to 89000 so as to not get confused in the splitting process later.\n\nIn the following lines I will print the first image contained in training set and its corresponding category by using its id in the csv file:","metadata":{}},{"cell_type":"code","source":"from PIL import Image","metadata":{"execution":{"iopub.status.busy":"2022-03-07T18:39:32.399290Z","iopub.execute_input":"2022-03-07T18:39:32.399767Z","iopub.status.idle":"2022-03-07T18:39:32.403073Z","shell.execute_reply.started":"2022-03-07T18:39:32.399729Z","shell.execute_reply":"2022-03-07T18:39:32.402430Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"im = Image.open('../input/histopathologic-cancer-detection/train/'+os.listdir('../input/histopathologic-cancer-detection/train')[0])\nplt.imshow(im)\nplt.axis('off')\nprint(df[df.id==os.listdir('../input/histopathologic-cancer-detection/train')[0].split('.')[0]].label)","metadata":{"execution":{"iopub.status.busy":"2022-03-07T18:39:32.975633Z","iopub.execute_input":"2022-03-07T18:39:32.976413Z","iopub.status.idle":"2022-03-07T18:39:33.591779Z","shell.execute_reply.started":"2022-03-07T18:39:32.976338Z","shell.execute_reply":"2022-03-07T18:39:33.591040Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"Above we see the the first training image has label:1 corresponding to metastatic tissue, let's see more examples about both categories by running the following lines. If you want to see more on the next functions to print images by categories I encourage you to take a look at my next notebook in which I explain it much detailed: \n\nhttps://www.kaggle.com/georgesaavedra/best-intel-image-classifiers","metadata":{}},{"cell_type":"code","source":"Labels = df.label.values\nLabels","metadata":{"execution":{"iopub.status.busy":"2022-03-07T18:39:40.873662Z","iopub.execute_input":"2022-03-07T18:39:40.874394Z","iopub.status.idle":"2022-03-07T18:39:40.880004Z","shell.execute_reply.started":"2022-03-07T18:39:40.874337Z","shell.execute_reply":"2022-03-07T18:39:40.879013Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"def get_indexes(label,list_n):\n  for x in range(len(Labels)):\n    if Labels[x]==label:\n      list_n.append(x)\n  return list_n","metadata":{"execution":{"iopub.status.busy":"2022-03-07T18:39:42.591916Z","iopub.execute_input":"2022-03-07T18:39:42.592164Z","iopub.status.idle":"2022-03-07T18:39:42.596276Z","shell.execute_reply.started":"2022-03-07T18:39:42.592137Z","shell.execute_reply":"2022-03-07T18:39:42.595602Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"no_cancer=[]\nno_cancer=get_indexes(0,no_cancer)\ncancer=[]\ncancer=get_indexes(1,cancer)","metadata":{"execution":{"iopub.status.busy":"2022-03-07T18:39:43.528232Z","iopub.execute_input":"2022-03-07T18:39:43.528893Z","iopub.status.idle":"2022-03-07T18:39:43.745805Z","shell.execute_reply.started":"2022-03-07T18:39:43.528854Z","shell.execute_reply":"2022-03-07T18:39:43.745087Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"def get_classlabel(class_code):\n    labels = {0:'Non-cancerous', 1:'Cancerous'}\n    \n    return labels[class_code]","metadata":{"execution":{"iopub.status.busy":"2022-03-07T18:40:05.011719Z","iopub.execute_input":"2022-03-07T18:40:05.011974Z","iopub.status.idle":"2022-03-07T18:40:05.019089Z","shell.execute_reply.started":"2022-03-07T18:40:05.011946Z","shell.execute_reply":"2022-03-07T18:40:05.018226Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"import random\nfrom random import randint\n\nf,ax = plt.subplots(2,4, figsize=(12,12)) \ntypes_img=[no_cancer, cancer]\n\nfor z in range(0,2,1):\n    for j in range(0,4,1):\n        rnd_number=random.choice(types_img[z])\n        ax[z,j].imshow(Image.open('../input/histopathologic-cancer-detection/train/'+df.iloc[rnd_number,0]+'.tif'))\n        ax[z,j].set_title(get_classlabel(z))\n        ax[z,j].axis('off')\n        plt.tight_layout()","metadata":{"execution":{"iopub.status.busy":"2022-03-07T18:40:06.054974Z","iopub.execute_input":"2022-03-07T18:40:06.055511Z","iopub.status.idle":"2022-03-07T18:40:08.114586Z","shell.execute_reply.started":"2022-03-07T18:40:06.055479Z","shell.execute_reply":"2022-03-07T18:40:08.113976Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"## Data Preparation:\n\nWe will get rid of the next images as they either create errors during training or doesn't represent its category:","metadata":{}},{"cell_type":"code","source":"f, (ax1, ax2) = plt.subplots(1,2,figsize=(17,17))\n\nax1.imshow(Image.open('../input/histopathologic-cancer-detection/train/'+'dd6dfed324f9fcb6f93f46f32fc800f2ec196be2.tif'))\nax1.axis('off')\nax1.set_title('Error Image')\n\nax2.imshow(Image.open('../input/histopathologic-cancer-detection/train/'+'9369c7278ec8bcc6c880d99194de09fc2bd4efbe.tif'))\nax2.axis('off')\nax2.set_title('Black Image')","metadata":{"execution":{"iopub.status.busy":"2022-03-07T18:40:25.248609Z","iopub.execute_input":"2022-03-07T18:40:25.249146Z","iopub.status.idle":"2022-03-07T18:40:25.542548Z","shell.execute_reply.started":"2022-03-07T18:40:25.249107Z","shell.execute_reply":"2022-03-07T18:40:25.541855Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"df.shape","metadata":{"execution":{"iopub.status.busy":"2022-03-07T18:40:29.722770Z","iopub.execute_input":"2022-03-07T18:40:29.723040Z","iopub.status.idle":"2022-03-07T18:40:29.728106Z","shell.execute_reply.started":"2022-03-07T18:40:29.723011Z","shell.execute_reply":"2022-03-07T18:40:29.727424Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# removing this image because it caused a training error previously\ndf = df[df['id'] != 'dd6dfed324f9fcb6f93f46f32fc800f2ec196be2']\n\n# removing this image because it's black\ndf = df[df['id'] != '9369c7278ec8bcc6c880d99194de09fc2bd4efbe']\n\nprint(df.shape)","metadata":{"execution":{"iopub.status.busy":"2022-03-07T18:40:33.140092Z","iopub.execute_input":"2022-03-07T18:40:33.140646Z","iopub.status.idle":"2022-03-07T18:40:33.226433Z","shell.execute_reply.started":"2022-03-07T18:40:33.140606Z","shell.execute_reply":"2022-03-07T18:40:33.225601Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"Once we got rid of both images we have to create dataframes containing the id's of each category and gather 89000 images as we said earlier randomly:","metadata":{}},{"cell_type":"code","source":"SAMPLE_SIZE=89000\n\n# take a random sample of class 0 with size equal to num samples in class 1\ndf_0 = df[df['label'] == 0].sample(SAMPLE_SIZE, random_state = 42)\n# filter out class 1\ndf_1 = df[df['label'] == 1].sample(SAMPLE_SIZE, random_state = 42)","metadata":{"execution":{"iopub.status.busy":"2022-03-07T18:45:24.230695Z","iopub.execute_input":"2022-03-07T18:45:24.231418Z","iopub.status.idle":"2022-03-07T18:45:24.268157Z","shell.execute_reply.started":"2022-03-07T18:45:24.231373Z","shell.execute_reply":"2022-03-07T18:45:24.267408Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"Once we created both dataframes we will concatenate them so as to have one file containing 178000 images, finally we will shuffle it because it was sorted:","metadata":{}},{"cell_type":"code","source":"from sklearn.utils import shuffle\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()","metadata":{"execution":{"iopub.status.busy":"2022-03-07T18:45:28.798910Z","iopub.execute_input":"2022-03-07T18:45:28.799516Z","iopub.status.idle":"2022-03-07T18:45:28.934306Z","shell.execute_reply.started":"2022-03-07T18:45:28.799474Z","shell.execute_reply":"2022-03-07T18:45:28.933602Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"df_data.head(10)","metadata":{"execution":{"iopub.status.busy":"2022-03-07T18:45:30.217304Z","iopub.execute_input":"2022-03-07T18:45:30.218034Z","iopub.status.idle":"2022-03-07T18:45:30.226561Z","shell.execute_reply.started":"2022-03-07T18:45:30.217996Z","shell.execute_reply":"2022-03-07T18:45:30.225865Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"Now that we have a balanced dataset we can split into training and validation sets at 10% as a typical ML workflow.","metadata":{}},{"cell_type":"code","source":"# train_test_split\nfrom sklearn.model_selection import 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.10, random_state=42, stratify=y)\n\nprint(df_train.shape)\nprint(df_val.shape)","metadata":{"execution":{"iopub.status.busy":"2022-03-07T18:46:26.557410Z","iopub.execute_input":"2022-03-07T18:46:26.557861Z","iopub.status.idle":"2022-03-07T18:46:26.643771Z","shell.execute_reply.started":"2022-03-07T18:46:26.557823Z","shell.execute_reply":"2022-03-07T18:46:26.642946Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"We can see the number of images in both sets make sense and kept the balance.","metadata":{}},{"cell_type":"code","source":"df_train['label'].value_counts()","metadata":{"execution":{"iopub.status.busy":"2022-03-07T18:46:28.390552Z","iopub.execute_input":"2022-03-07T18:46:28.391198Z","iopub.status.idle":"2022-03-07T18:46:28.399810Z","shell.execute_reply.started":"2022-03-07T18:46:28.391160Z","shell.execute_reply":"2022-03-07T18:46:28.399027Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"df_val['label'].value_counts()","metadata":{"execution":{"iopub.status.busy":"2022-03-07T18:46:29.476593Z","iopub.execute_input":"2022-03-07T18:46:29.477670Z","iopub.status.idle":"2022-03-07T18:46:29.491168Z","shell.execute_reply.started":"2022-03-07T18:46:29.477591Z","shell.execute_reply":"2022-03-07T18:46:29.490310Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"At this moment we could create the model and the objects containing the training and validation images according to the id's in both sets, however this process will crash our machine RAM forcing us to restart it, this is why we have to create directories and sub-directories and save the images in their respective folder, this process will consume a significative lower RAM allowing us to succesfully train our model for various epochs.\n\nAs I said we will create a base directory containing training and testing sub-directories and these will contain folders for categories 'Cancerous' and 'Non-Cancerous', we will perform this step-by-step as follows:","metadata":{}},{"cell_type":"code","source":"# Create a new directory\nbase_dir = 'base_dir'\nos.mkdir(base_dir)\n\n#[CREATE FOLDERS INSIDE THE BASE DIRECTORY]\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# [CREATE FOLDERS INSIDE THE TRAIN AND VALIDATION FOLDERS]\n# Inside each folder we create separate folders for each class\n\n# create new folders inside train_dir\nnon_cancerous_tissue = os.path.join(train_dir, 'non_cancerous_tissue')\nos.mkdir(non_cancerous_tissue)\ncancerous_tissue = os.path.join(train_dir, 'cancerous_tissue')\nos.mkdir(cancerous_tissue)\n\n# create new folders inside val_dir\nnon_cancerous_tissue = os.path.join(val_dir, 'non_cancerous_tissue')\nos.mkdir(non_cancerous_tissue)\ncancerous_tissue = os.path.join(val_dir, 'cancerous_tissue')\nos.mkdir(cancerous_tissue)","metadata":{"execution":{"iopub.status.busy":"2022-03-07T18:47:16.314289Z","iopub.execute_input":"2022-03-07T18:47:16.314999Z","iopub.status.idle":"2022-03-07T18:47:16.323199Z","shell.execute_reply.started":"2022-03-07T18:47:16.314963Z","shell.execute_reply":"2022-03-07T18:47:16.322473Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"We have to set the 'id' column as index in order to gather the image labels more easily, this will help us when copying the images to our just created directories:","metadata":{}},{"cell_type":"code","source":"# Set the id as the index in df_data\ndf_data.set_index('id', inplace=True)","metadata":{"execution":{"iopub.status.busy":"2022-03-07T18:47:16.789240Z","iopub.execute_input":"2022-03-07T18:47:16.789950Z","iopub.status.idle":"2022-03-07T18:47:16.794181Z","shell.execute_reply.started":"2022-03-07T18:47:16.789909Z","shell.execute_reply":"2022-03-07T18:47:16.793424Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"df_data.head()","metadata":{"execution":{"iopub.status.busy":"2022-03-07T18:47:19.682797Z","iopub.execute_input":"2022-03-07T18:47:19.683060Z","iopub.status.idle":"2022-03-07T18:47:19.690780Z","shell.execute_reply.started":"2022-03-07T18:47:19.683031Z","shell.execute_reply":"2022-03-07T18:47:19.690047Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"Time to copy the images to their respective directories:","metadata":{}},{"cell_type":"code","source":"import shutil\n\n# Get a list of train and val images\ntrain_list = list(df_train['id'])\nval_list = list(df_val['id'])\n\n# Transfer the train images\nfor image in train_list:\n    # the id in the csv file does not have the .tif extension therefore we add it here\n    fname = 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 = 'non_cancerous_tissue'\n    if target == 1:\n        label = 'cancerous_tissue'\n    \n    # source path to image\n    src = os.path.join('../input/histopathologic-cancer-detection/train', fname)\n    # destination path to image\n    dst = os.path.join(train_dir, label, fname)\n    # copy the image from the source to the destination\n    shutil.copyfile(src, dst)\n\n\n# Transfer the val images\nfor image in val_list:\n    # the id in the csv file does not have the .tif extension therefore we add it here\n    fname = 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 = 'non_cancerous_tissue'\n    if target == 1:\n        label = 'cancerous_tissue'\n    \n    # source path to image\n    src = os.path.join('../input/histopathologic-cancer-detection/train', fname)\n    # destination path to image\n    dst = os.path.join(val_dir, label, fname)\n    # copy the image from the source to the destination\n    shutil.copyfile(src, dst)","metadata":{"execution":{"iopub.status.busy":"2022-03-07T18:48:29.367064Z","iopub.execute_input":"2022-03-07T18:48:29.367320Z","iopub.status.idle":"2022-03-07T19:11:51.898943Z","shell.execute_reply.started":"2022-03-07T18:48:29.367291Z","shell.execute_reply":"2022-03-07T19:11:51.898197Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"To confirm that the images were succefully copied we will print the amount of images in each folder of the directories, the numbers should correspond to the same we got when the dataset was splitted:","metadata":{}},{"cell_type":"code","source":"# check how many training images we have in each folder\nprint(len(os.listdir('base_dir/train_dir/non_cancerous_tissue')))\nprint(len(os.listdir('base_dir/train_dir/cancerous_tissue')))","metadata":{"execution":{"iopub.status.busy":"2022-03-07T19:11:51.900501Z","iopub.execute_input":"2022-03-07T19:11:51.900735Z","iopub.status.idle":"2022-03-07T19:11:52.009517Z","shell.execute_reply.started":"2022-03-07T19:11:51.900701Z","shell.execute_reply":"2022-03-07T19:11:52.008648Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# check how many validation images we have in each folder\nprint(len(os.listdir('base_dir/val_dir/non_cancerous_tissue')))\nprint(len(os.listdir('base_dir/val_dir/cancerous_tissue')))","metadata":{"execution":{"iopub.status.busy":"2022-03-07T19:11:52.011033Z","iopub.execute_input":"2022-03-07T19:11:52.011289Z","iopub.status.idle":"2022-03-07T19:11:52.031796Z","shell.execute_reply.started":"2022-03-07T19:11:52.011254Z","shell.execute_reply":"2022-03-07T19:11:52.031057Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"Perfect, now our images are available in in the 'Output Data' using such memory. We could start creating our model and training it with flow_from_directory, however in order to increase the accuracy we will perform Data Augmentation by creating flipped, shifted and rotated images based on the existing ones and obviously scale them, as we are working with images the proper process is min-max scaling and this can be done in the augmentation process.","metadata":{}},{"cell_type":"code","source":"train_path = 'base_dir/train_dir'\nvalid_path = 'base_dir/val_dir'\ntest_path = '../input/test'\n\nnum_train_samples = len(df_train)\nnum_val_samples = len(df_val)\ntrain_batch_size = 32\nval_batch_size = 32\n\ntrain_steps = np.ceil(num_train_samples / train_batch_size)\nval_steps = np.ceil(num_val_samples / val_batch_size)","metadata":{"execution":{"iopub.status.busy":"2022-03-07T19:11:52.033801Z","iopub.execute_input":"2022-03-07T19:11:52.034079Z","iopub.status.idle":"2022-03-07T19:11:52.041578Z","shell.execute_reply.started":"2022-03-07T19:11:52.034043Z","shell.execute_reply":"2022-03-07T19:11:52.040860Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"ImageDataGenerator allows us to augment our data and this function will be applied to our training and validation by gathering them with the flow_from_directory function, notice that we have to shuffle both as this is a new function and we have to create a another validation set unshuffled in which we will perform a new prediction to compute the error metrics: ","metadata":{}},{"cell_type":"code","source":"from tensorflow.keras.preprocessing.image import ImageDataGenerator\n\nIMAGE_SIZE=96\ndatagen = ImageDataGenerator(rescale=1.0/255,\n                             featurewise_center=False,\n                             samplewise_center=False,\n                             featurewise_std_normalization=False,\n                             samplewise_std_normalization=False,\n                             zca_whitening=False,\n                             rotation_range=10,\n                             zoom_range = 0.1,\n                             width_shift_range=0.1,\n                             height_shift_range=0.1,\n                             horizontal_flip=True,\n                             vertical_flip=True)\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='binary',\n                                        shuffle=True)\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='binary',\n                                      shuffle=True)\n\n# Note: shuffle=False causes the test dataset to not be shuffled\nval2_gen = datagen.flow_from_directory(valid_path,\n                                       target_size=(IMAGE_SIZE,IMAGE_SIZE),\n                                       batch_size=1,\n                                       class_mode='binary',\n                                       shuffle=False)","metadata":{"execution":{"iopub.status.busy":"2022-03-07T19:11:52.043682Z","iopub.execute_input":"2022-03-07T19:11:52.043865Z","iopub.status.idle":"2022-03-07T19:12:02.201847Z","shell.execute_reply.started":"2022-03-07T19:11:52.043843Z","shell.execute_reply":"2022-03-07T19:12:02.200274Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"Nice!, the function found all images distributed into two classes, these objects will be used as arguments when training the model.","metadata":{}},{"cell_type":"markdown","source":"## Modeling:\n\nWe will start by importing all libraries and functions needed to create the model as follows:","metadata":{}},{"cell_type":"code","source":"from sklearn.metrics import confusion_matrix\nimport itertools\n\nfrom tensorflow.keras.models import Sequential\nfrom tensorflow.keras.layers import Dense, Dropout, Flatten, Conv2D, MaxPool2D\nfrom tensorflow.keras.layers import BatchNormalization\nfrom tensorflow.keras.optimizers import RMSprop,Adam,SGD,Adadelta","metadata":{"execution":{"iopub.status.busy":"2022-03-07T19:12:02.203042Z","iopub.execute_input":"2022-03-07T19:12:02.203378Z","iopub.status.idle":"2022-03-07T19:12:02.211593Z","shell.execute_reply.started":"2022-03-07T19:12:02.203328Z","shell.execute_reply":"2022-03-07T19:12:02.210748Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"Before we start creating our model we will define three callbacks that will help us to improve the training, stop it once it reaches a threshold and save the best model according to its accuracy:","metadata":{}},{"cell_type":"code","source":"#Will stop the training once it reaches 99% validation accuracy:\nclass myCallback(tf.keras.callbacks.Callback):\n  def on_epoch_end(self, epoch, logs={}):\n    if(logs.get('val_accuracy')>0.99):\n      print(\"\\nReached 99% accuracy so cancelling training!\")\n      self.model.stop_training = True\n        \ncallbacks = myCallback()\n\n#Will reduce the learning rate is validation accuracy didn't improve in one epoch:\nfrom tensorflow.keras.callbacks import ReduceLROnPlateau\nlr_reduction = ReduceLROnPlateau(monitor='val_accuracy',\n                                 patience=1, \n                                 verbose=1, \n                                 factor=0.5, \n                                 min_lr=0.000001)\n\n#Will save the very best model according to validation accuracy:\nfrom tensorflow.keras.callbacks import ModelCheckpoint\nmodel_dir = 'CNN_model_histo.h5'\ncheckpoint = ModelCheckpoint(model_dir, monitor='val_accuracy', verbose=1,\n                             save_best_only=True, mode='max')","metadata":{"execution":{"iopub.status.busy":"2022-03-07T19:12:02.212919Z","iopub.execute_input":"2022-03-07T19:12:02.213339Z","iopub.status.idle":"2022-03-07T19:12:02.227407Z","shell.execute_reply.started":"2022-03-07T19:12:02.213297Z","shell.execute_reply":"2022-03-07T19:12:02.226742Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"The architecture I decided to use was made in one of my previous projects in which the performance was considerably high, it considers 4 sets of layers including 2D-Convolutional, 2D-Max Pooling and Batch Normalization, at the end we add a couple of Dropout and Dense layers.\n\nI kindly encourage you to take a look at the following notebook in which I explain such architecture much better and aims a similar task: \n\nhttps://www.kaggle.com/georgesaavedra/tumor-classification-cnn","metadata":{}},{"cell_type":"code","source":"optimizer = Adam(learning_rate=0.001,beta_1=0.9,beta_2=0.999)\n\nmodel=Sequential()\nmodel.add(Conv2D(32,(3,3),strides=1,padding='Same',activation='relu',input_shape=(IMAGE_SIZE, IMAGE_SIZE, 3)))\nmodel.add(MaxPool2D(2,2))\nmodel.add(BatchNormalization())\nmodel.add(Conv2D(64,(3,3), strides=1,padding= 'Same', activation='relu'))\nmodel.add(MaxPool2D(2,2))\nmodel.add(BatchNormalization())\nmodel.add(Conv2D(128,(3,3), strides=1,padding= 'Same', activation='relu'))\nmodel.add(MaxPool2D(2,2))\nmodel.add(BatchNormalization())\nmodel.add(Conv2D(256,(3,3), strides=1,padding= 'Same', activation='relu'))\nmodel.add(MaxPool2D(2,2))\nmodel.add(BatchNormalization())\nmodel.add(Flatten())\nmodel.add(Dropout(0.2))\nmodel.add(Dense(512, activation = \"relu\"))\nmodel.add(Dropout(0.2))\nmodel.add(Dense(1, activation = \"sigmoid\"))\n\nmodel.compile(optimizer = optimizer , loss = \"binary_crossentropy\", metrics=[\"accuracy\"])","metadata":{"execution":{"iopub.status.busy":"2022-03-07T19:12:02.228518Z","iopub.execute_input":"2022-03-07T19:12:02.228941Z","iopub.status.idle":"2022-03-07T19:12:04.901253Z","shell.execute_reply.started":"2022-03-07T19:12:02.228904Z","shell.execute_reply":"2022-03-07T19:12:04.900483Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"model.summary()","metadata":{"execution":{"iopub.status.busy":"2022-03-07T19:12:04.902513Z","iopub.execute_input":"2022-03-07T19:12:04.902756Z","iopub.status.idle":"2022-03-07T19:12:04.916114Z","shell.execute_reply.started":"2022-03-07T19:12:04.902722Z","shell.execute_reply":"2022-03-07T19:12:04.915269Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"The following function displays our model architecture by layers, not showing the layers detail though, however we can follow and associate each color to a type of layer, such as: Yelow: Conv2D, Red: MaxPooling, Green: BatchNormalization, Blue:Flatten, Black: Dropout, Yelow: Dense.","metadata":{}},{"cell_type":"code","source":"visualkeras.layered_view(model)","metadata":{"execution":{"iopub.status.busy":"2022-03-07T19:12:04.918783Z","iopub.execute_input":"2022-03-07T19:12:04.919024Z","iopub.status.idle":"2022-03-07T19:12:04.983703Z","shell.execute_reply.started":"2022-03-07T19:12:04.918990Z","shell.execute_reply":"2022-03-07T19:12:04.983010Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"Time now to train our model using the objects pointing to our created directories, we will train for 20 epochs so as to find the best possible model. \n\n*Important: Notice that for the deep of our network it will take a considerably long time to train, where each epoch took me around 8 minutes and 20 seconds, so be patient if you want to train it again.*","metadata":{}},{"cell_type":"code","source":"history = model.fit_generator(train_gen, validation_data=val_gen,\n                              epochs=20, verbose=1,\n                              callbacks=[callbacks, lr_reduction, checkpoint])","metadata":{"execution":{"iopub.status.busy":"2022-03-07T19:12:04.984757Z","iopub.execute_input":"2022-03-07T19:12:04.985447Z","iopub.status.idle":"2022-03-07T21:59:22.823075Z","shell.execute_reply.started":"2022-03-07T19:12:04.985411Z","shell.execute_reply":"2022-03-07T21:59:22.822412Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"The best model reached 95.37% validation accuracy and was saved in the CNN_model_histo.h5 file that we will load, but before we have to plot the performance curves in relation to the epochs:","metadata":{}},{"cell_type":"code","source":"pd.DataFrame(history.history)","metadata":{"execution":{"iopub.status.busy":"2022-03-07T21:59:22.824303Z","iopub.execute_input":"2022-03-07T21:59:22.824583Z","iopub.status.idle":"2022-03-07T21:59:22.847434Z","shell.execute_reply.started":"2022-03-07T21:59:22.824547Z","shell.execute_reply":"2022-03-07T21:59:22.846595Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"def metrics_plot(history):\n    acc = history.history['accuracy']\n    val_acc = history.history['val_accuracy']\n    loss = history.history['loss']\n    val_loss = history.history['val_loss']\n\n    epochs = range(1,len(acc)+1,1)\n\n    plt.plot(epochs, acc, 'r', label='Training accuracy')\n    plt.plot(epochs, val_acc, 'b', label='Validation accuracy')\n    plt.title('Training and validation accuracy')\n    plt.legend()\n    plt.figure()\n\n    plt.plot(epochs, loss, 'r', label='Training Loss')\n    plt.plot(epochs, val_loss, 'b', label='Validation Loss')\n    plt.title('Training and validation loss')\n    plt.legend()\n\n    plt.show()","metadata":{"execution":{"iopub.status.busy":"2022-03-07T21:59:22.848797Z","iopub.execute_input":"2022-03-07T21:59:22.849222Z","iopub.status.idle":"2022-03-07T21:59:22.857893Z","shell.execute_reply.started":"2022-03-07T21:59:22.849174Z","shell.execute_reply":"2022-03-07T21:59:22.857122Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"metrics_plot(history)","metadata":{"execution":{"iopub.status.busy":"2022-03-07T21:59:22.859316Z","iopub.execute_input":"2022-03-07T21:59:22.859726Z","iopub.status.idle":"2022-03-07T21:59:23.385959Z","shell.execute_reply.started":"2022-03-07T21:59:22.859691Z","shell.execute_reply":"2022-03-07T21:59:23.385199Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"We can see the validation set had a performance which was underdamped and the settling time was equivalent to around 15 epochs, this is the main why we trained for 20 epochs and used ModelCheckpoint.\n\nIn the next line we will load the model saved in the h5 file and confirm it's working properly if we want to use it in other moment avoiding training the model again.","metadata":{}},{"cell_type":"code","source":"from keras.models import load_model\n\nmodel_saved = load_model('./CNN_model_histo.h5')","metadata":{"execution":{"iopub.status.busy":"2022-03-07T22:00:15.406024Z","iopub.execute_input":"2022-03-07T22:00:15.406746Z","iopub.status.idle":"2022-03-07T22:00:15.734143Z","shell.execute_reply.started":"2022-03-07T22:00:15.406708Z","shell.execute_reply":"2022-03-07T22:00:15.733287Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"Here is where we have to use the copy of the validation set we created earlier which was unshuffled, we will evaluate the performance of this loaded model and predict the label for such images as follows:","metadata":{}},{"cell_type":"code","source":"model_saved.evaluate_generator(val2_gen, steps=len(df_val), verbose=1)","metadata":{"execution":{"iopub.status.busy":"2022-03-07T22:00:20.096621Z","iopub.execute_input":"2022-03-07T22:00:20.097235Z","iopub.status.idle":"2022-03-07T22:02:42.192875Z","shell.execute_reply.started":"2022-03-07T22:00:20.097197Z","shell.execute_reply":"2022-03-07T22:02:42.192144Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"predicted_val_prob = model_saved.predict_generator(val2_gen, steps=len(df_val), verbose=1)","metadata":{"execution":{"iopub.status.busy":"2022-03-07T22:02:42.194412Z","iopub.execute_input":"2022-03-07T22:02:42.194824Z","iopub.status.idle":"2022-03-07T22:03:59.121426Z","shell.execute_reply.started":"2022-03-07T22:02:42.194784Z","shell.execute_reply":"2022-03-07T22:03:59.120648Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"Y_val_pred= np.round(predicted_val_prob)\nY_val_pred","metadata":{"execution":{"iopub.status.busy":"2022-03-07T22:03:59.122749Z","iopub.execute_input":"2022-03-07T22:03:59.123025Z","iopub.status.idle":"2022-03-07T22:03:59.130209Z","shell.execute_reply.started":"2022-03-07T22:03:59.122988Z","shell.execute_reply":"2022-03-07T22:03:59.129512Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"The next lines will compute error metrics such as accuracy, recall, precision, f1-score and area under the curve, shown as classification report and confusion matrix:","metadata":{}},{"cell_type":"code","source":"from sklearn.metrics import classification_report\n\ny_true = val2_gen.classes\nreport = classification_report(y_true, Y_val_pred)\n\nprint(report)","metadata":{"execution":{"iopub.status.busy":"2022-03-07T22:03:59.132402Z","iopub.execute_input":"2022-03-07T22:03:59.132840Z","iopub.status.idle":"2022-03-07T22:03:59.169436Z","shell.execute_reply.started":"2022-03-07T22:03:59.132792Z","shell.execute_reply":"2022-03-07T22:03:59.168674Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"from sklearn.metrics import confusion_matrix\n\nf,ax = plt.subplots(figsize=(15, 15))\nconfusion_mtx = confusion_matrix(y_true, Y_val_pred)\nsns.set(font_scale=1.4)\nsns.heatmap(confusion_mtx, annot=True, linewidths=0.01,cmap=\"Greens\",linecolor=\"gray\",ax=ax)\nplt.xlabel(\"Predicted Label\")\nplt.ylabel(\"True Label\")\nplt.title(\"Confusion Matrix Validation set\")\nplt.show()","metadata":{"execution":{"iopub.status.busy":"2022-03-07T22:03:59.170470Z","iopub.execute_input":"2022-03-07T22:03:59.171152Z","iopub.status.idle":"2022-03-07T22:03:59.446009Z","shell.execute_reply.started":"2022-03-07T22:03:59.171116Z","shell.execute_reply":"2022-03-07T22:03:59.445237Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"from sklearn.metrics import classification_report\nfrom sklearn.metrics import precision_recall_fscore_support as score\nfrom sklearn.metrics import roc_auc_score\nfrom sklearn.metrics import accuracy_score\nfrom sklearn.preprocessing import label_binarize","metadata":{"execution":{"iopub.status.busy":"2022-03-07T22:03:59.447330Z","iopub.execute_input":"2022-03-07T22:03:59.447747Z","iopub.status.idle":"2022-03-07T22:03:59.452891Z","shell.execute_reply.started":"2022-03-07T22:03:59.447708Z","shell.execute_reply":"2022-03-07T22:03:59.452218Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"metrics = []\n\nprecision, recall, fscore, _ = score(y_true, Y_val_pred, average='weighted')\naccuracy = accuracy_score(y_true, Y_val_pred)\nauc = roc_auc_score(y_true, Y_val_pred)\nmetrics.append(pd.Series({'precision':precision, 'recall':recall,\n                          'fscore':fscore, 'accuracy':accuracy,\n                          'auc':auc}, name='CNN model'))\n    \nmetrics = pd.concat(metrics, axis=1)","metadata":{"execution":{"iopub.status.busy":"2022-03-07T22:03:59.454389Z","iopub.execute_input":"2022-03-07T22:03:59.454639Z","iopub.status.idle":"2022-03-07T22:03:59.477926Z","shell.execute_reply.started":"2022-03-07T22:03:59.454606Z","shell.execute_reply":"2022-03-07T22:03:59.477298Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"metrics","metadata":{"execution":{"iopub.status.busy":"2022-03-07T22:03:59.480335Z","iopub.execute_input":"2022-03-07T22:03:59.480548Z","iopub.status.idle":"2022-03-07T22:03:59.489384Z","shell.execute_reply.started":"2022-03-07T22:03:59.480524Z","shell.execute_reply":"2022-03-07T22:03:59.488506Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"## Inference:\n\nWe will do almost the same process as before, we have to understand the unseen images and copy all of them in a new directory:","metadata":{}},{"cell_type":"code","source":"os.listdir('../input/histopathologic-cancer-detection/test')[:5]","metadata":{"execution":{"iopub.status.busy":"2022-03-07T22:05:00.350279Z","iopub.execute_input":"2022-03-07T22:05:00.351019Z","iopub.status.idle":"2022-03-07T22:05:00.951398Z","shell.execute_reply.started":"2022-03-07T22:05:00.350982Z","shell.execute_reply":"2022-03-07T22:05:00.950721Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"print('\\n Amount of images in test dataset: ', len(os.listdir('../input/histopathologic-cancer-detection/test')))","metadata":{"execution":{"iopub.status.busy":"2022-03-07T22:05:05.182652Z","iopub.execute_input":"2022-03-07T22:05:05.182900Z","iopub.status.idle":"2022-03-07T22:05:05.217995Z","shell.execute_reply.started":"2022-03-07T22:05:05.182873Z","shell.execute_reply":"2022-03-07T22:05:05.217184Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# create test_dir\ntest_dir = 'test_set_dir'\nos.mkdir(test_dir)\n    \n# create test_images inside test_dir\ntest_images = os.path.join(test_dir, 'test_images')\nos.mkdir(test_images)","metadata":{"execution":{"iopub.status.busy":"2022-03-07T22:05:08.679343Z","iopub.execute_input":"2022-03-07T22:05:08.679940Z","iopub.status.idle":"2022-03-07T22:05:08.684687Z","shell.execute_reply.started":"2022-03-07T22:05:08.679903Z","shell.execute_reply":"2022-03-07T22:05:08.683880Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# Transfer the test images into image_dir\n\ntest_list = os.listdir('../input/histopathologic-cancer-detection/test')\n\nfor image in test_list:\n    fname = image\n    # source path to image\n    src = os.path.join('../input/histopathologic-cancer-detection/test', fname)\n    # destination path to image\n    dst = os.path.join(test_images, fname)\n    # copy the image from the source to the destination\n    shutil.copyfile(src, dst)","metadata":{"execution":{"iopub.status.busy":"2022-03-07T22:05:13.297413Z","iopub.execute_input":"2022-03-07T22:05:13.297729Z","iopub.status.idle":"2022-03-07T22:14:12.113007Z","shell.execute_reply.started":"2022-03-07T22:05:13.297695Z","shell.execute_reply":"2022-03-07T22:14:12.112150Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"len(os.listdir('test_set_dir/test_images'))","metadata":{"execution":{"iopub.status.busy":"2022-03-07T22:14:12.114794Z","iopub.execute_input":"2022-03-07T22:14:12.115268Z","iopub.status.idle":"2022-03-07T22:14:12.187173Z","shell.execute_reply.started":"2022-03-07T22:14:12.115232Z","shell.execute_reply":"2022-03-07T22:14:12.186447Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"Once we copied all images to our 'test_set_dir' directory we have to gather them using the flow_from_directory function as before and use it as argument of the prediction function:","metadata":{}},{"cell_type":"code","source":"test_path = 'test_set_dir'\ntest_gen = datagen.flow_from_directory(test_path,\n                                       target_size=(IMAGE_SIZE,IMAGE_SIZE),\n                                       batch_size=1,\n                                       class_mode='categorical',\n                                       shuffle=False)","metadata":{"execution":{"iopub.status.busy":"2022-03-07T22:14:12.188753Z","iopub.execute_input":"2022-03-07T22:14:12.189244Z","iopub.status.idle":"2022-03-07T22:14:14.127811Z","shell.execute_reply.started":"2022-03-07T22:14:12.189206Z","shell.execute_reply":"2022-03-07T22:14:14.126913Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"test_predictions = model_saved.predict_generator(test_gen, steps=len(os.listdir('test_set_dir/test_images')), verbose=1)","metadata":{"execution":{"iopub.status.busy":"2022-03-07T22:14:14.129950Z","iopub.execute_input":"2022-03-07T22:14:14.130586Z","iopub.status.idle":"2022-03-07T22:18:48.463526Z","shell.execute_reply.started":"2022-03-07T22:14:14.130529Z","shell.execute_reply":"2022-03-07T22:18:48.462666Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"test_predictions","metadata":{"execution":{"iopub.status.busy":"2022-03-07T22:18:48.466266Z","iopub.execute_input":"2022-03-07T22:18:48.466554Z","iopub.status.idle":"2022-03-07T22:18:48.472118Z","shell.execute_reply.started":"2022-03-07T22:18:48.466518Z","shell.execute_reply":"2022-03-07T22:18:48.471414Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"non_cancerous=1-test_predictions","metadata":{"execution":{"iopub.status.busy":"2022-03-07T22:19:10.398912Z","iopub.execute_input":"2022-03-07T22:19:10.399171Z","iopub.status.idle":"2022-03-07T22:19:10.403550Z","shell.execute_reply.started":"2022-03-07T22:19:10.399143Z","shell.execute_reply":"2022-03-07T22:19:10.402129Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"The following line creates the csv file that we will submit:","metadata":{}},{"cell_type":"code","source":"submission=pd.DataFrame(non_cancerous, columns=['label'])\nsubmission['id']=test_gen.filenames\nsubmission['id']=submission['id'].str.split('/', n=1, expand=True)[1].str.split('.', n=1, expand=True)[0] \nsubmission.set_index('id', inplace=True)\nsubmission.head()","metadata":{"execution":{"iopub.status.busy":"2022-03-07T22:19:11.578279Z","iopub.execute_input":"2022-03-07T22:19:11.578549Z","iopub.status.idle":"2022-03-07T22:19:11.779912Z","shell.execute_reply.started":"2022-03-07T22:19:11.578521Z","shell.execute_reply":"2022-03-07T22:19:11.779217Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"submission.to_csv('submission.csv')","metadata":{"execution":{"iopub.status.busy":"2022-03-07T22:19:18.358846Z","iopub.execute_input":"2022-03-07T22:19:18.359121Z","iopub.status.idle":"2022-03-07T22:19:18.531400Z","shell.execute_reply.started":"2022-03-07T22:19:18.359090Z","shell.execute_reply":"2022-03-07T22:19:18.530627Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"I would like to know any feedback in order to increase the performance of the models or tell me if you found a different one even better!\n\nIf you liked this notebook I would appreciate so much your upvote if you want to see more projects/tutorials like this one. I encourage you to see my projects portfolio, am sure you will love it.\n\nThank you!","metadata":{}},{"cell_type":"code","source":"","metadata":{},"execution_count":null,"outputs":[]}]}