class_docstr: Implement the Mixup data augmentation defence approach in TensorFlow v2.
  
  | Paper link: https://arxiv.org/abs/1710.09412
  
  | Please keep in mind the limitations of defences. For more information on the limitations of this defence,
      see https://arxiv.org/abs/1803.09868 . For details on how to evaluate classifier security in general, see
      https://arxiv.org/abs/1902.06705
docstr: Apply Mixup data augmentation to feature data `x` and labels `y`.
  
  :param x: Feature data to augment with shape `(batch_size, ...)`.
  :param y: Labels of `x` either one-hot or multi-hot encoded of shape `(nb_samples, nb_classes)`
            or class indices of shape `(nb_samples,)`.
  :return: Data augmented sample. The returned labels will be probability vectors of shape
           `(nb_samples, nb_classes)`.
  :raises `ValueError`: If no labels are provided.
code: def forward(
      self, x: "tf.Tensor", y: Optional["tf.Tensor"] = None
  ) -> Tuple["tf.Tensor", Optional["tf.Tensor"]]:
      """
      Apply Mixup data augmentation to feature data `x` and labels `y`.
  
      :param x: Feature data to augment with shape `(batch_size, ...)`.
      :param y: Labels of `x` either one-hot or multi-hot encoded of shape `(nb_samples, nb_classes)`
                or class indices of shape `(nb_samples,)`.
      :return: Data augmented sample. The returned labels will be probability vectors of shape
               `(nb_samples, nb_classes)`.
      :raises `ValueError`: If no labels are provided.
      """
      import tensorflow as tf  # lgtm [py/repeated-import]
  
      if y is None:
          raise ValueError("Labels `y` cannot be None.")
  
      # convert labels to one-hot encoding
      if len(y.shape) == 2:
          y_one_hot = y
      elif len(y.shape) == 1:
          y_one_hot = tf.one_hot(
              y, self.num_classes, on_value=1.0, off_value=0.0
          )
      else:
          raise ValueError(
              "Shape of labels not recognised. "
              "Please provide labels in shape (nb_samples,) or (nb_samples, nb_classes)"
          )
  
      n = x.shape[0]
  
      # sample the mixing factor from the Dirichlet distribution
      lmbs = np.random.dirichlet([self.alpha] * self.num_mix)
  
      x_aug = lmbs[0] * x
      y_aug = lmbs[0] * y_one_hot
      for lmb in lmbs[1:]:
          # randomly choose indices for samples to mix
          indices = tf.random.shuffle(tf.range(n))
          x_aug = x_aug + lmb * tf.gather(x, indices, axis=None)
          y_aug = y_aug + lmb * tf.gather(y_one_hot, indices, axis=None)
  
      return x_aug, y_aug
  
file_path: adversarial-robustness-toolbox/art/defences/preprocessor/mixup/mixup_tensorflow.py
imports: from __future__ import absolute_import, division, print_function, unicode_literals
  import logging
  from typing import Optional, Tuple, TYPE_CHECKING
  import numpy
  from art.defences.preprocessor.preprocessor import PreprocessorTensorFlowV2
label_desc: Use image node_id 2 for calling the MixupTensorFlowV2 obj's underlying member method code with example usage: obj.forward(x, y) and returns: x_aug,  y_aug