导语
PaddlePaddle提供了丰富的运算单元,帮助大家以模块化的方式构建起千变万化的深度学习模型来解决不同的应用问题。这里,我们针对常见的机器学习任务,提供了不同的神经网络模型供大家学习和使用。本周推文目录如下:
周一:【点击率预估】
Wide&deep 点击率预估模型
周二:【文本分类】
基于DNN/CNN的情感分类
周三:【文本分类】
基于双层序列的文本分类模型
周四:【排序学习】
基于Pairwise和Listwise的排序学习
周五:【结构化语义模型】
深度结构化语义模型
文本分类是自然语言处理领域最基础的任务之一,深度学习方法能够免除复杂的特征工程,直接使用原始文本作为输入,数据驱动地最优化分类准确率。
在文本分类任务中,我们以情感分类任务为例,提供了基于DNN的非序列文本分类模型,以及基于CNN的序列模型供大家学习和使用(基于LSTM的模型见PaddleBook中情感分类一课http://www.paddlepaddle.org/docs/develop/book/06.understand_sentiment/index.cn.html)。
01
├── images # 文档中的图片
│ ├── cnn_net.png
│ └── dnn_net.png
├── index.html # 文档
├── infer.py # 预测脚本
├── network_conf.py # 本例中涉及的各种网络结构均定义在此文件中,若进一步修改模型结构,请查看此文件
├── reader.py # 读取数据接口,若使用自定义格式的数据,请查看此文件
├── README.md # 文档
├── run.sh # 训练任务运行脚本,直接运行此脚本,将以默认参数开始训练任务
├── train.py # 训练脚本
└── utils.py # 定义通用的函数,例如:打印日志、解析命令行参数、构建字典、加载字典等
|1. 简介
文本分类任务根据给定一条文本的内容,判断该文本所属的类别,是自然语言处理领域的一项重要的基础任务。PaddleBook 中的情感分类一课,正是一个典型的文本分类任务,任务流程如下:
训练好的分类器能够自动判断新出现的用户评论的情感是正面还是负面,在舆情监控、营销策划、产品品牌价值评估等任务中,能够起到重要作用。以上过程也是我们去完成一个新的文本分类任务需要遵循的常规流程。可以看到,深度学习方法的巨大优势体现在:免除复杂的特征的设计,只需要对原始文本进行基础的清理、标注即可。
PaddleBook 中的情感分类介绍了一个较为复杂的栈式双向 LSTM 模型,循环神经网络在一些需要理解语言语义的复杂任务中有着明显的优势,但计算量大,通常对调参技巧也有着更高的要求。在对计算时间有一定限制的任务中,也会考虑其它模型。除了计算时间的考量,更重要的一点:模型选择往往是机器学习任务成功的基础。机器学习任务的目标始终是提高泛化能力,也就是对未知的新的样本预测的能力:
"No Free Lunch (NFL)" 是机器学习任务基本原则之一:没有任何一种模型是天生优于其他模型的。模型的设计和选择建立在了解不同模型特性的基础之上,但同时也是一个多次实验评估的过程。在本例中,我们继续向大家介绍几种最常用的文本分类模型,它们的能力和复杂程度不同,帮助大家对比学习这些模型学习效果之间的差异,针对不同的场景选择使用。
|2. 模型详解
network_conf.py 中包括以下模型:
我们以情感分类任务为例,简单说明序列模型和非序列模型之间的差异。情感分类是一项常见的文本分类任务,模型自动判断文本中表现出的情感是正向还是负向。以句子 "The apple is not bad" 为例,"not bad" 是决定这个句子情感的关键:
两者各自的一些特点简单总结如下:
A.DNN 模型
DNN 模型结构入下图所示:
在 PaddlePaddle 实现该 DNN 结构的代码见 network_conf.py 中的 fc_net 函数,模型主要分为如下几个部分:
该 DNN 模型默认对输入的语料进行二分类(class_dim=2),embedding(词向量)维度默认为28(emd_dim=28),两个隐层均使用Tanh激活函数(act=paddle.activation.Tanh())。需要注意的是,该模型的输入数据为整数序列,而不是原始的单词序列。事实上,为了处理方便,我们一般会事先将单词根据词频顺序进行 id 化,即将词语转化成在字典中的序号。
B.CNN 模型
CNN 模型结构如下图所示:
通过 PaddlePaddle 实现该 CNN 结构的代码见 network_conf.py 中的 convolution_net 函数,模型主要分为如下几个部分:
CNN 网络的输入数据类型和 DNN 一致。PaddlePaddle 中已经封装好的带有池化的文本序列卷积模块:paddle.networks.sequence_conv_pool,可直接调用。该模块的 context_len 参数用于指定卷积核在同一时间覆盖的文本长度,即图 2 中的卷积核的高度。hidden_size 用于指定该类型的卷积核的数量。本例代码默认使用了 128 个大小为 3 的卷积核和 128 个大小为 4 的卷积核,这些卷积的结果经过最大池化和结果拼接后产生一个 256 维的向量,向量经过一个全连接层输出最终的预测结果。
|3. 使用 PaddlePaddle 内置数据运行
A.如何训练
在终端中执行 sh run.sh 以下命令, 将以 PaddlePaddle 内置的情感分类数据集:paddle.dataset.imdb 直接运行本例,会看到如下输入:
Pass 0, Batch 0, Cost 0.696031, {'__auc_evaluator_0__': 0.47360000014305115, 'classification_error_evaluator': 0.5}
Pass 0, Batch 100, Cost 0.544438, {'__auc_evaluator_0__': 0.839249312877655, 'classification_error_evaluator': 0.30000001192092896}
Pass 0, Batch 200, Cost 0.406581, {'__auc_evaluator_0__': 0.9030032753944397, 'classification_error_evaluator': 0.2199999988079071}
Test at Pass 0, {'__auc_evaluator_0__': 0.9289745092391968, 'classification_error_evaluator': 0.14927999675273895}
日志每隔 100 个 batch 输出一次,输出信息包括:(1)Pass 序号;(2)Batch 序号;(3)依次输出当前 Batch 上评估指标的评估结果。评估指标在配置网络拓扑结构时指定,在上面的输出中,输出了训练样本集之的 AUC 以及错误率指标。
B.如何预测
训练结束后模型默认存储在当前工作目录下,在终端中执行 python infer.py ,预测脚本会加载训练好的模型进行预测。
默认加载使用 paddle.data.imdb.train 训练一个 Pass 产出的 DNN 模型对 paddle.dataset.imdb.test 进行测试,会看到如下输出:
positive 0.9275 0.0725 previous reviewer <unk> <unk> gave a much better <unk> of the films plot details than i could what i recall mostly is that it was just so beautiful in every sense emotionally visually <unk> just <unk> br if you like movies that are wonderful to look at and also have emotional content to which that beauty is relevant i think you will be glad to have seen this extraordinary and unusual work of <unk> br on a scale of 1 to 10 id give it about an <unk> the only reason i shy away from 9 is that it is a mood piece if you are in the mood for a really artistic very romantic film then its a 10 i definitely think its a mustsee but none of us can be in that mood all the time so overall <unk>
negative 0.0300 0.9700 i love scifi and am willing to put up with a lot scifi <unk> are usually <unk> <unk> and <unk> i tried to like this i really did but it is to good tv scifi as <unk> 5 is to star trek the original silly <unk> cheap cardboard sets stilted dialogues cg that doesnt match the background and painfully onedimensional characters cannot be overcome with a scifi setting im sure there are those of you out there who think <unk> 5 is good scifi tv its not its clichéd and <unk> while us viewers might like emotion and character development scifi is a genre that does not take itself seriously <unk> star trek it may treat important issues yet not as a serious philosophy its really difficult to care about the characters here as they are not simply <unk> just missing a <unk> of life their actions and reactions are wooden and predictable often painful to watch the makers of earth know its rubbish as they have to always say gene <unk> earth otherwise people would not continue watching <unk> <unk> must be turning in their <unk> as this dull cheap poorly edited watching it without <unk> breaks really brings this home <unk> <unk> of a show <unk> into space spoiler so kill off a main character and then bring him back as another actor <unk> <unk> all over again
输出日志每一行是对一条样本预测的结果,以 \t 分隔,共 3 列,分别是:(1)预测类别标签;(2)样本分别属于每一类的概率,内部以空格分隔;(3)输入文本。
|4. 使用自定义数据训练和预测
A.如何训练
(1)数据组织
假设有如下格式的训练数据:每一行为一条样本,以 \t 分隔,第一列是类别标签,第二列是输入文本的内容,文本内容中的词语以空格分隔。以下是两条示例数据:
positive PaddlePaddle is good
negative What a terrible weather
(2)编写数据读取接口
自定义数据读取接口只需编写一个 Python 生成器实现从原始输入文本中解析一条训练样本的逻辑。以下代码片段实现了读取原始数据返回类型为: paddle.data_type.integer_value_sequence(词语在字典的序号)和 paddle.data_type.integer_value(类别标签)的 2 个输入给网络中定义的 2 个 data_layer 的功能。
def train_reader(data_dir, word_dict, label_dict):
def reader():
UNK_ID = word_dict["<UNK>"]
word_col = 0
lbl_col = 1
for file_name in os.listdir(data_dir):
with open(os.path.join(data_dir, file_name), "r") as f:
for line in f:
line_split = line.strip().split("\t")
word_ids = [
word_dict.get(w, UNK_ID)
for w in line_split[word_col].split()
]
yield word_ids, label_dict[line_split[lbl_col]]
return reader
以上代码片段详见本例目录下的 reader.py 脚本,reader.py 同时提供了读取测试数据的全部代码。
接下来,只需要将数据读取函数 train_reader 作为参数传递给 train.py 脚本中的 paddle.batch 接口即可使用自定义数据接口读取数据,调用方式如下:
train_reader = paddle.batch(
paddle.reader.shuffle(
reader.train_reader(train_data_dir, word_dict, lbl_dict),
buf_size=1000),
batch_size=batch_size)
(3)修改命令行参数
如果将数据组织成示例数据的同样的格式,只需在 run.sh 脚本中修改 train.py 启动参数,指定 train_data_dir 参数,可以直接运行本例,无需修改数据读取接口 reader.py。
执行 python train.py --help 可以获取 train.py 脚本各项启动参数的详细说明,主要参数如下:
nn_type:选择要使用的模型,目前支持两种:“dnn” 或者 “cnn”。
train_data_dir:指定训练数据所在的文件夹,使用自定义数据训练,必须指定此参数,否则使用paddle.dataset.imdb训练,同时忽略test_data_dir,word_dict,和 label_dict 参数。
test_data_dir:指定测试数据所在的文件夹,若不指定将不进行测试。
word_dict:字典文件所在的路径,若不指定,将从训练数据根据词频统计,自动建立字典。
label_dict:类别标签字典,用于将字符串类型的类别标签,映射为整数类型的序号。
batch_size:指定多少条样本后进行一次神经网络的前向运行及反向更新。
num_passes:指定训练多少个轮次。
B.如何预测
(1)修改 infer.py 中以下变量,指定使用的模型、指定测试数据。
model_path = "dnn_params_pass_00000.tar.gz"
# 指定模型所在的路径
nn_type = "dnn" # 指定测试使用的模型
test_dir = "./data/test"
# 指定测试文件所在的目录
word_dict = "./data/dict/word_dict.txt"
# 指定字典所在的路径
label_dict = "./data/dict/label_dict.txt"
# 指定类别标签字典的路径
(2)在终端中执行 python infer.py。
本文分享自 PaddlePaddle 微信公众号,前往查看
如有侵权,请联系 cloudcommunity@tencent.com 删除。
本文参与 腾讯云自媒体同步曝光计划 ,欢迎热爱写作的你一起参与!