class_docstr: The ElasticNet L1 Attack, https://arxiv.org/abs/1709.04114
  
  :param predict: forward pass function.
  :param num_classes: number of clasess.
  :param confidence: confidence of the adversarial examples.
  :param targeted: if the attack is targeted.
  :param learning_rate: the learning rate for the attack algorithm
  :param binary_search_steps: number of binary search times to find the
      optimum
  :param max_iterations: the maximum number of iterations
  :param abort_early: if set to true, abort early if getting stuck in local
      min
  :param initial_const: initial value of the constant c
  :param clip_min: mininum value per input dimension.
  :param clip_max: maximum value per input dimension.
  :param beta: hyperparameter trading off L2 minimization for L1 minimization
  :param decision_rule: EN or L1. Select final adversarial example from
                        all successful examples based on the least
                        elastic-net or L1 distortion criterion.
  :param loss_fn: loss function
class_docstr_tok: ["The","ElasticNet","L1","Attack",",","https",":","\/\/arxiv.org\/abs\/1709.04114",":","param","predict",":","forward","pass","function",".",":","param","num_classes",":","number","of","clasess",".",":","param","confidence",":","confidence","of","the","adversarial","examples",".",":","param","targeted",":","if","the","attack","is","targeted",".",":","param","learning_rate",":","the","learning","rate","for","the","attack","algorithm",":","param","binary_search_steps",":","number","of","binary","search","times","to","find","the","optimum",":","param","max_iterations",":","the","maximum","number","of","iterations",":","param","abort_early",":","if","set","to","true",",","abort","early","if","getting","stuck","in","local","min",":","param","initial_const",":","initial","value","of","the","constant","c",":","param","clip_min",":","mininum","value","per","input","dimension",".",":","param","clip_max",":","maximum","value","per","input","dimension",".",":","param","beta",":","hyperparameter","trading","off","L2","minimization","for","L1","minimization",":","param","decision_rule",":","EN","or","L1",".","Select","final","adversarial","example","from","all","successful","examples","based","on","the","least","elastic-net","or","L1","distortion","criterion",".",":","param","loss_fn",":","loss","function"]
code: def perturb(self, x, y=None):
      x, y = self._verify_and_process_inputs(x, y)
  
      # Initialization
      if y is None:
          y = self._get_predicted_label(x)
  
      x = replicate_input(x)
      batch_size = len(x)
      coeff_lower_bound = x.new_zeros(batch_size)
      coeff_upper_bound = x.new_ones(batch_size) * COEFF_UPPER
      loss_coeffs = torch.ones_like(y).float() * self.initial_const
  
      final_dist = [DIST_UPPER] * batch_size
      final_labels = [INVALID_LABEL] * batch_size
  
      final_advs = x.clone()
      y_onehot = to_one_hot(y, self.num_classes).float()
  
      final_dist = torch.FloatTensor(final_dist).to(x.device)
      final_labels = torch.LongTensor(final_labels).to(x.device)
  
      # Start binary search
      for outer_step in range(self.binary_search_steps):
          self.global_step = 0
  
          # slack vector from the paper
          yy_k = nn.Parameter(x.clone())
          xx_k = x.clone()
  
          cur_dist = [DIST_UPPER] * batch_size
          cur_labels = [INVALID_LABEL] * batch_size
  
          cur_dist = torch.FloatTensor(cur_dist).to(x.device)
          cur_labels = torch.LongTensor(cur_labels).to(x.device)
  
          prevloss = PREV_LOSS_INIT
  
          if self.repeat and outer_step == (
              self.binary_search_steps - 1
          ):
              loss_coeffs = coeff_upper_bound
  
          lr = self.learning_rate
  
          for ii in range(self.max_iterations):
              # reset gradient
              if yy_k.grad is not None:
                  yy_k.grad.detach_()
                  yy_k.grad.zero_()
  
              # loss over yy_k with only L2 same as C&W
              # we don't update L1 loss with SGD because we use ISTA
              output = self.predict(yy_k)
              l2distsq = calc_l2distsq(yy_k, x)
              loss_opt = self._loss_fn(
                  output,
                  y_onehot,
                  None,
                  l2distsq,
                  loss_coeffs,
                  opt=True,
              )
              loss_opt.backward()
  
              # gradient step
              yy_k.data.add_(-lr, yy_k.grad.data)
              self.global_step += 1
  
              # ploynomial decay of learning rate
              lr = (
                  self.init_learning_rate
                  * (1 - self.global_step / self.max_iterations) ** 0.5
              )
  
              yy_k, xx_k = self._fast_iterative_shrinkage_thresholding(
                  x, yy_k, xx_k
              )
  
              # loss ElasticNet or L1 over xx_k
              with torch.no_grad():
                  output = self.predict(xx_k)
                  l2distsq = calc_l2distsq(xx_k, x)
                  l1dist = calc_l1dist(xx_k, x)
  
                  if self.decision_rule == "EN":
                      dist = l2distsq + (l1dist * self.beta)
                  elif self.decision_rule == "L1":
                      dist = l1dist
                  loss = self._loss_fn(
                      output, y_onehot, l1dist, l2distsq, loss_coeffs
                  )
  
                  if self.abort_early:
                      if (
                          ii % (self.max_iterations // NUM_CHECKS or 1)
                          == 0
                      ):
                          if loss > prevloss * ONE_MINUS_EPS:
                              break
                          prevloss = loss
  
                  self._update_if_smaller_dist_succeed(
                      xx_k.data,
                      y,
                      output,
                      dist,
                      batch_size,
                      cur_dist,
                      cur_labels,
                      final_dist,
                      final_labels,
                      final_advs,
                  )
  
          self._update_loss_coeffs(
              y,
              cur_labels,
              batch_size,
              loss_coeffs,
              coeff_upper_bound,
              coeff_lower_bound,
          )
  
      return final_advs
  
imports: from __future__ import absolute_import
  from __future__ import division
  from __future__ import print_function
  from __future__ import unicode_literals
  import torch
  import torch.nn
  from advertorch.utils import calc_l2distsq
  from advertorch.utils import calc_l1dist
  from advertorch.utils import clamp
  from advertorch.utils import to_one_hot
  from advertorch.utils import replicate_input
  from .base import Attack
  from .base import LabelMixin
  from .utils import is_successful
label_desc: Use image node_id 7 for calling the ElasticNetL1Attack obj's underlying member method code with example usage: obj.perturb(x, y) and returns: final_advs