You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
135 lines
4.9 KiB
135 lines
4.9 KiB
# Copyright 2021 Huawei Technologies Co., Ltd
|
|
#
|
|
# Licensed under the Apache License, Version 2.0 (the "License");
|
|
# you may not use this file except in compliance with the License.
|
|
# You may obtain a copy of the License at
|
|
#
|
|
# http://www.apache.org/licenses/LICENSE-2.0
|
|
#
|
|
# Unless required by applicable law or agreed to in writing, software
|
|
# distributed under the License is distributed on an "AS IS" BASIS,
|
|
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
# See the License for the specific language governing permissions and
|
|
# limitations under the License.
|
|
# ============================================================================
|
|
"""Tests of Localization of mindspore.explainer.benchmark."""
|
|
|
|
from unittest.mock import patch
|
|
|
|
import numpy as np
|
|
import pytest
|
|
|
|
import mindspore as ms
|
|
from mindspore import context
|
|
from mindspore import nn
|
|
from mindspore.explainer.benchmark import Localization
|
|
from mindspore.explainer.explanation import Gradient
|
|
|
|
|
|
context.set_context(mode=context.PYNATIVE_MODE)
|
|
|
|
H, W = 4, 4
|
|
SALIENCY = ms.Tensor(np.random.rand(1, 1, H, W), ms.float32)
|
|
|
|
|
|
class CustomNet(nn.Cell):
|
|
"""Simple net for unit test."""
|
|
|
|
def __init__(self):
|
|
super().__init__()
|
|
|
|
def construct(self, _):
|
|
return ms.Tensor([[0.1, 0.9]], ms.float32)
|
|
|
|
|
|
def mock_gradient_call(_, inputs, targets):
|
|
del inputs, targets
|
|
return SALIENCY
|
|
|
|
|
|
class TestLocalization:
|
|
"""Test on Localization."""
|
|
|
|
def setup_method(self):
|
|
self.net = CustomNet()
|
|
self.data = ms.Tensor(np.random.rand(1, 1, H, W), ms.float32)
|
|
self.target = 1
|
|
|
|
masks_np = np.zeros((1, 1, H, W))
|
|
masks_np[:, :, 1:3, 1:3] = 1
|
|
self.masks_np = masks_np
|
|
self.masks = ms.Tensor(masks_np, ms.float32)
|
|
|
|
self.explainer = Gradient(self.net)
|
|
self.saliency_gt = mock_gradient_call(self.explainer, self.data, self.target)
|
|
self.num_class = 2
|
|
|
|
@pytest.mark.level0
|
|
@pytest.mark.platform_arm_ascend_training
|
|
@pytest.mark.platform_x86_ascend_training
|
|
@pytest.mark.env_onecard
|
|
def test_pointing_game(self):
|
|
"""Test case for `metric="PointingGame"` without input saliency."""
|
|
with patch.object(Gradient, "__call__", mock_gradient_call):
|
|
max_pos = np.argmax(abs(self.saliency_gt.asnumpy().flatten()))
|
|
x_gt, y_gt = max_pos // W, max_pos % W
|
|
res_gt = self.masks_np[0, 0, x_gt, y_gt]
|
|
|
|
pg = Localization(self.num_class, metric="PointingGame")
|
|
pg._metric_arg = 1 # make the tolerance smaller to simplify the test
|
|
|
|
res = pg.evaluate(self.explainer, self.data, targets=self.target, mask=self.masks)
|
|
assert np.max(np.abs(np.array([res_gt]) - res)) < 1e-5
|
|
|
|
@pytest.mark.level0
|
|
@pytest.mark.platform_arm_ascend_training
|
|
@pytest.mark.platform_x86_ascend_training
|
|
@pytest.mark.env_onecard
|
|
def test_iosr(self):
|
|
"""Test case for `metric="IoSR"` without input saliency."""
|
|
with patch.object(Gradient, "__call__", mock_gradient_call):
|
|
threshold = 0.5
|
|
max_val = np.max(self.saliency_gt.asnumpy())
|
|
sr = (self.saliency_gt.asnumpy() > (max_val * threshold)).astype(int)
|
|
res_gt = np.sum(sr * self.masks_np) / (np.sum(sr).clip(1e-10))
|
|
|
|
iosr = Localization(self.num_class, metric="IoSR")
|
|
iosr._metric_arg = threshold
|
|
|
|
res = iosr.evaluate(self.explainer, self.data, targets=self.target, mask=self.masks)
|
|
|
|
assert np.allclose(np.array([res_gt]), res)
|
|
|
|
@pytest.mark.level0
|
|
@pytest.mark.platform_arm_ascend_training
|
|
@pytest.mark.platform_x86_ascend_training
|
|
@pytest.mark.env_onecard
|
|
def test_pointing_game_with_saliency(self):
|
|
"""Test metric PointingGame with input saliency."""
|
|
max_pos = np.argmax(abs(self.saliency_gt.asnumpy().flatten()))
|
|
x_gt, y_gt = max_pos // W, max_pos % W
|
|
res_gt = self.masks_np[0, 0, x_gt, y_gt]
|
|
|
|
pg = Localization(self.num_class, metric="PointingGame")
|
|
pg._metric_arg = 1 # make the tolerance smaller to simplify the test
|
|
|
|
res = pg.evaluate(self.explainer, self.data, targets=self.target, mask=self.masks, saliency=self.saliency_gt)
|
|
assert np.allclose(np.array([res_gt]), res)
|
|
|
|
@pytest.mark.level0
|
|
@pytest.mark.platform_arm_ascend_training
|
|
@pytest.mark.platform_x86_ascend_training
|
|
@pytest.mark.env_onecard
|
|
def test_iosr_with_saliency(self):
|
|
"""Test metric IoSR with input saliency map."""
|
|
threshold = 0.5
|
|
max_val = np.max(self.saliency_gt.asnumpy())
|
|
sr = (self.saliency_gt.asnumpy() > (max_val * threshold)).astype(int)
|
|
res_gt = np.sum(sr * self.masks_np) / (np.sum(sr).clip(1e-10))
|
|
|
|
iosr = Localization(self.num_class, metric="IoSR")
|
|
|
|
res = iosr.evaluate(self.explainer, self.data, targets=self.target, mask=self.masks, saliency=self.saliency_gt)
|
|
|
|
assert np.allclose(np.array([res_gt]), res)
|