forked from mindspore-Ecosystem/mindspore
!9003 Fix mistakes in docstring.
From: @yuhanshi Reviewed-by: @wuxuejian,@ouwenchang Signed-off-by: @wuxuejian
This commit is contained in:
commit
829cc849a0
|
@ -16,10 +16,8 @@
|
||||||
|
|
||||||
import numpy as np
|
import numpy as np
|
||||||
|
|
||||||
from mindspore import Tensor
|
|
||||||
from .metric import LabelAgnosticMetric
|
from .metric import LabelAgnosticMetric
|
||||||
from ... import _operators as ops
|
from ... import _operators as ops
|
||||||
from ...explanation._attribution.attribution import Attribution
|
|
||||||
from ..._utils import calc_correlation
|
from ..._utils import calc_correlation
|
||||||
|
|
||||||
|
|
||||||
|
@ -35,12 +33,12 @@ class ClassSensitivity(LabelAgnosticMetric):
|
||||||
|
|
||||||
"""
|
"""
|
||||||
|
|
||||||
def evaluate(self, explainer: Attribution, inputs: Tensor) -> np.ndarray:
|
def evaluate(self, explainer, inputs):
|
||||||
"""
|
"""
|
||||||
Evaluate class sensitivity on a single data sample.
|
Evaluate class sensitivity on a single data sample.
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
explainer (Attribution): The explainer to be evaluated, see `mindspore.explainer.explanation`.
|
explainer (Explanation): The explainer to be evaluated, see `mindspore.explainer.explanation`.
|
||||||
inputs (Tensor): A data sample, a 4D tensor of shape :math:`(N, C, H, W)`.
|
inputs (Tensor): A data sample, a 4D tensor of shape :math:`(N, C, H, W)`.
|
||||||
|
|
||||||
Returns:
|
Returns:
|
||||||
|
@ -49,7 +47,8 @@ class ClassSensitivity(LabelAgnosticMetric):
|
||||||
Examples:
|
Examples:
|
||||||
>>> import mindspore as ms
|
>>> import mindspore as ms
|
||||||
>>> from mindspore.explainer.explanation import Gradient
|
>>> from mindspore.explainer.explanation import Gradient
|
||||||
>>> gradient = Gradient()
|
>>> model = resnet(10)
|
||||||
|
>>> gradient = Gradient(model)
|
||||||
>>> x = ms.Tensor(np.random.rand(1, 3, 224, 224), ms.float32)
|
>>> x = ms.Tensor(np.random.rand(1, 3, 224, 224), ms.float32)
|
||||||
>>> class_sensitivity = ClassSensitivity()
|
>>> class_sensitivity = ClassSensitivity()
|
||||||
>>> res = class_sensitivity.evaluate(gradient, x)
|
>>> res = class_sensitivity.evaluate(gradient, x)
|
||||||
|
|
|
@ -14,21 +14,14 @@
|
||||||
# ============================================================================
|
# ============================================================================
|
||||||
"""Robustness."""
|
"""Robustness."""
|
||||||
|
|
||||||
from typing import Optional, Union
|
|
||||||
|
|
||||||
import numpy as np
|
import numpy as np
|
||||||
|
|
||||||
import mindspore as ms
|
import mindspore as ms
|
||||||
import mindspore.nn as nn
|
import mindspore.nn as nn
|
||||||
from mindspore import Tensor
|
|
||||||
from mindspore import log
|
from mindspore import log
|
||||||
from .metric import LabelSensitiveMetric
|
from .metric import LabelSensitiveMetric
|
||||||
from ...explanation._attribution import Attribution
|
|
||||||
from ...explanation._attribution._perturbation.replacement import RandomPerturb
|
from ...explanation._attribution._perturbation.replacement import RandomPerturb
|
||||||
|
|
||||||
_Array = np.ndarray
|
|
||||||
_Label = Union[ms.Tensor, int]
|
|
||||||
|
|
||||||
|
|
||||||
class Robustness(LabelSensitiveMetric):
|
class Robustness(LabelSensitiveMetric):
|
||||||
"""
|
"""
|
||||||
|
@ -44,7 +37,7 @@ class Robustness(LabelSensitiveMetric):
|
||||||
>>> robustness = Robustness(num_labels)
|
>>> robustness = Robustness(num_labels)
|
||||||
"""
|
"""
|
||||||
|
|
||||||
def __init__(self, num_labels: int, activation_fn=nn.Softmax()):
|
def __init__(self, num_labels, activation_fn=nn.Softmax()):
|
||||||
super().__init__(num_labels)
|
super().__init__(num_labels)
|
||||||
|
|
||||||
self._perturb = RandomPerturb()
|
self._perturb = RandomPerturb()
|
||||||
|
@ -52,12 +45,7 @@ class Robustness(LabelSensitiveMetric):
|
||||||
self._threshold = 0.1 # threshold to generate perturbation
|
self._threshold = 0.1 # threshold to generate perturbation
|
||||||
self._activation_fn = activation_fn
|
self._activation_fn = activation_fn
|
||||||
|
|
||||||
def evaluate(self,
|
def evaluate(self, explainer, inputs, targets, saliency=None):
|
||||||
explainer: Attribution,
|
|
||||||
inputs: Tensor,
|
|
||||||
targets: _Label,
|
|
||||||
saliency: Optional[Tensor] = None
|
|
||||||
) -> _Array:
|
|
||||||
"""
|
"""
|
||||||
Evaluate robustness on single sample.
|
Evaluate robustness on single sample.
|
||||||
|
|
||||||
|
|
|
@ -48,7 +48,7 @@ class Ablation:
|
||||||
inputs (np.ndarray): Input array to perturb. The first dim of inputs is assumed to be the batch size, i.e.,
|
inputs (np.ndarray): Input array to perturb. The first dim of inputs is assumed to be the batch size, i.e.,
|
||||||
number of samples.
|
number of samples.
|
||||||
reference (np.ndarray or float): Array of values to replace the elements in the original inputs. The shape
|
reference (np.ndarray or float): Array of values to replace the elements in the original inputs. The shape
|
||||||
of reference must math the inputs. If scalar is provided, the perturbed elements will be assigned the
|
of reference must match the inputs. If scalar is provided, the perturbed elements will be assigned the
|
||||||
given value..
|
given value..
|
||||||
masks (np.ndarray): Several boolean array to mark the perturbed positions. True marks the pixels to be
|
masks (np.ndarray): Several boolean array to mark the perturbed positions. True marks the pixels to be
|
||||||
perturbed, otherwise the pixels will be kept. The shape of masks is assumed to be
|
perturbed, otherwise the pixels will be kept. The shape of masks is assumed to be
|
||||||
|
@ -134,9 +134,9 @@ class AblationWithSaliency(Ablation):
|
||||||
saliency is expected to be: [batch_size, optional(num_channels), *spatial_size]. If multi-channel
|
saliency is expected to be: [batch_size, optional(num_channels), *spatial_size]. If multi-channel
|
||||||
saliency is provided, an averaged saliency will be taken to calculate pixel order in spatial dimension.
|
saliency is provided, an averaged saliency will be taken to calculate pixel order in spatial dimension.
|
||||||
num_channels (optional[int]): Number of channels of the input data. In order to match the shape of inputs,
|
num_channels (optional[int]): Number of channels of the input data. In order to match the shape of inputs,
|
||||||
num_channels should be provided when input data have channels dimension, even if num_channel. If None is
|
num_channels should be provided when input data have channels dimension, even if num_channel is 1.
|
||||||
provided, the inputs is assumed to be no-channel data, and the generated mask will have no channel
|
If None is provided, the inputs is assumed to be no-channel data, and the generated mask will have
|
||||||
dimension. Default: None.
|
no channel dimension. Default: None.
|
||||||
|
|
||||||
Return:
|
Return:
|
||||||
mask (np.ndarray): boolen mask for generate perturbations.
|
mask (np.ndarray): boolen mask for generate perturbations.
|
||||||
|
|
|
@ -15,7 +15,6 @@
|
||||||
"""Occlusion explainer."""
|
"""Occlusion explainer."""
|
||||||
|
|
||||||
import math
|
import math
|
||||||
from typing import Tuple, Union
|
|
||||||
|
|
||||||
import numpy as np
|
import numpy as np
|
||||||
from numpy.lib.stride_tricks import as_strided
|
from numpy.lib.stride_tricks import as_strided
|
||||||
|
@ -23,15 +22,11 @@ from numpy.lib.stride_tricks import as_strided
|
||||||
import mindspore as ms
|
import mindspore as ms
|
||||||
import mindspore.nn as nn
|
import mindspore.nn as nn
|
||||||
from mindspore import Tensor
|
from mindspore import Tensor
|
||||||
from mindspore.nn import Cell
|
|
||||||
from .ablation import Ablation
|
from .ablation import Ablation
|
||||||
from .perturbation import PerturbationAttribution
|
from .perturbation import PerturbationAttribution
|
||||||
from .replacement import Constant
|
from .replacement import Constant
|
||||||
from ...._utils import abs_max
|
from ...._utils import abs_max
|
||||||
|
|
||||||
_Array = np.ndarray
|
|
||||||
_Label = Union[int, Tensor]
|
|
||||||
|
|
||||||
|
|
||||||
def _generate_patches(array, window_size, stride):
|
def _generate_patches(array, window_size, stride):
|
||||||
"""View as windows."""
|
"""View as windows."""
|
||||||
|
@ -76,16 +71,17 @@ class Occlusion(PerturbationAttribution):
|
||||||
|
|
||||||
Example:
|
Example:
|
||||||
>>> from mindspore.explainer.explanation import Occlusion
|
>>> from mindspore.explainer.explanation import Occlusion
|
||||||
>>> net = resnet50(10)
|
>>> from mindspore.train.serialization import load_checkpoint, load_param_into_net
|
||||||
|
>>> network = resnet50(10)
|
||||||
>>> param_dict = load_checkpoint("resnet50.ckpt")
|
>>> param_dict = load_checkpoint("resnet50.ckpt")
|
||||||
>>> load_param_into_net(net, param_dict)
|
>>> load_param_into_net(network, param_dict)
|
||||||
>>> occlusion = Occlusion(net)
|
>>> occlusion = Occlusion(network)
|
||||||
>>> x = ms.Tensor(np.random.rand([1, 3, 224, 224]), ms.float32)
|
>>> x = Tensor(np.random.rand([1, 3, 224, 224]), ms.float32)
|
||||||
>>> label = 1
|
>>> label = 1
|
||||||
>>> saliency = occlusion(x, label)
|
>>> saliency = occlusion(x, label)
|
||||||
"""
|
"""
|
||||||
|
|
||||||
def __init__(self, network: Cell, activation_fn: Cell = nn.Softmax()):
|
def __init__(self, network, activation_fn=nn.Softmax()):
|
||||||
super().__init__(network, activation_fn)
|
super().__init__(network, activation_fn)
|
||||||
|
|
||||||
self._ablation = Ablation(perturb_mode='Deletion')
|
self._ablation = Ablation(perturb_mode='Deletion')
|
||||||
|
@ -94,7 +90,7 @@ class Occlusion(PerturbationAttribution):
|
||||||
self._num_sample_per_dim = 32 # specify the number of perturbations each dimension.
|
self._num_sample_per_dim = 32 # specify the number of perturbations each dimension.
|
||||||
self._num_per_eval = 32 # number of perturbations each evaluation step.
|
self._num_per_eval = 32 # number of perturbations each evaluation step.
|
||||||
|
|
||||||
def __call__(self, inputs: Tensor, targets: _Label) -> Tensor:
|
def __call__(self, inputs, targets):
|
||||||
"""Call function for 'Occlusion'."""
|
"""Call function for 'Occlusion'."""
|
||||||
self._verify_data(inputs, targets)
|
self._verify_data(inputs, targets)
|
||||||
|
|
||||||
|
@ -145,11 +141,11 @@ class Occlusion(PerturbationAttribution):
|
||||||
outputs_diff.reshape(outputs_diff.shape + (1,) * (len(masks.shape) - 2)) * masks).sum(axis=1).clip(1e-6)
|
outputs_diff.reshape(outputs_diff.shape + (1,) * (len(masks.shape) - 2)) * masks).sum(axis=1).clip(1e-6)
|
||||||
weights += masks.sum(axis=1)
|
weights += masks.sum(axis=1)
|
||||||
|
|
||||||
attribution = self._aggregation_fn(ms.Tensor(total_attribution / weights))
|
attribution = self._aggregation_fn(Tensor(total_attribution / weights))
|
||||||
return attribution
|
return attribution
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def _generate_masks(inputs: Tensor, window_size: Tuple[int, ...], strides: Tuple[int, ...]) -> _Array:
|
def _generate_masks(inputs, window_size, strides):
|
||||||
"""Generate masks to perturb contiguous regions."""
|
"""Generate masks to perturb contiguous regions."""
|
||||||
total_dim = np.prod(inputs.shape[1:]).item()
|
total_dim = np.prod(inputs.shape[1:]).item()
|
||||||
template = np.arange(total_dim).reshape(inputs.shape[1:])
|
template = np.arange(total_dim).reshape(inputs.shape[1:])
|
||||||
|
|
Loading…
Reference in New Issue