Browse Source

Merge branch 'dev' of github.com:choosewhatulike/fastNLP-private into dev

tags/v0.4.10
yh_cc 5 years ago
parent
commit
6d4a945bb8
6 changed files with 170 additions and 55 deletions
  1. +44
    -8
      fastNLP/__init__.py
  2. +2
    -1
      fastNLP/core/__init__.py
  3. +81
    -11
      fastNLP/core/callback.py
  4. +4
    -1
      fastNLP/core/dataset.py
  5. +29
    -33
      fastNLP/core/trainer.py
  6. +10
    -1
      fastNLP/io/dataset_loader.py

+ 44
- 8
fastNLP/__init__.py View File

@@ -10,14 +10,50 @@ fastNLP 由 :mod:`~fastNLP.core` 、 :mod:`~fastNLP.io` 、:mod:`~fastNLP.module


fastNLP 中最常用的组件可以直接从 fastNLP 包中 import ,他们的文档如下: fastNLP 中最常用的组件可以直接从 fastNLP 包中 import ,他们的文档如下:
""" """
__all__ = ["Instance", "FieldArray", "Batch", "Vocabulary", "DataSet", "Const",
"Trainer", "Tester", "Callback",
"Padder", "AutoPadder", "EngChar2DPadder",
"AccuracyMetric", "BMESF1PreRecMetric", "SpanFPreRecMetric", "SQuADMetric",
"Optimizer", "SGD", "Adam",
"Sampler", "SequentialSampler", "BucketSampler", "RandomSampler",
"LossFunc", "CrossEntropyLoss", "L1Loss", "BCELoss", "NLLLoss", "LossInForward",
"cache_results"]
__all__ = [
"Instance",
"FieldArray",
"Batch",
"Vocabulary",
"DataSet",
"Const",
"Trainer",
"Tester",
"Callback",
"GradientClipCallback",
"EarlyStopCallback",
"TensorboardCallback",
"LRScheduler",
"ControlC",
"Padder",
"AutoPadder",
"EngChar2DPadder",
"AccuracyMetric",
"BMESF1PreRecMetric",
"SpanFPreRecMetric",
"SQuADMetric",
"Optimizer",
"SGD",
"Adam",
"Sampler",
"SequentialSampler",
"BucketSampler",
"RandomSampler",
"LossFunc",
"CrossEntropyLoss",
"L1Loss", "BCELoss",
"NLLLoss",
"LossInForward",
"cache_results"
]
from .core import * from .core import *
from . import models from . import models
from . import modules from . import modules


+ 2
- 1
fastNLP/core/__init__.py View File

@@ -10,10 +10,11 @@ core 模块里实现了 fastNLP 的核心框架,常用的组件都可以从 fa


对于常用的功能,你只需要在 :doc:`fastNLP` 中查看即可。如果想了解各个子模块的分工,您可以阅读以下文档: 对于常用的功能,你只需要在 :doc:`fastNLP` 中查看即可。如果想了解各个子模块的分工,您可以阅读以下文档:


TODO 向导


""" """
from .batch import Batch from .batch import Batch
from .callback import Callback
from .callback import Callback, GradientClipCallback, EarlyStopCallback, TensorboardCallback, LRScheduler, ControlC
from .const import Const from .const import Const
from .dataset import DataSet from .dataset import DataSet
from .field import FieldArray, Padder, AutoPadder, EngChar2DPadder from .field import FieldArray, Padder, AutoPadder, EngChar2DPadder


+ 81
- 11
fastNLP/core/callback.py View File

@@ -1,7 +1,62 @@
"""
callback模块实现了 fastNLP 中的Callback类,用于增强 :class:`~fastNLP.Trainer` 类,
r"""
callback模块实现了 fastNLP 中的许多 callback 类,用于增强 :class:`~fastNLP.Trainer` 类,

我们将 :meth:`~fastNLP.Train.train` 这个函数内部分为以下的阶段,在对应阶段会触发相应的调用::

callback.on_train_begin() # 开始进行训练
for i in range(1, n_epochs+1):
callback.on_epoch_begin() # 开始新的epoch
for batch_x, batch_y in Batch:
callback.on_batch_begin(batch_x, batch_y, indices) # batch_x是设置为input的field,batch_y是设置为target的field
获取模型输出
callback.on_loss_begin()
计算loss
callback.on_backward_begin() # 可以进行一些检查,比如loss是否为None
反向梯度回传
callback.on_backward_end() # 进行梯度截断等
进行参数更新
callback.on_step_end()
callback.on_batch_end()
# 根据设置进行evaluation,比如这是本epoch最后一个batch或者达到一定step
if do evaluation:
callback.on_valid_begin()
进行dev data上的验证
callback.on_valid_end() # 可以进行在其它数据集上进行验证
callback.on_epoch_end() # epoch结束调用
callback.on_train_end() # 训练结束
callback.on_exception() # 这是一个特殊的步骤,在训练过程中遭遇exception会跳转到这里

关于Trainer的详细文档,请参见 :doc:`trainer 模块<fastNLP.core.trainer>` 关于Trainer的详细文档,请参见 :doc:`trainer 模块<fastNLP.core.trainer>`

如下面的例子所示,我们可以使用内置的 callback 类,或者继承 :class:`~fastNLP.core.callback.Callback`
定义自己的 callback 类::
from fastNLP import Callback, EarlyStopCallback, Trainer, CrossEntropyLoss, AccuracyMetric
from fastNLP.models import CNNText
start_time = time.time()
class MyCallback(Callback):
def on_epoch_end(self):
print('{:d}ms\n\n'.format(round((time.time()-start_time)*1000)))
model = CNNText((len(vocab),50), num_classes=5, padding=2, dropout=0.1)
trainer = Trainer(model=model, train_data=train_data, dev_data=dev_data, loss=CrossEntropyLoss(),
metrics=AccuracyMetric(), callbacks=[MyCallback(),EarlyStopCallback(10)])
trainer.train()

""" """
__all__ = [
"Callback",
"GradientClipCallback",
"EarlyStopCallback",
"TensorboardCallback",
"LRScheduler",
"ControlC",
"CallbackException",
"EarlyStopError"
]
import os import os
import torch import torch
from ..io.model_io import ModelSaver, ModelLoader from ..io.model_io import ModelSaver, ModelLoader
@@ -19,7 +74,7 @@ class Callback(object):
Callback是fastNLP中被设计用于增强 :class:`~fastNLP.Trainer` 的类。 Callback是fastNLP中被设计用于增强 :class:`~fastNLP.Trainer` 的类。
如果Callback被传递给了 Trainer , 则 Trainer 会在对应的阶段调用Callback的函数, 如果Callback被传递给了 Trainer , 则 Trainer 会在对应的阶段调用Callback的函数,
具体调用时机可以通过 :doc:`trainer 模块<fastNLP.core.trainer>` 查看。 具体调用时机可以通过 :doc:`trainer 模块<fastNLP.core.trainer>` 查看。
这是Callback的基类,所有的callback必须继承自这个类(参见 :doc:`callback 模块 <fastNLP.core.callback>` )
这是Callback的基类,所有的callback必须继承自这个类


""" """
@@ -236,7 +291,7 @@ class CallbackManager(Callback):
for env_name, env_val in env.items(): for env_name, env_val in env.items():
for callback in self.callbacks: for callback in self.callbacks:
print(callback, env_name, env_val )
print(callback, env_name, env_val)
setattr(callback, '_' + env_name, env_val) # Callback.trainer setattr(callback, '_' + env_name, env_val) # Callback.trainer
@_transfer @_transfer
@@ -294,12 +349,15 @@ class CallbackManager(Callback):


class GradientClipCallback(Callback): class GradientClipCallback(Callback):
""" """
别名::class:`fastNLP.GradientClipCallback` :class:`fastNLP.core.callback.GradientClipCallback`

每次backward前,将parameter的gradient clip到某个范围。 每次backward前,将parameter的gradient clip到某个范围。


:param None,torch.Tensor,List[torch.Tensor] parameters: 一般通过model.parameters()获得。如果为None则默认对Trainer :param None,torch.Tensor,List[torch.Tensor] parameters: 一般通过model.parameters()获得。如果为None则默认对Trainer
的model中所有参数进行clip 的model中所有参数进行clip
:param float clip_value: 将gradient 限制到[-clip_value, clip_value]。clip_value应该为正数 :param float clip_value: 将gradient 限制到[-clip_value, clip_value]。clip_value应该为正数
:param str clip_type: 支持'norm', 'value'两种::
:param str clip_type: 支持'norm', 'value'
两种::


1 'norm', 将gradient的norm rescale到[-clip_value, clip_value] 1 'norm', 将gradient的norm rescale到[-clip_value, clip_value]
@@ -331,8 +389,11 @@ class GradientClipCallback(Callback):


class EarlyStopCallback(Callback): class EarlyStopCallback(Callback):
""" """
别名::class:`fastNLP.EarlyStopCallback` :class:`fastNLP.core.callback.EarlyStopCallback`
多少个epoch没有变好就停止训练,相关类 :class:`EarlyStopError`


:param int patience: 多少个epoch没有变好就停止训练
:param int patience: epoch的数量
""" """
def __init__(self, patience): def __init__(self, patience):
@@ -358,11 +419,10 @@ class EarlyStopCallback(Callback):




class LRScheduler(Callback): class LRScheduler(Callback):
"""对PyTorch LR Scheduler的包装以使得其可以被Trainer所使用

Example::
"""
别名::class:`fastNLP.LRScheduler` :class:`fastNLP.core.callback.LRScheduler`


from fastNLP import LRScheduler
对PyTorch LR Scheduler的包装以使得其可以被Trainer所使用


:param torch.optim.lr_scheduler._LRScheduler lr_scheduler: PyTorch的lr_scheduler :param torch.optim.lr_scheduler._LRScheduler lr_scheduler: PyTorch的lr_scheduler
""" """
@@ -382,6 +442,7 @@ class LRScheduler(Callback):


class ControlC(Callback): class ControlC(Callback):
""" """
别名::class:`fastNLP.ControlC` :class:`fastNLP.core.callback.ControlC`


:param bool quit_all: 若为True,则检测到control+C 直接退出程序;否则只退出Trainer :param bool quit_all: 若为True,则检测到control+C 直接退出程序;否则只退出Trainer
""" """
@@ -418,6 +479,8 @@ class SmoothValue(object):


class LRFinder(Callback): class LRFinder(Callback):
""" """
别名::class:`fastNLP.LRFinder` :class:`fastNLP.core.callback.LRFinder`

用第一个 epoch 找最佳的学习率,从第二个epoch开始应用它 用第一个 epoch 找最佳的学习率,从第二个epoch开始应用它


:param float start_lr: 学习率下界 :param float start_lr: 学习率下界
@@ -442,7 +505,7 @@ class LRFinder(Callback):
def lr_gen(self): def lr_gen(self):
scale = (self.end_lr - self.start_lr) / self.batch_per_epoch scale = (self.end_lr - self.start_lr) / self.batch_per_epoch
return (self.start_lr + scale * (step + 1) for step in range(self.batch_per_epoch)) return (self.start_lr + scale * (step + 1) for step in range(self.batch_per_epoch))
@property @property
def num_it(self): def num_it(self):
return self.batch_per_epoch return self.batch_per_epoch
@@ -487,10 +550,17 @@ class LRFinder(Callback):


class TensorboardCallback(Callback): class TensorboardCallback(Callback):
""" """
别名::class:`fastNLP.TensorboardCallback` :class:`fastNLP.core.callback.TensorboardCallback`

接受以下一个或多个字符串作为参数: 接受以下一个或多个字符串作为参数:
- "model" - "model"
- "loss" - "loss"
- "metric" - "metric"
.. warning::
fastNLP 已停止对此功能的维护,请等待 fastNLP 兼容 PyTorch1.1 的下一个版本。
或者使用和 fastNLP 高度配合的 fitlog(参见 :doc:`/user/with_fitlog` )。
""" """
def __init__(self, *options): def __init__(self, *options):


+ 4
- 1
fastNLP/core/dataset.py View File

@@ -798,7 +798,10 @@ class DataSet(object):
@classmethod @classmethod
def read_csv(cls, csv_path, headers=None, sep=",", dropna=True): def read_csv(cls, csv_path, headers=None, sep=",", dropna=True):
""" """
从csv_path路径下以csv的格式读取数据.
.. warning::
此方法会在下个版本移除,请使用 :class:`fastNLP.io.CSVLoader`
从csv_path路径下以csv的格式读取数据。


:param str csv_path: 从哪里读取csv文件 :param str csv_path: 从哪里读取csv文件
:param list[str] headers: 如果为None,则使用csv文件的第一行作为header; 如果传入list(str), 则元素的个数必须 :param list[str] headers: 如果为None,则使用csv文件的第一行作为header; 如果传入list(str), 则元素的个数必须


+ 29
- 33
fastNLP/core/trainer.py View File

@@ -1,4 +1,4 @@
"""
r"""
Trainer在fastNLP中用于组织单任务的训练过程,可以避免用户在不同训练任务中重复撰以下步骤的代码 Trainer在fastNLP中用于组织单任务的训练过程,可以避免用户在不同训练任务中重复撰以下步骤的代码


(1) epoch循环; (1) epoch循环;
@@ -93,7 +93,10 @@ Trainer在fastNLP中用于组织单任务的训练过程,可以避免用户在
尽管fastNLP使用了映射机制来使得loss的计算变得比较灵活,但有些情况下loss必须在模型中进行计算,比如使用了CRF的模型。 尽管fastNLP使用了映射机制来使得loss的计算变得比较灵活,但有些情况下loss必须在模型中进行计算,比如使用了CRF的模型。
fastNLP中提供了 :class:`~fastNLP.LossInForward` 这个loss。 fastNLP中提供了 :class:`~fastNLP.LossInForward` 这个loss。
这个loss的原理是直接在forward()的返回结果中找到loss_key(默认寻找'loss')指定的那个tensor,并使用它作为loss。 这个loss的原理是直接在forward()的返回结果中找到loss_key(默认寻找'loss')指定的那个tensor,并使用它作为loss。
如果Trainer初始化没有提供loss则默认使用 :class:`~fastNLP.LossInForward` 。TODO 补充一个例子 详细例子可以参照
如果Trainer初始化没有提供loss则默认使用 :class:`~fastNLP.LossInForward` 。
.. todo::
补充一个例子 详细例子可以参照


1.3 Metric 1.3 Metric
:mod:`Metric<fastNLP.core.metrics>` 使用了与上述Loss一样的策略,即使用名称进行匹配。 :mod:`Metric<fastNLP.core.metrics>` 使用了与上述Loss一样的策略,即使用名称进行匹配。
@@ -102,7 +105,10 @@ Trainer在fastNLP中用于组织单任务的训练过程,可以避免用户在
在进行验证时,可能用到的计算与forward()中不太一致,没有办法直接从forward()的结果中得到预测值,这时模型可以提供一个predict()方法, 在进行验证时,可能用到的计算与forward()中不太一致,没有办法直接从forward()的结果中得到预测值,这时模型可以提供一个predict()方法,
如果提供的模型具有predict方法,则在模型验证时将调用predict()方法获取预测结果, 如果提供的模型具有predict方法,则在模型验证时将调用predict()方法获取预测结果,
传入到predict()的参数也是从DataSet中被设置为input的field中选择出来的; 传入到predict()的参数也是从DataSet中被设置为input的field中选择出来的;
与forward()一样,返回值需要为一个dict。 TODO 补充一个例子 具体例子可以参考
与forward()一样,返回值需要为一个dict。
.. todo::
补充一个例子 具体例子可以参考


2 Trainer的代码检查 2 Trainer的代码检查
由于在fastNLP中采取了映射的机制,所以难免可能存在对应出错的情况。Trainer提供一种映射检查机制,可以通过check_code_level来进行控制 由于在fastNLP中采取了映射的机制,所以难免可能存在对应出错的情况。Trainer提供一种映射检查机制,可以通过check_code_level来进行控制
@@ -267,37 +273,26 @@ Example2.3
虽然Trainer本身已经集成了一些功能,但仍然不足以囊括训练过程中可能需要到的功能,比如负采样,learning rate decay, Early Stop等。 虽然Trainer本身已经集成了一些功能,但仍然不足以囊括训练过程中可能需要到的功能,比如负采样,learning rate decay, Early Stop等。
为了解决这个问题fastNLP引入了callback的机制,:class:`~fastNLP.Callback` 是一种在Trainer训练过程中特定阶段会运行的函数集合, 为了解决这个问题fastNLP引入了callback的机制,:class:`~fastNLP.Callback` 是一种在Trainer训练过程中特定阶段会运行的函数集合,
所有的 :class:`~fastNLP.Callback` 都具有on_*(比如on_train_start, on_backward_begin)等函数。 所有的 :class:`~fastNLP.Callback` 都具有on_*(比如on_train_start, on_backward_begin)等函数。
如果 Callback 实现了该函数,则Trainer运行至对应阶段,会进行调用。

我们将Train.train()这个函数内部分为以下的阶段,在对应阶段会触发相应的调用。

Example::
如果 Callback 实现了该函数,则Trainer运行至对应阶段,会进行调用,例如::
from fastNLP import Callback, EarlyStopCallback, Trainer, CrossEntropyLoss, AccuracyMetric
from fastNLP.models import CNNText


callback.on_train_begin() # 开始进行训练
for i in range(1, n_epochs+1):
callback.on_epoch_begin() # 开始新的epoch
for batch_x, batch_y in Batch:
callback.on_batch_begin(batch_x, batch_y, indices) # batch_x是设置为input的field,batch_y是设置为target的field
获取模型输出
callback.on_loss_begin()
计算loss
callback.on_backward_begin() # 可以进行一些检查,比如loss是否为None
反向梯度回传
callback.on_backward_end() # 进行梯度截断等
进行参数更新
callback.on_step_end()
callback.on_batch_end()
# 根据设置进行evaluation,比如这是本epoch最后一个batch或者达到一定step
if do evaluation:
callback.on_valid_begin()
进行dev data上的验证
callback.on_valid_end() # 可以进行在其它数据集上进行验证
callback.on_epoch_end() # epoch结束调用
callback.on_train_end() # 训练结束
callback.on_exception() # 这是一个特殊的步骤,在训练过程中遭遇exception会跳转到这里

fastNLP已经自带了很多callback函数供使用,可以参考 :class:`~fastNLP.Callback` 。
TODO callback的例子 一些关于callback的例子,请参考
start_time = time.time()
class MyCallback(Callback):
def on_epoch_end(self):
print('{:d}ms\n\n'.format(round((time.time()-start_time)*1000)))
model = CNNText((len(vocab),50), num_classes=5, padding=2, dropout=0.1)
trainer = Trainer(model=model, train_data=train_data, dev_data=dev_data, loss=CrossEntropyLoss(),
metrics=AccuracyMetric(), callbacks=[MyCallback(),EarlyStopCallback(10)])
trainer.train()
这里,我们通过继承 :class:`~fastNLP.Callback` 类定义了自己的 callback 的,并和内置的 :class:`~fastNLP.EarlyStopCallback`
一起传给了 :class:`~fastNLP.Trainer` ,增强了 :class:`~fastNLP.Trainer` 的功能
fastNLP已经自带了很多callback函数供使用,可以参考 :doc:`fastNLP.core.callback` 。


""" """


@@ -445,6 +440,7 @@ class Trainer(object):
_check_code(dataset=train_data, model=model, losser=losser, metrics=metrics, dev_data=dev_data, _check_code(dataset=train_data, model=model, losser=losser, metrics=metrics, dev_data=dev_data,
metric_key=metric_key, check_level=check_code_level, metric_key=metric_key, check_level=check_code_level,
batch_size=min(batch_size, DEFAULT_CHECK_BATCH_SIZE)) batch_size=min(batch_size, DEFAULT_CHECK_BATCH_SIZE))
# _check_code 是 fastNLP 帮助你检查代码是否正确的方法 。如果你在错误栈中看到这行注释,请认真检查你的代码
self.train_data = train_data self.train_data = train_data
self.dev_data = dev_data # If None, No validation. self.dev_data = dev_data # If None, No validation.


+ 10
- 1
fastNLP/io/dataset_loader.py View File

@@ -11,7 +11,16 @@ Example::


# ... do stuff # ... do stuff
""" """

__all__ = [
'DataSetLoader',
'CSVLoader',
'JsonLoader',
'ConllLoader',
'SNLILoader',
'SSTLoader',
'PeopleDailyCorpusLoader',
'Conll2003Loader',
]
from nltk.tree import Tree from nltk.tree import Tree


from ..core.dataset import DataSet from ..core.dataset import DataSet


Loading…
Cancel
Save