{"cells":[{"metadata":{},"cell_type":"markdown","source":"## Introduction\n\n---\n\n![](https://miro.medium.com/max/10096/1*B7T0sSVNPCNtdpyMkA7lGA.jpeg)\n\n---\n\n### TF-explain\n\n[tf-explain](https://tf-explain.readthedocs.io/en/latest/) offers interpretability methods for Tensorflow 2.0 to ease neural network’s understanding. With either its core API or its tf.keras callbacks, you can get a feedback on the training of your models.\n\nWe will use **Core API** in this notebook to visualize **What our Model is seeing in the Image to take the decision.**\n\n*(You can use it as a Callback during model training)*\n\n\n### GradCams\n\n---\n\n**Gradient-weighted Class Activation Mapping(Grad-CAM)** is a method that extracts gradients from a convolutional neural network's final convolutional layer(mostly) and uses this information to highlight regions most responsible for the predicted probability the image belongs to a predefined class.\n\nThe steps of Grad-CAM include extracting the gradients with subsequent global average pooling. A ReLU activation function is added to only depict the regions of the image that have a positive contribution to the predefined class. The resulting attention map can be plotted over the original image and can be interpreted as a visual tool for identifying regions the model ‘looks at’ to predict if an image belongs to a specific class. Readers interested in the mathematical theory behind Grad-CAM are encouraged to read the paper by Selvaraju et al. via https://arxiv.org/abs/1610.02391.\n\nThis notebook demonstrates the relative ease of implementing Grad-CAM with our basic model using **tf-explain**.\n\n---\n\n<font size=5 color='red'>Please Upvote, If you find it useful!!</font>","execution_count":null},{"metadata":{},"cell_type":"markdown","source":"## Necessary Libraries","execution_count":null},{"metadata":{"trusted":true},"cell_type":"code","source":"!pip install -q efficientnet\n!pip install -q tf-explain","execution_count":null,"outputs":[]},{"metadata":{"_uuid":"8f2839f25d086af736a60e9eeb907d3b93b6e0e5","_cell_guid":"b1076dfc-b9ad-4769-8c92-a6c4dae69d19","trusted":true},"cell_type":"code","source":"import os\nimport cv2\nimport time\nimport numpy as np\nimport pandas as pd\nfrom datetime import date\n\nfrom scipy.stats import rankdata\n\nimport matplotlib.pyplot as plt\nimport seaborn as sns\nsns.set()\n\nfrom kaggle_datasets import KaggleDatasets\n\nimport tensorflow as tf\nimport tensorflow.keras.backend as K\nfrom tensorflow.keras.layers import Dense, BatchNormalization, ReLU, Dropout\nfrom tensorflow.keras.models import Model, Sequential\nfrom tensorflow.keras import optimizers\n\nfrom sklearn.metrics import roc_auc_score, roc_curve\n\nfrom tf_explain.core.grad_cam import GradCAM\n\n# from tensorflow.keras.mixed_precision import experimental as mixed_precision\n# policy = mixed_precision.Policy('mixed_bfloat16')\n# mixed_precision.set_policy(policy)\n\nimport efficientnet.tfkeras as efn","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"## Hyperparameters used to train the Model","execution_count":null},{"metadata":{"trusted":true},"cell_type":"code","source":"SEED = 2020\n\nLABEL_SMOOTHING = 0.05\nWEIGHT_DECAY = 0\n\nIMG_R = 256\nIMG_C = 250\nIMG_N = 224\n\nROT = 180.0\nSHR = 2.0\nHZOOM = 6.0\nWZOOM = 6.0\nHSHIFT = 8.0\nWSHIFT = 8.0\n\nR, C = 5,5","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"## Data Loading","execution_count":null},{"metadata":{"trusted":true},"cell_type":"code","source":"DATA_PATH = '../input/siim-isic-melanoma-classification'\nMODEL_PATH = '../input/melanoma-efficientnet-b6-tpu-tta-saved-models'\nTRAIN_IMG_PATH = '../input/siim-isic-melanoma-classification/jpeg/train'\nTEST_IMG_PATH = '../input/siim-isic-melanoma-classification/jpeg/test'\n\ntrain_df = pd.read_csv(os.path.join(DATA_PATH,'train.csv'))\ntest_df = pd.read_csv(os.path.join(DATA_PATH,'test.csv'))\n\nsgkf = pd.read_csv('../input/siimisic-stratified-group-kfold-traindata/train_StratifiedGroupK(5)Fold(SEED2020)(Group_sex_anatomsite_target).csv')\n\nval_pred = pd.read_csv(f'{MODEL_PATH}/{[filename for filename in os.listdir(MODEL_PATH) if \"VALPREDS\" in filename][0]}')\n\ntrain_pred = pd.read_csv(f'{MODEL_PATH}/{[filename for filename in os.listdir(MODEL_PATH) if \"TRAINPREDS\" in filename][0]}')\ntrain_logs = pd.read_csv(f'{MODEL_PATH}/{[filename for filename in os.listdir(MODEL_PATH) if \"TRAINING_LOGS\" in filename][0]}')\n\ntest_pred = pd.read_csv(f'{MODEL_PATH}/{[filename for filename in os.listdir(MODEL_PATH) if \"TESTPREDS_2\" in filename][0]}')\ntest_pred_mean = pd.read_csv(f'{MODEL_PATH}/{[filename for filename in os.listdir(MODEL_PATH) if \"TESTPREDS_MEAN\" in filename][0]}')\ntest_pred_noaug = pd.read_csv(f'{MODEL_PATH}/{[filename for filename in os.listdir(MODEL_PATH) if \"TESTPREDS_NOAUG\" in filename][0]}')\ntest_pred_rank = pd.read_csv(f'{MODEL_PATH}/{[filename for filename in os.listdir(MODEL_PATH) if \"TESTPREDS_RANK\" in filename][0]}')\n\nFOLD = int(os.listdir(MODEL_PATH)[0].split(\"_\")[-1][0])\nprint(\"Fold: \",FOLD)\n\nEFNMODEL = [filename for filename in os.listdir(MODEL_PATH) if 'hdf5' in filename][0].split(\"_\")[2][-1]\nprint(\"EfficientNet Model Num: \",EFNMODEL)\n\nval_merged = sgkf[sgkf.fold==FOLD].merge(val_pred,on='image_name')\ntrain_merged = sgkf[sgkf.fold!=FOLD].merge(train_pred,on='image_name')","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"## Model to Interpret","execution_count":null},{"metadata":{"trusted":true,"_kg_hide-output":true},"cell_type":"code","source":"modelName = f'EfficientNetB{EFNMODEL}'\n\nMODEL_WEIGHTS = [filename for filename in os.listdir(MODEL_PATH) if 'hdf5' in filename][0]\n\n# model_input = tf.keras.Input(shape=(IMG_N, IMG_N, 3), name='imgInput')\n    \nconstructor = getattr(efn, modelName)\n\nbase_model = constructor(include_top=False,\n                         weights='imagenet',\n                         input_shape=(IMG_N, IMG_N, 3),\n                         pooling='avg')\n\noutput = tf.keras.layers.Dense(1, activation='sigmoid',dtype='float32')(base_model.output)\n\nmodel = tf.keras.Model(base_model.input, output, name=modelName)\n        \n# model.compile(\n#     optimizer='adam',\n#     loss = tf.keras.losses.BinaryCrossentropy(label_smoothing = LABEL_SMOOTHING),\n#     metrics=[\n#         'binary_accuracy',\n#         tf.keras.metrics.AUC(name='auc'),\n#         tf.keras.metrics.Recall(name='recall'),\n#         tf.keras.metrics.TruePositives(name=\"TP\"),\n#         tf.keras.metrics.FalseNegatives(name=\"FN\"),\n#         tf.keras.metrics.FalsePositives(name=\"FP\")\n#     ]\n# )\n\nmodel.summary()\n\nmodel.load_weights(f'{MODEL_PATH}/{MODEL_WEIGHTS}')","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"## Necessary Functions","execution_count":null},{"metadata":{"trusted":true},"cell_type":"code","source":"def getImage(image_name,train=True):\n    PATH = TRAIN_IMG_PATH if train else TEST_IMG_PATH\n    \n    image = cv2.imread(f'{PATH}/{image_name}.jpg')\n    image = cv2.cvtColor(image,cv2.COLOR_BGR2RGB)\n    \n    # Preprocessing\n    image = cv2.resize(image,(IMG_R,IMG_R))\n    image = tf.image.central_crop(image,IMG_C/IMG_R).numpy()\n    image = cv2.resize(image,(IMG_N,IMG_N))\n    \n#     print(image)\n    \n    return image\n\ndef overlay_heatmap(heatmap, image, alpha=0.5, colormap=cv2.COLORMAP_JET):\n    # apply the supplied color map to the heatmap and then\n    # overlay the heatmap on the input image\n    heatmap = cv2.applyColorMap(heatmap, colormap)\n    output = cv2.addWeighted(image, alpha, heatmap, 1 - alpha, 0)\n    # return a 2-tuple of the color mapped heatmap and the output,\n    # overlaid image\n    return heatmap,output","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"## Model Interpretation","execution_count":null},{"metadata":{},"cell_type":"markdown","source":"### Distributions of Predictions","execution_count":null},{"metadata":{"trusted":true,"_kg_hide-input":true},"cell_type":"code","source":"fig, ax = plt.subplots(2,2,figsize=(20,15))\n\nval_merged['ranks'] = rankdata(val_merged.target_y.values)/len(val_merged.target_y.values)\ntrain_merged['ranks'] = rankdata(train_merged.target_y.values)/len(train_merged.target_y.values)\n\n\n# sns.kdeplot(val_merged[val_merged.target_x==1].ranks,label='malignant(Rank wise)',shade=True,ax=ax[0,0])\n# sns.kdeplot(val_merged[val_merged.target_x==0].ranks,label='beingn(Rank wise)',shade=True,ax=ax[0,0])\n# sns.kdeplot(val_merged.target_y,label='Combined',shade=True,ax=ax[0,0])\nsns.kdeplot(val_merged[val_merged.target_x==1].target_y,label='malignant',shade=True,ax=ax[0,0])\nsns.kdeplot(val_merged[val_merged.target_x==0].target_y,label='benign',shade=True,ax=ax[0,0])\nax[0,0].set_title(f'Distribution of Validation set Predictions (FOLD:{FOLD})')\n\n# sns.kdeplot(train_merged.target_y,label='Combined',shade=True,ax=ax[0,1])\nsns.kdeplot(train_merged[train_merged.target_x==1].target_y,label='malignant',shade=True,ax=ax[0,1])\nsns.kdeplot(train_merged[train_merged.target_x==0].target_y,label='benign',shade=True,ax=ax[0,1])\nax[0,1].set_title(f'Distribution of Training set Predictions (FOLD:{FOLD})')\n\nfpr, tpr, thresholds = roc_curve(val_merged.target_x, val_merged.target_y)\nroc_auc = roc_auc_score(val_merged.target_x, val_merged.target_y)\nax[1,0].plot(fpr,tpr,linestyle='--')\nax[1,0].set_title(f\"ROC Curve of Validation set predictions (AUC: {roc_auc})\")\n\nfpr, tpr, thresholds = roc_curve(train_merged.target_x, train_merged.target_y)\nroc_auc = roc_auc_score(train_merged.target_x, train_merged.target_y)\nax[1,1].plot(fpr,tpr,linestyle='--')\nax[1,1].set_title(f\"ROC Curve of Training set predictions (AUC: {roc_auc})\")","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"_kg_hide-input":true},"cell_type":"code","source":"fig, ax = plt.subplots(1,3,figsize=(20,5))\n\nsns.kdeplot(test_pred_mean.target,shade=True,ax=ax[0])\nax[0].set_title(f'Distribution of Test set (TTA-Mean) Predictions')\n\nsns.kdeplot(test_pred_noaug.target,shade=True,ax=ax[1])\nax[1].set_title(f'Distribution of Test set (No-AUG) Predictions')\n\nsns.kdeplot(test_pred_rank.target,shade=True,ax=ax[2])\nax[2].set_title(f'Distribution of Test set (TTA-Mean by Ranks) Predictions')","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"### GridCAMs of TP + FN of Training Images","execution_count":null},{"metadata":{"trusted":true},"cell_type":"code","source":"def displayImages(df,target):\n    \n    image_names = list(set(df.image_name).intersection(set(df[df.target_x==target].image_name)))\n    print(\"Total Images: \",len(image_names))\n    \n    r, c = min(int(np.ceil(len(image_names)/R)),R), C\n    \n    if r==1:\n        r=2\n    \n    fig, ax = plt.subplots(r,c,figsize=(c*4*2,r*6))\n\n    layer_name = 'top_conv'\n\n    # fig.suptitle(f'GridCAMs of layer: {layer_name} of train images',fontsize=15)\n\n    explainer = GradCAM()\n\n    i = 0\n\n    for image_name in np.random.choice(image_names,replace=False,size=min(r*c,len(image_names))):\n\n        prediction = df[df.image_name==image_name]['target_y'].values[0]\n        actual = df[df.image_name==image_name]['target_x'].values[0]\n\n        color = 'green' if int(prediction>=0.5)==actual else 'red'\n\n        title = f'Image Name: {image_name}\\nActual: {actual}\\nPrediction: {prediction}'\n\n        image = getImage(image_name)\n\n        heatmap1 = explainer.explain(([image/255.0], None), model, layer_name = layer_name, class_index=0)\n\n        heatmap2, output = overlay_heatmap(heatmap1,image)\n\n        output = np.hstack([image,output])\n\n        ax[i//c,i%c].imshow(output)\n        ax[i//c,i%c].axis('off')\n        ax[i//c,i%c].set_title(title,fontsize=15,color=color)\n\n        i += 1","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"displayImages(train_merged,1)","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"### GridCAMs of Benign Predictions(TN + FP) of Training Images","execution_count":null},{"metadata":{"trusted":true},"cell_type":"code","source":"displayImages(train_merged,0)","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"### GridCAMs of TP + FN in Validation Images","execution_count":null},{"metadata":{"trusted":true},"cell_type":"code","source":"displayImages(val_merged,1)","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"### GridCAMs of TN + FP in Validation Images","execution_count":null},{"metadata":{"trusted":true},"cell_type":"code","source":"displayImages(val_merged,0)","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"### GridCAMs of a Random Patient from Validation-set","execution_count":null},{"metadata":{"trusted":true},"cell_type":"code","source":"layer_name = 'top_conv'\nexplainer = GradCAM()\n\npatient_id = np.random.choice(val_merged.patient_id.unique(),size=1,replace=False)[0]\n\nx = val_merged[val_merged.patient_id == patient_id].sort_values(['age_approx','anatom_site_general_challenge','image_name'])\n\nr, c = int(np.ceil(x.shape[0]/5)), 5\n\nfig, ax = plt.subplots(r,c, figsize=(c*4*2,6*r))\n\n# fig = fig.suptitle(f'{patient_id} Sex: {x.sex.values[0]}',fontsize=20)\nprint(f'{patient_id} Sex: {x.sex.values[0]}')\n\nfor i, image_name in enumerate(x.image_name.values):\n    \n    prediction = val_pred[val_pred.image_name==image_name]['target'].values[0]\n    actual = train_df[train_df.image_name==image_name]['target'].values[0]\n    age = train_df[train_df.image_name==image_name]['age_approx'].values[0]\n    site = train_df[train_df.image_name==image_name]['anatom_site_general_challenge'].values[0]\n    \n    color = 'green' if int(prediction>=0.5)==actual else 'red'\n    \n    title = f'Image Name: {image_name}\\nActual: {actual}\\nPrediction: {prediction}\\nAge:{age}\\nAnatom site:{site}'\n    \n    image = getImage(image_name)\n    \n    heatmap1 = explainer.explain(([image/255.0], None), model, layer_name = layer_name, class_index=0)\n    \n    heatmap2, output = overlay_heatmap(heatmap1,image)\n    \n    output = np.hstack([image,output])\n    \n    if r>1:\n        ax[i//c,i%c].imshow(output)\n        ax[i//c,i%c].set_title(title,color=color)\n        ax[i//c,i%c].axis('off')\n    else:\n        ax[i%c].imshow(output)\n        ax[i%c].set_title(title,color=color)\n        ax[i%c].axis('off')\n\n# plt.savefig(f'{x.target.sum()}_{patient_id}_{x.sex.values[0]}.png')\n\nplt.show()","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"### GridCAMs of Different Anatom Sites from Validation-set","execution_count":null},{"metadata":{"trusted":true},"cell_type":"code","source":"val_merged.anatom_site_general_challenge.value_counts()","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"def displayAnatomsite(df,site,target,layer_name = 'top_conv'):\n    image_names = list(df[(df.target_x==target) & (df.anatom_site_general_challenge==site)].image_name)\n    print(\"Total Images: \",len(image_names))\n    \n    if len(image_names)==0:\n        return\n    \n    r, c = 5, 5\n    \n    r, c = min(int(np.ceil(len(image_names)/5)),5), 5\n    if r==1:\n        r=2\n\n    fig, ax = plt.subplots(r,c,figsize=(c*4*2,r*6))\n\n    # fig.suptitle(f'GridCAMs of layer: {layer_name} of train images',fontsize=15)\n\n    explainer = GradCAM()\n\n    i = 0\n\n    for image_name in np.random.choice(image_names,replace=False,size=min(r*c,len(image_names))):\n\n        prediction = df[df.image_name==image_name]['target_y'].values[0]\n        actual = df[df.image_name==image_name]['target_x'].values[0]\n\n        color = 'green' if int(prediction>=0.5)==actual else 'red'\n\n        title = f'Image Name: {image_name}\\nActual: {actual}\\nPrediction: {prediction}'\n\n        image = getImage(image_name)\n\n        heatmap1 = explainer.explain(([image/255.0], None), model, layer_name = layer_name, class_index=0)\n\n        heatmap2, output = overlay_heatmap(heatmap1,image)\n\n        output = np.hstack([image,output])\n\n        ax[i//c,i%c].imshow(output)\n        ax[i//c,i%c].axis('off')\n        ax[i//c,i%c].set_title(title,fontsize=15,color=color)\n\n        i += 1","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"#### Torso (TP+FN)","execution_count":null},{"metadata":{"trusted":true},"cell_type":"code","source":"displayAnatomsite(val_merged,'torso',1)","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"#### Torso (TN + FP)","execution_count":null},{"metadata":{"trusted":true},"cell_type":"code","source":"displayAnatomsite(val_merged,'torso',0)","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"#### Lower Extremity (TP + FN)","execution_count":null},{"metadata":{"trusted":true},"cell_type":"code","source":"displayAnatomsite(val_merged,'lower extremity',1)","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"#### Lower Extremity (TN + FP)","execution_count":null},{"metadata":{"trusted":true},"cell_type":"code","source":"displayAnatomsite(val_merged,'lower extremity',0)","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"#### Upper Extremity (TP + FN)\n","execution_count":null},{"metadata":{"trusted":true},"cell_type":"code","source":"displayAnatomsite(val_merged,'upper extremity',1)","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"#### Upper Extremity (TN + FP)","execution_count":null},{"metadata":{"trusted":true},"cell_type":"code","source":"displayAnatomsite(val_merged,'upper extremity',0)","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"#### Head/Neck (TP + FN)","execution_count":null},{"metadata":{"trusted":true},"cell_type":"code","source":"displayAnatomsite(val_merged,'head/neck',1)","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"#### Head/Neck (TN + FP)","execution_count":null},{"metadata":{"trusted":true},"cell_type":"code","source":"displayAnatomsite(val_merged,'head/neck',0)","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"#### Palms/Soles (TP + FN)","execution_count":null},{"metadata":{"trusted":true},"cell_type":"code","source":"displayAnatomsite(val_merged,'palms/soles',1)","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"#### Palms/Soles (TN + FP)","execution_count":null},{"metadata":{"trusted":true},"cell_type":"code","source":"displayAnatomsite(val_merged,'palms/soles',0)","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"#### Oral/Genital (TP + FN)","execution_count":null},{"metadata":{"trusted":true},"cell_type":"code","source":"displayAnatomsite(val_merged,'oral/genital',1)","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"#### Oral/Genital (TN + FP)","execution_count":null},{"metadata":{"trusted":true},"cell_type":"code","source":"displayAnatomsite(val_merged,'oral/genital',0)","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"### Mistakes made by the Model","execution_count":null},{"metadata":{},"cell_type":"markdown","source":"#### False Negatives in Validation set","execution_count":null},{"metadata":{"_kg_hide-input":true,"trusted":true},"cell_type":"code","source":"layer_name = 'top_conv'\n\nimage_names = list(val_merged[(val_merged.target_x==1)&(val_merged.target_y<0.5)].image_name)\nprint(\"Total Images: \",len(image_names))\n\nif len(image_name)!=0:\n\n    r, c = 5, 5\n\n    r, c = min(int(np.ceil(len(image_names)/5)),5), 5\n    if r==1:\n        r=2\n\n    fig, ax = plt.subplots(r,c,figsize=(c*4*2,r*6))\n\n    # fig.suptitle(f'GridCAMs of layer: {layer_name} of train images',fontsize=15)\n\n    explainer = GradCAM()\n\n    i = 0\n\n    for image_name in np.random.choice(image_names,replace=False,size=min(r*c,len(image_names))):\n\n        prediction = val_merged[val_merged.image_name==image_name]['target_y'].values[0]\n        actual = val_merged[val_merged.image_name==image_name]['target_x'].values[0]\n\n        color = 'green' if int(prediction>=0.5)==actual else 'red'\n\n        title = f'Image Name: {image_name}\\nActual: {actual}\\nPrediction: {prediction}'\n\n        image = getImage(image_name)\n\n        heatmap1 = explainer.explain(([image/255.0], None), model, layer_name = layer_name, class_index=0)\n\n        heatmap2, output = overlay_heatmap(heatmap1,image)\n\n        output = np.hstack([image,output])\n\n        ax[i//c,i%c].imshow(output)\n        ax[i//c,i%c].axis('off')\n        ax[i//c,i%c].set_title(title,fontsize=15,color=color)\n\n        i += 1","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"#### False Positives in Validation set","execution_count":null},{"metadata":{"_kg_hide-input":true,"trusted":true},"cell_type":"code","source":"layer_name = 'top_conv'\n\nimage_names = list(val_merged[(val_merged.target_x==0)&(val_merged.target_y>=0.5)].image_name)\nprint(\"Total Images: \",len(image_names))\n\nif len(image_name)!=0:\n    \n    r, c = 5, 5\n\n    r, c = min(int(np.ceil(len(image_names)/5)),5), 5\n    if r==1:\n        r=2\n\n    fig, ax = plt.subplots(r,c,figsize=(c*4*2,r*6))\n\n    # fig.suptitle(f'GridCAMs of layer: {layer_name} of train images',fontsize=15)\n\n    explainer = GradCAM()\n\n    i = 0\n\n    for image_name in np.random.choice(image_names,replace=False,size=min(r*c,len(image_names))):\n\n        prediction = val_merged[val_merged.image_name==image_name]['target_y'].values[0]\n        actual = val_merged[val_merged.image_name==image_name]['target_x'].values[0]\n\n        color = 'green' if int(prediction>=0.5)==actual else 'red'\n\n        title = f'Image Name: {image_name}\\nActual: {actual}\\nPrediction: {prediction}'\n\n        image = getImage(image_name)\n\n        heatmap1 = explainer.explain(([image/255.0], None), model, layer_name = layer_name, class_index=0)\n\n        heatmap2, output = overlay_heatmap(heatmap1,image)\n\n        output = np.hstack([image,output])\n\n        ax[i//c,i%c].imshow(output)\n        ax[i//c,i%c].axis('off')\n        ax[i//c,i%c].set_title(title,fontsize=15,color=color)\n\n        i += 1","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"### GridCAMs of Testset Images","execution_count":null},{"metadata":{"trusted":true},"cell_type":"code","source":"image_names = test_pred_mean.image_name.values\n\nr, c = min(int(np.ceil(len(image_names)/R)),R), C\n    \nif r==1:\n    r=2\n\nfig, ax = plt.subplots(r,c,figsize=(c*4*2,r*6))\n\nlayer_name = 'top_conv'\n\n# fig.suptitle(f'GridCAMs of layer: {layer_name} of train images',fontsize=15)\n\nexplainer = GradCAM()\n\ni = 0\n\nfor image_name in np.random.choice(image_names,replace=False,size=min(r*c,len(image_names))):\n\n    prediction = test_pred_mean[test_pred_mean.image_name==image_name]['target'].values[0]\n    rank = test_pred_rank[test_pred_rank.image_name==image_name]['target'].values[0]\n\n    title = f'Image Name: {image_name}\\nRank: {rank}\\nPrediction: {prediction}'\n\n    image = getImage(image_name,train=False)\n\n    heatmap1 = explainer.explain(([image/255.0], None), model, layer_name = layer_name, class_index=0)\n\n    heatmap2, output = overlay_heatmap(heatmap1,image)\n\n    output = np.hstack([image,output])\n\n    ax[i//c,i%c].imshow(output)\n    ax[i//c,i%c].axis('off')\n    ax[i//c,i%c].set_title(title,fontsize=15)\n\n    i += 1","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"## 💡 Key Takeaways\n\n---\n\n* We can see for many images **Hairs** are influencing the prediction.\n* Model is focusing on **Dark Corners** in the images. *(Maybe cropping the image(random or center) will help the model to focus on central region more)*","execution_count":null},{"metadata":{},"cell_type":"markdown","source":"## Helpful Resources\n\n---\n\n* [tf-explain docs](https://tf-explain.readthedocs.io/en/latest/)\n* [Demystifying Convolutional Neural Networks using GradCam](https://towardsdatascience.com/demystifying-convolutional-neural-networks-using-gradcam-554a85dd4e48)\n* [Grad-CAM class activation visualization | keras.io](https://keras.io/examples/vision/grad_cam/)\n* [Grad-CAM: Visualize class activation maps with Keras, TensorFlow, and Deep Learning](https://www.pyimagesearch.com/2020/03/09/grad-cam-visualize-class-activation-maps-with-keras-tensorflow-and-deep-learning/)\n* [Introducing tf-explain, Interpretability for TensorFlow 2.0](https://www.sicara.ai/blog/2019-07-31-tf-explain-interpretability-tensorflow)\n* [Interpreting Tensorflow models with tf-explain](https://gilberttanner.com/blog/interpreting-tensorflow-model-with-tf-explain)","execution_count":null},{"metadata":{},"cell_type":"markdown","source":"### If you observe something useful, please mention it in the comment section!\n*(I have used 0.5 as the threshold value to decide TP,FP,TN,FN. Which is not the ideal way as the evaluation metric is AUC)*\n\n<font size=5 color='red'>Please Upvote, If you find it useful!!</font>","execution_count":null}],"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}