{"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":"code","source":"# This Python 3 environment comes with many helpful analytics libraries installed\n# It is defined by the kaggle/python Docker image: https://github.com/kaggle/docker-python\n# For example, here's several helpful packages to load\n\nimport numpy as np # linear algebra\nimport pandas as pd # data processing, CSV file I/O (e.g. pd.read_csv)\n\n# Input data files are available in the read-only \"../input/\" directory\n# For example, running this (by clicking run or pressing Shift+Enter) will list all files under the input directory\n\nimport os\nfor dirname, _, filenames in os.walk('/kaggle/input'):\n    for filename in filenames:\n        print(os.path.join(dirname, filename))\n\n# You can write up to 20GB to the current directory (/kaggle/working/) that gets preserved as output when you create a version using \"Save & Run All\" \n# You can also write temporary files to /kaggle/temp/, but they won't be saved outside of the current session","metadata":{"_cell_guid":"b1076dfc-b9ad-4769-8c92-a6c4dae69d19","_uuid":"8f2839f25d086af736a60e9eeb907d3b93b6e0e5","papermill":{"duration":0.057766,"end_time":"2022-05-03T07:34:36.648279","exception":false,"start_time":"2022-05-03T07:34:36.590513","status":"completed"},"tags":[],"execution":{"iopub.status.busy":"2022-05-31T05:49:02.331842Z","iopub.execute_input":"2022-05-31T05:49:02.332249Z","iopub.status.idle":"2022-05-31T05:49:02.344845Z","shell.execute_reply.started":"2022-05-31T05:49:02.332214Z","shell.execute_reply":"2022-05-31T05:49:02.344059Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# 1 <b><span style=\"color:#27aee3; font-weight:1200\">|</span> Required Libraries","metadata":{"papermill":{"duration":0.037712,"end_time":"2022-05-03T07:34:36.802273","exception":false,"start_time":"2022-05-03T07:34:36.764561","status":"completed"},"tags":[]}},{"cell_type":"code","source":"import matplotlib.pyplot as plt\nimport seaborn as sns\n%matplotlib inline\nfrom collections import Counter\n\nimport scipy as sp\n\nimport warnings\nwarnings.filterwarnings('ignore')\n\nimport tensorflow as tf\nfrom tensorflow import keras\nfrom keras.models import Sequential, Model\nfrom keras.layers import Dense, Conv2D, Dropout, BatchNormalization, Flatten, MaxPooling2D, GlobalAveragePooling2D\nfrom keras.preprocessing.image import ImageDataGenerator\nfrom keras.callbacks import ModelCheckpoint, LearningRateScheduler\nfrom keras import regularizers\nfrom tensorflow.keras.utils import to_categorical\nfrom tensorflow.keras.preprocessing.image import ImageDataGenerator","metadata":{"papermill":{"duration":5.831388,"end_time":"2022-05-03T07:34:42.671441","exception":false,"start_time":"2022-05-03T07:34:36.840053","status":"completed"},"tags":[],"execution":{"iopub.status.busy":"2022-05-31T06:13:13.715968Z","iopub.execute_input":"2022-05-31T06:13:13.716302Z","iopub.status.idle":"2022-05-31T06:13:13.728772Z","shell.execute_reply.started":"2022-05-31T06:13:13.716274Z","shell.execute_reply":"2022-05-31T06:13:13.727846Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# 2 <b><span style=\"color:#27aee3; font-weight:1200\">|</span> Data","metadata":{"papermill":{"duration":0.038927,"end_time":"2022-05-03T07:34:42.751204","exception":false,"start_time":"2022-05-03T07:34:42.712277","status":"completed"},"tags":[]}},{"cell_type":"code","source":"train = pd.read_csv('../input/digit-recognizer/train.csv')\n\nprint(f'{train.shape}\\n')\ntrain.head()","metadata":{"papermill":{"duration":3.335942,"end_time":"2022-05-03T07:34:46.125154","exception":false,"start_time":"2022-05-03T07:34:42.789212","status":"completed"},"tags":[],"execution":{"iopub.status.busy":"2022-05-31T05:49:02.382869Z","iopub.execute_input":"2022-05-31T05:49:02.383187Z","iopub.status.idle":"2022-05-31T05:49:05.664553Z","shell.execute_reply.started":"2022-05-31T05:49:02.383154Z","shell.execute_reply":"2022-05-31T05:49:05.663160Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"test = pd.read_csv('../input/digit-recognizer/test.csv')\n\nprint(f'{test.shape}\\n')\ntest.head()","metadata":{"papermill":{"duration":1.806562,"end_time":"2022-05-03T07:34:47.971606","exception":false,"start_time":"2022-05-03T07:34:46.165044","status":"completed"},"tags":[],"execution":{"iopub.status.busy":"2022-05-31T05:49:05.667269Z","iopub.execute_input":"2022-05-31T05:49:05.667581Z","iopub.status.idle":"2022-05-31T05:49:07.807919Z","shell.execute_reply.started":"2022-05-31T05:49:05.667531Z","shell.execute_reply":"2022-05-31T05:49:07.806835Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# 3 <b><span style=\"color:#27aee3; font-weight:1200\">|</span> Data Preprocessing","metadata":{"papermill":{"duration":0.042991,"end_time":"2022-05-03T07:34:48.878663","exception":false,"start_time":"2022-05-03T07:34:48.835672","status":"completed"},"tags":[]}},{"cell_type":"code","source":"x_train = train.values[:, 1:] # get all values from 1st index onwards\ny_train = train.values[:, 0]  # get the label column\n\nx_test = test.values[:, 0:]   # get all values starting from 0th index\n\ndel train # delete train and test set to free up memory\ndel test ","metadata":{"papermill":{"duration":0.048826,"end_time":"2022-05-03T07:34:48.969863","exception":false,"start_time":"2022-05-03T07:34:48.921037","status":"completed"},"tags":[],"execution":{"iopub.status.busy":"2022-05-31T05:49:07.808984Z","iopub.execute_input":"2022-05-31T05:49:07.809209Z","iopub.status.idle":"2022-05-31T05:49:07.816836Z","shell.execute_reply.started":"2022-05-31T05:49:07.809181Z","shell.execute_reply":"2022-05-31T05:49:07.814626Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"### <b><span style=\"color:#27aee3; font-weight:1200\">※</span> Some of the training set contents<br/>","metadata":{"papermill":{"duration":0.041992,"end_time":"2022-05-03T07:34:49.053708","exception":false,"start_time":"2022-05-03T07:34:49.011716","status":"completed"},"tags":[]}},{"cell_type":"code","source":"fig = plt.figure(figsize=[14, 10])\n\nfor i in range(16):\n    ax = fig.add_subplot(4 , 4, i + 1, xticks=[], yticks=[])\n    ax.imshow(x_train[i].reshape((28,28)))\n    ax.set_title(str(y_train[i]))","metadata":{"papermill":{"duration":0.687705,"end_time":"2022-05-03T07:34:49.783317","exception":false,"start_time":"2022-05-03T07:34:49.095612","status":"completed"},"tags":[],"execution":{"iopub.status.busy":"2022-05-31T05:49:07.820313Z","iopub.execute_input":"2022-05-31T05:49:07.820679Z","iopub.status.idle":"2022-05-31T05:49:08.492808Z","shell.execute_reply.started":"2022-05-31T05:49:07.820639Z","shell.execute_reply":"2022-05-31T05:49:08.491163Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"### <b><span style=\"color:#27aee3; font-weight:1200\">※</span> Normalizing the pixel values","metadata":{"papermill":{"duration":0.042807,"end_time":"2022-05-03T07:34:49.869841","exception":false,"start_time":"2022-05-03T07:34:49.827034","status":"completed"},"tags":[]}},{"cell_type":"code","source":"mean = np.mean(x_train) # take the mean\nstd = np.std(x_train)   # take the standard deviation\nx_train = (x_train-mean)/(std+1e-7)    # normalizing the values\nx_test = (x_test-mean)/(std+1e-7)\n\nx_train = x_train.reshape(-1, 28, 28, 1) # reshaping them\nx_test = x_test.reshape(-1, 28, 28, 1)\n\ny_train","metadata":{"papermill":{"duration":0.467418,"end_time":"2022-05-03T07:34:50.379849","exception":false,"start_time":"2022-05-03T07:34:49.912431","status":"completed"},"tags":[],"execution":{"iopub.status.busy":"2022-05-31T05:49:08.495374Z","iopub.execute_input":"2022-05-31T05:49:08.495798Z","iopub.status.idle":"2022-05-31T05:49:08.829164Z","shell.execute_reply.started":"2022-05-31T05:49:08.495756Z","shell.execute_reply":"2022-05-31T05:49:08.827744Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"plt.imshow(x_train[2])","metadata":{"papermill":{"duration":0.290254,"end_time":"2022-05-03T07:34:50.756405","exception":false,"start_time":"2022-05-03T07:34:50.466151","status":"completed"},"tags":[],"execution":{"iopub.status.busy":"2022-05-31T05:49:08.831121Z","iopub.execute_input":"2022-05-31T05:49:08.831419Z","iopub.status.idle":"2022-05-31T05:49:08.996231Z","shell.execute_reply.started":"2022-05-31T05:49:08.831388Z","shell.execute_reply":"2022-05-31T05:49:08.994799Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"y_train[2]","metadata":{"papermill":{"duration":0.087453,"end_time":"2022-05-03T07:34:50.92226","exception":false,"start_time":"2022-05-03T07:34:50.834807","status":"completed"},"tags":[],"execution":{"iopub.status.busy":"2022-05-31T05:49:08.998014Z","iopub.execute_input":"2022-05-31T05:49:08.998399Z","iopub.status.idle":"2022-05-31T05:49:09.005923Z","shell.execute_reply.started":"2022-05-31T05:49:08.998359Z","shell.execute_reply":"2022-05-31T05:49:09.004919Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"num_classes = 10\n\ny_train = to_categorical(y_train, num_classes=num_classes)\n\nx_train, x_val = x_train[:37000], x_train[37000:]\ny_train, y_val = y_train[:37000], y_train[37000:]\n\nprint(f'Training samples: {x_train.shape}\\nValidation samples: {x_val.shape}\\nTesting samples: {x_test.shape}')","metadata":{"papermill":{"duration":0.054372,"end_time":"2022-05-03T07:34:51.146067","exception":false,"start_time":"2022-05-03T07:34:51.091695","status":"completed"},"tags":[],"execution":{"iopub.status.busy":"2022-05-31T05:49:09.007379Z","iopub.execute_input":"2022-05-31T05:49:09.007724Z","iopub.status.idle":"2022-05-31T05:49:09.022979Z","shell.execute_reply.started":"2022-05-31T05:49:09.007693Z","shell.execute_reply":"2022-05-31T05:49:09.022313Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# 4 <b><span style=\"color:#27aee3; font-weight:1200\">|</span> CNN Model","metadata":{"papermill":{"duration":0.046547,"end_time":"2022-05-03T07:34:51.652757","exception":false,"start_time":"2022-05-03T07:34:51.60621","status":"completed"},"tags":[]}},{"cell_type":"code","source":"model = Sequential()\n\n# notice the padding parameter to recover the lost border pixels when doing the convolution\nmodel.add(Conv2D(16,input_shape=(28,28,1),kernel_size=(3,3),activation='relu',padding='same'))\n# pooling layer with a stride of 2 will reduce the image dimensions by half\nmodel.add(MaxPooling2D(pool_size=(2,2)))\n\n# pass through more convolutions with increasing filters\nmodel.add(Conv2D(32,kernel_size=(3,3),activation='relu',padding='same'))\nmodel.add(MaxPooling2D(pool_size=(2,2)))\n\nmodel.add(Conv2D(64,kernel_size=(3,3),activation='relu',padding='same'))\nmodel.add(MaxPooling2D(pool_size=(2,2)))\n\nmodel.add(Conv2D(128,kernel_size=(3,3),activation='relu',padding='same'))\n\n# use global average pooling to take into account lesser intensity pixels\nmodel.add(GlobalAveragePooling2D())\n\n# output class probabilities\nmodel.add(Dense(10,activation='softmax'))\n\nmodel.summary()\n\nmodel.compile(optimizer='adam', loss='categorical_crossentropy', metrics=['accuracy'])","metadata":{"papermill":{"duration":3.436329,"end_time":"2022-05-03T07:34:55.317753","exception":false,"start_time":"2022-05-03T07:34:51.881424","status":"completed"},"tags":[],"execution":{"iopub.status.busy":"2022-05-31T05:51:11.045203Z","iopub.execute_input":"2022-05-31T05:51:11.045453Z","iopub.status.idle":"2022-05-31T05:51:11.123716Z","shell.execute_reply.started":"2022-05-31T05:51:11.045428Z","shell.execute_reply":"2022-05-31T05:51:11.123073Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# 5 <b><span style=\"color:#27aee3; font-weight:1200\">|</span> Data Augmentation","metadata":{"papermill":{"duration":0.046288,"end_time":"2022-05-03T07:34:55.412609","exception":false,"start_time":"2022-05-03T07:34:55.366321","status":"completed"},"tags":[]}},{"cell_type":"code","source":"datagen = ImageDataGenerator(\n                rotation_range=10,  \n                zoom_range = 0.10,  \n                width_shift_range=0.1, \n                height_shift_range=0.1\n)\n\naug = datagen.flow(x_train[6].reshape(-1, 28, 28, 1))\n\nfig = plt.figure(figsize=[10, 8])\nfor i in range(24):\n    \n    ax = fig.add_subplot(3, 8, i+1, xticks=[], yticks=[])\n    aug_img = next(aug)[0]\n    ax.imshow(aug_img, cmap = 'gray')\n    \nplt.show()","metadata":{"papermill":{"duration":0.791497,"end_time":"2022-05-03T07:34:56.344596","exception":false,"start_time":"2022-05-03T07:34:55.553099","status":"completed"},"tags":[],"execution":{"iopub.status.busy":"2022-05-31T05:51:14.787739Z","iopub.execute_input":"2022-05-31T05:51:14.788814Z","iopub.status.idle":"2022-05-31T05:51:15.541159Z","shell.execute_reply.started":"2022-05-31T05:51:14.788755Z","shell.execute_reply":"2022-05-31T05:51:15.540288Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# 6 <b><span style=\"color:#27aee3; font-weight:1200\">|</span> Network Training","metadata":{"papermill":{"duration":0.048146,"end_time":"2022-05-03T07:34:56.44247","exception":false,"start_time":"2022-05-03T07:34:56.394324","status":"completed"},"tags":[]}},{"cell_type":"markdown","source":"LearningRateScheduler is used to update the learning rate with each new epoch.","metadata":{"papermill":{"duration":0.047964,"end_time":"2022-05-03T07:34:56.538606","exception":false,"start_time":"2022-05-03T07:34:56.490642","status":"completed"},"tags":[]}},{"cell_type":"code","source":"annealer = LearningRateScheduler(lambda x: 1e-3 * 0.95 ** x)\nepochs = 10\nbatch_size = 64\nhist = model.fit(\n    datagen.flow(x_train, y_train, batch_size=batch_size), \n    epochs = epochs,\n    steps_per_epoch=x_train.shape[0] // batch_size,\n    validation_data = (x_val, y_val),\n    callbacks = [annealer],\n    verbose = 1)","metadata":{"papermill":{"duration":2705.424984,"end_time":"2022-05-03T08:20:02.01201","exception":false,"start_time":"2022-05-03T07:34:56.587026","status":"completed"},"tags":[],"execution":{"iopub.status.busy":"2022-05-31T05:51:18.156042Z","iopub.execute_input":"2022-05-31T05:51:18.156772Z","iopub.status.idle":"2022-05-31T05:55:42.058504Z","shell.execute_reply.started":"2022-05-31T05:51:18.156736Z","shell.execute_reply":"2022-05-31T05:55:42.056767Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# 7 <b><span style=\"color:#27aee3; font-weight:1200\">|</span> Class Activation Map (CAM)\n    \n    \nClass Activation Map is a matrix that shows what parts of the image the model was paying more or less attention to. <br/> <br/>\n    \n<center><img src='https://res.cloudinary.com/vincent1bt/image/upload/c_scale,w_752/v1559767859/x-bone_ovdahr.jpg'></img></center>\n\n<br/>\n\n- The more intense colors signify the most attention given by the model; while\n- The darker ones signify less attention.\n\nNow, to generate the class activation maps, we need to get the features detected in the last convolutional layer and then see which ones are most active when generating the output probabilities.\n\nSo, we'll take the following ones:","metadata":{}},{"cell_type":"code","source":"print(\"The last layers:\\n\")\nfor i in model.layers[-3:]:\n    print(str(i).split('.')[3])","metadata":{"execution":{"iopub.status.busy":"2022-05-31T06:00:46.394031Z","iopub.execute_input":"2022-05-31T06:00:46.394562Z","iopub.status.idle":"2022-05-31T06:00:46.400964Z","shell.execute_reply.started":"2022-05-31T06:00:46.394528Z","shell.execute_reply":"2022-05-31T06:00:46.400338Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"Now, we can create our _**CAM** model_. Remember not to include the *GlobalAveragePooling2D* layer as it does nothing extra except squeezing the spatial dimension.\n\nSo, we create a new model using **Model** and pass in the model input and the output of the **Conv2D** and **Dense** layers.","metadata":{}},{"cell_type":"code","source":"cam_model = Model(inputs=model.input, \n                 outputs=(model.layers[-3].output,\n                         model.layers[-1].output))\ncam_model.summary()","metadata":{"execution":{"iopub.status.busy":"2022-05-31T06:07:14.181591Z","iopub.execute_input":"2022-05-31T06:07:14.182249Z","iopub.status.idle":"2022-05-31T06:07:14.196264Z","shell.execute_reply.started":"2022-05-31T06:07:14.182210Z","shell.execute_reply":"2022-05-31T06:07:14.194651Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"Now, use that **CAM** model to predict on the test set to generate the features and predicted prob for each class.","metadata":{}},{"cell_type":"code","source":"feats,res = cam_model.predict(x_test)\n\n# shape of the features\nprint(\"features shape: \", feats.shape)\nprint(\"results shape\", res.shape)","metadata":{"execution":{"iopub.status.busy":"2022-05-31T06:07:37.995223Z","iopub.execute_input":"2022-05-31T06:07:37.995482Z","iopub.status.idle":"2022-05-31T06:07:44.276418Z","shell.execute_reply.started":"2022-05-31T06:07:37.995455Z","shell.execute_reply":"2022-05-31T06:07:44.275190Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"### <b><span style=\"color:#27aee3; font-weight:1200\">※</span> Generating CAM by dot product of class activation feats and weights\n    \n    \nTo generate CAM, we need to do the dot product of the class activation features and the class activation weights.\n\nWe'll need the weights from the Global Average Pooling layer (GAP) to calculate the activations of each feature given a particular class.\n    \nAlso, keep in mind that we'll get the weights from the dense layer that follows the global average pooling layer. To understand how, see the below points:\n    \n- The last conv2D layer has (h,w,depth) of (3 x 3 x 128), so there are 128 features.\n- The global average pooling layer collapses the (h,w,depth) of (3 x 3 x 128) into a dense layer of 128 neurons (1 neuron per feature).\n- The activations from the global average pooling layer get passed to the last dense layer.\n- The last dense layer assigns weights to each of those 128 features (for each of the 10 classes),\n- So the weights of the last dense layer (which immmediately follows the global average pooling layer) are referred to in this context as the **\"weights of the global average pooling layer\"**.","metadata":{}},{"cell_type":"code","source":"last_layer = model.layers[-1]\n\ngap_weights_lst = last_layer.get_weights()\nprint(f'{gap_weights_lst[0].shape}\\n{gap_weights_lst[1].shape}')\n\ngap_weights = gap_weights_lst[0]","metadata":{"execution":{"iopub.status.busy":"2022-05-31T06:56:30.816660Z","iopub.execute_input":"2022-05-31T06:56:30.816994Z","iopub.status.idle":"2022-05-31T06:56:30.827203Z","shell.execute_reply.started":"2022-05-31T06:56:30.816961Z","shell.execute_reply":"2022-05-31T06:56:30.825253Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"Now, choose index of any image.","metadata":{}},{"cell_type":"code","source":"idx = 0\nfeats_img = feats[idx, :,:,:]\nprint(f'The shape of the image at index {idx}: {feats_img.shape}')","metadata":{"execution":{"iopub.status.busy":"2022-05-31T06:58:13.998225Z","iopub.execute_input":"2022-05-31T06:58:13.998544Z","iopub.status.idle":"2022-05-31T06:58:14.016003Z","shell.execute_reply.started":"2022-05-31T06:58:13.998512Z","shell.execute_reply":"2022-05-31T06:58:14.008965Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"Now, the features have height and width of 3 x 3. So, we need to scale them back up to the original image height and width i.e. 28 x 28.\n\nWe'll do it using **scipy** module.","metadata":{}},{"cell_type":"code","source":"feats_img_scaled = sp.ndimage.zoom(feats_img,\n                                  (28/3, 28/3, 1), order=2)\n\nprint(feats_img_scaled.shape)","metadata":{"execution":{"iopub.status.busy":"2022-05-31T06:14:49.474024Z","iopub.execute_input":"2022-05-31T06:14:49.474641Z","iopub.status.idle":"2022-05-31T06:14:49.532357Z","shell.execute_reply.started":"2022-05-31T06:14:49.474601Z","shell.execute_reply":"2022-05-31T06:14:49.531580Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"class_id = 0\ngap_weights_for_one_class = gap_weights[:,class_id]\n\nprint(\"features_for_img_scaled has shape \", feats_img_scaled.shape)\nprint(\"gap_weights_for_one_class has shape \", gap_weights_for_one_class.shape)\n\n# take the dot product between the scaled features and the weights for one class\ncam = np.dot(feats_img_scaled, gap_weights_for_one_class)\n\nprint(\"Class Activation Map shape \", cam.shape)","metadata":{"execution":{"iopub.status.busy":"2022-05-31T06:15:54.220297Z","iopub.execute_input":"2022-05-31T06:15:54.220808Z","iopub.status.idle":"2022-05-31T06:15:54.229031Z","shell.execute_reply.started":"2022-05-31T06:15:54.220766Z","shell.execute_reply":"2022-05-31T06:15:54.227861Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"### <b><span style=\"color:#27aee3; font-weight:1200\">※</span> Class Activation Map Function\n    \nAll the above things can be written down in the below function.","metadata":{}},{"cell_type":"code","source":"def show_cam(image_index):\n\n  # takes the features of the chosen image\n  feats_for_img = feats[image_index,:,:,:]\n\n  # get the class with the highest output probability\n  prediction = np.argmax(res[image_index])\n\n  # get the gap weights at the predicted class\n  class_activation_weights = gap_weights[:, prediction]\n\n  # upsample the features to the image's original size (28 x 28)\n  class_activation_features = sp.ndimage.zoom(feats_for_img, (28/3, 28/3, 1), order=2)\n\n  # compute the intensity of each feature in the CAM\n  cam_output  = np.dot(class_activation_features,class_activation_weights)\n  \n  print('Predicted Class = ' +str(prediction)+ ', Probability = ' + str(res[image_index][prediction]))\n  \n  # show the upsampled image\n  plt.imshow(np.squeeze(x_test[image_index],-1), alpha=0.5)\n  \n  # strongly classified (95% probability) images will be in green, else red\n  if res[image_index][prediction]>0.95:\n    cmap_str = 'Greens'\n  else:\n    cmap_str = 'Reds'\n\n  # overlay the cam output\n  plt.imshow(cam_output, cmap=cmap_str, alpha=0.5)\n\n  # display the image\n  plt.show()","metadata":{"execution":{"iopub.status.busy":"2022-05-31T06:18:09.715743Z","iopub.execute_input":"2022-05-31T06:18:09.716467Z","iopub.status.idle":"2022-05-31T06:18:09.722994Z","shell.execute_reply.started":"2022-05-31T06:18:09.716437Z","shell.execute_reply":"2022-05-31T06:18:09.722415Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"def show_maps(desired_class, num_maps):\n\n    counter = 0\n\n    for i in range(0,10000):\n        # break if we already displayed the specified number of maps\n        if counter == num_maps:\n            break\n\n        # images that match the class will be shown\n        if np.argmax(res[i]) == desired_class:\n            counter += 1\n            show_cam(i)","metadata":{"execution":{"iopub.status.busy":"2022-05-31T06:18:26.978881Z","iopub.execute_input":"2022-05-31T06:18:26.979956Z","iopub.status.idle":"2022-05-31T06:18:26.986984Z","shell.execute_reply.started":"2022-05-31T06:18:26.979873Z","shell.execute_reply":"2022-05-31T06:18:26.985388Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"show_maps(1, 10)","metadata":{"execution":{"iopub.status.busy":"2022-05-31T07:08:23.170313Z","iopub.execute_input":"2022-05-31T07:08:23.171223Z","iopub.status.idle":"2022-05-31T07:08:25.236043Z","shell.execute_reply.started":"2022-05-31T07:08:23.171177Z","shell.execute_reply":"2022-05-31T07:08:25.235039Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"Remember:\n\n- The more intense color pixels signify the most attention given by the model; while\n- The darker ones signify less attention.\n\n### Thanks for reading this! 😄","metadata":{}}]}