docstr: this tests that `NaiveInfluence`, the simplest implementation, agree with the
  analytically calculated solution for influence and self-influence for a model
  where we can calculate that solution - linear regression trained with squared
  error loss.
docstr_tok: ["this","tests","that","`","NaiveInfluence","`",",","the","simplest","implementation",",","agree","with","the","analytically","calculated","solution","for","influence","and","self-influence","for","a","model","where","we","can","calculate","that","solution","-","linear","regression","trained","with","squared","error","loss","."]
code: def test_matches_linear_regression(
      self,
      reduction: str,
      influence_constructor: Callable,
      delta: float,
      mode: str,
      unpack_inputs: bool,
      use_gpu: Union[bool, str],
  ):
      """
      this tests that `NaiveInfluence`, the simplest implementation, agree with the
      analytically calculated solution for influence and self-influence for a model
      where we can calculate that solution - linear regression trained with squared
      error loss.
      """
      with tempfile.TemporaryDirectory() as tmpdir:
          (
              net,
              train_dataset,
              hessian_samples,
              hessian_labels,
              test_samples,
              test_labels,
          ) = get_random_model_and_data(
              tmpdir,
              unpack_inputs,
              return_test_data=True,
              use_gpu=use_gpu,
              return_hessian_data=True,
              model_type="trained_linear",
          )
  
          train_dataset = DataLoader(train_dataset, batch_size=5)
  
          hessian_dataset = (
              ExplicitDataset(hessian_samples, hessian_labels, use_gpu)
              if not unpack_inputs
              else UnpackDataset(
                  hessian_samples, hessian_labels, use_gpu
              )
          )
          hessian_dataset = DataLoader(hessian_dataset, batch_size=5)
  
          criterion = nn.MSELoss(reduction=reduction)
          batch_size = None
  
          # set `sample_grads_per_batch` based on `reduction` to be compatible
          sample_wise_grads_per_batch = (
              False if reduction == "none" else True
          )
  
          influence = influence_constructor(
              net,
              train_dataset,
              tmpdir,
              batch_size,
              criterion,
              sample_wise_grads_per_batch=sample_wise_grads_per_batch,
              hessian_dataset=hessian_dataset,
          )
  
          # since the model is a linear regression model trained with MSE loss, we
          # can calculate the hessian and per-example parameter gradients
          # analytically
          tensor_hessian_samples = (
              hessian_samples
              if not unpack_inputs
              else torch.cat(hessian_samples, dim=1)
          )
          # hessian at optimal parameters is 2 * X'X, where X is the feature matrix
          # of the examples used for calculating the hessian.
          # this is based on https://math.stackexchange.com/questions/2864585/hessian-on-linear-least-squares-problem # noqa: E501
          # and multiplying by 2, since we optimize squared error,
          # not 1/2 squared error.
          hessian = (
              torch.matmul(
                  tensor_hessian_samples.T, tensor_hessian_samples
              )
              * 2
          )
          hessian = hessian + (
              torch.eye(len(hessian)).to(device=hessian.device) * 1e-4
          )
          version = _parse_version(torch.__version__)
          if version < (1, 8):
              hessian_inverse = torch.pinverse(hessian, rcond=1e-4)
          else:
              hessian_inverse = torch.linalg.pinv(hessian, rcond=1e-4)
  
          # gradient for an example is 2 * features * error
  
          # compute train gradients
          tensor_train_samples = torch.cat(
              [torch.cat(batch[:-1], dim=1) for batch in train_dataset],
              dim=0,
          )
          train_predictions = torch.cat(
              [net(*batch[:-1]) for batch in train_dataset], dim=0
          )
          train_labels = torch.cat(
              [batch[-1] for batch in train_dataset], dim=0
          )
          train_gradients = (
              (train_predictions - train_labels)
              * tensor_train_samples
              * 2
          )
  
          # compute test gradients
          tensor_test_samples = (
              test_samples
              if not unpack_inputs
              else torch.cat(test_samples, dim=1)
          )
          test_predictions = (
              net(test_samples)
              if not unpack_inputs
              else net(*test_samples)
          )
          test_gradients = (
              (test_predictions - test_labels) * tensor_test_samples * 2
          )
  
          if mode == "influence":
              # compute pairwise influences, analytically
              analytical_train_test_influences = torch.matmul(
                  torch.matmul(test_gradients, hessian_inverse),
                  train_gradients.T,
              )
              # compute pairwise influences using influence implementation
              influence_train_test_influences = influence.influence(
                  _format_batch_into_tuple(
                      test_samples, test_labels, unpack_inputs
                  )
              )
              # check error
              assertTensorAlmostEqual(
                  self,
                  influence_train_test_influences,
                  analytical_train_test_influences,
                  delta=delta,
                  mode="max",
              )
          elif mode == "self_influence":
              # compute self influence, analytically
              analytical_self_influences = torch.diag(
                  torch.matmul(
                      torch.matmul(train_gradients, hessian_inverse),
                      train_gradients.T,
                  )
              )
              # compute pairwise influences using influence implementation
              influence_self_influences = influence.self_influence(
                  train_dataset
              )
              # check error
              assertTensorAlmostEqual(
                  self,
                  influence_self_influences,
                  analytical_self_influences,
                  delta=delta,
                  mode="max",
              )
          else:
              raise Exception("unknown test mode")
  
file_path: captum/tests/influence/_core/test_naive_influence.py
imports: import tempfile
  from typing import Callable, List, Tuple, Union
  import torch
  import torch.nn
  from captum._utils.common import _parse_version
  from captum.influence._core.influence_function import NaiveInfluenceFunction
  from captum.influence._utils.common import _custom_functional_call, _flatten_params, _functional_call, _unflatten_params_factory
  from parameterized import parameterized
  from tests.helpers.basic import assertTensorAlmostEqual, assertTensorTuplesAlmostEqual, BaseTest
  from tests.influence._utils.common import _format_batch_into_tuple, build_test_name_func, DataInfluenceConstructor, ExplicitDataset, get_random_model_and_data, Linear, UnpackDataset, USE_GPU_LIST
  from torch.utils.data import DataLoader
label_desc: Use image node_id 2 for calling the TestNaiveInfluence obj's underlying member method code with example usage: obj.test_matches_linear_regression(reduction, influence_constructor, delta, mode, unpack_inputs, use_gpu) without return types