作为一个NLP届的菜鸟,想把自己学到的一点知识写下来,一是帮助自己梳理知识;二是希望能够帮到一些打算入门以及正在入门的NLPer.由于我的文笔挺差的,以及学识有限,有不忍直视的地方,请多包涵。
github上有很多关于TextCNN的开源项目,从里面可以获得大量练手的数据。我在学TextCNN的时候,是在了解了cnn的基本原理之后,从github上下载了几个我觉得看着比较顺眼的(我就是觉得代码风格比较喜欢)。然后再按照自己的代码风格以及对于代码的理解进行重现。本文重点介绍TextCNN在tensorflow中的实行,所有数据均来自github,已有标签。首先根据实际数据,介绍数据预处理过程;最后说明tensorflow中的CNN实现。
1.TxetCNN数据预处理
1.1 词向量
打算自己训练词向量的同学,可以使用gensim,方便快捷,当然使用tensorflow来做也是可以的。下面是使用gensim训练词向量的代码。
size是词向量的维度,sg=0,是用cbow进行训练,sg=1,使用sg进行训练。
1.2 文本分词
有了打标签的文本,接下来当然是要处理它了啊。上代码。。。
这步的操作主要是对文本分词,然后得到文本列表,标签列表。举个🌰。
content=[['文本','分词'],['标签','列表'];label=['A','B']
1.3 建立词典,词典词向量
不能是个词我就要吧。那怎么办呢?去停用词!去了停用词之后,取文本(这个文本指的是所有文本,包括训练、测试、验证集)中前N个词,表示这N个词是比较重要的,然后保存。之前训练的词向量是个数据量很大集合。很多词,我已经不需要了,我只要这N个词的词向量。同样是上代码。
我提取了文本的前9999个比较重要的词,并按顺序保存了下来。embeddings= np.zeros([10000, 100]) 表示我建立了一个10000个词,维度是100的词向量集合。然后将9999个词在大词向量中的数值,按1-9999的顺序,放入了新建的词向量中。第0项,让它保持是100个0的状态。
1.4 建立词典
这部分比较简单,直接上代码。
注意:词典里面词的顺序,要跟新建的词向量中词的顺序一致。
1.5 标签词典
将标签也词典一下。
1.6 Padding的过程
padding是将所有句子进行等长处理,不够的在句子最后补0;将标签转换为one-hot编码。
首先将句子中的词,根据词典中的索引,变成全数字的形式;标签也进行同样处理。然后,根据max_length(句子最大长度)进行padding,得到x_pad,标签转换one-hot格式。好了,到这里文本的预处理,告一段落!
1.7 读取所需数据
我们保存了10000词的词向量,我们要读取它,还有处理的句子,我们也要分批,输入进模型。
在代码里,我用一个例子,解释了np.random.permutation的作用。
2.tensorflow中的TextCNN
2.1 定义占位符
2.2 embedding
vocab_size:是词的个数,在这里是10000;
embedding_size:是词向量尺寸,这里是100;
embedding_lookup:我把它看成与excel vlookup类似的查找函数,是将embedding中的词向量根据input_x中的数字进行索引,然后填充。比如,input_x中的3,将input_x中的3用embedding中的第三行的100个数字进行填充,得到一个tensor:[batch_size,seq_length,embedding_size].
因为,卷积神经网络中的,conv2d是需要4维张量的,故用tf.expand_dims在embedding_input最后再补一维。
3.3 卷积层
filte 高度设定为【2,3,4】三种,宽度与词向量等宽,卷积核数量设为num_filter。假设batch_size =1,即对一个句子进行卷积操作。每一种filter卷积后,结果输出为[1,seq_length - filter_size +1,1,num_filter]的tensor。再用ksize=[1,seq_length - filter_size + 1,1,1]进行max_pooling,得到[1,1,1,num_filter]这样的tensor.将得到的三种结果进行组合,得到[1,1,1,num_filter*3]的tensor.最后将结果变形一下[-1,num_filter*3],目的是为了下面的全连接。再次有请代码。
3.4 全连接层
在全连接层中进行dropout,通常保持率为0.5。其中num_classes为文本分类的类别数目。然后得到输出的结果scores,以及得到预测类别在标签词典中对应的数值predicitons。
3.5 loss
这里使用softmax交叉熵求loss, logits=self.scores 这里一定用的是未经过softmax处理的数值。
3.6 optimizer
这里使用了梯度裁剪。首先计算梯度,这个计算是类似L2正则化计算w的值,也就是求平方再平方根。然后与设定的clip裁剪值进行比较,如果小于等于clip,梯度不变;如果大于clip,则梯度*(clip/梯度L2值)。
3.7 accuracy
最后,计算模型的准确度。
3.8 训练模型
模型迭代次数为5,每完成一轮迭代,模型保存一次。当global_step为100的整数倍时,输出模型的训练结果以及在测试集上的测试结果。
一个batch中训练集最好准确度达到98%,同时在测试集上的结果达到100%。接下来,我们看看保存的模型在验证集上的效果。
3.9 模型验证
验证集有5000条语句,我用最后一次保存的模型,对5000条句子进行预测,将预测的结果与原标签进行对比,得到验证集上的准确率,结果表明在整个验证集上准确达到96.58%,并输出前10条语句,将预测结果与原结果进行对比。
整个模型的流程,分析完毕。流程和文中的TextCNN过程图基本一致。因学识有限,文中难免有描述不对的地方,请各位批评指正。希望我的文章,能够帮到大家。
本文代码地址:https://github.com/NLPxiaoxu/Easy_TextCnn_Rnn
参考文献:
《Convolutional Neural Networks for Sentence Classification》
https://github.com/cjymz886/text-cnn
http://www.wildml.com/2015/12/implementing-a-cnn-for-text-classification-in-tensorflow