Load a saved model, gather its predictions, and save a confidence report.
  :param filepath: path to model to evaluate
  :param train_start: index of first training set example to use
  :param train_end: index of last training set example to use
  :param test_start: index of first test set example to use
  :param test_end: index of last test set example to use
  :param which_set: 'train' or 'test'
  :param nb_iter: int, number of iterations of attack algorithm
    (note that different recipes will use this differently,
     for example many will run two attacks, one with nb_iter
     iterations and one with 25X more)
  :param base_eps: float, epsilon parameter for threat model, on a scale of [0, 1].
    Inferred from the dataset if not specified.
  :param base_eps_iter: float, a step size used in different ways by different recipes.
    Typically the step size for a PGD attack.
    Inferred from the dataset if not specified.
  :param base_eps_iter_small: float, a second step size for a more fine-grained attack.
    Inferred from the dataset if not specified.
  :param batch_size: int, batch size

def make_confidence_report_bundled(filepath, train_start=TRAIN_START,
                                   train_end=TRAIN_END, test_start=TEST_START,
                                   test_end=TEST_END, which_set=WHICH_SET,
                                   recipe=RECIPE, report_path=REPORT_PATH,
                                   nb_iter=NB_ITER, base_eps=None,
                                   base_eps_iter=None, base_eps_iter_small=None,
                                   batch_size=BATCH_SIZE):
  """
  Load a saved model, gather its predictions, and save a confidence report.
  :param filepath: path to model to evaluate
  :param train_start: index of first training set example to use
  :param train_end: index of last training set example to use
  :param test_start: index of first test set example to use
  :param test_end: index of last test set example to use
  :param which_set: 'train' or 'test'
  :param nb_iter: int, number of iterations of attack algorithm
    (note that different recipes will use this differently,
     for example many will run two attacks, one with nb_iter
     iterations and one with 25X more)
  :param base_eps: float, epsilon parameter for threat model, on a scale of [0, 1].
    Inferred from the dataset if not specified.
  :param base_eps_iter: float, a step size used in different ways by different recipes.
    Typically the step size for a PGD attack.
    Inferred from the dataset if not specified.
  :param base_eps_iter_small: float, a second step size for a more fine-grained attack.
    Inferred from the dataset if not specified.
  :param batch_size: int, batch size
  """
  # Avoid circular import
  from cleverhans import attack_bundling
  if callable(recipe):
    run_recipe = recipe
  else:
    run_recipe = getattr(attack_bundling, recipe)

  # Set logging level to see debug information
  set_log_level(logging.INFO)

  # Create TF session
  sess = tf.Session()

  assert filepath.endswith('.joblib')
  if report_path is None:
    report_path = filepath[:-len('.joblib')] + "_bundled_report.joblib"

  with sess.as_default():
    model = load(filepath)
  assert len(model.get_params()) > 0
  factory = model.dataset_factory
  factory.kwargs['train_start'] = train_start
  factory.kwargs['train_end'] = train_end
  factory.kwargs['test_start'] = test_start
  factory.kwargs['test_end'] = test_end
  dataset = factory()

  center = dataset.kwargs['center']
  if 'max_val' in factory.kwargs:
    max_value = factory.kwargs['max_val']
  elif hasattr(dataset, 'max_val'):
    max_value = dataset.max_val
  else:
    raise AttributeError("Can't find max_value specification")
  min_value = 0. - center * max_value
  value_range = max_value - min_value

  if 'CIFAR' in str(factory.cls):
    if base_eps is None:
      base_eps = 8. / 255.
    if base_eps_iter is None:
      base_eps_iter = 2. / 255.
    if base_eps_iter_small is None:
      base_eps_iter_small = 1. / 255.
  elif 'MNIST' in str(factory.cls):
    if base_eps is None:
      base_eps = .3
    if base_eps_iter is None:
      base_eps_iter = .1
    base_eps_iter_small = None
  else:
    # Note that it is not required to specify base_eps_iter_small
    if base_eps is None or base_eps_iter is None:
      raise NotImplementedError("Not able to infer threat model from " + str(factory.cls))

  eps = base_eps * value_range
  eps_iter = base_eps_iter * value_range
  if base_eps_iter_small is None:
    eps_iter_small = None
  else:
    eps_iter_small = base_eps_iter_small * value_range
  clip_min = min_value
  clip_max = max_value

  x_data, y_data = dataset.get_set(which_set)
  assert x_data.max() <= max_value
  assert x_data.min() >= min_value

  assert eps_iter <= eps
  assert eps_iter_small is None or eps_iter_small <= eps

  # Different recipes take different arguments.
  # For now I don't have an idea for a beautiful unifying framework, so
  # we get an if statement.
  if recipe == 'random_search_max_confidence_recipe':
    # pylint always checks against the default recipe here
    # pylint: disable=no-value-for-parameter
    run_recipe(sess=sess, model=model, x=x_data, y=y_data, eps=eps,
               clip_min=clip_min, clip_max=clip_max, report_path=report_path)
  else:
    run_recipe(sess=sess, model=model, x=x_data, y=y_data,
               nb_classes=dataset.NB_CLASSES, eps=eps, clip_min=clip_min,
               clip_max=clip_max, eps_iter=eps_iter, nb_iter=nb_iter,
               report_path=report_path, eps_iter_small=eps_iter_small, batch_size=batch_size)