File size: 6,713 Bytes
b059e33
 
 
 
 
 
7cfb8be
 
080f6e6
b059e33
509b38e
 
 
 
 
 
 
8849d6d
 
384c3f4
0afb7f8
384c3f4
8849d6d
384c3f4
8849d6d
b059e33
 
2f37c1e
b059e33
 
3618416
b059e33
 
2f37c1e
b059e33
 
2f37c1e
 
 
 
 
b059e33
2f37c1e
b059e33
 
 
 
 
 
b23a511
 
 
 
 
 
 
 
2f37c1e
 
 
 
 
 
 
b059e33
bafae09
2f37c1e
bafae09
 
b059e33
 
2f37c1e
 
 
 
b059e33
 
 
 
 
 
 
 
 
 
 
f7bf704
 
b059e33
 
 
2f37c1e
 
c0d6d2f
b059e33
 
 
 
 
 
 
 
 
 
 
384c3f4
b059e33
 
 
 
12925a0
b059e33
 
 
2f37c1e
384c3f4
2f37c1e
b059e33
fe1c53b
2f37c1e
 
b059e33
384c3f4
b059e33
 
 
384c3f4
 
 
2f37c1e
 
 
 
 
698782a
2f37c1e
 
3576575
2f37c1e
9b0db10
b059e33
4c8eb7e
384c3f4
3576575
384c3f4
2f37c1e
 
 
fe1c53b
2f37c1e
bfd4996
4c8eb7e
0c7cb71
 
84adb48
5ffe7a9
88531d4
be2c21d
 
0c7cb71
 
 
 
 
 
 
 
 
 
 
 
 
 
 
b61f228
b059e33
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
import tensorflow as tf
import numpy as np
from tensorflow import keras
from keras.layers import Input, Lambda, Dense, Flatten, Rescaling
from keras.models import Model
import PIL
from PIL import Image
import gradio as gr
import matplotlib.cm as cm

base_model = keras.applications.Xception(
    # weights = "../input/xception/xception_weights_tf_dim_ordering_tf_kernels_notop.h5",
    input_shape = (160,160,3),
    include_top = False,)

base_model.trainable = False


def img_pros(img):
  original_img = tf.keras.preprocessing.image.img_to_array(img)
  original_img_shape = original_img.shape
  img = tf.image.resize(original_img, [160,160])
  img = tf.expand_dims(img, axis = 0)
  return img, original_img, original_img_shape

#function for creating model
#returns model, its inputs, Xception's last conv output, the whole model's outputs
def create_model_mod(classes, activation):
    inputs = keras.Input(shape = (160,160,3))
    #normalizing pixel values
    r = Rescaling(scale = 1./255)(inputs)
    x = base_model(r, training = False)
    gap = keras.layers.GlobalAveragePooling2D()(x)
    outputs = keras.layers.Dense(classes ,activation = activation)(gap)
    model = keras.Model(inputs, outputs)
    
    if activation == "linear":
        loss_s = keras.losses.BinaryCrossentropy(from_logits = True)
    else:
        loss_s = keras.losses.BinaryCrossentropy()
    
    model.compile(
    loss = loss_s,
    optimizer = keras.optimizers.Adam(0.001),
    metrics = ["accuracy"]
    )
    
    return model, inputs, x, outputs


#function that creates a gradcam model and returns it
def create_grad_model(weights, classes, activation):
    model_mod, input, x, output = create_model_mod(classes, activation)
    #lodaing weights of already trained model
    model_mod.load_weights(weights)
    grad_model = Model(input, [x, output])
    return grad_model
    
#create heatmaps of the given images
#returns the heatmaps and the raw score of predicted class of each image
def create_heatmap(model, imgs, class_index):
    model.layers[-1].activation = None
    
    #predicting the images and getting the conv outputs and predictions from the gradcam model
    with tf.GradientTape() as tape:
        maps, preds = model(imgs);
    
        # class_channel = tf.expand_dims(preds[:,class_index],axis = 1)
        class_channel = preds[:, class_index]
    
    #computing gradients of predictions w.r.t the feature maps
    if class_index == -1:
        grads = tape.gradient(preds, maps)
    else:
        grads = tape.gradient(class_channel, maps)
    
    # global average pooling of each feature map
    gap_grads = tf.reduce_mean(grads, axis=(0, 1, 2))
    
    #multiplying each pooled value with its correponding feature map
    # maps = maps[0]
    heatmap = maps @ gap_grads[..., tf.newaxis]
    
    #removing the extra dimension of value 1
    heatmap = tf.squeeze(heatmap)
    
    # For visualization purpose, we will normalize the heatmap between 0 & 1
    heatmap = tf.maximum(heatmap, 0) / tf.math.reduce_max(heatmap)
    
    return heatmap, preds.numpy()


#superimpose function buth for a single input image
def superimpose_single(heatmap, img, original_img_shape, alpha = 0.7):
    heatmap = np.uint8(255 * heatmap)
    
    # Use jet colormap to colorize heatmap
    jet = cm.get_cmap("jet")
    
    # Use RGB values of the colormap
    jet_colors = jet(np.arange(256))[:, :3]
    jet_heatmap = jet_colors[heatmap]
    
    # Create an image with RGB colorized heatmap
    jet_heatmap = keras.utils.array_to_img(jet_heatmap)
    jet_heatmap = jet_heatmap.resize((original_img_shape[1], original_img_shape[0]))
    jet_heatmap = keras.utils.img_to_array(jet_heatmap)
    
    # Superimpose the heatmap on original image
    superimposed_img = jet_heatmap * alpha + img
    superimposed_img = keras.utils.array_to_img(superimposed_img)
    
    return superimposed_img

#for generating single gradcam image
def gen_grad_img_single(grad_model, img, class_index, original_img, original_img_shape, alpha = 0.4):
    heatmaps, y_pred = create_heatmap(grad_model, img, class_index)
    
    # for i in range(len(y_pred)):
    #     if y_pred[i] > 0.5: y_pred[i] = 1
    #     else: y_pred[i] = 0
    
    img = superimpose_single(heatmaps, original_img, original_img_shape)
    return np.array(img).astype('uint8'), y_pred


def gen_grad_both(grad_model, img, original_img, original_img_shape):
    img_c, y_pred_c = gen_grad_img_single(grad_model, img, 0, original_img, original_img_shape)
    img_d, y_pred_d = gen_grad_img_single(grad_model, img, 1, original_img, original_img_shape)
    y_pred_c = np.around(y_pred_c,3)
    y_pred_d = np.around(y_pred_d,3)
    # show_imgs([img_c, img_d], [y_true, y_true], [size[0], size[1]], cols, [y_pred_c, y_pred_d], font_size = font_size)
    
    infer = ""
    if y_pred_c[0][0] > y_pred_c[0][1]: infer = "cat"
    else: infer = "dog"
        
    return img_c, img_d, y_pred_c, infer

weights = "weights_nm.h5"

def get_grad(img):
    img, original_img, original_img_shape = img_pros(img)
    grad_model = create_grad_model(weights, 2, "softmax")
    grad_img_c, grad_img_d, y_pred, infer = gen_grad_both(grad_model, img, original_img, original_img_shape)
    # pred_class = ""
    # if y_pred[0] > 0.5: pred_class = "cat"
    # else: pred_class = "dog"
        
    text = "Raw Score: " + str(y_pred[0]) + "\nClassification: " + infer
    return grad_img_c, grad_img_d, text

demo = gr.Interface(
    fn = get_grad,
    # inputs = gr.Image(type = "pil", shape = (224,224)),
    inputs = gr.Image(type = "pil"),
    outputs = [gr.Image(type = "numpy", width = 640, height = 320, label = "Grad_CAM w.r.t cat"), gr.Image(type = "numpy", width = 640, height = 320, label = "Grad_CAM w.r.t dog"), gr.Textbox(label = 'Prediction', info = '[P of cat, P of dog]')], 
    description = "Visual Explanations from Deep Networks",
    title = "Gradient-Weighted Class Activation Mapping (Grad-CAM)"
)

# with gr.Blocks() as demo:
#     gr.Markdown(
#     "# Gradient-Weighted Class Activation Mapping (Grad-CAM)\nVisual Explanations from Deep Networks"
#     )
    
#     with gr.Row().style(equal_height=True):
#         img_input = gr.Image(type = "pil", shape = (224,224), width = 320, height = 320)
#         img_output1 = gr.Image(type = "numpy", width = 320, height = 320, label = "Grad_CAM w.r.t cat")
#         img_output2 = gr.Image(type = "numpy", width = 320, height = 320, label = "Grad_CAM w.r.t dog")

#     description = "Visual Explanations from Deep Networks",
#     title = "Gradient-Weighted Class Activation Mapping (Grad-CAM)"
#     img_input.upload(get_grad, inputs = img_input, outputs = [img_output1, img_output2])

demo.launch()