Spaces:
Runtime error
Runtime error
jaekookang
commited on
Commit
β’
22001ac
1
Parent(s):
2758be0
first upload
Browse files- .gitignore +6 -0
- README.md +4 -35
- examples/01.jpg +0 -0
- examples/02.jpg +0 -0
- examples/03.jpg +0 -0
- examples/04.jpg +0 -0
- gradio_gradcam.py +80 -0
- reqs.txt +6 -0
- requirements.txt +6 -0
- utils.py +137 -0
.gitignore
ADDED
@@ -0,0 +1,6 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
__pycache__
|
2 |
+
flagged
|
3 |
+
*~
|
4 |
+
*.log
|
5 |
+
*.nohup
|
6 |
+
*.db
|
README.md
CHANGED
@@ -1,37 +1,6 @@
|
|
1 |
-
|
2 |
-
title: Demo Gradcam Imagenet
|
3 |
-
emoji: π
|
4 |
-
colorFrom: blue
|
5 |
-
colorTo: red
|
6 |
-
sdk: gradio
|
7 |
-
app_file: app.py
|
8 |
-
pinned: false
|
9 |
-
---
|
10 |
-
|
11 |
-
# Configuration
|
12 |
-
|
13 |
-
`title`: _string_
|
14 |
-
Display title for the Space
|
15 |
-
|
16 |
-
`emoji`: _string_
|
17 |
-
Space emoji (emoji-only character allowed)
|
18 |
|
19 |
-
`
|
20 |
-
Color for Thumbnail gradient (red, yellow, green, blue, indigo, purple, pink, gray)
|
21 |
|
22 |
-
|
23 |
-
|
24 |
-
|
25 |
-
`sdk`: _string_
|
26 |
-
Can be either `gradio` or `streamlit`
|
27 |
-
|
28 |
-
`sdk_version` : _string_
|
29 |
-
Only applicable for `streamlit` SDK.
|
30 |
-
See [doc](https://hf.co/docs/hub/spaces) for more info on supported versions.
|
31 |
-
|
32 |
-
`app_file`: _string_
|
33 |
-
Path to your main application file (which contains either `gradio` or `streamlit` Python code).
|
34 |
-
Path is relative to the root of the repository.
|
35 |
-
|
36 |
-
`pinned`: _boolean_
|
37 |
-
Whether the Space stays on top of your list.
|
|
|
1 |
+
# Grad-CAM visualization demo
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
2 |
|
3 |
+
- This demo is based on `https://keras.io/examples/vision/grad_cam/`
|
|
|
4 |
|
5 |
+
---
|
6 |
+
- 2021-12-18 first created
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
examples/01.jpg
ADDED
examples/02.jpg
ADDED
examples/03.jpg
ADDED
examples/04.jpg
ADDED
gradio_gradcam.py
ADDED
@@ -0,0 +1,80 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
'''
|
2 |
+
Grad-CAM visualization demo
|
3 |
+
|
4 |
+
2021-12-18 first created
|
5 |
+
'''
|
6 |
+
from PIL import Image
|
7 |
+
import matplotlib.pyplot as plt
|
8 |
+
from PIL import Image
|
9 |
+
import os
|
10 |
+
import io
|
11 |
+
from glob import glob
|
12 |
+
from loguru import logger
|
13 |
+
import gradio as gr
|
14 |
+
|
15 |
+
from utils import (get_imagenet_classes, get_xception_model, get_img_4d_array,
|
16 |
+
make_gradcam_heatmap, align_image_with_heatmap)
|
17 |
+
|
18 |
+
# ----- Settings -----
|
19 |
+
GPU_ID = '-1'
|
20 |
+
os.environ['CUDA_VISIBLE_DEVICES'] = GPU_ID
|
21 |
+
|
22 |
+
EXAMPLE_DIR = 'examples'
|
23 |
+
CMAP_CHOICES = ['jet', 'rainbow', 'gist_ncar', 'autumn', 'hot', 'winter', 'hsv']
|
24 |
+
examples = sorted(glob(os.path.join(EXAMPLE_DIR, '*.jpg')))
|
25 |
+
examples = [[image, 'French_bulldog', 0.3, 'jet'] for image in examples]
|
26 |
+
|
27 |
+
# ----- Logging -----
|
28 |
+
logger.add('app.log', mode='a')
|
29 |
+
logger.info('===== APP RESTARTED =====')
|
30 |
+
|
31 |
+
# ----- Model -----
|
32 |
+
model, grad_model, preprocessor, decode_predictions = get_xception_model()
|
33 |
+
idx2lab, lab2idx = get_imagenet_classes()
|
34 |
+
classes = ['none'] + sorted(list(lab2idx.keys()))
|
35 |
+
|
36 |
+
def predict(image_obj, pred_class, alpha, cmap):
|
37 |
+
image_file = image_obj.name
|
38 |
+
logger.info(f'--- image loaded: class={pred_class} | alpha={alpha} | cmap={cmap}')
|
39 |
+
|
40 |
+
img = Image.open(image_file)
|
41 |
+
width = img.size[0]
|
42 |
+
height = img.size[1]
|
43 |
+
|
44 |
+
img_4d_array = get_img_4d_array(image_file)
|
45 |
+
img_4d_array = preprocessor(img_4d_array)
|
46 |
+
|
47 |
+
if pred_class == 'none':
|
48 |
+
pred_idx = None
|
49 |
+
else:
|
50 |
+
pred_idx = lab2idx[pred_class]
|
51 |
+
heatmap = make_gradcam_heatmap(grad_model, img_4d_array, pred_idx=pred_idx)
|
52 |
+
img_pil = align_image_with_heatmap(img_4d_array, heatmap, alpha=0.3, cmap=cmap)
|
53 |
+
img_pil = img_pil.resize((width, height))
|
54 |
+
logger.info('--- Grad-CAM visualized')
|
55 |
+
return img_pil
|
56 |
+
|
57 |
+
iface = gr.Interface(
|
58 |
+
predict,
|
59 |
+
title='Gradient Class Actiavtion Map (Grad-CAM) Visualization Demo',
|
60 |
+
description='Provide an image with image class or just image alone. For all 1000 imagenet classes, see https://gist.github.com/yrevar/942d3a0ac09ec9e5eb3a',
|
61 |
+
inputs=[
|
62 |
+
gr.inputs.Image(label='Input image', type='file'),
|
63 |
+
gr.inputs.Dropdown(label='Predicted class (if "none", predicted class will be used)',
|
64 |
+
choices=classes, default='none', type='value'),
|
65 |
+
gr.inputs.Slider(label='Output image alpha level for heatmap',
|
66 |
+
minimum=0, maximum=1, step=0.1, default=0.4),
|
67 |
+
gr.inputs.Dropdown(label='Grad-CAM heatmap colormap',
|
68 |
+
choices=CMAP_CHOICES, default='jet', type='value'),
|
69 |
+
],
|
70 |
+
outputs=[
|
71 |
+
gr.outputs.Image(label='Output image', type='pil')
|
72 |
+
],
|
73 |
+
examples=examples,
|
74 |
+
enable_queue=True,
|
75 |
+
article='<p style="text-align:center">Based on <a href="https://keras.io/examples/vision/grad_cam/">the example</a> written by <a href="https://twitter.com/fchollet">fchollet</a></p>',
|
76 |
+
)
|
77 |
+
|
78 |
+
|
79 |
+
if __name__ == '__main__':
|
80 |
+
iface.launch(debug=True)
|
reqs.txt
ADDED
@@ -0,0 +1,6 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
matplotlib==3.4.3
|
2 |
+
gradio==2.4.6
|
3 |
+
loguru==0.5.3
|
4 |
+
tensorflow==2.7.0
|
5 |
+
numpy==1.19.5
|
6 |
+
Pillow==8.4.0
|
requirements.txt
ADDED
@@ -0,0 +1,6 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
matplotlib==3.4.3
|
2 |
+
gradio==2.4.6
|
3 |
+
loguru==0.5.3
|
4 |
+
tensorflow==2.7.0
|
5 |
+
numpy==1.19.5
|
6 |
+
Pillow==8.4.0
|
utils.py
ADDED
@@ -0,0 +1,137 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
'''
|
2 |
+
Grad-CAM visualization utilities
|
3 |
+
|
4 |
+
- Based on https://keras.io/examples/vision/grad_cam/
|
5 |
+
|
6 |
+
2021-12-18 first created
|
7 |
+
'''
|
8 |
+
import matplotlib.cm as cm
|
9 |
+
|
10 |
+
import os
|
11 |
+
import re
|
12 |
+
from glob import glob
|
13 |
+
import numpy as np
|
14 |
+
import tensorflow as tf
|
15 |
+
tfk = tf.keras
|
16 |
+
K = tfk.backend
|
17 |
+
|
18 |
+
# Disable GPU for testing
|
19 |
+
os.environ['CUDA_VISIBLE_DEVICES'] = '-1'
|
20 |
+
|
21 |
+
|
22 |
+
def get_imagenet_classes():
|
23 |
+
'''Retrieve all 1000 imagenet classes/labels as dictionaries'''
|
24 |
+
classes = tfk.applications.imagenet_utils.decode_predictions(
|
25 |
+
np.expand_dims(np.arange(1000), 0), top=1000
|
26 |
+
)
|
27 |
+
idx2lab = {cla[2]: cla[1] for cla in classes[0]}
|
28 |
+
lab2idx = {idx2lab[idx]: idx for idx in idx2lab}
|
29 |
+
return idx2lab, lab2idx
|
30 |
+
|
31 |
+
|
32 |
+
def search_by_name(str_part):
|
33 |
+
'''Search imagenet class by partial matching string'''
|
34 |
+
results = [key for key in list(lab2idx.keys()) if re.search(str_part, key)]
|
35 |
+
if len(results) != 0:
|
36 |
+
return [(key, lab2idx[key]) for key in results]
|
37 |
+
else:
|
38 |
+
return []
|
39 |
+
|
40 |
+
|
41 |
+
def get_xception_model():
|
42 |
+
'''Get model to use'''
|
43 |
+
base_model = tfk.applications.xception.Xception
|
44 |
+
preprocessor = tfk.applications.xception.preprocess_input
|
45 |
+
decode_predictions = tfk.applications.xception.decode_predictions
|
46 |
+
last_conv_layer_name = "block14_sepconv2_act"
|
47 |
+
|
48 |
+
model = base_model(weights='imagenet')
|
49 |
+
grad_model = tfk.models.Model(
|
50 |
+
inputs=[model.inputs],
|
51 |
+
outputs=[model.get_layer(last_conv_layer_name).output,
|
52 |
+
model.output]
|
53 |
+
)
|
54 |
+
return model, grad_model, preprocessor, decode_predictions
|
55 |
+
|
56 |
+
|
57 |
+
def get_img_4d_array(image_file, image_size=(299, 299)):
|
58 |
+
'''Load image as 4d array'''
|
59 |
+
img = tfk.preprocessing.image.load_img(
|
60 |
+
image_file, target_size=image_size) # PIL obj
|
61 |
+
img_array = tfk.preprocessing.image.img_to_array(
|
62 |
+
img) # float32 numpy array
|
63 |
+
img_array = np.expand_dims(img_array, axis=0) # 3d -> 4d (1,299,299,3)
|
64 |
+
return img_array
|
65 |
+
|
66 |
+
|
67 |
+
def make_gradcam_heatmap(grad_model, img_array, pred_idx=None):
|
68 |
+
'''Generate heatmap to overlay with
|
69 |
+
- img_array: 4d numpy array
|
70 |
+
- pred_idx: index out of 1000 imagenet classes
|
71 |
+
if None, argmax is chosen from prediction
|
72 |
+
'''
|
73 |
+
# Get gradient of pred class w.r.t. last conv activation
|
74 |
+
with tf.GradientTape() as tape:
|
75 |
+
last_conv_act, preds = grad_model(img_array)
|
76 |
+
if pred_idx == None:
|
77 |
+
pred_idx = tf.argmax(preds[0])
|
78 |
+
class_channel = preds[:, pred_idx] # (1,1000) => (1,)
|
79 |
+
|
80 |
+
# d(class_channel/last_conv_act)
|
81 |
+
grads = tape.gradient(class_channel, last_conv_act)
|
82 |
+
pooled_grads = tf.reduce_mean(grads, axis=(
|
83 |
+
0, 1, 2)) # (1,10,10,2048) => (2048,)
|
84 |
+
|
85 |
+
# (10,10,2048) x (2048,1) => (10,10,1)
|
86 |
+
heatmap = last_conv_act[0] @ pooled_grads[..., tf.newaxis]
|
87 |
+
heatmap = tf.squeeze(heatmap) # (10,10)
|
88 |
+
|
89 |
+
# Normalize heatmap between 0 and 1
|
90 |
+
heatmap = tf.maximum(heatmap, 0) / tf.math.reduce_max(heatmap)
|
91 |
+
return heatmap.numpy()
|
92 |
+
|
93 |
+
|
94 |
+
def align_image_with_heatmap(img_array, heatmap, alpha=0.3, cmap='jet'):
|
95 |
+
'''Align the image with gradcam heatmap
|
96 |
+
- img_array: 4d numpy array
|
97 |
+
- heatmap: output of `def make_gradcam_heatmap()` as 2d numpy array
|
98 |
+
'''
|
99 |
+
img_array = img_array.squeeze() # 4d => 3d
|
100 |
+
|
101 |
+
# Rescale to 0-255 range
|
102 |
+
heatmap_scaled = np.uint8(255 * heatmap)
|
103 |
+
img_array_scaled = np.uint8(255 * img_array)
|
104 |
+
|
105 |
+
colormap = cm.get_cmap(cmap)
|
106 |
+
colors = colormap(np.arange(256))[:, :3] # mapping RGB to heatmap
|
107 |
+
heatmap_colored = colors[heatmap_scaled] # ? still unclear
|
108 |
+
|
109 |
+
# Make RGB colorized heatmap
|
110 |
+
heatmap_colored = (tfk.preprocessing.image.array_to_img(heatmap_colored) # array => PIL
|
111 |
+
.resize((img_array.shape[1], img_array.shape[0])))
|
112 |
+
heatmap_colored = tfk.preprocessing.image.img_to_array(
|
113 |
+
heatmap_colored) # PIL => array
|
114 |
+
|
115 |
+
# Overlay image with heatmap
|
116 |
+
overlaid_img = heatmap_colored * alpha + img_array_scaled
|
117 |
+
overlaid_img = tfk.preprocessing.image.array_to_img(overlaid_img)
|
118 |
+
return overlaid_img
|
119 |
+
|
120 |
+
|
121 |
+
if __name__ == '__main__':
|
122 |
+
# Test GradCAM
|
123 |
+
examples = sorted(glob(os.path.join('examples', '*.jpg')))
|
124 |
+
idx2lab, lab2idx = get_imagenet_classes()
|
125 |
+
|
126 |
+
model, grad_model, preprocessor, decode_predictions = get_xception_model()
|
127 |
+
|
128 |
+
img_4d_array = get_img_4d_array(examples[0])
|
129 |
+
img_4d_array = preprocessor(img_4d_array)
|
130 |
+
|
131 |
+
heatmap = make_gradcam_heatmap(grad_model, img_4d_array, pred_idx=None)
|
132 |
+
|
133 |
+
img_pil = align_image_with_heatmap(
|
134 |
+
img_4d_array, heatmap, alpha=0.3, cmap='jet')
|
135 |
+
|
136 |
+
img_pil.save('test.jpg')
|
137 |
+
print('done')
|