class_docstr: 用于评测模型性能好坏的评测器；
  
  .. note::
  
      ``Evaluator`` 与 ``Trainer`` 类似，都是使用 ``Driver`` 作为底层来实现评测或者训练，因此大多数与 ``Trainer`` 同名的参数的意义和使用都与
      ``Trainer`` 中的参数相同，对于这些参数，您可以参考 ``Trainer`` 的文档来获取更详细的信息；详见 :class:`~fastNLP.core.controllers.trainer.Trainer`；
  
  :param model: 训练所需要的模型，例如 ``torch.nn.Module``，等价于 ``Trainer`` 中的 ``model`` 参数；
  :param dataloaders: 用于评测的数据集。如果为多个，您需要使用 ``dict`` 传入，即对每一个数据集标上用于标识它们的标签；也可以使用 evaluate_dataloaders
      作为参数的名称。
  :param metrics: 评测时使用的指标。注意该参数必须为 ``dict`` 类型，其中 ``key`` 为一个 ``metric`` 的名称，``value`` 为具体的 ``Metric`` 对象。目前支持以下 metrics：
  
      1. fastNLP 自己的 ``metric``：详见 :class:`~fastNLP.core.metrics.Metric`；
      2. torchmetrics；
      3. allennlp.training.metrics；
      4. paddle.metric；
  
  :param driver: 等价于 ``Trainer`` 中的 ``driver`` 参数；
  
      .. note::
  
          如果在您的脚本中在初始化 ``Evaluator`` 前也初始化了 ``Trainer`` 进行训练，那么强烈建议您直接将 ``trainer.driver`` 传入 ``Evaluator`` 当做该参数的值；
  
          .. code-block::
  
              # 初始化 Trainer
              trainer = Trainer(
                  ...
                  driver='torch',
                  device=[0,1]
              )
              trainer.run()
  
              # 此时再初始化 Evaluator 时应当直接使用 trainer.driver；
              evaluator = Evaluator(
                  ...
                  driver=trainer.driver
              )
  
  :param device: 等价于 ``Trainer`` 中的 ``device`` 参数；
  :param evaluate_batch_step_fn: 您可以传入该参数来定制每次评测一个 batch 的数据时所执行的函数。该函数应接受的两个参数为 ``evaluator`` 和 ``batch``，
      不需要有返回值；可以参考 :meth:`~fastNLP.core.controllers.loops.evaluate_batch_loop.EvaluateBatchLoop.batch_step_fn`；
  :param evaluate_fn: 用来控制 ``Evaluator`` 在评测的前向传播过程中调用的是哪一个函数，例如对于 pytorch 而言，通过该参数确定使用的是 :meth:`model.evaluate_step` 还是
      :meth:`model.forward` （不同训练框架所使用的的前向传播函数的方法名称不同）；
  
      1. 如果该值是 ``None``，那么我们会默认使用 ``evaluate_step`` 当做前向传播的函数，如果在模型中没有找到该方法，则使用训练框架默认的前向传播函数；
      2. 如果为 ``str`` 类型，例如为 ``'my_evaluate_step_fn'``，则尝试寻找 :meth:`model.my_evaluate_step_fn`，如果找不到则直接报错；
  
  :param input_mapping: 等价于 ``Trainer`` 中的 ``input_mapping`` 参数；对具体的用于评测一个 batch 的数据使用 ``input_mapping`` 处理之后再输入到 ``model`` 以及 ``metric`` 中。如果针对
      ``model`` 和 ``metric`` 需要不同的 ``mapping``，请考虑使用 ``evaluate_batch_step_fn`` 参数定制；也可以使用 evaluate_input_mapping 参数名传入。
  
      .. todo::
  
          之后链接上 参数匹配 的文档；
  
  :param output_mapping: 等价于 ``Trainer`` 中的 ``output_mapping`` 参数；对 ``model`` 输出的内容，将通过 ``output_mapping`` 处理之后再输入到 ``metric`` 中；
      也可以使用 evaluate_output_mapping 参数名传入。
  :param model_wo_auto_param_call: 等价于 ``Trainer`` 中的 ``model_wo_auto_param_call`` 参数；
  
      .. note::
  
          一个十分需要注意的问题在于 ``model_wo_auto_param_call`` 只会关闭部分的参数匹配，即指挥关闭前向传播时的参数匹配，但是由于 ``Evaluator`` 中
          ``metric`` 的计算都是自动化的，因此其一定需要参数匹配：根据 ``metric.update`` 的函数签名直接从字典数据中抽取其需要的参数传入进去；
  
  
  :param fp16: 是否在评测时使用 fp16 混合精度；
  :param verbose: 是否打印 evaluate 的结果；
  :kwargs:
      * *torch_kwargs* -- 等价于 ``Trainer`` 中的 ``torch_kwargs`` 参数；
      * *paddle_kwargs* -- 等价于 ``Trainer`` 中的 ``paddle_kwargs`` 参数；
      * *fairscale_kwargs* -- 等价于 ``Trainer`` 中的 ``fairscale_kwargs`` 参数；
      * *deepspeed_kwargs* -- 等价于 ``Trainer`` 中的 ``deepspeed_kwargs`` 参数；
      * *oneflow_kwargs* -- 等价于 ``Trainer`` 中的 ``oneflow_kwargs`` 参数；
      * *data_device* -- 等价于 ``Trainer`` 中的 ``data_device`` 参数；
      * *model_use_eval_mode* (``bool``) --
        是否在评测的时候将 ``model`` 的状态设置成 ``eval`` 状态。在 ``eval`` 状态下，``model`` 的
        ``dropout`` 与 ``batch normalization`` 将会关闭。默认为 ``True``。如果为 ``False``，``fastNLP`` 不会对 ``model`` 的 ``evaluate`` 状态做任何设置。无论
        该值是什么，``fastNLP`` 都会在评测后将 ``model`` 的状态设置为 ``train``；
      * *use_dist_sampler* --
        表示在 ``Evaluator`` 中在使用分布式的时候是否将保证 dataloader 的 ``sampler`` 替换为
        分布式的 ``sampler``，其特点是每个卡上的数据之间不重叠，所有卡上数据的加起来是整个数据集。若传入的 dataloader
        的 sampler 为：
        
          - 深度学习框架自带的默认 sampler ;
          - fastNLP 的 Sampler ；
        则将替换为 :class:`~fastNLP.UnrepeatedSequentialSampler`，如果这个行为不是期待的，请本参数设置为 ``False``，并针对每个卡控制其可以
        用到的数据。如果不是以上两类 sampler ，fastNLP 将报错。
      * *output_from_new_proc* -- 等价于 ``Trainer`` 中的 ``output_from_new_proc`` 参数；
      * *progress_bar* -- 等价于 ``Trainer`` 中的 ``progress_bar`` 参数；
      * *check_dataloader_legality* -- 是否检查 ``DataLoader`` 是否合法，默认为 ``True`` 。
code: def __init__(
      self,
      model,
      dataloaders=None,
      metrics: Optional[Dict] = None,
      driver: Union[str, Driver] = "auto",
      device: Optional[Union[int, List[int], str]] = None,
      evaluate_batch_step_fn: Optional[Callable] = None,
      evaluate_fn: Optional[str] = None,
      input_mapping: Optional[Union[Callable, Dict]] = None,
      output_mapping: Optional[Union[Callable, Dict]] = None,
      model_wo_auto_param_call: bool = False,
      fp16: bool = False,
      verbose: int = 1,
      **kwargs,
  ):
      self.model = model
      self.metrics = metrics
      self.driver = choose_driver(
          model,
          driver,
          device,
          fp16=fp16,
          model_wo_auto_param_call=model_wo_auto_param_call,
          **kwargs,
      )
  
      dataloaders = (
          dataloaders
          if dataloaders is not None
          else kwargs.get("evaluate_dataloaders")
      )
      if dataloaders is None:
          raise ValueError("Parameter `dataloaders` can not be None.")
      self.dataloaders = dataloaders
      self.device = device
      self.verbose = verbose
  
      self.evaluate_batch_loop = EvaluateBatchLoop(
          batch_step_fn=evaluate_batch_step_fn
      )
  
      if evaluate_batch_step_fn is not None:
          _check_valid_parameters_number(
              evaluate_batch_step_fn,
              ["evaluator", "batch"],
              fn_name="evaluate_batch_step_fn",
          )
      self.evaluate_batch_step_fn = evaluate_batch_step_fn
  
      self.input_mapping = (
          input_mapping
          if input_mapping is not None
          else kwargs.get("evaluate_input_mapping")
      )
      self.output_mapping = (
          output_mapping
          if output_mapping is not None
          else kwargs.get("evaluate_output_mapping")
      )
  
      # check dataloader
      if not isinstance(dataloaders, dict):
          if kwargs.get("check_dataloader_legality", True):
              try:
                  self.driver.check_dataloader_legality(
                      dataloader=dataloaders
                  )
              except TypeError as e:
                  logger.error("`dataloaders` is invalid.")
                  raise e
          dataloaders = {None: dataloaders}
      else:
          if kwargs.get("check_dataloader_legality", True):
              for key, dataloader in dataloaders.items():
                  try:
                      self.driver.check_dataloader_legality(
                          dataloader=dataloader
                      )
                  except TypeError as e:
                      logger.error(
                          f"The dataloader named:{key} is invalid."
                      )
                      raise e
  
      self.driver.setup()
      self.driver.barrier()
  
      self.separator = kwargs.get("separator", "#")
      self.model_use_eval_mode = kwargs.get("model_use_eval_mode", True)
      use_dist_sampler = kwargs.get("use_dist_sampler", None)
      if use_dist_sampler is None:
          use_dist_sampler = self.driver.is_distributed()
      if use_dist_sampler:
          self._dist_sampler = "unrepeatdist"
      else:
          self._dist_sampler = None
      self._metric_wrapper = None
      _ = self.metrics_wrapper  # 触发检查
  
      if evaluate_fn is not None and not isinstance(evaluate_fn, str):
          raise TypeError(
              "Parameter `evaluate_fn` can only be `str` type when it is not None."
          )
      (
          self._evaluate_step,
          self._evaluate_step_signature_fn,
      ) = self.driver.get_model_call_fn(
          "evaluate_step" if evaluate_fn is None else evaluate_fn
      )
      self.evaluate_fn = evaluate_fn
  
      self.dataloaders = {}
      for name, dl in dataloaders.items():  # 替换为正确的 sampler
          dl = self.driver.set_dist_repro_dataloader(
              dataloader=dl, dist=self._dist_sampler, reproducible=False
          )
          self.dataloaders[name] = dl
  
      self.progress_bar = kwargs.get("progress_bar", "auto")
      assert self.progress_bar in [None, "rich", "auto", "tqdm", "raw"]
      if self.progress_bar == "auto":
          self.progress_bar = "raw" if f_rich_progress.dummy else "rich"
  
      self.driver.barrier()
  
imports: from typing import Union, List, Optional, Dict, Callable, BinaryIO
  import os
  from pathlib import Path
  import io
  from dataclasses import is_dataclass
  from fastNLP.core.drivers import Driver, TorchDriver
  from ..drivers.choose_driver import choose_driver
  from .loops import Loop, EvaluateBatchLoop
  from fastNLP.core.utils import auto_param_call, dataclass_to_dict, match_and_substitute_params, f_rich_progress, flat_nest_dict, f_tqdm_progress
  from fastNLP.core.metrics import Metric
  from fastNLP.core.metrics.utils import _is_torchmetrics_metric, _is_paddle_metric, _is_allennlp_metric
  from fastNLP.core.controllers.utils.utils import _TruncatedDataLoader
  from fastNLP.core.utils.utils import _check_valid_parameters_number
  from fastNLP.core.log import logger
  from fastNLP.envs import FASTNLP_MODEL_FILENAME
label_desc: Use image node_id 1 to create a new Evaluator object  with example: obj = Evaluator(model, dataloaders, metrics, driver, device, evaluate_batch_step_fn, evaluate_fn, input_mapping, output_mapping, model_wo_auto_param_call, fp16, verbose)