code: def _run_threshold_attack(attack_input: AttackInputData):
      """Runs a threshold attack on loss."""
      ntrain, ntest = (
          attack_input.get_train_size(),
          attack_input.get_test_size(),
      )
      loss_train = attack_input.get_loss_train()
      loss_test = attack_input.get_loss_test()
      if loss_train is None or loss_test is None:
          raise ValueError(
              "Not possible to run threshold attack without losses."
          )
      if attack_input.is_multilabel_data():
          logging.info(
              (
                  "For multilabel data, when a threshold attack is requested, "
                  "losses are summed over the class axis before slicing."
              )
          )
          loss_train = np.sum(loss_train, axis=1)
          loss_test = np.sum(loss_test, axis=1)
      fpr, tpr, thresholds = metrics.roc_curve(
          np.concatenate((np.ones(ntrain), np.zeros(ntest))),
          # roc_curve uses classifier in the form of
          # "score >= threshold ==> predict positive", while training data has lower
          # loss, so we negate the loss.
          -np.concatenate((loss_train, loss_test)),
      )
      # 'test_train_ratio' is the ratio of test data size to train data size. It is
      # used to compute the Positive Predictive Value.
      test_train_ratio = ntest / ntrain
  
      roc_curve = RocCurve(
          tpr=tpr,
          fpr=fpr,
          thresholds=-thresholds,  # negate because we negated the loss
          test_train_ratio=test_train_ratio,
      )
      epsilon_lower_bound_value = EpsilonLowerBoundValue(
          bounds=elb.EpsilonLowerBound(
              pos_scores=loss_train,
              neg_scores=loss_test,
              alpha=EPSILON_ALPHA,
              two_sided_threshold=True,
          ).compute_epsilon_lower_bounds(
              methods=EPSILON_METHODS, k=EPSILON_K
          )
      )
  
      return SingleAttackResult(
          slice_spec=_get_slice_spec(attack_input),
          data_size=DataSize(ntrain=ntrain, ntest=ntest),
          attack_type=AttackType.THRESHOLD_ATTACK,
          # Negate loss because training examples are expected to have lower loss.
          membership_scores_train=-attack_input.get_loss_train(),
          membership_scores_test=-attack_input.get_loss_test(),
          roc_curve=roc_curve,
          epsilon_lower_bound_value=epsilon_lower_bound_value,
      )
  
imports: import logging
  from typing import Iterable, List, Optional, Union
  import numpy
  from scipy import special
  from sklearn import metrics
  from sklearn import model_selection
  from tensorflow_privacy.privacy.privacy_tests import epsilon_lower_bound
  from tensorflow_privacy.privacy.privacy_tests.membership_inference_attack import models
  from tensorflow_privacy.privacy.privacy_tests.membership_inference_attack.data_structures import AttackInputData
  from tensorflow_privacy.privacy.privacy_tests.membership_inference_attack.data_structures import AttackResults
  from tensorflow_privacy.privacy.privacy_tests.membership_inference_attack.data_structures import AttackType
  from tensorflow_privacy.privacy.privacy_tests.membership_inference_attack.data_structures import DataSize
  from tensorflow_privacy.privacy.privacy_tests.membership_inference_attack.data_structures import EPSILON_ALPHA
  from tensorflow_privacy.privacy.privacy_tests.membership_inference_attack.data_structures import EPSILON_K
  from tensorflow_privacy.privacy.privacy_tests.membership_inference_attack.data_structures import EPSILON_METHODS
  from tensorflow_privacy.privacy.privacy_tests.membership_inference_attack.data_structures import EpsilonLowerBoundValue
  from tensorflow_privacy.privacy.privacy_tests.membership_inference_attack.data_structures import MembershipProbabilityResults
  from tensorflow_privacy.privacy.privacy_tests.membership_inference_attack.data_structures import PrivacyReportMetadata
  from tensorflow_privacy.privacy.privacy_tests.membership_inference_attack.data_structures import RocCurve
  from tensorflow_privacy.privacy.privacy_tests.membership_inference_attack.data_structures import SingleAttackResult
  from tensorflow_privacy.privacy.privacy_tests.membership_inference_attack.data_structures import SingleMembershipProbabilityResult
  from tensorflow_privacy.privacy.privacy_tests.membership_inference_attack.data_structures import SingleSliceSpec
  from tensorflow_privacy.privacy.privacy_tests.membership_inference_attack.data_structures import SlicingSpec
  from tensorflow_privacy.privacy.privacy_tests.membership_inference_attack.dataset_slicing import get_single_slice_specs
  from tensorflow_privacy.privacy.privacy_tests.membership_inference_attack.dataset_slicing import get_slice
label_desc: Use image node_id 3 for calling a global function with example usage: _run_threshold_attack(attack_input) and returns: SingleAttackResult