def estimator_spec_eval(self, features, logits, labels, loss, losses_dict):
    """Constructs `tf.estimator.EstimatorSpec` for EVAL (evaluation) mode."""
    del losses_dict
    hparams = self.hparams

    if not hasattr(hparams, "problem"):
      raise NotImplementedError(_no_problem_err("estimator_spec_eval"))

    problem = hparams.problem

    if common_layers.is_xla_compiled():
      # Note: important to call this before remove_summaries()
      if self.hparams.tpu_enable_host_call:
        host_call = self.create_eval_host_call()
      else:
        host_call = None

      remove_summaries()

      eval_metrics_fn = create_tpu_eval_metrics_fn(problem, hparams)

      batch_size = [feature.shape.as_list()[0] for _, feature
                    in features.items() if feature.shape.ndims][0]

      # Add batch dimension to all features since tpu requires the batch
      # dimension on all tensors.
      for name, feature in features.items():
        if not feature.shape.as_list():
          # All features must have a batch dimension
          feature = tf.tile(tf.expand_dims(feature, 0), [batch_size])
        features[name] = feature

      eval_metrics_fn_args = dict(
          logits=logits,  # possibly a dict
          labels=labels,
          features=features,  # dict
      )

      eval_metrics_fn_flat_args = _flatten_dict(eval_metrics_fn_args)
      return tf.contrib.tpu.TPUEstimatorSpec(
          tf.estimator.ModeKeys.EVAL,
          eval_metrics=(eval_metrics_fn, eval_metrics_fn_flat_args),
          host_call=host_call,
          loss=loss)
    else:
      task_list = [problem]
      if hasattr(problem, "task_list"):
        task_list = problem.task_list

      eval_metrics_fns = metrics.create_evaluation_metrics(task_list, hparams)
      eval_metrics = {}
      for metric_name, metric_fn in six.iteritems(eval_metrics_fns):
        if isinstance(logits, dict):
          # the key is located in the center of metric_name: "metrics-%s/%s/%s"
          k = metric_name.split("/")[1]
          if k in logits:
            eval_metrics[metric_name] = metric_fn(logits[k], features,
                                                  features[k])
          else:
            # We do not make it an error because we sometimes run models that
            # predict only parts of the targets defined by the Problem class.
            # For example, an autoencoder or pure-video model can run on a gym
            # problem even if another model is also predicting other things,
            # like actions or rewards.
            tf.logging.warning("No key %s in logits for evaluation." % k)
        else:
          eval_metrics[metric_name] = metric_fn(logits, features,
                                                features["targets"])
      if isinstance(logits, dict):
        predictions = logits
      else:
        predictions = {"predictions": logits}

      evaluation_hooks = []
      # Create a SummarySaverHook
      eval_dir = os.path.join(
          self.hparams.model_dir,
          self.hparams.get("eval_dir_name", "eval"))
      eval_summary_hook = tf.train.SummarySaverHook(
          save_steps=1,
          output_dir=eval_dir,
          summary_op=tf.summary.merge_all())
      evaluation_hooks.append(eval_summary_hook)

      evaluation_hooks += problem.eval_hooks(features, logits, hparams)

      return tf.estimator.EstimatorSpec(
          tf.estimator.ModeKeys.EVAL,
          predictions=predictions,
          eval_metric_ops=eval_metrics,
          evaluation_hooks=evaluation_hooks,
          loss=loss)
Constructs `tf.estimator.EstimatorSpec` for EVAL (evaluation) mode.