code: def perturb(
      X: np.ndarray,
      eps: Union[float, np.ndarray] = 1e-08,
      proba: bool = False,
  ) -> Tuple[np.ndarray, np.ndarray]:
      """
      Apply perturbation to instance or prediction probabilities. Used for numerical calculation of gradients.
  
      Parameters
      ----------
      X
          Array to be perturbed.
      eps
          Size of perturbation.
      proba
          If ``True``, the net effect of the perturbation needs to be 0 to keep the sum of the probabilities equal to 1.
  
      Returns
      -------
      Instances where a positive and negative perturbation is applied.
      """
      # N = batch size; F = nb of features in X
      shape = X.shape
      X = np.reshape(X, (shape[0], -1))  # NxF
      dim = X.shape[1]  # F
      pert = np.tile(np.eye(dim) * eps, (shape[0], 1))  # (N*F)xF
      if proba:
          eps_n = eps / (dim - 1)
          pert += np.tile(
              (np.eye(dim) - np.ones((dim, dim))) * eps_n, (shape[0], 1)
          )  # (N*F)xF
      X_rep = np.repeat(X, dim, axis=0)  # (N*F)xF
      X_pert_pos, X_pert_neg = X_rep + pert, X_rep - pert
      shape = (dim * shape[0],) + shape[1:]
      X_pert_pos = np.reshape(
          X_pert_pos, shape
      )  # (N*F)x(shape of X[0])
      X_pert_neg = np.reshape(
          X_pert_neg, shape
      )  # (N*F)x(shape of X[0])
      return X_pert_pos, X_pert_neg
  
imports: from typing import Union, Tuple, Callable
  import numpy
label_desc: Use image node_id 1 for calling a global function with example usage: perturb(X, eps, proba) and returns: X_pert_pos,  X_pert_neg