def get_inverse_hvp_lissa(
    vs: Sequence[torch.Tensor],
    model: Model,
    used_params: Sequence[torch.Tensor],
    lissa_data_loader: DataLoader,
    damping: float,
    num_samples: int,
    scale: float,
) -> torch.Tensor:
    """
    This function approximates the product of the inverse of the Hessian and
    the vectors `vs` using LiSSA.

    Adapted from [github.com/kohpangwei/influence-release]
    (https://github.com/kohpangwei/influence-release/blob/0f656964867da6ddcca16c14b3e4f0eef38a7472/influence/genericNeuralNet.py#L475),
    the repo for [Koh, P.W., & Liang, P. (2017)](https://api.semanticscholar.org/CorpusID:13193974),
    and [github.com/xhan77/influence-function-analysis]
    (https://github.com/xhan77/influence-function-analysis/blob/78d5a967aba885f690d34e88d68da8678aee41f1/bert_util.py#L336),
    the repo for [Han, Xiaochuang et al. (2020)](https://api.semanticscholar.org/CorpusID:218628619).
    """
    inverse_hvps = [torch.tensor(0) for _ in vs]
    for _ in Tqdm.tqdm(range(num_samples), desc="LiSSA samples", total=num_samples):
        # See a explanation at "Stochastic estimation" paragraph in [https://arxiv.org/pdf/1703.04730.pdf]
        # initialize \tilde{H}^{−1}_0 v = v
        cur_estimates = vs
        recursion_iter = Tqdm.tqdm(
            lissa_data_loader, desc="LiSSA depth", total=len(lissa_data_loader)
        )
        for j, training_batch in enumerate(recursion_iter):
            # TODO (epwalsh): should we make sure `model` is in "train" or "eval" mode here?
            model.zero_grad()
            train_output_dict = model(**training_batch)
            # Hessian of loss @ \tilde{H}^{−1}_{j - 1} v
            hvps = get_hvp(train_output_dict["loss"], used_params, cur_estimates)

            # This is the recursive step:
            # cur_estimate = \tilde{H}^{−1}_{j - 1} v
            # (i.e. Hessian-Vector Product estimate from last iteration)
            # Updating for \tilde{H}^{−1}_j v, the new current estimate becomes:
            # v + (I - (Hessian_at_x + damping)) * cur_estimate
            # = v + (I + damping) * cur_estimate - Hessian_at_x * cur_estimate
            # We divide `hvp / scale` here (or, equivalently `Hessian_at_x / scale`)
            # so that we're effectively dividing the loss by `scale`.
            cur_estimates = [
                v + (1 - damping) * cur_estimate - hvp / scale
                for v, cur_estimate, hvp in zip(vs, cur_estimates, hvps)
            ]

            # Update the Tqdm progress bar with the current norm so the user can
            # see it converge.
            if (j % 50 == 0) or (j == len(lissa_data_loader) - 1):
                norm = np.linalg.norm(_flatten_tensors(cur_estimates).cpu().numpy())
                recursion_iter.set_description(desc=f"calculating inverse HVP, norm = {norm:.5f}")

        # Accumulating X_{[i,S_2]}  (notation from the LiSSA (algo. 1) [https://arxiv.org/pdf/1602.03943.pdf]
        # Need to divide by `scale` again here because the `vs` represent gradients
        # that haven't been scaled yet.
        inverse_hvps = [
            inverse_hvp + cur_estimate / scale
            for inverse_hvp, cur_estimate in zip(inverse_hvps, cur_estimates)
        ]
    return_ihvp = _flatten_tensors(inverse_hvps)
    return_ihvp /= num_samples
    return return_ihvp
This function approximates the product of the inverse of the Hessian and
the vectors `vs` using LiSSA.

Adapted from [github.com/kohpangwei/influence-release]
(https://github.com/kohpangwei/influence-release/blob/0f656964867da6ddcca16c14b3e4f0eef38a7472/influence/genericNeuralNet.py#L475),
the repo for [Koh, P.W., & Liang, P. (2017)](https://api.semanticscholar.org/CorpusID:13193974),
and [github.com/xhan77/influence-function-analysis]
(https://github.com/xhan77/influence-function-analysis/blob/78d5a967aba885f690d34e88d68da8678aee41f1/bert_util.py#L336),
the repo for [Han, Xiaochuang et al. (2020)](https://api.semanticscholar.org/CorpusID:218628619).
allennlp/interpret/influence_interpreters/simple_influence.py