code: def compute_score_offset(
      stat_target: Union[np.ndarray, Sequence[float]],
      stat_in: Sequence[np.ndarray],
      stat_out: Sequence[np.ndarray],
      option: str = "both",
      median_or_mean: str = "median",
  ) -> np.ndarray:
      """Computes score of each sample as stat_target - some offset.
  
      Args:
        stat_target: a list or numpy array where stat_target[i] is the statistics of
          example i computed from the target model. stat_target[i] is an array of k
          scalars for k being the number of augmentations for each sample.
        stat_in: a list where stat_in[i] is the in-training statistics of example i.
          stat_in[i] is a m by k numpy array where m is the number of shadow models
          and k is the number of augmentations for each sample. m can be different
          for different examples.
        stat_out: a list where stat_out[i] is the out-training statistics of example
          i. stat_out[i] is a m by k numpy array where m is the number of shadow
          models and k is the number of augmentations for each sample.
        option: using stat_in ("in"), stat_out ("out"), or both ("both").
        median_or_mean: use median or mean across shadow models.
  
      Returns:
        The score of each sample as stat_target - some offset, where offset is
        computed with stat_in, stat_out, or both depending on the option.
        The relation between the score and the membership depends on that
        between stat_target and membership.
      """
      if option not in ["both", "in", "out"]:
          raise ValueError('option should be "both", "in", or "out".')
      if median_or_mean not in ["median", "mean"]:
          raise ValueError(
              'median_or_mean should be either "median" or "mean".'
          )
      if option in ["in", "both"]:
          if any([s.ndim != 2 for s in stat_in]):
              raise ValueError(
                  "Each element in stat_in should be a 2-d numpy array."
              )
          if any([s.shape[1] != stat_in[0].shape[1] for s in stat_in]):
              raise ValueError(
                  "Each element in stat_in should have the same size "
                  "in the second dimension."
              )
      if option in ["out", "both"]:
          if any([s.ndim != 2 for s in stat_out]):
              raise ValueError(
                  "Each element in stat_out should be a 2-d numpy array."
              )
          if any(
              [s.shape[1] != stat_out[0].shape[1] for s in stat_out]
          ):
              raise ValueError(
                  "Each element in stat_out should have the same size "
                  "in the second dimension."
              )
      func_avg = functools.partial(
          np.nanmedian if median_or_mean == "median" else np.nanmean,
          axis=0,
      )
  
      if (
          option == "both"
      ):  # use the average of the in-score and out-score
          avg_in = np.array(list(map(func_avg, stat_in)))
          avg_out = np.array(list(map(func_avg, stat_out)))
          # use average in case of NaN
          replace_nan_with_column_mean(avg_in)
          replace_nan_with_column_mean(avg_out)
          offset = (avg_in + avg_out) / 2
      elif option == "in":  # use in-score only
          offset = np.array(list(map(func_avg, stat_in)))
          replace_nan_with_column_mean(offset)
      else:  # use out-score only
          offset = np.array(list(map(func_avg, stat_out)))
          replace_nan_with_column_mean(offset)
      scores = (stat_target - offset).mean(axis=1)
      return scores
  
file_path: privacy/tensorflow_privacy/privacy/privacy_tests/membership_inference_attack/advanced_mia.py
imports: import functools
  from typing import Optional, Sequence, Union
  import numpy
  import scipy.stats
  from tensorflow_privacy.privacy.privacy_tests.utils import log_loss
label_desc: Use image node_id 2 for calling a global function with example usage: compute_score_offset(stat_target, stat_in, stat_out, option, median_or_mean) and returns: scores