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