code: def n_attack(
      predict_fn,
      loss_fn,
      x,
      y,
      projector,
      mu_init=None,
      nb_samples=100,
      nb_iter=40,
      eps_iter=0.02,
      sigma=0.1,
      targeted=False,
  ):
      """
      Models the distribution of adversarial examples near an input data point.
      Similar to an evolutionary algorithm, but parameteric.
  
      Used as part of NAttack.
  
      :param predict: forward pass function.
      :param loss_fn: loss function
          - must accept tensors of shape [nbatch, pop_size, ndim]
      :param x: input tensor.
      :param y: label tensor.
          - if None and self.targeted=False, compute y as predicted
          labels.
          - if self.targeted=True, then y must be the targeted labels.
      :param projector: function to project the perturbation into the eps-ball
          - must accept tensors of shape [nbatch, pop_size, ndim]
      :param nb_samples: number of samples for  (default 100)
      :param nb_iter: number of iterations (default 40)
      :param eps_iter: attack step size (default 0.02).
      :param sigma: variance to control sample generation (default 0.1)
      :param clip_min: mininum value per input dimension (default 0.)
      :param clip_max: mininum value per input dimension (default 1.)
      :param targeted: if the attack is targeted (default False)
      """
  
      n_batch, n_dim = x.shape
      y_repeat = y.repeat(nb_samples, 1).T.flatten()
  
      # [B,F]
      if mu_init is None:
          mu_t = torch.FloatTensor(n_batch, n_dim).normal_() * 0.001
          mu_t = mu_t.to(x.device)
      else:
          mu_t = mu_init.clone()
  
      # factor used to scale updates to mu_t
      alpha = eps_iter / (nb_samples * sigma)
  
      for _ in range(nb_iter):
          # Sample from N(0,I), shape [B, N, F]
          gauss_samples = torch.FloatTensor(
              n_batch, nb_samples, n_dim
          ).normal_()
          gauss_samples = gauss_samples.to(x.device)
  
          # Compute gi = g(mu_t + sigma * samples), shape [B, N, F]
          mu_samples = mu_t[:, None, :] + sigma * gauss_samples
          delta = projector(mu_samples)
          adv = (x[:, None, :] + delta).reshape(-1, n_dim)
          outputs = predict_fn(adv)
          losses = loss_fn(outputs, y_repeat, targeted=targeted)
          losses = losses.reshape(n_batch, nb_samples)
  
          # Convert losses into z_scores
          z_score = (losses - losses.mean(1)[:, None]) / (
              losses.std(1)[:, None] + 1e-7
          )
  
          # Update mu_t based on the z_scores
          mu_t = mu_t + alpha * (
              z_score[:, :, None] * gauss_samples
          ).sum(1)
  
      adv = adv.reshape(n_batch, nb_samples, -1)
  
      return adv, mu_t, losses
  
imports: from math import inf
  from typing import Optional
  import torch
  import torch.nn.functional
  from advertorch.attacks.base import Attack
  from advertorch.attacks.base import LabelMixin
  from .utils import _check_param, _flatten, _make_projector
  from advertorch.utils import to_one_hot
label_desc: Use image node_id 3 for calling a global function with example usage: n_attack(predict_fn, loss_fn, x, y, projector, mu_init, nb_samples, nb_iter, eps_iter, sigma, targeted) and returns: adv,  mu_t,  losses