利用卷积神经网络的Text-CNN 文本分类

简介

TextCNN 是利用卷积神经网络对文本进行分类的算法,由 Yoon Kim 在 “Convolutional Neural Networks for Sentence Classification” 一文 (见参考[1]) 中提出. 是 2014 年的算法.

图 1-1 参考[1] 中的论文配图

在这里插入图片描述

以下是阅读 TextCNN 后的理解

步骤:

1.先对句子进行分词,一般使用“jieba”库进行分词。

2.在原文中,用了 6 个卷积核对原词向量矩阵进行卷积。

卷积具有局部特征提取的功能, 所以可用 CNN 来提取句子中类似 n-gram 的关键信息.

个卷积核大小:2 个 46、2 个 36 和 2 个 2*6,如上图所示;然后进行池化,对相同卷积核产生的特征图进行连接;再进行 softmax 输出 2 个类别。

1).这里对 no-static 进行阐述,采用不固定的词向量,这样更加贴近自然生活中,不同长度的句子代表的意思不同,所以在我看来采用 no-static 比 static 更加的贴近语义。

2).对一个词向量进行卷积和池化后,产生的特征只有一个 1*1 的向量,所以说不管采用 static 和 no-static 得到的特征都只有一个,对本生网络没什么影响。

为什么采用不同大小的卷积核,不同的感受视野,卷积核的宽取词汇表的纬度,有利于语义的提取。

体现在代码中

tf.flags.DEFINE_string("filter_sizes", "3,4,5", "Comma-separated filter sizes (default: '3,4,5')")
filter_sizes=list(map(int, FLAGS.filter_sizes.split(","))),

是一个 list

5.研究证明为什么要采用字,而不采用字,原因是词粒度准确率 > 字粒度准确率。存在两种模型,一种是词袋模型,第二种是词向量模型。下面对词向量模型来进行讲述。

词向量模型:

一般开始为高纬度,高稀疏向量,利用嵌入层对其进行降维,增加稠密性。

使用词向量进行文本分类的步骤为:

①.先使用分词工具提取词汇表。

②.将要分类的内容转换为词向量。

a.分词

b.将每个词转换为 word2vec 向量。

c.按顺序组合 word2vec,那么久组合成了一个词向量。

d.降维,由原来的高纬度降维为我们设定的低纬度。

e.卷积、池化和连接,然后进行分类。

6.嵌入层

通过一个隐藏层将 word2vec 高纬度的词向量转换到低纬度空间的词向量,这个层的本质是特征提取,提取高纬度词向量的特征到低纬度,这样可以使语义相近的词映射到低维空间以后,欧式距离更近。

参数与超参数

sequence_length
Q: 对于 CNN, 输入与输出都是固定的,可每个句子长短不一, 怎么处理?
A: 需要做定长处理, 比如定为 n, 超过的截断, 不足的补 0. 注意补充的 0 对后面的结果没有影响,因为后面的 max-pooling 只会输出最大值,补零的项会被过滤掉.

num_classes
多分类, 分为几类.

vocabulary_size
语料库的词典大小, 记为 |D|.

embedding_size
将词向量的维度, 由原始的 |D| 降维到 embedding_size.

filter_size_arr
多个不同 size 的 filter.

Embedding Layer

首先用 VocabularyProcessor 将 每一句话 转为 词 id 向量

在这里插入图片描述

然后定义了词嵌入矩阵,将输入的词 id 转化成词向量,这里的词嵌入矩阵是可以训练的,我们希望得到的是训练完以后,输入经过 W 矩阵转换得到的固定维度的隐藏层,及词向量矩阵通过一个词嵌入矩阵, 将 编码的词投影到一个低维空间中.

本质上是特征提取器,在指定维度中编码语义特征. 这样, 语义相近的词, 它们的欧氏距离或余弦距离也比较近.

self.embedded_chars=tf.nn.embedding_lookup(W,self.input_x)

在这里插入图片描述

如果先用 word2vec_helpers 处理完,然后代用 textCNN 的情况下,这里的 embeding 层是不是就不要了?

原始的在没有预先使用 word2vec 的情况下:在网络层有 embeding 层

在这里插入图片描述

而预先使用了 word2vec_helpers 处理完之后,

在这里插入图片描述

Convolution Layer

为不同尺寸的 filter 都建立一个卷积层. 所以会有多个 feature map.
图像是像素点组成的二维数据, 有时还会有 RGB 三个通道, 所以它们的卷积核至少是二维的.
从某种程度上讲, word is to text as pixel is to image, 所以这个卷积核的 size 与 stride 会有些不一样.

xixi
xi∈Rkxi∈Rk, 一个长度为 n 的句子中, 第 i 个词语的词向量, 维度为 k.

xi:jxi:j
xi:j=xi⊕xi+1⊕…⊕xjxi:j=xi⊕xi+1⊕…⊕xj
表示在长度为 n 的句子中, 第 [i,j] 个词语的词向量的拼接.

hh
卷积核所围窗口中单词的个数, 卷积核的尺寸其实就是 hkhk.

ww
w∈Rhkw∈Rhk, 卷积核的权重矩阵.

cici
ci=f(wxi:i+h1+b)ci=f(wxi:i+h1+b), 卷积核在单词 i 位置上的输出.b∈RKb∈RK, 是 bias.ff 是双曲正切之类的激活函数.

c=[c1,c2,…,cnh+1]c=[c1,c2,…,cnh+1]
filter 在句中单词上进行所有可能的滑动, 得到的 featuremapfeaturemap.

Max-Pooling Layer

max-pooling 只会输出最大值, 对输入中的补 0 做过滤.

SoftMax 分类 Layer

最后接一层全连接的 softmax 层,输出每个类别的概率。

  • 小的变种

  • 在 word representation 处理上会有一些变种.

  • CNN-rand
    设计好 embedding_size 这个 Hyperparameter 后, 对不同单词的向量作随机初始化, 后续 BP 的时候作调整.

  • static
    拿 pre-trained vectors from word2vec, FastText or GloVe 直接用, 训练过程中不再调整词向量. 这也算是迁移学习的一种思想.

  • non-static

  • pre-trained vectors + fine tuning , 即拿 word2vec 训练好的词向量初始化, 训练过程中再对它们微调.

  • multiple channel
    类比于图像中的 RGB 通道, 这里也可以用 static 与 non-static 搭两个通道来搞.

一些结果表明,max-pooling 总是优于 average-pooling ,理想的 filter sizes 是重要的,但具体任务具体考量,而用不用正则化似乎在 NLP 任务中并没有很大的不同。

Text CNN 的 tf 实现
图 8-1 Text CNN 网络中的卷积与池化 结构

需要注意的细节有。
tf.nn.embedding_lookup()

与 LeNet 作比较

在这里插入图片描述

figure LeNet-5 网络结构

# LeNet5
conv1_weights = tf.get_variable(
                    "weight",
                    [CONV1_SIZE, CONV1_SIZE, NUM_CHANNELS, CONV1_DEEP],
                    initializer=tf.truncated_normal_initializer(stddev=0.1))
                tf.nn.conv2d(
                    input_tensor,
                    conv1_weights,
                    strides=[1, 1, 1, 1],
                    padding='SAME')
                tf.nn.max_pool(
                    relu1,
                    ksize = [1,POOL1_SIZE,POOL1_SIZE,1],
                    strides=[1,POOL1_SIZE,POOL1_SIZE,1],
                    padding="SAME")
# TextCNN
                conv1_weights = tf.get_variable(
                                    "weight",
                                    [FILTER_SIZE, EMBEDDING_SIZE, 1, NUM_FILTERS],
                                    initializer=tf.truncated_normal_initializer(stddev=0.1))
                                tf.nn.conv2d(
                                    self.embedded_chars_expanded,
                                    conv1_weights,
                                    strides=[1, 1, 1, 1],
                                    padding="VALID")
                                tf.nn.max_pool(
                                    h,
                                    ksize=[1, SEQUENCE_LENGTH - FILTER_SIZE + 1, 1, 1],
                                    strides=[1, 1, 1, 1],
                                    padding='VALID')

先来比较卷积

LeNet 的 filter 是正方形的, 且每一层都只用了同一种尺寸的卷积核. Text-CNN 中, filter 是矩形, 矩形的长度有好几种, 一般取 (2,3,4), 而矩形的宽度是定长的, 同 word 的 embedding_size 相同. 每种尺寸都配有 NUM_FILTERS 个数目, 类比于 LeNet 中的 output_depth,所以得到的 feature_map 是长条状, 宽度为 1.
因为是卷积, 所以 stride 每个维度都是 1.

再说池化层.

池化处理, 也叫下采样. 这里依旧可以对比 LeNet 网络.
LeNet 的 kernel 是正方形, 一般也是 2*2 等, 所以会把卷积后的 feature_map 尺寸缩小一半.
Text-CNN 的 kernel 依旧是长方形, 将整个 feature_map 映射到一个点上. 一步到位, 只有一个池化层.

全连接层

都是多分类, 这一步的处理比较类似. 将池化后的矩阵 reshape 为二维, 用 tf.nn.sparse_softmax_cross_entropy_with_logits() 计算损失.

TextCNN 论文中的网络结构

windows size 分别取 (3,4,5), 每个尺寸都会有 100 个 filter.

Hyperparameters and Training
For all datasets we use:
rectified linear units, filter
windows (h) of 3, 4, 5 with 100 feature maps each,
        dropout rate (p) of 0.5, l2 constraint (s) of 3, and
        mini-batch size of 50. These values were chosen
        via a grid search on the SST-2 dev set.
        1
Logo

技术共进,成长同行——讯飞AI开发者社区

更多推荐