code: def spsa_grad(
      predict, loss_fn, x, y, delta, nb_sample, max_batch_size
  ):
      """Uses SPSA method to apprixmate gradient w.r.t `x`.
  
      Use the SPSA method to approximate the gradient of `loss_fn(predict(x), y)`
      with respect to `x`, based on the nonce `v`.
  
      :param predict: predict function (single argument: input).
      :param loss_fn: loss function (dual arguments: output, target).
      :param x: input argument for function `predict`.
      :param y: target argument for function `loss_fn`.
      :param v: perturbations of `x`.
      :param delta: scaling parameter of SPSA.
      :param reduction: how to reduce the gradients of the different samples.
  
      :return: return the approximated gradient of `loss_fn(predict(x), y)`
               with respect to `x`.
      """
  
      grad = torch.zeros_like(x)
      x = x.unsqueeze(0)
      y = y.unsqueeze(0)
  
      def f(xvar, yvar):
          return loss_fn(predict(xvar), yvar)
  
      x = x.expand(max_batch_size, *x.shape[1:]).contiguous()
      y = y.expand(max_batch_size, *y.shape[1:]).contiguous()
      v = torch.empty_like(x[:, :1, ...])
  
      for batch_size in _get_batch_sizes(nb_sample, max_batch_size):
          x_ = x[:batch_size]
          y_ = y[:batch_size]
          vb = v[:batch_size]
          vb = vb.bernoulli_().mul_(2.0).sub_(1.0)
          v_ = vb.expand_as(x_).contiguous()
          x_shape = x_.shape
          x_ = x_.view(-1, *x.shape[2:])
          y_ = y_.view(-1, *y.shape[2:])
          v_ = v_.view(-1, *v.shape[2:])
          df = f(x_ + delta * v_, y_) - f(x_ - delta * v_, y_)
          df = df.view(-1, *[1 for _ in v_.shape[1:]])
          grad_ = df / (2.0 * delta * v_)
          grad_ = grad_.view(x_shape)
          grad_ = grad_.sum(dim=0, keepdim=False)
          grad += grad_
      grad /= nb_sample
  
      return grad
  
file_path: advertorch/advertorch/attacks/spsa.py
imports: from __future__ import absolute_import
  from __future__ import division
  from __future__ import print_function
  from __future__ import unicode_literals
  import warnings
  import torch
  from .base import Attack
  from .base import LabelMixin
  from .utils import MarginalLoss
  from ..utils import is_float_or_torch_tensor, batch_clamp, clamp
label_desc: Use image node_id 3 for calling a global function with example usage: spsa_grad(predict, loss_fn, x, y, delta, nb_sample, max_batch_size) and returns: grad, loss_fn