TensorFlow Eager implementation of the Fast Gradient Method.
    :param x: the input variable
    :param targeted: Is the attack targeted or untargeted? Untargeted, the
                     default, will try to make the label incorrect.
                     Targeted will instead try to move in the direction
                     of being more like y.
    :return: a tensor for the adversarial example

def fgm(self, x, labels, targeted=False):
    """
    TensorFlow Eager implementation of the Fast Gradient Method.
    :param x: the input variable
    :param targeted: Is the attack targeted or untargeted? Untargeted, the
                     default, will try to make the label incorrect.
                     Targeted will instead try to move in the direction
                     of being more like y.
    :return: a tensor for the adversarial example
    """
    # Compute loss
    with tf.GradientTape() as tape:
      # input should be watched because it may be
      # combination of trainable and non-trainable variables
      tape.watch(x)
      loss_obj = LossCrossEntropy(self.model, smoothing=0.)
      loss = loss_obj.fprop(x=x, y=labels)
      if targeted:
        loss = -loss

    # Define gradient of loss wrt input
    grad = tape.gradient(loss, x)
    optimal_perturbation = attacks.optimize_linear(grad, self.eps, self.ord)

    # Add perturbation to original example to obtain adversarial example
    adv_x = x + optimal_perturbation

    # If clipping is needed
    # reset all values outside of [clip_min, clip_max]
    if (self.clip_min is not None) and (self.clip_max is not None):
      adv_x = tf.clip_by_value(adv_x, self.clip_min, self.clip_max)
    return adv_x