class_docstr: This class implements gradient attack method, and is the base of FGSM, BIM,
  ILCM, etc.
class_docstr_tok: ["This","class","implements","gradient","attack","method",",","and","is","the","base","of","FGSM",",","BIM",",","ILCM",",","etc","."]
docstr: Apply the gradient attack method.
  :param adversary(Adversary):
      The Adversary object.
  :param norm_ord(int):
      Order of the norm, such as np.inf, 1, 2, etc. It can't be 0.
  :param epsilons(list|tuple|int):
      Attack step size (input variation).
      Largest step size if epsilons is not iterable.
  :param steps:
      The number of attack iteration.
  :param epsilon_steps:
      The number of Epsilons' iteration for each attack iteration.
  :return:
      adversary(Adversary): The Adversary object.
docstr_tok: ["Apply","the","gradient","attack","method",".",":","param","adversary","(","Adversary",")",":","The","Adversary","object",".",":","param","norm_ord","(","int",")",":","Order","of","the","norm",",","such","as","np.inf",",","1",",","2",",","etc",".","It","ca","n't","be","0.",":","param","epsilons","(","list|tuple|int",")",":","Attack","step","size","(","input","variation",")",".","Largest","step","size","if","epsilons","is","not","iterable",".",":","param","steps",":","The","number","of","attack","iteration",".",":","param","epsilon_steps",":","The","number","of","Epsilons","'","iteration","for","each","attack","iteration",".",":","return",":","adversary","(","Adversary",")",":","The","Adversary","object","."]
code: def _apply(
      self,
      adversary,
      norm_ord=np.inf,
      epsilons=0.01,
      epsilons_max=0.5,
      steps=10,
      epsilon_steps=100,
  ):
      # epsilons_max 为动态调整epsilon时的上限 静态epsilon算法时epsilon_steps=1  epsilons_max=epsilons即可
      """
      Apply the gradient attack method.
      :param adversary(Adversary):
          The Adversary object.
      :param norm_ord(int):
          Order of the norm, such as np.inf, 1, 2, etc. It can't be 0.
      :param epsilons(list|tuple|int):
          Attack step size (input variation).
          Largest step size if epsilons is not iterable.
      :param steps:
          The number of attack iteration.
      :param epsilon_steps:
          The number of Epsilons' iteration for each attack iteration.
      :return:
          adversary(Adversary): The Adversary object.
      """
      if norm_ord == 0:
          raise ValueError("L0 norm is not supported!")
  
      if not self.support_targeted:
          if adversary.is_targeted_attack:
              raise ValueError(
                  "This attack method doesn't support targeted attack!"
              )
  
      logging.info(
          "epsilons={0},epsilons_max={1},steps={2},epsilon_steps={3}".format(
              epsilons, epsilons_max, steps, epsilon_steps
          )
      )
  
      if not isinstance(epsilons, Iterable):
          # 从epsilons到0.5逐步增大
          epsilons = np.linspace(
              epsilons, epsilons_max, num=epsilon_steps
          )
  
      pre_label = adversary.original_label
      min_, max_ = self.model.bounds()
  
      # assert self.model.channel_axis() == adversary.original.ndim
      assert (
          self.model.channel_axis() == 1
          or self.model.channel_axis() == adversary.original.shape[0]
          or self.model.channel_axis() == adversary.original.shape[-1]
      )
  
      # 从[epsilon,0.5]动态调整epsilon 直到攻击成功
      for epsilon in epsilons[:]:
          step = 1
          # 强制拷贝 避免针对adv_img的修改也影响adversary.original
          adv_img = np.copy(adversary.original)
          if epsilon == 0.0:
              continue
          for i in range(steps):
              if adversary.is_targeted_attack:
                  gradient = +self.model.gradient(
                      adv_img, adversary.target_label
                  )
              else:
                  gradient = -self.model.gradient(
                      adv_img, adversary.original_label
                  )
              if norm_ord == np.inf:
                  gradient_norm = np.sign(gradient)
              else:
                  gradient_norm = gradient / self._norm(
                      gradient, ord=norm_ord
                  )
  
              # logging.info('epsilon * gradient_norm={0}'.format(gradient_norm * epsilon))
              # logging.info('epsilon * gradient_norm* (max_ - min_)={0}'.format(gradient_norm * epsilon* (max_ - min_)))
              # 改进的实现 不用考虑特征取值范围
              # adv_img = adv_img + epsilon * gradient_norm * (max_ - min_)
              # 按照论文实现
              adv_img = adv_img + epsilon * gradient_norm
  
              adv_img = np.clip(adv_img, min_, max_)
              adv_label = np.argmax(self.model.predict(adv_img))
              logging.info(
                  "step={}, epsilon = {:.5f}, pre_label = {}, adv_label={} logits={}".format(
                      step,
                      epsilon,
                      pre_label,
                      adv_label,
                      self.model.predict(adv_img)[adv_label],
                  )
              )
              if adversary.try_accept_the_example(adv_img, adv_label):
                  return adversary
              step += 1
      return adversary
  
imports: from __future__ import division
  from builtins import range
  import logging
  from collections import Iterable
  import numpy
  from .base import Attack
  from functools import reduce
label_desc: Use image node_id 2 for calling the GradientMethodAttack obj's underlying member method code with example usage: obj._apply(adversary, norm_ord, epsilons, epsilons_max, steps, epsilon_steps) and returns: adversary, adversary