Skip to content

Commit

Permalink
Merge pull request #73 from keisen/releases/v0.8.0
Browse files Browse the repository at this point in the history
Releases/v0.8.0
  • Loading branch information
keisen authored Aug 14, 2021
2 parents e3cf404 + 0188103 commit c325157
Show file tree
Hide file tree
Showing 14 changed files with 61 additions and 98 deletions.
2 changes: 1 addition & 1 deletion LICENSE
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
MIT License

Copyright (c) 2016 Raghavendra Kotikalapudi
Copyright (c) 2019 keisen(Kubota Yasuhiro) and contributors
Copyright (c) 2019 keisen(Yasuhiro Kubota) and contributors

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
Expand Down
2 changes: 2 additions & 0 deletions MANIFEST.in
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
include VERSION
recursive-exclude tests *
2 changes: 1 addition & 1 deletion VERSION
Original file line number Diff line number Diff line change
@@ -1 +1 @@
0.7.2
0.8.0
Original file line number Diff line number Diff line change
Expand Up @@ -199,12 +199,6 @@ def test__call__if_regularizers_are_(self, regularizer_container, regularizers,
result = activation_maximization(CategoricalScore(0), regularizers=regularizers)
assert result.shape == (1, 8, 8, 3)

@pytest.mark.usefixtures("mixed_precision", "legacy")
def test__call__if_normalize_gradient_is_True(self, conv_model):
activation_maximization = ActivationMaximization(conv_model)
result = activation_maximization(CategoricalScore(0), normalize_gradient=True)
assert result.shape == (1, 8, 8, 3)

@pytest.mark.usefixtures("mixed_precision", "legacy")
def test__call__with_gradient_modifier(self, conv_model):
activation_maximization = ActivationMaximization(conv_model)
Expand Down
13 changes: 1 addition & 12 deletions tests/tf_keras_vis/gradcam_test.py
Original file line number Diff line number Diff line change
@@ -1,13 +1,2 @@
import pytest

from tf_keras_vis.gradcam import Gradcam
from tf_keras_vis.utils.scores import CategoricalScore
from tf_keras_vis.utils.test import dummy_sample


class TestGradcam():
@pytest.mark.usefixtures("mixed_precision")
def test__call__if_normalize_gradient_is_True(self, conv_model):
cam = Gradcam(conv_model)
result = cam(CategoricalScore(0), dummy_sample((1, 8, 8, 3)), normalize_gradient=True)
assert result.shape == (1, 8, 8)
pass
16 changes: 8 additions & 8 deletions tf_keras_vis/__init__.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,10 @@
try:
from importlib.metadata import version
except ImportError: # pragma: no cover
from importlib_metadata import version

__version__ = version("tf-keras-vis")

from abc import ABC, abstractmethod
from typing import Union

Expand All @@ -6,21 +13,14 @@

from .utils import listify

try:
from importlib.metadata import version
except ImportError: # pragma: no cover
from importlib_metadata import version

__version__ = version("tf-keras-vis")


class ModelVisualization(ABC):
"""Visualization class that analyze the model for debugging.
"""
def __init__(self, model, model_modifier=None, clone=True) -> None:
"""
Args:
model: A `tf.keras.Model` instance. When `model_modifier` is NOT None, this model will
model: A `tf.keras.Model` instance. When `model_modifier` is NOT None, this model will
be cloned with `tf.keras.models.clone_model` function and then will be modified by
`model_modifier` according to needs.
model_modifier: A :obj:`tf_keras_vis.utils.model_modifiers.ModelModifier` instance,
Expand Down
9 changes: 1 addition & 8 deletions tf_keras_vis/activation_maximization/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,6 @@ def __call__(
Norm(weight=0.3, p=1)],
steps=200,
optimizer=None, # When None, the default is tf.optimizers.RMSprop(1.0, 0.999)
normalize_gradient=None, # Disabled option.
gradient_modifier=None,
callbacks=None,
training=False,
Expand Down Expand Up @@ -150,8 +149,7 @@ def __call__(
gradient_modifier: A function to modify gradients.
Defaults to None.
callbacks: A :obj:`tf_keras_vis.activation_maximization.callbacks.Callback` instance
or a list of them.
Defaults to None.
or a list of them. Defaults to None.
training: A bool that indicates whether the model's training-mode on or off.
Defaults to False.
unconnected_gradients: Specifies the gradient value returned when the given input
Expand All @@ -177,11 +175,6 @@ def __call__(
arguments = dict(
(k, v) for k, v in locals().items() if k != 'self' and not k.startswith('_'))

if normalize_gradient is not None:
warnings.warn(
"`normalize_gradient` option of ActivationMaximization#__call__() is disabled.,"
" And this will be removed in future.", DeprecationWarning)

# Check model
mixed_precision_model = is_mixed_precision(self.model)

Expand Down
1 change: 0 additions & 1 deletion tf_keras_vis/activation_maximization/legacy.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,6 @@ def __call__(self,
Norm(weight=0.003, p=1)],
steps=200,
optimizer=None,
normalize_gradient=None,
gradient_modifier=None,
callbacks=None,
training=False,
Expand Down
45 changes: 18 additions & 27 deletions tf_keras_vis/gradcam.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
import warnings
from typing import Union

import numpy as np
Expand All @@ -7,7 +6,7 @@
from scipy.ndimage.interpolation import zoom

from . import ModelVisualization
from .utils import is_mixed_precision, standardize, zoom_factor
from .utils import is_mixed_precision, normalize, zoom_factor
from .utils.model_modifiers import ExtractIntermediateLayerForGradcam as ModelModifier


Expand All @@ -19,19 +18,17 @@ class Gradcam(ModelVisualization):
Visual Explanations from Deep Networks via Gradient-based Localization
(https://arxiv.org/pdf/1610.02391v1.pdf)
"""
def __call__(
self,
score,
seed_input,
penultimate_layer=None,
seek_penultimate_conv_layer=True,
gradient_modifier=None,
activation_modifier=lambda cam: K.relu(cam),
training=False,
normalize_gradient=None, # Disabled option.
expand_cam=True,
standardize_cam=True,
unconnected_gradients=tf.UnconnectedGradients.NONE) -> Union[np.ndarray, list]:
def __call__(self,
score,
seed_input,
penultimate_layer=None,
seek_penultimate_conv_layer=True,
gradient_modifier=None,
activation_modifier=lambda cam: K.relu(cam),
training=False,
expand_cam=True,
normalize_cam=True,
unconnected_gradients=tf.UnconnectedGradients.NONE) -> Union[np.ndarray, list]:
"""Generate gradient based class activation maps (CAM) by using positive gradient of
penultimate_layer with respect to score.
Expand Down Expand Up @@ -64,16 +61,14 @@ def __call__(
seek_penultimate_conv_layer: A bool that indicates whether or not seeks a penultimate
layer when the layer specified by `penultimate_layer` is not `convolutional` layer.
Defaults to True.
gradient_modifier: A function to modify gradients. Defaults to None.
activation_modifier: A function to modify the Class Activation Map (CAM). Defaults to
`lambda cam: K.relu(cam)`.
training: A bool that indicates whether the model's training-mode on or off. Defaults
to False.
normalize_gradient (bool, optional): **Note!** This option is now disabled.
Defaults to None.
gradient_modifier: A function to modify gradients. Defaults to None.
expand_cam: True to resize CAM to the same as input image size. **Note!** When False,
even if the model has multiple inputs, return only a CAM. Defaults to True.
standardize_cam: When True, CAM will be standardized. Defaults to True.
normalize_cam: When True, CAM will be normalized. Defaults to True.
unconnected_gradients: Specifies the gradient value returned when the given input
tensors are unconnected. Defaults to tf.UnconnectedGradients.NONE.
Expand All @@ -86,10 +81,6 @@ def __call__(
:obj:`ValueError`: When there is any invalid arguments.
"""

if normalize_gradient is not None:
warnings.warn(
'`normalize_gradient` option is disabled.,'
' And this will be removed in future.', DeprecationWarning)
# Preparing
scores = self._get_scores_for_multiple_outputs(score)
seed_inputs = self._get_seed_inputs_for_multiple_inputs(seed_input)
Expand Down Expand Up @@ -119,15 +110,15 @@ def __call__(
cam = activation_modifier(cam)

if not expand_cam:
if standardize_cam:
cam = standardize(cam)
if normalize_cam:
cam = normalize(cam)
return cam

# Visualizing
factors = (zoom_factor(cam.shape, X.shape) for X in seed_inputs)
cam = [zoom(cam, factor, order=1) for factor in factors]
if standardize_cam:
cam = [standardize(x) for x in cam]
if normalize_cam:
cam = [normalize(x) for x in cam]
if len(self.model.inputs) == 1 and not isinstance(seed_input, list):
cam = cam[0]
return cam
Expand Down
14 changes: 7 additions & 7 deletions tf_keras_vis/gradcam_plus_plus.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
from scipy.ndimage.interpolation import zoom

from . import ModelVisualization
from .utils import is_mixed_precision, standardize, zoom_factor
from .utils import is_mixed_precision, normalize, zoom_factor
from .utils.model_modifiers import ExtractIntermediateLayerForGradcam as ModelModifier


Expand All @@ -26,7 +26,7 @@ def __call__(self,
activation_modifier=lambda cam: K.relu(cam),
training=False,
expand_cam=True,
standardize_cam=True,
normalize_cam=True,
unconnected_gradients=tf.UnconnectedGradients.NONE) -> Union[np.ndarray, list]:
"""Generate gradient based class activation maps (CAM) by using positive gradient of
penultimate_layer with respect to score.
Expand Down Expand Up @@ -67,7 +67,7 @@ def __call__(self,
to False.
expand_cam: True to resize CAM to the same as input image size. **Note!** When False,
even if the model has multiple inputs, return only a CAM. Defaults to True.
standardize_cam: When True, CAM will be standardized. Defaults to True.
normalize_cam: When True, CAM will be normalized. Defaults to True.
unconnected_gradients: Specifies the gradient value returned when the given input
tensors are unconnected. Defaults to tf.UnconnectedGradients.NONE.
Expand Down Expand Up @@ -141,15 +141,15 @@ def __call__(self,
cam = activation_modifier(cam)

if not expand_cam:
if standardize_cam:
cam = standardize(cam)
if normalize_cam:
cam = normalize(cam)
return cam

# Visualizing
factors = (zoom_factor(cam.shape, X.shape) for X in seed_inputs)
cam = [zoom(cam, factor, order=1) for factor in factors]
if standardize_cam:
cam = [standardize(x) for x in cam]
if normalize_cam:
cam = [normalize(x) for x in cam]
if len(self.model.inputs) == 1 and not isinstance(seed_input, list):
cam = cam[0]
return cam
4 changes: 2 additions & 2 deletions tf_keras_vis/layercam.py
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ def __call__(self,
activation_modifier=lambda cam: K.relu(cam),
training=False,
expand_cam=True,
standardize_cam=True,
normalize_cam=True,
unconnected_gradients=tf.UnconnectedGradients.NONE) -> Union[np.ndarray, list]:
"""Generate gradient based class activation maps (CAM) by using positive gradient of
penultimate_layer with respect to score.
Expand Down Expand Up @@ -65,7 +65,7 @@ def __call__(self,
`lambda grads: tf.keras.backend.relu(grads)`.
expand_cam: True to resize CAM to the same as input image size. **Note!** When False,
even if the model has multiple inputs, return only a CAM. Defaults to True.
standardize_cam: When True, CAM will be standardized. Defaults to True.
normalize_cam: When True, CAM will be normalized. Defaults to True.
unconnected_gradients: Specifies the gradient value returned when the given input
tensors are unconnected. Defaults to tf.UnconnectedGradients.NONE.
Expand Down
10 changes: 5 additions & 5 deletions tf_keras_vis/saliency.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
import tensorflow.keras.backend as K

from . import ModelVisualization
from .utils import get_num_of_steps_allowed, listify, standardize
from .utils import get_num_of_steps_allowed, listify, normalize


class Saliency(ModelVisualization):
Expand All @@ -24,7 +24,7 @@ def __call__(self,
keepdims=False,
gradient_modifier=lambda grads: K.abs(grads),
training=False,
standardize_saliency=True,
normalize_map=True,
unconnected_gradients=tf.UnconnectedGradients.NONE) -> Union[np.ndarray, list]:
"""Generate an attention map that appears how output value changes with respect to a small
change in input image pixels.
Expand Down Expand Up @@ -60,7 +60,7 @@ def __call__(self,
gradient_modifier: A function to modify gradients. Defaults to None.
training: A bool that indicates whether the model's training-mode on or off. Defaults
to False.
standardize_saliency (bool, optional): When True, saliency map will be standardized.
normalize_map (bool, optional): When True, saliency map will be normalized.
Defaults to True.
unconnected_gradients: Specifies the gradient value returned when the given input
tensors are unconnected. Defaults to tf.UnconnectedGradients.NONE.
Expand Down Expand Up @@ -102,8 +102,8 @@ def __call__(self,
# Visualizing
if not keepdims:
grads = [np.max(g, axis=-1) for g in grads]
if standardize_saliency:
grads = [standardize(g) for g in grads]
if normalize_map:
grads = [normalize(g) for g in grads]
if len(self.model.inputs) == 1 and not isinstance(seed_input, list):
grads = grads[0]
return grads
Expand Down
14 changes: 7 additions & 7 deletions tf_keras_vis/scorecam.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
from scipy.ndimage.interpolation import zoom

from . import ModelVisualization
from .utils import get_num_of_steps_allowed, is_mixed_precision, listify, standardize, zoom_factor
from .utils import get_num_of_steps_allowed, is_mixed_precision, listify, normalize, zoom_factor
from .utils.model_modifiers import ExtractIntermediateLayerForGradcam as ModelModifier


Expand All @@ -28,7 +28,7 @@ def __call__(self,
max_N=None,
training=False,
expand_cam=True,
standardize_cam=True) -> Union[np.ndarray, list]:
normalize_cam=True) -> Union[np.ndarray, list]:
"""Generate score-weighted class activation maps (CAM) by using gradient-free
visualization method.
Expand Down Expand Up @@ -71,7 +71,7 @@ def __call__(self,
to False.
expand_cam: True to resize CAM to the same as input image size. **Note!** When False,
even if the model has multiple inputs, return only a CAM. Defaults to True.
standardize_cam: When True, CAM will be standardized. Defaults to True.
normalize_cam: When True, CAM will be normalized. Defaults to True.
unconnected_gradients: Specifies the gradient value returned when the given input
tensors are unconnected. Defaults to tf.UnconnectedGradients.NONE.
Expand Down Expand Up @@ -177,15 +177,15 @@ def __call__(self,
cam = activation_modifier(cam)

if not expand_cam:
if standardize_cam:
cam = standardize(cam)
if normalize_cam:
cam = normalize(cam)
return cam

# Visualizing
zoom_factors = (zoom_factor(cam.shape, X.shape) for X in seed_inputs)
cam = [zoom(cam, factor, order=1) for factor in zoom_factors]
if standardize_cam:
cam = [standardize(x) for x in cam]
if normalize_cam:
cam = [normalize(x) for x in cam]
if len(self.model.inputs) == 1 and not isinstance(seed_input, list):
cam = cam[0]
return cam
Expand Down
Loading

0 comments on commit c325157

Please sign in to comment.