传统的机器翻译的方法每每是基于单词与短语的统计,以及复杂的语法结构来完成的。基于序列的方式,能够当作两步,分别是 Encoder 与 Decoder,Encoder 阶段就是将输入的单词序列(单词向量)变成上下文向量,而后 decoder根据这个向量来预测翻译的结果。html
encoder 阶段面临的一个问题是,对于输入语句,语句的长度每每是不固定的,可是咱们训练神经网络每每都是要固定长度的向量。因此如何解决这个问题是 encoder阶段的关键。咱们一般使用多层的 LSTM,上一层的输出将做为下一层的输入。网络
在 Google 提出 Seq2Seq 的时候,提出了将输出的语句反序输入到 encoder中,这么作是为了在 encoder阶段的最后一个输出刚好就是 docoder阶段的第一个输入。函数
这一阶段要稍微与encoder阶段要复杂一点点。首先是一个 Token, 通常是一个 <EOS> 表示输入的结束,也就是下图中的 "Go",表示 decoder 阶段的开始,还有一点不同就是,咱们指望用以及正确预测的数据做为下一次的上下文参考,因此也就是上一节讲到的 \(C_i\) 的信息,做用到下一个时间点。横向能够当作 序列的,纵向能够当作是并行的(可是实际上不是并行的)。lua
上面的方法面临这样一个问题,那就是单词向量每每是与上下文有关的,而不只仅只于前面的文字有关,因此须要改进单向 RNN,这里咱们使用双向 RNN来解决这个问题:spa
上图是一个双向 LSTM,图中是一个encoder的例子,每个隐含层的状态都有两个向量表示,分别表示两个方向,\(h=\left[h^{(f)} \quad h^{(b)}\right]\)。输出也有两个,分别是 \(\left[ \begin{array}{ll}{o_{t}^{(f)}} & {o_{t}^{(b)}}\end{array}\right]\)。翻译
在翻译的模型中,举个简单的例子,code
"the ball is on the field,"htm
其中关键的单词就那么几个,并且不少状况下,若是将全部的单词都考虑进来的话,会致使过拟合,反而会致使语义的不许确,因此提出了attention 的机制,主要思想做用在 decoder阶段,每次观察整个句子,在每一步能够决定那些单词是重要的。blog
encoder阶段使用一个双向 LSTM,ip
神经网络隐含层的使用的机制:
\[ s_{i}=f\left(s_{i-1}, y_{i-1}, c_{i}\right) \]
其中 \(s_{i-1}\) 是神经网络前一层的输出,而后 \(y_{i-1}\) 是上一个时间序列,也就是预测的上一个单词的输出,\(C_{t}\) 于LSTM中的 \(C_t\)不太同样,可是本质上都是用来记录信息的。
经过神经网络的输出,预测的机制:
\[ p\left(y_{i} | y_{1}, \ldots, y_{i-1}, \mathbf{x}\right)=g\left(y_{i-1}, s_{i}, c_{i}\right) \]
上面式子中用到的 \(y_{i-1}\) 就很容易理解了。
这个 \(C_i\) 本质上都是用来记录信息的,这里的计算方式是:
\[ c_{i}=\sum_{j=1}^{T_{x}} \alpha_{i j} h_{j} \]
上式中的 \(h_j\) 也不是LSTM中的隐含层的状态,隐含层的状态是 \(s_i\) ,而是包含了重点关注第 \(i\)个单词的信息。因此咱们很容易想到,这里获取 \(c_i\) 的时候必需要加权,就是对每一个 \(i\),进行加权,那么衡量权重的标志是什么呢?咱们用 \(e_{ij}\) 来表示,
\[ e_{i j}=a\left(s_{i-1}, h_{j}\right) \]
这是一个对齐模型,表示输入的单词 \(j\), (咱们重点关注的)在输出位置为 \(i\) 的可能性大小。而后咱们将这个得分进行加权计算,就获得了
\[ \alpha_{i j}=\frac{\exp \left(e_{i j}\right)}{\sum_{k=1}^{T_{x}} \exp \left(e_{i k}\right)} \]
再返回去求 \(c_i\)。上面的对齐模型,咱们能够直接使用一个传统的神经网络。attention 机制的一个好处就是能够很好的翻译长句子,由于能够忽略不须要的信息。
对于encoder阶段给出的隐藏层的状态,\(h_{1}, \ldots, h_{n}\),对于 decoder阶段的隐含层状态,\(\overline{h_{1}}, \ldots, \overline{h_{n}}\)。咱们能够计算一个得分,使用下面任意一种函数:
\[ \operatorname{score}\left(h_{i}, \overline{h}_{j}\right)=\left\{\begin{array}{l}{h_{i}^{T} \overline{h}_{j}} \\ {h_{i}^{T} W \overline{h}_{j}} \\ {W\left[h_{i}, \overline{h}_{j}\right]}\end{array}\right. \]
而后就像上面的那个模型同样,经过 \(softmax\) 函数来计算几率,将这个几率做为加权便可,
\[ \alpha_{i, j}=\frac{\exp \left(\operatorname{score}\left(h_{j}, \overline{h}_{i}\right)\right)}{\sum_{k=1}^{n} \exp \left(\operatorname{score}\left(h_{k}, \overline{h}_{i}\right)\right)} \]
而后就得出了单词的文本向量,
\[ c_{i}=\sum_{j=1}^{n} \alpha_{i, j} h_{j} \]
接下来就能够计算新的隐含层的状态了:
\[ \tilde{h}_{i}=f\left(\left[\overline{h}_{i}, c_{i}\right]\right) \]
而后经过最后的预测函数,预测出下一个单词。这里在时间上 \(\tilde{h}_{i}\) 也会做为下一个时间点的输入。
Local Attention 就是使用了一个窗口表示关注的单词,能够改变窗口的大小,说明对任意的单词均可以关注。
上面的例子也说明了,在 Attention 阶段最重要的是 Decoder的策略。
机器翻译起源于统计翻译,咱们从几率的角度就是对于输入语句 \(S\) 与目标语句 \(\overline{S}\),咱们的目标就是
\[ \overline{s} *=\operatorname{argmax}_{\overline{s}}(\mathbb{P}(\overline{s} | s)) \]
可是对于目标语句可能性太多,也就形成了计算量太大,咱们有几种策略:
Beam search 是使用的最多的一种策略,这种方法就是每次维持一个大小为 \(K\) 的翻译语句集合,
\[ \mathcal{H}_{t}=\left\{\left(x_{1}^{1}, \ldots, x_{t}^{1}\right), \ldots,\left(x_{1}^{K}, \ldots, x_{t}^{K}\right)\right\} \]
当咱们预测 \(t+1\) 的时刻的时候,咱们依然取可能性最大的 \(K\) 个集合:
\[ \tilde{\mathcal{H}}_{t+1}=\bigcup_{k=1}^{K} \mathcal{H}_{t+1}^{\tilde{k}} \]
其中
\[ \mathcal{H}_{t+1}^{\tilde{k}}=\left\{\left(x_{1}^{k}, \ldots, x_{t}^{k}, v_{1}\right), \ldots,\left(x_{1}^{k}, \ldots, x_{t}^{k}, v_{|V|}\right)\right\} \]
表示每一种可能的组合。
将咱们翻译的语句用于其余的系统中以查看翻译的效果。举个例子,咱们将翻译的语句用于问答系统,与标准的语句用于问答系统,都能获得准确的回答,那么说明咱们翻译的过程当中抓住了句子的关键信息,在评估翻译结果的时候,时要考虑多方面的,这是咱们既不能说咱们的翻译彻底正确,也不能说是失败了。
这个方法是经过将一个参与的翻译系统的结果 B,与人工翻译的结果 A,进行对比评估,使用 n-gram 的方法进行对比。其中可能会有多个参考也就是reference。
n-gram 的方法主要是关注窗口的大小。将连在一块儿的单词做为一个窗口,而后计算匹配的窗口的个数。最简单的例子就是:
对于窗口,咱们用 window 来表示,出现的次数,
\[ Count_{clip}=\min \left(\text { Count }, \text { Max }_{-} \text { Ref }_{-} \text { Count }\right) \]
表示这个 window 在翻译文本与 reference文本中出现的最低的次数,那么精度能够这样计算:
\[ P_{n}=\frac{\sum_{i} \sum_{k} \min \left(h_{k}\left(c_{i}\right), \max _{j \in m} h_{k}\left(s_{i j}\right)\right)}{\sum_{i} \sum_{k} \min \left(h_{k}\left(c_{i}\right)\right)} \]
\(H_k(c_i)\) 表示机器翻译的结果中 \(c_i\) 出现的次数,\(H_k(s_{ij})\) 表示标准答案下 \(S_{ij}\) 出现的次数,这里为何 \(S\) 下面有双下标,是由于,这里咱们能够有不少个 reference。
考虑机器翻译的结果为第二句,第一句为参考的状况,这个时候,计算的结果代表,翻译的很好,由于第二个语句比较短,因此 \(H_k(s_{ij})\) 的正确率表现得比较高,可是实际上整个句子的翻译效果没有那么高:
there are many ways to evaluate the quality of a translation, like comparing the number of n-grams between a candidate translation and reference
the quality of a translation is evaluate of n-grams in a reference and with translation
所以咱们引入一个惩罚因子:
\[ \beta=e^{\min \left(0,1-\frac{\operatorname{le}_{\mathrm{ref}}}{\operatorname{len}_{\mathrm{MT}}}\right)} \]
其中分子表示 reference的长度,分母是机器翻译结果的长度,那么最终的评分咱们就能够表示成:
\[ B L E U=\beta \times \exp \left(\sum_{n=1}^{N} w_{n} \log P_{n}\right) \]
还有一个问题就是处理 vocabulary 过大的状况下,因为输出的时候须要通过一个 \(softmax\) 函数,因此在输出的时候,若是输出的 vocabulary 过大的话,那么 softmax 这一过程计算量就会特别大。
在第一节课里面咱们就介绍过两种方法,分别是分层 SoftMax 与 Negative Sampling(负采样)。传送门:传送门
还有一些方法能够用:
为了限制词典的大小,对于语句中出现的未知的单词,咱们就用 <UNK> 来表示,可是这样可能会致使源语句失去一些关键信息。还有一种方法就是,
还有一种作法就是将数据集进行划分,这样的好处是,类似关系的数据集通常在一块儿。每一个训练数据的子集取大小为 $ \tau=\left|V^{\prime}\right|$ 的字典。而后对整个数据集进行迭代。主要思想就是,咱们在训练的时候,将训练数据分红不少个 Min-Batches,对每一个 Min-Batches 的选取就是选取到 $ \tau$ 个单词的时候,用来表示这个字典,而后在训练的时候用这种数据会大大下降在 SoftMax 阶段的计算量。咱们假设每次训练集的目标单词,也就是 Min-Batches 部分的单词,构成集合 \(V_{i}^{\prime}\),那么这个集合中每一个单词的几率就是:
\[ Q_{i}\left(y_{k}\right)=\left\{\begin{array}{ll}{\frac{1}{\left|V_{i}^{\prime}\right|}} & {\text { if } y_{t} \in V_{i}^{\prime}} \\ {0} & {\text { otherwise }}\end{array}\right. \]
基于单词的模型,能够选取出现几率最高的 n-gram 框,而后将这个框不断地加到数据集中去。
简单说下这两种方式的混合策略,
混合策略中,首先是对于单词的预测,使用常规的 LSTM,可是遇到输出的单词是 <UNK> 的时候,咱们就须要使用字母级上的神经网络了。