jaekookang commited on
Commit
22001ac
β€’
1 Parent(s): 2758be0

first upload

Browse files
Files changed (10) hide show
  1. .gitignore +6 -0
  2. README.md +4 -35
  3. examples/01.jpg +0 -0
  4. examples/02.jpg +0 -0
  5. examples/03.jpg +0 -0
  6. examples/04.jpg +0 -0
  7. gradio_gradcam.py +80 -0
  8. reqs.txt +6 -0
  9. requirements.txt +6 -0
  10. 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
- `colorFrom`: _string_
20
- Color for Thumbnail gradient (red, yellow, green, blue, indigo, purple, pink, gray)
21
 
22
- `colorTo`: _string_
23
- Color for Thumbnail gradient (red, yellow, green, blue, indigo, purple, pink, gray)
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')