Browse Source

修改了核心部分的一大部分文档,TODO:

1. 完善 trainer 和 tester 部分的文档
2. 研究注释样例与测试
tags/v0.4.10
ChenXin 6 years ago
parent
commit
257eb2b9eb
6 changed files with 500 additions and 427 deletions
  1. +15
    -1
      fastNLP/core/__init__.py
  2. +39
    -24
      fastNLP/core/batch.py
  3. +367
    -341
      fastNLP/core/dataset.py
  4. +48
    -34
      fastNLP/core/field.py
  5. +26
    -23
      fastNLP/core/instance.py
  6. +5
    -4
      fastNLP/core/vocabulary.py

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

@@ -1,6 +1,20 @@
"""
core 模块里实现了 fastNLP 的核心框架,常用的组件都可以从 fastNLP 包中直接 import。当然你也同样可以从 core 模块的子模块中 import,
例如 Batch 组件有两种 import 的方式::
# 直接从 fastNLP 中 import
from fastNLP import Batch
# 从 core 模块的子模块 batch 中 import
from fastNLP.core.batch import Batch

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


"""
from .batch import Batch
from .dataset import DataSet
from .fieldarray import FieldArray
from .field import FieldArray, Padder, AutoPadder, EngChar2DPadder
from .instance import Instance
from .losses import LossFunc, CrossEntropyLoss, L1Loss, BCELoss, NLLLoss, LossInForward
from .metrics import AccuracyMetric


+ 39
- 24
fastNLP/core/batch.py View File

@@ -1,24 +1,34 @@
"""
batch 模块实现了 fastNLP 所需的 Batch 类。

"""
__all__ = ["Batch"]
import numpy as np
import torch
import atexit

from fastNLP.core.sampler import RandomSampler, Sampler
from .sampler import RandomSampler, Sampler
import torch.multiprocessing as mp

_python_is_exit = False


def _set_python_is_exit():
global _python_is_exit
_python_is_exit = True


atexit.register(_set_python_is_exit)


class Batch(object):
"""

.. _Batch:
别名::class:`fastNLP.Batch` :class:`fastNLP.core.batch.Batch`

Batch 用于从 `DataSet` 中按一定的顺序, 依次按 ``batch_size`` 的大小将数据取出.
组成 `x` 和 `y`


Example::

batch = Batch(data_set, batch_size=16, sampler=SequentialSampler())
@@ -26,16 +36,19 @@ class Batch(object):
for batch_x, batch_y in batch:
# do stuff ...

:param DataSet dataset: `DataSet` 对象, 数据集
:param dataset: :class:`~fastNLP.DataSet` 对象, 数据集
:param int batch_size: 取出的batch大小
:param Sampler sampler: 规定使用的 Sample 方式. 若为 ``None`` , 使用 RandomSampler.
:param sampler: 规定使用的 :class:`~fastNLP.Sampler` 方式. 若为 ``None`` , 使用 :class:`~fastNLP.RandomSampler`.
Default: ``None``
:param bool as_numpy: 若为 ``True`` , 输出batch为 numpy.array. 否则为 torch.Tensor.
:param bool as_numpy: 若为 ``True`` , 输出batch为 numpy.array. 否则为 :class:`torch.Tensor`.
Default: ``False``
:param bool prefetch: 若为 ``True`` 使用多进程预先取出下一batch.
Default: ``False``
"""
def __init__(self, dataset, batch_size, sampler=None, as_numpy=False, prefetch=False):
self.dataset = dataset
self.batch_size = batch_size
@@ -49,17 +62,17 @@ class Batch(object):
self.cur_batch_indices = None
self.prefetch = prefetch
self.lengths = 0
def _fetch_one(self):
def fetch_one(self):
if self.curidx >= len(self.idx_list):
return None
else:
endidx = min(self.curidx + self.batch_size, len(self.idx_list))
batch_x, batch_y = {}, {}
indices = self.idx_list[self.curidx:endidx]
self.cur_batch_indices = indices
for field_name, field in self.dataset.get_all_fields().items():
if field.is_target or field.is_input:
batch = field.get(indices)
@@ -69,10 +82,10 @@ class Batch(object):
batch_y[field_name] = batch
if field.is_input:
batch_x[field_name] = batch
self.curidx = endidx
return batch_x, batch_y
def __iter__(self):
"""
Iterate on dataset, fetch batch data. Fetch process don't block the iterate process
@@ -80,25 +93,28 @@ class Batch(object):
"""
if self.prefetch:
return _run_batch_iter(self)
def batch_iter():
self._init_iter()
self.init_iter()
while 1:
res = self._fetch_one()
res = self.fetch_one()
if res is None:
break
yield res
return batch_iter()
def _init_iter(self):
def init_iter(self):
self.idx_list = self.sampler(self.dataset)
self.curidx = 0
self.lengths = self.dataset.get_length()
def __len__(self):
return self.num_batches
def get_batch_indices(self):
"""取得当前batch在DataSet中所在的index下标序列
"""
取得当前batch在DataSet中所在的index下标序列

:return list(int) indexes: 下标序列
"""
@@ -118,16 +134,16 @@ def _to_tensor(batch, dtype):

def _run_fetch(batch, q):
global _python_is_exit
batch._init_iter()
batch.init_iter()
# print('start fetch')
while 1:
res = batch._fetch_one()
res = batch.fetch_one()
# print('fetch one')
while 1:
try:
q.put(res, timeout=3)
break
except Exception as e:
except:
if _python_is_exit:
return
if res is None:
@@ -159,4 +175,3 @@ def _run_batch_iter(batch):
fetch_p.terminate()
fetch_p.join()
# print('iter done')


+ 367
- 341
fastNLP/core/dataset.py
File diff suppressed because it is too large
View File


fastNLP/core/fieldarray.py → fastNLP/core/field.py View File

@@ -1,7 +1,6 @@
"""
FieldArray是 DataSet_ 中一列的存储方式,原理部分请参考 DataSet_ 处

.. _FieldArray:
field模块实现了 FieldArray 和若干 Padder。 FieldArray 是 :class:`~fastNLP.DataSet` 中一列的存储方式,
原理部分请参考 :doc:`fastNLP.core.dataset`

"""

@@ -11,19 +10,21 @@ from copy import deepcopy


class FieldArray(object):
"""
别名::class:`fastNLP.FieldArray` :class:`fastNLP.core.field.FieldArray`

FieldArray 是用于保存 :class:`~fastNLP.DataSet` 中一个field的类型。
:param str name: FieldArray的名称
:param list,numpy.ndarray content: 列表的元素可以为list,int,float,
:param bool is_target: 这个field是否是一个target field。
:param bool is_input: 这个field是否是一个input field。
:param padder: :class:`~fastNLP.Padder` 类型。赋值给fieldarray的padder的对象会被deepcopy一份,需要修改padder参数必须通过
fieldarray.set_pad_val()。默认为None,即使用 :class:`~fastNLP.AutoPadder` 。
:param bool ignore_type: 是否忽略该field的type,一般如果这个field不需要转为torch.FloatTensor或torch.LongTensor,
就可以设置为True。具体意义请参考 :class:`~fastNLP.DataSet` 。
"""
def __init__(self, name, content, is_target=None, is_input=None, padder=None, ignore_type=False):
"""FieldArray是用于保存 DataSet_ 中一个field的实体。

:param str name: FieldArray的名称
:param list,numpy.ndarray content: 列表的元素可以为list,int,float,
:param bool is_target: 这个field是否是一个target field。
:param bool is_input: 这个field是否是一个input field。
:param Padder padder: PadderBase类型。赋值给fieldarray的padder的对象会被deepcopy一份,需要修改padder参数必须通过
fieldarray.set_pad_val()。默认为None,即使用 AutoPadder_ 。
:param bool ignore_type: 是否忽略该field的type,一般如果这个field不需要转为torch.FloatTensor或torch.LongTensor, 就
可以设置为True。具体意义请参考 DataSet_ 。
"""

self.name = name
if isinstance(content, list):
# 如果DataSet使用dict初始化, content 可能是二维list/二维array/三维list
@@ -87,14 +88,15 @@ class FieldArray(object):
@is_target.setter
def is_target(self, value):
"""
当 field_array.is_target = True / False 时被调用
当 field_array.is_target = True / False 时被调用
"""
if value is True:
self._set_dtype()
self._is_target = value

def _type_detection(self, content):
"""当该field被设置为is_input或者is_target时被调用
"""
当该field被设置为is_input或者is_target时被调用

"""
if len(content) == 0:
@@ -238,11 +240,12 @@ class FieldArray(object):
self.content[idx] = val

def get(self, indices, pad=True):
"""根据给定的indices返回内容
"""
根据给定的indices返回内容

:param int,list(int) indices:, 获取indices对应的内容。
:param bool pad: , 是否对返回的结果进行padding。仅对indices为List[int]时有效
:return: (single, List)
:param int,List[int] indices: 获取indices对应的内容。
:param bool pad: 是否对返回的结果进行padding。仅对indices为List[int]时有效
:return: 根据给定的indices返回的内容,可能是单个值或List
"""
if isinstance(indices, int):
return self.content[indices]
@@ -259,8 +262,7 @@ class FieldArray(object):
"""
设置padder,在这个field进行pad的时候用这个padder进行pad,如果为None则不进行pad。

:param None,Padder padder:. 设置为None即删除padder。
:return:
:param padder: :class:`~fastNLP.Padder` 类型,设置为None即删除padder。
"""
if padder is not None:
assert isinstance(padder, Padder), "padder must be of type Padder."
@@ -269,10 +271,10 @@ class FieldArray(object):
self.padder = None

def set_pad_val(self, pad_val):
"""修改padder的pad_val.
"""
修改padder的pad_val.

:param int pad_val: 该field的pad值设置为该值。
:return:
"""
if self.padder is not None:
self.padder.set_pad_val(pad_val)
@@ -280,7 +282,8 @@ class FieldArray(object):


def __len__(self):
"""Returns the size of FieldArray.
"""
Returns the size of FieldArray.

:return int length:
"""
@@ -288,10 +291,11 @@ class FieldArray(object):

def to(self, other):
"""
将other的属性复制给本FieldArray(other必须为FieldArray类型).属性包括 is_input, is_target, padder, ignore_type
将other的属性复制给本FieldArray(other必须为FieldArray类型).
属性包括 is_input, is_target, padder, ignore_type

:param FieldArray other: 从哪个field拷贝属性
:return: FieldArray
:param other: :class:`~fastNLP.FieldArray` 从哪个field拷贝属性
:return: :class:`~fastNLP.FieldArray`
"""
assert isinstance(other, FieldArray), "Only support FieldArray type, not {}.".format(type(other))

@@ -312,10 +316,20 @@ def _is_iterable(content):

class Padder:
"""
.. _Padder:
别名::class:`fastNLP.Padder` :class:`fastNLP.core.field.Padder`

所有padder都需要继承这个类,并覆盖__call__()方法。
用于对batch进行padding操作。传入的element是inplace的,即直接修改element可能导致数据变化,建议inplace修改之前deepcopy一份。
所有padder都需要继承这个类,并覆盖__call__方法。
用于对batch进行padding操作。传入的element是inplace的,即直接修改element可能导致数据变化,建议inplace修改之前deepcopy一份。
.. py:function:: __call__(self, contents, field_name, field_ele_dtype):
传入的是List内容。假设有以下的DataSet。
:param list(Any) contents: 传入的element是inplace的,即直接修改element可能导致数据变化,建议inplace修改之前
deepcopy一份。
:param str, field_name: field的名称。
:param np.int64,np.float64,np.str,None, field_ele_dtype: 该field的内层元素的类型。如果该field的ignore_type为True,该这个值为None。
:return: np.array([padded_element])
"""

def __init__(self, pad_val=0, **kwargs):
@@ -368,7 +382,7 @@ class Padder:

class AutoPadder(Padder):
"""
.. _AutoPadder:
别名::class:`fastNLP.AutoPadder` :class:`fastNLP.core.field.AutoPadder`

根据contents的数据自动判定是否需要做padding。

@@ -420,7 +434,7 @@ class AutoPadder(Padder):

class EngChar2DPadder(Padder):
"""
.. _EngChar2DPadder:
别名::class:`fastNLP.EngChar2DPadder` :class:`fastNLP.core.field.EngChar2DPadder`

用于为英语执行character级别的2D padding操作。对应的field内容应该类似[['T', 'h', 'i', 's'], ['a'], ['d', 'e', 'm', 'o']],
但这个Padder只能处理index为int的情况。

+ 26
- 23
fastNLP/core/instance.py View File

@@ -1,47 +1,50 @@
"""
Instance文档

.. _Instance:

Instance是fastNLP中对应于一个sample的类。一个sample可以认为是fastNLP中的一个Instance对象。一个具像化的表示类似与 DataSet_
出那个表中所展示的一行。
instance 模块实现了Instance 类在fastNLP中对应sample。一个sample可以认为是一个Instance类型的对象。
便于理解的例子可以参考文档 :doc:`fastNLP.core.dataset` 中的表格

"""
__all__ = ["Instance"]


class Instance(object):
"""
别名::class:`fastNLP.Instance` :class:`fastNLP.core.instance.Instance`

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

Example::
>>>from fastNLP import Instance
>>>ins = Instance(field_1=[1, 1, 1], field_2=[2, 2, 2])
>>>ins["field_1"]
[1, 1, 1]
>>>ins.add_field("field_3", [3, 3, 3])
>>>ins = Instance(**{'x1': 1, 'x2':np.zeros((3, 4))})
"""
def __init__(self, **fields):
"""Instance的初始化如下面的Example所示

Example::

ins = Instance(field_1=[1, 1, 1], field_2=[2, 2, 2])
ins["field_1"]
>>[1, 1, 1]
ins.add_field("field_3", [3, 3, 3])

ins = Instance(**{'x1': 1, 'x2':np.zeros((3, 4))})
"""
self.fields = fields

def add_field(self, field_name, field):
"""向Instance中增加一个field
"""
向Instance中增加一个field

:param str field_name: 新增field的名称
:param Any field: 新增field的内容
"""
self.fields[field_name] = field
def __getitem__(self, name):
if name in self.fields:
return self.fields[name]
else:
raise KeyError("{} not found".format(name))
def __setitem__(self, name, field):
return self.add_field(name, field)
def __repr__(self):
s = '\''
return "{" + ",\n".join(


+ 5
- 4
fastNLP/core/vocabulary.py View File

@@ -34,6 +34,8 @@ def _check_build_status(func):

class Vocabulary(object):
"""
别名::class:`fastNLP.Vocabulary` :class:`fastNLP.core.vocabulary.Vocabulary`
用于构建, 存储和使用 `str` 到 `int` 的一一映射

Example::
@@ -98,7 +100,7 @@ class Vocabulary(object):
"""
依次增加序列中词在词典中的出现频率

:param list(str) word_lst: 词的序列
:param list[str] word_lst: 词的序列
"""
self.update(word_lst)

@@ -185,12 +187,11 @@ class Vocabulary(object):
# remember to use `field_name`
vocab.index_dataset(train_data, dev_data, test_data, field_name='words')

:param DataSet datasets: 需要转index的 DataSet, 支持一个或多个
:param datasets: 需要转index的 class:`~fastNLP.DataSet` , 支持一个或多个(list)
:param str field_name: 需要转index的field, 若有多个 DataSet, 每个DataSet都必须有此 field.
目前仅支持 ``str`` , ``list(str)`` , ``list(list(str))``
:param str new_field_name: 保存结果的field_name. 若为 ``None`` , 将覆盖原field.
Default: ``None``
:return self:
"""
def index_instance(ins):
"""
@@ -230,7 +231,7 @@ class Vocabulary(object):
# remember to use `field_name`
vocab.from_dataset(train_data1, train_data2, field_name='words')

:param DataSet datasets: 需要转index的 DataSet, 支持一个或多个.
:param datasets: 需要转index的 class:`~fastNLP.DataSet` , 支持一个或多个(list)
:param field_name: 可为 ``str`` 或 ``list(str)`` .
构建词典所使用的 field(s), 支持一个或多个field
若有多个 DataSet, 每个DataSet都必须有这些field.


Loading…
Cancel
Save