CNN最初是用于图像分类。因为图像的分类信息往往只是体现在图像的某个局部特征上,而CNN能通过训练,去寻找这个局部特征。CNN在图像里,采用的是2D的卷积,如图所示。
NLP中,对一段文字进行分类(比如情感分析)时,和图像一样,往往是局部的几个词会体现出要表达文字的情感,因此也可以用CNN进行处理。
和RNN不同,RNN适用于要根据整段话,提炼出相应的信息。因此RNN需要将这段文字进行encoder-decoder处理。CNN则适用于要抓取某几个词判断“情感”的场合。
此外,RNN实际上是“串行处理”,其运行速度较慢。而CNN可以采用并行处理的方式,运行速度比RNN快。
而在NLP中,同样可以把要处理的一句话看成图像。可以将一句话中的多个词排成一列,每一行代表着对应的这个词的词向量。这样,也就把NLP的问题也变成了图像问题,NLP的分类问题也就可以应用图像分类所采用的CNN了。
关于卷积
当然在NLP的CNN中,采用2D卷积,“横向”挪动卷积核其实是没有意义的。因为词向量本身就是一个完整的向量,不能再“拆”。因此卷积核只能“竖”着移动,这样在NLP中,实际上使用的是1D的卷积。卷积核的“宽度”必须和词向量的长度保持一致。
在图像分类中,输入到CNN的每幅图长宽的像素是一定的,所以同理在NLP中,输入到CNN的句子的长度也必须是定长的,不够长的只能补<pad>。
以下就是采用三个卷积核,采用了padding,并取max_pooling的计算过程。
max也可以换成avg,但目前并没有证据证明avg的性能比max更好。
max也能换成k-max,但同样也没有证据证明这种方式比max更好。
和图像分类相同,NLP也可以设置卷积时的stride, local-maxpooling等。
CNN数学表述
假设只有一个卷积核。对于由
n
n
n个单词组成的一句话,
x
1
:
n
=
x
1
⊕
x
2
⊕
.
.
.
⊕
x
n
\mathbf x_{1:n}=\mathbf x_1 \oplus \mathbf x_2 \oplus ... \oplus \mathbf x_n
x1:n=x1⊕x2⊕...⊕xn,其中词向量
x
i
∈
R
k
\mathbf x_i \in \mathbb R^k
xi∈Rk。取窗口大小为
h
h
h,卷积的向量
w
∈
R
h
k
\mathbf w \in \mathbb R^{hk}
w∈Rhk,经过卷积后,输出的向量为
c
=
[
c
1
,
c
2
,
.
.
.
,
c
n
−
h
+
1
]
\mathbf c=[c_1,c_2,...,c_{n-h+1}]
c=[c1,c2,...,cn−h+1],其中
c
i
=
f
(
w
T
x
i
:
i
+
h
−
1
+
b
)
c_i = f(\mathbf w^T \mathbf x_{i:i+h-1} + b)
ci=f(wTxi:i+h−1+b)
在对向量取max_pooling,得到
c
^
=
m
a
x
{
c
}
\hat c=max\{\mathbf c\}
c^=max{c}
这样,一个卷积核最终得到一个数值。同一个
h
h
h可以采用不同的卷积核,也可以采用不同的
h
h
h。如果采用
m
m
m个卷积核,就会有
m
m
m个输出,即
z
=
[
c
^
1
,
.
.
.
,
c
^
m
]
\mathbf z=[\hat c_1,...,\hat c_m]
z=[c^1,...,c^m]。对输出取Dropout,再经过全连接层并softmax,就可以得到
y
=
s
o
f
t
m
a
x
(
W
S
(
r
⊙
z
)
+
b
S
)
\mathbf y = softmax(\mathbf W^S (\mathbf r \odot \mathbf z)+\mathbf b^S)
y=softmax(WS(r⊙z)+bS)
其中
r
\mathbf r
r是
z
\mathbf z
z形状相同的向量,元素为0或1,取1的概率为
p
p
p.
在test阶段,不能取Dropout,而是要采用
W ^ S = p W S \mathbf{\hat W}^S=p \mathbf W^S W^S=pWS
CNN改进:Residual
同样为了解决深层神经网络的梯度消失问题,也可以采用把输入加到输出
也有论文通过类似于GRU和LSTM的机制,通过参数控制要将
x
\mathbf x
x传多少到下一层。但是并没有证据证明这种做法比直接传的效果会更好。
CNN改进2:batchNorm
也有论文建议,对每个batch在卷积的输出进行标准化,转换成均值为0,方差为1的数。这种做法可以使得模型能够不依赖于初始值。
CNN:关于1x1卷积
采用1x1的卷积,相当于可以将输入进行降维,作用类似于全连接的操作,但是需要的变量比全连接要少。
CNN和RNN的组合
有论文在机器翻译里,在encoder采用CNN,在decoder采用RNN。也有采用QRNN,其结构如图所示
其思想是,首先对输入的词
x
1
,
.
.
.
,
x
T
\mathbf x_1,...,\mathbf x_T
x1,...,xT用3组
m
m
m个长度为
k
k
k卷积核进行卷积,分别得到输出
z
t
,
f
t
,
o
t
\mathbf z_t, \mathbf f_t, \mathbf o_t
zt,ft,ot,再利用LSTM类似的方法,产生相应的hidden state,
h
t
\mathbf h_t
ht和cell state,
c
t
\mathbf c_t
ct。再对输出的
h
t
\mathbf h_t
ht进行RNN中相同的处理。测试结果表明,其速度可以比LSTM快很多,而且准确率在层数较高时也能比LSTM略强。
CNN: VD-CNN
基于上述提到的Residual和BatchNorm技术,可以构建深层的CNN网络。和VGNet类似,VDCNN按照如图配置。
这里输入到VDCNN是基于字符的向量,
s
=
1024
s=1024
s=1024表示字符数,每个字符以16维的向量代替。这里的每一层卷积都采用了padding=“same"的参数。对于每个Convolutional block,其结构为
具体的代码实现在github上:
- tensorflow的实现地址是:https://github.com/wenanshi/VDCNN
- keras的实现地址是https://github.com/zonetrooper32/VDCNN
从测试结果看,和VGNet不同,VDCNN从17层-29层时,性能的改善已经非常小了。