CAM: Class Activation Maps
def generate_cam(input_model, image, layer_name='block5_conv3', H=224, W=224):
cls = np.argmax(input_model.predict(image)) # Obtain the predicted class
conv_output = input_model.get_layer(layer_name).output # Get the weights of the last output layer
last_conv_layer_model = keras.Model(input_model.inputs, conv_output) # Create a model with the last output layer
class_weights = input_model.get_layer(layer_name).get_weights()[0] # Get the weights of the output layer
class_weights = class_weights[0,:,:,:]
class_weights = np.mean(class_weights, axis=(0, 1))
last_conv_output = last_conv_layer_model.predict(image) # The feature map output from last output layer
last_conv_output = last_conv_output[0, :]
cam = np.dot(last_conv_output, class_weights)
cam = zoom(cam, H/cam.shape[0]) # Spatial Interpolation/zooming to image size
cam = cam / np.max(cam) # Normalizing the gradcam
return cam
Grad-CAM
def grad_cam(input_model, image, layer_name='block5_conv3', H=224, W=224):
cls = np.argmax(input_model.predict(image)) # Get the predicted class
y_c = input_model.output[0, cls] # Probability Score
conv_output = input_model.get_layer(layer_name).output #Tensor of the last layer of cnn
grads = K.gradients(y_c, conv_output)[0] # Gradients of the predicted class wrt conv_output layer
get_output = K.function([input_model.input], [conv_output, grads])
output, grads_val = get_output([image]) # Gives output of image till conv_output layer and the gradient values at that level
output, grads_val = output[0, :], grads_val[0, :, :, :]
weights = np.mean(grads_val, axis=(0, 1)) # Mean of gradients which acts as our weights
cam = np.dot(output, weights) #Grad-CAM output
cam = np.maximum(cam, 0) # Applying Relu
cam = zoom(cam,H/cam.shape[0]) # Spatial Interpolation/zooming to image size
cam = cam / cam.max() # Normalizing the gradcam
return cam
Grad-CAM++
def grad_cam_plus(input_model, image, layer_name='block5_conv3',H=224, W=224):
cls = np.argmax(input_model.predict(image))
y_c = input_model.output[0, cls]
conv_output = input_model.get_layer(layer_name).output
grads = K.gradients(y_c, conv_output)[0]
first = K.exp(y_c)*grads # Variables used to calculate first second and third gradients
second = K.exp(y_c)*grads*grads
third = K.exp(y_c)*grads*grads*grads
# Gradient calculation
get_output = K.function([input_model.input], [y_c,first,second,third, conv_output, grads])
y_c, conv_first_grad, conv_second_grad,conv_third_grad, conv_output, grads_val = get_output([img])
global_sum = np.sum(conv_output[0].reshape((-1,conv_first_grad[0].shape[2])), axis=0)
# Used to calculate the alpha values for each spatial location
alpha_num = conv_second_grad[0]
alpha_denom = conv_second_grad[0]*2.0 + conv_third_grad[0]*global_sum.reshape((1,1,conv_first_grad[0].shape[2]))
alpha_denom = np.where(alpha_denom != 0.0, alpha_denom, np.ones(alpha_denom.shape))
alphas = alpha_num/alpha_denom
# Calculating the weights and alpha's which is the scale at which we multiply the weights with more importance
weights = np.maximum(conv_first_grad[0], 0.0)
alpha_normalization_constant = np.sum(np.sum(alphas, axis=0),axis=0)
alphas /= alpha_normalization_constant.reshape((1,1,conv_first_grad[0].shape[2])) # Normalizing alpha
# Weights with alpha multiplied to get spatial importance
deep_linearization_weights = np.sum((weights*alphas).reshape((-1,conv_first_grad[0].shape[2])),axis=0)
grad_CAM_map = np.sum(deep_linearization_weights*conv_output[0], axis=2) # Grad-CAM++ map
cam = np.maximum(grad_CAM_map, 0)
cam = zoom(cam,H/cam.shape[0])
cam = cam / np.max(cam)
return cam
Reference