From 30b657129c511f5745e1503b75a9f0adf6b5d46f Mon Sep 17 00:00:00 2001 From: kitamura-felipe Date: Sat, 21 Jul 2018 00:15:08 -0300 Subject: [PATCH 01/10] 3D version of gradCAM 3D implementation of Class activation maps. Activation maximization and Saliency maps are the same as in the original saliency.py --- vis/visualization/saliency3D.py | 254 ++++++++++++++++++++++++++++++++ 1 file changed, 254 insertions(+) create mode 100644 vis/visualization/saliency3D.py diff --git a/vis/visualization/saliency3D.py b/vis/visualization/saliency3D.py new file mode 100644 index 0000000..93ef81b --- /dev/null +++ b/vis/visualization/saliency3D.py @@ -0,0 +1,254 @@ +from __future__ import absolute_import + +import numpy as np +import matplotlib.cm as cm +from scipy.misc import imresize + +from keras.layers.convolutional import _Conv +from keras.layers.pooling import _Pooling1D, _Pooling2D, _Pooling3D +from keras import backend as K + +from ..losses import ActivationMaximization +from ..optimizer import Optimizer +from ..backprop_modifiers import get +from ..utils import utils + +import cv2 + + +def _find_penultimate_layer(model, layer_idx, penultimate_layer_idx): + """Searches for the nearest penultimate `Conv` or `Pooling` layer. + + Args: + model: The `keras.models.Model` instance. + layer_idx: The layer index within `model.layers`. + penultimate_layer_idx: The pre-layer to `layer_idx`. If set to None, the nearest penultimate + `Conv` or `Pooling` layer is used. + + Returns: + The penultimate layer. + """ + if penultimate_layer_idx is None: + for idx, layer in utils.reverse_enumerate(model.layers[:layer_idx - 1]): + if isinstance(layer, (_Conv, _Pooling1D, _Pooling2D, _Pooling3D)): + penultimate_layer_idx = idx + break + + if penultimate_layer_idx is None: + raise ValueError('Unable to determine penultimate `Conv` or `Pooling` ' + 'layer for layer_idx: {}'.format(layer_idx)) + + # Handle negative indexing otherwise the next check can fail. + if layer_idx < 0: + layer_idx = len(model.layers) + layer_idx + if penultimate_layer_idx > layer_idx: + raise ValueError('`penultimate_layer_idx` needs to be before `layer_idx`') + + return model.layers[penultimate_layer_idx] + + +def visualize_saliency_with_losses(input_tensor, losses, seed_input, grad_modifier='absolute'): + """Generates an attention heatmap over the `seed_input` by using positive gradients of `input_tensor` + with respect to weighted `losses`. + + This function is intended for advanced use cases where a custom loss is desired. For common use cases, + refer to `visualize_class_saliency` or `visualize_regression_saliency`. + + For a full description of saliency, see the paper: + [Deep Inside Convolutional Networks: Visualising Image Classification Models and Saliency Maps] + (https://arxiv.org/pdf/1312.6034v2.pdf) + + Args: + input_tensor: An input tensor of shape: `(samples, channels, image_dims...)` if `image_data_format= + channels_first` or `(samples, image_dims..., channels)` if `image_data_format=channels_last`. + losses: List of ([Loss](vis.losses#Loss), weight) tuples. + seed_input: The model input for which activation map needs to be visualized. + grad_modifier: gradient modifier to use. See [grad_modifiers](vis.grad_modifiers.md). By default `absolute` + value of gradients are used. To visualize positive or negative gradients, use `relu` and `negate` + respectively. (Default value = 'absolute') + + Returns: + The heatmap image indicating the `seed_input` regions whose change would most contribute towards minimizing + weighted `losses`. + """ + opt = Optimizer(input_tensor, losses, norm_grads=False) + grads = opt.minimize(seed_input=seed_input, max_iter=1, grad_modifier=grad_modifier, verbose=False)[1] + + channel_idx = 1 if K.image_data_format() == 'channels_first' else -1 + grads = np.max(grads, axis=channel_idx) + + # Normalize and create heatmap. + grads = utils.normalize(grads) + return np.uint8(cm.jet(grads)[..., :3] * 255)[0] + + +def visualize_saliency(model, layer_idx, filter_indices, seed_input, + backprop_modifier=None, grad_modifier='absolute'): + """Generates an attention heatmap over the `seed_input` for maximizing `filter_indices` + output in the given `layer_idx`. + + Args: + model: The `keras.models.Model` instance. The model input shape must be: `(samples, channels, image_dims...)` + if `image_data_format=channels_first` or `(samples, image_dims..., channels)` if + `image_data_format=channels_last`. + layer_idx: The layer index within `model.layers` whose filters needs to be visualized. + filter_indices: filter indices within the layer to be maximized. + If None, all filters are visualized. (Default value = None) + For `keras.layers.Dense` layer, `filter_idx` is interpreted as the output index. + If you are visualizing final `keras.layers.Dense` layer, consider switching 'softmax' activation for + 'linear' using [utils.apply_modifications](vis.utils.utils#apply_modifications) for better results. + seed_input: The model input for which activation map needs to be visualized. + backprop_modifier: backprop modifier to use. See [backprop_modifiers](vis.backprop_modifiers.md). If you don't + specify anything, no backprop modification is applied. (Default value = None) + grad_modifier: gradient modifier to use. See [grad_modifiers](vis.grad_modifiers.md). By default `absolute` + value of gradients are used. To visualize positive or negative gradients, use `relu` and `negate` + respectively. (Default value = 'absolute') + + Example: + If you wanted to visualize attention over 'bird' category, say output index 22 on the + final `keras.layers.Dense` layer, then, `filter_indices = [22]`, `layer = dense_layer`. + + One could also set filter indices to more than one value. For example, `filter_indices = [22, 23]` should + (hopefully) show attention map that corresponds to both 22, 23 output categories. + + Returns: + The heatmap image indicating the `seed_input` regions whose change would most contribute towards + maximizing the output of `filter_indices`. + """ + if backprop_modifier is not None: + modifier_fn = get(backprop_modifier) + model = modifier_fn(model) + + # `ActivationMaximization` loss reduces as outputs get large, hence negative gradients indicate the direction + # for increasing activations. Multiply with -1 so that positive gradients indicate increase instead. + losses = [ + (ActivationMaximization(model.layers[layer_idx], filter_indices), -1) + ] + return visualize_saliency_with_losses(model.input, losses, seed_input, grad_modifier) + + +def visualize_cam_with_losses(input_tensor, losses, + seed_input, penultimate_layer, + grad_modifier=None): + """Generates a gradient based class activation map (CAM) by using positive gradients of `input_tensor` + with respect to weighted `losses`. + + For details on grad-CAM, see the paper: + [Grad-CAM: Why did you say that? Visual Explanations from Deep Networks via Gradient-based Localization] + (https://arxiv.org/pdf/1610.02391v1.pdf). + + Unlike [class activation mapping](https://arxiv.org/pdf/1512.04150v1.pdf), which requires minor changes to + network architecture in some instances, grad-CAM has a more general applicability. + + Compared to saliency maps, grad-CAM is class discriminative; i.e., the 'cat' explanation exclusively highlights + cat regions and not the 'dog' region and vice-versa. + + Args: + input_tensor: An input tensor of shape: `(samples, channels, image_dims...)` if `image_data_format= + channels_first` or `(samples, image_dims..., channels)` if `image_data_format=channels_last`. + losses: List of ([Loss](vis.losses#Loss), weight) tuples. + seed_input: The model input for which activation map needs to be visualized. + penultimate_layer: The pre-layer to `layer_idx` whose feature maps should be used to compute gradients + with respect to filter output. + grad_modifier: gradient modifier to use. See [grad_modifiers](vis.grad_modifiers.md). If you don't + specify anything, gradients are unchanged (Default value = None) + + Returns: + The heatmap image indicating the `seed_input` regions whose change would most contribute towards minimizing the + weighted `losses`. + """ + penultimate_output = penultimate_layer.output + opt = Optimizer(input_tensor, losses, wrt_tensor=penultimate_output, norm_grads=False) + _, grads, penultimate_output_value = opt.minimize(seed_input, max_iter=1, grad_modifier=grad_modifier, verbose=False) + + # For numerical stability. Very small grad values along with small penultimate_output_value can cause + # w * penultimate_output_value to zero out, even for reasonable fp precision of float32. + grads = grads / (np.max(grads) + K.epsilon()) + + # Average pooling across all feature maps. + # This captures the importance of feature map (channel) idx to the output. + channel_idx = 1 if K.image_data_format() == 'channels_first' else -1 + other_axis = np.delete(np.arange(len(grads.shape)), channel_idx) + weights = np.mean(grads, axis=tuple(other_axis)) + + # Generate heatmap by computing weight * output over feature maps + output_dims = utils.get_img_shape(penultimate_output)[2:] + heatmap = np.zeros(shape=output_dims, dtype=K.floatx()) + for i, w in enumerate(weights): + if channel_idx == -1: + heatmap += w * penultimate_output_value[0, ..., i] + else: + heatmap += w * penultimate_output_value[0, i, ...] + + # ReLU thresholding to exclude pattern mismatch information (negative gradients). + heatmap = np.maximum(heatmap, 0) + + # The penultimate feature map size is definitely smaller than input image. + input_dims = utils.get_img_shape(input_tensor)[2:] + #heatmap = imresize(heatmap, input_dims, interp='bicubic', mode='F') + + # Normalize and create heatmap. + heatmap = utils.normalize(heatmap) + + target_size = input_dims + + mapa = heatmap + + mapa_ex = np.zeros((target_size[0], target_size[1], mapa.shape[2])) + for i in range(mapa.shape[2]): + mapa_ex[:, :, i] = cv2.resize(mapa[:, :, i],(target_size[1], target_size[0]), interpolation = cv2.INTER_CUBIC) + + mapa_ex2 = np.zeros(target_size) + for i in range(len(mapa_ex)): + mapa_ex2[i, :, :] = cv2.resize(mapa_ex[i, :, :],(target_size[2], target_size[1]), interpolation = cv2.INTER_CUBIC) + + return mapa_ex2 #np.uint8(cm.jet(heatmap)[..., :] * 255) #3 + + +def visualize_cam(model, layer_idx, filter_indices, + seed_input, penultimate_layer_idx=None, + backprop_modifier=None, grad_modifier=None): + """Generates a gradient based class activation map (grad-CAM) that maximizes the outputs of + `filter_indices` in `layer_idx`. + + Args: + model: The `keras.models.Model` instance. The model input shape must be: `(samples, channels, image_dims...)` + if `image_data_format=channels_first` or `(samples, image_dims..., channels)` if + `image_data_format=channels_last`. + layer_idx: The layer index within `model.layers` whose filters needs to be visualized. + filter_indices: filter indices within the layer to be maximized. + If None, all filters are visualized. (Default value = None) + For `keras.layers.Dense` layer, `filter_idx` is interpreted as the output index. + If you are visualizing final `keras.layers.Dense` layer, consider switching 'softmax' activation for + 'linear' using [utils.apply_modifications](vis.utils.utils#apply_modifications) for better results. + seed_input: The input image for which activation map needs to be visualized. + penultimate_layer_idx: The pre-layer to `layer_idx` whose feature maps should be used to compute gradients + wrt filter output. If not provided, it is set to the nearest penultimate `Conv` or `Pooling` layer. + backprop_modifier: backprop modifier to use. See [backprop_modifiers](vis.backprop_modifiers.md). If you don't + specify anything, no backprop modification is applied. (Default value = None) + grad_modifier: gradient modifier to use. See [grad_modifiers](vis.grad_modifiers.md). If you don't + specify anything, gradients are unchanged (Default value = None) + + Example: + If you wanted to visualize attention over 'bird' category, say output index 22 on the + final `keras.layers.Dense` layer, then, `filter_indices = [22]`, `layer = dense_layer`. + + One could also set filter indices to more than one value. For example, `filter_indices = [22, 23]` should + (hopefully) show attention map that corresponds to both 22, 23 output categories. + + Returns: + The heatmap image indicating the input regions whose change would most contribute towards + maximizing the output of `filter_indices`. + """ + if backprop_modifier is not None: + modifier_fn = get(backprop_modifier) + model = modifier_fn(model) + + penultimate_layer = _find_penultimate_layer(model, layer_idx, penultimate_layer_idx) + + # `ActivationMaximization` outputs negative gradient values for increase in activations. Multiply with -1 + # so that positive gradients indicate increase instead. + losses = [ + (ActivationMaximization(model.layers[layer_idx], filter_indices), -1) + ] + return visualize_cam_with_losses(model.input, losses, seed_input, penultimate_layer, grad_modifier) From 745bcc9370d24260ab2ded60d5f34d0cedcdeea6 Mon Sep 17 00:00:00 2001 From: kitamura-felipe Date: Sat, 21 Jul 2018 00:24:57 -0300 Subject: [PATCH 02/10] Instructions to make saliency3D.py work --- vis/visualization/follow_this.txt | 12 ++++++++++++ 1 file changed, 12 insertions(+) create mode 100644 vis/visualization/follow_this.txt diff --git a/vis/visualization/follow_this.txt b/vis/visualization/follow_this.txt new file mode 100644 index 0000000..678a841 --- /dev/null +++ b/vis/visualization/follow_this.txt @@ -0,0 +1,12 @@ +In order for this saliency3D.py t owork properly, it is necessary to make a minor change in /site-packages/scipy/misc/pilutils.py: + +Inside "def toimage()", replace: + + if mode not in ['RGB', 'RGBA', 'YCbCr', 'CMYK']: + +by: + + if mode not in ['RGB', 'RGBA', 'YCbCr', 'CMYK', 'F']: + + +This should no hurt other uses of scipy. From 2cee9105af318628d619a8840845adce27251737 Mon Sep 17 00:00:00 2001 From: kitamura-felipe Date: Sat, 21 Jul 2018 00:27:03 -0300 Subject: [PATCH 03/10] Update follow_this.txt --- vis/visualization/follow_this.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/vis/visualization/follow_this.txt b/vis/visualization/follow_this.txt index 678a841..80b8deb 100644 --- a/vis/visualization/follow_this.txt +++ b/vis/visualization/follow_this.txt @@ -1,4 +1,4 @@ -In order for this saliency3D.py t owork properly, it is necessary to make a minor change in /site-packages/scipy/misc/pilutils.py: +In order for this saliency3D.py to work properly, it is necessary to make a minor change in /site-packages/scipy/misc/pilutils.py: Inside "def toimage()", replace: From 251b3d0a27646783114f47f598225772e7d16cd7 Mon Sep 17 00:00:00 2001 From: kitamura-felipe Date: Sat, 21 Jul 2018 00:29:57 -0300 Subject: [PATCH 04/10] Update saliency3D.py --- vis/visualization/saliency3D.py | 83 +-------------------------------- 1 file changed, 1 insertion(+), 82 deletions(-) diff --git a/vis/visualization/saliency3D.py b/vis/visualization/saliency3D.py index 93ef81b..15bdfb1 100644 --- a/vis/visualization/saliency3D.py +++ b/vis/visualization/saliency3D.py @@ -46,87 +46,6 @@ def _find_penultimate_layer(model, layer_idx, penultimate_layer_idx): return model.layers[penultimate_layer_idx] - -def visualize_saliency_with_losses(input_tensor, losses, seed_input, grad_modifier='absolute'): - """Generates an attention heatmap over the `seed_input` by using positive gradients of `input_tensor` - with respect to weighted `losses`. - - This function is intended for advanced use cases where a custom loss is desired. For common use cases, - refer to `visualize_class_saliency` or `visualize_regression_saliency`. - - For a full description of saliency, see the paper: - [Deep Inside Convolutional Networks: Visualising Image Classification Models and Saliency Maps] - (https://arxiv.org/pdf/1312.6034v2.pdf) - - Args: - input_tensor: An input tensor of shape: `(samples, channels, image_dims...)` if `image_data_format= - channels_first` or `(samples, image_dims..., channels)` if `image_data_format=channels_last`. - losses: List of ([Loss](vis.losses#Loss), weight) tuples. - seed_input: The model input for which activation map needs to be visualized. - grad_modifier: gradient modifier to use. See [grad_modifiers](vis.grad_modifiers.md). By default `absolute` - value of gradients are used. To visualize positive or negative gradients, use `relu` and `negate` - respectively. (Default value = 'absolute') - - Returns: - The heatmap image indicating the `seed_input` regions whose change would most contribute towards minimizing - weighted `losses`. - """ - opt = Optimizer(input_tensor, losses, norm_grads=False) - grads = opt.minimize(seed_input=seed_input, max_iter=1, grad_modifier=grad_modifier, verbose=False)[1] - - channel_idx = 1 if K.image_data_format() == 'channels_first' else -1 - grads = np.max(grads, axis=channel_idx) - - # Normalize and create heatmap. - grads = utils.normalize(grads) - return np.uint8(cm.jet(grads)[..., :3] * 255)[0] - - -def visualize_saliency(model, layer_idx, filter_indices, seed_input, - backprop_modifier=None, grad_modifier='absolute'): - """Generates an attention heatmap over the `seed_input` for maximizing `filter_indices` - output in the given `layer_idx`. - - Args: - model: The `keras.models.Model` instance. The model input shape must be: `(samples, channels, image_dims...)` - if `image_data_format=channels_first` or `(samples, image_dims..., channels)` if - `image_data_format=channels_last`. - layer_idx: The layer index within `model.layers` whose filters needs to be visualized. - filter_indices: filter indices within the layer to be maximized. - If None, all filters are visualized. (Default value = None) - For `keras.layers.Dense` layer, `filter_idx` is interpreted as the output index. - If you are visualizing final `keras.layers.Dense` layer, consider switching 'softmax' activation for - 'linear' using [utils.apply_modifications](vis.utils.utils#apply_modifications) for better results. - seed_input: The model input for which activation map needs to be visualized. - backprop_modifier: backprop modifier to use. See [backprop_modifiers](vis.backprop_modifiers.md). If you don't - specify anything, no backprop modification is applied. (Default value = None) - grad_modifier: gradient modifier to use. See [grad_modifiers](vis.grad_modifiers.md). By default `absolute` - value of gradients are used. To visualize positive or negative gradients, use `relu` and `negate` - respectively. (Default value = 'absolute') - - Example: - If you wanted to visualize attention over 'bird' category, say output index 22 on the - final `keras.layers.Dense` layer, then, `filter_indices = [22]`, `layer = dense_layer`. - - One could also set filter indices to more than one value. For example, `filter_indices = [22, 23]` should - (hopefully) show attention map that corresponds to both 22, 23 output categories. - - Returns: - The heatmap image indicating the `seed_input` regions whose change would most contribute towards - maximizing the output of `filter_indices`. - """ - if backprop_modifier is not None: - modifier_fn = get(backprop_modifier) - model = modifier_fn(model) - - # `ActivationMaximization` loss reduces as outputs get large, hence negative gradients indicate the direction - # for increasing activations. Multiply with -1 so that positive gradients indicate increase instead. - losses = [ - (ActivationMaximization(model.layers[layer_idx], filter_indices), -1) - ] - return visualize_saliency_with_losses(model.input, losses, seed_input, grad_modifier) - - def visualize_cam_with_losses(input_tensor, losses, seed_input, penultimate_layer, grad_modifier=None): @@ -202,7 +121,7 @@ def visualize_cam_with_losses(input_tensor, losses, for i in range(len(mapa_ex)): mapa_ex2[i, :, :] = cv2.resize(mapa_ex[i, :, :],(target_size[2], target_size[1]), interpolation = cv2.INTER_CUBIC) - return mapa_ex2 #np.uint8(cm.jet(heatmap)[..., :] * 255) #3 + return mapa_ex2 def visualize_cam(model, layer_idx, filter_indices, From 49a0afcb9d1988116141759c6c600e50a8f669af Mon Sep 17 00:00:00 2001 From: kitamura-felipe Date: Sat, 21 Jul 2018 00:48:07 -0300 Subject: [PATCH 05/10] Snippet for saliency3D.py --- examples/3D_saliency_snippet.ipynb | 62 ++++++++++++++++++++++++++++++ 1 file changed, 62 insertions(+) create mode 100644 examples/3D_saliency_snippet.ipynb diff --git a/examples/3D_saliency_snippet.ipynb b/examples/3D_saliency_snippet.ipynb new file mode 100644 index 0000000..06d26d1 --- /dev/null +++ b/examples/3D_saliency_snippet.ipynb @@ -0,0 +1,62 @@ +{ + "cells": [ + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "from keras.models import load_model\n", + "from vis.visualization import saliency3D" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "model = load_model('3D_image_classification_model.hdf5')" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Usage of saliency3D.py is simple: just make sure seed_input has the same shape as model.input\n", + "## The other arguments should follow the original saliency.py usage" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "heatmap = saliency3D.visualize_cam(model, layer, filter_indices, seed_input, penultimate_layer_idx, \\\n", + " backprop_modifier=None, grad_modifier=None)" + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.5.4" + } + }, + "nbformat": 4, + "nbformat_minor": 2 +} From 9150e417157b71c8c687af8d0ea5a4bc6b562bbe Mon Sep 17 00:00:00 2001 From: kitamura-felipe Date: Sat, 21 Jul 2018 00:59:32 -0300 Subject: [PATCH 06/10] Add files via upload --- examples/3D_saliency_snippet.ipynb | 26 ++++++++++++++++++++++++-- 1 file changed, 24 insertions(+), 2 deletions(-) diff --git a/examples/3D_saliency_snippet.ipynb b/examples/3D_saliency_snippet.ipynb index 06d26d1..18fd5f5 100644 --- a/examples/3D_saliency_snippet.ipynb +++ b/examples/3D_saliency_snippet.ipynb @@ -1,5 +1,13 @@ { "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Usage of saliency3D.py is simple\n", + "First, import dependencies:" + ] + }, { "cell_type": "code", "execution_count": null, @@ -10,6 +18,13 @@ "from vis.visualization import saliency3D" ] }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Load your 3D model:" + ] + }, { "cell_type": "code", "execution_count": null, @@ -23,8 +38,7 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "## Usage of saliency3D.py is simple: just make sure seed_input has the same shape as model.input\n", - "## The other arguments should follow the original saliency.py usage" + "Then, calculate the heatmap:" ] }, { @@ -36,6 +50,14 @@ "heatmap = saliency3D.visualize_cam(model, layer, filter_indices, seed_input, penultimate_layer_idx, \\\n", " backprop_modifier=None, grad_modifier=None)" ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Just make sure seed_input has the same shape as model.input.\n", + "The other arguments should follow the original saliency.py usage." + ] } ], "metadata": { From 686f42cb93a905be61acf52fa6a7a0deba8826b5 Mon Sep 17 00:00:00 2001 From: kitamura-felipe Date: Mon, 23 Jul 2018 14:53:31 -0300 Subject: [PATCH 07/10] Update README.md --- README.md | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 96ac8cb..98f6b18 100644 --- a/README.md +++ b/README.md @@ -1,8 +1,14 @@ -# Keras Visualization Toolkit +# Keras Visualization Toolkit with 3D gradCAM [![Build Status](https://travis-ci.org/raghakot/keras-vis.svg?branch=master)](https://travis-ci.org/raghakot/keras-vis) [![license](https://img.shields.io/github/license/mashape/apistatus.svg?maxAge=2592000)](https://github.com/raghakot/keras-vis/blob/master/LICENSE) [![Slack](https://img.shields.io/badge/slack-discussion-E01563.svg)](https://keras-vis.herokuapp.com/) +Please refer to /vis/visualization/follow_this.txt to properly modify scipy. It's a minor change. + +This repository is similiar to the original from raghakot, except there is one more file: /vis/visualization/saliency3D.py + +There is a code snippet in /examples/3D_saliency_snippet.ipynb + keras-vis is a high-level toolkit for visualizing and debugging your trained keras neural net models. Currently supported visualizations include: From d069d5b95742d98bb92fd7696e19b2acc8de071f Mon Sep 17 00:00:00 2001 From: kitamura-felipe Date: Tue, 31 Jul 2018 12:16:13 -0300 Subject: [PATCH 08/10] Update README.md --- README.md | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 98f6b18..bd59f20 100644 --- a/README.md +++ b/README.md @@ -3,11 +3,17 @@ [![license](https://img.shields.io/github/license/mashape/apistatus.svg?maxAge=2592000)](https://github.com/raghakot/keras-vis/blob/master/LICENSE) [![Slack](https://img.shields.io/badge/slack-discussion-E01563.svg)](https://keras-vis.herokuapp.com/) +## Modifications for 3D gradCAM + Please refer to /vis/visualization/follow_this.txt to properly modify scipy. It's a minor change. This repository is similiar to the original from raghakot, except there is one more file: /vis/visualization/saliency3D.py -There is a code snippet in /examples/3D_saliency_snippet.ipynb +There is a code snippet in /examples/3D_saliency_snippet.ipynb. Use it as a guide on your on code and model. + +Thanks to Romane Gariau from the MGH and BWH Center for Clinical Data Science (CCDS) for reviewing the code. + +## Intro keras-vis is a high-level toolkit for visualizing and debugging your trained keras neural net models. Currently supported visualizations include: From c846f687221f2ebdec2cd57d2dadaed6898ae6f7 Mon Sep 17 00:00:00 2001 From: kitamura-felipe Date: Tue, 31 Jul 2018 12:44:54 -0300 Subject: [PATCH 09/10] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index bd59f20..6decad3 100644 --- a/README.md +++ b/README.md @@ -11,7 +11,7 @@ This repository is similiar to the original from raghakot, except there is one m There is a code snippet in /examples/3D_saliency_snippet.ipynb. Use it as a guide on your on code and model. -Thanks to Romane Gariau from the MGH and BWH Center for Clinical Data Science (CCDS) for reviewing the code. +Thanks to Romane Gauriau from the MGH and BWH Center for Clinical Data Science (CCDS) for reviewing the code. ## Intro From a84ec7216b1d2b96c9697c141ed78d37d5da291b Mon Sep 17 00:00:00 2001 From: kitamura-felipe Date: Mon, 17 Sep 2018 19:04:39 -0300 Subject: [PATCH 10/10] Update README.md --- README.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/README.md b/README.md index 6decad3..24dbd2d 100644 --- a/README.md +++ b/README.md @@ -5,6 +5,8 @@ ## Modifications for 3D gradCAM +This is a small modification forked from raghakot/keras-vis, just to correct a minor bug. All the work was done by raghakot. + Please refer to /vis/visualization/follow_this.txt to properly modify scipy. It's a minor change. This repository is similiar to the original from raghakot, except there is one more file: /vis/visualization/saliency3D.py