译:Tensorflow实现的CNN文本分类

翻译自博客:IMPLEMENTING A CNN FOR TEXT CLASSIFICATION IN TENSORFLOWgit

原博文:http://www.wildml.com/2015/12/implementing-a-cnn-for-text-classification-in-tensorflow/github

github:https://github.com/dennybritz/cnn-text-classification-tf网络

在这篇文章中,咱们将实现一个相似于Kim Yoon的卷积神经网络语句分类的模型。 本文提出的模型在一系列文本分类任务(如情感分析)中实现了良好的分类性能,并已成为新的文本分类架构的标准基准。session

本文假设你已经熟悉了应用于NLP的卷积神经网络的基础知识。 若是没有,建议先阅读Understanding Convolutional Neural Networks for NLP 以得到必要的背景。架构

1. 数据和预处理

咱们将在这篇文章中使用的数据集是 Movie Review data from Rotten Tomatoes,也是原始文献中使用的数据集之一。 数据集包含10,662个示例评论句子,正负向各占一半。 数据集的大小约为20k。 请注意,因为这个数据集很小,咱们极可能会使用强大的模型。 此外,数据集不附带拆分的训练/测试集,所以咱们只需将10%的数据用做 dev set。 原始文献展现了对数据进行10倍交叉验证的结果。ide

这里不讨论数据预处理代码,代码能够在 Github 上得到,并执行如下操做:函数

  • 从原始数据文件中加载正负向情感的句子。性能

  • 使用与原始文献相同的代码清理文本数据。学习

  • 将每一个句子加到最大句子长度(59)。咱们向全部其余句子添加特殊的操做,使其成为59个字。填充句子相同的长度是有用的,由于这样就容许咱们有效地批量咱们的数据,由于批处理中的每一个示例必须具备相同的长度。测试

  • 构建词汇索引,并将每一个单词映射到0到18,765之间的整数(词库大小)。 每一个句子都成为一个整数向量。

2. 模型

原始文献的网络结构以下图:
watermark,size_16,text_QDUxQ1RP5Y2a5a6i,color_FFFFFF,t_100,g_se,x_10,y_10,shadow_90,type_ZmFuZ3poZW5naGVpdGk=

第一层将单词嵌入到低维向量中。 下一层使用多个过滤器大小对嵌入的字矢量执行卷积。 例如,一次滑过3,4或5个字。 接下来,咱们将卷积层的max_pooling结果做为一个长的特征向量,添加dropout正则,并使用softmax层对结果进行分类。

由于这是是一篇教学性质的博客,因此对于原始文献的模型进行一下简化:

  1. 咱们不会对咱们的词嵌入使用预先训练的word2vec向量。 相反,咱们从头开始学习嵌入。

  2. 咱们不会对权重向量执行L2规范约束。 《A Sensitivity Analysis of (and Practitioners’ Guide to) Convolutional Neural Networks for Sentence Classification》这篇文章中发现约束对最终结果几乎没有影响。(关注公众号输入cnn获取)

  3. 原始实验用两个输入数据通道 - 静态和非静态字矢量。 咱们只使用一个通道。

将这些扩展代码添加到这里是比较简单的(几十行代码)。 看看帖子结尾的练习。

3. 代码实现

为了容许各类超参数配置,咱们将代码放入TextCNN类中,在init函数中生成模型图。

watermark,size_16,text_QDUxQ1RP5Y2a5a6i,color_FFFFFF,t_100,g_se,x_10,y_10,shadow_90,type_ZmFuZ3poZW5naGVpdGk=

为了实例化类,咱们传递如下参数:

  • sequence_length - 句子的长度。注意:咱们将全部句子填充到相同的长度(咱们的数据集为59)。

  • num_classes - 输出层中的类数,在咱们的例子中为(消极,积极)。

  • vocab_size - 咱们的词汇量的大小。 这须要定义咱们的嵌入层的大小,它将具备[vocabulary_size,embedding_size]的形状。

  • embedding_size - 嵌入的维度。

  • filter_sizes - 咱们想要卷积过滤器覆盖的字数。 咱们将为此处指定的每一个大小设置num_filters。 例如,[3,4,5]意味着咱们将有一个过滤器,分别滑过3,4和5个字,总共有3 * num_filters个过滤器。

  • num_filters - 每一个过滤器大小的过滤器数量(见上文)。

3.1 INPUT PLACEHOLDERS

首先定义网络的输入数据

watermark,size_16,text_QDUxQ1RP5Y2a5a6i,color_FFFFFF,t_100,g_se,x_10,y_10,shadow_90,type_ZmFuZ3poZW5naGVpdGk=

tf.placeholder建立一个占位符变量,当咱们在训练集或测试时间执行它时,咱们将其馈送到网络。 第二个参数是输入张量的形状:None意味着该维度的长度能够是任何东西。 在咱们的状况下,第一个维度是批量大小,而且使用“None”容许网络处理任意大小的批次。

将神经元保留在丢失层中的几率也是网络的输入,由于咱们仅在训练期间使用dropout。 咱们在评估模型时禁用它(稍后再说)。

3.2 EMBEDDING LAYER

咱们定义的第一层是嵌入层,它将词汇词索引映射到低维向量表示中。 它本质上是一个从数据中学习的lookup table。

watermark,size_16,text_QDUxQ1RP5Y2a5a6i,color_FFFFFF,t_100,g_se,x_10,y_10,shadow_90,type_ZmFuZ3poZW5naGVpdGk=

咱们在这里使用了几个功能:

  • tf.device(“/ cpu:0”)强制在CPU上执行操做。 默认状况下,TensorFlow将尝试将操做放在GPU上(若是有的话)可用,可是嵌入式实现当前没有GPU支持,而且若是放置在GPU上会引起错误。

  • tf.name_scope建立一个名称范围,名称为“embedding”。 范围将全部操做添加到名为“嵌入”的顶级节点中,以便在TensorBoard中可视化网络时得到良好的层次结构。

W是咱们在训练中学习的嵌入矩阵。 咱们使用随机均匀分布来初始化它。 tf.nn.embedding_lookup建立实际的嵌入操做。 嵌入操做的结果是形状为[None,sequence_length,embedding_size]的三维张量。

TensorFlow的卷积转换操做具备对应于批次,宽度,高度和通道的尺寸的4维张量。 咱们嵌入的结果不包含通道尺寸,因此咱们手动添加,留下一层shape为[None,sequence_length,embedding_size,1]。

3.3 CONVOLUTION AND MAX-POOLING LAYERS

如今咱们已经准备好构建卷积层,而后再进行max-pooling。 注意:咱们使用不一样大小的filter。 由于每一个卷积产生不一样形状的张量,咱们须要迭代它们,为它们中的每个建立一个层,而后将结果合并成一个大特征向量。

watermark,size_16,text_QDUxQ1RP5Y2a5a6i,color_FFFFFF,t_100,g_se,x_10,y_10,shadow_90,type_ZmFuZ3poZW5naGVpdGk=

这里,W是咱们的滤波器矩阵,h是将非线性应用于卷积输出的结果。 每一个过滤器在整个嵌入中滑动,可是它涵盖的字数有所不一样。 “VALID”填充意味着咱们在没有填充边缘的状况下将过滤器滑过咱们的句子,执行给咱们输出形状[1,sequence_length - filter_size + 1,1,1]的窄卷积。 在特定过滤器大小的输出上执行最大值池将留下一张张量的形状[batch_size,1,num_filters]。 这本质上是一个特征向量,其中最后一个维度对应于咱们的特征。 一旦咱们从每一个过滤器大小获得全部的汇总输出张量,咱们将它们组合成一个长形特征向量[batch_size,num_filters_total]。 在tf.reshape中使用-1能够告诉TensorFlow在可能的状况下平坦化维度。

3.4 DROPOUT LAYER

Dropout多是卷积神经网络正则最流行的方法。Dropout背后的想法很简单。Dropout层随机地“禁用”其神经元的一部分。 这能够防止神经元共同适应(co-adapting),并迫使他们学习个别有用的功能。 咱们保持启用的神经元的分数由咱们网络的dropout_keep_prob输入定义。 在训练过程当中,咱们将其设置为0.5,在评估过程当中设置为1(禁用Dropout)。

watermark,size_16,text_QDUxQ1RP5Y2a5a6i,color_FFFFFF,t_100,g_se,x_10,y_10,shadow_90,type_ZmFuZ3poZW5naGVpdGk=

3.5 SCORES AND PREDICTIONS

使用max-pooling(with dropout )的特征向量,咱们能够经过执行矩阵乘法并选择具备最高分数的类来生成预测。 咱们还能够应用softmax函数将原始分数转换为归一化几率,但这不会改变咱们的最终预测。

这里,tf.nn.xw_plus_b是执行Wx + b矩阵乘法的便利包装器。

watermark,size_16,text_QDUxQ1RP5Y2a5a6i,color_FFFFFF,t_100,g_se,x_10,y_10,shadow_90,type_ZmFuZ3poZW5naGVpdGk=

3.6 LOSS AND ACCURACY

使用分数咱们能够定义损失函数。 损失是对咱们网络错误的衡量,咱们的目标是将其最小化。分类问题的标准损失函数是交叉熵损失 cross-entropy loss。

watermark,size_16,text_QDUxQ1RP5Y2a5a6i,color_FFFFFF,t_100,g_se,x_10,y_10,shadow_90,type_ZmFuZ3poZW5naGVpdGk=

这里,tf.nn.softmax_cross_entropy_with_logits是一个方便的函数,计算每一个类的交叉熵损失,给定咱们的分数和正确的输入标签。 而后求损失的平均值。 咱们也可使用总和,但这比较难以比较不一样批量大小和训练/测试集数据的损失。

咱们还为精度定义一个表达式,这是在训练和测试期间跟踪的有用数值。

watermark,size_16,text_QDUxQ1RP5Y2a5a6i,color_FFFFFF,t_100,g_se,x_10,y_10,shadow_90,type_ZmFuZ3poZW5naGVpdGk=

TensorFlow能够看到其结构图以下:

 

watermark,size_16,text_QDUxQ1RP5Y2a5a6i,color_FFFFFF,t_100,g_se,x_10,y_10,shadow_90,type_ZmFuZ3poZW5naGVpdGk=

3.7 TRAINING PROCEDURE

在咱们为网络定义训练程序以前,咱们须要了解一些关于TensorFlow如何使用Sessions和Graphs的基础知识。若是您已经熟悉这些概念,请随时跳过本节。

在TensorFlow中, Session是正在执行graph 操做的环境,它包含有关变量和队列的状态。每一个 Session都在单个graph上运行。若是在建立变量和操做时未明确使用 Session,则使用TensorFlow建立的当前默认 Session。您能够经过在session.as_default()块中执行命令来更改默认 Session(见下文)。

Graph包含操做和张量。您能够在程序中使用多个Graph,但大多数程序只须要一个Graph。您能够在多个 Session中使用相同的Graph,但在一个 Session中不能使用多Graph。 TensorFlow始终建立一个默认Graph,但您也能够手动建立一个Graph,并将其设置为新的默认Graph,以下图所示。显式建立 Session和Graph可确保在再也不须要资源时正确释放资源。

watermark,size_16,text_QDUxQ1RP5Y2a5a6i,color_FFFFFF,t_100,g_se,x_10,y_10,shadow_90,type_ZmFuZ3poZW5naGVpdGk=

当优选设备不存在时,allow_soft_placement设置容许TensorFlow回退到具备特定操做的设备上。 例如,若是咱们的代码在GPU上放置一个操做,而且咱们在没有GPU的机器上运行代码,则不使用allow_soft_placement将致使错误。 若是设置了log_device_placement,TensorFlow会登陆那些设备(CPU或GPU)进行操做。 这对调试很是有用。 标记是咱们程序的命令行参数。

3.8 INSTANTIATING THE CNN AND MINIMIZING THE LOSS

当咱们实例化咱们的TextCNN模型时,全部定义的变量和操做将被放置在上面建立的默认图和会话中。

watermark,size_16,text_QDUxQ1RP5Y2a5a6i,color_FFFFFF,t_100,g_se,x_10,y_10,shadow_90,type_ZmFuZ3poZW5naGVpdGk=

接下来,咱们定义如何优化网络的损失函数。 TensorFlow有几个内置优化器。 咱们正在使用Adam优化器。

watermark,size_16,text_QDUxQ1RP5Y2a5a6i,color_FFFFFF,t_100,g_se,x_10,y_10,shadow_90,type_ZmFuZ3poZW5naGVpdGk=

在这里,train_op这里是一个新建立的操做,咱们能够运行它们来对咱们的参数执行更新。 train_op的每次执行都是一个训练步骤。 TensorFlow自动计算哪些变量是“可训练的”并计算它们的梯度。 经过定义一个global_step变量并将其传递给优化器,让TensorFlow对训练步骤进行计数。 每次执行train_op时,global step 将自动递增1。

3.9 SUMMARIES

TensorFlow有一个概述(summaries),能够在训练和评估过程当中跟踪和查看各类数值。 例如,您可能但愿跟踪您的损失和准确性随时间的变化。您还能够跟踪更复杂的数值,例如图层激活的直方图。 summaries是序列化对象,并使用SummaryWriter写入磁盘。

watermark,size_16,text_QDUxQ1RP5Y2a5a6i,color_FFFFFF,t_100,g_se,x_10,y_10,shadow_90,type_ZmFuZ3poZW5naGVpdGk=

在这里,咱们分别跟踪培训和评估的总结。 在咱们的状况下,这些数值是相同的,可是您可能只有在训练过程当中跟踪的数值(如参数更新值)。 tf.merge_summary是将多个摘要操做合并到能够执行的单个操做中的便利函数。

3.10 CHECKPOINTING

一般使用TensorFlow的另外一个功能是checkpointing- 保存模型的参数以便稍后恢复。Checkpoints 可用于在之后的时间继续训练,或使用 early stopping选择最佳参数设置。 使用Saver对象建立 Checkpoints。

watermark,size_16,text_QDUxQ1RP5Y2a5a6i,color_FFFFFF,t_100,g_se,x_10,y_10,shadow_90,type_ZmFuZ3poZW5naGVpdGk=

3.11 INITIALIZING THE VARIABLES

在训练模型以前,咱们还须要在图中初始化变量。

watermark,size_16,text_QDUxQ1RP5Y2a5a6i,color_FFFFFF,t_100,g_se,x_10,y_10,shadow_90,type_ZmFuZ3poZW5naGVpdGk=

global_variables_initializer函数是一个方便函数,它运行咱们为变量定义的全部初始值。也能够手动调用变量的初始化程序。 若是但愿使用预先训练的值初始化嵌入,这颇有用。

3.12 DEFINING A SINGLE TRAINING STEP

如今咱们来定义一个训练步骤的函数,评估一批数据上的模型并更新模型参数。

watermark,size_16,text_QDUxQ1RP5Y2a5a6i,color_FFFFFF,t_100,g_se,x_10,y_10,shadow_90,type_ZmFuZ3poZW5naGVpdGk=

feed_dict包含咱们传递到咱们网络的占位符节点的数据。您必须为全部占位符节点提供值,不然TensorFlow将抛出错误。使用输入数据的另外一种方法是使用队列,但这超出了这篇文章的范围。

接下来,咱们使用session.run执行咱们的train_op,它返回咱们要求它进行评估的全部操做的值。请注意,train_op什么都不返回,它只是更新咱们网络的参数。最后,咱们打印当前培训批次的丢失和准确性,并将摘要保存到磁盘。请注意,若是批量过小,训练批次的损失和准确性可能会在批次间显着变化。并且由于咱们使用dropout,您的训练指标可能开始比您的评估指标更糟。

咱们写一个相似的函数来评估任意数据集的丢失和准确性,例如验证集或整个训练集。本质上这个功能与上述相同,但没有训练操做。它也禁用退出。

watermark,size_16,text_QDUxQ1RP5Y2a5a6i,color_FFFFFF,t_100,g_se,x_10,y_10,shadow_90,type_ZmFuZ3poZW5naGVpdGk=

3.13 TRAINING LOOP

最后,准备编写训练循环。 迭代数据的批次,调用每一个批次的train_step函数,偶尔评估和检查咱们的模型:

watermark,size_16,text_QDUxQ1RP5Y2a5a6i,color_FFFFFF,t_100,g_se,x_10,y_10,shadow_90,type_ZmFuZ3poZW5naGVpdGk=

这里,batch_iter是一个批处理数据的帮助函数,而tf.train.global_step是返回global_step值的便利函数。

3.14 VISUALIZING RESULTS IN TENSORBOARD

咱们的训练脚本将summaries写入输出目录,并将TensorBoard指向该目录,咱们能够将图和咱们建立的summaries可视化。

watermark,size_16,text_QDUxQ1RP5Y2a5a6i,color_FFFFFF,t_100,g_se,x_10,y_10,shadow_90,type_ZmFuZ3poZW5naGVpdGk=

有几件事情脱颖而出:

  • 咱们的训练指标并不平滑,由于咱们使用小批量。 若是咱们使用较大的批次(或在整个训练集上评估),咱们会获得一个更平滑的蓝线。

  • 由于测试者的准确性显着低于训练准确度,咱们的网络在训练数据彷佛过拟合了,这代表咱们须要更多的数据(MR数据集很是小),更强的正则化或更少的模型参数。 例如,我尝试在最后一层为重量添加额外的L2正则,而且可以将准确度提升到76%,接近于原始文献。

  • 由于使用了dropout,训练损失和准确性开始大大低于测试指标。

您可使用代码进行操做,并尝试使用各类参数配置运行模型。 Github提供了代码和说明。

4. EXTENSIONS AND EXERCISES

如下是一些的练习,能够提升模型的性能:

  • 使用预先训练的word2vec向量初始化嵌入。 为了可以起做用,您须要使用300维嵌入,并用预先训练的值初始化它们。

  • 限制最后一层权重向量的L2范数,就像原始文献同样。 您能够经过定义一个新的操做,在每次训练步骤以后更新权重值。

  • 将L2正规化添加到网络以防止过拟合,同时也提升dropout比率。 (Github上的代码已经包括L2正则化,但默认状况下禁用)

  • 添加权重更新和图层操做的直方图summaries,并在TensorBoard中进行可视化。

 

 

watermark,size_16,text_QDUxQ1RP5Y2a5a6i,color_FFFFFF,t_100,g_se,x_10,y_10,shadow_90,type_ZmFuZ3poZW5naGVpdGk=

相关文章
相关标签/搜索