From df94bb6562da394197248d9f62fff9351da5605f Mon Sep 17 00:00:00 2001 From: lixiaohui Date: Mon, 2 Nov 2020 11:52:03 +0800 Subject: [PATCH] Fix issue#123FX6: format API comments --- mindspore/explainer/_runner.py | 23 ++++--- .../benchmark/_attribution/faithfulness.py | 55 +++++++++++----- .../benchmark/_attribution/localization.py | 30 ++++++--- .../_attribution/_backprop/gradcam.py | 54 +++++++++------- .../_attribution/_backprop/gradient.py | 33 +++++----- .../_attribution/_backprop/modified_relu.py | 63 ++++++++++++------- 6 files changed, 164 insertions(+), 94 deletions(-) diff --git a/mindspore/explainer/_runner.py b/mindspore/explainer/_runner.py index 4defc8364c..a3b4899e3b 100644 --- a/mindspore/explainer/_runner.py +++ b/mindspore/explainer/_runner.py @@ -56,16 +56,17 @@ def _make_rgba(saliency): class ExplainRunner: """ - High-level API for users to generate results with the explanation methods and the evaluation methods. + A high-level API for users to generate and store results of the explanation methods and the evaluation methods. After generating results with the explanation methods and the evaluation methods, the results will be written into - a specified file with 'mindspore.summary.SummaryRecord'. The stored content can be viewed using MindInsight. + a specified file with `mindspore.summary.SummaryRecord`. The stored content can be viewed using MindInsight. Args: - summary_dir (str): The directory path to save the summary files which store the generated results. + summary_dir (str, optional): The directory path to save the summary files which store the generated results. Default: "./" Examples: + >>> from mindspore.explainer import ExplainRunner >>> # init a runner with a specified directory >>> summary_dir = "summary_dir" >>> runner = ExplainRunner(summary_dir) @@ -83,14 +84,20 @@ class ExplainRunner: explainers: List, benchmarkers: Optional[List] = None): """ - Genereate results and write results into the summary files in `self.summary_dir`. + Genereates results and writes results into the summary files in `summary_dir` specified during the object + initialization. Args: dataset (tuple): A tuple that contains `mindspore.dataset` object for iteration and its labels. - - dataset[0], a `mindspore.dataset` object to provide data to explain. - - dataset[1], a list of string that specifies the label names of the dataset. - explainers (list): A list of explanation objects to generate _attribution results. - benchmarkers (list): A list of benchmark objects to generate evaluation results. Default: None + + - dataset[0]: A `mindspore.dataset` object to provide data to explain. + - dataset[1]: A list of string that specifies the label names of the dataset. + + explainers (list[Explanation]): A list of explanation objects to generate attribution results. Explanation + object is an instance initialized with the explanation methods in module + `mindspore.explainer.explanation`. + benchmarkers (list[Benchmark], optional): A list of benchmark objects to generate evaluation results. + Default: None Examples: >>> from mindspore.explainer.explanation import GuidedBackprop, Gradient diff --git a/mindspore/explainer/benchmark/_attribution/faithfulness.py b/mindspore/explainer/benchmark/_attribution/faithfulness.py index 8233728bd2..9fa17c65ae 100644 --- a/mindspore/explainer/benchmark/_attribution/faithfulness.py +++ b/mindspore/explainer/benchmark/_attribution/faithfulness.py @@ -508,16 +508,34 @@ class Faithfulness(AttributionMetric): """ Provides evaluation on faithfulness on XAI explanations. - Faithfulness first generate saliency map with given explainers and calculate faithfulness based on different - faithfulness metric. + Three specific metrics to obtain quantified results are supported: "NaiveFaithfulness", "DeletionAUC", and + "InsertionAUC". + + For metric "NaiveFaithfulness", a series of perturbed images are created by modifying pixels + on original image. Then the perturbed images will be fed to the model and a series of output probability drops can + be obtained. The faithfulness is then quantified as the correlation between the propability drops and the saliency + map values on the same pixels (we normalize the correlation further to make them in range of [0, 1]). + + For metric "DeletionAUC", a series of perturbed images are created by accumulatively modifying pixels of the + original image to a base value (e.g. a constant). The perturbation starts from pixels with high saliency values + to pixels with low saliency values. Feeding the perturbed images into the model in order, an output probability + drop curve can be obtained. "DeletionAUC" is then obtained as the area under this probability drop curve. + + For metric "InsertionAUC", a series of perturbed images are created by accumulatively inserting pixels of the + original image to a reference image (e.g. a black image). The insertion starts from pixels with high saliency values + to pixels with low saliency values. Feeding the perturbed images into the model in order, an output probability + increase curve can be obtained. "InsertionAUC" is then obtained as the area under this curve. + + For all the three metrics, higher value indicates better faithfulness. Args: - num_labels (int): number of labels - metric (str): the specifi metric to quantify faithfulness. - Options: 'DeletionAUC', 'InsertionAUC', 'NaiveFaithfulness'. + num_labels (int): Number of labels. + metric (str, optional): The specifi metric to quantify faithfulness. + Options: "DeletionAUC", "InsertionAUC", "NaiveFaithfulness". Default: 'NaiveFaithfulness'. Examples: + >>> from mindspore.explainer.benchmark import Faithfulness >>> # init a `Faithfulness` object >>> num_labels = 10 >>> metric = "InsertionAUC" @@ -549,19 +567,22 @@ class Faithfulness(AttributionMetric): """ Evaluate faithfulness on a single data sample. - Args: - explainer (Explainer): A explainer instance object. - The 'Explainer' object see mindspore/explainer/explanation. - inputs (Tensor): data sample. Currently only support single sample at each call. - targets (Union[int, Tensor]): A target label to evaluate on. - saliency (Tensor): A saliency tensor. - - Return: - np.ndarray: result of faithfulness evaluated on explainer. + Note: + To apply `Faithfulness` to evaluate an explainer, this explainer must be initialized with a network that + contains the output activation function. Otherwise, the results will not be correct. Currently only single + sample (:math:`N=1`) at each call is supported. - Notes: - To apply `Faithfulness` to evaluate an explainer, this explainer must be initialize with a network that - contains the output activation function. Otherwise, the results will not be correct. + Args: + 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)`. + targets (Tensor, int): The label of interest. It should be a 1D or 0D tensor, or an integer. + If `targets` is a 1D tensor, its length should be the same as `inputs`. + saliency (Tensor, optional): The saliency map to be evaluated, a 4D tensor of shape :math:`(N, 1, H, W)`. + If it is None, the parsed `explainer` will generate the saliency map with `inputs` and `targets` and + continue the evaluation. Default: None. + + Returns: + numpy.ndarray, 1D array of shape :math:`(N,)`, result of faithfulness evaluated on `explainer`. Examples: >>> # init an explainer, the network should contain the output activation function. diff --git a/mindspore/explainer/benchmark/_attribution/localization.py b/mindspore/explainer/benchmark/_attribution/localization.py index e8bf83511f..4176c57457 100644 --- a/mindspore/explainer/benchmark/_attribution/localization.py +++ b/mindspore/explainer/benchmark/_attribution/localization.py @@ -38,21 +38,24 @@ def _mask_out_saliency(saliency, threshold): class Localization(AttributionMetric): - """ + r""" Provides evaluation on the localization capability of XAI methods. - We support two metrics for the evaluation os localization capability: "PointingGame" and "IoSR". + Three specific metrics to obtain quantified results are supported: "PointingGame", and "IoSR" + (Intersection over Salient Region). + For metric "PointingGame", the localization capability is calculated as the ratio of data in which the max position of their saliency maps lies within the bounding boxes. Specifically, for a single datum, given the saliency map and its bounding box, if the max point of its saliency map lies within the bounding box, the evaluation result is 1 otherwise 0. For metric "IoSR" (Intersection over Salient Region), the localization capability is calculated as the intersection - of the bounding box and the salient region over the area of the salient region. + of the bounding box and the salient region over the area of the salient region. The salient region is defined as + the region whose value exceeds :math:`\theta * \max{saliency}`. Args: - num_labels (int): number of classes in the dataset. - metric (str): specific metric to calculate localization capability. + num_labels (int): Number of classes in the dataset. + metric (str, optional): Specific metric to calculate localization capability. Options: "PointingGame", "IoSR". Default: "PointingGame". @@ -89,15 +92,22 @@ class Localization(AttributionMetric): """ Evaluate localization on a single data sample. + Note: + Currently only single sample (:math:`N=1`) at each call is supported. + Args: explainer (Explanation): The explainer to be evaluated, see `mindspore.explainer.explanation`. - inputs (Tensor): data sample. Currently only support single sample at each call. - targets (int): target label to evaluate on. - saliency (Tensor): A saliency tensor. - mask (Union[Tensor, np.ndarray]): ground truth bounding box/masks for the inputs w.r.t targets. + inputs (Tensor): A data sample, a 4D tensor of shape :math:`(N, C, H, W)`. + targets (Tensor, int): The label of interest. It should be a 1D or 0D tensor, or an integer. + If `targets` is a 1D tensor, its length should be the same as `inputs`. + saliency (Tensor, optional): The saliency map to be evaluated, a 4D tensor of shape :math:`(N, 1, H, W)`. + If it is None, the parsed `explainer` will generate the saliency map with `inputs` and `targets` and + continue the evaluation. Default: None. + mask (Tensor, numpy.ndarray): Ground truth bounding box/masks for the inputs w.r.t targets, a 4D tensor + or numpy.ndarray of shape :math:`(N, 1, H, W)`. Returns: - np.ndarray, result of localization evaluated on explainer + numpy.ndarray, 1D array of shape :math:`(N,)`, result of localization evaluated on `explainer`. Examples: >>> # init an explainer, the network should contain the output activation function. diff --git a/mindspore/explainer/explanation/_attribution/_backprop/gradcam.py b/mindspore/explainer/explanation/_attribution/_backprop/gradcam.py index 07789ad0fe..ecf07d78e0 100644 --- a/mindspore/explainer/explanation/_attribution/_backprop/gradcam.py +++ b/mindspore/explainer/explanation/_attribution/_backprop/gradcam.py @@ -43,38 +43,37 @@ class GradCAM(IntermediateLayerAttribution): r""" Provides GradCAM explanation method. - GradCAM generates saliency map at intermediate layer. - ..math: - \alpha_k^c = 1/Z \sum_i \sum_j \div{\partial{y^c}}{\partial{A_{i,j}^k}} - L_{GradCAM} = ReLu(\sum_k \alpha_k^c A^k) - For more details, please refer to the original paper: GradCAM - [https://openaccess.thecvf.com/content_ICCV_2017/papers/Selvaraju_Grad-CAM_Visual_Explanations_ICCV_2017_paper.pdf] + `GradCAM` generates saliency map at intermediate layer. The attribution is obtained as: - Args: - network (Cell): The black-box model to be explained. - layer (str): The layer name to generate the explanation at. Default: ''. - If default, the explantion will be generated at the input layer. + .. math:: + + \alpha_k^c = \frac{1}{Z} \sum_i \sum_j \frac{\partial{y^c}}{\partial{A_{i,j}^k}} + + attribution = ReLU(\sum_k \alpha_k^c A^k) - Notes: + For more details, please refer to the original paper: `GradCAM `_. + + Note: The parsed `network` will be set to eval mode through `network.set_grad(False)` and `network.set_train(False)`. If you want to train the `network` afterwards, please reset it back to training mode through the opposite operations. + Args: + network (Cell): The black-box model to be explained. + layer (str, optional): The layer name to generate the explanation, usually chosen as the last convolutional + layer for better practice. If it is '', the explantion will be generated at the input layer. + Default: ''. + Examples: + >>> from mindspore.explainer.explanation import GradCAM >>> net = resnet50(10) >>> param_dict = load_checkpoint("resnet50.ckpt") >>> load_param_into_net(net, param_dict) - >>> # bind net with its output activation if you wish, e.g. nn.Sigmoid(), - >>> # you may also use the net itself. - >>> net = nn.SequentialCell([net, nn.Sigmoid()]) >>> # specify a layer name to generate explanation, usually the layer can be set as the last conv layer. - >>> layer_name = '0.layer4' - >>> # init GradCAM with a trained network and specify the layer to obtain + >>> layer_name = 'layer4' + >>> # init GradCAM with a trained network and specify the layer to obtain attribution >>> gradcam = GradCAM(net, layer=layer_name) - >>> # parse data and the target label to be explained and get the saliency map - >>> inputs = ms.Tensor(np.random.rand([1, 3, 224, 224]), ms.float32) - >>> label = 5 - >>> saliency = gradcam(inputs, label) """ def __init__( @@ -108,9 +107,18 @@ class GradCAM(IntermediateLayerAttribution): Call function for `GradCAM`. Args: - inputs (Tensor): The input data to be explained, 4D Tensor. - targets (Union[Tensor, int]): The label of interest. It should be a 1D or 0D Tensor, or an integer. - If `targets` is a 1D Tensor, its length should be the same as `inputs`. + inputs (Tensor): The input data to be explained, a 4D tensor of shape :math:`(N, C, H, W)`. + targets (Tensor, int): The label of interest. It should be a 1D or 0D tensor, or an integer. + If it is a 1D tensor, its length should be the same as `inputs`. + + Returns: + Tensor, a 4D tensor of shape :math:`(N, 1, H, W)`. + + Examples: + >>> inputs = ms.Tensor(np.random.rand([1, 3, 224, 224]), ms.float32) + >>> label = 5 + >>> # gradcam is a GradCAM object, parse data and the target label to be explained and get the attribution + >>> saliency = gradcam(inputs, label) """ self._verify_data(inputs, targets) self._hook_cell() diff --git a/mindspore/explainer/explanation/_attribution/_backprop/gradient.py b/mindspore/explainer/explanation/_attribution/_backprop/gradient.py index 00ca94629a..fc467cceb9 100644 --- a/mindspore/explainer/explanation/_attribution/_backprop/gradient.py +++ b/mindspore/explainer/explanation/_attribution/_backprop/gradient.py @@ -59,29 +59,23 @@ class Gradient(Attribution): explanation. .. math:: - _attribution = \div{\delta{y}, \delta{x}} - Args: - network (Cell): The black-box model to be explained. + attribution = \frac{\partial{y}}{\partial{x}} - Notes: + Note: The parsed `network` will be set to eval mode through `network.set_grad(False)` and `network.set_train(False)`. If you want to train the `network` afterwards, please reset it back to training mode through the opposite operations. + Args: + network (Cell): The black-box model to be explained. + Examples: + >>> from mindspore.explainer.explanation import Gradient >>> net = resnet50(10) >>> param_dict = load_checkpoint("resnet50.ckpt") >>> load_param_into_net(net, param_dict) - >>> # bind net with its output activation if you wish, e.g. nn.Sigmoid(), - >>> # you may also use the net itself. The saliency map might be slightly different for softmax activation. - >>> net = nn.SequentialCell([net, nn.Sigmoid()]) - >>> # init Gradient with a trained network. >>> gradient = Gradient(net) - >>> # parse data and the target label to be explained and get the saliency map - >>> inputs = ms.Tensor(np.random.rand([1, 3, 224, 224]), ms.float32) - >>> label = 5 - >>> saliency = gradient(inputs, label) """ def __init__(self, network): @@ -99,9 +93,18 @@ class Gradient(Attribution): Call function for `Gradient`. Args: - inputs (Tensor): The input data to be explained, 4D Tensor. - targets (Union[Tensor, int]): The label of interest. It should be a 1D or 0D Tensor, or an integer. - If `targets` is a 1D `Tensor`, its length should be the same as `inputs`. + inputs (Tensor): The input data to be explained, a 4D tensor of shape :math:`(N, C, H, W)`. + targets (Tensor, int): The label of interest. It should be a 1D or 0D tensor, or an integer. + If it is a 1D tensor, its length should be the same as `inputs`. + + Returns: + Tensor, a 4D tensor of shape :math:`(N, 1, H, W)`. + + Examples: + >>> inputs = ms.Tensor(np.random.rand([1, 3, 224, 224]), ms.float32) + >>> label = 5 + >>> # gradient is a Gradient object, parse data and the target label to be explained and get the attribution + >>> saliency = gradient(inputs, label) """ self._verify_data(inputs, targets) inputs = unify_inputs(inputs) diff --git a/mindspore/explainer/explanation/_attribution/_backprop/modified_relu.py b/mindspore/explainer/explanation/_attribution/_backprop/modified_relu.py index f84e6dbc3c..96cb5c9156 100644 --- a/mindspore/explainer/explanation/_attribution/_backprop/modified_relu.py +++ b/mindspore/explainer/explanation/_attribution/_backprop/modified_relu.py @@ -33,6 +33,25 @@ class ModifiedReLU(Gradient): self.hooked_list = [] def __call__(self, inputs, targets): + """ + Call function for `ModifiedReLU`, inherited by "Deconvolution" and "GuidedBackprop". + + Args: + inputs (Tensor): The input data to be explained, a 4D tensor of shape :math:`(N, C, H, W)`. + targets (Tensor, int): The label of interest. It should be a 1D or 0D tensor, or an integer. + If it is a 1D tensor, its length should be the same as `inputs`. + + Returns: + Tensor, a 4D tensor of shape :math:`(N, 1, H, W)`. + + Examples: + >>> inputs = ms.Tensor(np.random.rand([1, 3, 224, 224]), ms.float32) + >>> label = 5 + >>> # explainer is a "Deconvolution" or "GuidedBackprop" object, parse data and the target label to be + >>> # explained and get the attribution + >>> saliency = explainer(inputs, label) + """ + self._verify_data(inputs, targets) inputs = unify_inputs(inputs) targets = unify_targets(targets) @@ -63,24 +82,25 @@ class Deconvolution(ModifiedReLU): """ Deconvolution explanation. - To use `Deconvolution`, the `ReLU` operations in the network must be implemented with `mindspore.nn.Cell` object - rather than `mindspore.ops.Operations.ReLU`. Otherwise, the results will not be correct. + Deconvolution method is a modified version of Gradient method. For the original ReLU operation in the network to be + explained, Deconvolution modifies the propagation rule from directly backpropagating gradients to backprpagating + positive gradients. - Args: - network (Cell): The black-box model to be explained. - - Notes: + Note: The parsed `network` will be set to eval mode through `network.set_grad(False)` and `network.set_train(False)`. If you want to train the `network` afterwards, please reset it back to training mode through the opposite - operations. + operations. To use `Deconvolution`, the `ReLU` operations in the network must be implemented with + `mindspore.nn.Cell` object rather than `mindspore.ops.Operations.ReLU`. Otherwise, the results will not be + correct. + + Args: + network (Cell): The black-box model to be explained. Examples: + >>> from mindspore.explainer.explanation import Deconvolution >>> net = resnet50(10) >>> param_dict = load_checkpoint("resnet50.ckpt") >>> load_param_into_net(net, param_dict) - >>> # bind net with its output activation if you wish, e.g. nn.Sigmoid(), - >>> # you may also use the net itself. The saliency map might be slightly different for softmax activation. - >>> net = nn.SequentialCell([net, nn.Sigmoid()]) >>> # init Gradient with a trained network. >>> deconvolution = Deconvolution(net) >>> # parse data and the target label to be explained and get the saliency map @@ -95,26 +115,27 @@ class Deconvolution(ModifiedReLU): class GuidedBackprop(ModifiedReLU): """ - Guided-Backpropation explanation. + Guided-Backpropagation explanation. - To use `GuidedBackprop`, the `ReLU` operations in the network must be implemented with `mindspore.nn.Cell` object - rather than `mindspore.ops.Operations.ReLU`. Otherwise, the results will not be correct. - - Args: - network (Cell): The black-box model to be explained. + Guided-Backpropagation method is an extension of Gradient method. On top of the original ReLU operation in the + network to be explained, Guided-Backpropagation introduces another ReLU operation to filter out the negative + gradients during backpropagation. - Notes: + Note: The parsed `network` will be set to eval mode through `network.set_grad(False)` and `network.set_train(False)`. If you want to train the `network` afterwards, please reset it back to training mode through the opposite - operations. + operations. To use `GuidedBackprop`, the `ReLU` operations in the network must be implemented with + `mindspore.nn.Cell` object rather than `mindspore.ops.Operations.ReLU`. Otherwise, the results will not be + correct. + + Args: + network (Cell): The black-box model to be explained. Examples: + >>> from mindspore.explainer.explanation import GuidedBackprop >>> net = resnet50(10) >>> param_dict = load_checkpoint("resnet50.ckpt") >>> load_param_into_net(net, param_dict) - >>> # bind net with its output activation if you wish, e.g. nn.Sigmoid(), - >>> # you may also use the net itself. The saliency map might be slightly different for softmax activation. - >>> net = nn.SequentialCell([net, nn.Sigmoid()]) >>> # init Gradient with a trained network. >>> gbp = GuidedBackprop(net) >>> # parse data and the target label to be explained and get the saliency map