code: def estimator_spec_eval(
        self, features, logits, labels, loss, restore_hook, use_tpu):
      
      hparams = self.hparams
      problem = hparams.problem
      if logits.get_shape().ndims == 3:
        logits = tf.expand_dims(tf.expand_dims(logits, 2), 3)
  
      # Support for multiproblem
      task_list = [problem]
      if hasattr(problem, "task_list"):
        task_list = problem.task_list
  
      eval_metrics_fns = metrics.create_evaluation_metrics(task_list, hparams)
  
      if use_tpu:
        def metric_fn(tf_logits, labels):
          with tf.device("cpu:0"), mtf.utils.outside_all_rewrites():
            eval_metrics = {}
            for metric_name, metric_fn in six.iteritems(eval_metrics_fns):
              if metric_name.split("/")[-1] not in t2t_model.TPU_METRIC_BLACKLIST:
                eval_metrics[metric_name] = metric_fn(
                    tf_logits, None, tf.identity(labels))
            return eval_metrics
        return tpu_estimator.TPUEstimatorSpec(
            tf.estimator.ModeKeys.EVAL,
            evaluation_hooks=[restore_hook],
            loss=loss,
            eval_metrics=(metric_fn, [logits, labels]))
      else:
        eval_metrics = {}
        predictions = {"predictions": logits}
        for metric_name, metric_fn in six.iteritems(eval_metrics_fns):
          eval_metrics[metric_name] = metric_fn(logits, features,
                                                features["targets"])
  
        return tf.estimator.EstimatorSpec(
            tf.estimator.ModeKeys.EVAL,
            predictions=predictions,
            eval_metric_ops=eval_metrics,
            evaluation_hooks=[restore_hook],
            loss=loss)
docs: Construct EstimatorSpec for EVAL mode.