docstr: This method creates a single Data Parallel / GPU test for the given
  algorithm and parameters.
docstr_tok: ["This","method","creates","a","single","Data","Parallel","\/","GPU","test","for","the","given","algorithm","and","parameters","."]
code: def make_single_dp_test(
      cls,
      algorithm: Type[Attribution],
      model: Module,
      target_layer: Optional[str],
      args: Dict[str, Any],
      dp_delta: float,
      noise_tunnel: bool,
      baseline_distr: bool,
      mode: DataParallelCompareMode,
  ) -> Callable:
      """
      This method creates a single Data Parallel / GPU test for the given
      algorithm and parameters.
      """
  
      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
          elif mode is DataParallelCompareMode.dist_data_parallel:
              model_1, model_2 = (
                  cuda_model,
                  torch.nn.parallel.DistributedDataParallel(
                      cuda_model, device_ids=[0], output_device=0
                  ),
              )
              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_target_layer(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_target_layer(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,
                          LayerLRP,
                          NeuronDeepLift,
                          NeuronDeepLiftShap,
                          NeuronDeconvolution,
                          NeuronGuidedBackprop,
                          GuidedGradCam,
                      ),
                  ):
                      attr_method_2 = internal_algorithm(
                          model_2,
                          get_target_layer(cuda_model, target_layer),  # type: ignore
                      )
                  else:
                      attr_method_2 = internal_algorithm(
                          model_2.forward,
                          get_target_layer(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
              )
              if isinstance(attributions_1, list):
                  for i in range(len(attributions_1)):
                      assertTensorTuplesAlmostEqual(
                          self,
                          attributions_1[i],
                          attributions_2[i],
                          mode="max",
                          delta=dp_delta,
                      )
              else:
                  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)
              if isinstance(attributions_1, list):
                  for i in range(len(attributions_1)):
                      assertTensorTuplesAlmostEqual(
                          self,
                          attributions_1[i],
                          attributions_2[i],
                          mode="max",
                          delta=dp_delta,
                      )
              else:
                  assertTensorTuplesAlmostEqual(
                      self,
                      attributions_1,
                      attributions_2,
                      mode="max",
                      delta=dp_delta,
                  )
  
      return data_parallel_test_assert
  
imports: import copy
  import os
  from enum import Enum
  from typing import Any, Callable, cast, Dict, Optional, Tuple, Type
  import torch
  import torch.distributed
  from captum.attr._core.guided_grad_cam import GuidedGradCam
  from captum.attr._core.layer.layer_deep_lift import LayerDeepLift, LayerDeepLiftShap
  from captum.attr._core.layer.layer_lrp import LayerLRP
  from captum.attr._core.neuron.neuron_deep_lift import NeuronDeepLift, NeuronDeepLiftShap
  from captum.attr._core.neuron.neuron_guided_backprop_deconvnet import NeuronDeconvolution, NeuronGuidedBackprop
  from captum.attr._core.noise_tunnel import NoiseTunnel
  from captum.attr._utils.attribution import Attribution, InternalAttribution
  from tests.attr.helpers.gen_test_utils import gen_test_name, get_target_layer, parse_test_config, should_create_generated_test
  from tests.attr.helpers.test_config import config
  from tests.helpers.basic import assertTensorTuplesAlmostEqual, BaseTest, deep_copy_args
  from torch import Tensor
  from torch.nn import Module
label_desc: Use image node_id 2 for calling the DataParallelMeta obj's underlying member method code with example usage: obj.make_single_dp_test(cls, algorithm, model, target_layer, args, dp_delta, noise_tunnel, baseline_distr, mode) and returns: data_parallel_test_assert