CS224n系列:
【CS224n】Neural Networks, Backpropagation
【CS224n】Neural-Dependency-Parsing
【CS224n】Language Models, RNN, GRU and LSTM
【CS224n】Neural Machine Translation with Seq2Seq
【CS224n】ConvNets for NLP
1. Language Models
作业实现代码:Neural-machine-translation
Corpus BLEU: 35.18
1.1 Introduction
语言模型表示句子中的词共现的概率:
关于语言模型这一块的具体内容,可以参考我的另一篇博客:word2vec原理剖析
1.2 n-gram Language Models
原始的语言模型计算量非常大,因此有了n-gram语言模型,下图分别表示bigram和trigram模型:
n-gram语言模型存在两个问题:稀疏性和存储空间大。
for example,公式3的分子要求三个词同时出现,但更多情况情况是,这些词共现的次数为0,那这时候需要做平滑处理;当分母两个词没有同时出现时,此时不能计算概率,需要做回退(backoff)。
存储空间大是指,我们需要存储很多n-gram词组,当n很大,这个存储空间呈指数级增长。
1.3 Window-based Neural Language Model
神经语言模型是Bengio提出的第一次将深度学习用于自然语言处理模型:
公式:
2. Recurrent Neural Networks (RNN)
RNN是指循环神经网络,如下图:
公式:
值得注意的是,在每个时间步中的权重
W
(
h
h
)
W^{(hh)}
W(hh)和
W
(
h
x
)
W^{(hx)}
W(hx)都是参数共享的。这样做有两个好处:一个是减少模型需要学习的参数量,另一个是可以使得模型对语料的输入长度不敏感。
2.1 RNN Loss and Perplexity
RNN的损失函数也是交叉熵:
困惑度:
困惑度越低,表示预测结果的置信度越高。
2.2 Advantages, Disadvantages and Applications of RNNs
优点:
- 输入可以是任意长度(过长截断,过短补齐);
- 模型大小并不会因为长度的增加而增大(因为参数共享);
- 计算第t个时间步可以使用很多步之前的信息(理论上);
- 相同的权重应用于输入的每个时间步,因此在处理输入时存在对称性;
缺点: - 计算过程很慢(序列化模型,没办法做并行计算);
- 当序列很长时,会出现梯度消失或梯度爆炸的问题。
2.3 Vanishing Gradient & Gradient Explosion Problems
梯度消失/梯度爆炸问题是因为RNN在反向传播过程中,更早的时间步的梯度存在累乘步骤,因而很容易导致梯度为0或者无穷大。具体可以看以下的反向传播过程:
计算RNN对权重W的梯度:
使用链式法则可以得到:
因为W是参数共享的,所以
h
t
h_t
ht对于W的梯度必须是前t个时刻的梯度之和,所以才有上述公式的求和过程。其中,
这个公式怎么理解呢?我们可以先回顾下
h
t
h_t
ht与
h
t
−
1
h_{t-1}
ht−1的关系:
h
t
=
f
(
W
(
h
h
)
h
t
−
1
+
W
(
h
x
)
x
[
t
]
)
h_t=f(W^{(hh)}h_{t-1}+W^{(hx)}x_{[t]})
ht=f(W(hh)ht−1+W(hx)x[t])
一个个解释,首先,累乘是因为链式法则,例如:
∂
h
4
∂
h
2
=
∂
h
4
∂
h
3
∂
h
3
∂
h
2
\frac{\partial h_4}{\partial h_{2}}=\frac{\partial h_4}{\partial h_{3}}\frac{\partial h_3}{\partial h_{2}}
∂h2∂h4=∂h3∂h4∂h2∂h3
其次,
即
∂
h
j
∂
h
j
−
1
=
W
T
×
d
i
a
g
[
f
′
(
j
j
−
1
)
]
\frac{\partial h_j}{\partial h_{j-1}}=W^T \times diag[f^{'}(j_{j-1})]
∂hj−1∂hj=WT×diag[f′(jj−1)]
当激活函数为sigmoid时,
∂
h
j
∂
h
j
−
1
=
W
T
×
d
i
a
g
[
f
′
(
j
j
−
1
)
]
=
W
T
×
d
i
a
g
[
σ
(
1
−
σ
)
]
\frac{\partial h_j}{\partial h_{j-1}}=W^T \times diag[f^{'}(j_{j-1})]= W^T \times diag[\sigma(1-\sigma)]
∂hj−1∂hj=WT×diag[f′(jj−1)]=WT×diag[σ(1−σ)]
当激活函数为tanh时,
∂
h
j
∂
h
j
−
1
=
W
T
×
d
i
a
g
[
f
′
(
j
j
−
1
)
]
=
W
T
×
d
i
a
g
[
1
−
(
t
a
n
h
)
2
]
\frac{\partial h_j}{\partial h_{j-1}}=W^T \times diag[f^{'}(j_{j-1})]= W^T \times diag[1-(tanh)^2]
∂hj−1∂hj=WT×diag[f′(jj−1)]=WT×diag[1−(tanh)2]
因此,总的导数为:
其中,
β
W
\beta_W
βW和
β
h
\beta_h
βh分别表示两个矩阵2范式的上界;
因此,
当t-k足够大是,
β
W
β
h
\beta_W\beta_h
βWβh小于1会出现梯度消失,
β
W
β
h
\beta_W\beta_h
βWβh大于1会出现梯度爆炸。
在实验中,当出现梯度爆炸时,会导致计算流中出现NaN,所以比较检测出来;仔细看上述的分析,我们可以知道,梯度消失在计算过程中不会报错,只是在较前时间步的梯度贡献很少(或者为0),因此比较难察觉出来。
2.4 Solution to the Exploding & Vanishing Gradients
为了解决梯度爆炸问题,当梯度比较大时,我们设定一个阈值,使梯度不大于这个值,具体如下:
为了解决梯度消失问题,可以使用的方法有:1. 初始化权重
W
(
h
h
)
W^{(hh)}
W(hh)为单位矩阵代替随机初始化(优化指数衰减的第一项);2. 使用ReLU激活函数代替sigmoid, tanh等(因为ReLU导数为1,优化指数衰减的第二项);3. 从根本上修改,RNN模型改为LSTM(后面会介绍该模型)。
2.5 Deep Bidirectional RNNs
双向RNN是指从左到右以及从右到左两个方向的RNN模型,如下图:
公式:
深度双向RNN顾名思义就是多层的双向RNN,如下图:
公式:
2.6 Application: RNN Translation Model
这一小节将RNN应用于机器翻译模型,包括encoder, decoder两个阶段,如下图:
公式:
第一条公式表示encoder阶段,第二三条公式表示decoder阶段。
上述例子只能产生一个输出结果,且模型的解码能力有限,更通常的,我们使用以下的编解码方式:
一些tricks:
1. encoder和decoder阶段使用不同的RNN权重;
2. decoder阶段使用三个类型的输入(入上图所示),包括前一个时刻的隐藏层,encoder变量,上一个时刻的预测输出;
3. 训练多层的RNN模型(前提是要有足够大的语料);
4. encoder阶段训练双向的RNN模型;
5. 使用倒序的方法训练RNN模型。(ABC->XY改为CBA->XY)。
3 Gated Recurrent Units
GRU是在隐藏层
h
t
h_{t}
ht到
h
t
−
1
h_{t-1}
ht−1的过程中,使用了复杂的门控激活函数来修正RNN结构,具体如下:
结构图:
每个结构的解析:
- New memory generation(新的记忆单元): 新的记忆单元 h ^ t \hat h_t h^t是新输入词 x t x_t xt与过去的隐藏状态 h t − 1 h_{t-1} ht−1的合并。从人类学的角度来看,这一阶段是将新观察到的词与过去的隐藏状态 h t − 1 h_{t-1} ht−1结合起来以根据上下文过去作为向量 h ^ t \hat h_t h^t;
- Reset Gate(重置门): r t r_t rt负责确定 h t − 1 h_{t-1} ht−1对于 h ^ t \hat h_t h^t有多重要。如果重置门发现 h t − 1 h_{t-1} ht−1与新的记忆单元的计算无关,则它有能力完全消除过去的隐藏状态;
- Update Gate(更新门): z t z_t zt负责确定应将多少 h t − 1 h_{t-1} ht−1结转到下一状态。例如,如果 z t z_t zt≈1,则 h t − 1 h_{t-1} ht−1几乎全部复制到ht。相反,如果 z t z_t zt≈0,则大多数新的记忆单元 h ^ t \hat h_t h^t将转发到下一个隐藏状态;
- Hidden state:最终更新门的建议下, 使用过去的隐藏输入 h t − 1 h_{t-1} ht−1和新的记忆单元 h ^ t \hat h_t h^t生成隐藏状态 h t h_{t} ht。
4 Long-Short-Term-Memories
LSTM有点类似于GRU,只是隐藏层
h
t
h_{t}
ht到
h
t
−
1
h_{t-1}
ht−1的门控激活函数有一些不同,具体如下:
结构图:
每个结构的解析:
- New memory generation(新的记忆单元): 此阶段类似于我们在GRU中看到的新的记忆单元生成阶段。我们实质上是使用输入词 x t x_t xt和过去的隐藏状态 h t − 1 h_{t-1} ht−1来生成一个新的记忆单元 c ~ t \widetilde c_t c t,其中包括新词 x ( t ) x^{(t)} x(t)的各个方面;
- Input Gate(输入门): 我们看到,新的记忆单元生成阶段不会在生成新的记忆单元之前检查新单词是否重要-这正是输入门的功能。输入门使用输入词和过去的隐藏状态来确定输入是否值得保留,因此用于门控新记忆单元。因此,它将其作为此信息的指示;
- Forget Gate(忘记门): 该门与输入门相似,不同之处在于它不确定输入词的有用性,而是评估过去的记忆单元是否对当前记忆单元的计算有用。因此,忘记门查看输入的单词和过去的隐藏状态并产生 f t f_t ft;
- Final memory generation: 该阶段首先接受遗忘门 f t f_t ft的建议,并因此遗忘过去的记忆单元 c t − 1 c_{t-1} ct−1。类似地,它接受输入门的建议,将其选通,并相应地选通新的记忆单元。然后,将这两个结果相加,以生成最终记忆 c t c_{t} ct;
- Output/Exposure Gate: 这是GRU中未明确存在的门。目的是将最终记忆与隐藏状态分开。最终记忆单元 c t c_t ct包含很多信息,这些信息不一定需要以隐藏状态保存。在LSTM的每个单独的门中都使用了隐藏状态,因此,此门将对记忆单元ct的哪些部分需要在隐藏状态 h t h_t ht中进行暴露/呈现进行评估。