Browse Source

补充文档

tags/v1.0.0alpha
yh_cc 3 years ago
parent
commit
c562982f1d
32 changed files with 732 additions and 594 deletions
  1. +0
    -1
      fastNLP/core/callbacks/__init__.py
  2. +10
    -10
      fastNLP/core/callbacks/callback_event.py
  3. +0
    -4
      fastNLP/core/callbacks/callback_manager.py
  4. +43
    -47
      fastNLP/core/callbacks/checkpoint_callback.py
  5. +16
    -15
      fastNLP/core/callbacks/early_stop_callback.py
  6. +51
    -42
      fastNLP/core/callbacks/has_monitor_callback.py
  7. +24
    -24
      fastNLP/core/callbacks/load_best_model_callback.py
  8. +7
    -7
      fastNLP/core/callbacks/lr_scheduler_callback.py
  9. +61
    -42
      fastNLP/core/callbacks/more_evaluate_callback.py
  10. +19
    -17
      fastNLP/core/callbacks/progress_callback.py
  11. +53
    -43
      fastNLP/core/callbacks/topk_saver.py
  12. +13
    -12
      fastNLP/core/callbacks/torch_callbacks/torch_grad_clip_callback.py
  13. +12
    -10
      fastNLP/core/callbacks/torch_callbacks/torch_lr_sched_callback.py
  14. +20
    -11
      fastNLP/core/collators/collator.py
  15. +9
    -8
      fastNLP/core/collators/packer_unpacker.py
  16. +3
    -3
      fastNLP/core/collators/padders/jittor_padder.py
  17. +36
    -24
      fastNLP/core/collators/padders/numpy_padder.py
  18. +12
    -8
      fastNLP/core/collators/padders/padder.py
  19. +24
    -24
      fastNLP/core/collators/padders/paddle_padder.py
  20. +24
    -24
      fastNLP/core/collators/padders/raw_padder.py
  21. +31
    -24
      fastNLP/core/collators/padders/torch_padder.py
  22. +115
    -55
      fastNLP/core/controllers/evaluator.py
  23. +4
    -4
      fastNLP/core/controllers/trainer.py
  24. +8
    -8
      fastNLP/core/dataset/instance.py
  25. +13
    -8
      fastNLP/core/metrics/metric.py
  26. +17
    -17
      fastNLP/core/metrics/span_f1_pre_rec_metric.py
  27. +1
    -1
      fastNLP/core/samplers/conversion_utils.py
  28. +39
    -39
      fastNLP/core/samplers/reproducible_batch_sampler.py
  29. +30
    -30
      fastNLP/core/samplers/reproducible_sampler.py
  30. +29
    -23
      fastNLP/core/samplers/unrepeated_sampler.py
  31. +0
    -5
      fastNLP/core/utils/rich_progress.py
  32. +8
    -4
      fastNLP/envs/distributed.py

+ 0
- 1
fastNLP/core/callbacks/__init__.py View File

@@ -2,7 +2,6 @@ __all__ = [
'Callback',
'Event',
'Filter',
'CallbackManager',
'CheckpointCallback',
'choose_progress_callback',
'ProgressCallback',


+ 10
- 10
fastNLP/core/callbacks/callback_event.py View File

@@ -30,20 +30,20 @@ def check_legality(fn):


class Event:
"""
与 Trainer.on 函数配合使用,达到控制 callback 函数运行时机的目的。

:param value: Trainer 的 callback 时机。
:param int every: 触发了多少次,才真正运行一次。
:param bool once: 是否只在第一次运行后就不再执行了。
:param Callable filter_fn: 输入参数的应该为 (filter, trainer),其中 filter 对象中包含了 filter.num_called 和
filter.num_executed 两个变量分别获取当前被调用了多少次,真正执行了多少次。trainer 对象即为当前正在运行的 Trainer 。
"""
every: Optional[int]
once: Optional[int]

def __init__(self, value: str, every: Optional[int] = None, once: Optional[int] = None,
filter_fn: Optional[Callable] = None):
"""
请勿直接使用本对象,而是通过调用 Event.on_after_trainer_initialized() 等方式调用。

:param value: Trainer 的 callback 时机。
:param int every: 触发了多少次,才真正运行一次。
:param bool once: 是否只在第一次运行后就不再执行了。
:param Callable filter_fn: 输入参数的应该为 (filter, trainer),其中 filter 对象中包含了 filter.num_called 和
filter.num_executed 两个变量分别获取当前被调用了多少次,真正执行了多少次。trainer 对象即为当前正在运行的 Trainer 。
"""
self.every = every
self.once = once
self.filter_fn = filter_fn
@@ -456,7 +456,7 @@ class Event:
class Filter:
def __init__(self, every: Optional[int] = None, once: Optional[bool] = None, filter_fn: Optional[Callable] = None):
r"""
通过该 `Filter` 作为函数修饰器来控制一个函数的实际的运行频率
通过该 `Filter` 作为函数修饰器来控制一个函数的实际的运行频率

:param every: 表示一个函数隔多少次运行一次;
:param once: 表示一个函数只运行一次;


+ 0
- 4
fastNLP/core/callbacks/callback_manager.py View File

@@ -2,10 +2,6 @@ import inspect
from typing import List, Optional, Dict, Sequence
from collections import defaultdict

__all__ = [
'CallbackManager'
]

from .callback_event import Event
from .callback import Callback
from fastNLP.core.log import logger


+ 43
- 47
fastNLP/core/callbacks/checkpoint_callback.py View File

@@ -13,55 +13,55 @@ from ..utils.exceptions import EarlyStopException


class CheckpointCallback(Callback):
"""
保存 checkpoint 的 callback ,其保存的文件目录以及文件名命名规则如下::

- folder/
- YYYY-mm-dd-HH_MM_SS_fffff/ # 自动根据当前脚本的启动时间创建的
- {save_object}-epoch_{epoch_idx}/ # 满足 every_n_epochs 条件保存的模型
- {save_object}-epoch_{epoch_idx}-batch_{global_batch_idx}/ # 满足 every_n_batches 保存的模型
- {save_object}-last/ # 最后一个 epoch 的保存
- {save_object}-epoch_{epoch_idx}-batch_{global_batch_idx}-exception_{exception_type}/ # exception时保存。
- {save_object}-epoch_{epoch_idx}-batch_{global_batch_idx}-{monitor}_{monitor_value}/ # 满足topk条件存储文件名

model_save_fn 为 None ,则以上每个 folder 中,将生成 fastnlp_model.pkl.tar 文件。若 model_save_fn 不为 None,
则 fastNLP 将 folder 绝对路径传递给该函数,fastNLP 在该 folder 下不进行模型保存。默认情况下,本 checkpoint 只保存了 model
的状态;如还需保存 Trainer 的状态以断点重训的话,请使用 ``save_object='trainer'`` 。

:param monitor: 监控的 metric 值。

* 为 ``None``
将尝试使用 :class:`~fastNLP.Trainer` 中设置 `monitor` 值(如果有设置)。
* 为 ``str``
尝试直接使用该名称从 ``evaluation`` 结果中寻找,如果在 ``evaluation`` 结果中没有找到完全一致的名称,将
使用 最长公共字符串算法 从 ``evaluation`` 结果中找到最匹配的那个作为 ``monitor`` 。
* 为 ``Callable``
接受参数为 ``evaluation`` 的结果(字典类型),返回一个 ``float`` 值作为 ``monitor`` 的结果,如果当前结果中没有相关
的 ``monitor`` 值请返回 ``None`` 。
:param folder: 保存的文件夹,fastNLP 将在该文件下以时间戳创建子文件夹,并在里面保存。因此不同次运行可以将被保存到不同的
时间戳文件夹中。如果为 None ,默认使用当前文件夹。
:param every_n_epochs: 多少个 epoch 保存一次。
:param every_n_batches: 多少个 batch 保存一次。
:param last: 如果为 True ,将在每次 epoch 运行结束都保存一次,会覆盖之前的保存。
:param topk: 保存 monitor 结果 topK 个。
:param on_exceptions: 在出异常信息时,是否保存。传入需要捕获的异常的类。默认将捕获 EarlyStopException 。
:param larger_better: monitor 的值是否时越大越好。
:param only_state_dict: 保存模型时是否只保存 state_dict 。当 model_save_fn 不为 None 时,该参数无效。
:param model_save_fn: 个性化的保存函数,当触发保存操作时,就调用这个函数,这个函数应当接受一个文件夹作为参数,不返回任何东西。
如果传入了 model_save_fn 函数,fastNLP 将不再进行模型相关的保存。在多卡场景下,我们只在 rank 0 上会运行该函数。
:param save_object: 可选 ['trainer', 'model'],表示在保存时的保存对象为 ``trainer+model`` 还是 只是 ``model`` 。如果
保存 ``trainer`` 对象的话,将会保存 :class:~fastNLP.Trainer 的相关状态,可以通过 :meth:`Trainer.load` 加载该断
点继续训练。如果保存的是 ``Model`` 对象,则可以通过 :meth:`Trainer.load_model` 加载该模型权重。
:param save_evaluate_results: 是否保存 evaluate 的结果。如果为 True ,在保存 topk 模型的 folder 中还将额外保存一个
fastnlp_evaluate_results.json 文件,记录当前的 results。仅在设置了 topk 的场景下有用,默认为 True 。
:param kwargs:
"""
def __init__(self, folder: Optional[Union[str, Path]] = None, every_n_epochs: Optional[int] = None,
every_n_batches: Optional[int] = None, last: bool = False, topk: int = 0,
on_exceptions: Optional[Union[BaseException, Sequence[BaseException]]] = [EarlyStopException],
monitor: Optional[Union[str, Callable]] = None, larger_better: bool = True,
only_state_dict: bool = True, model_save_fn: Optional[Callable] = None, save_object: str = 'model',
save_evaluate_results=True, **kwargs):
"""
保存 checkpoint 的 callback ,其保存的文件目录以及文件名命名规则如下::

- folder/
- YYYY-mm-dd-HH_MM_SS_fffff/ # 自动根据当前脚本的启动时间创建的
- {save_object}-epoch_{epoch_idx}/ # 满足 every_n_epochs 条件保存的模型
- {save_object}-epoch_{epoch_idx}-batch_{global_batch_idx}/ # 满足 every_n_batches 保存的模型
- {save_object}-last/ # 最后一个 epoch 的保存
- {save_object}-epoch_{epoch_idx}-batch_{global_batch_idx}-exception_{exception_type}/ # exception时保存。
- {save_object}-epoch_{epoch_idx}-batch_{global_batch_idx}-{monitor}_{monitor_value}/ # 满足topk条件存储文件名

model_save_fn 为 None ,则以上每个 folder 中,将生成 fastnlp_model.pkl.tar 文件。若 model_save_fn 不为 None,
则 fastNLP 将 folder 绝对路径传递给该函数,fastNLP 在该 folder 下不进行模型保存。默认情况下,本 checkpoint 只保存了 model
的状态;如还需保存 Trainer 的状态以断点重训的话,请使用 ``save_object='trainer'`` 。

:param monitor: 监控的 metric 值。

* 为 ``None``
将尝试使用 :class:`~fastNLP.Trainer` 中设置 `monitor` 值(如果有设置)。
* 为 ``str``
尝试直接使用该名称从 ``evaluation`` 结果中寻找,如果在 ``evaluation`` 结果中没有找到完全一致的名称,将
使用 最长公共字符串算法 从 ``evaluation`` 结果中找到最匹配的那个作为 ``monitor`` 。
* 为 ``Callable``
接受参数为 ``evaluation`` 的结果(字典类型),返回一个 ``float`` 值作为 ``monitor`` 的结果,如果当前结果中没有相关
的 ``monitor`` 值请返回 ``None`` 。
:param folder: 保存的文件夹,fastNLP 将在该文件下以时间戳创建子文件夹,并在里面保存。因此不同次运行可以将被保存到不同的
时间戳文件夹中。如果为 None ,默认使用当前文件夹。
:param every_n_epochs: 多少个 epoch 保存一次。
:param every_n_batches: 多少个 batch 保存一次。
:param last: 如果为 True ,将在每次 epoch 运行结束都保存一次,会覆盖之前的保存。
:param topk: 保存 monitor 结果 topK 个。
:param on_exceptions: 在出异常信息时,是否保存。传入需要捕获的异常的类。默认将捕获 EarlyStopException 。
:param larger_better: monitor 的值是否时越大越好。
:param only_state_dict: 保存模型时是否只保存 state_dict 。当 model_save_fn 不为 None 时,该参数无效。
:param model_save_fn: 个性化的保存函数,当触发保存操作时,就调用这个函数,这个函数应当接受一个文件夹作为参数,不返回任何东西。
如果传入了 model_save_fn 函数,fastNLP 将不再进行模型相关的保存。在多卡场景下,我们只在 rank 0 上会运行该函数。
:param save_object: 可选 ['trainer', 'model'],表示在保存时的保存对象为 ``trainer+model`` 还是 只是 ``model`` 。如果
保存 ``trainer`` 对象的话,将会保存 :class:~fastNLP.Trainer 的相关状态,可以通过 :meth:`Trainer.load` 加载该断
点继续训练。如果保存的是 ``Model`` 对象,则可以通过 :meth:`Trainer.load_model` 加载该模型权重。
:param save_evaluate_results: 是否保存 evaluate 的结果。如果为 True ,在保存 topk 模型的 folder 中还将额外保存一个
fastnlp_evaluate_results.json 文件,记录当前的 results。仅在设置了 topk 的场景下有用,默认为 True 。
:param kwargs:
"""
super().__init__()
if every_n_epochs is not None:
if not isinstance(every_n_epochs, int) or every_n_epochs < 1:
@@ -133,10 +133,6 @@ class CheckpointCallback(Callback):
self.topk_saver.save(trainer, folder_name=folder_name)

def on_save_checkpoint(self, trainer) -> Dict:
"""
保存状态,以便之后可以继续使用
"""

states = {}
states['topk_saver'] = self.topk_saver.state_dict()
return states


+ 16
- 15
fastNLP/core/callbacks/early_stop_callback.py View File

@@ -9,22 +9,23 @@ from fastNLP.core.utils.exceptions import EarlyStopException


class EarlyStopCallback(HasMonitorCallback):
def __init__(self, monitor:Union[str, Callable]=None, larger_better:bool=True, patience:int=10):
"""
"""
用于 early stop 的 callback 。当监控的结果连续多少次没有变好边 raise 一个 EarlyStopException 。

:param monitor: 监控的 metric 值。
:param monitor: 监控的 metric 值。

* 为 ``None``
将尝试使用 :class:`~fastNLP.Trainer` 中设置 `monitor` 值(如果有设置)。
* 为 ``str``
尝试直接使用该名称从 ``evaluation`` 结果中寻找,如果在 ``evaluation`` 结果中没有找到完全一致的名称,将
使用 最长公共字符串算法 从 ``evaluation`` 结果中找到最匹配的那个作为 ``monitor`` 。
* 为 ``Callable``
接受参数为 ``evaluation`` 的结果(字典类型),返回一个 ``float`` 值作为 ``monitor`` 的结果,如果当前结果中没有相关
的 ``monitor`` 值请返回 ``None`` 。
:param larger_better: monitor 的值是否是越大越好。
:param patience: 多少次 evaluate 不没有提升就停止。
"""
* 为 ``None``
将尝试使用 :class:`~fastNLP.Trainer` 中设置 `monitor` 值(如果有设置)。
* 为 ``str``
尝试直接使用该名称从 ``evaluation`` 结果中寻找,如果在 ``evaluation`` 结果中没有找到完全一致的名称,将
使用 最长公共字符串算法 从 ``evaluation`` 结果中找到最匹配的那个作为 ``monitor`` 。
* 为 ``Callable``
接受参数为 ``evaluation`` 的结果(字典类型),返回一个 ``float`` 值作为 ``monitor`` 的结果,如果当前结果中没有相关
的 ``monitor`` 值请返回 ``None`` 。
:param larger_better: monitor 的值是否是越大越好。
:param patience: 多少次 evaluate 不没有提升就停止。
"""
def __init__(self, monitor:Union[str, Callable]=None, larger_better:bool=True, patience:int=10):
super(EarlyStopCallback, self).__init__(monitor=monitor, larger_better=larger_better, must_have_monitor=True)
self.wait = 0
self.patience = patience
@@ -42,7 +43,7 @@ class EarlyStopCallback(HasMonitorCallback):
# 当是 step evaluate 的时候,下一步执行的就是这个, 所以在这里检查。
if self.wait >= self.patience:
raise EarlyStopException(f"After {self.wait} validations, no improvement for "
f"metric `{self._real_monitor}`")
f"metric `{self._real_monitor}`(best value: {self.monitor_value})")

def on_train_epoch_begin(self, trainer):
# 当是 epoch evaluate 的时候,下一步执行的就是这个, 所以在这里检查。


+ 51
- 42
fastNLP/core/callbacks/has_monitor_callback.py View File

@@ -16,11 +16,6 @@ from fastNLP.core.utils.utils import _check_valid_parameters_number


class CanItemDataType(ABC):
"""
检测可以进行传输的对象。

"""

@classmethod
def __subclasshook__(cls, subclass: Any) -> Union[bool, Any]:
if cls is CanItemDataType:
@@ -30,15 +25,22 @@ class CanItemDataType(ABC):


class ResultsMonitor:
"""
可用于监控某个数值,并通过 is_better_results() 等接口实现检测结果是否变得更好了。

:param monitor: 监控的 metric 值。

* 为 ``None``
将尝试使用 :class:`~fastNLP.Trainer` 中设置 `monitor` 值(如果有设置)。
* 为 ``str``
尝试直接使用该名称从 ``evaluation`` 结果中寻找,如果在 ``evaluation`` 结果中没有找到完全一致的名称,将
使用 最长公共字符串算法 从 ``evaluation`` 结果中找到最匹配的那个作为 ``monitor`` 。
* 为 ``Callable``
接受参数为 ``evaluation`` 的结果(字典类型),返回一个 ``float`` 值作为 ``monitor`` 的结果,如果当前结果中没有相关
的 ``monitor`` 值请返回 ``None`` 。
:param larger_better: monitor 是否时越大越好
"""
def __init__(self, monitor:Union[Callback, str], larger_better:bool=True):
"""
可用于监控某个数值,并通过 is_better_results() 等接口实现检测结果是否变得更好了。

:param monitor: 监控的 metric 值。如果在 evaluation 结果中没有找到完全一致的名称,将使用 最长公共字符串算法 找到最匹配
的那个作为 monitor 。如果为 None,将尝试使用 Trainer 设置的 monitor 。也可以传入一个函数,接受参数为 evaluation 的结
果(字典类型),返回一个 float 值作为 monitor 的结果,如果当前结果中没有相关的 monitor 值请返回 None 。
:param larger_better: monitor 是否时越大越好
"""
self.set_monitor(monitor, larger_better)

def set_monitor(self, monitor, larger_better):
@@ -66,9 +68,9 @@ class ResultsMonitor:

def get_monitor_value(self, results:Dict)->Union[float, None]:
"""
获取 monitor 的值,如果 monitor 没有直接找到,会尝试使用匹配的方式寻找,并把匹配到的设置到 self._real_monitor 属性上
获取 monitor 的值,如果 monitor 没有直接找到,会尝试使用 最长公共字符串算法 匹配的方式寻找。

:param results:
:param results: 评测结果。
:return: 如果为 None ,表明此次没有找到合适的monitor
"""
if len(results) == 0 or self.monitor is None:
@@ -113,7 +115,7 @@ class ResultsMonitor:
"""
检测给定的 results 是否比上一次更好,如果本次 results 中没有找到相关的monitor 返回 False。

:param results: on_valid_ends() 接口中传入的 evaluation 结果。
:param results: evaluation 结果。
:param keep_if_better: 当返回为 True 时,是否保存到 self.monitor_value 中。
:return:
"""
@@ -166,24 +168,24 @@ class ResultsMonitor:


class HasMonitorCallback(ResultsMonitor, Callback):
"""
该 callback 不直接进行使用,作为其它相关 callback 的父类使用,如果 callback 有使用 monitor 可以继承该函数里面实现了
(1)判断monitor合法性;(2)在需要时, 根据trainer的monitor设置自己的monitor名称。

:param monitor: 监控的 metric 值。

* 为 ``None``
将尝试使用 :class:`~fastNLP.Trainer` 中设置 `monitor` 值(如果有设置)。
* 为 ``str``
尝试直接使用该名称从 ``evaluation`` 结果中寻找,如果在 ``evaluation`` 结果中没有找到完全一致的名称,将
使用 最长公共字符串算法 从 ``evaluation`` 结果中找到最匹配的那个作为 ``monitor`` 。
* 为 ``Callable``
接受参数为 ``evaluation`` 的结果(字典类型),返回一个 ``float`` 值作为 ``monitor`` 的结果,如果当前结果中没有相关
的 ``monitor`` 值请返回 ``None`` 。
:param larger_better: monitor 是否时越大越好
:param must_have_monitor: 这个 callback 是否必须有 monitor 设置。如果设置为 True ,且没检测到设置 monitor 会报错。
"""
def __init__(self, monitor, larger_better, must_have_monitor=False):
"""
该 callback 不直接进行使用,作为其它相关 callback 的父类使用,如果 callback 有使用 monitor 可以继承该函数里面实现了
(1)判断monitor合法性;(2)在需要时, 根据trainer的monitor设置自己的monitor名称。

:param monitor: 监控的 metric 值。

* 为 ``None``
将尝试使用 :class:`~fastNLP.Trainer` 中设置 `monitor` 值(如果有设置)。
* 为 ``str``
尝试直接使用该名称从 ``evaluation`` 结果中寻找,如果在 ``evaluation`` 结果中没有找到完全一致的名称,将
使用 最长公共字符串算法 从 ``evaluation`` 结果中找到最匹配的那个作为 ``monitor`` 。
* 为 ``Callable``
接受参数为 ``evaluation`` 的结果(字典类型),返回一个 ``float`` 值作为 ``monitor`` 的结果,如果当前结果中没有相关
的 ``monitor`` 值请返回 ``None`` 。
:param larger_better: monitor 是否时越大越好
:param must_have_monitor: 这个 callback 是否必须有 monitor 设置。如果设置为 True ,且没检测到设置 monitor 会报错。
"""
super().__init__(monitor, larger_better)
self.must_have_monitor = must_have_monitor

@@ -212,16 +214,23 @@ class HasMonitorCallback(ResultsMonitor, Callback):


class ExecuteOnceBetterMonitor(HasMonitorCallback):
"""
当监控的 monitor 结果更好的时候,调用 execute_fn 函数。

:param monitor: 监控的 metric 值。

* 为 ``None``
将尝试使用 :class:`~fastNLP.Trainer` 中设置 `monitor` 值(如果有设置)。
* 为 ``str``
尝试直接使用该名称从 ``evaluation`` 结果中寻找,如果在 ``evaluation`` 结果中没有找到完全一致的名称,将
使用 最长公共字符串算法 从 ``evaluation`` 结果中找到最匹配的那个作为 ``monitor`` 。
* 为 ``Callable``
接受参数为 ``evaluation`` 的结果(字典类型),返回一个 ``float`` 值作为 ``monitor`` 的结果,如果当前结果中没有相关
的 ``monitor`` 值请返回 ``None`` 。
:param larger_better: monitor 是否时越大越好
:param execute_fn: 一个可执行的函数,不接受任何参数,不反回值。在 monitor 取得更好结果的时候会调用。
"""
def __init__(self, monitor, larger_better, execute_fn):
"""
当监控的 monitor 结果更好的时候,调用 execute_fn 函数。

:param monitor: 监控的 metric 值。如果在 evaluation 结果中没有找到完全一致的名称,将使用 最长公共字符串算法 找到最匹配
的那个作为 monitor 。如果为 None,将尝试使用 Trainer 设置的 monitor 。也可以传入一个函数,接受参数为 evaluation 的结
果(字典类型),返回一个 float 值作为 monitor 的结果,如果当前结果中没有相关的 monitor 值请返回 None 。
:param larger_better: monitor 是否时越大越好
:param execute_fn: 一个可执行的函数,不接受任何参数,不反回值。在 monitor 取得更好结果的时候会调用。
"""
super().__init__(monitor, larger_better, must_have_monitor=True)
_check_valid_parameters_number(execute_fn, expected_params=[], fn_name='execute_fn')
self.execute_fn = execute_fn


+ 24
- 24
fastNLP/core/callbacks/load_best_model_callback.py View File

@@ -14,34 +14,34 @@ from fastNLP.envs import all_rank_call_context


class LoadBestModelCallback(HasMonitorCallback):
"""
保存最佳的 monitor 值最佳的模型,并在训练结束的时候重新加载模型,默认会在加载之后删除权重文件。仅在训练正常结束的时候才能加载
最好的模型。

:param monitor: 监控的 metric 值。

* 为 ``None``
将尝试使用 :class:`~fastNLP.Trainer` 中设置 `monitor` 值(如果有设置)。
* 为 ``str``
尝试直接使用该名称从 ``evaluation`` 结果中寻找,如果在 ``evaluation`` 结果中没有找到完全一致的名称,将
使用 最长公共字符串算法 从 ``evaluation`` 结果中找到最匹配的那个作为 ``monitor`` 。
* 为 ``Callable``
接受参数为 ``evaluation`` 的结果(字典类型),返回一个 ``float`` 值作为 ``monitor`` 的结果,如果当前结果中没有相关
的 ``monitor`` 值请返回 ``None`` 。
:param larger_better: 该 metric 值是否是越大越好。
:param save_folder: 保存的文件夹,如果为空,则保存在内存中。不为空,则保存一份权重到文件中,当为多机训练,且本值不为空时,请确保
不同的机器均可访问当该路径。当 model_save_fn 不为 None 时该值一定不能为空。
:param only_state_dict: 是否只保存模型的参数。当 model_save_fn 不为空时,该值无效。
:param model_save_fn: 保存 model 的函数,与 model_load_fn 必须同时不为空。本函数的输入为一个已经创建好的文件夹,没有输出,
请在函数内完成对模型的保存。
:param model_load_fn: 加载 model 的函数,与 model_save_fn 必须同时不为空。本函数的输入为一个已经创建好的文件夹,没有输出,
请在函数内完成对模型的加载。
:param delete_after_train: 在训练结束后是否删掉模型。
"""
def __init__(self, monitor:Union[str, Callable]=None, larger_better:bool = True, only_state_dict:bool = True,
save_folder:Optional[str] = None, model_save_fn:Optional[Callable] = None,
model_load_fn:Optional[Callable] = None,
delete_after_train:bool = True):
"""
保存最佳的 monitor 值最佳的模型,并在训练结束的时候重新加载模型,默认会在加载之后删除权重文件。仅在训练正常结束的时候才能加载
最好的模型。

:param monitor: 监控的 metric 值。

* 为 ``None``
将尝试使用 :class:`~fastNLP.Trainer` 中设置 `monitor` 值(如果有设置)。
* 为 ``str``
尝试直接使用该名称从 ``evaluation`` 结果中寻找,如果在 ``evaluation`` 结果中没有找到完全一致的名称,将
使用 最长公共字符串算法 从 ``evaluation`` 结果中找到最匹配的那个作为 ``monitor`` 。
* 为 ``Callable``
接受参数为 ``evaluation`` 的结果(字典类型),返回一个 ``float`` 值作为 ``monitor`` 的结果,如果当前结果中没有相关
的 ``monitor`` 值请返回 ``None`` 。
:param larger_better: 该 metric 值是否是越大越好。
:param save_folder: 保存的文件夹,如果为空,则保存在内存中。不为空,则保存一份权重到文件中,当为多机训练,且本值不为空时,请确保
不同的机器均可访问当该路径。当 model_save_fn 不为 None 时该值一定不能为空。
:param only_state_dict: 是否只保存模型的参数。当 model_save_fn 不为空时,该值无效。
:param model_save_fn: 保存 model 的函数,与 model_load_fn 必须同时不为空。本函数的输入为一个已经创建好的文件夹,没有输出,
请在函数内完成对模型的保存。
:param model_load_fn: 加载 model 的函数,与 model_save_fn 必须同时不为空。本函数的输入为一个已经创建好的文件夹,没有输出,
请在函数内完成对模型的加载。
:param delete_after_train: 在训练结束后是否删掉模型。
"""
super().__init__(monitor=monitor, larger_better=larger_better, must_have_monitor=True)
if model_load_fn is not None:
assert callable(model_load_fn), "`model_load_fn` must be a callable object."


+ 7
- 7
fastNLP/core/callbacks/lr_scheduler_callback.py View File

@@ -6,14 +6,14 @@ __all__ = [


class LRSchedCallback(Callback):
def __init__(self, scheduler, step_on:str='batch'):
"""
根据 step_on 参数在合适的时机调用 scheduler 的 step 函数。
"""
根据 step_on 参数在合适的时机调用 scheduler 的 step 函数。

:param scheduler: 实现了 step() 函数的对象
:param step_on: 可选 ['batch', 'epoch'] 表示在何时调用 scheduler 的 step 函数。如果为 batch 的话在每次更新参数
之前调用;如果为 epoch 则是在一个 epoch 运行结束后调用。
"""
:param scheduler: 实现了 step() 函数的对象
:param step_on: 可选 ['batch', 'epoch'] 表示在何时调用 scheduler 的 step 函数。如果为 batch 的话在每次更新参数
之前调用;如果为 epoch 则是在一个 epoch 运行结束后调用。
"""
def __init__(self, scheduler, step_on:str='batch'):
assert hasattr(scheduler, 'step') and callable(scheduler.step), "The scheduler object should have a " \
"step function."
self.scheduler = scheduler


+ 61
- 42
fastNLP/core/callbacks/more_evaluate_callback.py View File

@@ -11,6 +11,67 @@ from .topk_saver import TopkSaver


class MoreEvaluateCallback(HasMonitorCallback):
"""
当评测时需要调用不同的 evaluate_fn (例如在大部分生成任务中,一般使用训练 loss 作为训练过程中的 evaluate ;但同时在训练到
一定 epoch 数量之后,会让 model 生成的完整的数据评测 bleu 等。此刻就可能需要两种不同的 evaluate_fn ),只使用 Trainer
无法满足需求,可以通过调用本 callback 进行。如果需要根据本 callback 中的评测结果进行模型保存,请传入 topk 以及
topk_monitor 等相关参数。可以通过 evaluate_every 或 watch_monitor 控制触发进行 evaluate 的条件。

如果设置了 evaluate 结果更好就保存的话,将按如下文件结构进行保存::

- folder/
- YYYY-mm-dd-HH_MM_SS_fffff/ # 自动根据当前脚本的启动时间创建的
- {save_object}-epoch_{epoch_idx}-batch_{global_batch_idx}-{topk_monitor}_{monitor_value}/ # 满足topk条件存储文件名

:param dataloaders: 需要评估的数据
:param metrics: 使用的 metrics 。
:param evaluate_every: 用来控制 ``Trainer`` 内部的 ``Evaluator`` 验证的频率,其可以为负数、正数或者函数:

1. 为负数时表示每隔几个 ``epoch`` evaluate 一次;
2. 为正数则表示每隔几个 ``batch`` evaluate 一次;
3. 为函数时表示用户自己传入的用于控制 evaluate 的频率的函数,该函数的应该接受当前 trainer 对象作为参数,并
返回一个 bool 值,返回为 True 说明需要进行 evaluate ;将在每个 ``batch`` 结束后调用该函数判断是否需要 evaluate;

.. note::

如果参数 ``evaluate_every`` 为函数,其应当类似:

>>> def my_evaluate_every(trainer) -> bool:
... if (trainer.global_forward_batches+1) % 1000 == 0:
... return True
... else:
... return False

该函数表示当每经过 1000 个 batch,``Trainer`` 中内置的 ``Evaluator`` 就会验证一次;

另一个需要注意的事情在于该函数会在每一次 batch 的结尾进行调用,当该函数返回 ``True`` 时,``Evaluator`` 才会进行验证;
:param watch_monitor: 这个值用来表示监控的 Trainer 中的 evaluate 结果的,当该值不为 None ,evaluate_every 失效。本参数的
意义是,当检测到 Trainer 中 evaluate results 的 {watch_monitor} 的结果更好时,则进行一次 evaluate 。该参数有两种
取值: (1) str 类型,监控的 metric 值。如果在 evaluation 结果中没有找到完全一致的名称,将使用 最长公共字符串算法 找到最
匹配的那个作为 monitor ; (2) 也可以传入一个函数,接受参数为 evaluation 的结果(字典类型),返回一个 float 值作为 monitor
的结果,如果当前结果中没有相关的monitor 值请返回 None 。
:param watch_monitor_larger_better: watch_monitor 是否越大越好。
:param evaluate_fn: 用来控制 `Evaluator` 在评测的前向传播过程中是调用哪一个函数,例如是 `model.evaluate_step` 还是
`model.forward`;(1) 如果该值是 None,那么我们会默认使用 `evaluate_step` 当做前向传播的函数,如果在模型中没有
找到该方法,则使用 `model.forward` 函数;(2) 如果为 str 类型,则尝试从 model 中寻找该方法,找不到则报错。
:param num_eval_sanity_batch: 在初始化 Evaluator 后运行多少个 sanity check 的 batch ,检测一下。
:param topk: 如果需要根据当前 callback 中的 evaluate 结果保存模型或 Trainer ,可以通过设置 tokp 实现。(1)为 -1 表示每次
evaluate 后都保存;(2)为 0 (默认),表示不保存;(3)为整数,表示保存性能最 topk 个。
:param topk_monitor: 如果需要根据当前 callback 中的 evaluate 结果保存。这个参数是指在当前 callback 中的 evaluate 结果寻找
:param topk_larger_better: topk_monitor 的值是否时越大越好。
:param folder: 保存的文件夹,fastNLP 将在该文件下以时间戳创建子文件夹,并在里面保存。因此不同次运行可以将被保存到不同的
时间戳文件夹中。如果为 None ,默认使用当前文件夹。
:param only_state_dict: 保存模型时是否只保存 state_dict 。当 model_save_fn 不为 None 时,该参数无效。
:param save_object: 可选 ['trainer', 'model'],表示在保存时的保存对象为 ``trainer+model`` 还是 只是 ``model`` 。如果
保存 ``trainer`` 对象的话,将会保存 :class:~fastNLP.Trainer 的相关状态,可以通过 :meth:`Trainer.load` 加载该断
点继续训练。如果保存的是 ``Model`` 对象,则可以通过 :meth:`Trainer.load_model` 加载该模型权重。
:param model_save_fn: 个性化的保存函数,当触发保存操作时,就调用这个函数,这个函数应当接受一个文件夹作为参数,不返回任何东西。
如果传入了 model_save_fn 函数,fastNLP 将不再进行模型相关的保存。在多卡场景下,我们只在 rank 0 上会运行该函数。
:param save_evaluate_results: 是否保存 evaluate 的结果。如果为 True ,在保存 topk 模型的 folder 中还将额外保存一个
``fastnlp_evaluate_results.json`` 文件,记录当前的 results。仅在设置了 topk 的场景下有用,默认为 True 。
:param save_kwargs: dict。更多的保存相关的参数。
:param kwargs: 其它与 Evaluator 相关的初始化参数,如果不传入,将从 Trainer 中获取。
"""
def __init__(self, dataloaders, metrics:Dict, evaluate_every:Optional[Union[int, Callable]]=-1,
watch_monitor:Union[str, Callable]=None, watch_monitor_larger_better:bool=True,
evaluate_fn=None, num_eval_sanity_batch=2,
@@ -18,48 +79,6 @@ class MoreEvaluateCallback(HasMonitorCallback):
folder=None, only_state_dict=True, save_object='model', model_save_fn=None,
save_evaluate_results=True, save_kwargs=None,
**kwargs):
"""
当评测时需要调用不同的 evaluate_fn (例如在大部分生成任务中,一般使用训练 loss 作为训练过程中的 evaluate ;但同时在训练到
一定 epoch 数量之后,会让 model 生成的完整的数据评测 bleu 等。此刻就可能需要两种不同的 evaluate_fn ),只使用 Trainer
无法满足需求,可以通过调用本 callback 进行。如果需要根据本 callback 中的评测结果进行模型保存,请传入 topk 以及
topk_monitor 等相关参数。可以通过 evaluate_every 或 watch_monitor 控制触发进行 evaluate 的条件。

如果设置了 evaluate 结果更好就保存的话,将按如下文件结构进行保存::

- folder/
- YYYY-mm-dd-HH_MM_SS_fffff/ # 自动根据当前脚本的启动时间创建的
- {save_object}-epoch_{epoch_idx}-batch_{global_batch_idx}-{topk_monitor}_{monitor_value}/ # 满足topk条件存储文件名

:param dataloaders: 需要评估的数据
:param metrics: 使用的 metrics 。
:param evaluate_every: 可以为负数、正数和函数;(1) 为负整数时表示每隔几个 epoch evaluate 一次;(2) 为正整数则表示每隔几个 batch
evaluate 一次;(3) 为函数时表示用户自己传入的用于控制 evaluate 的频率的函数,该函数的应该接受 trainer 对象作为参数,并返回
一个 bool 值,返回为 True 说明需要进行 evaluate ;将在每个 batch 结束后调用该函数判断是否需要 evaluate 。
:param watch_monitor: 这个值用来表示监控的 Trainer 中的 evaluate 结果的,当该值不为 None ,evaluate_every 失效。本参数的
意义是,当检测到 Trainer 中 evaluate results 的 {watch_monitor} 的结果更好时,则进行一次 evaluate 。该参数有两种
取值: (1) str 类型,监控的 metric 值。如果在 evaluation 结果中没有找到完全一致的名称,将使用 最长公共字符串算法 找到最
匹配的那个作为 monitor ; (2) 也可以传入一个函数,接受参数为 evaluation 的结果(字典类型),返回一个 float 值作为 monitor
的结果,如果当前结果中没有相关的monitor 值请返回 None 。
:param watch_monitor_larger_better: watch_monitor 是否越大越好。
:param evaluate_fn: 用来控制 `Evaluator` 在评测的前向传播过程中是调用哪一个函数,例如是 `model.evaluate_step` 还是
`model.forward`;(1) 如果该值是 None,那么我们会默认使用 `evaluate_step` 当做前向传播的函数,如果在模型中没有
找到该方法,则使用 `model.forward` 函数;(2) 如果为 str 类型,则尝试从 model 中寻找该方法,找不到则报错。
:param num_eval_sanity_batch: 在初始化 Evaluator 后运行多少个 sanity check 的 batch ,检测一下。
:param topk: 如果需要根据当前 callback 中的 evaluate 结果保存模型或 Trainer ,可以通过设置 tokp 实现。(1)为 -1 表示每次
evaluate 后都保存;(2)为 0 (默认),表示不保存;(3)为整数,表示保存性能最 topk 个。
:param topk_monitor: 如果需要根据当前 callback 中的 evaluate 结果保存。这个参数是指在当前 callback 中的 evaluate 结果寻找
:param topk_larger_better: topk_monitor 的值是否时越大越好。
:param folder: 保存的文件夹,fastNLP 将在该文件下以时间戳创建子文件夹,并在里面保存。因此不同次运行可以将被保存到不同的
时间戳文件夹中。如果为 None ,默认使用当前文件夹。
:param only_state_dict: 保存模型时是否只保存 state_dict 。当 model_save_fn 不为 None 时,该参数无效。
:param save_object: 可选 ['trainer', 'model'],表示在保存时的保存对象为 trainer+model 还是 只是model 。
:param model_save_fn: 个性化的保存函数,当触发保存操作时,就调用这个函数,这个函数应当接受一个文件夹作为参数,不返回任何东西。
如果传入了 model_save_fn 函数,fastNLP 将不再进行模型相关的保存。在多卡场景下,我们只在 rank 0 上会运行该函数。
:param save_evaluate_results: 是否保存 evaluate 的结果。如果为 True ,在保存 topk 模型的 folder 中还将额外保存一个
fastnlp_evaluate_results.json 文件,记录当前的 results。仅在设置了 topk 的场景下有用,默认为 True 。
:param save_kwargs: dict。更多的保存相关的参数。
:param kwargs: 其它与 Evaluator 相关的初始化参数,如果不传入,将从 Trainer 中获取。请特别留意 evaluate_fn 的设置。
"""
super(MoreEvaluateCallback, self).__init__(watch_monitor, watch_monitor_larger_better,
must_have_monitor=False)



+ 19
- 17
fastNLP/core/callbacks/progress_callback.py View File

@@ -39,25 +39,27 @@ def choose_progress_callback(progress_bar: Union[str, ProgressCallback]) -> Prog


class RichCallback(ProgressCallback):
"""
在训练过程中打印 rich progress bar 的 callback 。在 Trainer 中,默认就会使用这个 callback 来显示进度。如果需要定制这个 Callback 的
参数,请通过实例化本 Callback 并传入到 Trainer 中实现。

:param print_every: 多少个 batch 更新一次显示。
:param loss_round_ndigit: 显示的 loss 保留多少位有效数字
:param monitor: 监控的 metric 值。当检测到这个key的结果更好时,会打印出不同的颜色进行提示。

* 为 ``None``
将尝试使用 :class:`~fastNLP.Trainer` 中设置 `monitor` 值(如果有设置)。
* 为 ``str``
尝试直接使用该名称从 ``evaluation`` 结果中寻找,如果在 ``evaluation`` 结果中没有找到完全一致的名称,将
使用 最长公共字符串算法 从 ``evaluation`` 结果中找到最匹配的那个作为 ``monitor`` 。
* 为 ``Callable``
接受参数为 ``evaluation`` 的结果(字典类型),返回一个 ``float`` 值作为 ``monitor`` 的结果,如果当前结果中没有相关
的 ``monitor`` 值请返回 ``None`` 。
:param larger_better: 是否是 monitor 的结果越大越好。
:param format_json: 是否格式化 json 再打印
"""
def __init__(self, print_every:int = 1, loss_round_ndigit:int = 6, monitor:str=None, larger_better:bool=True,
format_json=True):
"""

:param print_every: 多少个 batch 更新一次显示。
:param loss_round_ndigit: 显示的 loss 保留多少位有效数字
:param monitor: 监控的 metric 值。当检测到这个key的结果更好时,会打印出不同的颜色进行提示。

* 为 ``None``
将尝试使用 :class:`~fastNLP.Trainer` 中设置 `monitor` 值(如果有设置)。
* 为 ``str``
尝试直接使用该名称从 ``evaluation`` 结果中寻找,如果在 ``evaluation`` 结果中没有找到完全一致的名称,将
使用 最长公共字符串算法 从 ``evaluation`` 结果中找到最匹配的那个作为 ``monitor`` 。
* 为 ``Callable``
接受参数为 ``evaluation`` 的结果(字典类型),返回一个 ``float`` 值作为 ``monitor`` 的结果,如果当前结果中没有相关
的 ``monitor`` 值请返回 ``None`` 。
:param larger_better: 是否是 monitor 的结果越大越好。
:param format_json: 是否格式化 json 再打印
"""
super().__init__(monitor=monitor, larger_better=larger_better, must_have_monitor=False)
self.print_every = print_every
self.progress_bar = f_rich_progress


+ 53
- 43
fastNLP/core/callbacks/topk_saver.py View File

@@ -16,22 +16,24 @@ from .has_monitor_callback import ResultsMonitor


class Saver:
"""
执行保存的对象。保存的文件组织结构为::

- folder # 当前初始化的参数
- YYYY-mm-dd-HH_MM_SS_fffff/ # 自动根据当前脚本的启动时间创建的
- folder_name # 由 save() 调用时传入。

:param folder: 保存在哪个文件夹下,默认为当前 folder 下。
:param save_object: 可选 ['trainer', 'model'],表示在保存时的保存对象为 ``trainer+model`` 还是 只是 ``model`` 。如果
保存 ``trainer`` 对象的话,将会保存 :class:~fastNLP.Trainer 的相关状态,可以通过 :meth:`Trainer.load` 加载该断
点继续训练。如果保存的是 ``Model`` 对象,则可以通过 :meth:`Trainer.load_model` 加载该模型权重。
:param only_state_dict: 保存时是否仅保存权重,在 model_save_fn 不为 None 时无意义。
:param model_save_fn: 个性化的保存函数,当触发保存操作时,就调用这个函数,这个函数应当接受一个文件夹作为参数,不返回任何东西。
如果传入了 model_save_fn 函数,fastNLP 将不再进行模型相关的保存。在多卡场景下,我们只在 rank 0 上会运行该函数。
:param kwargs: 更多需要传递给 Trainer.save() 或者 Trainer.save_model() 接口的参数。
"""
def __init__(self, folder:str=None, save_object:str='model', only_state_dict:bool=True,
model_save_fn:Callable=None, **kwargs):
"""
执行保存的对象。保存的文件组织结构为::

- folder # 当前初始化的参数
- YYYY-mm-dd-HH_MM_SS_fffff/ # 自动根据当前脚本的启动时间创建的
- folder_name # 由 save() 调用时传入。

:param folder: 保存在哪个文件夹下,默认为当前 folder 下。
:param save_object: 可选 ['trainer', 'model'],表示在保存时的保存对象为 trainer+model 还是 只是model 。
:param only_state_dict: 保存时是否仅保存权重,在 model_save_fn 不为 None 时无意义。
:param model_save_fn: 个性化的保存函数,当触发保存操作时,就调用这个函数,这个函数应当接受一个文件夹作为参数,不返回任何东西。
如果传入了 model_save_fn 函数,fastNLP 将不再进行模型相关的保存。在多卡场景下,我们只在 rank 0 上会运行该函数。
:param kwargs: 更多需要传递给 Trainer.save() 或者 Trainer.save_model() 接口的参数。
"""
if folder is None:
folder = Path.cwd().absolute()
logger.info(f"Parameter `folder` is None, and we will use {folder} to save and load your model.")
@@ -79,8 +81,8 @@ class Saver:
"""
以 json 格式保存 results 到 path 中

:param results:
:param path:
:param results: 一般是评测后的结果。
:param path: 保存的文件名
:return:
"""
with open(path, 'w', encoding='utf8') as f:
@@ -117,12 +119,12 @@ class Saver:


class TopkQueue:
def __init__(self, topk):
"""
用于维护处于 topk 的 key, value 对。
"""
用于维护处于 topk 的 key, value 对。

:param int topk: 整数,-1 表示所有数据都是 topk 的; 如果是 0, 表示没有任何数据是满足 topk 的。
"""
:param int topk: 整数,-1 表示所有数据都是 topk 的; 如果是 0, 表示没有任何数据是满足 topk 的。
"""
def __init__(self, topk):
assert isinstance(topk, int)
self.topk = topk
self.topk_dict = {} # 其中 key 为保存的内容, value 是对应的性能。
@@ -170,31 +172,39 @@ class TopkQueue:


class TopkSaver(ResultsMonitor, Saver):
"""
用来识别 topk 模型并保存,也可以仅当一个保存 Saver 使用。保存路径为::

- folder/
- YYYY-mm-dd-HH_MM_SS_fffff/ # 自动根据当前脚本的启动时间创建的
- {save_object}-epoch_{epoch_idx}-batch_{global_batch_idx}-{topk_monitor}_{monitor_value}/ # 满足topk条件存储文件名

:param topk: 保存 topk 多少的模型,-1 为保存所有模型;0 为都不保存;大于 0 的数为保存 topk 个。
:param monitor: 监控的 metric 值。

* 为 ``None``
将尝试使用 :class:`~fastNLP.Trainer` 中设置 `monitor` 值(如果有设置)。
* 为 ``str``
尝试直接使用该名称从 ``evaluation`` 结果中寻找,如果在 ``evaluation`` 结果中没有找到完全一致的名称,将
使用 最长公共字符串算法 从 ``evaluation`` 结果中找到最匹配的那个作为 ``monitor`` 。
* 为 ``Callable``
接受参数为 ``evaluation`` 的结果(字典类型),返回一个 ``float`` 值作为 ``monitor`` 的结果,如果当前结果中没有相关
的 ``monitor`` 值请返回 ``None`` 。
:param larger_better: 该 monitor 是否越大越好。
:param folder: 保存在哪个文件夹下,默认为当前 folder 下。
:param save_object: 可选 ['trainer', 'model'],表示在保存时的保存对象为 ``trainer+model`` 还是 只是 ``model`` 。如果
保存 ``trainer`` 对象的话,将会保存 :class:~fastNLP.Trainer 的相关状态,可以通过 :meth:`Trainer.load` 加载该断
点继续训练。如果保存的是 ``Model`` 对象,则可以通过 :meth:`Trainer.load_model` 加载该模型权重。
:param only_state_dict: 保存时是否仅保存权重,在 model_save_fn 不为 None 时无意义。
:param model_save_fn: 个性化的保存函数,当触发保存操作时,就调用这个函数,这个函数应当接受一个文件夹作为参数,不返回任何东西。
如果传入了 model_save_fn 函数,fastNLP 将不再进行模型相关的保存。在多卡场景下,我们只在 rank 0 上会运行该函数。
:param save_evaluate_results: 是否保存 evaluate 的结果。如果为 True ,在保存 topk 模型的 folder 中还将额外保存一个
``fastnlp_evaluate_results.json`` 文件,记录当前的 metric results 。仅在设置了 topk 的场景下有用,默认为 True 。
:param kwargs: 更多需要传递给 Trainer.save() 或者 Trainer.save_model() 接口的参数。
"""
def __init__(self, topk:int=0, monitor:str=None, larger_better:bool=True, folder:str=None, save_object:str='model',
only_state_dict:bool=True, model_save_fn:Callable=None, save_evaluate_results:bool=True,
**kwargs):
"""
用来识别 topk 模型并保存,也可以仅当一个保存 Saver 使用。保存路径为::

- folder/
- YYYY-mm-dd-HH_MM_SS_fffff/ # 自动根据当前脚本的启动时间创建的
- {save_object}-epoch_{epoch_idx}-batch_{global_batch_idx}-{topk_monitor}_{monitor_value}/ # 满足topk条件存储文件名

:param topk: 保存 topk 多少的模型,-1 为保存所有模型;0 为都不保存;大于 0 的数为保存 topk 个。
:param monitor: 监控哪个指标判断是否是 topk 的。监控的 metric 值。如果在 evaluation 结果中没有找到完全一致的名称,将使用
最长公共字符串算法 找到最匹配的那个作为 monitor 。如果为 None,将尝试使用 Trainer 设置的 monitor 。也可以传入一个函数,
接受参数为 evaluation 的结果(字典类型),返回一个 float 值作为 monitor 的结果,如果当前结果中没有相关的 monitor 值请
返回 None 。
:param larger_better: 该 monitor 是否越大越好。
:param folder: 保存在哪个文件夹下,默认为当前 folder 下。
:param save_object: 可选 ['trainer', 'model'],表示在保存时的保存对象为 trainer+model 还是 只是model 。
:param only_state_dict: 保存时是否仅保存权重,在 model_save_fn 不为 None 时无意义。
:param model_save_fn: 个性化的保存函数,当触发保存操作时,就调用这个函数,这个函数应当接受一个文件夹作为参数,不返回任何东西。
如果传入了 model_save_fn 函数,fastNLP 将不再进行模型相关的保存。在多卡场景下,我们只在 rank 0 上会运行该函数。
:param save_evaluate_results: 是否保存 evaluate 的结果。如果为 True ,在保存 topk 模型的 folder 中还将额外保存一个
fastnlp_evaluate_results.json 文件,记录当前的 results。仅在设置了 topk 的场景下有用,默认为 True 。
:param kwargs: 更多需要传递给 Trainer.save() 或者 Trainer.save_model() 接口的参数。
"""
ResultsMonitor.__init__(self, monitor, larger_better)
Saver.__init__(self, folder, save_object, only_state_dict, model_save_fn, **kwargs)



+ 13
- 12
fastNLP/core/callbacks/torch_callbacks/torch_grad_clip_callback.py View File

@@ -1,25 +1,26 @@
__all__ = [
'TorchGradClipCallback'
]
from typing import Union, List
from ..callback import Callback


class TorchGradClipCallback(Callback):
def __init__(self, clip_value=1, clip_type='norm', parameters=None):
r"""
在每次 optimizer update 之前将 parameter 进行 clip
r"""
在每次 optimizer update 之前将 parameter 进行 clip 。

:param float clip_value: 将gradient 限制到[-clip_value, clip_value]。clip_value应该为正数
:param str clip_type: 支持'norm', 'value'两种:
:param clip_value: 将gradient 限制到[-clip_value, clip_value]。clip_value应该为正数
:param clip_type: 支持'norm', 'value'两种:

1. 'norm', 将gradient的norm rescale到[-clip_value, clip_value]
2. 'value', 将gradient限制在[-clip_value, clip_value],
小于-clip_value的gradient被赋值为-clip_value;
大于clip_value的gradient被赋值为clip_value.
1. 'norm', 将gradient的norm rescale到[-clip_value, clip_value]
2. 'value', 将gradient限制在[-clip_value, clip_value],
小于-clip_value的gradient被赋值为-clip_value;大于clip_value的gradient被赋值为clip_value.

:param None,torch.Tensor,List[torch.Tensor] parameters: 一般通过model.parameters()获得。
如果为None则默认对 Trainer 的 optimizers 中所有参数进行梯度裁剪。
"""
:param None,torch.Tensor,List[torch.Tensor] parameters: 一般通过model.parameters()获得。
如果为None则默认对 Trainer 的 optimizers 中所有参数进行梯度裁剪。
"""
def __init__(self, clip_value:int=1, clip_type:str='norm',
parameters:Union["torch.Tensor", List["torch.Tensor"]]=None):
super().__init__()

from torch import nn


+ 12
- 10
fastNLP/core/callbacks/torch_callbacks/torch_lr_sched_callback.py View File

@@ -2,21 +2,23 @@ __all__ = [
'TorchWarmupCallback'
]
import math
from typing import Union

from ..callback import Callback


class TorchWarmupCallback(Callback):
def __init__(self, warmup=0.1, schedule='constant'):
r"""
调整 learning rate 的 callback 。仅在实际发生参数更新的情况下

:param int,float warmup: 如果warmup为int,则在该step之前,learning rate根据schedule的策略变化; 如果warmup为float,
如0.1, 则前10%的step是按照schedule策略调整learning rate。
:param str schedule: 以哪种方式调整。
linear: 前warmup的step上升到指定的learning rate(从Trainer中的optimizer处获取的), 后warmup的step下降到0;
constant前warmup的step上升到指定learning rate,后面的step保持learning rate.
"""
r"""
调整 learning rate 的 callback 。

:param warmup: 如果warmup为int,则在该step之前,learning rate根据schedule的策略变化; 如果warmup为float,
如0.1, 则前10%的step是按照schedule策略调整learning rate。
:param schedule: 以哪种方式调整。

1. linear: 前warmup的step上升到指定的learning rate(从Trainer中的optimizer处获取的), 后warmup的step下降到0;
2. constant前warmup的step上升到指定learning rate,后面的step保持learning rate.
"""
def __init__(self, warmup:Union[int, float]=0.1, schedule:str='constant'):
super().__init__()
self.warmup = max(warmup, 0.)



+ 20
- 11
fastNLP/core/collators/collator.py View File

@@ -82,16 +82,26 @@ def _get_backend() -> str:


class Collator:
def __init__(self, backend='auto'):
"""
用于 pad 数据的对象。会自动将所有能够 pad (由 fastNLP 根据数据判定能否 pad )的数据都进行 pad 操作,默认 pad 的值为 0。
可使用 set_pad() 函数调整。如果有些 field 不想输出,可以使用 set_ignore() 函数进行设置。Collator 在第一次进行 pad 的
时候自动根据设置以及数据情况,为每个 field 获取一个 padder ,在之后的每次调用中,都将使用对应的 Padder 给对应的 field 。
"""
用于 pad 数据的对象。会自动将所有能够 pad (由 fastNLP 根据数据判定能否 pad )的数据都进行 pad 操作,默认 pad 的值为 0。
哦安定一个 field 是否可以 pad 的方式为:(1)当前这个 field 是否所有对象都是一样的数据类型;(因此,如果某 field 的数据有些是float
有些是 int 将知道该 field 被判定为不可 pad 类型。)(2)当前这个 field 是否每个 sample 都具有一样的深度;(因此,例如有个 field 的
数据转为 batch 类型后为 [1, [1,2]], 会被判定为不可 pad ,因为第一个 sample 与 第二个 sample 深度不同)(3)当前这个 field 的类
型是否是可以 pad (例如 str 类型的数据)。可以通过设置 logger.setLevel('debug') 来打印是判定不可 pad 的原因。

:param backend: 对于可以 pad 的 field,使用哪种 tensor,支持 ['torch','jittor','paddle','numpy','raw', auto, None]。
若为 'auto' ,则在进行 pad 的时候会根据调用的环境决定其 backend 。该参数对不能进行 pad 的数据没用影响,不能 pad
的数据返回一定是 list 。
"""
todo 补充 code example 。

如果需要将某个本可以 pad 的 field 设置为不可 pad ,则可以通过 :meth:`~fastNLP.Collator.set_pad` 的 pad_val 设置为 None 实现。
如果需要某些 field 不要包含在 pad 之后的结果中,可以使用 :meth:`~fastNLP.Collator.set_ignore` 进行设置。

Collator 在第一次进行 pad 的时候自动根据设置以及数据情况,为每个 field 获取一个 padder ,在之后的每次调用中,都将使用对应
的 Padder 给对应的 field 。

:param backend: 对于可以 pad 的 field,使用哪种 tensor,支持 ['torch','jittor','paddle','numpy','raw', auto, None]。
若为 'auto' ,则在进行 pad 的时候会根据调用的环境决定其 backend 。该参数对不能进行 pad 的数据没用影响,不能 pad
的数据返回一定是 list 。
"""
def __init__(self, backend='auto'):
self.unpack_batch_func = None
self.pack_batch_func = None
self.ignore_fields = set()
@@ -264,9 +274,8 @@ class Collator:
def set_ignore(self, *field_names) -> "Collator":
"""
如果有的内容不希望输出,可以在此处进行设置,被设置的 field 将在 batch 的输出中被忽略。
Example::

collator.set_ignore('field1', 'field2')
>>> collator = Collator().set_ignore('field1', 'field2')

:param field_names: 需要忽略的 field 的名称。如果 Dataset 的 __getitem__ 方法返回的是 dict 类型的,则可以直接使用对应的
field 的 key 来表示,如果是 nested 的 dict,可以使用元组来表示,例如 {'a': {'b': 1}} 中的使用 ('a', 'b'); 如果


+ 9
- 8
fastNLP/core/collators/packer_unpacker.py View File

@@ -9,9 +9,9 @@ class MappingPackerUnpacker:
"""
将 Sequence[Mapping] 转为 Dict 。例如 [{'a': [1, 2], 'b': 1}, {'a': [3], 'b': 2}] -> {'a': [[1, 2], [3]], 'b': [1, 2]}

:param batch:
:param ignore_fields:
:param input_fields:
:param batch: 需要 unpack 的 batch 数据。
:param ignore_fields: 需要忽略的 field 。
:param input_fields: 需要设置为 input 的 field 。
:return:
"""
dict_batch = defaultdict(list)
@@ -29,13 +29,13 @@ class MappingPackerUnpacker:

class NestedMappingPackerUnpacker:
@staticmethod
def unpack_batch(batch:Sequence[Mapping], ignore_fields:set, input_fields:Dict):
def unpack_batch(batch:Sequence[Mapping], ignore_fields:set, input_fields:Dict)->Dict:
"""
将 nested 的 dict 中的内容展开到一个 flat dict 中

:param batch:
:param batch: 需要 unpack 的 batch 数据。
:param ignore_fields: 需要忽略的 field 。
:param input_fields: 不需要继续往下衍射的
:param input_fields: 需要设置为 input 的 field 。
:return:
"""
dict_batch = defaultdict(list)
@@ -72,8 +72,9 @@ class SequencePackerUnpacker:
"""
将 Sequence[Sequence] 转为 Mapping 。例如 [[[1, 2], 2], [[3], 2]] -> {'_0': [[1, 2], [3]], '_1': [1, 2]}

:param batch:
:param ignore_fields: 需要忽略的field
:param batch: 需要 unpack 的 batch 数据。
:param ignore_fields: 需要忽略的 field 。
:param input_fields: 需要设置为 input 的 field 。
:return:
"""
dict_batch = defaultdict(list)


+ 3
- 3
fastNLP/core/collators/padders/jittor_padder.py View File

@@ -90,7 +90,7 @@ class JittorNumberPadder(Padder):
super().__init__(pad_val=pad_val, dtype=dtype)

@staticmethod
def pad(batch_field, pad_val, dtype):
def pad(batch_field, pad_val=0, dtype=None):
return jittor.Var(np.array(batch_field, dtype=dtype))


@@ -107,7 +107,7 @@ class JittorSequencePadder(Padder):
super().__init__(pad_val=pad_val, dtype=dtype)

@staticmethod
def pad(batch_field, pad_val, dtype):
def pad(batch_field, pad_val=0, dtype=None):
tensor = get_padded_jittor_tensor(batch_field, dtype=dtype, pad_val=pad_val)
return tensor

@@ -125,7 +125,7 @@ class JittorTensorPadder(Padder):
super().__init__(pad_val=pad_val, dtype=dtype)

@staticmethod
def pad(batch_field, pad_val, dtype):
def pad(batch_field, pad_val=0, dtype=None):
try:
if not isinstance(batch_field[0], jittor.Var):
batch_field = [jittor.Var(np.array(field.tolist(), dtype=dtype)) for field in batch_field]


+ 36
- 24
fastNLP/core/collators/padders/numpy_padder.py View File

@@ -30,53 +30,65 @@ def _get_dtype(ele_dtype, dtype, class_name):


class NumpyNumberPadder(Padder):
def __init__(self, pad_val=0, ele_dtype=None, dtype=None):
"""
可以将形如 [1, 2, 3] 这类的数据转为 np.array([1, 2, 3])
"""
可以将形如 [1, 2, 3] 这类的数据转为 np.array([1, 2, 3]) 。可以通过:

>>> NumpyNumberPadder.pad([1, 2, 3])

使用。

:param pad_val: 该值无意义
:param ele_dtype: 用于检测当前 field 的元素类型是否可以转换为 np.array 类型。
:param dtype: 输出的数据的 dtype 是什么
"""
:param pad_val: 该值无意义
:param ele_dtype: 用于检测当前 field 的元素类型是否可以转换为 np.array 类型。
:param dtype: 输出的数据的 dtype 是什么
"""
def __init__(self, pad_val=0, ele_dtype=None, dtype=None):
dtype = _get_dtype(ele_dtype, dtype, self.__class__.__name__)
super().__init__(pad_val=pad_val, dtype=dtype)

@staticmethod
def pad(batch_field, pad_val, dtype):
def pad(batch_field, pad_val=0, dtype=None):
return np.array(batch_field, dtype=dtype)


class NumpySequencePadder(Padder):
"""
将类似于 [[1], [1, 2]] 的内容 pad 为 np.array([[1, 0], [1, 2]]) 可以 pad 多重嵌套的数据。
可以通过以下的方式直接使用:

>>> NumpySequencePadder.pad([[1], [1, 2]], pad_val=-100, dtype=float)
[[ 1. -100.]
[ 1. 2.]]

:param pad_val: pad 的值是多少。
:param ele_dtype: 用于检测当前 field 的元素类型是否可以转换为 np.array 类型。
:param dtype: 输出的数据的 dtype 是什么
"""
def __init__(self, pad_val=0, ele_dtype=None, dtype=None):
"""
将类似于 [[1], [1, 2]] 的内容 pad 为 np.array([[1, 0], [1, 2]]) 可以 pad 多重嵌套的数据。

:param pad_val: pad 的值是多少。
:param ele_dtype: 用于检测当前 field 的元素类型是否可以转换为 np.array 类型。
:param dtype: 输出的数据的 dtype 是什么
"""
dtype = _get_dtype(ele_dtype, dtype, self.__class__.__name__)
super().__init__(pad_val=pad_val, dtype=dtype)

@staticmethod
def pad(batch_field, pad_val, dtype):
def pad(batch_field, pad_val=0, dtype=None):
return get_padded_numpy_array(batch_field, dtype=dtype, pad_val=pad_val)


class NumpyTensorPadder(Padder):
"""
pad 类似于 [np.array([3, 4]), np.array([1])] 的 field 。若内部元素不为 np.ndarray ,则必须含有 tolist() 方法。

>>> NumpyTensorPadder.pad([np.array([3, 4]), np.array([1])], pad_val=-100)
[[ 3. 4.]
[ 1. -100.]]
:param pad_val: pad 的值是多少。
:param ele_dtype: 用于检测当前 field 的元素类型是否可以转换为 np.array 类型。
:param dtype: 输出的数据的 dtype 是什么
"""
def __init__(self, pad_val=0, ele_dtype=None, dtype=None):
"""
pad 类似于 [np.array([3, 4], np.array([1])] 的 field 。若内部元素不为 np.ndarray ,则必须含有 tolist() 方法。

:param pad_val: pad 的值是多少。
:param ele_dtype: 用于检测当前 field 的元素类型是否可以转换为 np.array 类型。
:param dtype: 输出的数据的 dtype 是什么
"""
dtype = _get_dtype(ele_dtype, dtype, self.__class__.__name__)
super().__init__(pad_val=pad_val, dtype=dtype)

@staticmethod
def pad(batch_field, pad_val, dtype):
def pad(batch_field, pad_val=0, dtype=None):
try:
if not isinstance(batch_field[0], np.ndarray):
batch_field = [np.array(field.tolist(), dtype=dtype) for field in batch_field]


+ 12
- 8
fastNLP/core/collators/padders/padder.py View File

@@ -1,5 +1,9 @@

class Padder:
"""
所有 Padder 对象父类,所有的 Padder 对象都会实现 pad(batch_field, pad_val=0, dtype=None) 的静态函数。

"""
def __init__(self, pad_val, dtype):
self.pad_val = pad_val
self.dtype = dtype
@@ -8,19 +12,19 @@ class Padder:
return self.pad(batch_field=batch_field, pad_val=self.pad_val, dtype=self.dtype)

@staticmethod
def pad(batch_field, pad_val, dtype):
def pad(batch_field, pad_val=0, dtype=None):
raise NotImplementedError()


class NullPadder(Padder):
def __init__(self, ele_dtype=None, pad_val=None, dtype=None):
"""
不进行任何 检查 与 pad 的空 padder 。
"""
不进行任何 检查 与 pad 的空 padder 。

:param ele_dtype:
:param pad_val:
:param dtype:
"""
:param ele_dtype:
:param pad_val:
:param dtype:
"""
def __init__(self, ele_dtype=None, pad_val=None, dtype=None):
super().__init__(pad_val=pad_val, dtype=dtype)

def __call__(self, batch_field):


+ 24
- 24
fastNLP/core/collators/padders/paddle_padder.py View File

@@ -80,55 +80,55 @@ def _get_dtype(ele_dtype, dtype, class_name):


class PaddleNumberPadder(Padder):
def __init__(self, pad_val=0, ele_dtype=None, dtype=None):
"""
可以将形如 [1, 2, 3] 这类的数据转为 paddle.Tensor([1, 2, 3])
"""
可以将形如 [1, 2, 3] 这类的数据转为 paddle.Tensor([1, 2, 3])

:param pad_val: 该值无意义
:param ele_dtype: 用于检测当前 field 的元素类型是否可以转换为 paddle.tensor 类型。
:param dtype: 输出的数据的 dtype 是什么。如 int, float, 'int32' 等
"""
:param pad_val: 该值无意义
:param ele_dtype: 用于检测当前 field 的元素类型是否可以转换为 paddle.tensor 类型。
:param dtype: 输出的数据的 dtype 是什么。如 int, float, 'int32' 等
"""
def __init__(self, pad_val=0, ele_dtype=None, dtype=None):
# 仅当 ele_dtype 是 python number/ numpy number 或者 tensor
dtype = _get_dtype(ele_dtype, dtype, class_name=self.__class__.__name__)
super().__init__(pad_val=pad_val, dtype=dtype)

@staticmethod
def pad(batch_field, pad_val, dtype):
def pad(batch_field, pad_val=0, dtype=None):
return paddle.to_tensor(batch_field, dtype=dtype)


class PaddleSequencePadder(Padder):
def __init__(self, ele_dtype=None, pad_val=0, dtype=None):
"""
将类似于 [[1], [1, 2]] 的内容 pad 为 paddle.Tensor([[1, 0], [1, 2]]) 可以 pad 多重嵌套的数据。
"""
将类似于 [[1], [1, 2]] 的内容 pad 为 paddle.Tensor([[1, 0], [1, 2]]) 可以 pad 多重嵌套的数据。

:param pad_val: pad 的值。
:param ele_dtype: 用于检测当前 field 的元素类型是否可以转换为 paddle.tensor 类型。
:param dtype: 输出的数据的 dtype 是什么。如 int, float, 'int32' 等
"""
:param pad_val: pad 的值。
:param ele_dtype: 用于检测当前 field 的元素类型是否可以转换为 paddle.tensor 类型。
:param dtype: 输出的数据的 dtype 是什么。如 int, float, 'int32' 等
"""
def __init__(self, ele_dtype=None, pad_val=0, dtype=None):
dtype = _get_dtype(ele_dtype, dtype, class_name=self.__class__.__name__)
super().__init__(pad_val=pad_val, dtype=dtype)

@staticmethod
def pad(batch_field, pad_val, dtype):
def pad(batch_field, pad_val=0, dtype=None):
tensor = get_padded_paddle_tensor(batch_field, dtype=dtype, pad_val=pad_val)
return tensor


class PaddleTensorPadder(Padder):
def __init__(self, pad_val=0, ele_dtype=None, dtype=None):
"""
目前支持 [paddle.tensor([3, 2], paddle.tensor([2, 1])] 类似的,若内部元素不为 paddle.tensor ,则必须含有 tolist() 方法。
"""
目前支持 [paddle.tensor([3, 2], paddle.tensor([2, 1])] 类似的,若内部元素不为 paddle.tensor ,则必须含有 tolist() 方法。

:param pad_val: pad 的值。
:param ele_dtype: 用于检测当前 field 的元素类型是否可以转换为 paddle.tensor 类型。
:param dtype: 输出的数据的 dtype 是什么。如 int, float, 'int32' 等
"""
:param pad_val: pad 的值。
:param ele_dtype: 用于检测当前 field 的元素类型是否可以转换为 paddle.tensor 类型。
:param dtype: 输出的数据的 dtype 是什么。如 int, float, 'int32' 等
"""
def __init__(self, pad_val=0, ele_dtype=None, dtype=None):
dtype = _get_dtype(ele_dtype, dtype, class_name=self.__class__.__name__)
super().__init__(pad_val=pad_val, dtype=dtype)

@staticmethod
def pad(batch_field, pad_val, dtype):
def pad(batch_field, pad_val=0, dtype=None):
try:
if not isinstance(batch_field[0], paddle.Tensor):
batch_field = [np.array(field.tolist()) for field in batch_field]


+ 24
- 24
fastNLP/core/collators/padders/raw_padder.py View File

@@ -26,14 +26,14 @@ def _get_dtype(ele_dtype, dtype, class_name):


class RawNumberPadder(Padder):
def __init__(self, pad_val=0, ele_dtype=None, dtype=None):
"""
可以将形如 [1, 2, 3] 这类的数据转为 [1, 2, 3] 。实际上该 padder 无意义。
"""
可以将形如 [1, 2, 3] 这类的数据转为 [1, 2, 3] 。实际上该 padder 无意义。

:param pad_val: 该值无意义
:param ele_dtype: 用于检测当前 field 的元素类型是否可以转换为 np.array 类型。
:param dtype: 输出的数据的 dtype 是什么
"""
:param pad_val: 该值无意义
:param ele_dtype: 用于检测当前 field 的元素类型是否可以转换为 np.array 类型。
:param dtype: 输出的数据的 dtype 是什么
"""
def __init__(self, pad_val=0, ele_dtype=None, dtype=None):
dtype = _get_dtype(ele_dtype, dtype, self.__class__.__name__)
super().__init__(pad_val=pad_val, dtype=dtype)

@@ -41,24 +41,24 @@ class RawNumberPadder(Padder):
return batch_field

@staticmethod
def pad(batch_field, pad_val, dtype):
def pad(batch_field, pad_val=0, dtype=None):
raise NotImplementedError()


class RawSequencePadder(Padder):
def __init__(self, pad_val=0, ele_dtype=None, dtype=None):
"""
将类似于 [[1], [1, 2]] 的内容 pad 为 [[1, 0], [1, 2]] 。可以 pad 多重嵌套的数据。
"""
将类似于 [[1], [1, 2]] 的内容 pad 为 [[1, 0], [1, 2]] 。可以 pad 多重嵌套的数据。

:param pad_val: pad 的值
:param ele_dtype: 用于检测当前 field 的元素类型是否可以转换为 np.array 类型。
:param dtype: 输出的数据的 dtype 是什么
"""
:param pad_val: pad 的值
:param ele_dtype: 用于检测当前 field 的元素类型是否可以转换为 np.array 类型。
:param dtype: 输出的数据的 dtype 是什么
"""
def __init__(self, pad_val=0, ele_dtype=None, dtype=None):
dtype = _get_dtype(ele_dtype, dtype, self.__class__.__name__)
super().__init__(pad_val=pad_val, dtype=dtype)

@staticmethod
def pad(batch_field, pad_val, dtype):
def pad(batch_field, pad_val=0, dtype=None):
"""

:param batch_field:
@@ -70,19 +70,19 @@ class RawSequencePadder(Padder):


class RawTensorPadder(Padder):
def __init__(self, pad_val=0, ele_dtype=None, dtype=None):
"""
将类似于 [[1], [1, 2]] 的内容 pad 为 [[1, 0], [1, 2]] 。可以 pad 多重嵌套的数据。
"""
将类似于 [[1], [1, 2]] 的内容 pad 为 [[1, 0], [1, 2]] 。可以 pad 多重嵌套的数据。

:param pad_val: pad 的值
:param ele_dtype: 用于检测当前 field 的元素类型是否可以转换为 np.array 类型。
:param dtype: 输出的数据的 dtype 是什么
"""
:param pad_val: pad 的值
:param ele_dtype: 用于检测当前 field 的元素类型是否可以转换为 np.array 类型。
:param dtype: 输出的数据的 dtype 是什么
"""
def __init__(self, pad_val=0, ele_dtype=None, dtype=None):
dtype = _get_dtype(ele_dtype, dtype, self.__class__.__name__)
super().__init__(pad_val=pad_val, dtype=dtype)

@staticmethod
def pad(batch_field, pad_val, dtype):
def pad(batch_field, pad_val=0, dtype=None):
"""

:param batch_field:


+ 31
- 24
fastNLP/core/collators/padders/torch_padder.py View File

@@ -64,54 +64,61 @@ def _get_dtype(ele_dtype, dtype, class_name):


class TorchNumberPadder(Padder):
def __init__(self, pad_val=0, ele_dtype=None, dtype=None):
"""
可以将形如 [1, 2, 3] 这类的数据转为 torch.Tensor([1, 2, 3])
"""
可以将形如 [1, 2, 3] 这类的数据转为 torch.Tensor([1, 2, 3])

:param pad_val: 该值无意义
:param ele_dtype: 用于检测当前 field 的元素类型是否可以转换为 torch.tensor 类型。
:param dtype: 输出的数据的 dtype 是什么。如 torch.long, torch.float32, int, float 等
"""
:param pad_val: 该值无意义
:param ele_dtype: 用于检测当前 field 的元素类型是否可以转换为 torch.tensor 类型。
:param dtype: 输出的数据的 dtype 是什么。如 torch.long, torch.float32, int, float 等
"""
def __init__(self, pad_val=0, ele_dtype=None, dtype=None):
dtype = _get_dtype(ele_dtype, dtype, class_name=self.__class__.__name__)
super().__init__(pad_val=pad_val, dtype=dtype)

@staticmethod
def pad(batch_field, pad_val, dtype):
def pad(batch_field, pad_val=0, dtype=None):
return torch.tensor(batch_field, dtype=dtype)


class TorchSequencePadder(Padder):
def __init__(self, pad_val=0, ele_dtype=None, dtype=None):
"""
将类似于 [[1], [1, 2]] 的内容 pad 为 torch.Tensor([[1, 0], [1, 2]]) 可以 pad 多重嵌套的数据。
"""
将类似于 [[1], [1, 2]] 的内容 pad 为 torch.Tensor([[1, 0], [1, 2]]) 可以 pad 多重嵌套的数据。

:param pad_val: 需要 pad 的值。
:param ele_dtype: 用于检测当前 field 的元素类型是否可以转换为 torch.tensor 类型。
:param dtype: 输出的数据的 dtype 是什么。如 torch.long, torch.float32, int, float 等
"""
:param pad_val: 需要 pad 的值。
:param ele_dtype: 用于检测当前 field 的元素类型是否可以转换为 torch.tensor 类型。
:param dtype: 输出的数据的 dtype 是什么。如 torch.long, torch.float32, int, float 等
"""
def __init__(self, pad_val=0, ele_dtype=None, dtype=None):
dtype = _get_dtype(ele_dtype, dtype, class_name=self.__class__.__name__)
super().__init__(pad_val=pad_val, dtype=dtype)

@staticmethod
def pad(batch_field, pad_val, dtype):
def pad(batch_field, pad_val=0, dtype=None):
tensor = get_padded_torch_tensor(batch_field, dtype=dtype, pad_val=pad_val)
return tensor


class TorchTensorPadder(Padder):
"""
目前支持 [torch.tensor([3, 2], torch.tensor([1])] 类似的。若内部元素不为 torch.tensor ,则必须含有 tolist() 方法。

>>> TorchTensorPadder.pad([np.array([3, 4]), np.array([1])], pad_val=-100)
[[ 3. 4.]
[ 1. -100.]]
>>> TorchTensorPadder.pad([torch.LongTensor([3, 4]), torch.LongTensor([1])], pad_val=-100)
tensor([[ 3, 4],
[ 1, -100]])

:param pad_val: 需要 pad 的值。
:param ele_dtype: 用于检测当前 field 的元素类型是否可以转换为 torch.tensor 类型。
:param dtype: 输出的数据的 dtype 是什么。如 torch.long, torch.float32, int, float 等
"""
def __init__(self, pad_val=0, ele_dtype=None, dtype=None):
"""
目前支持 [torch.tensor([3, 2], torch.tensor([1])] 类似的。若内部元素不为 torch.tensor ,则必须含有 tolist() 方法。

:param pad_val: 需要 pad 的值。
:param ele_dtype: 用于检测当前 field 的元素类型是否可以转换为 torch.tensor 类型。
:param dtype: 输出的数据的 dtype 是什么。如 torch.long, torch.float32, int, float 等
"""
dtype = _get_dtype(ele_dtype, dtype, class_name=self.__class__.__name__)
super().__init__(pad_val=pad_val, dtype=dtype)

@staticmethod
def pad(batch_field, pad_val, dtype):
def pad(batch_field, pad_val=0, dtype=None):
device = None
try:
if not isinstance(batch_field[0], torch.Tensor):


+ 115
- 55
fastNLP/core/controllers/evaluator.py View File

@@ -20,6 +20,114 @@ from fastNLP.core.log import logger


class Evaluator:
"""
用于对数据进行评测。

:param model: 待测试的模型,如果传入的 driver 为 Driver 实例,该参数将被忽略。
:param dataloaders: 待评测的数据集。如果为多个,请使用 dict 传入。
:param metrics: 使用的 metric 。必须为 dict 类型,其中 key 为 metric 的名称,value 为一个 Metric 对象。支持 fastNLP 的
metric ,torchmetrics,allennlpmetrics 等。
:param driver: 训练模型所使用的具体的驱动模式,应当为以下选择中的一个:``["torch", "jittor", "paddle"]``
其中 "torch" 表示使用 ``TorchSingleDriver`` 或者 ``TorchDDPDriver``,具体使用哪一种取决于参数 ``device``
的设置。
:param device: 该参数用来指定具体训练时使用的机器;注意当该参数仅当您通过 `torch.distributed.launch/run` 启动时可以为 None,
此时 fastNLP 不会对模型和数据进行设备之间的移动处理,但是你可以通过参数 `input_mapping` 和 `output_mapping` 来实现设备之间
数据迁移的工作(通过这两个参数传入两个处理数据的函数);同时你也可以通过在 kwargs 添加参数 "data_device" 来让我们帮助您将数据
迁移到指定的机器上(注意这种情况理应只出现在用户在 Trainer 实例化前自己构造 DDP 的场景);

device 的可选输入如下所示:

* *str*: 例如 'cpu', 'cuda', 'cuda:0', 'cuda:1' 等;
* *torch.device*: 例如 'torch.device("cuda:0")';
* *int*: 将使用 ``device_id`` 为该值的 ``gpu`` 进行训练;如果值为 -1,那么默认使用全部的显卡,此时使用的 driver 实例是 `TorchDDPDriver`;
* *list(int)*: 如果多于 1 个device,应当通过该种方式进行设定;注意此时我们一定会使用 ``TorchDDPDriver``,不管您传入的列表的长度是 1 还是其它值;
* *None*: 仅当用户自己通过训练框架提供的并行训练启动脚本开启 ddp 进程时为 None;

.. note::

如果希望使用 ``TorchDDPDriver``,在初始化 ``Trainer`` 时您应当使用::

Trainer(driver="torch", device=[0, 1])

注意如果这时 ``device=[0]``,我们仍旧会使用 ``TorchDDPDriver``。

如果希望使用 ``TorchSingleDriver``,则在初始化 ``Trainer`` 时您应当使用::

Trainer(driver="torch", device=0)

.. warning::

注意参数 ``device`` 仅当您通过 pytorch 或者其它训练框架自身的并行训练启动脚本启动 ddp 训练时才允许为 ``None``!

例如,当您使用::

python -m torch.distributed.launch --nproc_per_node 2 train.py

来使用 ``TorchDDPDriver`` 时,此时参数 ``device`` 不再有效(不管您是否自己初始化 ``init_process_group``),我们将直接
通过 ``torch.device(f"cuda:{local_rank}")`` 来获取当前进程所使用的的具体的 gpu 设备。因此此时您需要使用 ``os.environ["CUDA_VISIBLE_DEVICES"]``
来指定要使用的具体的 gpu 设备。

另一点需要注意的是,当您没有选择自己初始化 ``init_process_group`` 时,我们仍旧会帮助您把模型和数据迁移到当前进程所使用的
具体的 gpu 设备上。但是如果您选择自己在 ``Trainer`` 初始化前(意味着在 ``driver`` 的 ``setup`` 前)初始化 ``init_process_group``,
那么对于模型的迁移应当完全由您自己来完成。此时对于数据的迁移,如果您在 ``Trainer`` 初始化时指定了参数 ``data_device``,那么
我们会将数据迁移到 ``data_device`` 上;如果其为 None,那么将数据迁移到正确的设备上应当由您自己来完成。

对于使用 ``TorchDDPDriver`` 的更多细节,请见 :class:`fastNLP.core.drivers.torch_driver.TorchDDPDriver`。

:param evaluate_batch_step_fn: 定制每次 evaluate batch 执行的函数。该函数应接受的两个参数为 `evaluator` 和 `batch`,
不需要有返回值;可以参考 :meth:`~fastNLP.core.controllers.loops.EvaluateBatchLoop.batch_step_fn`
函数。
:param evaluate_fn: 用来控制 `Evaluator` 在评测的前向传播过程中是调用哪一个函数,例如是 `model.evaluate_step` 还是
`model.forward`;(1) 如果该值是 None,那么我们会默认使用 `evaluate_step` 函数,如果在模型中没有
找到该方法,则使用 `model.forward` 函数;(2) 如果为 str 类型,则尝试从 model 中寻找该方法,找不到则报错。
:param input_mapping: 应当为一个字典或者一个函数,表示在当前 step 拿到一个 batch 的数据后,应当做怎样的映射处理:

1. 如果 ``input_mapping`` 是一个字典:

1. 如果此时 batch 也是一个 ``Dict``,那么我们会把 batch 中同样在 ``input_mapping`` 中的 key 修改为 ``input_mapping`` 的对应 ``key`` 的 ``value``;
2. 如果此时 batch 是一个 ``dataclass``,那么我们会先将其转换为一个 ``Dict``,然后再进行上述转换;
3. 如果此时 batch 此时是其它类型,那么我们将会直接报错;
2. 如果 ``input_mapping`` 是一个函数,那么对于取出的 batch,我们将不会做任何处理,而是直接将其传入该函数里,并将其返回值
送入模型中;

:param output_mapping: 应当为一个字典或者一个函数,表示在当前 step 拿到一个 model 的返回值后,应当做怎样的映射处理:

1. 如果 ``output_mapping`` 是一个字典:

1. 如果此时 batch 也是一个 ``Dict``,那么我们会把输出中同样在 ``output_mapping`` 中的 key 修改为 ``output_mapping`` 的对应 ``key`` 的 ``value``;
例如输出结果为 {'a': 1},而 output_mapping={'a':'b'} ,那么结果就是 {'b': 1}
2. 如果此时 batch 是一个 ``dataclass``,那么我们会先将其转换为一个 ``Dict``,然后再进行上述转换;
3. 如果此时 batch 此时是其它类型,那么我们将会直接报错;
2. 如果 ``output_mapping`` 是一个函数,我们将会把结果传入该函数里,并将其返回值送入到 metric 中。

:param model_wo_auto_param_call: 是否关闭在训练时调用我们的 auto_param_call 来自动匹配 batch 和 evaluate_fn 函数的参数的行为;
如果该值为 True,并且当 batch 为字典时,我们会根据 evaluate_fn 所需要的参数从 batch 中提取对应的对象,传入到 evaluate_fn 函数中;如果该值
为 False,那么我们会将 batch 直接透传给 evaluate_fn 函数。
:param fp16: 是否使用 fp16 。
:param verbose: 是否打印 evaluate 的结果。
:kwargs:
* *torch_kwargs* -- 用于在指定 ``driver`` 为 'torch' 时设定具体 driver 实例的一些参数:
* ddp_kwargs -- 用于在使用 ``TorchDDPDriver`` 时指定 ``DistributedDataParallel`` 初始化时的参数;例如传入
{'find_unused_parameters': True} 来解决有参数不参与前向运算导致的报错等;
* torch_non_blocking -- 表示用于 pytorch 的 tensor 的 to 方法的参数 non_blocking;
* *data_device* -- 表示如果用户的模型 device (在 Driver 中对应为参数 model_device)为 None 时,我们会将数据迁移到 data_device 上;
注意如果 model_device 为 None,那么 data_device 不会起作用;
* *model_use_eval_mode* (``bool``) --
是否在 evaluate 的时候将 model 的状态设置成 eval 状态。在 eval 状态下,model 的
dropout 与 batch normalization 将会关闭。默认为True。如果为 False,fastNLP 不会对 model 的 evaluate 状态做任何设置。无论
该值是什么,fastNLP 都会在 evaluate 接受后将 model 的状态设置为 train 。
* *use_dist_sampler* --
是否使用分布式evaluate的方式。仅当 driver 为分布式类型时,该参数才有效。默认为根据 driver 是否支持
分布式进行设置。如果为True,将使得每个进程上的 dataloader 自动使用不同数据,所有进程的数据并集是整个数据集。
* *output_from_new_proc* --
应当为一个字符串,表示在多进程的 driver 中其它进程的输出流应当被做如何处理;其值应当为以下之一:
["all", "ignore", "only_error"];当该参数的值不是以上值时,该值应当表示一个文件夹的名字,我们会将其他 rank 的输出流重定向到
log 文件中,然后将 log 文件保存在通过该参数值设定的文件夹中;默认为 "only_error";
* *progress_bar* --
evaluate 的时候显示的 progress bar 。目前支持三种 [None, 'raw', 'rich', 'auto'], auto 表示如果检测
到当前terminal为交互型则使用 rich,否则使用 raw。
"""

driver: Driver
_evaluate_batch_loop: Loop

@@ -29,51 +137,6 @@ class Evaluator:
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):
"""
用于对数据进行评测。

:param model: 待测试的模型,如果传入的 driver 为 Driver 实例,该参数将被忽略。
:param dataloaders: 待评测的数据集。如果为多个,请使用 dict 传入。
:param metrics: 使用的 metric 。必须为 dict 类型,其中 key 为 metric 的名称,value 为一个 Metric 对象。支持 fastNLP 的
metric ,torchmetrics,allennlpmetrics 等。
:param driver: 使用 driver 。
:param device: 使用的设备。
:param evaluate_batch_step_fn: 定制每次 evaluate batch 执行的函数。该函数应接受的两个参数为 `evaluator` 和 `batch`,
不需要有返回值;可以参考 fastNLP.core.controllers.loops.evaluate_batch_loop.EvaluateBatchLoop中的batch_step_fn函数。
:param evaluate_fn: 用来控制 `Evaluator` 在评测的前向传播过程中是调用哪一个函数,例如是 `model.evaluate_step` 还是
`model.forward`;(1) 如果该值是 None,那么我们会默认使用 `evaluate_step` 当做前向传播的函数,如果在模型中没有
找到该方法,则使用 `model.forward` 函数;(2) 如果为 str 类型,则尝试从 model 中寻找该方法,找不到则报错。
:param input_mapping: 对 dataloader 中输出的内容将通过 input_mapping 处理之后再输入到 model 以及 metric 中。如果针对
model 和 metric 需要不同的 mapping,请考虑使用 evaluate_batch_step_fn 参数定制。
:param output_mapping: 对 model 输出的内容,将通过 output_mapping 处理之后再输入到 metric 中。
:param model_wo_auto_param_call: 是否关闭在训练时调用我们的 auto_param_call 来自动匹配 batch 和 forward 函数的参数的行为;
如果该值为 True,并且当 batch 为字典时,我们会根据 forward 所需要的参数从 batch 中提取对应的对象,传入到 forward 函数中;如果该值
为 False,那么我们会将 batch 直接透传给 forward 函数。注意上述逻辑同样应用于 `train_step`, `evaluate_step` 和 `test_step`;
:param fp16: 是否使用 fp16 。
:param verbose: 是否打印 evaluate 的结果。
:kwargs:
* *torch_kwargs* -- 用于在指定 ``driver`` 为 'torch' 时设定具体 driver 实例的一些参数:
* ddp_kwargs -- 用于在使用 ``TorchDDPDriver`` 时指定 ``DistributedDataParallel`` 初始化时的参数;例如传入
{'find_unused_parameters': True} 来解决有参数不参与前向运算导致的报错等;
* torch_non_blocking -- 表示用于 pytorch 的 tensor 的 to 方法的参数 non_blocking;
* *data_device* -- 表示如果用户的模型 device (在 Driver 中对应为参数 model_device)为 None 时,我们会将数据迁移到 data_device 上;
注意如果 model_device 为 None,那么 data_device 不会起作用;
* *model_use_eval_mode* (``bool``) --
是否在 evaluate 的时候将 model 的状态设置成 eval 状态。在 eval 状态下,model 的
dropout 与 batch normalization 将会关闭。默认为True。如果为 False,fastNLP 不会对 model 的 evaluate 状态做任何设置。无论
该值是什么,fastNLP 都会在 evaluate 接受后将 model 的状态设置为 train 。
* *use_dist_sampler* --
是否使用分布式evaluate的方式。仅当 driver 为分布式类型时,该参数才有效。默认为根据 driver 是否支持
分布式进行设置。如果为True,将使得每个进程上的 dataloader 自动使用不同数据,所有进程的数据并集是整个数据集。
* *output_from_new_proc* --
应当为一个字符串,表示在多进程的 driver 中其它进程的输出流应当被做如何处理;其值应当为以下之一:
["all", "ignore", "only_error"];当该参数的值不是以上值时,该值应当表示一个文件夹的名字,我们会将其他 rank 的输出流重定向到
log 文件中,然后将 log 文件保存在通过该参数值设定的文件夹中;默认为 "only_error";
* *progress_bar* --
evaluate 的时候显示的 progress bar 。目前支持三种 [None, 'raw', 'rich', 'auto'], auto 表示如果检测
到当前terminal为交互型则使用 rich,否则使用 raw。
"""

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,
@@ -129,16 +192,13 @@ class Evaluator:

def run(self, num_eval_batch_per_dl: int = -1, **kwargs) -> Dict:
"""
返回一个字典类型的数据,其中key为metric的名字,value为对应metric的结果。
如果存在多个metric,一个dataloader的情况,key的命名规则是
metric_indicator_name#metric_name
如果存在多个数据集,一个metric的情况,key的命名规则是
metric_indicator_name#metric_name#dataloader_name (其中 # 是默认的 separator ,可以通过 Evaluator 初始化参数修改)。
如果存在多个metric,多个dataloader的情况,key的命名规则是
metric_indicator_name#metric_name#dataloader_name
其中 metric_indicator_name 可能不存在。

:param num_eval_batch_per_dl: 每个 dataloader 测试多少个 batch 的数据,-1 为测试所有数据。
返回一个字典类型的数据,其中 key 为 metric 的名字,value 为对应结果。返回的字典中,key 的命名规则如下
``metric_indicator_name#metric_name#dataloader_name`` ,其中 ``metric_indicator_name`` 是由使用的 metric 返回的结果
决定的,仅当 metric 的结果返回是 dict 类型是才有该值;``metric_name`` 则由 ``Evaluator`` 初始化时传入的 ``metrics`` 参数
决定;``dataloader_name``仅在传入的 ``dataloaders`` 为 dict 时会有。此外其中的 ``#`` 符号通过 ``Evaluator`` 初始化
参数 ``separator`` 进行设置。

:param num_eval_batch_per_dl: 每个 dataloader 测试前多少个 batch 的数据,-1 为测试所有数据。
:return:
"""
assert isinstance(num_eval_batch_per_dl, int), "num_eval_batch_per_dl must be of int type."


+ 4
- 4
fastNLP/core/controllers/trainer.py View File

@@ -80,9 +80,9 @@ class Trainer(TrainerEventTrigger):
您应当使用 ``TorchDDPDriver``,意味着您需要通过 ``python -m torch.distributed.launch`` 的方式来启动训练,此时参数 ``device``
应当设置为 None(此时我们会忽略该参数),具体见下面对于参数 ``device`` 的更详细的解释。

:param driver: 训练模型所使用的具体的驱动模式,应当为以下选择中的一个:["torch"],之后我们会加入 jittor、paddle 等
国产框架的训练模式;其中 "torch" 表示使用 ``TorchSingleDriver`` 或者 ``TorchDDPDriver``,具体使用哪一种取决于参数 ``device``
的设置
:param driver: 训练模型所使用的具体的驱动模式,应当为以下选择中的一个:``["torch", "jittor", "paddle"]``
其中 "torch" 表示使用 ``TorchSingleDriver`` 或者 ``TorchDDPDriver``,具体使用哪一种取决于参数 ``device``
的设置
:param train_dataloader: 训练数据集,注意其必须是单独的一个数据集,不能是 List 或者 Dict;
:param optimizers: 训练所需要的优化器;可以是单独的一个优化器实例,也可以是多个优化器组成的 List;
:param device: 该参数用来指定具体训练时使用的机器;注意当该参数仅当您通过 `torch.distributed.launch/run` 启动时可以为 None,
@@ -135,7 +135,7 @@ class Trainer(TrainerEventTrigger):
:param batch_step_fn: 定制每次训练时前向运行一个 batch 的数据所执行的函数。该函数应接受两个参数为 ``trainer`` 和 ``batch``,
不需要要返回值;更详细的使用位置和说明请见 :meth:`fastNLP.core.controllers.TrainBatchLoop.batch_step_fn`;
:param evaluate_batch_step_fn: 定制每次验证时前向运行一个 batch 的数据所执行的函数。该函数应接受的两个参数为 ``evaluator`` 和 ``batch``,
不需要有返回值;可以参考 :meth:`fastNLP.core.controllers.EvaluateBatchLoop.batch_step_fn`;
不需要有返回值;可以参考 :meth:`fastNLP.core.controllers.TrainBatchLoop.batch_step_fn`;
:param train_fn: 用来控制 ``Trainer`` 在训练的前向传播过程中是调用模型的哪一个函数,例如是 ``train_step`` 还是 ``forward``;
默认为 ``None``,如果该值是 ``None``,那么我们会默认使用 ``train_step`` 当做前向传播的函数,如果在模型的定义类中没有找到该方法,
则使用模型默认的前向传播函数,例如对于 pytorch 来说就是 ``forward``。


+ 8
- 8
fastNLP/core/dataset/instance.py View File

@@ -1,6 +1,6 @@
r"""
instance 模块实现了Instance 类在fastNLP中对应sample。一个sample可以认为是一个Instance类型的对象。
便于理解的例子可以参考文档 :mod:`fastNLP.core.dataset` 中的表格
便于理解的例子可以参考文档 :mod:`fastNLP.core.dataset`

"""

@@ -14,10 +14,10 @@ from fastNLP.core.utils.utils import pretty_table_printer

class Instance(Mapping):
r"""
Instance是fastNLP中对应一个sample的类。每个sample在fastNLP中是一个Instance对象。
Instance一般与 :class:`~fastNLP.DataSet` 一起使用, Instance的初始化如下面的Example所示::
Instance fastNLP 中对应一个 sample 的类。每个 sample fastNLP 中是一个 Instance 对象。
Instance 一般与 :class:`~fastNLP.DataSet` 一起使用, Instance 的初始化如下面的 Example 所示::

instance = Instance() # 请补充完整
>>> instance = Instance(input="this is a demo sentence", label='good') # 请补充完整

"""

@@ -44,17 +44,17 @@ class Instance(Mapping):

def keys(self):
r"""
返回一个迭代器,内容是field_name
返回一个迭代器,内容是 field_name

:return: 一个迭代器
:return: 一个迭代器
"""
return self.fields.keys()

def values(self):
r"""
返回一个迭代器,内容是field_value
返回一个迭代器,内容是 field_value

:return: 一个迭代器
:return: 一个迭代器
"""
return self.fields.values()



+ 13
- 8
fastNLP/core/metrics/metric.py View File

@@ -14,14 +14,16 @@ from fastNLP.core.metrics.element import Element


class Metric:
"""
fastNLP 中 Metric 的基类,自定义 Metric 时,请继承该对象。使用该对象,将有助于减少在分布式状态下的 Metric 计算。

:param backend: 目前支持四种类型的 backend, ``[torch, paddle, jittor, auto]``。其中 ``auto`` 表示根据实际调用
Metric.update() 函数时传入的参数决定具体的 ``backend`` ,大部分情况下直接使用 ``auto`` 即可。
:param aggregate_when_get_metric: 在计算 metric 的时候是否自动将各个进程上的相同的 element 的数字聚合后再得到metric,
当 backend 不支持分布式时,该参数无意义。如果为 None ,将在 :class:`fastNLP.Evaluator` 中根据 sampler 是否使用分布式
进行自动设置。
"""
def __init__(self, backend: Union[str, Backend, None] = 'auto', aggregate_when_get_metric: bool = None):
"""

:param str backend: 目前支持四种类型的backend, [torch, paddle, jittor, auto]。其中 auto 表示根据实际调用 Metric.update()
函数时传入的参数决定具体的 backend ,大部分情况下直接使用 auto 即可。
:param bool aggregate_when_get_metric: 在计算 metric 的时候是否自动将各个进程上的相同的 element 的数字聚合后再得到metric,
当 backend 不支持分布式时,该参数无意义。如果为 None ,将在 Evaluator 中根据 sampler 是否使用分布式进行自动设置。
"""
self.backend = AutoBackend(backend)
self._updated = False
self.get_metric = self._sync_get_metric(self.get_metric)
@@ -39,7 +41,10 @@ class Metric:
"""
注册一个 element 对象,注册之后便可以通过在 Metric 中直接通过 self.{name} 进行调用,可以认为该对象即为对应 backend 的
tensor 直接进行加减乘除计算即可。
注意:如果想使得该 metric 可自动扩展到多卡的情况,请一定申明 aggregate_method 。

..warning::

如果想使得该 metric 可自动扩展到多卡的情况,请一定申明 aggregate_method 。

:param name: 当前 element 的名字,注册后,在 Metric 中可以通过 self.{name} 访问该变量。
:param value: 初始化的值。在调用 Metric.reset() 方法时也将自动设置为该值


+ 17
- 17
fastNLP/core/metrics/span_f1_pre_rec_metric.py View File

@@ -200,27 +200,27 @@ def _bio_tag_to_spans(tags, ignore_labels=None):


class SpanFPreRecMetric(Metric):
r"""

:param tag_vocab: 标签的 :class:`~fastNLP.Vocabulary` 。支持的标签为"B"(没有label);或"B-xxx"(xxx为某种label,比如POS中的NN),
在解码时,会将相同xxx的认为是同一个label,比如['B-NN', 'E-NN']会被合并为一个'NN'.
:param pred: 用该key在evaluate()时从传入dict中取出prediction数据。 为None,则使用 `pred` 取数据
:param target: 用该key在evaluate()时从传入dict中取出target数据。 为None,则使用 `target` 取数据
:param seq_len: 用该key在evaluate()时从传入dict中取出sequence length数据。为None,则使用 `seq_len` 取数据。
:param encoding_type: 目前支持bio, bmes, bmeso, bioes。默认为None,通过tag_vocab自动判断.
:param ignore_labels: str 组成的list. 这个list中的class不会被用于计算。例如在POS tagging时传入['NN'],则不会计算'NN'个label
:param only_gross: 是否只计算总的f1, precision, recall的值;如果为False,不仅返回总的f1, pre, rec, 还会返回每个label的f1, pre, rec
:param f_type: `micro` 或 `macro` . `micro` :通过先计算总体的TP,FN和FP的数量,再计算f, precision, recall; `macro` : 分布计算每个类别的f, precision, recall,然后做平均(各类别f的权重相同)
:param beta: f_beta分数, :math:`f_{beta} = \frac{(1 + {beta}^{2})*(pre*rec)}{({beta}^{2}*pre + rec)}` . 常用为 `beta=0.5, 1, 2` 若为0.5则精确率的权重高于召回率;若为1,则两者平等;若为2,则召回率权重高于精确率。
:param backend: 目前支持四种类型的 backend, ``[torch, paddle, jittor, auto]``。其中 ``auto`` 表示根据实际调用
Metric.update() 函数时传入的参数决定具体的 ``backend`` ,大部分情况下直接使用 ``auto`` 即可。
:param aggregate_when_get_metric: 在计算 metric 的时候是否自动将各个进程上的相同的 element 的数字聚合后再得到metric,
当 backend 不支持分布式时,该参数无意义。如果为 None ,将在 :class:`fastNLP.Evaluator` 中根据 sampler 是否使用分布式
进行自动设置。
"""
def __init__(self, tag_vocab: Vocabulary, encoding_type: str = None, ignore_labels: List[str] = None,
only_gross: bool = True, f_type='micro',
beta=1, backend: Union[str, Backend, None] = 'auto', aggregate_when_get_metric: bool = None) -> None:
r"""

:param tag_vocab: 标签的 :class:`~fastNLP.Vocabulary` 。支持的标签为"B"(没有label);或"B-xxx"(xxx为某种label,比如POS中的NN),
在解码时,会将相同xxx的认为是同一个label,比如['B-NN', 'E-NN']会被合并为一个'NN'.
:param str pred: 用该key在evaluate()时从传入dict中取出prediction数据。 为None,则使用 `pred` 取数据
:param str target: 用该key在evaluate()时从传入dict中取出target数据。 为None,则使用 `target` 取数据
:param str seq_len: 用该key在evaluate()时从传入dict中取出sequence length数据。为None,则使用 `seq_len` 取数据。
:param str encoding_type: 目前支持bio, bmes, bmeso, bioes。默认为None,通过tag_vocab自动判断.
:param list ignore_labels: str 组成的list. 这个list中的class不会被用于计算。例如在POS tagging时传入['NN'],则不会计算'NN'个label
:param bool only_gross: 是否只计算总的f1, precision, recall的值;如果为False,不仅返回总的f1, pre, rec, 还会返回每个label的f1, pre, rec
:param str f_type: `micro` 或 `macro` . `micro` :通过先计算总体的TP,FN和FP的数量,再计算f, precision, recall; `macro` : 分布计算每个类别的f, precision, recall,然后做平均(各类别f的权重相同)
:param float beta: f_beta分数, :math:`f_{beta} = \frac{(1 + {beta}^{2})*(pre*rec)}{({beta}^{2}*pre + rec)}` . 常用为 `beta=0.5, 1, 2` 若为0.5则精确率的权重高于召回率;若为1,则两者平等;若为2,则召回率权重高于精确率。
:param str backend: 目前支持四种类型的backend, ['auto', 'torch', 'paddle', 'jittor']。其中 auto 表示根据实际调用 Metric.update()
函数时传入的参数决定具体的 backend ,一般情况下直接使用 'auto' 即可。
:param bool aggregate_when_get_metric: 在计算 metric 的时候是否自动将各个进程上的相同的 element 的数字聚合后再得到metric,
当 backend 不支持分布式时,该参数无意义。如果为 None ,将在 Evaluator 中根据 sampler 是否使用分布式进行自动设置。
"""
super(SpanFPreRecMetric, self).__init__(backend=backend, aggregate_when_get_metric=aggregate_when_get_metric)
if f_type not in ('micro', 'macro'):
raise ValueError("f_type only supports `micro` or `macro`', got {}.".format(f_type))


+ 1
- 1
fastNLP/core/samplers/conversion_utils.py View File

@@ -10,7 +10,7 @@ def conversion_between_reproducible_and_unrepeated_sampler(sampler):
将 sampler 替换成其对应的 reproducible 版本或 unrepeated 版本。如果输入是 UnrepeatedSampler 但是没找到对应的
ReproducibleSampler,

:param sampler:
:param sampler: 需要转换的 sampler 。
:return:
"""
assert isinstance(sampler, UnrepeatedSampler) or isinstance(sampler, ReproducibleSampler), \


+ 39
- 39
fastNLP/core/samplers/reproducible_batch_sampler.py View File

@@ -55,16 +55,16 @@ class ReproducibleBatchSampler:


class ReproduceBatchSampler(ReproducibleBatchSampler):
"""
可以使得 batch_sampler 对象状态恢复的 wrapper 。

:param batch_sampler: 可迭代出 数字 或 数字列表 的可迭代对象。ReproduceBatchSampler 将首先遍历一边该对象,然后将迭代
出来的序号暂存起来,使用时按照 batch_size 的 batch 大小吐出序号列表。
:param batch_size: 每个 batch 的大小是多少。
:param drop_last: 如果最后一个 batch 无法构成 batch_size 那么多个 sample ,是否丢掉。
:param kwargs: fastNLP 内部使用。
"""
def __init__(self, batch_sampler, batch_size: int, drop_last: bool, **kwargs):
"""
可以使得 batch_sampler 对象状态恢复的 wrapper 。

:param batch_sampler: 可迭代出 数字 或 数字列表 的可迭代对象。ReproduceBatchSampler 将首先遍历一边该对象,然后将迭代
出来的序号暂存起来,使用时按照 batch_size 的 batch 大小吐出序号列表。
:param batch_size: 每个 batch 的大小是多少。
:param drop_last: 如果最后一个 batch 无法构成 batch_size 那么多个 sample ,是否丢掉。
:param kwargs: fastNLP 内部使用。
"""
super().__init__()

self.batch_sampler = batch_sampler
@@ -158,18 +158,18 @@ class ReproduceBatchSampler(ReproducibleBatchSampler):


class RandomBatchSampler(ReproducibleBatchSampler):
"""
随机分 batch 的 batch_sampler 。

:param dataset: 实现了 __len__ 方法的数据容器。
:param batch_size: 每个 batch 的大小
:param shuffle: 如果为 True,将不进行 shuffle,实际上数据会以从长到短的方式输出。
:param drop_last: 如果最后一个 batch 的 sample 数量无法凑齐 batch_size 这么多,是否需要丢掉。
:param seed: 设置的随机数种子
:param kwargs: fastNLP 保留使用
"""
def __init__(self, dataset, batch_size:int = 32, shuffle: bool = True,
drop_last: bool = False, seed: int = 0, **kwargs):
"""
随机分 batch 的 batch_sampler 。

:param dataset: 实现了 __len__ 方法的数据容器。
:param batch_size: 每个 batch 的大小
:param shuffle: 如果为 True,将不进行 shuffle,实际上数据会以从长到短的方式输出。
:param drop_last: 如果最后一个 batch 的 sample 数量无法凑齐 batch_size 这么多,是否需要丢掉。
:param seed: 设置的随机数种子
:param kwargs: fastNLP 保留使用
"""
super().__init__()

self.dataset = dataset
@@ -363,28 +363,28 @@ class RandomBatchSampler(ReproducibleBatchSampler):


class BucketedBatchSampler(ReproducibleBatchSampler):
"""
首先按照 ``sample`` 的长度排序,然后按照 batch_size*num_batch_per_bucket 为一个桶的大小,``sample`` 只会在这个桶内进行组
合,这样每个 ``batch`` 中的 ``padding`` 数量会比较少 (因为桶内的数据的长度都接近)。

:param dataset: 实现了 __len__ 方法的数据容器。
:param length: 每条数据的长度。

* 为 ``List[int]`` 时
应当与 dataset 有一样的长度,表示 dataset 中每个元素的数量;
* 为 ``str`` 时
仅当传入的 ``dataset`` 是 :class:`fastNLP.DataSet` 时,允许传入 `str` ,该 `str` 将被认为是 ``dataset`` 中的
``field`` 。若 field 中的元素为 ``int``,则认为该值是 sample 的长度;若不为 ``int`` ,则尝试使用 ``len`` 方法
获取该 ``field`` 中每个元素的长度。
:param batch_size: 每个 batch 的大小
:param num_batch_per_bucket: 多少个 ``batch`` 组成一个桶,数据只会在一个桶内进行 ``shuffle`` 。
:param shuffle: 如果为 True,将不进行 ``shuffle``,实际上数据会以从长到短的方式输出。
:param drop_last: 如果最后一个 `batch` 的 ``sample`` 数量无法凑齐 ``batch_size`` 这么多,是否需要丢掉。
:param seed: 设置的随机数种子
:param kwargs: fastNLP 保留使用
"""
def __init__(self, dataset, length: Union[List[int], str], batch_size:int = 32, num_batch_per_bucket:int = 10,
shuffle: bool = True, drop_last: bool = False, seed: int = 0, **kwargs):
"""
首先按照 ``sample`` 的长度排序,然后按照 batch_size*num_batch_per_bucket 为一个桶的大小,``sample`` 只会在这个桶内进行组
合,这样每个 ``batch`` 中的 ``padding`` 数量会比较少 (因为桶内的数据的长度都接近)。

:param dataset: 实现了 __len__ 方法的数据容器。
:param length: 每条数据的长度。

* 为 ``List[int]`` 时
应当与 dataset 有一样的长度,表示 dataset 中每个元素的数量;
* 为 ``str`` 时
仅当传入的 ``dataset`` 是 :class:`fastNLP.DataSet` 时,允许传入 `str` ,该 `str` 将被认为是 ``dataset`` 中的
``field`` 。若 field 中的元素为 ``int``,则认为该值是 sample 的长度;若不为 ``int`` ,则尝试使用 ``len`` 方法
获取该 ``field`` 中每个元素的长度。
:param batch_size: 每个 batch 的大小
:param num_batch_per_bucket: 多少个 ``batch`` 组成一个桶,数据只会在一个桶内进行 ``shuffle`` 。
:param shuffle: 如果为 True,将不进行 ``shuffle``,实际上数据会以从长到短的方式输出。
:param drop_last: 如果最后一个 `batch` 的 ``sample`` 数量无法凑齐 ``batch_size`` 这么多,是否需要丢掉。
:param seed: 设置的随机数种子
:param kwargs: fastNLP 保留使用
"""
super().__init__()
if isinstance(dataset, DataSet) and isinstance(length, str):
length = dataset.get_field(length).content


+ 30
- 30
fastNLP/core/samplers/reproducible_sampler.py View File

@@ -53,15 +53,15 @@ class ReproducibleSampler:


class RandomSampler(ReproducibleSampler):
def __init__(self, dataset, shuffle: bool = True, seed: int = 0, **kwargs):
"""
随机顺序的 Sampler 。
"""
随机顺序的 Sampler 。

:param dataset: 实现了 __len__ 方法的数据容器
:param shuffle: 是否在每次 iterate 的时候打乱顺序。
:param seed: 随机数种子。
:param kwargs: 用户不需要使用,fastNLP 内部使用
"""
:param dataset: 实现了 __len__ 方法的数据容器
:param shuffle: 是否在每次 iterate 的时候打乱顺序。
:param seed: 随机数种子。
:param kwargs: 用户不需要使用,fastNLP 内部使用
"""
def __init__(self, dataset, shuffle: bool = True, seed: int = 0, **kwargs):
super(RandomSampler, self).__init__()
self.dataset = dataset
self.shuffle = shuffle
@@ -213,13 +213,13 @@ class RandomSampler(ReproducibleSampler):


class SequentialSampler(RandomSampler):
def __init__(self, dataset, **kwargs):
"""
按照顺序读取 ``dataset`` 。在多卡情况下,间隔读取,例如,在两卡情况下,卡 0 取 ``[0,2,4,..]``, 卡1取 ``[1,3,5...]`` 。
"""
按照顺序读取 ``dataset`` 。在多卡情况下,间隔读取,例如,在两卡情况下,卡 0 取 ``[0,2,4,..]``, 卡1取 ``[1,3,5...]`` 。

:param dataset: 实现了 __len__ 方法的数据容器。
:param kwargs:
"""
:param dataset: 实现了 __len__ 方法的数据容器。
:param kwargs:
"""
def __init__(self, dataset, **kwargs):
super().__init__(dataset=dataset, **kwargs)

def __iter__(self):
@@ -283,23 +283,23 @@ class SequentialSampler(RandomSampler):


class SortedSampler(SequentialSampler):
"""
将 ``dataset`` 中的数据根据 ``length`` 从长到短进行迭代。在多卡情况下,由于 ``padding`` , 最后一个 ``sample`` 可能是最长
的那个 ``sample`` 。

:param dataset: 实现了 __len__ 方法的数据容器。
:param length: 每条数据的长度。

* 为 ``List[int]`` 时
应当与 dataset 有一样的长度,表示 dataset 中每个元素的数量;
* 为 ``str`` 时
仅当传入的 ``dataset`` 是 :class:`fastNLP.DataSet` 时,允许传入 `str` ,该 `str` 将被认为是 ``dataset`` 中的
``field`` 。若 field 中的元素为 ``int``,则认为该值是 sample 的长度;若不为 ``int`` ,则尝试使用 ``len`` 方法
获取该 ``field`` 中每个元素的长度。
:param seed: 设置的随机数种子。
:param kwargs: fastNLP 保留使用。
"""
def __init__(self, dataset, length:Union[str, List], **kwargs):
"""
将 ``dataset`` 中的数据根据 ``length`` 从长到短进行迭代。在多卡情况下,由于 ``padding`` , 最后一个 ``sample`` 可能是最长
的那个 ``sample`` 。

:param dataset: 实现了 __len__ 方法的数据容器。
:param length: 每条数据的长度。

* 为 ``List[int]`` 时
应当与 dataset 有一样的长度,表示 dataset 中每个元素的数量;
* 为 ``str`` 时
仅当传入的 ``dataset`` 是 :class:`fastNLP.DataSet` 时,允许传入 `str` ,该 `str` 将被认为是 ``dataset`` 中的
``field`` 。若 field 中的元素为 ``int``,则认为该值是 sample 的长度;若不为 ``int`` ,则尝试使用 ``len`` 方法
获取该 ``field`` 中每个元素的长度。
:param seed: 设置的随机数种子。
:param kwargs: fastNLP 保留使用。
"""
super().__init__(dataset=dataset, **kwargs)
if isinstance(dataset, DataSet) and isinstance(length, str):
length = dataset.get_field(length).content


+ 29
- 23
fastNLP/core/samplers/unrepeated_sampler.py View File

@@ -19,15 +19,15 @@ class UnrepeatedSampler:


class UnrepeatedRandomSampler(UnrepeatedSampler):
def __init__(self, dataset, shuffle: bool = False, seed: int = 0, **kwargs):
"""
考虑在多卡evaluate的场景下,不能重复sample。
"""
考虑在多卡 evaluate 的场景下,不能重复 sample。

:param dataset: 实现了 __len__ 方法的数据容器。
:param shuffle: 如果为 True,将不进行 shuffle,实际上数据会以从长到短的方式输出。
:param seed: 设置的随机数种子
:param kwargs: fastNLP 保留使用
"""
:param dataset: 实现了 __len__ 方法的数据容器。
:param shuffle: 如果为 True,将不进行 shuffle,实际上数据会以从长到短的方式输出。
:param seed: 设置的随机数种子
:param kwargs: fastNLP 保留使用
"""
def __init__(self, dataset, shuffle: bool = False, seed: int = 0, **kwargs):
self.dataset = dataset
self.shuffle = shuffle
self.seed = seed
@@ -96,16 +96,22 @@ class UnrepeatedRandomSampler(UnrepeatedSampler):


class UnrepeatedSortedSampler(UnrepeatedRandomSampler):
"""
将 dataset 中的数据根据 length 从长到短进行迭代,并且保证在多卡场景下数据不重复。本 sampler 可能导致各个机器上的
batch 数量不完全一致。

:param dataset: 实现了 __len__ 方法的数据容器。
:param length: 每条数据的长度。

* 为 ``List[int]`` 时
应当与 dataset 有一样的长度,表示 dataset 中每个元素的数量;
* 为 ``str`` 时
仅当传入的 ``dataset`` 是 :class:`fastNLP.DataSet` 时,允许传入 `str` ,该 `str` 将被认为是 ``dataset`` 中的
``field`` 。若 field 中的元素为 ``int``,则认为该值是 sample 的长度;若不为 ``int`` ,则尝试使用 ``len`` 方法
获取该 ``field`` 中每个元素的长度。
:param kwargs: fastNLP 保留使用
"""
def __init__(self, dataset, length:Union[str, List], **kwargs):
"""
将 dataset 中的数据根据 length 从长到短进行迭代,并且保证在多卡场景下数据不重复。本 sampler 可能导致各个机器上的
batch 数量不完全一致。

:param dataset: 实现了 __len__ 方法的数据容器。
:param length: 如果为 List,应当与 dataset 有一样的长度,表示 dataset 中每个元素的数量;仅当传入的 dataset 为 fastNLP 的
DataSet 时支持传入 str,会将该str理解为 dataset 的 field 名称,若 field 中的元素为 int,则认为该值是 sample 的长度。
:param kwargs: fastNLP 保留使用
"""
super().__init__(dataset=dataset, shuffle=False, seed=0, **kwargs)
if isinstance(dataset, DataSet) and isinstance(length, str):
length = dataset.get_field(length).content
@@ -125,13 +131,13 @@ class UnrepeatedSortedSampler(UnrepeatedRandomSampler):


class UnrepeatedSequentialSampler(UnrepeatedRandomSampler):
def __init__(self, dataset, **kwargs):
"""
按照顺序读取 dataset。在多卡情况下,间隔读取,例如,在两卡情况下,卡0取 [0,2,4,..], 卡1取 [1,3,5...]。
"""
按照顺序读取 dataset。在多卡情况下,间隔读取,例如,在两卡情况下,卡0取 [0,2,4,..], 卡1取 [1,3,5...]。

:param dataset: 实现了 __len__ 方法的数据容器。
:param kwargs:
"""
:param dataset: 实现了 __len__ 方法的数据容器。
:param kwargs:
"""
def __init__(self, dataset, **kwargs):
super(UnrepeatedSequentialSampler, self).__init__(dataset, shuffle=False, seed=0, **kwargs)

def __iter__(self):


+ 0
- 5
fastNLP/core/utils/rich_progress.py View File

@@ -44,11 +44,6 @@ class DummyFRichProgress:
return True

class FRichProgress(Progress, metaclass=Singleton):
"""
fastNLP 使用的 progress bar ,新增了 new_progress 函数,通过此函数即可定制 fastNLP 中所有 progress 的样式。

"""

def new_progess(self, *columns: Union[str, ProgressColumn],
console: Optional[Console] = None,
auto_refresh: bool = True,


+ 8
- 4
fastNLP/envs/distributed.py View File

@@ -20,13 +20,17 @@ def is_cur_env_distributed() -> bool:
"""
单卡模式该函数一定返回 False;
注意进程 0 在多卡的训练模式下前后的值是不一样的,例如在开启多卡的 driver 之前,在进程 0 上的该函数返回 False;但是在开启后,在进程 0 上
的该函数返回的值是 True;
多卡模式下除了进程 0 外的其它进程返回的值一定是 True;
的该函数返回的值是 True;多卡模式下除了进程 0 外的其它进程返回的值一定是 True;
"""
return FASTNLP_GLOBAL_RANK in os.environ


def get_global_rank():
def get_global_rank()->int:
"""
获取当前进程的 global_rank 。

:return:
"""
return int(os.environ.get(FASTNLP_GLOBAL_RANK, 0))


@@ -64,7 +68,7 @@ def rank_zero_call(fn: Callable):
@contextmanager
def fastnlp_no_sync_context(level=2):
"""
用于让 fastNLP 的 barrier 以及 gather/broadcast等操作等同于只有1卡的多卡程序。如果为 1 表示 fastNLP 里的barrier 操作失效;
用于让 fastNLP 的 barrier 以及 gather/broadcast等操作等同于只有 1 卡的多卡程序。如果为 1 表示 fastNLP 里的barrier 操作失效;
如果为 2 表示 barrier 与 gather/broadcast 都失效。

:param int level: 可选 [0, 1, 2]


Loading…
Cancel
Save