提交 94005393 编写于 作者: S Superjom

Merge branch 'develop' of https://github.com/PaddlePaddle/models into develop

# models简介 # models 简介
[![Documentation Status](https://img.shields.io/badge/docs-latest-brightgreen.svg?style=flat)](https://github.com/PaddlePaddle/models) [![Documentation Status](https://img.shields.io/badge/docs-latest-brightgreen.svg?style=flat)](https://github.com/PaddlePaddle/models)
[![Documentation Status](https://img.shields.io/badge/中文文档-最新-brightgreen.svg)](https://github.com/PaddlePaddle/models) [![Documentation Status](https://img.shields.io/badge/中文文档-最新-brightgreen.svg)](https://github.com/PaddlePaddle/models)
...@@ -6,81 +6,110 @@ ...@@ -6,81 +6,110 @@
PaddlePaddle提供了丰富的运算单元,帮助大家以模块化的方式构建起千变万化的深度学习模型来解决不同的应用问题。这里,我们针对常见的机器学习任务,提供了不同的神经网络模型供大家学习和使用。 PaddlePaddle提供了丰富的运算单元,帮助大家以模块化的方式构建起千变万化的深度学习模型来解决不同的应用问题。这里,我们针对常见的机器学习任务,提供了不同的神经网络模型供大家学习和使用。
## 词向量 ## [词向量](https://github.com/PaddlePaddle/models/tree/develop/word_embedding)
- **介绍** - **介绍**
[词向量](https://github.com/PaddlePaddle/book/blob/develop/04.word2vec/README.cn.md) 是深度学习应用于自然语言处理领域最成功的概念和成果之一,是一种分散式表示(distributed representation)法。分散式表示法用一个更低维度的实向量表示词语,向量的每个维度在实数域取值,都表示文本的某种潜在语法或语义特征。广义地讲,词向量也可以应用于普通离散特征。词向量的学习通常都是一个无监督的学习过程,因此,可以充分利用海量的无标记数据以捕获特征之间的关系,也可以有效地解决特征稀疏、标签数据缺失、数据噪声等问题。 [词向量](https://github.com/PaddlePaddle/book/blob/develop/04.word2vec/README.cn.md) 是深度学习应用于自然语言处理领域最成功的概念和成果之一,是一种分散式表示(distributed representation)法。分散式表示法用一个更低维度的实向量表示词语,向量的每个维度在实数域取值,都表示文本的某种潜在语法或语义特征。广义地讲,词向量也可以应用于普通离散特征。词向量的学习通常都是一个无监督的学习过程,因此,可以充分利用海量的无标记数据以捕获特征之间的关系,也可以有效地解决特征稀疏、标签数据缺失、数据噪声等问题。
然而,在常见词向量学习方法中,模型最后一层往往会遇到一个超大规模的分类问题,是计算性能的瓶颈。在词向量的例子中,我们向大家展示如何使用Hierarchical-Sigmoid 和噪声对比估计(Noise Contrastive Estimation,NCE)来加速词向量的学习。 然而,在常见词向量学习方法中,模型最后一层往往会遇到一个超大规模的分类问题,是计算性能的瓶颈。在词向量的例子中,我们向大家展示如何使用Hierarchical-Sigmoid 和噪声对比估计(Noise Contrastive Estimation,NCE)来加速词向量的学习。
- **应用领域** - **应用领域**
词向量是深度学习方法引入自然语言处理领域的核心技术之一,在大规模无标记语料上训练的词向量常作为各种自然语言处理任务的预训练参数,是一种较为通用的资源,对任务性能的进一步提升有一定的帮助。同时,词嵌入的思想也是深度学习模型处理离散特征的重要方法,有着广泛地借鉴和参考意义。 词向量是深度学习方法引入自然语言处理领域的核心技术之一,在大规模无标记语料上训练的词向量常作为各种自然语言处理任务的预训练参数,是一种较为通用的资源,对任务性能的进一步提升有一定的帮助。同时,词嵌入的思想也是深度学习模型处理离散特征的重要方法,有着广泛地借鉴和参考意义。
词向量是搜索引擎、广告系统、推荐系统等互联网服务背后的常见基础技术之一。 词向量是搜索引擎、广告系统、推荐系统等互联网服务背后的常见基础技术之一。
- **模型配置说明** - **模型配置**
1. [Hsigmoid加速词向量训练](https://github.com/PaddlePaddle/models/blob/develop/word_embedding/hsigmoid_train.py)
2. [噪声对比估计加速词向量训练]()
[word_embedding](https://github.com/PaddlePaddle/models/tree/develop/word_embedding) ## [文本分类](https://github.com/PaddlePaddle/models/tree/develop/text_classification)
## 文本生成
- **介绍** - **介绍**
我们期待有一天机器可以使用自然语言与人们进行交流,像人一样能够撰写高质量的自然语言文本,自动文本生成是实现这一目标的关键技术,可以应用于机器翻译系统、对话系统、问答系统等,为人们带来更加有趣地交互体验,也可以自动撰写新闻摘要,撰写歌词,简单的故事等等。或许未来的某一天,机器能够代替编辑,作家,歌词作者,颠覆这些内容创作领域的工作方式。 文本分类是自然语言处理领域最基础的任务之一,深度学习方法能够免除复杂的特征工程,直接使用原始文本作为输入,数据驱动地最优化分类准确率。我们以情感分类任务为例,提供了基于DNN的非序列文本分类模型,基于CNN和LSTM的序列模型供大家学习和使用。
- **应用领域**
分类是机器学习基础任务之一。文本分类模型在SPAM检测,文本打标签,文本意图识别,文章质量评估,色情暴力文章识别,评论情绪识别,广告物料风险控制等领域都有着广泛的应用。
- **模型配置**
1. [基于 DNN 的文本分类](https://github.com/PaddlePaddle/models/blob/develop/text_classification/text_classification_dnn.py)
2. [基于 CNN 的文本分类](https://github.com/PaddlePaddle/models/blob/develop/text_classification/text_classification_cnn.py)
3. [基于 LSTM 的文本分类](https://github.com/PaddlePaddle/book/blob/develop/06.understand_sentiment/train.py)
基于神经网络生成文本常使用两类方法:1. 语言模型;2. 序列到序列(sequence to sequence)映射模型。在文本生成的例子中,我们为大家展示如何使用以上两种模型来自动生成文本。 ## [序列标注](https://github.com/PaddlePaddle/models/tree/develop/sequence_tagging_for_ner)
特别的,对序列到序列映射模型,我们以机器翻译任务为例提供了多种改进模型,供大家学习和使用,包括: - **介绍**
1. 不带注意力机制的序列到序列映射模型,这一模型是所有序列到序列学习模型的基础。
2. 带注意力机制使用 scheduled sampling 改善生成质量,用来改善RNN模型在文本生成过程中的错误累积问题。 序列标注是自然语言处理中最常见的问题之一。在这一任务中,给定输入序列,模型为序列中每一个元素贴上一个类别标签。随着深度学习的不断探索和发展,利用循环神经网络模型学习输入序列的特征表示,条件随机场(Conditional Random Field, CRF)在特征基础上完成序列标注任务,逐渐成为解决序列标注问题的标配解决方案。深度学习的巨大优势在于:从原始文本中学习,避免复杂的特征工程,只要构建好这样一套深度学习模型,绝大多数序列标注问题都可以直接套用,只需要相应地替换不同问题对应的训练数据。
3. 带外部记忆机制的神经机器翻译,通过增强神经网络的记忆能力,来完成复杂的序列到序列学习任务。
这里,我们以命名实体识别(Named Entity Recognition,NER)任务为例,向大家介绍如何使用 PaddlePaddle 训练一个端到端(End-to-End)的序列标注模型。
- **应用领域** - **应用领域**
文本生成模型实现了两个甚至是多个不定长模型之间的映射,有着广泛地应用,包括机器翻译、智能对话与问答、广告创意语料生成、自动编码(如金融画像编码)、判断多个文本串之间的语义相关性等 序列标注是自然语言处理领域最重要的基础任务之一,有着广泛地应用:自动分词,语言角色标注,命名实体识别,深度问答(Deep QA),关键词提取等问题都可以转化为序列标注问题直接套用本例中的模型
- **模型配置说明** - **模型配置**
[seq2seq](https://github.com/PaddlePaddle/models/tree/develop/seq2seq) | [scheduled_sampling](https://github.com/PaddlePaddle/models/tree/develop/scheduled_sampling) | [external_memory](https://github.com/PaddlePaddle/models/tree/develop/mt_with_external_memory) 1. [命名实体识别](https://github.com/PaddlePaddle/models/blob/develop/sequence_tagging_for_ner/ner.py)
## 排序学习(Learning to Rank, LTR) ## [排序学习](https://github.com/PaddlePaddle/models/tree/develop/ltr)
- **介绍** - **介绍**
排序学习(Learning to Rank,下简称LTR)是信息检索和搜索引擎研究的核心问题之一,通过机器学习方法学习一个分值函数(Scoring Function)对待排序的候选进行打分,再根据分值的高低确定序关系。深度神经网络可以用来建模分值函数,构成各类基于深度学习的LTR模型。 排序学习(Learning to Rank,下简称LTR)是信息检索和搜索引擎研究的核心问题之一,通过机器学习方法学习一个分值函数(Scoring Function)对待排序的候选进行打分,再根据分值的高低确定序关系。深度神经网络可以用来建模分值函数,构成各类基于深度学习的LTR模型。
以信息检索任务为例,给定查询以及检索到的候选文档列表,LTR系统需要按照查询与候选文档的相关性,对候选文档进行打分并排序。LTR学习方法可以分为三种: 以信息检索任务为例,给定查询以及检索到的候选文档列表,LTR系统需要按照查询与候选文档的相关性,对候选文档进行打分并排序。流行的LTR学习方法分为以下三种:
- Pointwise:Pointwise 学习方法将LTR被转化为回归或是分类问题。给定查询以及一个候选文档,模型基于序数进行二分类、多分类或者回归拟合,是一种基础的LTR学习策略。 - [Pointwise](https://github.com/PaddlePaddle/book/blob/develop/05.recommender_system/README.cn.md)
- Pairwise:Pairwise学习方法将排序问题归约为对有序对(ordered pair)的分类,比Pointwise方法更近了一步。模型判断一对候选文档中,哪一个与给定查询更相关,学习的目标为是最小化误分类文档对的数量。理想情况下,如果所有文档对都能被正确的分类,那么原始的候选文档也会被正确的排序。 - Pointwise 学习方法将LTR被转化为回归或是分类问题。
- Listwise:与Pointwise与Pairwise学习方法相比,Listwise方法将给定查询对应的整个候选文档集合列表(list)作为输入,直接对排序结果列表进行优化。Listwise方法在损失函数中考虑了文档排序的位置因素,是前两种方法所不具备的。 - 给定查询以及一个候选文档,模型基于序数进行二分类、多分类或者回归拟合,是一种基础的LTR学习策略。
- Pairwise
- Pairwise学习方法将排序问题归约为对有序对(ordered pair)的分类,比Pointwise方法更近了一步。
- 模型判断一对候选文档中,哪一个与给定查询更相关,学习的目标为是最小化误分类文档对的数量。
- 理想情况下,如果所有文档对都能被正确的分类,那么原始的候选文档也会被正确的排序。
- Listwise
- 与Pointwise与Pairwise 学习方法相比,Listwise方法将给定查询对应的整个候选文档集合列表(list)作为输入,直接对排序结果列表进行优化。Listwise方法在损失函数中考虑了文档排序的位置因素,是前两种方法所不具备的。
Pointwise 学习策略可参考PaddleBook的[推荐系统](https://github.com/PaddlePaddle/book/blob/develop/05.recommender_system/README.cn.md)一节。在这里,我们提供了基于RankLoss 损失函数的Pairwise 排序模型,以及基于LambdaRank 损失函数的ListWise排序模型。 Pointwise 学习策略是PaddleBook中[推荐系统](https://github.com/PaddlePaddle/book/blob/develop/05.recommender_system/README.cn.md)一节介绍过的方法。这里,我们一进步提供了基于 RankLoss 损失函数的 Pairwise 排序模型和基于LambdaRank损失函数的Listwise排序模型。
- **应用领域** - **应用领域**
LTR模型在搜索排序,包括:图片搜索排序、外卖美食搜索排序、App搜索排序、酒店搜索排序等场景中有着广泛的应用。还可以扩展应用于:关键词推荐、各类业务榜单、个性化推荐等任务。 LTR模型在搜索排序,包括:图片搜索排序、外卖美食搜索排序、App搜索排序、酒店搜索排序等场景中有着广泛的应用,还可以扩展应用于:关键词推荐、各类业务榜单、个性化推荐等任务。
- **模型配置说明** - **模型配置说明**
[Pointwise 排序模型](https://github.com/PaddlePaddle/book/blob/develop/05.recommender_system/README.cn.md) 1. [Pointwise 排序模型](https://github.com/PaddlePaddle/book/blob/develop/05.recommender_system/train.py)
| [Pairwise 排序模型](https://github.com/PaddlePaddle/models/tree/develop/ltr) | [Listwise 排序模型](https://github.com/PaddlePaddle/models/tree/develop/ltr) 2. [Pairwise 排序模型](https://github.com/PaddlePaddle/models/blob/develop/ltr/ranknet.py)
3. [Listwise 排序模型](https://github.com/PaddlePaddle/models/blob/develop/ltr/lambda_rank.py)
## 文本分类 ## [文本生成](https://github.com/PaddlePaddle/models/tree/develop/nmt_without_attention)
- **介绍** - **介绍**
文本分类是自然语言处理领域最基础的任务之一,深度学习方法能够免除复杂的特征工程,直接使用原始文本作为输入,数据驱动地最优化分类准确率。我们以情感分类任务为例,提供了基于DNN的非序列文本分类模型,基于CNN和LSTM的序列模型供大家学习和使用。 我们期待有一天机器可以使用自然语言与人们进行交流,像人一样能够撰写高质量的自然语言文本,自动文本生成是实现这一目标的关键技术,可以应用于机器翻译系统、对话系统、问答系统等,为人们带来更加有趣地交互体验,也可以自动撰写新闻摘要,撰写歌词,简单的故事等等。或许未来的某一天,机器能够代替编辑,作家,歌词作者,颠覆这些内容创作领域的工作方式。
基于神经网络生成文本常使用两类方法:1. 语言模型;2. 序列到序列(sequence to sequence)映射模型。在文本生成的例子中,我们为大家展示如何使用以上两种模型来自动生成文本。
特别的,对序列到序列映射模型,我们以机器翻译任务为例提供了多种改进模型,供大家学习和使用,包括:
1. 不带注意力机制的序列到序列映射模型,这一模型是所有序列到序列学习模型的基础。
2. 带注意力机制使用 scheduled sampling 改善生成质量,用来改善RNN模型在文本生成过程中的错误累积问题。
3. 带外部记忆机制的神经机器翻译,通过增强神经网络的记忆能力,来完成复杂的序列到序列学习任务。
- **应用领域** - **应用领域**
分类是机器学习基础任务之一。文本分类模型在SPAM检测,文本打标签,文本意图识别,文章质量评估,色情暴力文章识别,评论情绪识别,广告物料风险控制等领域都有着广泛的应用 文本生成模型实现了两个甚至是多个不定长模型之间的映射,有着广泛地应用,包括机器翻译、智能对话与问答、广告创意语料生成、自动编码(如金融画像编码)、判断多个文本串之间的语义相关性等
- **模型配置说明** - **模型配置**
[text_classification](https://github.com/PaddlePaddle/models/tree/develop/text_classification) 1. [无注意力机制的编码器解码器模型](https://github.com/PaddlePaddle/models/blob/develop/nmt_without_attention/nmt_without_attention.py)
2. [使用 scheduled sampling 改善生成质量]()
3. [ 带外部记忆机制的神经机器翻译]()
## Copyright and License ## Copyright and License
PaddlePaddle is provided under the [Apache-2.0 license](LICENSE). PaddlePaddle is provided under the [Apache-2.0 license](LICENSE).
此差异已折叠。
...@@ -4,18 +4,16 @@ import paddle.v2 as paddle ...@@ -4,18 +4,16 @@ import paddle.v2 as paddle
import numpy as np import numpy as np
import functools import functools
#lambdaRank is listwise learning to rank model
def lambda_rank(input_dim):
def lambdaRank(input_dim):
""" """
lambdaRank is a ListWise Rank Model, input data and label must be sequence lambda_rank is a Listwise rank model, the input data and label must be sequences.
https://papers.nips.cc/paper/2971-learning-to-rank-with-nonsmooth-cost-functions.pdf https://papers.nips.cc/paper/2971-learning-to-rank-with-nonsmooth-cost-functions.pdf
parameters : parameters :
input_dim, one document's dense feature vector dimension input_dim, one document's dense feature vector dimension
dense_vector_sequence format format of the dense_vector_sequence:
[[f, ...], [f, ...], ...], f is represent for an float or int number [[f, ...], [f, ...], ...], f is a float or an int number
""" """
label = paddle.layer.data("label", label = paddle.layer.data("label",
paddle.data_type.dense_vector_sequence(1)) paddle.data_type.dense_vector_sequence(1))
...@@ -48,7 +46,7 @@ def lambdaRank(input_dim): ...@@ -48,7 +46,7 @@ def lambdaRank(input_dim):
return cost, output return cost, output
def train_lambdaRank(num_passes): def train_lambda_rank(num_passes):
# listwise input sequence # listwise input sequence
fill_default_train = functools.partial( fill_default_train = functools.partial(
paddle.dataset.mq2007.train, format="listwise") paddle.dataset.mq2007.train, format="listwise")
...@@ -60,7 +58,7 @@ def train_lambdaRank(num_passes): ...@@ -60,7 +58,7 @@ def train_lambdaRank(num_passes):
# mq2007 input_dim = 46, dense format # mq2007 input_dim = 46, dense format
input_dim = 46 input_dim = 46
cost, output = lambdaRank(input_dim) cost, output = lambda_rank(input_dim)
parameters = paddle.parameters.create(cost) parameters = paddle.parameters.create(cost)
trainer = paddle.trainer.SGD( trainer = paddle.trainer.SGD(
...@@ -76,7 +74,7 @@ def train_lambdaRank(num_passes): ...@@ -76,7 +74,7 @@ def train_lambdaRank(num_passes):
if isinstance(event, paddle.event.EndPass): if isinstance(event, paddle.event.EndPass):
result = trainer.test(reader=test_reader, feeding=feeding) result = trainer.test(reader=test_reader, feeding=feeding)
print "\nTest with Pass %d, %s" % (event.pass_id, result.metrics) print "\nTest with Pass %d, %s" % (event.pass_id, result.metrics)
with gzip.open("lambdaRank_params_%d.tar.gz" % (event.pass_id), with gzip.open("lambda_rank_params_%d.tar.gz" % (event.pass_id),
"w") as f: "w") as f:
parameters.to_tar(f) parameters.to_tar(f)
...@@ -88,17 +86,17 @@ def train_lambdaRank(num_passes): ...@@ -88,17 +86,17 @@ def train_lambdaRank(num_passes):
num_passes=num_passes) num_passes=num_passes)
def lambdaRank_infer(pass_id): def lambda_rank_infer(pass_id):
""" """
lambdaRank model inference interface lambda_rank model inference interface
parameters: parameters:
pass_id : inference model in pass_id pass_id : inference model in pass_id
""" """
print "Begin to Infer..." print "Begin to Infer..."
input_dim = 46 input_dim = 46
output = lambdaRank(input_dim) output = lambda_rank(input_dim)
parameters = paddle.parameters.Parameters.from_tar( parameters = paddle.parameters.Parameters.from_tar(
gzip.open("lambdaRank_params_%d.tar.gz" % (pass_id - 1))) gzip.open("lambda_rank_params_%d.tar.gz" % (pass_id - 1)))
infer_query_id = None infer_query_id = None
infer_data = [] infer_data = []
...@@ -119,6 +117,6 @@ def lambdaRank_infer(pass_id): ...@@ -119,6 +117,6 @@ def lambdaRank_infer(pass_id):
if __name__ == '__main__': if __name__ == '__main__':
paddle.init(use_gpu=False, trainer_count=4) paddle.init(use_gpu=False, trainer_count=1)
train_lambdaRank(2) train_lambda_rank(2)
lambdaRank_infer(pass_id=1) lambda_rank_infer(pass_id=1)
TBD # 命名实体识别
命名实体识别(Named Entity Recognition,NER)又称作“专名识别”,是指识别文本中具有特定意义的实体,主要包括人名、地名、机构名、专有名词等,是自然语言处理研究的一个基础问题。NER任务通常包括实体边界识别、确定实体类别两部分,可以将其作为序列标注问题解决。
序列标注可以分为Sequence Classification、Segment Classification和Temporal Classification三类[[1](#参考文献)],本例只考虑Segment Classification,即对输入序列中的每个元素在输出序列中给出对应的标签。对于NER任务,由于需要标识边界,一般采用[BIO方式](http://book.paddlepaddle.org/07.label_semantic_roles/)定义的标签集,如下是一个NER的标注结果示例:
<div align="center">
<img src="images/ner_label_ins.png" width = "80%" align=center /><br>
图1. BIO标注方法示例
</div>
根据序列标注结果可以直接得到实体边界和实体类别。类似的,分词、词性标注、语块识别、[语义角色标注](http://book.paddlepaddle.org/07.label_semantic_roles/index.cn.html)等任务同样可通过序列标注来解决。
由于序列标注问题的广泛性,产生了[CRF](http://book.paddlepaddle.org/07.label_semantic_roles/index.cn.html)等经典的序列模型,这些模型大多只能使用局部信息或需要人工设计特征。随着深度学习研究的发展,循环神经网络(Recurrent Neural Network,RNN等序列模型能够处理序列元素之间前后关联问题,能够从原始输入文本中学习特征表示,而更加适合序列标注任务,更多相关知识可参考PaddleBook中[语义角色标注](https://github.com/PaddlePaddle/book/blob/develop/07.label_semantic_roles/README.cn.md)一课。
使用神经网络模型解决问题的思路通常是:前层网络学习输入的特征表示,网络的最后一层在特征基础上完成最终的任务;对于序列标注问题,通常:使用基于RNN的网络结构学习特征,将学习到的特征接入CRF完成序列标注。实际上是将传统CRF中的线性模型换成了非线性神经网络。沿用CRF的出发点是:CRF使用句子级别的似然概率,能够更好的解决标记偏置问题[[2](#参考文献)]。本例也将基于此思路建立模型。虽然,这里以NER任务作为示例,但所给出的模型可以应用到其他各种序列标注任务中。
## 模型说明
NER任务的输入是"一句话",目标是识别句子中的实体边界及类别,我们参照论文\[[2](#参考文献)\]仅对原始句子进行了一些预处理工作:将每个词转换为小写,并将原词是否大写另作为一个特征,共同作为模型的输入。按照上述处理序列标注问题的思路,可构造如下结构的模型(图2是模型结构示意图):
1. 构造输入
- 输入1是句子序列,采用one-hot方式表示
- 输入2是大写标记序列,标记了句子中每一个词是否是大写,采用one-hot方式表示;
2. one-hot方式的句子序列和大写标记序列通过词表,转换为实向量表示的词向量序列;
3. 将步骤2中的2个词向量序列作为双向RNN的输入,学习输入序列的特征表示,得到新的特性表示序列;
4. CRF以步骤3中模型学习到的特征为输入,以标记序列为监督信号,实现序列标注。
<div align="center">
<img src="images/ner_network.png" width = "40%" align=center /><br>
图2. NER模型的网络结构图
</div>
## 数据说明
在本例中,我们使用CoNLL 2003 NER任务中开放出的数据集。该任务(见[此页面](http://www.clips.uantwerpen.be/conll2003/ner/))只提供了标注工具的下载,原始Reuters数据由于版权原因需另外申请免费下载。在获取原始数据后可参照标注工具中README生成所需数据文件,完成后将包括如下三个数据文件:
| 文件名 | 描述 |
|---|---|
| eng.train | 训练数据 |
| eng.testa | 验证数据,可用来进行参数调优 |
| eng.testb | 评估数据,用来进行最终效果评估 |
为保证本例的完整性,我们从中抽取少量样本放在`data/train``data/test`文件中,作为示例使用;由于版权原因,完整数据还请大家自行获取。这三个文件数据格式如下:
```
U.N. NNP I-NP I-ORG
official NN I-NP O
Ekeus NNP I-NP I-PER
heads VBZ I-VP O
for IN I-PP O
Baghdad NNP I-NP I-LOC
. . O O
```
其中第一列为原始句子序列(第二、三列分别为词性标签和句法分析中的语块标签,这里暂时不用),第四列为采用了I-TYPE方式表示的NER标签(I-TYPE和BIO方式的主要区别在于语块开始标记的使用上,I-TYPE只有在出现相邻的同类别实体时对后者使用B标记,其他均使用I标记),句子之间以空行分隔。
原始数据需要进行数据预处理才能被PaddlePaddle处理,预处理主要包括下面几个步骤:
1. 从原始数据文件中抽取出句子和标签,构造句子序列和标签序列;
2. 将I-TYPE表示的标签转换为BIO方式表示的标签;
3. 将句子序列中的单词转换为小写,并构造大写标记序列;
4. 依据词典获取词对应的整数索引。
我们将在`conll03.py`中完成以上预处理工作(使用方法将在后文给出):
```python
# import conll03
# conll03.corpus_reader函数完成上面第1步和第2步.
# conll03.reader_creator函数完成上面第3步和第4步.
# conll03.train和conll03.test函数可以获取处理之后的每条样本来供PaddlePaddle训练和测试.
```
预处理完成后,一条训练样本包含3个部分:句子序列、首字母大写标记序列、标注序列。下表是一条训练样本的示例。
| 句子序列 | 大写标记序列 | 标注序列 |
|---|---|---|
| u.n. | 1 | B-ORG |
| official | 0 | O |
| ekeus | 1 | B-PER |
| heads | 0 | O |
| for | 0 | O |
| baghdad | 1 | B-LOC |
| . | 0 | O |
另外,本例依赖的数据还包括:word词典、label词典和预训练的词向量三个文件。label词典已附在`data`目录中,对应于`data/target.txt`;word词典和预训练的词向量来源于[Stanford CS224d](http://cs224d.stanford.edu/)课程作业,请先在该示例所在目录下运行`data/download.sh`脚本进行下载,完成后会将这两个文件一并放入`data`目录下,分别对应`data/vocab.txt``data/wordVectors.txt`
## 使用说明
本示例给出的`conll03.py``ner.py`两个Python脚本分别提供了数据相关和模型相关接口。
### 数据接口使用
`conll03.py`提供了使用CoNLL 2003数据的接口,各主要函数的功能已在数据说明部分进行说明。结合我们提供的接口和文件,可以按照如下步骤使用CoNLL 2003数据:
1. 定义各数据文件、词典文件和词向量文件路径;
2. 调用`conll03.train``conll03.test`接口。
对应如下代码:
```python
import conll03
# 修改以下变量为对应文件路径
train_data_file = 'data/train' # 训练数据文件的路径
test_data_file = 'data/test' # 测试数据文件的路径
vocab_file = 'data/vocab.txt' # 输入句子对应的字典文件的路径
target_file = 'data/target.txt' # 标签对应的字典文件的路径
emb_file = 'data/wordVectors.txt' # 预训练的词向量参数的路径
# 返回训练数据的生成器
train_data_reader = conll03.train(train_data_file, vocab_file, target_file)
# 返回测试数据的生成器
test_data_reader = conll03.test(test_data_file, vocab_file, target_file)
```
### 模型接口使用
`ner.py`提供了以下两个接口分别进行模型训练和预测:
1. `ner_net_train(data_reader, num_passes)`函数实现了模型训练功能,参数`data_reader`表示训练数据的迭代器、`num_passes`表示训练pass的轮数。训练过程中每100个iteration会打印模型训练信息。我们同时在模型配置中加入了chunk evaluator,会输出当前模型对语块识别的Precision、Recall和F1值。chunk evaluator 的详细使用说明请参照[文档](http://www.paddlepaddle.org/develop/doc/api/v2/config/evaluators.html#chunk)。每个pass后会将模型保存为`params_pass_***.tar.gz`的文件(`***`表示pass的id)。
2. `ner_net_infer(data_reader, model_file)`函数实现了预测功能,参数`data_reader`表示测试数据的迭代器、`model_file`表示保存在本地的模型文件,预测过程会按如下格式打印预测结果:
```
U.N. B-ORG
official O
Ekeus B-PER
heads O
for O
Baghdad B-LOC
. O
```
其中第一列为原始句子序列,第二列为BIO方式表示的NER标签。
### 运行程序
本例另在`ner.py`中提供了完整的运行流程,包括数据接口的使用和模型训练、预测。根据上文所述的接口使用方法,使用时需要将`ner.py`中如下的数据设置部分中的各变量修改为对应文件路径:
```python
# 修改以下变量为对应文件路径
train_data_file = 'data/train' # 训练数据文件的路径
test_data_file = 'data/test' # 测试数据文件的路径
vocab_file = 'data/vocab.txt' # 输入句子对应的字典文件的路径
target_file = 'data/target.txt' # 标签对应的字典文件的路径
emb_file = 'data/wordVectors.txt' # 预训练的词向量参数的路径
```
各接口的调用已在`ner.py`中提供:
```python
# 训练数据的生成器
train_data_reader = conll03.train(train_data_file, vocab_file, target_file)
# 测试数据的生成器
test_data_reader = conll03.test(test_data_file, vocab_file, target_file)
# 模型训练
ner_net_train(data_reader=train_data_reader, num_passes=1)
# 预测
ner_net_infer(data_reader=test_data_reader, model_file='params_pass_0.tar.gz')
```
为运行序列标注模型除适当调整`num_passes``model_file`两参数值外,无需再做其它修改(也可根据需要自行调用各接口,如只使用预测功能)。完成修改后,运行本示例只需在`ner.py`所在路径下执行`python ner.py`即可。该示例程序会执行数据读取、模型训练和保存、模型读取及新样本预测等步骤。
### 自定义数据和任务
前文提到本例中的模型可以应用到其他序列标注任务中,这里以词性标注任务为例,给出使用其他数据,并应用到其他任务的操作方法。
假定有如下格式的原始数据:
```
U.N. NNP
official NN
Ekeus NNP
heads VBZ
for IN
Baghdad NNP
. .
```
第一列为原始句子序列,第二列为词性标签序列,两列之间以“\t”分隔,句子之间以空行分隔。
为使用PaddlePaddle和本示例提供的模型,可参照`conll03.py`并根据需要自定义数据接口,如下:
1. 参照`conll03.py`中的`corpus_reader`函数,定义接口返回句子序列和标签序列生成器;
```python
# 实现句子和对应标签的抽取,传入数据文件路径,返回句子和标签序列生成器。
def corpus_reader(filename):
def reader():
sentence = []
labels = []
with open(filename) as f:
for line in f:
if len(line.strip()) == 0:
if len(sentence) > 0:
yield sentence, labels
sentence = []
labels = []
else:
segs = line.strip().split()
sentence.append(segs[0])
labels.append(segs[-1])
f.close()
return reader
```
2. 参照`conll03.py`中的`reader_creator`函数,定义接口返回id化的句子和标签序列生成器。
```python
# 传入corpus_reader返回的生成器、dict类型的word词典和label词典,返回id化的句子和标签序列生成器。
def reader_creator(corpus_reader, word_dict, label_dict):
def reader():
for sentence, labels in corpus_reader():
word_idx = [
word_dict.get(w, UNK_IDX) # 若使用小写单词,请使用w.lower()
for w in sentence
]
# 若使用首字母大写标记,请去掉以下注释符号,并在yield语句的word_idx后加上mark
# mark = [
# 1 if w[0].isupper() else 0
# for w in sentence
# ]
label_idx = [label_dict.get(w) for w in labels]
yield word_idx, label_idx, sentence # 加上sentence方便预测时打印
return reader
```
自定义了数据接口后,要使用本示例中的模型,只需在调用模型训练和预测接口`ner_net_train``ner_net_infer`时传入调用`reader_creator`返回的生成器即可。另外需要注意,这里给出的数据接口定义去掉了`conll03.py`一些预处理(使用原始句子,而非转换成小写单词加上大写标记),`ner.py`中的模型相关接口也需要进行一些调整:
1. 修改网络结构定义接口`ner_net`中大写标记相关内容:
删去`mark`和`mark_embedding`两个变量;
2. 修改模型训练接口`ner_net_train`中大写标记相关内容:
将变量`feeding`定义改为`feeding = {'word': 0, 'target': 1}`;
3. 修改预测接口`ner_net_infer`中大写标记相关内容:
将`test_data.append([item[0], item[1]])`改为`test_data.append([item[0]])`。
如果要继续使用NER中的特征预处理(小写单词、大写标记),请参照上文`reader_creator`代码段给出的注释进行修改,此时`ner.py`中的模型相关接口不必进行修改。
## 参考文献
1. Graves A. [Supervised Sequence Labelling with Recurrent Neural Networks](http://www.cs.toronto.edu/~graves/preprint.pdf)[J]. Studies in Computational Intelligence, 2013, 385.
2. Collobert R, Weston J, Bottou L, et al. [Natural Language Processing (Almost) from Scratch](http://www.jmlr.org/papers/volume12/collobert11a/collobert11a.pdf)[J]. Journal of Machine Learning Research, 2011, 12(1):2493-2537.
"""
Conll03 dataset.
"""
import tarfile
import gzip
import itertools
import collections
import re
import numpy as np
__all__ = ['train', 'test', 'get_dict', 'get_embedding']
UNK_IDX = 0
def canonicalize_digits(word):
if any([c.isalpha() for c in word]): return word
word = re.sub("\d", "DG", word)
if word.startswith("DG"):
word = word.replace(",", "") # remove thousands separator
return word
def canonicalize_word(word, wordset=None, digits=True):
word = word.lower()
if digits:
if (wordset != None) and (word in wordset): return word
word = canonicalize_digits(word) # try to canonicalize numbers
if (wordset == None) or (word in wordset): return word
else: return "UUUNKKK" # unknown token
def load_dict(filename):
d = dict()
with open(filename, 'r') as f:
for i, line in enumerate(f):
d[line.strip()] = i
return d
def get_dict(vocab_file='data/vocab.txt', target_file='data/target.txt'):
"""
Get the word and label dictionary.
"""
word_dict = load_dict(vocab_file)
label_dict = load_dict(target_file)
return word_dict, label_dict
def get_embedding(emb_file='data/wordVectors.txt'):
"""
Get the trained word vector.
"""
return np.loadtxt(emb_file, dtype=float)
def corpus_reader(filename='data/train'):
def reader():
sentence = []
labels = []
with open(filename) as f:
for line in f:
if re.match(r"-DOCSTART-.+", line) or (len(line.strip()) == 0):
if len(sentence) > 0:
yield sentence, labels
sentence = []
labels = []
else:
segs = line.strip().split()
sentence.append(segs[0])
# transform from I-TYPE to BIO schema
if segs[-1] != 'O' and (len(labels) == 0 or
labels[-1][1:] != segs[-1][1:]):
labels.append('B' + segs[-1][1:])
else:
labels.append(segs[-1])
f.close()
return reader
def reader_creator(corpus_reader, word_dict, label_dict):
"""
Conll03 train set creator.
The dataset can be obtained according to http://www.clips.uantwerpen.be/conll2003/ner/.
It returns a reader creator, each sample in the reader includes word id sequence, label id sequence and raw sentence for purpose of print.
:return: Training reader creator
:rtype: callable
"""
def reader():
for sentence, labels in corpus_reader():
word_idx = [
word_dict.get(canonicalize_word(w, word_dict), UNK_IDX)
for w in sentence
]
mark = [1 if w[0].isupper() else 0 for w in sentence]
label_idx = [label_dict.get(w) for w in labels]
yield word_idx, mark, label_idx, sentence
return reader
def train(data_file='data/train',
vocab_file='data/vocab.txt',
target_file='data/target.txt'):
return reader_creator(
corpus_reader(data_file),
word_dict=load_dict(vocab_file),
label_dict=load_dict(target_file))
def test(data_file='data/test',
vocab_file='data/vocab.txt',
target_file='data/target.txt'):
return reader_creator(
corpus_reader(data_file),
word_dict=load_dict(vocab_file),
label_dict=load_dict(target_file))
wget http://cs224d.stanford.edu/assignment2/assignment2.zip
unzip assignment2.zip
cp assignment2_release/data/ner/wordVectors.txt data/
cp assignment2_release/data/ner/vocab.txt data/
rm -rf assignment2.zip assignment2_release
B-LOC
I-LOC
B-MISC
I-MISC
B-ORG
I-ORG
B-PER
I-PER
O
-DOCSTART- -X- O O
CRICKET NNP I-NP O
- : O O
LEICESTERSHIRE NNP I-NP I-ORG
TAKE NNP I-NP O
OVER IN I-PP O
AT NNP I-NP O
TOP NNP I-NP O
AFTER NNP I-NP O
INNINGS NNP I-NP O
VICTORY NN I-NP O
. . O O
LONDON NNP I-NP I-LOC
1996-08-30 CD I-NP O
West NNP I-NP I-MISC
Indian NNP I-NP I-MISC
all-rounder NN I-NP O
Phil NNP I-NP I-PER
Simmons NNP I-NP I-PER
took VBD I-VP O
four CD I-NP O
for IN I-PP O
38 CD I-NP O
on IN I-PP O
Friday NNP I-NP O
as IN I-PP O
Leicestershire NNP I-NP I-ORG
beat VBD I-VP O
Somerset NNP I-NP I-ORG
by IN I-PP O
an DT I-NP O
innings NN I-NP O
and CC O O
39 CD I-NP O
runs NNS I-NP O
in IN I-PP O
two CD I-NP O
days NNS I-NP O
to TO I-VP O
take VB I-VP O
over IN I-PP O
at IN B-PP O
the DT I-NP O
head NN I-NP O
of IN I-PP O
the DT I-NP O
county NN I-NP O
championship NN I-NP O
. . O O
Their PRP$ I-NP O
stay NN I-NP O
on IN I-PP O
top NN I-NP O
, , O O
though RB I-ADVP O
, , O O
may MD I-VP O
be VB I-VP O
short-lived JJ I-ADJP O
as IN I-PP O
title NN I-NP O
rivals NNS I-NP O
Essex NNP I-NP I-ORG
, , O O
Derbyshire NNP I-NP I-ORG
and CC I-NP O
Surrey NNP I-NP I-ORG
all DT O O
closed VBD I-VP O
in RP I-PRT O
on IN I-PP O
victory NN I-NP O
while IN I-SBAR O
Kent NNP I-NP I-ORG
made VBD I-VP O
up RP I-PRT O
for IN I-PP O
lost VBN I-NP O
time NN I-NP O
in IN I-PP O
their PRP$ I-NP O
rain-affected JJ I-NP O
match NN I-NP O
against IN I-PP O
Nottinghamshire NNP I-NP I-ORG
. . O O
After IN I-PP O
bowling VBG I-NP O
Somerset NNP I-NP I-ORG
out RP I-PRT O
for IN I-PP O
83 CD I-NP O
on IN I-PP O
the DT I-NP O
opening NN I-NP O
morning NN I-NP O
at IN I-PP O
Grace NNP I-NP I-LOC
Road NNP I-NP I-LOC
, , O O
Leicestershire NNP I-NP I-ORG
extended VBD I-VP O
their PRP$ I-NP O
first JJ I-NP O
innings NN I-NP O
by IN I-PP O
94 CD I-NP O
runs VBZ I-VP O
before IN I-PP O
being VBG I-VP O
bowled VBD I-VP O
out RP I-PRT O
for IN I-PP O
296 CD I-NP O
with IN I-PP O
England NNP I-NP I-LOC
discard VBP I-VP O
Andy NNP I-NP I-PER
Caddick NNP I-NP I-PER
taking VBG I-VP O
three CD I-NP O
for IN I-PP O
83 CD I-NP O
. . O O
-DOCSTART- -X- O O
EU NNP I-NP I-ORG
rejects VBZ I-VP O
German JJ I-NP I-MISC
call NN I-NP O
to TO I-VP O
boycott VB I-VP O
British JJ I-NP I-MISC
lamb NN I-NP O
. . O O
Peter NNP I-NP I-PER
Blackburn NNP I-NP I-PER
BRUSSELS NNP I-NP I-LOC
1996-08-22 CD I-NP O
The DT I-NP O
European NNP I-NP I-ORG
Commission NNP I-NP I-ORG
said VBD I-VP O
on IN I-PP O
Thursday NNP I-NP O
it PRP B-NP O
disagreed VBD I-VP O
with IN I-PP O
German JJ I-NP I-MISC
advice NN I-NP O
to TO I-PP O
consumers NNS I-NP O
to TO I-VP O
shun VB I-VP O
British JJ I-NP I-MISC
lamb NN I-NP O
until IN I-SBAR O
scientists NNS I-NP O
determine VBP I-VP O
whether IN I-SBAR O
mad JJ I-NP O
cow NN I-NP O
disease NN I-NP O
can MD I-VP O
be VB I-VP O
transmitted VBN I-VP O
to TO I-PP O
sheep NN I-NP O
. . O O
Germany NNP I-NP I-LOC
's POS B-NP O
representative NN I-NP O
to TO I-PP O
the DT I-NP O
European NNP I-NP I-ORG
Union NNP I-NP I-ORG
's POS B-NP O
veterinary JJ I-NP O
committee NN I-NP O
Werner NNP I-NP I-PER
Zwingmann NNP I-NP I-PER
said VBD I-VP O
on IN I-PP O
Wednesday NNP I-NP O
consumers NNS I-NP O
should MD I-VP O
buy VB I-VP O
sheepmeat NN I-NP O
from IN I-PP O
countries NNS I-NP O
other JJ I-ADJP O
than IN I-PP O
Britain NNP I-NP I-LOC
until IN I-SBAR O
the DT I-NP O
scientific JJ I-NP O
advice NN I-NP O
was VBD I-VP O
clearer JJR I-ADJP O
. . O O
" " O O
We PRP I-NP O
do VBP I-VP O
n't RB I-VP O
support VB I-VP O
any DT I-NP O
such JJ I-NP O
recommendation NN I-NP O
because IN I-SBAR O
we PRP I-NP O
do VBP I-VP O
n't RB I-VP O
see VB I-VP O
any DT I-NP O
grounds NNS I-NP O
for IN I-PP O
it PRP I-NP O
, , O O
" " O O
the DT I-NP O
Commission NNP I-NP I-ORG
's POS B-NP O
chief JJ I-NP O
spokesman NN I-NP O
Nikolaus NNP I-NP I-PER
van NNP I-NP I-PER
der FW I-NP I-PER
Pas NNP I-NP I-PER
told VBD I-VP O
a DT I-NP O
news NN I-NP O
briefing NN I-NP O
. . O O
He PRP I-NP O
said VBD I-VP O
further JJ I-NP O
scientific JJ I-NP O
study NN I-NP O
was VBD I-VP O
required VBN I-VP O
and CC O O
if IN I-SBAR O
it PRP I-NP O
was VBD I-VP O
found VBN I-VP O
that IN I-SBAR O
action NN I-NP O
was VBD I-VP O
needed VBN I-VP O
it PRP I-NP O
should MD I-VP O
be VB I-VP O
taken VBN I-VP O
by IN I-PP O
the DT I-NP O
European NNP I-NP I-ORG
Union NNP I-NP I-ORG
. . O O
import math
import gzip
import paddle.v2 as paddle
import paddle.v2.evaluator as evaluator
import conll03
import itertools
# init dataset
train_data_file = 'data/train'
test_data_file = 'data/test'
vocab_file = 'data/vocab.txt'
target_file = 'data/target.txt'
emb_file = 'data/wordVectors.txt'
train_data_reader = conll03.train(train_data_file, vocab_file, target_file)
test_data_reader = conll03.test(test_data_file, vocab_file, target_file)
word_dict, label_dict = conll03.get_dict(vocab_file, target_file)
word_vector_values = conll03.get_embedding(emb_file)
# init hyper-params
word_dict_len = len(word_dict)
label_dict_len = len(label_dict)
mark_dict_len = 2
word_dim = 50
mark_dim = 5
hidden_dim = 300
mix_hidden_lr = 1e-3
default_std = 1 / math.sqrt(hidden_dim) / 3.0
emb_para = paddle.attr.Param(
name='emb', initial_std=math.sqrt(1. / word_dim), is_static=True)
std_0 = paddle.attr.Param(initial_std=0.)
std_default = paddle.attr.Param(initial_std=default_std)
def d_type(size):
return paddle.data_type.integer_value_sequence(size)
def ner_net(is_train):
word = paddle.layer.data(name='word', type=d_type(word_dict_len))
mark = paddle.layer.data(name='mark', type=d_type(mark_dict_len))
word_embedding = paddle.layer.mixed(
name='word_embedding',
size=word_dim,
input=paddle.layer.table_projection(input=word, param_attr=emb_para))
mark_embedding = paddle.layer.mixed(
name='mark_embedding',
size=mark_dim,
input=paddle.layer.table_projection(input=mark, param_attr=std_0))
emb_layers = [word_embedding, mark_embedding]
word_caps_vector = paddle.layer.concat(
name='word_caps_vector', input=emb_layers)
hidden_1 = paddle.layer.mixed(
name='hidden1',
size=hidden_dim,
act=paddle.activation.Tanh(),
bias_attr=std_default,
input=[
paddle.layer.full_matrix_projection(
input=word_caps_vector, param_attr=std_default)
])
rnn_para_attr = paddle.attr.Param(initial_std=0.0, learning_rate=0.1)
hidden_para_attr = paddle.attr.Param(
initial_std=default_std, learning_rate=mix_hidden_lr)
rnn_1_1 = paddle.layer.recurrent(
name='rnn1-1',
input=hidden_1,
act=paddle.activation.Relu(),
bias_attr=std_0,
param_attr=rnn_para_attr)
rnn_1_2 = paddle.layer.recurrent(
name='rnn1-2',
input=hidden_1,
act=paddle.activation.Relu(),
reverse=1,
bias_attr=std_0,
param_attr=rnn_para_attr)
hidden_2_1 = paddle.layer.mixed(
name='hidden2-1',
size=hidden_dim,
bias_attr=std_default,
act=paddle.activation.STanh(),
input=[
paddle.layer.full_matrix_projection(
input=hidden_1, param_attr=hidden_para_attr),
paddle.layer.full_matrix_projection(
input=rnn_1_1, param_attr=rnn_para_attr)
])
hidden_2_2 = paddle.layer.mixed(
name='hidden2-2',
size=hidden_dim,
bias_attr=std_default,
act=paddle.activation.STanh(),
input=[
paddle.layer.full_matrix_projection(
input=hidden_1, param_attr=hidden_para_attr),
paddle.layer.full_matrix_projection(
input=rnn_1_2, param_attr=rnn_para_attr)
])
rnn_2_1 = paddle.layer.recurrent(
name='rnn2-1',
input=hidden_2_1,
act=paddle.activation.Relu(),
reverse=1,
bias_attr=std_0,
param_attr=rnn_para_attr)
rnn_2_2 = paddle.layer.recurrent(
name='rnn2-2',
input=hidden_2_2,
act=paddle.activation.Relu(),
bias_attr=std_0,
param_attr=rnn_para_attr)
hidden_3 = paddle.layer.mixed(
name='hidden3',
size=hidden_dim,
bias_attr=std_default,
act=paddle.activation.STanh(),
input=[
paddle.layer.full_matrix_projection(
input=hidden_2_1, param_attr=hidden_para_attr),
paddle.layer.full_matrix_projection(
input=rnn_2_1,
param_attr=rnn_para_attr), paddle.layer.full_matrix_projection(
input=hidden_2_2, param_attr=hidden_para_attr),
paddle.layer.full_matrix_projection(
input=rnn_2_2, param_attr=rnn_para_attr)
])
output = paddle.layer.mixed(
name='output',
size=label_dict_len,
bias_attr=False,
input=[
paddle.layer.full_matrix_projection(
input=hidden_3, param_attr=std_default)
])
if is_train:
target = paddle.layer.data(name='target', type=d_type(label_dict_len))
crf_cost = paddle.layer.crf(
size=label_dict_len,
input=output,
label=target,
param_attr=paddle.attr.Param(
name='crfw',
initial_std=default_std,
learning_rate=mix_hidden_lr))
crf_dec = paddle.layer.crf_decoding(
size=label_dict_len,
input=output,
label=target,
param_attr=paddle.attr.Param(name='crfw'))
return crf_cost, crf_dec, target
else:
predict = paddle.layer.crf_decoding(
size=label_dict_len,
input=output,
param_attr=paddle.attr.Param(name='crfw'))
return predict
def ner_net_train(data_reader=train_data_reader, num_passes=1):
# define network topology
crf_cost, crf_dec, target = ner_net(is_train=True)
evaluator.sum(name='error', input=crf_dec)
evaluator.chunk(
name='ner_chunk',
input=crf_dec,
label=target,
chunk_scheme='IOB',
num_chunk_types=(label_dict_len - 1) / 2)
# create parameters
parameters = paddle.parameters.create(crf_cost)
parameters.set('emb', word_vector_values)
# create optimizer
optimizer = paddle.optimizer.Momentum(
momentum=0,
learning_rate=2e-4,
regularization=paddle.optimizer.L2Regularization(rate=8e-4),
gradient_clipping_threshold=25,
model_average=paddle.optimizer.ModelAverage(
average_window=0.5, max_average_window=10000), )
trainer = paddle.trainer.SGD(
cost=crf_cost,
parameters=parameters,
update_equation=optimizer,
extra_layers=crf_dec)
reader = paddle.batch(
paddle.reader.shuffle(data_reader, buf_size=8192), batch_size=64)
feeding = {'word': 0, 'mark': 1, 'target': 2}
def event_handler(event):
if isinstance(event, paddle.event.EndIteration):
if event.batch_id % 100 == 0:
print "Pass %d, Batch %d, Cost %f, %s" % (
event.pass_id, event.batch_id, event.cost, event.metrics)
if event.batch_id % 1000 == 0:
result = trainer.test(reader=reader, feeding=feeding)
print "\nTest with Pass %d, Batch %d, %s" % (
event.pass_id, event.batch_id, result.metrics)
if isinstance(event, paddle.event.EndPass):
# save parameters
with gzip.open('params_pass_%d.tar.gz' % event.pass_id, 'w') as f:
parameters.to_tar(f)
result = trainer.test(reader=reader, feeding=feeding)
print "\nTest with Pass %d, %s" % (event.pass_id, result.metrics)
trainer.train(
reader=reader,
event_handler=event_handler,
num_passes=num_passes,
feeding=feeding)
return parameters
def ner_net_infer(data_reader=test_data_reader, model_file='ner_model.tar.gz'):
test_data = []
test_sentences = []
for item in data_reader():
test_data.append([item[0], item[1]])
test_sentences.append(item[-1])
if len(test_data) == 10:
break
predict = ner_net(is_train=False)
lab_ids = paddle.infer(
output_layer=predict,
parameters=paddle.parameters.Parameters.from_tar(gzip.open(model_file)),
input=test_data,
field='id')
flat_data = [word for word in itertools.chain.from_iterable(test_sentences)]
labels_reverse = {}
for (k, v) in label_dict.items():
labels_reverse[v] = k
pre_lab = [labels_reverse[lab_id] for lab_id in lab_ids]
for word, label in zip(flat_data, pre_lab):
print word, label
if __name__ == '__main__':
paddle.init(use_gpu=False, trainer_count=1)
ner_net_train(data_reader=train_data_reader, num_passes=1)
ner_net_infer(
data_reader=test_data_reader, model_file='params_pass_0.tar.gz')
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册