@@ -375,4 +375,4 @@ fastNLP提供了Trainer对象来组织训练过程,包括完成loss计算(所 | |||
.. raw:: html | |||
<a href="../_static/notebooks/%E6%96%87%E6%9C%AC%E5%88%86%E7%B1%BB.ipynb" download="文本分类.ipynb">点击下载 IPython Notebook 文件 </a> | |||
<a href="../_static/notebooks/%E6%96%87%E6%9C%AC%E5%88%86%E7%B1%BB.ipynb" download="文本分类.ipynb">点击下载 IPython Notebook 文件 </a><hr> |
@@ -154,3 +154,9 @@ csv 表格 | |||
:meth:`fastNLP.DataSet.apply` | |||
下面这个代码是不可行的,必须要用 r""" 才行: | |||
.. code:: | |||
: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,则召回率权重高于精确率。 | |||
@@ -44,7 +44,7 @@ __all__ = [ | |||
"AutoPadder", | |||
"EngChar2DPadder", | |||
"CollectFn", | |||
# "CollectFn", | |||
"ConcatCollectFn", | |||
"MetricBase", | |||
@@ -260,51 +260,51 @@ class DataSetIter(BatchIter): | |||
class TorchLoaderIter(BatchIter): | |||
""" | |||
与DataSetIter类似,但可以用于非fastNLP的数据容器对象,然后将其传入到Trainer中。 | |||
只需要保证数据容器实现了实现了以下的方法 | |||
只需要保证数据容器实现了实现了以下的方法 | |||
Example:: | |||
import random | |||
from fastNLP import TorchLoaderIter | |||
import torch | |||
class UdfDataSet: | |||
def __init__(self, num_samples): | |||
self.num_samples = num_samples | |||
def __getitem__(self, idx): # 必须实现的方法,输入参数是一个int,范围为[0, len(self)) | |||
x = [random.random() for _ in range(3)] | |||
y = random.random() | |||
return x,y | |||
def __len__(self): # 需要实现该方法返回值需要是一个int数据 | |||
return self.num_samples | |||
# 需要实现collact_fn将数据转换为tensor | |||
def collact_fn(data_list): | |||
# [(x1,y1), (x2,y2), ...], 这里的输入实际上是将UdfDataSet的__getitem__输入结合为list | |||
xs, ys = [], [] | |||
for l in data_list: | |||
x, y = l | |||
xs.append(x) | |||
ys.append(y) | |||
# 不需要转移到gpu,Trainer或Tester会将其转移到model所在的device | |||
x,y = torch.FloatTensor(xs), torch.FloatTensor(ys) | |||
return {'x':x, 'y':y}, {'y':y} | |||
Example:: | |||
udf_dataset = UdfDataSet(10) | |||
dataset = TorchLoaderIter(udf_dataset, collate_fn=collact_fn) | |||
class Model(nn.Module): | |||
def __init__(self): | |||
super().__init__() | |||
self.fc = nn.Linear(3, 1) | |||
def forward(self, x, y): | |||
return {'loss':torch.pow(self.fc(x).squeeze(-1)-y, 2).sum()} | |||
def predict(self, x): | |||
return {'pred':self.fc(x).squeeze(0)} | |||
model = Model() | |||
trainer = Trainer(train_data=dataset, model=model, loss=None, print_every=2, dev_data=dataset, | |||
metrics=AccuracyMetric(target='y'), use_tqdm=False) | |||
trainer.train(load_best_model=False) | |||
import random | |||
from fastNLP import TorchLoaderIter | |||
import torch | |||
class UdfDataSet: | |||
def __init__(self, num_samples): | |||
self.num_samples = num_samples | |||
def __getitem__(self, idx): # 必须实现的方法,输入参数是一个int,范围为[0, len(self)) | |||
x = [random.random() for _ in range(3)] | |||
y = random.random() | |||
return x,y | |||
def __len__(self): # 需要实现该方法返回值需要是一个int数据 | |||
return self.num_samples | |||
# 需要实现collact_fn将数据转换为tensor | |||
def collact_fn(data_list): | |||
# [(x1,y1), (x2,y2), ...], 这里的输入实际上是将UdfDataSet的__getitem__输入结合为list | |||
xs, ys = [], [] | |||
for l in data_list: | |||
x, y = l | |||
xs.append(x) | |||
ys.append(y) | |||
# 不需要转移到gpu,Trainer或Tester会将其转移到model所在的device | |||
x,y = torch.FloatTensor(xs), torch.FloatTensor(ys) | |||
return {'x':x, 'y':y}, {'y':y} | |||
udf_dataset = UdfDataSet(10) | |||
dataset = TorchLoaderIter(udf_dataset, collate_fn=collact_fn) | |||
class Model(nn.Module): | |||
def __init__(self): | |||
super().__init__() | |||
self.fc = nn.Linear(3, 1) | |||
def forward(self, x, y): | |||
return {'loss':torch.pow(self.fc(x).squeeze(-1)-y, 2).sum()} | |||
def predict(self, x): | |||
return {'pred':self.fc(x).squeeze(0)} | |||
model = Model() | |||
trainer = Trainer(train_data=dataset, model=model, loss=None, print_every=2, dev_data=dataset, | |||
metrics=AccuracyMetric(target='y'), use_tqdm=False) | |||
trainer.train(load_best_model=False) | |||
除此之外,还可以通过该方法实现OnTheFly的训练,如下面的代码所示 | |||
@@ -321,7 +321,7 @@ class TorchLoaderIter(BatchIter): | |||
data.append(x + [y]) | |||
with open(tmp_file_path, 'w') as f: | |||
for d in data: | |||
f.write(' '.join(map(str, d)) + '\n') | |||
f.write(' '.join(map(str, d)) + '\\n') | |||
class FileDataSet: | |||
def __init__(self, tmp_file): | |||
@@ -382,6 +382,7 @@ class TorchLoaderIter(BatchIter): | |||
import os | |||
if os.path.exists(tmp_file_path): | |||
os.remove(tmp_file_path) | |||
""" | |||
def __init__(self, dataset, batch_size=1, sampler=None, | |||
num_workers=0, pin_memory=False, drop_last=False, | |||
@@ -391,7 +392,6 @@ class TorchLoaderIter(BatchIter): | |||
:param dataset: :class:`~fastNLP.DataSet` 对象, 数据集 | |||
:param int batch_size: 取出的batch大小 | |||
:param sampler: 规定使用的 :class:`~fastNLP.Sampler` 方式. 若为 ``None`` , 使用 :class:`~fastNLP.SequentialSampler`. | |||
Default: ``None`` | |||
:param int num_workers: 使用多少个进程来预处理数据 | |||
:param bool pin_memory: 是否将产生的tensor使用pin memory, 可能会加快速度。 | |||
@@ -806,7 +806,7 @@ class TensorboardCallback(Callback): | |||
.. warning:: | |||
fastNLP 已停止对此功能的维护,请等待 fastNLP 兼容 PyTorch1.1 的下一个版本。 | |||
或者使用和 fastNLP 高度配合的 fitlog(参见 :doc:`/tutorials/tutorial_11_fitlog` )。 | |||
或者使用和 fastNLP 高度配合的 fitlog(参见 :doc:`/tutorials/extend_2_fitlog` )。 | |||
""" | |||
@@ -282,7 +282,7 @@ | |||
dataset.set_pad_val('chars', -1) | |||
3.3 根据DataSet中多个field合成新的field | |||
-------------------------------------- | |||
------------------------------------------------------------ | |||
DataSet支持在进行batch时,默认只能看到当前的field的值,但在某些训练中可能存在以下的情况: (1)需要两个field拼接成为一个field; | |||
(2)需要在batch中进行负采样。这时候就需要能够同时利用多个field进行batch的操作,DataSet中的add_collect_fn()函数支持添加 | |||
@@ -282,21 +282,31 @@ class MetricBase(object): | |||
class ConfusionMatrixMetric(MetricBase): | |||
r""" | |||
分类问题计算混淆矩阵的Metric(其它的Metric参见 :mod:`fastNLP.core.metrics` ) | |||
最后返回结果为dict,{'confusion_matrix': ConfusionMatrix实例} | |||
最后返回结果为:: | |||
dict,{'confusion_matrix': ConfusionMatrix实例} | |||
ConfusionMatrix实例的print()函数将输出矩阵字符串。 | |||
pred_dict = {"pred": torch.Tensor([2,1,3])} | |||
target_dict = {'target': torch.Tensor([2,2,1])} | |||
metric = ConfusionMatrixMetric() | |||
metric(pred_dict=pred_dict, target_dict=target_dict, ) | |||
print(metric.get_metric()) | |||
{'confusion_matrix': | |||
target 1.0 2.0 3.0 all | |||
pred | |||
1.0 0 1 0 1 | |||
2.0 0 1 0 1 | |||
3.0 1 0 0 1 | |||
all 1 2 0 3 | |||
} | |||
.. code :: | |||
pred_dict = {"pred": torch.Tensor([2,1,3])} | |||
target_dict = {'target': torch.Tensor([2,2,1])} | |||
metric = ConfusionMatrixMetric() | |||
metric(pred_dict=pred_dict, target_dict=target_dict, ) | |||
print(metric.get_metric()) | |||
.. code :: | |||
{'confusion_matrix': | |||
target 1.0 2.0 3.0 all | |||
pred | |||
1.0 0 1 0 1 | |||
2.0 0 1 0 1 | |||
3.0 1 0 0 1 | |||
all 1 2 0 3 | |||
} | |||
""" | |||
def __init__(self, | |||
vocab=None, | |||
@@ -322,12 +332,12 @@ class ConfusionMatrixMetric(MetricBase): | |||
def evaluate(self, pred, target, seq_len=None): | |||
""" | |||
evaluate函数将针对一个批次的预测结果做评价指标的累计 | |||
:param torch.Tensor pred: 预测的tensor, tensor的形状可以是torch.Size([B,]), torch.Size([B, n_classes]), | |||
torch.Size([B, max_len]), 或者torch.Size([B, max_len, n_classes]) | |||
torch.Size([B, max_len]), 或者torch.Size([B, max_len, n_classes]) | |||
:param torch.Tensor target: 真实值的tensor, tensor的形状可以是Element's can be: torch.Size([B,]), | |||
torch.Size([B,]), torch.Size([B, max_len]), 或者torch.Size([B, max_len]) | |||
torch.Size([B,]), torch.Size([B, max_len]), 或者torch.Size([B, max_len]) | |||
:param torch.Tensor seq_len: 序列长度标记, 标记的形状可以是None, torch.Size([B]), 或者torch.Size([B]). | |||
""" | |||
if not isinstance(pred, torch.Tensor): | |||
raise TypeError( | |||
@@ -489,11 +499,12 @@ class ClassifyFPreRecMetric(MetricBase): | |||
'rec-label':xxx, | |||
... | |||
} | |||
""" | |||
def __init__(self, tag_vocab=None, pred=None, target=None, seq_len=None, ignore_labels=None, | |||
only_gross=True, f_type='micro', beta=1): | |||
""" | |||
r""" | |||
:param tag_vocab: 标签的 :class:`~fastNLP.Vocabulary` . 默认值为None。若为None则使用数字来作为标签内容,否则使用vocab来作为标签内容。 | |||
:param str pred: 用该key在evaluate()时从传入dict中取出prediction数据。 为None,则使用 `pred` 取数据 | |||
@@ -504,6 +515,7 @@ class ClassifyFPreRecMetric(MetricBase): | |||
: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,则召回率权重高于精确率。 | |||
""" | |||
if tag_vocab: | |||
if not isinstance(tag_vocab, Vocabulary): | |||
raise TypeError("tag_vocab can only be fastNLP.Vocabulary, not {}.".format(type(tag_vocab))) | |||
@@ -355,6 +355,7 @@ from .utils import _move_model_to_device | |||
from ._parallel_utils import _model_contains_inner_module | |||
from ._logger import logger | |||
class Trainer(object): | |||
""" | |||
Trainer在fastNLP中用于组织单任务的训练过程,可以避免用户在不同训练任务中重复撰写 | |||
@@ -373,9 +374,8 @@ class Trainer(object): | |||
dev_data=None, metrics=None, metric_key=None, | |||
validate_every=-1, save_path=None, use_tqdm=True, device=None, | |||
callbacks=None, check_code_level=0, **kwargs): | |||
""" | |||
:param train_data: 训练集, :class:`~fastNLP.DataSet` 类型或 :class:`~fastNLP.BatchIter`的子类 | |||
r""" | |||
:param train_data: 训练集, :class:`~fastNLP.DataSet` 类型或 :class:`~fastNLP.BatchIter` 的子类 | |||
:param nn.modules model: 待训练的模型 | |||
:param optimizer: `torch.optim.Optimizer` 优化器。如果为None,则Trainer使用默认的Adam(model.parameters(), lr=4e-3)这个优化器 | |||
:param int batch_size: 训练和验证的时候的batch大小。 | |||
@@ -26,6 +26,9 @@ class ElmoEmbedding(ContextualEmbedding): | |||
""" | |||
使用ELMo的embedding。初始化之后,只需要传入words就可以得到对应的embedding。 | |||
当前支持的使用名称初始化的模型: | |||
.. code:: | |||
en: 即en-medium hidden_size 1024; output_size 12 | |||
en-medium: hidden_size 2048; output_size 256 | |||
en-origial: hidden_size 4096; output_size 512 | |||
@@ -27,6 +27,9 @@ class StaticEmbedding(TokenEmbedding): | |||
StaticEmbedding组件. 给定预训练embedding的名称或路径,根据vocab从embedding中抽取相应的数据(只会将出现在vocab中的词抽取出来, | |||
如果没有找到,则会随机初始化一个值(但如果该word是被标记为no_create_entry的话,则不会单独创建一个值,而是会被指向unk的index))。 | |||
当前支持自动下载的预训练vector有: | |||
.. code:: | |||
en: 实际为en-glove-840b-300d(常用) | |||
en-glove-6b-50d: glove官方的50d向量 | |||
en-glove-6b-100d: glove官方的100d向量 | |||
@@ -88,8 +91,7 @@ class StaticEmbedding(TokenEmbedding): | |||
:param dict kwargs: | |||
bool only_train_min_freq: 仅对train中的词语使用min_freq筛选; | |||
bool only_norm_found_vector: 是否仅对在预训练中找到的词语使用normalize; | |||
bool only_use_pretrain_word: 仅使用出现在pretrain词表中的词,如果该词没有在预训练的词表中出现则为unk。如果 | |||
embedding不需要更新建议设置为True。 | |||
bool only_use_pretrain_word: 仅使用出现在pretrain词表中的词,如果该词没有在预训练的词表中出现则为unk。如果embedding不需要更新建议设置为True。 | |||
""" | |||
super(StaticEmbedding, self).__init__(vocab, word_dropout=word_dropout, dropout=dropout) | |||
if embedding_dim > 0: | |||
@@ -227,7 +227,7 @@ class OntoNotesNERLoader(ConllLoader): | |||
:header: "raw_words", "target" | |||
"['Hi', 'everyone', '.']", "['O', 'O', 'O']" | |||
"['first', 'up', 'on', 'the', 'docket'], "['O', 'O', 'O', 'O', 'O']" | |||
"['first', 'up', 'on', 'the', 'docket']", "['O', 'O', 'O', 'O', 'O']" | |||
"[...]", "[...]" | |||
""" | |||
@@ -29,10 +29,10 @@ class CMRC2018Loader(Loader): | |||
验证集DataSet将具备以下的内容,每个问题的答案可能有三个(有时候只是3个重复的答案) | |||
.. csv-table:: | |||
:header:"title", "context", "question", "answers", "answer_starts", "id" | |||
:header: "title", "context", "question", "answers", "answer_starts", "id" | |||
"战国无双3", "《战国无双3》()是由光荣和ω-force开发...", "《战国无双3》是由哪两个公司合作开发的?", ["光荣和ω-force", "光荣和ω-force", "光荣和ω-force"], ["30", "30", "30"], "DEV_0_QUERY_0" | |||
"战国无双3", "《战国无双3》()是由光荣和ω-force开发...", "男女主角亦有专属声优这一模式是由谁改编的?", ["村雨城", "村雨城", "任天堂游戏谜之村雨城"], ["226", "226", "219"], "DEV_0_QUERY_1" | |||
"战国无双3", "《战国无双3》()是由光荣和ω-force开发...", "《战国无双3》是由哪两个公司合作开发的?", "['光荣和ω-force', '光荣和ω-force', '光荣和ω-force']", "[30, 30, 30]", "DEV_0_QUERY_0" | |||
"战国无双3", "《战国无双3》()是由光荣和ω-force开发...", "男女主角亦有专属声优这一模式是由谁改编的?", "['村雨城', '村雨城', '任天堂游戏谜之村雨城']", "[226, 226, 219]", "DEV_0_QUERY_1" | |||
"...", "...", "...","...", ".", "..." | |||
其中answer_starts是从0开始的index。例如"我来自a复旦大学?",其中"复"的开始index为4。另外"Russell评价说"中的说的index为9, 因为 | |||
@@ -83,15 +83,19 @@ class CMRC2018BertPipe(Pipe): | |||
.. csv-table:: | |||
:header: "context_len", "raw_chars", "target_start", "target_end", "chars" | |||
492, ['范', '廷', '颂... ], 30, 34, [21, 25, ...] | |||
491, ['范', '廷', '颂... ], 41, 61, [21, 25, ...] | |||
492, ['范', '廷', '颂... ], 30, 34, "[21, 25, ...]" | |||
491, ['范', '廷', '颂... ], 41, 61, "[21, 25, ...]" | |||
".", "...", "...","...", "..." | |||
".", "...", "...","...", "..." | |||
raw_words列是context与question拼起来的结果(连接的地方加入了[SEP]),words是转为index的值, target_start为答案start的index,target_end为答案end的index | |||
(闭区间);context_len指示的是words列中context的长度。 | |||
其中各列的meta信息如下: | |||
.. code:: | |||
+-------------+-------------+-----------+--------------+------------+-------+---------+ | |||
| field_names | context_len | raw_chars | target_start | target_end | chars | answers | | |||
+-------------+-------------+-----------+--------------+------------+-------+---------| | |||
@@ -100,7 +104,7 @@ class CMRC2018BertPipe(Pipe): | |||
| ignore_type | False | True | False | False | False | True | | |||
| pad_value | 0 | 0 | 0 | 0 | 0 | 0 | | |||
+-------------+-------------+-----------+--------------+------------+-------+---------+ | |||
""" | |||
def __init__(self, max_len=510): | |||
super().__init__() | |||