目录网络
写这篇博客主要是为了进一步了解如何将CNN看成Encoder结构来使用,同时这篇论文也是必看的论文之一。该论文证实了使用CNN做为特征抽取结构实现Seq2Seq,能够达到与 RNN 相接近甚至更好的效果,而且CNN的高并行能力可以大大减小咱们的模型训练时间(本文对原文中不清晰的部分作了梳理,建议与原文搭配服用)ide
原文连接:Convolutional Sequence to Sequence Learning函数
模型结构以下图所示:
编码
下面对模型的每一个部分进行分块介绍:spa
卷积网络和Transformer同样,不是相似于RNN的时序模型,所以须要加入位置编码来体现词与词之间的位置关系设计
GLU和GTU是在同一篇论文中提出的,其中,GLU也是CNN Seq2Seq的主要结构。能够直接将其看成激活函数来看待,其将某以卷积核的输出输入到两个结构相同的卷积网络,令其中一个的输出为\(A\),另外一个为\(B\)。
GLU与GRU的区别就在于A输出的激活函数不一样:
\[GLU:H_0=A \otimes \sigma (B)\]code
\[GTU:H_0=tanh(A) \otimes \sigma (B)\]orm
而CNN Seq2Seq就采用了GLU做为模型的激活函数对象
原文连接:Language Modeling with Gated Convolutional Networksblog
编码器与解码器都是由多个卷积层构成的(原文中称为block,实际上就是layer),每一层包含一个1维卷积核以及一个门控线性单元(Gated linear units, GLU)。假设单词数即输入长度为\(m\),kernel大小为\(k\),pad为\(p\),那么计算输出sequence长度的公式为\((m+2p-k)/stride+1\),只要适当的设置卷积核的kernel大小、pad以及步长参数,便可使得输出序列与输入序列的维度保持一致。在文中,输入为25,kernel为5,则输出序列长度为(25+2*2-5)/1+1=25。
另外,为了充分让输出节点跟整个sequence单词有联系,必须使用多个卷积层,这样才能使得最后一个卷积核有足够大得感觉野以感觉整个句子的特征,同时也能捕捉局部句子的特征。
来看一下整个编码器的前向传播方式:
这样的卷积策略保证了每一层的输入与输出序列的一一对应,而且可以将其看做简单的编码器单元,多层堆叠以实现更深层次的编码。
对于Attention的计算,关键就是找到 Query、Key 和 Value。下图为计算Attention且解码的示意图
Attention的计算过程以下:
Query由decoder的最后一个卷积层的输出\(h_i^l\)以及上一时刻decoder最终的生成的目标\(g_i\)共同决定,\(W^l_d\)与\(b_d^l\)为线性映射的参数。
\[d_i^l = W^l_dh^l_i+b_d^l+g_i\]
Key 则采用 Encoder 的输出\(z_j^u\),典型的二维匹配模型,将 Query 与 Key 一一对齐,计算 dot attention分数:
\[a_{ij}^l = \frac{exp(d^l_i \cdot z^u_j)}{\sum_{t=1}^mexp(z_j^u+e_j)}\]
Value 的值则取编码器的输出\(z_j^u\)以及词向量表征\(e_j\)之和,目的是为编码器的输出加上位置表征信息。获得对应的 Value 值 \(c_i^l\) 以后,直接与当前时刻的 Decoder 输出 \(h_i^l\) 相加,再输入分类器进行分类。
\[c_i^l = \sum_{j=1}^ma_{ij}^l(z_j^u + e_j)\]
模型还经过归一化策略来保证经过每一层模型的方差变化不会太大,这里先简单的记录一下,具体的操做细节须要回去仔细琢磨代码。归一化的主要策略以下:
初始化的目的与归一化是一致的,即都是为了保证前向与后项传播的数据方差可以保持在一个较稳定的水准,模型初始化的策略以下:
最后的实验部分就不记录了,有兴趣的同窗能够去原文里看看。
https://zhuanlan.zhihu.com/p/26918935
https://zhuanlan.zhihu.com/p/27464080
https://www.zhihu.com/question/59645329/answer/170014414