{"cells":[{"metadata":{},"cell_type":"markdown","source":"This is a baseline model to detect Melanoma in the images given in the dataset. Here I have used subset of training data (3500 images). I used 3 pre-trained models which are VGG16, Resnet50 and Efficientnet B7, and ensembled the results using weighted average.\n\nThe process will be consisting of below steps.\n\n1. Importing the required libraries\n2. Loading and preparng the images\n3. Preprocessing\n4. Defining and training the model8\n5. Getting predictions for the model\n6. Repeating step 4,5 for other models\n7. Blending the scores from all 3 models\n8. Submission","execution_count":null},{"metadata":{},"cell_type":"markdown","source":"#  Importing Libraries","execution_count":null},{"metadata":{"_uuid":"d629ff2d2480ee46fbb7e2d37f6b5fab8052498a","_cell_guid":"79c7e3d0-c299-4dcb-8224-4455121ee9b0","trusted":true},"cell_type":"code","source":"import numpy as np\nimport pandas as pd\n\nimport keras\nfrom keras.preprocessing import image\nfrom keras.utils import to_categorical\n\nfrom keras.applications.vgg16 import VGG16,preprocess_input\nfrom keras.applications.resnet50 import ResNet50\nfrom keras.models import Sequential,Model\nfrom keras.layers import Conv2D, MaxPooling2D, Dense, Dropout, Input, Flatten,BatchNormalization,Activation\n\nfrom keras.applications.resnet50 import preprocess_input\nfrom keras.preprocessing.image import ImageDataGenerator\n\nfrom keras.optimizers import Adam, SGD, RMSprop\nfrom tensorflow.python.keras import backend as K\n\nfrom sklearn.model_selection import train_test_split\nfrom tqdm import tqdm\nimport cv2","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"# Exploring the data","execution_count":null},{"metadata":{"trusted":true},"cell_type":"code","source":"# Directory Listings for train and test images\n\ntrain_dir='/kaggle/input/siim-isic-melanoma-classification/jpeg/train/'\ntest_dir='/kaggle/input/siim-isic-melanoma-classification/jpeg/test/'","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"# Reading the csv files\n\ntrain = pd.read_csv('/kaggle/input/siim-isic-melanoma-classification/train.csv')\ntest = pd.read_csv('/kaggle/input/siim-isic-melanoma-classification/test.csv')\nsubmission=pd.read_csv('/kaggle/input/siim-isic-melanoma-classification/sample_submission.csv')","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"# Exploring the content of train file\ntrain.head()","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"# Comparing the number of records in both categories\ntrain['target'].value_counts()","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"The data is highly imbalanced as only 584 records belong to class 1 (Malignant).\nHence we will be taking a sample of 3000 images from benign cases, along with all 584 malignant cases","execution_count":null},{"metadata":{"trusted":true},"cell_type":"code","source":"train_benign = train[train['target']==0].sample(3000)\ntrain_malign = train[train['target']==1]\ntrain_samples = pd.concat([train_benign,train_malign])\ntrain_samples.reset_index()","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"# Preparing the train and test data","execution_count":null},{"metadata":{"trusted":true},"cell_type":"code","source":"# Training data\ntrain_labels = []\ntrain_images =[]\n\nfor i in range(train_samples.shape[0]):\n    train_images.append(train_dir+train_samples['image_name'].iloc[i]+'.jpg')\n    train_labels.append(train_samples['target'].iloc[i])\n\ndf_train = pd.DataFrame(train_images)\ndf_train.columns =['images']\ndf_train['target'] = train_labels","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"# Test data\ntest_images =[]\nfor i in range(test.shape[0]):\n    test_images.append(test_dir+test['image_name'].iloc[i]+'.jpg')\n\ndf_test = pd.DataFrame(test_images)\ndf_test.columns = ['images']","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"# Splitting the train data further into train and validation sets\nX_train, X_val, y_train,y_val = train_test_split(df_train['images'],df_train['target'],test_size=0.2,random_state=0)\n\ntrain = pd.DataFrame(X_train)\ntrain.columns = ['images']\ntrain['target']=y_train\n\nvalidation = pd.DataFrame(X_val)\nvalidation.columns = ['images']\nvalidation['target']=y_val","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"# Helper Functions","execution_count":null},{"metadata":{"trusted":true},"cell_type":"code","source":"def get_predictions(model,sub_df):\n    target=[]\n    for path in df_test['images']:\n        img=cv2.imread(str(path))\n        img = cv2.resize(img, (224,224))\n        img = cv2.cvtColor(img, cv2.COLOR_BGR2RGB)\n        img = img.astype(np.float32)/255.\n        img=np.reshape(img,(1,224,224,3))\n        prediction=model.predict(img)\n        target.append(prediction[0][0])\n    \n    sub_df['target']=target\n    return sub_df","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"# Data Preprocessing","execution_count":null},{"metadata":{},"cell_type":"markdown","source":"Data Processing will include following tasks\n\n1. Normalization of pixel values to range of 0 to 1\n2. Reshaping of the images\n3. Data augumentation for training images","execution_count":null},{"metadata":{"trusted":true},"cell_type":"code","source":"train_datagen = ImageDataGenerator(preprocess_input,rescale=1./255,rotation_range=20,\n    width_shift_range=0.2,\n    height_shift_range=0.2,horizontal_flip=True)\n\nval_datagen = ImageDataGenerator(preprocess_input,rescale=1./255)\n\nimage_size = 224\n\ntrain_generator = train_datagen.flow_from_dataframe(\n                    train,\n                    x_col='images',\n                    y_col ='target',\n                    target_size=(image_size,image_size),\n                    batch_size=8,\n                    shuffle=True,\n                    class_mode='raw')\n\nvalidation_generator = val_datagen.flow_from_dataframe(\n                    validation,\n                    x_col='images',\n                    y_col ='target',\n                    target_size=(image_size,image_size),\n                    batch_size=8,\n                    shuffle=False,\n                    class_mode='raw')","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"# Modeling","execution_count":null},{"metadata":{},"cell_type":"markdown","source":"**1. VGG16 Pre-trained Model**","execution_count":null},{"metadata":{"trusted":true},"cell_type":"code","source":"def vgg16_model(num_classes=None):\n    model = VGG16(weights='imagenet',include_top=False,input_shape=(224,224,3))\n    x = Flatten()(model.output)\n    output = Dense(1,activation='sigmoid')(x)\n    model = Model(model.input,output)\n    \n    return model","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"vgg_conv = vgg16_model(1)","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"Using focal loss instead of binary_cropssentory because of class imbalance","execution_count":null},{"metadata":{"trusted":true},"cell_type":"code","source":"def 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":"# Defining the optimizer and compiling the model\nopt = Adam(lr=1e-5)\nvgg_conv.compile(loss=focal_loss(),optimizer=opt,metrics=[keras.metrics.AUC()])","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"# Denining the num of epochs, batch_size and steps for training and validation\nnb_epochs = 2\nbatch_size=8\nnb_train_steps = train.shape[0]//batch_size  # // rounds off the result of division\nnb_validation_steps = validation.shape[0]//batch_size\nprint(\"Number of training and validation steps are {} and {}\".format(nb_train_steps,nb_validation_steps))","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"# Fitting the model\nvgg_conv.fit_generator(\n    train_generator,\n    steps_per_epoch=nb_train_steps,\n    epochs=nb_epochs,\n    validation_data=validation_generator,\n    validation_steps=nb_validation_steps)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"# Getting the predictions for test data\n\nsub_dfs = []\n\nsub_vgg16 = submission.copy()\nsub_vgg16 = get_predictions(vgg_conv,sub_vgg16)\nsub_vgg16.head()","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"sub_vgg16.to_csv('submission_vgg16.csv',index=False)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"df_vgg16 = pd.read_csv('../input/subvgg16csv/submission_vgg16.csv')\ndf_vgg16.head()","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"sub_dfs = []\nsub_dfs.append(df_vgg16)","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"**2. Resnet50 Pretrained Model**","execution_count":null},{"metadata":{"trusted":true},"cell_type":"code","source":"def resnet50_model(num_classes=None):\n    model = ResNet50(weights='imagenet',include_top=False,input_shape=(224,224,3),pooling='avg')\n    x = Flatten()(model.output)\n    output = Dense(1,activation='sigmoid')(x)\n    model = Model(model.input,output)\n    \n    return model","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"resnet_conv = resnet50_model(1)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"# Denining the optimizer and compiling the model\nopt = Adam(lr=1e-5)\nresnet_conv.compile(loss=focal_loss(),optimizer=opt,metrics=[keras.metrics.AUC()])","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"# Denining the num of epochs, batch_size and steps for training and validation\nnb_epochs = 2\nbatch_size=8\nnb_train_steps = train.shape[0]//batch_size  # // rounds off the result of division\nnb_validation_steps = validation.shape[0]//batch_size\nprint(\"Number of training and validation steps are {} and {}\".format(nb_train_steps,nb_validation_steps))","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"# Fitting the model\nresnet_conv.fit_generator(\n    train_generator,\n    steps_per_epoch=nb_train_steps,\n    epochs=nb_epochs,\n    validation_data=validation_generator,\n    validation_steps=nb_validation_steps)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"# Getting the predictions for test data\n\n\nsub_resnet = submission.copy()\nsub_resnet = get_predictions(resnet_conv,sub_resnet)\nsub_resnet.head()","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"sub_resnet.to_csv('submission_resnet.csv',index=False)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"df_resnet = pd.read_csv('../input/subresnetcsv/submission_resnet.csv')\nsub_dfs.append(df_resnet)","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"**2. EfficientNet B7 Pretrained Model**","execution_count":null},{"metadata":{"trusted":true},"cell_type":"code","source":"!pip install -q efficientnet\nimport efficientnet.tfkeras as efn","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"def efficientnet_model(num_classes=None):\n    \n    model = keras.Sequential([\n        \n            efn.EfficientNetB7(\n            weights='imagenet',\n            include_top=False,\n            input_shape=(224,224,3)),\n        keras.layers.GlobalAveragePooling2D(), #Works like flatten layer but adds pooling to it to optimize data before feeding to FC layer\n        keras.layers.Dense(1024,activation='relu'),\n        keras.layers.Dropout(0.3),\n        keras.layers.Dense(512,activation='relu'),\n        keras.layers.Dropout(0.2),\n        keras.layers.Dense(256,activation='relu'),\n        keras.layers.Dropout(0.2),\n        keras.layers.Dense(128,activation='relu'),\n        keras.layers.Dropout(0.1),\n        keras.layers.Dense(1,activation='sigmoid')\n        \n    ])\n    return model","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"efficientnet_conv = efficientnet_model(1)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"# Defining the optimizer and compiling the model\nopt = Adam(lr=1e-5)\nefficientnet_conv.compile(loss=focal_loss(),optimizer=opt,metrics=[keras.metrics.AUC()])","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"# Defining the num of epochs, batch_size and steps for training and validation\nnb_epochs = 2\nbatch_size=8\nnb_train_steps = train.shape[0]//batch_size  # // rounds off the result of division\nnb_validation_steps = validation.shape[0]//batch_size\nprint(\"Number of training and validation steps are {} and {}\".format(nb_train_steps,nb_validation_steps))","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"# Fitting the model\nefficientnet_conv.fit_generator(\n    train_generator,\n    steps_per_epoch=nb_train_steps,\n    epochs=nb_epochs,\n    validation_data=validation_generator,\n    validation_steps=nb_validation_steps)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"# Getting the predictions for test data\n\n\nsub_efficientnet = submission.copy()\nsub_efficientnet = get_predictions(efficientnet_conv,sub_efficientnet)\nsub_efficientnet.head()","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"sub_efficientnet.to_csv('submission_efficientnet.csv',index=False)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"df_efficient = pd.read_csv('../input/subefficientnetcsv/submission_efficientnet.csv')\nsub_dfs.append(df_efficient)","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"# Blending Scores from All Models","execution_count":null},{"metadata":{"trusted":true},"cell_type":"code","source":"from scipy.stats import rankdata","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"#Ranking results from all models\nfor i in range(3) :\n    sub_dfs[i]['target'] = rankdata(sub_dfs[i]['target'], method='min')","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"Giving more weightage to VGG16 since it gave better score on validation data","execution_count":null},{"metadata":{"trusted":true},"cell_type":"code","source":"sub_dfs[0]['target'] = sub_dfs[0]['target']*0.8 + sub_dfs[1]['target']*0.1 + sub_dfs[2]['target']*0.1\nsub_dfs[0].head()","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"# Submitting Final Predictions","execution_count":null},{"metadata":{"trusted":true},"cell_type":"code","source":"sub_dfs[0].to_csv('submission_blending.csv' , index = False)","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}