code: def test_dl_attr_with_perturb_per_pass(
      self, perturb_per_pass
  ) -> None:
      forward = sum_forward
  
      fa = FeatureAblation(forward)
      dl_fa = DataLoaderAttribution(fa)
  
      mock_dl_iter = Mock(wraps=DataLoader.__iter__)
  
      with patch.object(
          DataLoader, "__iter__", lambda self: mock_dl_iter(self)
      ):
          dataloader = DataLoader(mock_dataset, batch_size=2)
  
          dl_attributions = dl_fa.attribute(
              dataloader, perturbations_per_pass=perturb_per_pass
          )
  
      n_features = 7
      # 2 extra iter calls: get one input for format; get unperturbed output
      n_iter_overhead = 2
  
      self.assertEqual(
          mock_dl_iter.call_count,
          math.ceil(n_features / perturb_per_pass) + n_iter_overhead,
      )
  
      # default reduce of DataLoaderAttribution works the same as concat all batches
      attr_list = []
      for batch in dataloader:
          batch_attr = fa.attribute(tuple(batch))
          attr_list.append(batch_attr)
  
      expected_attr = tuple(
          torch.cat(feature_attrs, dim=0)
          for feature_attrs in zip(*attr_list)
      )
  
      assertAttributionComparision(self, dl_attributions, expected_attr)
  
imports: import math
  from typing import cast
  from unittest.mock import Mock, patch
  import torch
  from captum.attr._core.dataloader_attr import DataLoaderAttribution, InputRole
  from captum.attr._core.feature_ablation import FeatureAblation
  from parameterized import parameterized
  from tests.helpers.basic import assertAttributionComparision, assertTensorAlmostEqual, BaseTest
  from torch import Tensor
  from torch.utils.data import DataLoader, TensorDataset
label_desc: Use image node_id 8 for calling the Test obj's underlying member method code with example usage: obj.test_dl_attr_with_perturb_per_pass(perturb_per_pass) without return types