def test_batched_input_smoothgrad_wo_mutliplying_by_inputs(self) -> None:
        model = BasicModel_MultiLayer()
        inputs = torch.tensor(
            [[1.5, 2.0, 1.3], [0.5, 0.1, 2.3], [1.5, 2.0, 1.3]], requires_grad=True
        )
        ig_wo_mutliplying_by_inputs = IntegratedGradients(
            model, multiply_by_inputs=False
        )
        nt_wo_mutliplying_by_inputs = NoiseTunnel(ig_wo_mutliplying_by_inputs)

        ig = IntegratedGradients(model)
        nt = NoiseTunnel(ig)
        n_samples = 5
        target = 0
        type = "smoothgrad"
        attributions_wo_mutliplying_by_inputs = nt_wo_mutliplying_by_inputs.attribute(
            inputs,
            nt_type=type,
            nt_samples=n_samples,
            stdevs=0.0,
            target=target,
            n_steps=500,
        )
        with self.assertWarns(DeprecationWarning):
            attributions = nt.attribute(
                inputs,
                nt_type=type,
                n_samples=n_samples,
                stdevs=0.0,
                target=target,
                n_steps=500,
            )
        assertTensorAlmostEqual(
            self, attributions_wo_mutliplying_by_inputs * inputs, attributions
        )
Beispiel #2
0
        def target_test_assert(self) -> None:
            attr_method: Attribution
            if target_layer:
                internal_algorithm = cast(Type[InternalAttribution], algorithm)
                attr_method = internal_algorithm(model, target_layer)
            else:
                attr_method = algorithm(model)

            if noise_tunnel:
                attr_method = NoiseTunnel(attr_method)
            attributions_orig = attr_method.attribute(**args)
            for i in range(num_examples):
                args["target"] = (original_targets[i] if len(original_targets)
                                  == num_examples else original_targets)
                args["inputs"] = (original_inputs[i:i + 1] if isinstance(
                    original_inputs, Tensor) else tuple(
                        original_inp[i:i + 1]
                        for original_inp in original_inputs))
                if original_additional_forward_args is not None:
                    args["additional_forward_args"] = tuple(
                        single_add_arg[i:i + 1] if isinstance(
                            single_add_arg, Tensor) else single_add_arg
                        for single_add_arg in original_additional_forward_args)
                if replace_baselines:
                    if isinstance(original_inputs, Tensor):
                        args["baselines"] = original_baselines[i:i + 1]
                    elif isinstance(original_baselines, tuple):
                        args["baselines"] = tuple(
                            single_baseline[i:i + 1] if isinstance(
                                single_baseline, Tensor) else single_baseline
                            for single_baseline in original_baselines)
                self.setUp()
                single_attr = attr_method.attribute(**args)
                current_orig_attributions = (
                    attributions_orig[i:i + 1] if isinstance(
                        attributions_orig, Tensor) else tuple(
                            single_attrib[i:i + 1]
                            for single_attrib in attributions_orig))
                assertTensorTuplesAlmostEqual(
                    self,
                    current_orig_attributions,
                    single_attr,
                    delta=target_delta,
                    mode="max",
                )
                if len(original_targets) == num_examples:
                    # If original_targets contained multiple elements, then
                    # we also compare with setting targets to a list with
                    # a single element.
                    args["target"] = original_targets[i:i + 1]
                    self.setUp()
                    single_attr_target_list = attr_method.attribute(**args)
                    assertTensorTuplesAlmostEqual(
                        self,
                        current_orig_attributions,
                        single_attr_target_list,
                        delta=target_delta,
                        mode="max",
                    )
Beispiel #3
0
    def _input_x_gradient_classification_assert(self,
                                                nt_type: str = "vanilla"
                                                ) -> None:
        num_in = 5
        input = torch.tensor([[0.0, 1.0, 2.0, 3.0, 4.0]], requires_grad=True)
        target = torch.tensor(5)

        # 10-class classification model
        model = SoftmaxModel(num_in, 20, 10)
        input_x_grad = InputXGradient(model.forward)
        if nt_type == "vanilla":
            attributions = input_x_grad.attribute(input, target)
            output = model(input)[:, target]
            output.backward()
            expercted = input.grad * input
            self.assertEqual(
                expercted.detach().numpy().tolist(),
                attributions.detach().numpy().tolist(),
            )
        else:
            nt = NoiseTunnel(input_x_grad)
            attributions = nt.attribute(input,
                                        nt_type=nt_type,
                                        n_samples=10,
                                        stdevs=1.0,
                                        target=target)

        self.assertEqual(attributions.shape, input.shape)
Beispiel #4
0
    def _saliency_base_assert(
        self,
        model: Module,
        inputs: TensorOrTupleOfTensorsGeneric,
        expected: TensorOrTupleOfTensorsGeneric,
        additional_forward_args: Any = None,
        nt_type: str = "vanilla",
    ) -> None:
        saliency = Saliency(model)

        self.assertFalse(saliency.uses_input_marginal_effects)

        if nt_type == "vanilla":
            attributions = saliency.attribute(
                inputs, additional_forward_args=additional_forward_args)
        else:
            nt = NoiseTunnel(saliency)
            attributions = nt.attribute(
                inputs,
                nt_type=nt_type,
                n_samples=10,
                stdevs=0.0000002,
                additional_forward_args=additional_forward_args,
            )

        for input, attribution, expected_attr in zip(inputs, attributions,
                                                     expected):
            if nt_type == "vanilla":
                self._assert_attribution(attribution, expected_attr)
            self.assertEqual(input.shape, attribution.shape)
Beispiel #5
0
 def _saliency_base_assert(
     self, model, inputs, expected, additional_forward_args=None, nt_type="vanilla"
 ):
     saliency = Saliency(model)
     if nt_type == "vanilla":
         attributions = saliency.attribute(
             inputs, additional_forward_args=additional_forward_args
         )
     else:
         nt = NoiseTunnel(saliency)
         attributions = nt.attribute(
             inputs,
             nt_type=nt_type,
             n_samples=10,
             stdevs=0.0000002,
             additional_forward_args=additional_forward_args,
         )
     if isinstance(attributions, tuple):
         for input, attribution, expected_attr in zip(
             inputs, attributions, expected
         ):
             if nt_type == "vanilla":
                 self._assert_attribution(attribution, expected_attr)
             self.assertEqual(input.shape, attribution.shape)
     else:
         if nt_type == "vanilla":
             self._assert_attribution(attributions, expected)
         self.assertEqual(inputs.shape, attributions.shape)
Beispiel #6
0
    def _saliency_base_assert(
        self,
        model: Module,
        inputs: TensorOrTupleOfTensorsGeneric,
        expected: TensorOrTupleOfTensorsGeneric,
        additional_forward_args: Any = None,
        nt_type: str = "vanilla",
        n_samples_batch_size=None,
    ) -> Union[Tensor, Tuple[Tensor, ...]]:
        saliency = Saliency(model)

        self.assertFalse(saliency.multiplies_by_inputs)

        if nt_type == "vanilla":
            attributions = saliency.attribute(
                inputs, additional_forward_args=additional_forward_args)
        else:
            nt = NoiseTunnel(saliency)
            attributions = nt.attribute(
                inputs,
                nt_type=nt_type,
                nt_samples=10,
                nt_samples_batch_size=n_samples_batch_size,
                stdevs=0.0000002,
                additional_forward_args=additional_forward_args,
            )

        for input, attribution, expected_attr in zip(inputs, attributions,
                                                     expected):
            if nt_type == "vanilla":
                self._assert_attribution(attribution, expected_attr)
            self.assertEqual(input.shape, attribution.shape)

        return attributions
Beispiel #7
0
    def _saliency_classification_assert(self,
                                        nt_type: str = "vanilla") -> None:
        num_in = 5
        input = torch.tensor([[0.0, 1.0, 2.0, 3.0, 4.0]], requires_grad=True)
        target = torch.tensor(5)
        # 10-class classification model
        model = SoftmaxModel(num_in, 20, 10)
        saliency = Saliency(model)

        if nt_type == "vanilla":
            attributions = saliency.attribute(input, target)

            output = model(input)[:, target]
            output.backward()
            expected = torch.abs(cast(Tensor, input.grad))
            self.assertEqual(
                expected.detach().numpy().tolist(),
                attributions.detach().numpy().tolist(),
            )
        else:
            nt = NoiseTunnel(saliency)
            attributions = nt.attribute(input,
                                        nt_type=nt_type,
                                        n_samples=10,
                                        stdevs=0.0002,
                                        target=target)
        self.assertEqual(input.shape, attributions.shape)
    def _validate_completness(self,
                              model,
                              inputs,
                              target,
                              type="vanilla",
                              baseline=None):
        ig = IntegratedGradients(model.forward)
        for method in [
                "riemann_right",
                "riemann_left",
                "riemann_middle",
                "riemann_trapezoid",
                "gausslegendre",
        ]:
            model.zero_grad()
            if type == "vanilla":
                attributions, delta = ig.attribute(
                    inputs,
                    baselines=baseline,
                    target=target,
                    method=method,
                    n_steps=1000,
                    return_convergence_delta=True,
                )
                delta_expected = ig.compute_convergence_delta(
                    attributions, baseline, inputs, target)
                assertTensorAlmostEqual(self, delta_expected, delta)

                delta_condition = all(abs(delta.numpy().flatten()) < 0.003)
                self.assertTrue(
                    delta_condition,
                    "The sum of attribution values {} is not "
                    "nearly equal to the difference between the endpoint for "
                    "some samples".format(delta),
                )
                self.assertEqual([inputs.shape[0]], list(delta.shape))
            else:
                nt = NoiseTunnel(ig)
                n_samples = 10
                attributions, delta = nt.attribute(
                    inputs,
                    baselines=baseline,
                    nt_type=type,
                    n_samples=n_samples,
                    stdevs=0.0002,
                    n_steps=1000,
                    target=target,
                    method=method,
                    return_convergence_delta=True,
                )
                self.assertEqual([inputs.shape[0] * n_samples],
                                 list(delta.shape))

            self.assertTrue(all(abs(delta.numpy().flatten()) < 0.05))
            self.assertEqual(attributions.shape, inputs.shape)
Beispiel #9
0
        def hook_removal_test_assert(self) -> None:
            attr_method: Attribution
            expect_error = False
            if layer is not None:
                if mode is HookRemovalMode.invalid_module:
                    expect_error = True
                    if isinstance(layer, list):
                        _set_deep_layer_value(model, layer[0], ErrorModule())
                    else:
                        _set_deep_layer_value(model, layer, ErrorModule())
                target_layer = get_target_layer(model, layer)
                internal_algorithm = cast(Type[InternalAttribution], algorithm)
                attr_method = internal_algorithm(model, target_layer)
            else:
                attr_method = algorithm(model)

            if noise_tunnel:
                attr_method = NoiseTunnel(attr_method)

            if mode is HookRemovalMode.incorrect_target_or_neuron:
                # Overwriting target and neuron index arguments to
                # incorrect values.
                if "target" in args:
                    args["target"] = (9999, ) * 20
                    expect_error = True
                if "neuron_selector" in args:
                    args["neuron_selector"] = (9999, ) * 20
                    expect_error = True

            if expect_error:
                with self.assertRaises(AssertionError):
                    attr_method.attribute(**args)
            else:
                attr_method.attribute(**args)

            def check_leftover_hooks(module):
                self.assertEqual(len(module._forward_hooks), 0)
                self.assertEqual(len(module._backward_hooks), 0)
                self.assertEqual(len(module._forward_pre_hooks), 0)

            model.apply(check_leftover_hooks)
    def _validate_completness(
        self,
        model: Module,
        input: Tensor,
        target: Tensor,
        type: str = "vanilla",
        approximation_method: str = "gausslegendre",
        baseline: Optional[Union[Tensor, int, float, Tuple[Union[Tensor, int,
                                                                 float],
                                                           ...]]] = None,
    ) -> None:
        ig = IntegratedGradients(model.forward)
        model.zero_grad()
        if type == "vanilla":
            attributions, delta = ig.attribute(
                input,
                baselines=baseline,
                target=target,
                method=approximation_method,
                n_steps=200,
                return_convergence_delta=True,
            )
            delta_expected = ig.compute_convergence_delta(
                attributions, baseline, input, target)
            assertTensorAlmostEqual(self, delta_expected, delta)

            delta_condition = all(abs(delta.numpy().flatten()) < 0.005)
            self.assertTrue(
                delta_condition,
                "The sum of attribution values {} is not "
                "nearly equal to the difference between the endpoint for "
                "some samples".format(delta),
            )
            self.assertEqual([input.shape[0]], list(delta.shape))
        else:
            nt = NoiseTunnel(ig)
            n_samples = 10
            attributions, delta = nt.attribute(
                input,
                baselines=baseline,
                nt_type=type,
                n_samples=n_samples,
                stdevs=0.0002,
                n_steps=100,
                target=target,
                method=approximation_method,
                return_convergence_delta=True,
            )
            self.assertEqual([input.shape[0] * n_samples], list(delta.shape))

        self.assertTrue(all(abs(delta.numpy().flatten()) < 0.05))
        self.assertEqual(attributions.shape, input.shape)
    def _validate_completness(self, model, inputs, target, type="vanilla"):
        ig = IntegratedGradients(model.forward)
        for method in [
                "riemann_right",
                "riemann_left",
                "riemann_middle",
                "riemann_trapezoid",
                "gausslegendre",
        ]:
            model.zero_grad()
            if type == "vanilla":
                attributions, delta = ig.attribute(
                    inputs,
                    target=target,
                    method=method,
                    n_steps=1000,
                    return_convergence_delta=True,
                )
                # attributions are returned as tuples for the integrated_gradients
                self.assertAlmostEqual(
                    attributions.sum(),
                    model.forward(inputs)[:, target] -
                    model.forward(0 * inputs)[:, target],
                    delta=0.005,
                )
                delta_expected = abs(attributions.sum().item() - (
                    model.forward(inputs)[:, target].item() -
                    model.forward(0 * inputs)[:, target].item()))
                self.assertAlmostEqual(abs(delta).sum().item(),
                                       delta_expected,
                                       delta=0.005)
                self.assertEqual([inputs.shape[0]], list(delta.shape))
            else:
                nt = NoiseTunnel(ig)
                n_samples = 10
                attributions, delta = nt.attribute(
                    inputs,
                    nt_type=type,
                    n_samples=n_samples,
                    stdevs=0.0002,
                    n_steps=1000,
                    target=target,
                    method=method,
                    return_convergence_delta=True,
                )
                self.assertEqual([inputs.shape[0] * n_samples],
                                 list(delta.shape))

            self.assertTrue(all(abs(delta.numpy().flatten()) < 0.05))
            self.assertEqual(attributions.shape, inputs.shape)
    def _input_x_gradient_base_assert(
        self,
        model: Module,
        inputs: TensorOrTupleOfTensorsGeneric,
        expected_grads: TensorOrTupleOfTensorsGeneric,
        additional_forward_args: Any = None,
        nt_type: str = "vanilla",
    ) -> None:
        input_x_grad = InputXGradient(model)
        attributions: TensorOrTupleOfTensorsGeneric
        if nt_type == "vanilla":
            attributions = input_x_grad.attribute(
                inputs, additional_forward_args=additional_forward_args)
        else:
            nt = NoiseTunnel(input_x_grad)
            attributions = nt.attribute(
                inputs,
                nt_type=nt_type,
                n_samples=10,
                stdevs=0.0002,
                additional_forward_args=additional_forward_args,
            )

        if isinstance(attributions, tuple):
            for input, attribution, expected_grad in zip(
                    inputs, attributions, expected_grads):
                if nt_type == "vanilla":
                    assertArraysAlmostEqual(attribution.reshape(-1),
                                            (expected_grad *
                                             input).reshape(-1))
                self.assertEqual(input.shape, attribution.shape)
        elif isinstance(attributions, Tensor):
            if nt_type == "vanilla":
                assertArraysAlmostEqual(
                    attributions.reshape(-1),
                    (expected_grads * inputs).reshape(-1),
                    delta=0.5,
                )
            self.assertEqual(inputs.shape, attributions.shape)
Beispiel #13
0
    def _input_x_gradient_base_assert(
        self,
        model: Module,
        inputs: TensorOrTupleOfTensorsGeneric,
        expected_grads: TensorOrTupleOfTensorsGeneric,
        additional_forward_args: Any = None,
        nt_type: str = "vanilla",
    ) -> None:
        input_x_grad = InputXGradient(model)
        self.assertTrue(input_x_grad.multiplies_by_inputs)
        attributions: TensorOrTupleOfTensorsGeneric
        if nt_type == "vanilla":
            attributions = input_x_grad.attribute(
                inputs,
                additional_forward_args=additional_forward_args,
            )
        else:
            nt = NoiseTunnel(input_x_grad)
            attributions = nt.attribute(
                inputs,
                nt_type=nt_type,
                nt_samples=10,
                stdevs=0.0002,
                additional_forward_args=additional_forward_args,
            )

        if isinstance(attributions, tuple):
            for input, attribution, expected_grad in zip(
                inputs, attributions, expected_grads
            ):
                if nt_type == "vanilla":
                    self._assert_attribution(expected_grad, input, attribution)
                self.assertEqual(input.shape, attribution.shape)
        elif isinstance(attributions, Tensor):
            if nt_type == "vanilla":
                self._assert_attribution(expected_grads, inputs, attributions)
            self.assertEqual(
                cast(Tensor, inputs).shape, cast(Tensor, attributions).shape
            )
Beispiel #14
0
        def data_parallel_test_assert(self) -> None:
            # Construct cuda_args, moving all tensor inputs in args to CUDA device
            cuda_args = {}
            for key in args:
                if isinstance(args[key], Tensor):
                    cuda_args[key] = args[key].cuda()
                elif isinstance(args[key], tuple):
                    cuda_args[key] = tuple(
                        elem.cuda() if isinstance(elem, Tensor) else elem
                        for elem in args[key])
                else:
                    cuda_args[key] = args[key]

            alt_device_ids = None
            cuda_model = copy.deepcopy(model).cuda()
            # Initialize models based on DataParallelCompareMode
            if mode is DataParallelCompareMode.cpu_cuda:
                model_1, model_2 = model, cuda_model
                args_1, args_2 = args, cuda_args
            elif mode is DataParallelCompareMode.data_parallel_default:
                model_1, model_2 = (
                    cuda_model,
                    torch.nn.parallel.DataParallel(cuda_model),
                )
                args_1, args_2 = cuda_args, cuda_args
            elif mode is DataParallelCompareMode.data_parallel_alt_dev_ids:
                alt_device_ids = [0] + [
                    x for x in range(torch.cuda.device_count() - 1, 0, -1)
                ]
                model_1, model_2 = (
                    cuda_model,
                    torch.nn.parallel.DataParallel(cuda_model,
                                                   device_ids=alt_device_ids),
                )
                args_1, args_2 = cuda_args, cuda_args
            else:
                raise AssertionError(
                    "DataParallel compare mode type is not valid.")

            attr_method_1: Attribution
            attr_method_2: Attribution
            if target_layer:
                internal_algorithm = cast(Type[InternalAttribution], algorithm)
                attr_method_1 = internal_algorithm(
                    model_1, _get_deep_layer_name(model_1, target_layer))
                # cuda_model is used to obtain target_layer since DataParallel
                # adds additional wrapper.
                # model_2 is always either the CUDA model itself or DataParallel
                if alt_device_ids is None:
                    attr_method_2 = internal_algorithm(
                        model_2, _get_deep_layer_name(cuda_model,
                                                      target_layer))
                else:
                    # LayerDeepLift and LayerDeepLiftShap do not take device ids
                    # as a parameter, since they must always have the DataParallel
                    # model object directly.
                    # Some neuron methods and GuidedGradCAM also require the
                    # model and cannot take a forward function.
                    if issubclass(
                            internal_algorithm,
                        (
                            LayerDeepLift,
                            LayerDeepLiftShap,
                            NeuronDeepLift,
                            NeuronDeepLiftShap,
                            NeuronDeconvolution,
                            NeuronGuidedBackprop,
                            GuidedGradCam,
                        ),
                    ):
                        attr_method_2 = internal_algorithm(
                            model_2,
                            _get_deep_layer_name(cuda_model, target_layer))
                    else:
                        attr_method_2 = internal_algorithm(
                            model_2.forward,
                            _get_deep_layer_name(cuda_model, target_layer),
                            device_ids=alt_device_ids,
                        )
            else:
                attr_method_1 = algorithm(model_1)
                attr_method_2 = algorithm(model_2)

            if noise_tunnel:
                attr_method_1 = NoiseTunnel(attr_method_1)
                attr_method_2 = NoiseTunnel(attr_method_2)
            if attr_method_1.has_convergence_delta():
                attributions_1, delta_1 = attr_method_1.attribute(
                    return_convergence_delta=True, **args_1)
                self.setUp()
                attributions_2, delta_2 = attr_method_2.attribute(
                    return_convergence_delta=True, **args_2)
                assertTensorTuplesAlmostEqual(self,
                                              attributions_1,
                                              attributions_2,
                                              mode="max",
                                              delta=dp_delta)
                assertTensorTuplesAlmostEqual(self,
                                              delta_1,
                                              delta_2,
                                              mode="max",
                                              delta=dp_delta)
            else:
                attributions_1 = attr_method_1.attribute(**args_1)
                self.setUp()
                attributions_2 = attr_method_2.attribute(**args_2)
                assertTensorTuplesAlmostEqual(self,
                                              attributions_1,
                                              attributions_2,
                                              mode="max",
                                              delta=dp_delta)
    def _compute_attribution_and_evaluate(
        self,
        model: Module,
        inputs: TensorOrTupleOfTensorsGeneric,
        baselines: BaselineType = None,
        target: Union[None, int] = None,
        additional_forward_args: Any = None,
        type: str = "vanilla",
        approximation_method: str = "gausslegendre",
        multiply_by_inputs=True,
    ) -> Tuple[Tensor, ...]:
        r"""
        attrib_type: 'vanilla', 'smoothgrad', 'smoothgrad_sq', 'vargrad'
        """
        ig = IntegratedGradients(model, multiply_by_inputs=multiply_by_inputs)
        self.assertEquals(ig.multiplies_by_inputs, multiply_by_inputs)
        if not isinstance(inputs, tuple):
            inputs = (inputs,)  # type: ignore
        inputs: Tuple[Tensor, ...]

        if baselines is not None and not isinstance(baselines, tuple):
            baselines = (baselines,)

        if baselines is None:
            baselines = _tensorize_baseline(inputs, _zeros(inputs))

        if type == "vanilla":
            attributions, delta = ig.attribute(
                inputs,
                baselines,
                additional_forward_args=additional_forward_args,
                method=approximation_method,
                n_steps=500,
                target=target,
                return_convergence_delta=True,
            )
            model.zero_grad()
            attributions_without_delta, delta = ig.attribute(
                inputs,
                baselines,
                additional_forward_args=additional_forward_args,
                method=approximation_method,
                n_steps=500,
                target=target,
                return_convergence_delta=True,
            )
            model.zero_grad()
            self.assertEqual([inputs[0].shape[0]], list(delta.shape))
            delta_external = ig.compute_convergence_delta(
                attributions,
                baselines,
                inputs,
                target=target,
                additional_forward_args=additional_forward_args,
            )
            assertArraysAlmostEqual(delta, delta_external, 0.0)
        else:
            nt = NoiseTunnel(ig)
            n_samples = 5
            attributions, delta = nt.attribute(
                inputs,
                nt_type=type,
                nt_samples=n_samples,
                stdevs=0.00000002,
                baselines=baselines,
                target=target,
                additional_forward_args=additional_forward_args,
                method=approximation_method,
                n_steps=500,
                return_convergence_delta=True,
            )
            with self.assertWarns(DeprecationWarning):
                attributions_without_delta = nt.attribute(
                    inputs,
                    nt_type=type,
                    n_samples=n_samples,
                    stdevs=0.00000002,
                    baselines=baselines,
                    target=target,
                    additional_forward_args=additional_forward_args,
                    method=approximation_method,
                    n_steps=500,
                )
            self.assertEquals(nt.multiplies_by_inputs, multiply_by_inputs)
            self.assertEqual([inputs[0].shape[0] * n_samples], list(delta.shape))

        for input, attribution in zip(inputs, attributions):
            self.assertEqual(attribution.shape, input.shape)
        if multiply_by_inputs:
            self.assertTrue(all(abs(delta.numpy().flatten()) < 0.07))

        # compare attributions retrieved with and without
        # `return_convergence_delta` flag
        for attribution, attribution_without_delta in zip(
            attributions, attributions_without_delta
        ):
            assertTensorAlmostEqual(
                self, attribution, attribution_without_delta, delta=0.05
            )

        return cast(Tuple[Tensor, ...], attributions)
Beispiel #16
0
        def jit_test_assert(self) -> None:
            model_1 = model
            attr_args = args
            if (mode is JITCompareMode.data_parallel_jit_trace
                    or JITCompareMode.data_parallel_jit_script):
                if not torch.cuda.is_available() or torch.cuda.device_count(
                ) == 0:
                    raise unittest.SkipTest(
                        "Skipping GPU test since CUDA not available.")
                # Construct cuda_args, moving all tensor inputs in args to CUDA device
                cuda_args = {}
                for key in args:
                    if isinstance(args[key], Tensor):
                        cuda_args[key] = args[key].cuda()
                    elif isinstance(args[key], tuple):
                        cuda_args[key] = tuple(
                            elem.cuda() if isinstance(elem, Tensor) else elem
                            for elem in args[key])
                    else:
                        cuda_args[key] = args[key]
                attr_args = cuda_args
                model_1 = model_1.cuda()

            # Initialize models based on JITCompareMode
            if (mode is JITCompareMode.cpu_jit_script
                    or JITCompareMode.data_parallel_jit_script):
                model_2 = torch.jit.script(model_1)  # type: ignore
            elif (mode is JITCompareMode.cpu_jit_trace
                  or JITCompareMode.data_parallel_jit_trace):
                all_inps = _format_input(args["inputs"]) + (
                    _format_additional_forward_args(
                        args["additional_forward_args"])
                    if "additional_forward_args" in args and
                    args["additional_forward_args"] is not None else tuple())
                model_2 = torch.jit.trace(model_1, all_inps)  # type: ignore
            else:
                raise AssertionError("JIT compare mode type is not valid.")

            attr_method_1 = algorithm(model_1)
            attr_method_2 = algorithm(model_2)

            if noise_tunnel:
                attr_method_1 = NoiseTunnel(attr_method_1)
                attr_method_2 = NoiseTunnel(attr_method_2)
            if attr_method_1.has_convergence_delta():
                attributions_1, delta_1 = attr_method_1.attribute(
                    return_convergence_delta=True, **attr_args)
                self.setUp()
                attributions_2, delta_2 = attr_method_2.attribute(
                    return_convergence_delta=True, **attr_args)
                assertTensorTuplesAlmostEqual(self,
                                              attributions_1,
                                              attributions_2,
                                              mode="max")
                assertTensorTuplesAlmostEqual(self,
                                              delta_1,
                                              delta_2,
                                              mode="max")
            else:
                attributions_1 = attr_method_1.attribute(**attr_args)
                self.setUp()
                attributions_2 = attr_method_2.attribute(**attr_args)
                assertTensorTuplesAlmostEqual(self,
                                              attributions_1,
                                              attributions_2,
                                              mode="max")
Beispiel #17
0
    def _compute_attribution_and_evaluate(
        self,
        model,
        inputs,
        baselines=None,
        target=None,
        additional_forward_args=None,
        type="vanilla",
    ):
        r"""
            attrib_type: 'vanilla', 'smoothgrad', 'smoothgrad_sq', 'vargrad'
        """
        ig = IntegratedGradients(model)
        if not isinstance(inputs, tuple):
            inputs = (inputs,)

        if baselines is not None and not isinstance(baselines, tuple):
            baselines = (baselines,)

        if baselines is None:
            baselines = _zeros(inputs)

        for method in [
            "riemann_right",
            "riemann_left",
            "riemann_middle",
            "riemann_trapezoid",
            "gausslegendre",
        ]:
            if type == "vanilla":
                attributions, delta = ig.attribute(
                    inputs,
                    baselines,
                    additional_forward_args=additional_forward_args,
                    method=method,
                    n_steps=2000,
                    target=target,
                    return_convergence_delta=True,
                )
                model.zero_grad()
                attributions_without_delta, delta = ig.attribute(
                    inputs,
                    baselines,
                    additional_forward_args=additional_forward_args,
                    method=method,
                    n_steps=2000,
                    target=target,
                    return_convergence_delta=True,
                )
                model.zero_grad()
                self.assertEqual([inputs[0].shape[0]], list(delta.shape))
                delta_external = ig.compute_convergence_delta(
                    attributions,
                    baselines,
                    inputs,
                    target=target,
                    additional_forward_args=additional_forward_args,
                )
                assertArraysAlmostEqual(delta, delta_external, 0.0)
            else:
                nt = NoiseTunnel(ig)
                n_samples = 5
                attributions, delta = nt.attribute(
                    inputs,
                    nt_type=type,
                    n_samples=n_samples,
                    stdevs=0.00000002,
                    baselines=baselines,
                    target=target,
                    additional_forward_args=additional_forward_args,
                    method=method,
                    n_steps=2000,
                    return_convergence_delta=True,
                )
                attributions_without_delta = nt.attribute(
                    inputs,
                    nt_type=type,
                    n_samples=n_samples,
                    stdevs=0.00000002,
                    baselines=baselines,
                    target=target,
                    additional_forward_args=additional_forward_args,
                    method=method,
                    n_steps=2000,
                )
                self.assertEqual([inputs[0].shape[0] * n_samples], list(delta.shape))

            for input, attribution in zip(inputs, attributions):
                self.assertEqual(attribution.shape, input.shape)
            self.assertTrue(all(abs(delta.numpy().flatten()) < 0.05))

            # compare attributions retrieved with and without
            # `return_convergence_delta` flag
            for attribution, attribution_without_delta in zip(
                attributions, attributions_without_delta
            ):
                assertTensorAlmostEqual(
                    self, attribution, attribution_without_delta, delta=0.05
                )

        return attributions