class_docstr: 用来初始化 `Driver` 的基类，所有定制的 `driver` 都需要继承此类；
  **fastNLP** 提供的 driver 实例都会同时被 :class:`~fastNLP.core.controllers.Trainer` 和 :class:`~fastNLP.core.controllers.Evaluator` 调用。
  
  :param model: 训练或者评测的模型，需要注意该模型可能为用户已经使用类似 :class:`torch.nn.DataParallel` 或者
      :class:`torch.nn.parallel.DistributedDataParallel` 包裹过的模型。
class_docstr_tok: ["\u7528\u6765\u521d\u59cb\u5316","`","Driver","`","\u7684\u57fa\u7c7b\uff0c\u6240\u6709\u5b9a\u5236\u7684","`","driver","`","\u90fd\u9700\u8981\u7ee7\u627f\u6b64\u7c7b\uff1b","*","*","fastNLP","*","*","\u63d0\u4f9b\u7684","driver","\u5b9e\u4f8b\u90fd\u4f1a\u540c\u65f6\u88ab",":","class",":","`","~fastNLP.core.controllers.Trainer","`","\u548c",":","class",":","`","~fastNLP.core.controllers.Evaluator","`","\u8c03\u7528\u3002",":","param","model",":","\u8bad\u7ec3\u6216\u8005\u8bc4\u6d4b\u7684\u6a21\u578b\uff0c\u9700\u8981\u6ce8\u610f\u8be5\u6a21\u578b\u53ef\u80fd\u4e3a\u7528\u6237\u5df2\u7ecf\u4f7f\u7528\u7c7b\u4f3c",":","class",":","`","torch.nn.DataParallel","`","\u6216\u8005",":","class",":","`","torch.nn.parallel.DistributedDataParallel","`","\u5305\u88f9\u8fc7\u7684\u6a21\u578b\u3002"]
docstr: 该函数会接受 :class:`~fastNLP.core.controllers.Trainer` 的 ``train_fn`` 或者 :class:`~fastNLP.core.controllers.Evaluator`
  的 ``evaluate_fn``，返回一个实际用于调用 :meth:`model_call` 时传入的函数参数；该函数会由 :class:`~fastNLP.core.controllers.Trainer`
  和 :class:`~fastNLP.core.controllers.Evaluator` 在 :func:`driver.setup` 函数之后调用。
  
  之所以设置该函数的目的在于希望将具体的 model_call function 从 driver 中抽离出来，然后将其附着在 ``Trainer`` 或者 ``Evaluator`` 身上；
  这样是因为在新版的设计中，使用 model 的哪种方法来进行 ``train step`` 或者 ``evaluate step`` 是通过额外的参数 ``train_fn`` 和
  ``evaluate_fn`` 来确定的，而二者又分别是通过 ``Trainer`` 和 ``Evaluator`` 来控制的；因此不能将确定具体的 ``train step fn`` 和
  ``evaluate step fn`` 的逻辑放在每一个 driver 的初始化的时候（因此在 ``Trainer`` 初始化第一个 driver 时，``Evaluator`` 还没有初始化，但是
  ``evaluate step fn`` 的确定却需要 Evaluator 的初始化），因此我们将这一逻辑抽象到这一函数当中.
  
  这一函数应当通过参数 ``fn`` 来判断应当返回的实际的调用的函数，具体逻辑如下所示：
  
      1. 如果 ``fn`` == "train_step" or "evaluate_step"，那么对传入的模型进行检测，如果模型没有定义方法 ``fn``，则默认调用模型的 :meth:`forward`
         函数，然后给出 warning；
      2. 如果 ``fn`` 是其他字符串，那么如果模型没有定义方法 ``fn`` 则直接报错；
  
  注意不同的 driver 需要做额外的检测处理，例如在 :class:`~fastNLP.core.drivers.torch_driver.TorchDDPDriver` 中，当传入的模型本身就是
  :class:`DistributedDataParallel` 时，我们只能调用模型的 :meth:`forward` 函数，因此需要额外的 warning；这一点特别需要注意的问题在于
  driver 自己在 setup 时也会对模型进行改变（ :class:`~fastNLP.core.drivers.torch_driver.TorchDDPDriver` ），因此可能需要额外标记最初
  传入 driver 的模型是哪种形式的.
  
  :param fn: 一个字符串，该函数通过该字符串判断要返回模型的哪种方法
  :return: 一个元组，包含两个函数，用于在调用 :meth:`model_call` 时传入
docstr_tok: ["\u8be5\u51fd\u6570\u4f1a\u63a5\u53d7",":","class",":","`","~fastNLP.core.controllers.Trainer","`","\u7684","``","train_fn","``","\u6216\u8005",":","class",":","`","~fastNLP.core.controllers.Evaluator","`","\u7684","``","evaluate_fn","``","\uff0c\u8fd4\u56de\u4e00\u4e2a\u5b9e\u9645\u7528\u4e8e\u8c03\u7528",":","meth",":","`","model_call","`","\u65f6\u4f20\u5165\u7684\u51fd\u6570\u53c2\u6570\uff1b\u8be5\u51fd\u6570\u4f1a\u7531",":","class",":","`","~fastNLP.core.controllers.Trainer","`","\u548c",":","class",":","`","~fastNLP.core.controllers.Evaluator","`","\u5728",":","func",":","`","driver.setup","`","\u51fd\u6570\u4e4b\u540e\u8c03\u7528\u3002","\u4e4b\u6240\u4ee5\u8bbe\u7f6e\u8be5\u51fd\u6570\u7684\u76ee\u7684\u5728\u4e8e\u5e0c\u671b\u5c06\u5177\u4f53\u7684","model_call","function","\u4ece","driver","\u4e2d\u62bd\u79bb\u51fa\u6765\uff0c\u7136\u540e\u5c06\u5176\u9644\u7740\u5728","``","Trainer","``","\u6216\u8005","``","Evaluator","``","\u8eab\u4e0a\uff1b","\u8fd9\u6837\u662f\u56e0\u4e3a\u5728\u65b0\u7248\u7684\u8bbe\u8ba1\u4e2d\uff0c\u4f7f\u7528","model","\u7684\u54ea\u79cd\u65b9\u6cd5\u6765\u8fdb\u884c","``","train","step","``","\u6216\u8005","``","evaluate","step","``","\u662f\u901a\u8fc7\u989d\u5916\u7684\u53c2\u6570","``","train_fn","``","\u548c","``","evaluate_fn","``","\u6765\u786e\u5b9a\u7684\uff0c\u800c\u4e8c\u8005\u53c8\u5206\u522b\u662f\u901a\u8fc7","``","Trainer","``","\u548c","``","Evaluator","``","\u6765\u63a7\u5236\u7684\uff1b\u56e0\u6b64\u4e0d\u80fd\u5c06\u786e\u5b9a\u5177\u4f53\u7684","``","train","step","fn","``","\u548c","``","evaluate","step","fn","``","\u7684\u903b\u8f91\u653e\u5728\u6bcf\u4e00\u4e2a","driver","\u7684\u521d\u59cb\u5316\u7684\u65f6\u5019\uff08\u56e0\u6b64\u5728","``","Trainer","``","\u521d\u59cb\u5316\u7b2c\u4e00\u4e2a","driver","\u65f6\uff0c","``","Evaluator","``","\u8fd8\u6ca1\u6709\u521d\u59cb\u5316\uff0c\u4f46\u662f","``","evaluate","step","fn","``","\u7684\u786e\u5b9a\u5374\u9700\u8981","Evaluator","\u7684\u521d\u59cb\u5316\uff09\uff0c\u56e0\u6b64\u6211\u4eec\u5c06\u8fd9\u4e00\u903b\u8f91\u62bd\u8c61\u5230\u8fd9\u4e00\u51fd\u6570\u5f53\u4e2d",".","\u8fd9\u4e00\u51fd\u6570\u5e94\u5f53\u901a\u8fc7\u53c2\u6570","``","fn","``","\u6765\u5224\u65ad\u5e94\u5f53\u8fd4\u56de\u7684\u5b9e\u9645\u7684\u8c03\u7528\u7684\u51fd\u6570\uff0c\u5177\u4f53\u903b\u8f91\u5982\u4e0b\u6240\u793a\uff1a","1",".","\u5982\u679c","``","fn","``","==","``","train_step","''","or","``","evaluate_step","''","\uff0c\u90a3\u4e48\u5bf9\u4f20\u5165\u7684\u6a21\u578b\u8fdb\u884c\u68c0\u6d4b\uff0c\u5982\u679c\u6a21\u578b\u6ca1\u6709\u5b9a\u4e49\u65b9\u6cd5","``","fn","``","\uff0c\u5219\u9ed8\u8ba4\u8c03\u7528\u6a21\u578b\u7684",":","meth",":","`","forward","`","\u51fd\u6570\uff0c\u7136\u540e\u7ed9\u51fa","warning\uff1b","2",".","\u5982\u679c","``","fn","``","\u662f\u5176\u4ed6\u5b57\u7b26\u4e32\uff0c\u90a3\u4e48\u5982\u679c\u6a21\u578b\u6ca1\u6709\u5b9a\u4e49\u65b9\u6cd5","``","fn","``","\u5219\u76f4\u63a5\u62a5\u9519\uff1b","\u6ce8\u610f\u4e0d\u540c\u7684","driver","\u9700\u8981\u505a\u989d\u5916\u7684\u68c0\u6d4b\u5904\u7406\uff0c\u4f8b\u5982\u5728",":","class",":","`","~fastNLP.core.drivers.torch_driver.TorchDDPDriver","`","\u4e2d\uff0c\u5f53\u4f20\u5165\u7684\u6a21\u578b\u672c\u8eab\u5c31\u662f",":","class",":","`","DistributedDataParallel","`","\u65f6\uff0c\u6211\u4eec\u53ea\u80fd\u8c03\u7528\u6a21\u578b\u7684",":","meth",":","`","forward","`","\u51fd\u6570\uff0c\u56e0\u6b64\u9700\u8981\u989d\u5916\u7684","warning\uff1b\u8fd9\u4e00\u70b9\u7279\u522b\u9700\u8981\u6ce8\u610f\u7684\u95ee\u9898\u5728\u4e8e","driver","\u81ea\u5df1\u5728","setup","\u65f6\u4e5f\u4f1a\u5bf9\u6a21\u578b\u8fdb\u884c\u6539\u53d8\uff08",":","class",":","`","~fastNLP.core.drivers.torch_driver.TorchDDPDriver","`","\uff09\uff0c\u56e0\u6b64\u53ef\u80fd\u9700\u8981\u989d\u5916\u6807\u8bb0\u6700\u521d","\u4f20\u5165","driver","\u7684\u6a21\u578b\u662f\u54ea\u79cd\u5f62\u5f0f\u7684",".",":","param","fn",":","\u4e00\u4e2a\u5b57\u7b26\u4e32\uff0c\u8be5\u51fd\u6570\u901a\u8fc7\u8be5\u5b57\u7b26\u4e32\u5224\u65ad\u8981\u8fd4\u56de\u6a21\u578b\u7684\u54ea\u79cd\u65b9\u6cd5",":","return",":","\u4e00\u4e2a\u5143\u7ec4\uff0c\u5305\u542b\u4e24\u4e2a\u51fd\u6570\uff0c\u7528\u4e8e\u5728\u8c03\u7528",":","meth",":","`","model_call","`","\u65f6\u4f20\u5165"]
code: def get_model_call_fn(self, fn: str) -> Tuple:
      r"""
      该函数会接受 :class:`~fastNLP.core.controllers.Trainer` 的 ``train_fn`` 或者 :class:`~fastNLP.core.controllers.Evaluator`
      的 ``evaluate_fn``，返回一个实际用于调用 :meth:`model_call` 时传入的函数参数；该函数会由 :class:`~fastNLP.core.controllers.Trainer`
      和 :class:`~fastNLP.core.controllers.Evaluator` 在 :func:`driver.setup` 函数之后调用。
  
      之所以设置该函数的目的在于希望将具体的 model_call function 从 driver 中抽离出来，然后将其附着在 ``Trainer`` 或者 ``Evaluator`` 身上；
      这样是因为在新版的设计中，使用 model 的哪种方法来进行 ``train step`` 或者 ``evaluate step`` 是通过额外的参数 ``train_fn`` 和
      ``evaluate_fn`` 来确定的，而二者又分别是通过 ``Trainer`` 和 ``Evaluator`` 来控制的；因此不能将确定具体的 ``train step fn`` 和
      ``evaluate step fn`` 的逻辑放在每一个 driver 的初始化的时候（因此在 ``Trainer`` 初始化第一个 driver 时，``Evaluator`` 还没有初始化，但是
      ``evaluate step fn`` 的确定却需要 Evaluator 的初始化），因此我们将这一逻辑抽象到这一函数当中.
  
      这一函数应当通过参数 ``fn`` 来判断应当返回的实际的调用的函数，具体逻辑如下所示：
  
          1. 如果 ``fn`` == "train_step" or "evaluate_step"，那么对传入的模型进行检测，如果模型没有定义方法 ``fn``，则默认调用模型的 :meth:`forward`
             函数，然后给出 warning；
          2. 如果 ``fn`` 是其他字符串，那么如果模型没有定义方法 ``fn`` 则直接报错；
  
      注意不同的 driver 需要做额外的检测处理，例如在 :class:`~fastNLP.core.drivers.torch_driver.TorchDDPDriver` 中，当传入的模型本身就是
      :class:`DistributedDataParallel` 时，我们只能调用模型的 :meth:`forward` 函数，因此需要额外的 warning；这一点特别需要注意的问题在于
      driver 自己在 setup 时也会对模型进行改变（ :class:`~fastNLP.core.drivers.torch_driver.TorchDDPDriver` ），因此可能需要额外标记最初
      传入 driver 的模型是哪种形式的.
  
      :param fn: 一个字符串，该函数通过该字符串判断要返回模型的哪种方法
      :return: 一个元组，包含两个函数，用于在调用 :meth:`model_call` 时传入
      """
      raise NotImplementedError(
          "Each specific driver should implemented its own `get_model_call_fn` function."
      )
  
imports: import os
  import signal
  import sys
  from typing import Sequence, List, Optional, Callable, Dict, Union, Tuple
  from abc import ABC, abstractmethod
  from datetime import datetime
  from pathlib import Path
  from io import BytesIO
  import json
  from fastNLP.core.utils import nullcontext
label_desc: Use image node_id 7 for calling the Driver obj's underlying member method code with example usage: obj.get_model_call_fn(fn) without return types