mindspore_xai.explainer

查看源文件

深度神经网络解释器。

class mindspore_xai.explainer.Gradient(network)[源代码]

Gradient 解释方法。

Gradient 是最简单的归因方法,它使用输出对输入的梯度作为解释。

\[attribution = \frac{\partial{y}}{\partial{x}}\]

说明

解析后的 network 将通过 network.set_grad(False)network.set_train(False) 设为eval模式。如果想在之后训练 network,请通过相反的方式将其重置为训练模式。

参数:
  • network (Cell) - 要解释的黑盒模型。

输入:
  • inputs (Tensor) - 要解释的输入数据,shape为 \((N, C, H, W)\) 的4D Tensor。

  • targets (Tensor, int, tuple, list) - 目标分类,1D/Scalar Tensor或integer,或integer类型的tuple/list。如果是1D Tensor、tuple或list,其长度应为 \(N\)

  • ret (str, 可选) - 返回对象的类型。'tensor' 表示返回Tensor ,而 'image' 代表返回PIL.Image.Image的list。默认值: 'tensor'

  • show (bool, 可选) - 显示热力图, None 代表自动,只会在JupyterLab上显示。默认值: None

输出:

Tensor,shape为 \((N, 1, H, W)\) 的4D Tensor,热力图。如果 ret 设为 'image',输出list[list[PIL.Image.Image]],归一化热力图。

异常:
  • TypeError - 参数或输入类型错误。

  • ValueError - 输入值错误。

支持平台:

Ascend GPU

样例:

>>> import numpy as np
>>> import mindspore as ms
>>> from mindspore import set_context, PYNATIVE_MODE
>>> from mindspore_xai.explainer import Gradient
>>>
>>> set_context(mode=PYNATIVE_MODE)
>>> # The detail of LeNet5 is shown in models.official.cv.lenet.src.lenet.py
>>> net = LeNet5(10, num_channel=3)
>>> gradient = Gradient(net)
>>> inputs = ms.Tensor(np.random.rand(1, 3, 32, 32), ms.float32)
>>> label = 5
>>> saliency = gradient(inputs, label)
>>> print(saliency.shape)
(1, 1, 32, 32)
class mindspore_xai.explainer.Deconvolution(network)[源代码]

Deconvolution 解释方法。

Deconvolution 方法是梯度方法的改进版本。它把要解释的网络的 ReLU 传播规则由直接反向传播梯度修改为反向传播正梯度。

说明

解析后的 network 将通过 network.set_grad(False)network.set_train(False) 设为eval模式。如果想在之后训练 network ,请通过相反的方式将其重置为训练模式。在使用 Deconvolution 时,网络中的 ReLU 必须用 mindspore.nn.Cell 类来实现,而不是用 mindspore.ops.Operations.ReLU 。否则,将会导致错误结果。

参数:
  • network (Cell) - 要解释的黑盒模型。

输入:
  • inputs (Tensor) - 要解释的输入数据,shape为 \((N, C, H, W)\) 的4D Tensor。

  • targets (Tensor, int, tuple, list) - 目标分类。1D/Scalar Tensor、integer,或integer类型的tuple/list。如果是1D Tensor、tuple或list,其长度应与 inputs 一致。

  • ret (str, 可选) - 返回对象的类型。'tensor' 代表返回 Tensor,而 'image' 代表返回PIL.Image.Image的list。默认值: 'tensor'

  • show (bool, 可选) - 显示热力图, None 代表自动,只会在JupyterLab上显示。默认值: None

输出:

Tensor,shape为 \((N, 1, H, W)\) 的 4D Tensor。如果 ret 设为 'image',输出list[list[PIL.Image.Image]],归一化热力图。

异常:
  • TypeError - 参数或输入类型错误。

  • ValueError - 输入值错误。

支持平台:

Ascend GPU

样例:

>>> import numpy as np
>>> import mindspore as ms
>>> from mindspore import set_context, PYNATIVE_MODE
>>> from mindspore_xai.explainer import Deconvolution
>>>
>>> # only PYNATIVE_MODE is supported
>>> set_context(mode=PYNATIVE_MODE)
>>> # The detail of LeNet5 is shown in models.official.cv.lenet.src.lenet.py
>>> net = LeNet5(10, num_channel=3)
>>> deconvolution = Deconvolution(net)
>>> # parse data and the target label to be explained and get the saliency map
>>> inputs = ms.Tensor(np.random.rand(1, 3, 32, 32), ms.float32)
>>> label = 5
>>> saliency = deconvolution(inputs, label)
>>> print(saliency.shape)
(1, 1, 32, 32)
class mindspore_xai.explainer.GuidedBackprop(network)[源代码]

GuidedBackprop 解释方法。

GuidedBackprop 方法是梯度方法的扩展。在要解释的网络的原 ReLU 上,它引入了另一个 ReLU 来过滤反向传播期间的负梯度。

说明

解析后的 network 将通过 network.set_grad(False)network.set_train(False) 设为eval模式。如果想在之后训练 network ,请通过相反的方式将其重置为训练模式。要使用 GuidedBackprop 时,网络中的 ReLU 必须用 mindspore.nn.Cell 类来实现,而不是用 mindspore.ops.Operations.ReLU 。否则,将会导致错误结果。

参数:
  • network (Cell) - 要解释的黑盒模型。

输入:
  • inputs (Tensor) - 要解释的输入数据,shape为 \((N, C, H, W)\) 的4D Tensor。

  • targets (Tensor, int, tuple, list) - 目标分类。1D/Scalar Tensor、integer,或integer类型的tuple/list。如果是1D Tensor、tuple或list,其长度应为 \(N\)

  • ret (str, 可选) - 返回对象的类型。'tensor' 代表返回Tensor,而 'image' 代表返回PIL.Image.Image的list。默认值: 'tensor'

  • show (bool, 可选) - 显示热力图, None 代表自动,只会在JupyterLab上显示。默认值: None

输出:

Tensor,shape为 \((N, 1, H, W)\) 的4D Tensor,热力图。如果 ret 设为 'image',输出list[list[PIL.Image.Image]],归一化热力图。

异常:
  • TypeError - 参数或输入类型错误。

  • ValueError - 输入值错误。

支持平台:

Ascend GPU

样例:

>>> import numpy as np
>>> import mindspore as ms
>>> from mindspore_xai.explainer import GuidedBackprop
>>> from mindspore import set_context, PYNATIVE_MODE
>>>
>>> # only PYNATIVE_MODE is supported
>>> set_context(mode=PYNATIVE_MODE)
>>> # The detail of LeNet5 is shown in model_zoo.official.cv.lenet.src.lenet.py
>>> net = LeNet5(10, num_channel=3)
>>> gbp = GuidedBackprop(net)
>>> # feed data and the target label to be explained and get the saliency map
>>> inputs = ms.Tensor(np.random.rand(1, 3, 32, 32), ms.float32)
>>> label = 5
>>> saliency = gbp(inputs, label)
>>> print(saliency.shape)
(1, 1, 32, 32)
class mindspore_xai.explainer.GradCAM(network, layer='')[源代码]

GradCAM 解释方法。

GradCAM 会在中间层生成热力图。属性获取方式为:

\[ \begin{align}\begin{aligned}\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)\end{aligned}\end{align} \]

有关更多详情,请参考原始论文:GradCAM

说明

解析后的 network 将通过 network.set_grad(False)network.set_train(False) 设为eval模式。如果想在之后训练 network ,请通过相反的方式将其重置为训练模式。

参数:
  • network (Cell) - 要解释的黑盒模型。

  • layer (str, 可选) - 生成解释的层名称,最好的方法是选择最后一个卷积层。如果设为 '',将在输入层生成解释。默认值:''

输入:
  • inputs (Tensor) - 要解释的输入数据,shape为 \((N, C, H, W)\) 的4D Tensor。

  • targets (Tensor, int, tuple, list) - 目标分类,1D/Scalar Tensor、integer,或integer类型的tuple/list。如果是1D Tensor、tuple或list,其长度应为 \(N\)

  • ret (str, 可选) - 返回对象的类型。'tensor' 代表返回Tensor,而 'image' 代表返回PIL.Image.Image的list。默认值: 'tensor'

  • show (bool, 可选) - 显示热力图, None 代表自动,只会在JupyterLab上显示。默认值: None

输出:

Tensor,shape为 \((N, 1, H, W)\) 的4D Tensor,热力图。如果 ret 设为 'image',输出list[list[PIL.Image.Image]],归一化热力图。

异常:
  • TypeError - 参数或输入类型错误。

  • ValueError - 输入值错误。

支持平台:

Ascend GPU

样例:

>>> import numpy as np
>>> import mindspore as ms
>>> from mindspore_xai.explainer import GradCAM
>>> from mindspore import set_context, PYNATIVE_MODE
>>>
>>> # only PYNATIVE_MODE is supported
>>> set_context(mode=PYNATIVE_MODE)
>>> # The detail of LeNet5 is shown in models.official.cv.lenet.src.lenet.py
>>> net = LeNet5(10, num_channel=3)
>>> # specify a layer name to generate explanation, usually the layer can be set as the last conv layer.
>>> layer_name = 'conv2'
>>> # init GradCAM with a trained network and specify the layer to obtain attribution
>>> gradcam = GradCAM(net, layer=layer_name)
>>> inputs = ms.Tensor(np.random.rand(1, 3, 32, 32), ms.float32)
>>> label = 5
>>> saliency = gradcam(inputs, label)
>>> print(saliency.shape)
(1, 1, 32, 32)
class mindspore_xai.explainer.SHAPGradient(network, features, feature_names=None, class_names=None, num_neighbours=200, max_features=10)[源代码]

SHAP gradient 解释方法。

使用预期梯度,即为集成梯度的扩展,以解释网络。

说明

解析后的 network 将通过 network.set_grad(False)network.set_train(False) 设为eval模式。如果想在之后训练 network ,请通过相反的方式将其重置为训练模式。

参数:
  • network (Cell) - 要解释的 MindSpore cell。分类模型接受shape为 \((N, K)\) 的2D Tensor作为输入,并输出shape为 \((N, L)\) 的2D Tensor。而回归模型接受shape为 \((N, K)\) 的2D Tensor作为输入,并输出shape为 \((N)\) 的1D Tensor。

  • features (Tensor) - shape为 \((N, K)\) 的2DTensor,N是样本数,而K是特征数。用于集成特征的背景数据集,接受全部或部分的训练数据集。

  • feature_names (list, 可选) - 训练数据中的列的名称(string)的list。默认值: None

  • class_names (list, 可选) - 类名的list,排序根据分类器的类名排序。如果没有,类名会设为’0’、’1’、…。默认值: None

  • num_neighbours (int, 可选) - 用于估计shap数值的子集数。默认值:200

  • max_features (int, 可选) - 最多解释多少个特征。默认值:10

输入:
  • inputs (Tensor) - 要解释的输入数据,shape为 \((N, K)\) 的 2D float Tensor。

  • targets (Tensor, numpy.ndarray, list, int, 可选) - 要解释的目标分类。当 target 是integer时,生成该目标的归因图(attribution map)。而当 targets 为Tensor、numpy数组或list时,shape会是 \((N, L)\) ,L是每个样本的标签数量, \((N,)\) 或者 \(()\) 。默认值:0

  • show (bool, 可选) - 显示解释图像,None 代表自动,只会在JupyterLab上显示。默认值: None

输出:

Tensor,shape为 \((N, L, K)\) 的3D Tensor。第一个维度代表输入。第二个维度代表目标。第三个维度代表特征的权重。

支持平台:

Ascend GPU

样例:

>>> import numpy as np
>>> import mindspore as ms
>>> import mindspore.nn as nn
>>> from mindspore import set_context, PYNATIVE_MODE
>>> from mindspore_xai.explainer import SHAPGradient
>>>
>>> set_context(mode=PYNATIVE_MODE)
>>> # Linear classification model
>>> class LinearNet(nn.Cell):
...     def __init__(self, num_inputs, num_class):
...         super(LinearNet, self).__init__()
...         self.fc = nn.Dense(num_inputs, num_class, activation=nn.Softmax())
...     def construct(self, x):
...         x = self.fc(x)
...         return x
>>> net = LinearNet(4, 3)
>>> # use iris data as example
>>> feature_names = ['sepal length (cm)', 'sepal width (cm)', 'petal length (cm)', 'petal width (cm)']
>>> class_names = ['setosa', 'versicolor', 'virginica']
>>> training_data = ms.Tensor(np.random.rand(10, 4), ms.float32)
>>> shap = SHAPGradient(net, training_data, feature_names=feature_names, class_names=class_names)
>>> inputs = ms.Tensor(np.random.rand(2, 4), ms.float32)
>>> targets = ms.Tensor([[1, 2], [1, 2]], ms.int32)
>>> exps = shap(inputs, targets)
>>> print(exps.shape)
(2, 2, 4)
class mindspore_xai.explainer.SHAPKernel(predictor, features, feature_names=None, class_names=None, num_neighbours=5000, max_features=10)[源代码]

Kernel SHAP 解释方法。

使用Kernel SHAP方法解释任何函数的输出。

参数:
  • predictor (Cell, Callable) - 要解释的黑盒模型,一个网络或函数。分类模型接受shape为 \((N, K)\) 的2D 数组/Tensor作为输入,并输出shape为 \((N, L)\) 的2D数组/Tensor。而回归模型接受shape为 \((N, K)\) 的2D数组/Tensor作为输入,并输出shape为 \((N)\) 的1D数组/Tensor。

  • features (Tensor, numpy.ndarray) - 2D Tensor或 \((N, K)\) 的2D numpy数组,N是样本数,而K是特征数。用于集成特征的背景数据集,接受全部或部分的训练数据集。

  • feature_names (list, 可选) - 训练数据中的列的名称(string)的list。默认值: None

  • class_names (list, 可选) - 类名的 list,排序根据分类器的类名排序。如果没有,类名会设为‘0’、‘1’、…。默认值: None

  • num_neighbours (int, 可选) - 用于估计shap数值的子集数。默认值:5000

  • max_features (int, 可选) - 最多解释多少个特征。默认值:10

输入:
  • inputs (Tensor, numpy.ndarray) - 要解释的输入数据,2D float Tensor或shape为 \((N, K)\) 的2D float numpy数组。

  • targets (Tensor, numpy.ndarray, list, int, 可选) - 要解释的目标分类。当 targets 是integer时,生成该目标的归因图。而当 target 是一个Tensor、numpy数组或list时,shape会是 \((N, L)\) ,L是每个样本的标签数量, \((N,)\) 或者 \(()\) 。默认值:0

  • show (bool, 可选) - 显示解释图像,None 代表自动,只会在JupyterLab上显示。默认值:None

输出:

Tensor,shape为 \((N, L, K)\) 的3D Tensor。第一个维度代表输入。第二个维度代表目标。第三个维度代表特征的权重。

支持平台:

Ascend GPU

样例:

>>> import numpy as np
>>> import mindspore as ms
>>> import mindspore.nn as nn
>>> from mindspore_xai.explainer import SHAPKernel
>>> # Linear classification model
>>> class LinearNet(nn.Cell):
...     def __init__(self, num_inputs, num_class):
...         super(LinearNet, self).__init__()
...         self.fc = nn.Dense(num_inputs, num_class, activation=nn.Softmax())
...     def construct(self, x):
...         x = self.fc(x)
...         return x
>>> net = LinearNet(4, 3)
>>> # use iris data as example
>>> feature_names = ['sepal length (cm)', 'sepal width (cm)', 'petal length (cm)', 'petal width (cm)']
>>> class_names = ['setosa', 'versicolor', 'virginica']
>>> training_data = ms.Tensor(np.random.rand(10, 4), ms.float32)
>>> shap = SHAPKernel(net, training_data, feature_names=feature_names, class_names=class_names)
>>> inputs = ms.Tensor(np.random.rand(2, 4), ms.float32)
>>> targets = ms.Tensor([[1, 2], [1, 2]], ms.int32)
>>> exps = shap(inputs, targets)
>>> print(exps.shape)
(2, 2, 4)
class mindspore_xai.explainer.Occlusion(network, activation_fn, perturbation_per_eval=32)[源代码]

Occlusion 解释方法。

Occlusion 使用滑动窗口将像素换为一个参考值,例如常数,并计算新输出与原输出的差异。像素的重要性就是这些滑动窗口所引致的平均输出差异。

有关更多详情,请参考原始论文:Visualizing and Understanding Convolutional Networks

说明

目前,每个调用仅支持单个样本( \(N=1\) )。

参数:
  • network (Cell) - 要解释的黑盒模型。

  • activation_fn (Cell) - 将logits转换为预测概率的激活层。单标签分类任务通常使用 nn.Softmax ,而多标签分类任务较常使用 nn.Sigmoid 。用户也可以将自定义的 activation_fn 与网络结合,最终输出便是输入的概率。

  • perturbation_per_eval (int, 可选) - 在推理扰动样本期间,每次推理的扰动数。在内存容许情况下,通常此数字越大,便越快得到解释。默认值:32

输入:
  • inputs (Tensor) - 要解释的输入数据,shape为 \((N, C, H, W)\) 的4D Tensor 。

  • targets (Tensor, int, tuple, list) - 目标分类,1D/Scalar Tensor、integer或integer的tuple/list。如果是1D Tensor、tuple 或 list,其长度应为 \(N\)

  • ret (str, 可选) - 返回对象类型。'tensor' 代表返回Tensor,而 'image' 代表返回PIL.Image.Image的list。默认值: 'tensor'

  • show (bool, 可选) - 显示热力图, None 代表自动,只会在JupyterLab上显示。默认值: None

输出:

Tensor,shape为 \((N, 1, H, W)\) 的4D Tensor,热力图。如果 ret 设为 'image',输出list[list[PIL.Image.Image]],归一化热力图。

异常:
  • TypeError - 参数或输入类型错误。

  • ValueError - 输入值错误。

支持平台:

Ascend GPU

样例:

>>> import numpy as np
>>> import mindspore as ms
>>> from mindspore_xai.explainer import Occlusion
>>> from mindspore import set_context, PYNATIVE_MODE
>>>
>>> set_context(mode=PYNATIVE_MODE)
>>> # The detail of LeNet5 is shown in models.official.cv.lenet.src.lenet.py
>>> net = LeNet5(10, num_channel=3)
>>> # initialize Occlusion explainer with the pretrained model and activation function
>>> activation_fn = ms.nn.Softmax() # softmax layer is applied to transform logits to probabilities
>>> occlusion = Occlusion(net, activation_fn=activation_fn)
>>> input_x = ms.Tensor(np.random.rand(1, 3, 32, 32), ms.float32)
>>> label = ms.Tensor([1], ms.int32)
>>> saliency = occlusion(input_x, label)
>>> print(saliency.shape)
(1, 1, 32, 32)
class mindspore_xai.explainer.RISE(network, activation_fn, perturbation_per_eval=32)[源代码]

RISE 解释方法:用随机输入采样来解释黑盒模型。

RISE 是一种基于扰动的方法,通过在多个随机二进制掩码上采样来生成归因图。原始图像 \(I\) 被随机屏蔽,然后输入到黑盒模型以获取预测概率,最后的归因图便是这些随机掩码 \(M_i\) 的加权和,而权重是目标节点上的相应输出:

\[attribution = \sum_{i}f_c(I\odot M_i) M_i\]

有关更多详情,请参考原始论文:RISE

参数:
  • network (Cell) - 要解释的黑盒模型。

  • activation_fn (Cell) - 将logits转换为预测概率的激活层。单标签分类任务通常使用 nn.Softmax ,而多标签分类任务较常使用 nn.Sigmoid 。用户也可以将自定义的 activation_fn 与网络结合,最终输出便是输入的概率。

  • perturbation_per_eval (int, 可选) - 推理扰动样本期间,每次推理的扰动数。在内存容许情况下,通常此数字越大,便越快得到解释。默认值:32

输入:
  • inputs (Tensor) - 要解释的输入数据,shape为 \((N, C, H, W)\) 的 4D Tensor。

  • targets (Tensor, int) - 目标分类。当 targets 是integer时,生成该目标的归因图。而当 targets 是Tensor时,shape会是 \((N, L)\) ,L是每个样本的标签数量,或 \((N,)\) \(()\)

  • ret (str, 可选) - 返回对象类型。'tensor' 代表返回Tensor,'image' 代表返回PIL.Image.Image的list。默认值: 'tensor'

  • show (bool, 可选) - 显示热力图, None 代表自动,只会在JupyterLab上显示。默认值: None

输出:

Tensor,4D Tensor,当目标是shape为 \((N, L)\) 的Tensor时,输出的shape便会是 \((N, L, H, W)\) ,否则会是 \((N, 1, H, W)\) ,热力图。如果 ret 设为 'image',输出 list[list[PIL.Image.Image]],归一化热力图。

异常:
  • TypeError - 参数或输入类型错误。

  • ValueError - 输入值错误。

支持平台:

Ascend GPU

样例:

>>> import numpy as np
>>> import mindspore as ms
>>> from mindspore_xai.explainer import RISE
>>> from mindspore import set_context, PYNATIVE_MODE
>>>
>>> set_context(mode=PYNATIVE_MODE)
>>> # The detail of LeNet5 is shown in models.official.cv.lenet.src.lenet.py
>>> net = LeNet5(10, num_channel=3)
>>> # initialize RISE explainer with the pretrained model and activation function
>>> activation_fn = ms.nn.Softmax() # softmax layer is applied to transform logits to probabilities
>>> rise = RISE(net, activation_fn=activation_fn)
>>> # given an instance of RISE, saliency map can be generate
>>> inputs = ms.Tensor(np.random.rand(2, 3, 32, 32), ms.float32)
>>> # when 'targets' is an integer
>>> targets = 5
>>> saliency = rise(inputs, targets)
>>> print(saliency.shape)
(2, 1, 32, 32)
>>> # 'targets' can also be a 2D tensor
>>> targets = ms.Tensor([[5], [1]], ms.int32)
>>> saliency = rise(inputs, targets)
>>> print(saliency.shape)
(2, 1, 32, 32)
class mindspore_xai.explainer.RISEPlus(ood_net, network, activation_fn, perturbation_per_eval=32)[源代码]

RISEPlus 解释方法。

RISEPlus 是一种基于扰动的方法,通过在多个随机二进制掩码上采样来生成归因图。它采用分布外检测器来产生”inlier 分数”,并用于估计从分布生成样本的概率,然后将”inlier 分数”聚合到随机掩码的加权和,而权重是目标节点上的相应输出:

\[attribution = \sum_{i}s_if_c(I\odot M_i) M_i\]

有关更多详情,请参考原始论文: Resisting Out-of-Distribution Data Problem in Perturbation of XAI

参数:
  • ood_net (OoDNet) - 用于生成”inlier 分数”的 OoD 网络。

  • network (Cell) - 要解释的黑盒模型。

  • activation_fn (Cell) - 将logits转换为预测概率的激活层。单标签分类任务通常使用 nn.Softmax ,而多标签分类任务较常使用 nn.Sigmoid 。用户还可以将自己自定义的 activation_fn 与网络结合,最终输出便是输入的概率。

  • perturbation_per_eval (int, 可选) - 在推理扰动样本期间,每次推理的扰动数。在内存容许情况下,通常此数字越大,便越快得到解释。默认值:32

输入:
  • inputs (Tensor) - 要解释的输入数据,shape为 \((N, C, H, W)\) 的4D Tensor。

  • targets (Tensor, int) - 要解释的目标分类。当 targets 是integer时,生成该目标的归因图。而当 targets 是Tensor时,shape为 \((N, L)\) ,L是每个样本的标签数量,或 \((N,)\) \(()\)

  • ret (str, 可选) - 返回对象类型。'tensor' 代表返回Tensor,'image' 代表返回PIL.Image.Image的list。默认值: 'tensor'

  • show (bool, 可选) - 显示热力图, None 代表自动,只会在JupyterLab上显示。默认值: None

输出:

Tensor,4D Tensor,当目标是shape为 \((N, L)\) 的Tensor时,输出的shape便会是 \((N, L, H, W)\),否则会是 \((N, 1, H, W)\),热力图。如果 ret 设为 'image',输出list[list[PIL.Image.Image]],归一化热力图。

异常:
  • TypeError - 参数或输入类型错误。

  • ValueError - 输入值错误。

支持平台:

Ascend GPU

样例:

>>> import numpy as np
>>> import mindspore as ms
>>> from mindspore import nn, set_context, PYNATIVE_MODE
>>> from mindspore.common.initializer import Normal
>>> from mindspore_xai.explainer import RISEPlus
>>> from mindspore_xai.tool.cv import OoDNet
>>>
>>>
>>> class MyLeNet5(nn.Cell):
...    def __init__(self, num_class, num_channel):
...        super(MyLeNet5, self).__init__()
...
...        # must add the following 2 attributes to your model
...        self.num_features = 84 # no. of features, int
...        self.output_features = False # output features flag, bool
...
...        self.conv1 = nn.Conv2d(num_channel, 6, 5, pad_mode='valid')
...        self.conv2 = nn.Conv2d(6, 16, 5, pad_mode='valid')
...        self.relu = nn.ReLU()
...        self.max_pool2d = nn.MaxPool2d(kernel_size=2, stride=2)
...        self.flatten = nn.Flatten()
...        self.fc1 = nn.Dense(16 * 5 * 5, 120, weight_init=Normal(0.02))
...        self.fc2 = nn.Dense(120, self.num_features, weight_init=Normal(0.02))
...        self.fc3 = nn.Dense(self.num_features, num_class, weight_init=Normal(0.02))
...
...    def construct(self, x):
...        x = self.conv1(x)
...        x = self.relu(x)
...        x = self.max_pool2d(x)
...        x = self.conv2(x)
...        x = self.relu(x)
...        x = self.max_pool2d(x)
...        x = self.flatten(x)
...        x = self.relu(self.fc1(x))
...        x = self.relu(self.fc2(x))
...
...        # return the features tensor if output_features is True
...        if self.output_features:
...            return x
...
...        x = self.fc3(x)
...        return x
>>>
>>> # only PYNATIVE_MODE is supported
>>> set_context(mode=PYNATIVE_MODE)
>>> # prepare trained classifier
>>> net = MyLeNet5(10, num_channel=3)
>>> # prepare OoD network
>>> ood_net = OoDNet(net, 10)
>>> # initialize RISEPlus explainer with the pretrained model and activation function
>>> activation_fn = ms.nn.Softmax() # softmax layer is applied to transform logits to probabilities
>>> riseplus = RISEPlus(ood_net, net, activation_fn=activation_fn)
>>> # given an instance of RISEPlus, saliency map can be generate
>>> inputs = ms.Tensor(np.random.rand(2, 3, 32, 32), ms.float32)
>>> # when 'targets' is an integer
>>> targets = 5
>>> saliency = riseplus(inputs, targets)
>>> print(saliency.shape)
(2, 1, 32, 32)
class mindspore_xai.explainer.LIMETabular(predictor, train_feat_stats, feature_names=None, categorical_features_indexes=None, class_names=None, num_perturbs=5000, max_features=10)[源代码]

Lime Tabular 解释方法。

解释表格(即矩阵)数据的预测。数值特征会根据训练数据中的平均值和标准差,从 Normal(0,1) 分布中采样并以逆向均值中心化和缩放来进行扰动。而分类特征会根据训练分布采样进行扰动,当采样值与被解释的样本相同时,将生成一个数值为1的二进制特征。

参数:
  • predictor (Cell, Callable) - 要解释的黑盒模型,一个网络或函数。分类模型接受shape为 \((N, K)\) 的2D 数组/Tensor作为输入,并输出shape为 \((N, L)\) 的2D数组/Tensor。而回归模型接受shape为 \((N, K)\) 的2D 数组/Tensor作为输入,并输出shape为 \((N)\) 的1D数组/Tensor。

  • train_feat_stats (dict) - 含有训练数据统计详细信息的dict对象。统计信息可以使用静态方法 LIMETabular.to_feat_stats(training_data) 生成。

  • feature_names (list, 可选) - 训练数据中的名称(string)的list。默认值: None

  • categorical_features_indexes (list, 可选) - 分类列的索引(ints)的list,这些列中的值必须是integer。其他列将被视为连续的。默认值: None

  • class_names (list, 可选) - 类名的list,排序根据分类器的类名排序。如果没有,类名会设为’0’、’1’、…。默认值: None

  • num_perturbs (int, 可选) - 学习线性模型的邻域大小。默认值:5000

  • max_features (int, 可选) - 最多解释多少个特征。默认值:10

输入:
  • inputs (Tensor, numpy.ndarray) - 要解释的输入数据,2D float Tensor或shape为 \((N, K)\) 的2D float numpy 数组。

  • targets (Tensor, numpy.ndarray, list, int, 可选) - 要解释的目标分类。当 targets 是integer时,生成该目标的归因图。而当 targets 是Tensor、numpy数组或list时,shape会是 \((N, L)\),L是每个样本的标签数量, \((N,)\) 或者 \(()\)。对于回归模型,此参数将被忽略。默认值:0

  • show (bool, 可选) - 显示解释图像,None 代表自动,只会在JupyterLab上显示。默认值: None

输出:

list[list[list[(str, float)]]],一个tuple类的3D list。第一个维度代表输入。第二个维度代表目标。第三个维度代表特征。tuple代表特征的描述和权重。

异常:
  • TypeError - 参数或输入类型错误。

  • ValueError - 输入值错误。

支持平台:

Ascend GPU

样例:

>>> import numpy as np
>>> import mindspore as ms
>>> import mindspore.nn as nn
>>> from mindspore_xai.explainer import LIMETabular
>>> # Linear classification model
>>> class LinearNet(nn.Cell):
...     def __init__(self, num_inputs, num_class):
...         super(LinearNet, self).__init__()
...         self.fc = nn.Dense(num_inputs, num_class, activation=nn.Softmax())
...     def construct(self, x):
...         x = self.fc(x)
...         return x
>>> net = LinearNet(4, 3)
>>> # use iris data as example
>>> feature_names = ['sepal length (cm)', 'sepal width (cm)', 'petal length (cm)', 'petal width (cm)']
>>> class_names = ['setosa', 'versicolor', 'virginica']
>>> train = ms.Tensor(np.random.rand(10, 4), ms.float32)
>>> stats = LIMETabular.to_feat_stats(train, feature_names=feature_names)
>>> lime = LIMETabular(net, stats, feature_names=feature_names, class_names=class_names)
>>> inputs = ms.Tensor(np.random.rand(2, 4), ms.float32)
>>> targets = ms.Tensor([[1, 2], [1, 2]], ms.int32)
>>> exps = lime(inputs, targets)
>>> # output is a 3-dimension list of tuple
>>> print((len(exps), len(exps[0]), len(exps[0][0])))
(2, 2, 4)
load_feat_stats(file)[源代码]

从文件加载特征统计信息。

参数:
  • file (str, Path, IOBase) - 文件路径或流。

返回:

dict,训练数据统计信息

save_feat_stats(stats, file)[源代码]

将特征统计信息保存到文件。

参数:
  • stats (dict) - 训练数据统计信息。

  • file (str, Path, IOBase) - 文件路径或流。

to_feat_stats(features, feature_names=None, categorical_features_indexes=None)[源代码]

将特征转换为特征统计信息。

参数:
  • features (Tensor, numpy.ndarray) - 训练数据。

  • feature_names (list, 可选) - 特征名称。默认值: None

  • categorical_features_indexes (list, 可选) - 分类列的索引(ints)的list,这些列中的值必须是integer。其他列将被视为连续的。默认值:None

返回:

dict,训练数据统计信息。

class mindspore_xai.explainer.PseudoLinearCoef(predictor, num_classes, class_names=None, feature_names=None, stepwise=False, threshold=0.5, monte_carlo=1000, riemann=1000, batch_size=2000, eps=1e-09)[源代码]

分类器的伪线性系数(PLC)。

伪线性系数是一个全局归因方法,从数据分布的角度来看,它用来度量分类器决策边界周围的特征敏感度。

A类的伪线性系数:

\[\vec{R}(A)=\int \vec{S}(A,nearest_{A}(x),x)p_{\neg A}(x)dx\]

A类(目标类)相对于B类(视点类)的伪线性系数,称为相对伪线性系数:

\[\vec{R}(A,B)=\int \vec{S}(A,nearest_{A}(x),x)p_{B}(x)dx\]

其中:

\[ \begin{align}\begin{aligned}nearest_A(x):=\underset{g\in G}{argmin}(\left \| g-x \right \|)\text{ }s.t.\text{ } g\neq x,f_A(g) \geq \xi\\\begin{split}\vec{S}(A,a,x)=\left\{\begin{matrix} \vec{0} & \text{if }f_A(x)\geq \xi \\ \frac{a-x}{\left \| a-x \right \|} & \text{if }f_A(\cdot )\text{ is a step function}\\ \frac{(a-x)(f_{A}(a)-f_A(x))}{\left \| a-x \right \|^{2}\int_{0}^{1}h(f_A(u(t)))dt} & \text{else} \end{matrix}\right.\end{split}\end{aligned}\end{align} \]
\[u(t)=ta+(1-t)x\]
\[h(f_{A})=-f_{A}log_2(f_{A})-(1-f_A)log_2(1-f_A)\]

\(G\) 代表样本全集, \(f_A(\cdot )\) 代表A类的预测概率, \(\xi\) 代表决策阀值,通常设为0.5。 \(p_{\neg A}\)\(p_{B}\) 分别代表非A类和B类的样本分布的概率密度函數。请注意在伪线性系数中样本的类别是由分类器决定, 而不是使用ground truth标签。

说明

如果 predictor 是一个函数, stepwiseFalse 和在graph mode上运行, predictor 必须符合 static graph syntax 的语法。如果有很多样本被分类到多于一个类别,PLC可能会不准确。

参数:
  • predictor (Cell, Callable) - 要解释的分类器 \(f(\cdot )\) ,输入只接受一个shape为 \((N, K)\) 的Tensor,并输出一个shape为 \((N, L)\) 的概率Tensor。 \(K\) 是特征的数量,输入和输出的Tensor dtype只能是 ms.float32ms.float64

  • num_classes (int) - 类的数量 \(L\)

  • class_names (list[str], tuple[str], 可选) - 类名的list/tuple,排序根据分类器的类名排序。如果没有,类名会设为’Class 0’、’Class 1’、…。默认值: None

  • feature_names (list[str], tuple[str], 可选) - 训练数据中的名称的list/tuple。如果没有,类名会设为’feature 0’、’feature 1’、…。默认值: None

  • stepwise (bool, 可选) - 如果 predictor 只输出0和1,请设置为 True。默认值: False

  • threshold (float, 可选) - 分类的决策阀值 \(\xi\) 。默认值:0.5

  • monte_carlo (int, 可选) - 计算积分 \(\vec{R}\) 的蒙特卡洛样本的数量。默认值:1000。数值越大,计算时间就越长和越准确。

  • riemann (int, 可选) - 计算积分 \(\int_{0}^{1}h(f_A(u(t)))dt\) 的黎曼和分割数量。默认值:1000。数值越大,计算时间就越长和越准确。

  • batch_size (int, 可选) - 寻找最近的样本时 predictor 的批量大小。默认值:2000

  • eps (float, 可选) - 误差范围。数值必须大于0。默认值:1e-9

输入:
  • features (Tensor) - 样本全集 \(G\)。实际上,它通常是训练集或其随机子集,shape为 \((|G|, K)\)\(|G|\) 是样本的总数,输入的Tensor dtype只能是 ms.float32ms.float64

  • max_classes (int, 可选) - 最多显示多少个类。默认值:5

  • max_features (int, 可选) - 最多显示多少个特征。默认值:5

  • show (bool, 可选) - 显示解释图像,None 代表自动,只会在JupyterLab上显示。默认值: None

输出:
  • plc (Tensor) - shape为 \((L, K)\) 的伪线性系数。

  • relative plc (Tensor) - shape为 \((L, L, K)\) 的相对伪线性系数。第一个 \(L\) 轴代表目标类,而第二个代表视点类。

异常:
  • TypeError - 参数或输入类型错误。

  • ValueError - 输入值错误。

  • AttributeError - underlying缺少必需的属性。

支持平台:

Ascend GPU CPU

样例:

>>> import numpy as np
>>> import mindspore as ms
>>> from mindspore import nn
>>> from mindspore import ops
>>> from mindspore_xai.explainer import PseudoLinearCoef
>>>
>>> class Classifier(nn.Cell):
...     def construct(self, x):
...         y = ops.Zeros()((x.shape[0], 3), ms.float32)
...         y[:, 0] = -x[:, 0] + x[:, 1] + x[: ,2] - 0.5
...         y[:, 1] =  x[:, 0] - x[:, 1] + x[: ,2] - 0.5
...         y[:, 2] =  x[:, 0] + x[:, 1] - x[: ,2] - 0.5
...         return ops.Sigmoid()(y * 10)
>>>
>>> classifier = Classifier()
>>> explainer = PseudoLinearCoef(classifier, num_classes=3)
>>> features = ms.Tensor(np.random.uniform(size=(10000, 5)), dtype=ms.float32)  # 5 features
>>> plc, relative_plc = explainer(features)
>>> print(str(plc.shape))
(3, 5)
>>> print(str(relative_plc.shape))
(3, 3, 5)
normalize(plc, per_vector=False, eps=1e-09)[源代码]

归一化伪线性系数到[-1, 1]范围。

警告

把从未归一化特征产生的伪线性系数归一化可能会引致误导结果。

参数:
  • plc (Tensor) - 要归一化的伪线性系数或相对伪线性系数。

  • per_vector (bool, 可选) - 归一化 \(\vec{R}\) 向量。默认值: False

  • eps (float, 可选) - 误差范围。数值必须大于0。默认值:1e-9

返回:

Tensor,归一化的数值。

样例:

>>> from mindspore import Tensor
>>> from mindspore_xai.explainer import PseudoLinearCoef
>>>
>>> plc = Tensor([[0.1, 0.6, 0.8], [-2, 0.2, 0.4], [0.4, 0.1, -0.1]])
>>> print(PseudoLinearCoef.normalize(plc))
[[ 0.05  0.3   0.4 ]
[-1.    0.1   0.2 ]
[ 0.2   0.05 -0.05]]
>>> print(PseudoLinearCoef.normalize(plc, per_vector=True))
[[ 0.125  0.75   1.   ]
[-1.     0.1    0.2  ]
[ 1.     0.25  -0.25 ]]
plot(plc, title=None, feature_names=None, max_features=5)[源代码]

显示指定的伪线性系数或相对伪线性系数向量的图表。

参数:
  • plc (Tensor) - 要显示的伪线性系数或相对伪线性系数向量,shape为 \((K,)\)

  • title (str, 可选) - 图表标题。如果没有,则不会显示图表标题。默认值:None

  • feature_names (list[str], tuple[str], 可选) - 特征名称。如果没有,特征名称将为’feature 0’、’feature 1’、…。默认值:None

  • max_features (int, 可选) - 最多显示多少个特征。默认值:5

异常:
  • ValueError - 输入值错误。

样例:

>>> from mindspore import Tensor
>>> from mindspore_xai.explainer import PseudoLinearCoef
>>>
>>> plc = Tensor([[0.1, 0.6, 0.8], [-2, 0.2, 0.4], [0.4, 0.1, -0.1]])
>>> PseudoLinearCoef.plot(plc[0], title='Chart Title', feature_names=['f1','f2','f3'])
>>>
>>> relative_plc = Tensor([[[0., 0., 0.], [-2, 0.2, 0.4]], [[0.4, 0.1, -0.1], [0., 0., 0.]]])
>>> PseudoLinearCoef.plot(relative_plc[0, 1], title='Chart Title', feature_names=['f1','f2','f3'])