def compute_predictions(eval_example, candidate_beam, max_answer_length):
  """Converts an eval_example into a `ScoreSummary` object for evaluation.

  This performs python post-processing (after running NN graph in tensorflow)
  in order to get the best answer.

  Args:
    eval_example: `EvalExample` instance with features, results.
    candidate_beam: see FLAGS.candidate_beam.
    max_answer_length: see FLAGS.max_answer_length.

  Returns:
    A `ScoreSummary` or `None` if no passage prediction could be found.
  """

  predictions = []
  n_best_size = candidate_beam

  if not eval_example.results:
    return None
  if len(eval_example.features) != len(eval_example.results):
    logging.warning(
        "ERROR: len(features)=%s, but len(results)=%d for eval_example %s",
        len(eval_example.features), len(eval_example.results),
        eval_example.example_id)
    return None

  for unique_id, result in eval_example.results.items():
    if unique_id not in eval_example.features:
      logging.warning("No feature found with unique_id: %s", unique_id)
      return None

    wp_start_offset = (
        eval_example.features[unique_id]["wp_start_offset"].int64_list.value)
    wp_end_offset = (
        eval_example.features[unique_id]["wp_end_offset"].int64_list.value)
    language_id = (
        eval_example.features[unique_id]["language_id"].int64_list.value[0])
    language_name = data.Language(language_id).name.lower()
    start_indexes = get_best_indexes(result["start_logits"], n_best_size)
    end_indexes = get_best_indexes(result["end_logits"], n_best_size)
    cls_token_score = result["start_logits"][0] + result["end_logits"][0]
    for start_index in start_indexes:
      for end_index in end_indexes:
        if end_index < start_index:
          continue
        # This means these are dummy tokens (like separators).
        if wp_start_offset[start_index] == -1:
          continue
        if wp_end_offset[end_index] == -1:
          continue
        length = end_index - start_index + 1
        if length > max_answer_length:
          continue
        summary = ScoreSummary()
        summary.minimal_span_score = (
            result["start_logits"][start_index] +
            result["end_logits"][end_index])
        summary.cls_token_score = cls_token_score
        summary.answer_type_logits = result["answer_type_logits"]

        start_offset = wp_start_offset[start_index]
        end_offset = wp_end_offset[end_index] + 1

        # Span logits minus the [CLS] logits seems to be close to the best.
        score = summary.minimal_span_score - summary.cls_token_score
        predictions.append(
            (score, summary, language_name, start_offset, end_offset))

  if not predictions:
    logging.warning("No predictions for eval_example %s",
                    eval_example.example_id)
    return None

  score, summary, language_name, start_span, end_span = max(
      predictions, key=lambda x: x[0])
  minimal_span = Span(start_span, end_span)
  passage_span_index = 0
  for c_ind, c in enumerate(eval_example.candidates):
    start = minimal_span.start_byte_offset
    end = minimal_span.end_byte_offset
    if c["plaintext_start_byte"] <= start and c["plaintext_end_byte"] >= end:
      passage_span_index = c_ind
      break
  else:
    logging.warning("No passage predicted for eval_example %s. Choosing first.",
                    eval_example.example_id)
  summary.predicted_label = {
      "example_id": eval_example.example_id,
      "language": language_name,
      "passage_answer_index": passage_span_index,
      "passage_answer_score": score,
      "minimal_answer": {
          "start_byte_offset": minimal_span.start_byte_offset,
          "end_byte_offset": minimal_span.end_byte_offset
      },
      "minimal_answer_score": score,
      "yes_no_answer": "NONE"
  }
  return summary
Converts an eval_example into a `ScoreSummary` object for evaluation.

  This performs python post-processing (after running NN graph in tensorflow)
  in order to get the best answer.

  Args:
    eval_example: `EvalExample` instance with features, results.
    candidate_beam: see FLAGS.candidate_beam.
    max_answer_length: see FLAGS.max_answer_length.

  Returns:
    A `ScoreSummary` or `None` if no passage prediction could be found.
  
language/canine/tydiqa/postproc.py