CNN的语言模型
学习资料:
- 本节的全部代码
- 代码依赖的 utils.py 和 visual.py 在这里找到
- 我制作的 自然语言句子理解 短片简介
- 给句子分类的 CNN 语言模型:Convolutional Neural Networks for Sentence Classification
怎么了¶
一想到用深度学习解决语言问题,我们自然而然的就能想到使用循环神经网络RNN这一系列的模型。 而像CNN这种专注于图像处理的模型在语言领域也能胜任吗?答案是可以的。 我们在这个短片简介中了解到一句话放在深度学习中, 它其实也就是一段句向量。不管用什么样的模型,只要能将文字有效地转化成向量,那么这就会是一个好模型。
而这次,我们就尝试使用一种CNN模型,把文字描述转化成向量表达。用一句话来概括这个CNN语言模型,我想可以这样说: 用N个不同长度时间窗口,以CNN的卷积方法在句子中依次滑动,让模型拥有N种阅读的眼界宽度,综合N种宽度的信息总结出这句话的内容。
怎么卷积¶
上次我们提到了Encoder Decoder的概念, 这次的CNN语言模型重视的是怎么样使用CNN当做文字内容提取的Encoder。
CNN最擅长的事就是卷积,但是相比图像中的卷积,在句子中的卷积起到的作用是特殊的,学者想利用CNN去利用不同长度的卷积核去观察句子中不同长度的局部特征。 然后CNN对句子的理解就是不同长度的局部特征拼凑起来的理解。
比如:
- 卷积核A两个两个字一起看;
- 卷积核B三个三个字一起看;
- 卷积核C四个四个字一起看;
卷积核ABC利用自己看句子的独特视角,能够提炼出对句子不同的理解,然后如果再汇集这些不同理解,就有了一个对句子更加全面的理解。
翻译¶
在这节内容中,我还是以翻译为例。有了上次Seq2Seq 的经验,我们知道在翻译的模型中,实际上是要构建一个Encoder,一个Decoder。 这节CNN做文字翻译的内容中,我们更关注的是用CNN的方法来做Encoder,让计算机读懂句子,至于Decoder,我们还是使用Seq2Seq当中的RNN Decoder来实现。
秀代码¶
我使用一个非常简单,好训练的日期转换的例子来展示一下CNN的语言理解能力。需要实现的功能如下:
# 中文的 "年-月-日" -> "day/month/year"
"98-02-26" -> "26/Feb/1998"
我们将中文的顺序日期,转成英文的逆序日期,数据区间是20世纪后期到21世纪前期。 为了施加一些难度,在中文模式下,我不会告诉机器这是哪一个世纪,需要计算机自己去判断转成英文的时候是 20 世纪还是 21 世纪。
先来看训练过程(只想看全套代码的请点这里), 其实也很简单,生成数据,建立模型,训练模型。
最后你能看到它的整个训练过程。最开始预测成渣渣,但是后面预测结果会好很多。不过最后这个CNN的模型可能是应为参数量还不够大的关系, 预测并不是特别准确,不过将就能用~
t: 0 | loss: 3.293 | input: 96-06-17 | target: 17/Jun/1996 | inference: /////1///99
t: 70 | loss: 1.110 | input: 91-08-19 | target: 19/Aug/1991 | inference: 03/Feb/2013<EOS>
t: 140 | loss: 0.972 | input: 11-04-30 | target: 30/Apr/2011 | inference: 10/Sep/2001<EOS>
t: 210 | loss: 0.828 | input: 76-03-14 | target: 14/Mar/1976 | inference: 16/May/1977<EOS>
...
t: 1400 | loss: 0.183 | input: 86-10-14 | target: 14/Oct/1986 | inference: 14/Oct/1986<EOS>
t: 1470 | loss: 0.151 | input: 18-02-08 | target: 08/Feb/2018 | inference: 05/Feb/2018<EOS>
这节内容最重要的代码内容就在下方,我们动手搭建一下它的Encoder部分。为本节的例子,我们使用3个Conv2D
的卷积层,这三个对不同长度的局部信息做卷积, 所以他们的结构都不一样,然后再用MaxPool2D
去将他们归一化到同一dimension。这样就可以将最后的所有局部信息汇总,加工成句向量了。
接下来的Decoder部分就和Seq2Seq中一模一样了,decoder在训练是和句子生成时是不同的。为了方便训练,尤其是在刚开始训练时,decoder的输入如果是True label,那么就能大大减轻训练难度。 不管在训练时有没有预测错,下一步在decoder的输入都是正确的。
而在生产环境中预测时,真的在做翻译时,我们就希望有另一种decode的sample方式。使decoder下一步的预测基于decoder上一步的预测,而不是true label。
所以在seq2seq中,为了加快训练速度,我们一般使用的training和inference的decode方式是有所不同的。inference的时候,那没办法,只能拿着上次decode的词作为下一步的input, 因为没有label可以参考。但是在training时却可以拿着label过来加强训练的有效性。
局限性¶
不知道你有没有思考过,CNN做句向量encoding的时候有一个局限性,它要求有个句子最长的限制,句子如果超过这个长度,那么就最好截断它。 因为就像在给图像做卷积,图像也是要定长定宽的,不然卷积和池化会有尺度上的问题。这是一个相比RNN的硬伤。之后我们在介绍Transformer类型的语言模型时, 也会介绍到这个硬伤。
总结¶
这一节内容我们见识到CNN同样也能够做句向量的encoding,但是在decoder的时候,我们还是延续了之前的RNN decoder模式。现在我们已经了解了RNN和CNN两种模式的语言模型, 这放在10年前,算是最先进的技术了,但是到了现在,学者们玩起了一种叫Attention的东西,下节内容我们就来介绍Attention,注意力在语言模型中的重要地位。