{"cells":[{"metadata":{},"cell_type":"markdown","source":"Readme:\n- Click copy and edit\n- Click run all"},{"metadata":{"_uuid":"8f2839f25d086af736a60e9eeb907d3b93b6e0e5","_cell_guid":"b1076dfc-b9ad-4769-8c92-a6c4dae69d19","trusted":true},"cell_type":"code","source":"#Loading of important libraries that are used throughout \nimport numpy as np # linear algebra\nimport pandas as pd # data processing, CSV file I/O\nimport cv2 # computer vision library\nimport tensorflow as tf # machine learning library\nimport keras # Python interface to tensorflow\nimport matplotlib.pyplot as plt # data visualization tool\nfrom tensorflow.python.keras import backend as K #to utilize more of keras' functionality\n","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"#path to the training and test set\ntrain_dir='/kaggle/input/siim-isic-melanoma-classification/jpeg/train/'\ntest_dir = '/kaggle/input/siim-isic-melanoma-classification/jpeg/test/'\n#loading the training and test set\ntrain=pd.read_csv('/kaggle/input/siim-isic-melanoma-classification/train.csv')\ntest=pd.read_csv('/kaggle/input/siim-isic-melanoma-classification/test.csv')","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"#shows the five first rows of the dataframe\ntrain.head()","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"#include the path to the images in the dataframe \ntrain['path'] = train_dir + train.image_name + \".jpg\"\ntrain.head()\ntest['path'] = test_dir + test.image_name + \".jpg\"","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"#there are some duplicate images in the training data, these images might adversely impact our model, \n# so, lets remove these images\ndup = pd.read_csv(\"/kaggle/input/siim-list-of-duplicates/2020_Challenge_duplicates.csv\")\n\ndrop_idx_list = []\nfor dup_image in dup.ISIC_id_paired:\n    for idx,image in enumerate(train.image_name):\n        if image == dup_image:\n            drop_idx_list.append(idx)\n\nprint(\"no. of duplicates in training dataset:\",len(drop_idx_list))\n\ntrain.drop(drop_idx_list,inplace=True)\n\nprint(\"updated dimensions of the training dataset:\",train.shape)\n","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"#show one instance of the images that we have:\nimg=cv2.imread('../input/siim-isic-melanoma-classification/jpeg/train/ISIC_0015719.jpg')   \nimg = cv2.cvtColor(img, cv2.COLOR_BGR2RGB)\nplt.imshow(img)\n","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"#show how many of the different image types we have, we can see that we have many more benign images than malignant\ntrain.target.value_counts()","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"#to have a more balanced dataset, we create a new dataframe that contains a more equal percentage of each type of target image\ndf_0=train[train['target']==0].sample(3000)\ndf_1=train[train['target']==1]\ntrain=pd.concat([df_0,df_1])\ntrain=train.reset_index()","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"train.shape","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"train.head()","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"# we will resize the given images to 128 x 128 size images for faster processing\nIMG_DIM = (128, 128)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"# Keras provides some amazing libraries to work with images, lets import them\nfrom keras.preprocessing.image import ImageDataGenerator, load_img, img_to_array, array_to_img","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"# We will reserve 20% of our training data for the validation purpose\nfrom sklearn.model_selection import train_test_split\nX_train, X_val, y_train, y_val = train_test_split(train, train.target, test_size=0.2, random_state=42)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"\ntrain_files = X_train.path\nval_files = X_val.path\n\n# load images using load_img function from keras preprocessing \n# target_size is used to load the images with smaller size\n# img_to_array will tranform the loaded image to an array\ntrain_imgs = [img_to_array(load_img(img, target_size=IMG_DIM)) for img in train_files]\nvalidation_imgs = [img_to_array(load_img(img, target_size=IMG_DIM)) for img in val_files]\n\n# convert the list of arrays to array\ntrain_imgs = np.array(train_imgs)\ntrain_labels = y_train\n\nvalidation_imgs = np.array(validation_imgs)\nval_labels = y_val\n\n\nprint('Train dataset shape:', train_imgs.shape, \n      '\\tValidation dataset shape:', validation_imgs.shape)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"train_imgs_scaled = train_imgs.astype('float32')\nvalidation_imgs_scaled  = validation_imgs.astype('float32')\n\n# divide the pixels by 255 to scale the pixels between 0 and 1\ntrain_imgs_scaled /= 255\nvalidation_imgs_scaled /= 255\n\nprint(train_imgs[0].shape)\n\n# array_to_img function will convert the given array to image\narray_to_img(train_imgs[0])","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"# setup basic configuration\nbatch_size = 100\nnum_classes = 2\nepochs = 100\ninput_shape = (128, 128, 3)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"# focal loss, because we have an imbalanced data set\ndef focal_loss(alpha=0.25,gamma=2.0):\n    def focal_crossentropy(y_true, y_pred):\n        bce = K.binary_crossentropy(y_true, y_pred)\n        \n        y_pred = K.clip(y_pred, K.epsilon(), 1.- K.epsilon())\n        p_t = (y_true*y_pred) + ((1-y_true)*(1-y_pred))\n        \n        alpha_factor = 1\n        modulating_factor = 1\n\n        alpha_factor = y_true*alpha + ((1-alpha)*(1-y_true))\n        modulating_factor = K.pow((1-p_t), gamma)\n\n        # compute the final loss and return\n        return K.mean(alpha_factor*modulating_factor*bce, axis=-1)\n    return focal_crossentropy","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"# Here we will import the necessary libraries\nfrom keras.layers import Conv2D, MaxPooling2D, Flatten, Dense, Dropout\n\n# we will import sequential model and add different layers to it\nfrom keras.models import Sequential\n\n# import optimizers, please go through online tutorials if you want to learn what is the purpose of an optimizer\nfrom keras import optimizers\n\n\n# creating and instance of Sequential, which CNN is.\nmodel = Sequential()\n\n# add Conv2D layer(this is the convolutional layer we discussed earlier),filter size,kernel size,activation and padding are the parameters used\n# This layer would create feature maps for each and every filter used\n# feature maps created here are then taken through an activation function(relu here), which decides whether a certain feature is present \n# at a given location in the image.\nmodel.add(Conv2D(16, kernel_size=(3, 3), activation='relu', \n                 input_shape=input_shape))\n# Pooling layer used here will select the largest values on the feature maps and use these as inputs to subsequent layers\nmodel.add(MaxPooling2D(pool_size=(2, 2)))\n\n\n# another set of Convolutional & Max Pooling layers\nmodel.add(Conv2D(64, kernel_size=(3, 3), activation='relu'))\nmodel.add(MaxPooling2D(pool_size=(2, 2)))\nmodel.add(Conv2D(128, kernel_size=(3, 3), activation='relu'))\nmodel.add(MaxPooling2D(pool_size=(2, 2)))\n\nmodel.add(Flatten())\n# Finally the Dense Layer\nmodel.add(Dense(512, activation='relu'))\n# sigmoid function here will help us in performing binary classification\nmodel.add(Dense(1, activation='sigmoid'))\n\nmodel.compile(loss=focal_loss(),\n              optimizer=optimizers.Adam(),\n              metrics=['accuracy', tf.keras.metrics.FalsePositives(),tf.keras.metrics.FalseNegatives()])\n\nmodel.summary()\n","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"history = model.fit(x=train_imgs_scaled, y=train_labels,\n                    validation_data=(validation_imgs_scaled, val_labels),\n                    batch_size=batch_size,\n                    epochs=epochs,\n                    verbose=1)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"#checking model performance\nf, (ax1, ax2) = plt.subplots(1, 2, figsize=(12, 4))\nt = f.suptitle('Basic CNN Performance', fontsize=12)\nf.subplots_adjust(top=0.85, wspace=0.3)\n\nr = len(history.history['accuracy']) +1\nepoch_list = list(range(1,r))\nax1.plot(epoch_list, history.history['accuracy'], label='Train Accuracy')\nax1.plot(epoch_list, history.history['val_accuracy'], label='Validation Accuracy')\nax1.set_xticks(np.arange(0, 100, 5))\nax1.set_ylabel('Accuracy Value')\nax1.set_xlabel('Epoch')\nax1.set_title('Accuracy')\nl1 = ax1.legend(loc=\"best\")\n\nax2.plot(epoch_list, history.history['loss'], label='Train Loss')\nax2.plot(epoch_list, history.history['val_loss'], label='Validation Loss')\nax2.set_xticks(np.arange(0, 100, 5))\nax2.set_ylabel('Loss Value')\nax2.set_xlabel('Epoch')\nax2.set_title('Loss')\nl2 = ax2.legend(loc=\"best\")","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"#the second model will also implement Dropout and Data Augmentation as measures to improve the accuracy.\nfrom keras.preprocessing.image import ImageDataGenerator\n\n#the ImageDataGenerator will rescale the images, zoom in, rotate, shift and flip the images to create a more diverste training set.\ntrain_datagen = ImageDataGenerator(rescale=1./255, zoom_range=0.3, rotation_range=50,\n                                   width_shift_range=0.2, height_shift_range=0.2, shear_range=0.2, \n                                   horizontal_flip=True, fill_mode='nearest')\n\nval_datagen = ImageDataGenerator(rescale=1./255)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"#Under we can see how the ImageDataGenerator augments the images so that we get a more diversified training data.\n#This will result in a more robust model.\nimg_id = 1\n\nimg_generator = train_datagen.flow(train_imgs[img_id:img_id+1], train_labels[img_id:img_id+1],\n                                   batch_size=1)\n\nimg = [next(img_generator) for i in range(0,5)]\n\nfig, ax = plt.subplots(1,5, figsize=(16, 6))\nprint('Labels:', [item[1][0] for item in img])\nl = [ax[i].imshow(img[i][0][0]) for i in range(0,5)]","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"#We now implement the same model as last time, only with the new augmented images as well as two dropout layers.\nfrom tensorflow.keras.models import Sequential, save_model, load_model\nfrom keras.callbacks import ModelCheckpoint\n\ntrain_generator = train_datagen.flow(train_imgs, train_labels, batch_size=30)\nval_generator = val_datagen.flow(validation_imgs, val_labels, batch_size=20)\n\ninput_shape = input_shape\n\nmodel = tf.keras.Sequential() # define your model normally\nmodel.add(Conv2D(16, kernel_size=(3, 3), activation='relu', \n                 input_shape=input_shape))\nmodel.add(MaxPooling2D(pool_size=(2, 2)))\n\nmodel.add(Conv2D(64, kernel_size=(3, 3), activation='relu'))\nmodel.add(MaxPooling2D(pool_size=(2, 2)))\n\nmodel.add(Conv2D(128, kernel_size=(3, 3), activation='relu'))\nmodel.add(MaxPooling2D(pool_size=(2, 2)))\n\nmodel.add(Conv2D(128, kernel_size=(3, 3), activation='relu'))\nmodel.add(MaxPooling2D(pool_size=(2, 2)))\n\nmodel.add(Flatten())\nmodel.add(Dense(512, activation='relu'))\nmodel.add(Dropout(0.2))\nmodel.add(Dense(512, activation='relu'))\nmodel.add(Dropout(0.2))\nmodel.add(Dense(1, activation='sigmoid'))\nmodel.compile(loss=focal_loss(),\n              optimizer=optimizers.Adam(), \n              metrics=['accuracy', tf.keras.metrics.FalsePositives(),tf.keras.metrics.FalseNegatives()])\n\n#we want to save the best model for our test predictions\ncheckpointer = ModelCheckpoint(filepath=\"weights.hdf5\", verbose=1, save_best_only=True)\n\nhistory = model.fit_generator(train_generator, steps_per_epoch=32, epochs=100,\n                              validation_data=val_generator, validation_steps=12, \n                              verbose=1, callbacks=[checkpointer])\n\nmodel.summary()","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"f, (ax1, ax2) = plt.subplots(1, 2, figsize=(12, 4))\nt = f.suptitle('CNN with Regularization & Augmentation', fontsize=12)\nf.subplots_adjust(top=0.85, wspace=0.3)\n\nr = len(history.history['accuracy']) +1\nepoch_list = list(range(1,r))\nax1.plot(epoch_list, history.history['accuracy'], label='Train Accuracy')\nax1.plot(epoch_list, history.history['val_accuracy'], label='Validation Accuracy')\nax1.set_xticks(np.arange(0, 101, 5))\nax1.set_ylabel('Accuracy Value')\nax1.set_xlabel('Epoch')\nax1.set_title('Accuracy')\nl1 = ax1.legend(loc=\"best\")\n\nax2.plot(epoch_list, history.history['loss'], label='Train Loss')\nax2.plot(epoch_list, history.history['val_loss'], label='Validation Loss')\nax2.set_xticks(np.arange(0, 101, 5))\nax2.set_ylabel('Loss Value')\nax2.set_xlabel('Epoch')\nax2.set_title('Loss')\nl2 = ax2.legend(loc=\"best\")","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"import gc\nx_test = np.load('../input/siimisic-melanoma-resized-images/x_test_128.npy')\nx_test = x_test.astype('float16')\ntest_imgs_scaled = x_test / 255\ndel x_test\ngc.collect()\n\n#load our best saved model\nmodel.load_weights('weights.hdf5')\n\ntarget=[]\ni = 0\nfor img in test_imgs_scaled:\n    img1=np.reshape(img,(1,128,128,3))\n    prediction = model.predict(img1)\n    i = i + 1\n    print(\"predicted image no.\",i)\n    target.append(prediction[0][0])\n    \n#the submission file:\nsub=pd.read_csv(\"../input/siim-isic-melanoma-classification/sample_submission.csv\")\nsub['target']=target\nsub.to_csv('submission.csv', index=False)\nsub.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}