Commit acacfe9f by 曹润柘

更新 Chapter6.tex

parent 08a776fd
......@@ -407,23 +407,24 @@ NMT & $ 21.7^{\ast}$ & $18.7^{\ast}$ & -1
%----------------------------------------------
\parinterval 从数学模型上看,神经机器翻译模型与统计机器翻译的目标是一样的:在给定的源语言句子$\mathbf{x}$的情况下,找出翻译概率最大的目标语译文$\hat{\mathbf{y}}$:
\begin{equation}
\begin{eqnarray}
\hat{\mathbf{y}} = \argmax_{\mathbf{y}} \textrm{P} (\mathbf{y} | \mathbf{x})
\label{eqC6.1}
\end{equation}
\end{eqnarray}
\noindent 在这里,我们用$\mathbf{x}=\{ x_1,x_2,…, x_m \}$表示输入的源语言单词序列,$\mathbf{y}=\{ y_1,y_2,…, y_n \}$ 表示生成的目标语单词序列。由于神经机器翻译在生成译文时采用的是自左向右逐词生成的方式,并在翻译每个单词时会考虑已经生成的翻译结果,因此对$\textrm{P} (\mathbf{y} | \mathbf{x})$的求解可以转换为:
\begin{equation}
%-----------------
\begin{eqnarray}
\textrm{P} (\mathbf{y} | \mathbf{x}) = \prod_{j=1}^{n} \textrm{P} ( y_j | \mathbf{y}_{<j }, \mathbf{x} )
\label{eqC6.2}
\end{equation}
\end{eqnarray}
\noindent 其中,$ \mathbf{y}_{<j }$表示目标语第$j$个位置之前已经生成的译文单词序列。$\textrm{P} ( y_j | \mathbf{y}_{<j }, \mathbf{x})$可以被解释为,根据源语句子$\mathbf{x} $和已生成的目标语言译文片段$\mathbf{y}_{<j }=\{ y_1, y_2,…, y_{j-1} \}$,生成第$j$个目标语言单词$y_j$的概率。举个简单的例子,已知源文为$\mathbf{x} =$\{\textrm{我,很好}\},则译文$\mathbf{y}=$\{I’m,fine\}的概率为:
\begin{equation}
%-------------
\begin{eqnarray}
\textrm{P} ( \{{\textrm{I'm,fine}}\}|\{\textrm{我,很好}\}) = \textrm{P} (\textrm{I'm}| \{\textrm{我,很好}\} ) \cdot \textrm{P} (\textrm{fine}|\textrm{I'm},\{\textrm{我,很好}\})
\label{eqC6.3}
\end{equation}
\end{eqnarray}
\parinterval 求解$\textrm{P}(y_j | \mathbf{y}_{<j},\mathbf{x})$有三个关键问题(图\ref{fig:6-10}):
......@@ -433,20 +434,20 @@ NMT & $ 21.7^{\ast}$ & $18.7^{\ast}$ & -1
\item 如何在词嵌入的基础上获取整个序列的表示,即句子的\textbf{表示学习}问题。我们可以把词嵌入的序列作为循环神经网络的输入,循环神经网络最后一个时刻的输出向量便是整个句子的表示结果。如图\ref{fig:6-10}中,编码器最后一个循环单元的输出$\mathbf{h}_m$被看作是一种包含了源语句子信息的表示结果,记为$\mathbf{C}$
\item 如何得到每个目标语单词的概率,即\textbf{译文单词生成}问题。与神经语言模型一样,我们可以用一个Softmax输出层来获取当前时刻所有单词的分布,即利用Softmax函数计算目标语词表中每个单词的概率。令目标语序列$j$时刻的循环神经网络的输出向量(或状态)为$\mathbf{s}_j$。根据循环神经网络的性质,$ y_j$的生成只依赖前一个状态$\mathbf{s}_{j-1}$和当前时刻的输入(即词嵌入$\textrm{e}_y (y_{j-1})$)。同时考虑源语言信息$\mathbf{C}$$\textrm{P}(y_j | \mathbf{y}_{<j},\mathbf{x})$可以被重新定义为:
\begin{equation}
\begin{eqnarray}
\textrm{P} (y_j | \mathbf{y}_{<j},\mathbf{x}) \equiv \textrm{P} ( {y_j | \mathbf{s}_{j-1} ,y_{j-1},\mathbf{C}} )
\label{eqC6.4}
\end{equation}
\end{eqnarray}
$\textrm{P}({y_j | \mathbf{s}_{j-1} ,y_{j-1},\mathbf{C}})$由Softmax实现,Softmax的输入是循环神经网络$j$时刻的输出。在具体实现时,$\mathbf{C}$可以被简单的作为第一个时刻循环单元的输入,即,当$j=1$ 时,解码器的循环神经网络会读入编码器最后一个隐层状态$ \mathbf{h}_m$(也就是$\mathbf{C}$),而其它时刻的隐层状态不直与$\mathbf{C}$相关。最终,$\textrm{P} (y_j | \mathbf{y}_{<j},\mathbf{x})$ 被表示为:
\begin{equation}
\begin{eqnarray}
\textrm{P} (y_j | \mathbf{y}_{<j},\mathbf{x}) \equiv
\left \{ \begin{array}{ll}
\textrm{P} (y_j |\mathbf{C} ,y_{j-1}) &j=1 \\
\textrm{P} (y_j|\mathbf{s}_{j-1},y_{j-1}) \quad &j>1
\end{array} \right .
\label{eqC6.5}
\end{equation}
\end{eqnarray}
\end{itemize}
......@@ -468,10 +469,10 @@ $\textrm{P}({y_j | \mathbf{s}_{j-1} ,y_{j-1},\mathbf{C}})$由Softmax实现,Sof
\parinterval 由公式\ref{eqC6.2}可知,神经机器翻译系统在运行时需要两个输入,一个是源语言单词序列$\mathbf{x}$,和目标语单词序列$\mathbf{y}_{<j}$(到$j$时刻为止)。因此,第一步我们需要把单词的离散化表示转化为神经网络容易处理的分布式连续表示,即词嵌入。而我们也会把词嵌入的结果作为循环神经网络的输入层。词嵌入的概念已经在第五章神经语言模型的部分进行过详细介绍。以解码端为例,传统方法中每个目标语言单词都对应目标语言词表中的一个索引项,可以用one-hot向量表示。one-hot向量的维度和词表大小相同,但是只有单词所对应的那一维的值为1,其它为均为0。例如,词表中包含三个单词,则它们的one-hot表示分别为[0,0,1],[0,1,0],[1,0,0]。词嵌入的目的是把这种one-hot表示转化为一个实数向量,向量的每一维都对应这个单词的某种``属性''。由于是实数向量,这些属性是可以直接进行代数运算的。相比one-hot表示中所有向量都是正交的,词嵌入表示可以更容易描述不同单词间的关系,而不是简单的进行非零0即1的判断。比如,词嵌入表示中的著名例子``queen''=``woman''-``man''+``king''就能在一定程度上说明这个问题。
\parinterval 那么怎么在神经机器翻译系统中获得单词的词嵌入表示呢?这里我们引入一个词嵌入层对输入的单词进行词嵌入表示,即图\ref{fig:6-11}中的绿色方框部分。假设输入的单词$y_j$已经被表示为one-hot形式(行向量)。词嵌入层的工作就是把one-hot向量右乘一个实数矩阵$\mathbf{E}$,得到的结果(行向量)就是这个单词所对应的词嵌入结果。
\begin{equation}
\begin{eqnarray}
\textrm{e}_y (y_j) = y_j \mathbf{E}
\label{eqC6.6}
\end{equation}
\end{eqnarray}
\noindent 这里,$\mathbf{E}$也被称作词嵌入矩阵,它可以作为模型的一部分参数共同参与机器翻译系统的训练,也可以由外部其它模块训练得到(如预训练模型)。$\mathbf{E}$的大小为$|V| \times d$,这里$|V|$表示词表$V$的大小,$d$表示循环神经网络输入和输出向量的维度。
......@@ -502,22 +503,22 @@ $\textrm{P}({y_j | \mathbf{s}_{j-1} ,y_{j-1},\mathbf{C}})$由Softmax实现,Sof
%----------------------------------------------
\parinterval 输出层的构造很简单,对于输入的向量$\mathbf{s}_j$经过一个线性变换之后再经过Softmax\\函数,即可得到一个$V$上的分布,具体描述如下:
\begin{equation}
\begin{eqnarray}
\mathbf{o}_j=\textrm{Softmax}( \mathbf{s}_j \mathbf{W_o})
\label{eqC6.7}
\end{equation}
\end{eqnarray}
\noindent 其中,$\mathbf{W_o}$是线性变换的参数矩阵,矩阵的大小为$d \times |V|$,也就是$d$维的向量会变为$|V|$维的向量;$\mathbf{o}_j$表示输出的结果向量,$\mathbf{o}_j$的每一维$\mathbf{o}_{jk}$表示,在时刻$j$词表$V$中一个第$k$个单词出现的概率。这里我们把$\mathbf{o}_j(y_j)$记作目标语单词$y_j$的生成概率,显然有
\begin{equation}
\begin{eqnarray}
\textrm{P} (y_j| \mathbf{y}_{<j},\mathbf{x})=\mathbf{o}_j(y_j)
\label{eqC6.8}
\end{equation}
\end{eqnarray}
\parinterval Softmax($\cdot$)的作用是根据输入的$|V|$维向量(即$\mathbf{s}_j \mathbf{W_o}$),得到一个$|V|$维的分布。令$\mathbf{\tau}$表示Softmax($\cdot$)的输入向量,$\tau_k$表示向量的第$k$维。Softmax函数可以被定义为
\begin{equation}
\begin{eqnarray}
\textrm{Softmax}(\tau_k)=\frac{\textrm{exp}(\tau_k)} {\sum_{k'=1}^{|V|} \textrm{exp}(\tau_{k'})}
\label{eqC6.9}
\end{equation}
\end{eqnarray}
\noindent 这里,exp($\cdot$)表示指数函数e。Softmax函数是一个典型的归一化函数,它可以将输入的向量的每一维都转化为0-1之间的数,同时保证所有维的和等于1。Softmax的另一个优点是,它本身(对于输出的每一维)都是可微的(如图\ref{fig:6-13}所示),因此可以直接使用基于梯度的方法进行优化。实际上,Softmax经常被用于分类任务。我们也可以把机器翻译中目标语单词的生成看作一个分类问题,它的类别数是|$V$|。
......@@ -533,7 +534,7 @@ $\textrm{P}({y_j | \mathbf{s}_{j-1} ,y_{j-1},\mathbf{C}})$由Softmax实现,Sof
%----------------------------------------------
\parinterval 为了进一步理解Softmax的计算过程,来看一个简单的例子。假设我们的词表为[吃饭,睡觉,学习],当我们预测下一个译文单词时,我们将循环神经网络的输出通过矩阵$\mathbf{W_o}$映射到词表大小的向量,得到$\mathbf{\tau}=$[-3,1.5,2.7],此时我们使用Softmax激活函数将其进行归一化:
\begin{equation}
\begin{eqnarray}
\textrm{Softmax}(\mathbf{\tau})=
\left( \begin{array}{c}
\frac{0.05}{0.05+4.48+14.88} \\
......@@ -547,7 +548,7 @@ $\textrm{P}({y_j | \mathbf{s}_{j-1} ,y_{j-1},\mathbf{C}})$由Softmax实现,Sof
0.7666
\end{array} \right)
\label{eqC6.10}
\end{equation}
\end{eqnarray}
\parinterval 最终得到在整个词表上的概率分布[0.0026,0.2308,0.7666],其中概率最大的单词``学习'',便是我们最终得到的译文单词。
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
......@@ -557,10 +558,10 @@ $\textrm{P}({y_j | \mathbf{s}_{j-1} ,y_{j-1},\mathbf{C}})$由Softmax实现,Sof
%%%%%%%%%%%%%%%%%%
\subsubsection{循环神经单元(RNN)}\index{Chapter6.3.3.1}
\parinterval RNN(Recurrent Neural Network)是最原始的循环神经网络结构。在RNN中,对于序列$\mathbf{x}=\{ \mathbf{x}_1, \mathbf{x}_2,…,\mathbf{x}_m \}$,每个时刻$t$都对应一个循环单元,它的输出是一个向量$\mathbf{h}_t$,可以被描述为:
\begin{equation}
\begin{eqnarray}
\mathbf{h}_t=f(\mathbf{x}_t \mathbf{U}+\mathbf{h}_{t-1} \mathbf{W}+\mathbf{b})
\label{eqC6.11}
\end{equation}
\end{eqnarray}
\noindent 其中$\mathbf{x}_t$是当前时刻的输入,$\mathbf{h}_{t-1}$是上一时刻循环单元的输出,$f(\cdot)$是激活函数,$\mathbf{U}$\\ $\mathbf{W}$是参数矩阵,$\mathbf{b}$是偏置。
......@@ -590,40 +591,40 @@ $\textrm{P}({y_j | \mathbf{s}_{j-1} ,y_{j-1},\mathbf{C}})$由Softmax实现,Sof
\begin{itemize}
\item \textbf{遗忘}。顾名思义,遗忘的目的是忘记一些历史,在LSTM中通过遗忘门实现,其结构如图\ref{fig:6-14}(a)所示。$\mathbf{x}_{t}$表示时刻$t$的输入向量,$\mathbf{h}_{t-1}$是时刻$t-1$的循环单元的输出,$\mathbf{x}_{t}$$\mathbf{h}_{t-1}$都作为$t$时刻循环单元的输入。$\sigma$将对$\mathbf{x}_{t}$$\mathbf{h}_{t-1}$进行筛选,以决定遗忘的信息,其计算公式如下:
\begin{equation}
\begin{eqnarray}
\mathbf{f}_t=\sigma(\mathbf{W}_f [\mathbf{h}_{t-1},\mathbf{x}_{t}] + \mathbf{b}_f )
\label{eqC6.12}
\end{equation}
\end{eqnarray}
这里,$\mathbf{W}_f$是权值,$\mathbf{b}_f$是偏置,$[\mathbf{h}_{t-1},\mathbf{x}_{t}]$表示两个向量的拼接。该公式可以解释为,对$[\mathbf{h}_{t-1},\mathbf{x}_{t}]$进行变换,并得到一个 的实数向量$\mathbf{f}_t$$\mathbf{f}_t$的每一维都可以被理解为一个``门'',它决定可以有多少信息被留下(或遗忘)。
\item \textbf{记忆更新}。首先,要生成当前时刻需要新增加的信息,该部分由输入门完成,其结构如图\ref{fig:6-14}(b)红色线部分,图中``$\bigotimes$''表示进行点乘操作。输入门的计算分为两部分,首先利用$\sigma$决定门控参数$\mathbf{i}_t$,然后通过tanh函数得到新的信息$\hat{\mathbf{c}}_t$,具体公式如下:
\begin{equation}
\begin{eqnarray}
\mathbf{i}_t = \sigma (\mathbf{W}_i [\mathbf{h}_{t-1},\mathbf{x}_{t}] + \mathbf{b}_i )
\label{eqC6.13}
\end{equation}
\end{eqnarray}
%------------------------------------------
\begin{equation}
\begin{eqnarray}
\hat{\mathbf{c}}_t = \textrm{tanh} (\mathbf{W}_c [\mathbf{h}_{t-1},\mathbf{x}_{t}] + \mathbf{b}_c )
\label{eqC6.14}
\end{equation}
\end{eqnarray}
之后,用$\mathbf{i}_t$点乘$\hat{\mathbf{c}}_t$,得到当前需要记忆的信息,记为$\mathbf{i}_t \cdot \hat{\mathbf{c}}_t$。接下来需要更新旧的信息$\mathbf{c}_{t-1}$,得到新的记忆信息$\mathbf{c}_t$,更新的操作如图\ref{fig:6-14}(c)红色线部分所示,``$\bigoplus$''表示相加。具体规则是通过遗忘门选择忘记一部分上文信息$\mathbf{f}_t$,通过输入门计算新增的信息$\mathbf{i}_t \cdot \hat{\mathbf{c}}_t$,然后根据``$\bigotimes$''门与``$\bigoplus$''门进行相应的乘法和加法计算:
\begin{equation}
\begin{eqnarray}
\mathbf{c}_t = \mathbf{f}_t \cdot \mathbf{c}_{t-1} + \mathbf{i}_t \cdot \hat{\mathbf{c}_t}
\label{eqC6.15}
\end{equation}
\end{eqnarray}
\item \textbf{输出}。该部分使用输出门计算最终的输出信息$\mathbf{h}_t$,其结构如图\ref{fig:6-14}(d)红色线部分所示。在输出门中,首先将$\mathbf{x}_t$$\mathbf{h}_{t-1}$通过$\sigma$函数变换得到$\mathbf{o}_t$。其次,将上一步得到的新记忆信息$\mathbf{c}_t$通过tanh函数进行变换,得到值范围在[-1,1]的向量。最后将这两部分进行点乘,具体公式如下:
\begin{equation}
\begin{eqnarray}
\mathbf{o}_t = \sigma (\mathbf{W}_o [\mathbf{h}_{t-1},\mathbf{x}_{t}] + \mathbf{b}_o )
\label{eqC6.16}
\end{equation}
\end{eqnarray}
%----------------------------------------------------
\begin{equation}
\begin{eqnarray}
\mathbf{h}_t = \mathbf{o}_t \cdot \textrm{tanh} (\mathbf{c}_t)
\label{eqC6.17}
\end{equation}
\end{eqnarray}
\end{itemize}
%----------------------------------------------
......@@ -642,27 +643,27 @@ $\textrm{P}({y_j | \mathbf{s}_{j-1} ,y_{j-1},\mathbf{C}})$由Softmax实现,Sof
\parinterval LSTM 通过门控单元控制传递状态,忘记不重要的信息,记住必要的历史信息,在长序列上取得了很好的效果,但是其进行了许多门信号的计算,较为繁琐。门循环单元(Gated Recurrent Unit,GRU)作为一个LSTM的变种,它继承了LSTM中利用门控单元控制信息传递的思想,并对LSTM进行了简化\cite{Cho2014Learning}。它把循环单元状态$\mathbf{h}_t$和记忆$\mathbf{c}_t$合并成一个状态$\mathbf{h}_t$,同时使用了更少的门控单元,大大提升了计算效率。
\parinterval GRU的输入和RNN是一样的,由输入$\mathbf{x}_t$$t-1$时刻的状态$\mathbf{h}_{t-1}$组成。GRU只有两个门信号,分别是重置门和更新门。重置门$\mathbf{r}_t$用来控制前一时刻隐藏状态的记忆程度,其结构如图\ref{fig:6-16}(a)。更新门用来更新记忆,使用一个门同时完成遗忘和记忆两种操作,其结构如图\ref{fig:6-16}(b)。重置门和更新门的计算公式如下:
\begin{equation}
\begin{eqnarray}
\mathbf{r}_t = \sigma (\mathbf{W}_r [\mathbf{h}_{t-1},\mathbf{x}_{t}] )
\label{eqC6.18}
\end{equation}
\end{eqnarray}
%----------------------------------------------------
\begin{equation}
\begin{eqnarray}
\mathbf{u}_t = \sigma (\mathbf{W}_u [\mathbf{h}_{t-1},\mathbf{x}_{t}])
\label{eqC6.19}
\end{equation}
\end{eqnarray}
\parinterval 当完成了重置门和更新门计算后,就需要更新当前隐藏状态,如图\ref{fig:6-16}(c)所示。在计算得到了重置门的权重$\mathbf{r}_t$后,使用其对前一时刻的状态$\mathbf{h}_{t-1}$进行重置($\mathbf{r}_t \cdot \mathbf{h}_{t-1}$),将重置后的结果与$\mathbf{x}_t$拼接,通过tanh激活函数将数据变换到[-1,1]范围内:
\begin{equation}
\begin{eqnarray}
\hat{\mathbf{h}}_t = \textrm{tanh} (\mathbf{W}_h [\mathbf{r}_t \cdot \mathbf{h}_{t-1},\mathbf{x}_{t}])
\label{eqC6.20}
\end{equation}
\end{eqnarray}
\parinterval $\hat{\mathbf{h}}_t$在包含了输入信息$\mathbf{x}_t$的同时,引入了$\mathbf{h}_{t-1}$的信息,可以理解为,记忆了当前时刻的状态。下一步是计算更新后的隐藏状态也就是更新记忆,如下所示:
\begin{equation}
\begin{eqnarray}
\mathbf{h}_t = (1-\mathbf{u}_t) \cdot \mathbf{h}_{t-1} +\mathbf{u}_t \cdot \hat{\mathbf{h}}_t
\label{eqC6.21}
\end{equation}
\end{eqnarray}
\noindent 这里,$\mathbf{u}_t$是更新门中得到的权重,将$\mathbf{u}_t$作用于$\hat{\mathbf{h}}_t$表示对当前时刻的状态进行``遗忘'',舍弃一些不重要的信息,将$(1-\mathbf{u}_t)$作用于$\mathbf{h}_{t-1}$,用于对上一时刻隐藏状态进行选择性记忆。
......@@ -782,10 +783,10 @@ $\textrm{P}({y_j | \mathbf{s}_{j-1} ,y_{j-1},\mathbf{C}})$由Softmax实现,Sof
\parinterval 那么注意力机制是如何针对不同单词生成不同的上下文向量的呢?这里,我们可以将注意力机制看做是一种对接收到的信息的加权处理。对于更重要的信息赋予更高的权重即更高的关注度,对于贡献度较低的信息分配较低的权重,弱化其对结果的影响。这样,$\mathbf{C}_j$可以包含更多对当前目标语言位置有贡献的源语言片段的信息。
\parinterval 根据这种思想,上下文向量$\mathbf{C}_j$被定义为对不同时间步编码器输出的状态序列$\{ \mathbf{h}_1, \mathbf{h}_2,…,\mathbf{h}_m \}$进行加权求和,如下:
\begin{equation}
\begin{eqnarray}
\mathbf{C}_j=\sum_{i} \alpha_{i,j} \mathbf{h}_i
\label{eqC6.22}
\end{equation}
\end{eqnarray}
\noindent 其中,$\alpha_{i,j}$\textbf{注意力权重},它表示目标语第$j$个位置与源语第$i$个位置之间的相关性大小。这里,我们将每个时间步编码器的输出$\mathbf{h}_i$看作源语言位置$i$的表示结果。进行翻译时,解码端可以根据当前的位置$j$,通过控制不同$\mathbf{h}_i$的权重得到$\mathbf{C}_j$,使得对目标语位置$j$贡献大的$\mathbf{h}_i$$\mathbf{C}_j$的影响增大。也就是说,$\mathbf{C}_j$实际上就是\{${\mathbf{h}_1, \mathbf{h}_2,…,\mathbf{h}_m}$\}的一种组合,只不过不同的$\mathbf{h}_i$会根据对目标端的贡献给予不同的权重。图\ref{fig:6-22}展示了上下文向量$\mathbf{C}_j$的计算过程。
......@@ -803,13 +804,13 @@ $\textrm{P}({y_j | \mathbf{s}_{j-1} ,y_{j-1},\mathbf{C}})$由Softmax实现,Sof
\begin{itemize}
\item 我们使用目标语言上一时刻循环单元的输出$\mathbf{s}_{j-1}$与源语言第$i$个位置的表示$\mathbf{h}_i$之间的相关性,来表示目标语言位置$j$对源语言位置$i$的关注程度,记为$\beta_{i,j}$,由函数$\textrm{a}(\cdot)$实现
\begin{equation}
\begin{eqnarray}
\beta_{i,j} = \textrm{a}(\mathbf{s}_{j-1},\mathbf{h}_i)
\label{eqC6.23}
\end{equation}
\end{eqnarray}
$\textrm{a}(\cdot)$可以被看作是目标语表示和源语言表示的一种``统一化'',即把源语和目标语表示映射在同一个语义空间,进而语义相近的内容有更大的相似性。该函数有多种计算方式,比如,向量乘、向量夹角、单词神经网络等,如下:
\begin{equation}
\begin{eqnarray}
\textrm{a} (\textbf{s},\textbf{h}) = \left\{ \begin{array}{ll}
\textbf{s} \textbf{h}^{\textrm{T}} & \textrm{向量乘} \\
\textrm{cos}(\textbf{s}, \textbf{h}) & \textrm{向量夹角} \\
......@@ -818,15 +819,15 @@ $\textrm{a}(\cdot)$可以被看作是目标语表示和源语言表示的一种`
\end{array}
\right.
\label{eqC6.24}
\end{equation}
\end{eqnarray}
其中$\mathbf{W}$$\mathbf{v}$是可学习的参数。
\item 进一步,利用Softmax函数,将相关性系数$\beta_{i,j}$进行指数归一化处理,得到注意力权重$\alpha_{i,j}$
\begin{equation}
\begin{eqnarray}
\alpha_{i,j}=\frac{\textrm{exp}(\beta_{i,j})} {\sum_{i'} \textrm{exp}(\beta_{i',j})}
\label{eqC6.25}
\end{equation}
\end{eqnarray}
最终,\{$\alpha_{i,j}$\}可以被看作是一个矩阵,它的长为目标语言句子长度,宽为源语言句子长度,矩阵中的每一项对应一个$\alpha_{i,j}$。图\ref{fig:6-23}给出了\{$\alpha_{i,j}$\}的一个矩阵表示。图中蓝色方框的大小表示不同的注意力权重$\alpha_{i,j}$的大小,方框越大,位置$i$和位置$j$的相关性越高。能够看到,对于互译的中英文句子,\{$\alpha_{i,j}$\}可以较好的反应两种语言之间不同位置之间的对应关系。
......@@ -855,10 +856,10 @@ $\textrm{a}(\cdot)$可以被看作是目标语表示和源语言表示的一种`
%----------------------------------------------
\parinterval\ref{sec:6.3.1}节中,我们使用公式\ref{eqC6.5}描述了目标语单词生成概率P$(y_j | \mathbf{y}_{<j},\mathbf{x})$。在引入注意力机制后,我们使用不同时刻的上下文向量$\mathbf{C}_j$替换了传统模型中固定的句子表示$\mathbf{C}$。描述如下:
\begin{equation}
\begin{eqnarray}
\textrm{P} (y_j | \mathbf{y}_{<j},\mathbf{x}) \equiv \textrm{P} (y_j | \mathbf{s}_{j-1},y_{j-1},\mathbf{C}_j )
\label{eqC6.26}
\end{equation}
\end{eqnarray}
\parinterval 这样,我们可以在生成每个$y_j$时动态的使用不同的源语言表示$\mathbf{C}_j$,并更准确的捕捉源语言和目标语言不同位置之间的相关性。表\ref{tab:word-translation-examples}展示了引入注意力机制前后译文单词生成公式的对比。
......@@ -890,16 +891,16 @@ $\textrm{a}(\cdot)$可以被看作是目标语表示和源语言表示的一种`
\begin{figure}[htp]
\centering
\input{./Chapter6/Figures/figure-Query-model-corresponding-to-traditional-query-model-vs-attention-mechanism}
\caption{传统查询模型(a)和注意力机制所对应的查询模型(b)}
\caption{传统查询模型(a) vs 注意力机制(b)所对应的查询模型}
\label{fig:6-25}
\end{figure}
%----------------------------------------------
\parinterval 我们也可以用这个系统描述翻译中的注意力问题,其中,$\mathrm{query}$即目标语言位置$j$的某种表示,$\mathrm{key}$$\mathrm{value}$即源语言每个位置$i$上的${\mathbf{h}_i}$(这里$\mathrm{key}$$\mathrm{value}$是相同的)。但是,这样的系统在机器翻译问题上并不好用,因为目标语言的表示和源语言的表示都在多维实数空间上,我们无法要求两个实数向量像字符串一样进行严格匹配,或者说这种严格匹配的模型可能会导致$\mathrm{query}$几乎不会命中任何的$\mathrm{key}$。既然无法严格精确匹配,注意力机制就采用了一个``模糊''匹配的方法。我们定义每个$\mathrm{key}_i$$\mathrm{query}$都有一个0~1之间的匹配度,这个匹配度描述了$\mathrm{key}_i$$\mathrm{query}$之间的相关程度,记为$\alpha_i$。而查询的结果(记为$\overline{\mathrm{value}}$)也不再是某一个单元的$\mathrm{value}$,而是所有单元$\mathrm{value}$$\alpha_i$的加权和:
\begin{equation}
\begin{eqnarray}
\overline{\mathrm{value}} = \sum_i \alpha_i \cdot {\mathrm{value}}_i
\label{eqC6.27}
\end{equation}
\end{eqnarray}
\noindent 也就是说所有的$\mathrm{value}_i$都会对查询结果有贡献,只是贡献度不同罢了。我们可以通过设计$\alpha_i$来捕捉$\mathrm{key}$$\mathrm{query}$之间的相关性,以达到相关度越大的$\mathrm{key}$所对应的$\mathrm{value}$对结果的贡献越大。
......@@ -916,10 +917,10 @@ $\textrm{a}(\cdot)$可以被看作是目标语表示和源语言表示的一种`
%----------------------------------------------
\parinterval 最后,从统计学的角度,如果把$\alpha_i$作为每个$\mathrm{value}_i$出现的概率的某种估计,即:P($\mathrm{value}_i$) $= \alpha_i$,于是我们可以把公式\ref{eqC6.27}重写为:
\begin{equation}
\begin{eqnarray}
\overline{\mathrm{value}} = \sum_i \textrm{P}( {\mathrm{value}}_i) \cdot {\mathrm{value}}_i
\label{eqC6.28}
\end{equation}
\end{eqnarray}
\noindent 显然, $\overline{\mathrm{value}}$就是$\mathrm{value}_i$在分布P($\mathrm{value}_i$)下的期望,即$\mathbb{E}_{\sim \\ \textrm{P}( {\mathrm{\mathrm{value}}}_i )} ({\mathrm{value}}_i) = \sum_i \textrm{P}({\mathrm{value}}_i) \cdot {\mathrm{value}}_i $。从这个观点看,注意力机制实际上是得到了一个变量($\mathrm{value}$)的期望。当然,严格意义上说,$\alpha_i$并不是从概率角度定义的,这里我们也并不是要追求严格的统计学意义。不过这确实说明了,往往看似简单的模型背后的数学原理可能会很深刻。
......@@ -927,21 +928,21 @@ $\textrm{a}(\cdot)$可以被看作是目标语表示和源语言表示的一种`
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
\subsection{训练}\index{Chapter6.3.5}
\parinterval 在第五章中,我们已经介绍了神经网络的训练方法。其中最常用的是基于梯度的方法,即:使用一定量样本进行神经网络的前向计算,之后进行反向计算,并得到所有参数的梯度信息,再使用下面的规则进行参数更新:
\begin{equation}
\begin{eqnarray}
\mathbf{w}_{step+1} = \mathbf{w}_{step} - \alpha \cdot \frac{\partial L(\mathbf{w}_{step})} {\partial \mathbf{w}_{step} }
\label{eqC6.29}
\end{equation}
\end{eqnarray}
\noindent 其中,$\mathbf{w}_{step}$表示更新前的模型参数,$\mathbf{w}_{step+1}$表示更新后的模型参数,$L(\mathbf{w}_{step})$表示模型相对于$\mathbf{w}_{step}$的损失,$\frac{\partial L(\mathbf{w}_{step})} {\partial \mathbf{w}_{step} }$表示损失函数的梯度,$\alpha$是更新的步进值。也就是说,给定一定量的训练数据,我们不断运行公式\ref{eqC6.29}的过程。而训练数据也可以反复使用,直至模型参数达到收敛或者损失函数不再变化。通常,把公式的一次执行称为``一步''更新/训练,把访问完所有样本的训练上完称为``一轮''训练。
\parinterval 将公式\ref{eqC6.29}应用于神经机器翻译有几个基本问题需要考虑:1)损失函数的选择;2)参数初始化的策略,也就是如何设置$\mathbf{w}_0$;3)优化策略和学习率调整策略;4)训练加速。下面我们对这些问题进行讨论。
%%%%%%%%%%%%%%%%%%
\subsubsection{损失函数}\index{Chapter6.3.5.1}
\parinterval 因为神经机器翻译在每个目标语位置都会输出一个概率分布,表示这个位置上不同单词出现的可能性,因此我们需要知道当前位置输出的分布相比于标准答案的``损失''。对于这个问题,常用的是交叉熵损失函数\footnote{\ \ 百度百科:\url{https://baike.baidu.com/item/\%E4\%BA\%A4\%E5\%8F\%89\%E7\%86\%B5/8983241?fr=aladdin}}。令$\mathbf{y}$表示机器翻译模型输出的分布,$\hat{\mathbf{y}}$表示标准答案,则交叉熵损失可以被定义为$L_{\textrm{ce}}(\mathbf{y},\hat{\mathbf{y}}) = - \sum_{k=1}^{|V|} \mathbf{y}[k] \textrm{log} (\hat{\mathbf{y}}[k])$,其中$\mathbf{y}[k]$ $\hat{\mathbf{y}}[k]$分别表示向量$\mathbf{y}$$\hat{\mathbf{y}}$的第$k$维,$|V|$表示输出向量得维度(等于词表大小)。对于一个模型输出的概率分布$\mathbf{Y} = \{ \mathbf{y}_1,\mathbf{y}_2,…, \mathbf{y}_n \}$和标准答案分布$\hat{\mathbf{Y}}=\{ \hat{\mathbf{y}}_1, \hat{\mathbf{y}}_2,…,\hat{\mathbf{y}}_n \}$,损失函数可以被定义为
\begin{equation}
L(\mathbf{Y},\hat{\mathbf{Y}}) = \sum_{j=1}^n L_{\textrm{ce}}(\mathbf{y}_j,\hat{\mathbf{y}}_j)
\parinterval 因为神经机器翻译在每个目标语位置都会输出一个概率分布,表示这个位置上不同单词出现的可能性,因此我们需要知道当前位置输出的分布相比于标准答案的``损失''。对于这个问题,常用的是交叉熵损失函数\footnote{\ \ 百度百科:\url{https://baike.baidu.com/item/\%E4\%BA\%A4\%E5\%8F\%89\%E7\%86\%B5/8983241?fr=aladdin}}。令$\mathbf{y}$表示机器翻译模型输出的分布,$\hat{\mathbf{y}}$表示标准答案,则交叉熵损失可以被定义为$L_{ce}(\mathbf{y},\hat{\mathbf{y}}) = - \sum_{k=1}^{|V|} \mathbf{y}[k] \textrm{log} (\hat{\mathbf{y}}[k])$,其中$\mathbf{y}[k]$$\hat{\mathbf{y}}[k]$分别表示向量$\mathbf{y}$$\hat{\mathbf{y}}$的第$k$维,$|V|$表示输出向量得维度(等于词表大小)。对于一个模型输出的概率分布$\mathbf{Y} = \{ \mathbf{y}_1,\mathbf{y}_2,…, \mathbf{y}_n \}$和标准答案分布$\hat{\mathbf{Y}}=\{ \hat{\mathbf{y}}_1, \hat{\mathbf{y}}_2,…,\hat{\mathbf{y}}_n \}$,损失函数可以被定义为
\begin{eqnarray}
L(\mathbf{Y},\hat{\mathbf{Y}}) = \sum_{j=1}^n L_{ce}(\mathbf{y}_j,\hat{\mathbf{y}}_j)
\label{eqC6.30}
\end{equation}
\end{eqnarray}
\parinterval 公式\ref{eqC6.30}是一种非常通用的损失函数形式,除了交叉熵,我们也可以使用其它的损失函数,这时只需要替换$L_{ce} (\cdot)$即可。这里使用交叉熵损失函数的好处在于,它非常容易优化,特别是与Softmax组合,其反向传播的实现非常高效。此外,交叉熵损失(在一定条件下)也对应了极大似然的思想,这种方法在自然语言处理中已经被证明是非常有效的。
......@@ -958,10 +959,10 @@ L(\mathbf{Y},\hat{\mathbf{Y}}) = \sum_{j=1}^n L_{\textrm{ce}}(\mathbf{y}_j,\hat{
\item 网络中的其他偏置一般都初始化为0,可以有效防止加入过大或过小的偏置后使得激活函数的输出跑到``饱和区'',也就是梯度接近0的区域,防止训练一开始就无法跳出局部极小的区域。
\item 网络的权重矩阵$\mathbf{w}$一般使用Xavier参数初始化方法\cite{pmlr-v9-glorot10a},可以有效稳定训练过程,特别是对于比较``深''的网络。如果用$d_{in}$$d_{out}$分别表示$\mathbf{w}$的输入和输出的维度大小,则该方法的具体实现如下:
\begin{equation}
\begin{eqnarray}
\mathbf{w} \sim U(-\sqrt{ \frac{6} { d_{in} + d_{out} } } , \sqrt{ \frac{6} { d_{in} + d_{out} } })
\label{eqC6.31}
\end{equation}
\end{eqnarray}
其中$U(a,b)$表示以$[a,b]$为范围的均匀分布。
\end{itemize}
......@@ -989,10 +990,10 @@ L(\mathbf{Y},\hat{\mathbf{Y}}) = \sum_{j=1}^n L_{\textrm{ce}}(\mathbf{y}_j,\hat{
%%%%%%%%%%%%%%%%%%
\subsubsection{梯度裁剪}\index{Chapter6.3.5.4}
\parinterval 需要注意的是,训练循环神经网络时,反向传播使得网络层之间的梯度重复相乘,在网络层数过深时,如果连乘因子小于1可能造成梯度指数级的减少,甚至趋近于0,导致网络无法优化,也就是梯度消失问题。当连乘因子大于1时,可能会导致梯度的乘积变得异常大,造成梯度爆炸的问题。在这种情况下需要使用``梯度裁剪''来防止梯度$\pi$超过阈值。具体公式如下:
\begin{equation}
\begin{eqnarray}
\mathbf{w}' = \mathbf{w} \cdot \frac{threshold} {\textrm{max}(threshold,\| \mathbf{w} \|_2)}
\label{eqC6.32}
\end{equation}
\end{eqnarray}
\noindent 其中$threshold$是手工设定的梯度大小阈值, $\| \cdot \|_2$是L2范数,$\mathbf{w}'$表示梯度裁剪后的参数。这个公式的含义在于只要梯度大小超过阈值,就按照阈值与当前梯度大小的比例进行放缩。
%%%%%%%%%%%%%%%%%%
......@@ -1005,7 +1006,7 @@ L(\mathbf{Y},\hat{\mathbf{Y}}) = \sum_{j=1}^n L_{\textrm{ce}}(\mathbf{y}_j,\hat{
\centering
%\includegraphics[scale=0.7]{./Chapter6/Figures/Big learning rate vs Small learning rate.png}
\input{./Chapter6/Figures/figure-convergence&lr}
\caption{学习率过小(左) vs 学习率过大(右) }
\caption{学习率过小函数收敛过程(左) vs 学习率过大函数收敛过程(右) }
\label{fig:6-27}
\end{figure}
%----------------------------------------------
......@@ -1024,10 +1025,10 @@ L(\mathbf{Y},\hat{\mathbf{Y}}) = \sum_{j=1}^n L_{\textrm{ce}}(\mathbf{y}_j,\hat{
\parinterval\ref{fig:6-28}展示了一种常用的学习率调整策略。它分为两个阶段:预热阶段和衰减阶段。模型训练初期梯度通常很大,如果直接使用较大的学习率很容易让模型陷入局部最优。学习率的预热阶段便是通过在训练初期使学习率从小到大逐渐增加来减缓在初始阶段模型``跑偏''的现象。一般来说,初始学习率太高会使得模型进入一种损失函数曲面非常不平滑的区域,进而使得模型进入一种混乱状态,后续的优化过程很难取得很好的效果。一个常用的学习率预热方法是逐渐预热(Gradual Warmup),如果令预热的更新次数为$T'$,初始学习率为$\alpha_0$,则预热阶段第$t$次更新的学习率为:
%-------------------------------
\begin{equation}
\begin{eqnarray}
\alpha_t = \frac{t}{T'} \alpha_0 \quad,\quad 1 \leq t \leq T'
\label{eqC6.52-new}
\end{equation}
\end{eqnarray}
%-------
\noindent 另一方面,当模型训练逐渐接近收敛的时候,使用太大学习率会很容易让模型在局部最优解附近震荡,从而错过局部极小,因此需要通过减小学习率来调整更新的步长,以此来不断的逼近局部最优,这一阶段也称为学习率的衰减阶段。学习率衰减的方法有很多,比如指数衰减,余弦衰减等,图\ref{fig:6-28}展示的是分段常数衰减(Piecewise Constant Decay),即每经过$m$次更新,学习率衰减为原来的$\beta_m$$\beta_m<1$)倍,其中$m$$\beta_m$为经验设置的超参。
......@@ -1086,25 +1087,26 @@ L(\mathbf{Y},\hat{\mathbf{Y}}) = \sum_{j=1}^n L_{\textrm{ce}}(\mathbf{y}_j,\hat{
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
\subsection{推断}\index{Chapter6.3.6}
\parinterval 神经机器翻译的推断是指:利用已经训练好的模型对新的源语言句子进行翻译的过程。具体来说,首先利用编码器生成源语言句子的表示,之后利用解码器预测目标语译文。也就是,对于源语言句子$\mathbf{x}$,生成一个使翻译概率$\textrm{P}(\mathbf{y} | \mathbf{x})$最大的目标语译文$\hat{\mathbf{y}}$,如下(详细过程见\ref{sec:6.3.1}节):
%-----------------------
\begin{eqnarray}
\hat{\mathbf{y}} & = & \argmax_y \textrm{P}(\mathbf{y} | \mathbf{x}) \nonumber \\
& = & \argmax_y \prod_{j=1}^n \textrm{P}(y_j | \mathbf{y}_{<j},\mathbf{x})
\hat{\mathbf{y}} & = & \argmax_y \textrm{P}(\mathbf{y} | \mathbf{x}) \nonumber \\
& = & \argmax_y \prod_{j=1}^n \textrm{P}(y_j | \mathbf{y}_{<j},\mathbf{x})
\label{eqC6.33}
\end{eqnarray}
\noindent 在具体实现时,由于当前目标语单词的生成需要依赖前面单词的生成,因此无法同时生成所有的目标语单词。理论上,我们可以枚举所有的$\mathbf{y}$,之后利用$\textrm{P}(\mathbf{y} | \mathbf{x})$的定义对每个$\mathbf{y}$进行评价,然后找出最好的$\mathbf{y}$。这也被称作全搜索(full search)。但是,枚举所有的译文单词序列显然是不现实的。因此,在具体实现时,我们并不会访问所有的可能的译文单词序列,而是用某种策略进行有效的搜索。常用的做法是自左向右逐词生成。比如,对于每一个目标语位置,可以执行
%-------------------------------
\begin{equation}
\begin{eqnarray}
\hat{y}_j = \argmax_{y_j} \textrm{P}(y_j | \hat{\mathbf{y}}_{y<j} , \mathbf{x})
\label{eqC6.34}
\end{equation}
\end{eqnarray}
\noindent 其中,$\hat{y}_j$表示位置$j$概率最高的单词,$\hat{\mathbf{y}}_{<j} = \{ \hat{y}_1,...,\hat{y}_{j-1} \}$表示已经生成的最优译文单词序列。也就是,我们把最优的译文看作是所有位置上最优单词的组合。显然,这是一个贪婪的搜索(greedy search),因为我们无法保证$\{ \hat{y}_1,...,\hat{y}_{n} \}$是全局最优解。一种缓解这个问题的方法是,在每步中引入更多的候选。我们定义$\hat{y}_{jk} $表示在目标语第$j$个位置排名在第$k$位的单词。在每一步,我们可以生成$K$个最可能的单词,而不是1个,这个过程可以被描述为
\begin{equation}
\begin{eqnarray}
\{ \hat{y}_{j1},...,\hat{y}_{jk} \} = \argmax_{ \{ \hat{y}_{j1},...,\hat{y}_{jk} \} }
\textrm{P}(y_j | \{ \hat{\mathbf{y}}_{<{j^{\textrm{*}}}} \},\mathbf{x})
\label{eqC6.35}
\end{equation}
\end{eqnarray}
\noindent 这里,$\{ \hat{y}_{j1},...,\hat{y}_{jk} \}$表示对于位置$j$翻译概率最大的$K$的单词,$\{ \hat{\mathbf{y}}_{<j^{\ast}} \}$表示前$j-1$步top-K单词组成的所有历史。${\hat{\mathbf{y}}_{<j^{\ast}}}$可以被看作是一个集合,里面每一个元素都是一个目标语单词序列,这个序列是前面生成的一系列top-K单词的某种组成。$\textrm{P}(y_j | \{ \hat{\mathbf{y}}_{<{j^{\textrm{*}}}} \},\mathbf{x})$表示基于\{$ \hat{\mathbf{y}}_{<j^{\ast}} $\}的某一条路径生成$y_j$的概率\footnote{严格来说,P$(y_j | {\hat{\mathbf{y}}_{<j^{\ast}} })$不是一个准确的数学表达,这里我们通过这种写法强调$y_j$是由\{$ \hat{\mathbf{y}}_{<j^{\ast}} $\}中的某个译文单词序列作为条件生成的。} 。这种方法也被称为束搜索(beam search),意思是搜索时始终考虑一个集束内的候选。
......@@ -1141,8 +1143,8 @@ L(\mathbf{Y},\hat{\mathbf{Y}}) = \sum_{j=1}^n L_{\textrm{ce}}(\mathbf{y}_j,\hat{
\parinterval 束搜索是一种启发式图搜索算法。相比于全搜索,它可以减少搜索所占用的空间和时间,在每一步扩展的时候,剪掉一些质量比较差的结点,保留下一些质量较高的结点。具体到机器翻译任务,对于每一个目标语位置,束搜索选择了概率最大的前$K$个单词进行扩展(其中$K$叫做束宽度,或简称为束宽)。如图\ref{fig:6-33}所示,当$K=3$时,若令\{$y_1, y_2,…, y_n$\}表示生成的目标语序列,则束搜索的具体过程为:在预测第一个位置时,我们通过模型得到$y_1$的概率分布,选取概率最大的前3个单词作为候选结果(假设分别为``have'', ``has'', ``it'')。在预测第二个位置的单词时,模型针对已经得到的三个候选结果(``have'', ``has'', ``it'')计算第二个单词的概率分布。例如,我们可以在将``have''作为第二步的输入,计算$y_2$的概率分布。此时,译文序列的概率为
%--------------------------------------------
\begin{eqnarray}
\textrm{P} (y_2,y_1 | \mathbf{x}) & = & \textrm{P} (y_2, \textrm{``have''} | \mathbf{x}) \nonumber \\
& = & \textrm{P}(y_2 | \textrm{``have''} , \mathbf{x}) \textrm{P} (\textrm{``have''} | \mathbf{x})
\textrm{P} (y_2,y_1 | \mathbf{x}) &=& \textrm{P} (y_2, \textrm{``have''} | \mathbf{x}) \nonumber \\
&=& \textrm{P}(y_2 | \textrm{``have''} , \mathbf{x}) \textrm{P} (\textrm{``have''} | \mathbf{x})
\label{eqC6.36}
\end{eqnarray}
......@@ -1173,29 +1175,28 @@ L(\mathbf{Y},\hat{\mathbf{Y}}) = \sum_{j=1}^n L_{\textrm{ce}}(\mathbf{y}_j,\hat{
\parinterval 为了解决上面提到的问题,我们可以使用其它特征与$\textrm{log P}(\mathbf{y} | \mathbf{x})$一起组成新的模型得分$\textrm{score} ( \mathbf{y} , \mathbf{x})$。针对模型倾向于生成短句子的问题,常用的做法是引入惩罚机制。比如,可以定义一个惩罚因子,形式如下:
\begin{equation}
\begin{eqnarray}
\textrm{lp}(\mathbf{y}) = \frac {(5+ |\mathbf{y}|)^{\alpha}} {(5+1)^{\alpha}}
\label{eqC6.37}
\end{equation}
\end{eqnarray}
\noindent 其中,$|\mathbf{y}|$代表已经得到的译文长度,$\alpha$是一个固定的常数(通常取[0.6-0.7]),用于控制惩罚的强度。同时我们在句子得分的计算时,额外引入覆盖度的因子,如下:
\begin{equation}
\begin{eqnarray}
\textrm{cp}(\mathbf{y} , \mathbf{x}) = \beta \cdot \sum_{i=1}^{|\mathbf{x}|} \textrm{log} (\textrm{min}(\sum_j^{|\mathbf{y}|} \alpha_{ij},1 ) )
\label{eqC6.38}
\end{equation}
\end{eqnarray}
\noindent $\textrm{cp}(\cdot)$会惩罚把某些源语单词对应到很多目标语单词的情况(覆盖度),被覆盖的程度用$\sum_j^{|\mathbf{y}|} \alpha_{ij}$度量。$\beta$也是需要经验性设置的超参数(通常取1),用于对覆盖度惩罚的强度进行控制。
\parinterval 最终,模型得分定义如下:
\begin{equation}
\begin{eqnarray}
\textrm{score} ( \mathbf{y} , \mathbf{x}) = \frac{\textrm{log P}(\mathbf{y} | \mathbf{x})} {\textrm{lp}(\mathbf{y})} + \textrm{cp}(\mathbf{y} , \mathbf{x})
\label{eqC6.39}
\end{equation}
\end{eqnarray}
\noindent 显然,当目标语$y$过短时,$\textrm{lp}(\mathbf{y})$的值越小,因为$\textrm{log P}(\mathbf{y} | \mathbf{x})$是负数,所以句子得分$\textrm{score} ( \mathbf{y} , \mathbf{x})$越小。也就是说,模型会惩罚译文过短的结果。当覆盖度较高时,同样会使得分变低。通过这样的惩罚机制,使模型得分更为合理,从而帮助我们选择出质量更高的译文。
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
\subsection{实例-GNMT}\index{Chapter6.3.7}
\parinterval 循环神经网络在机器翻译中有很多成功的应用,比如、RNNSearch\cite{bahdanau2014neural}、Nematus\\ \cite{DBLP:journals/corr/SennrichFCBHHJL17}等系统就被很多研究者作为实验系统。在众多基于循环神经网络的系统中,GNMT系统是最成功的一个\cite{Wu2016GooglesNM}。GNMT是谷歌2016年发布的神经机器翻译系统。在GNMT之前,神经机器翻译有三个弱点:训练和推理速度较慢、在翻译稀有单词上缺乏鲁棒性和有时无法完整翻译源语言句子中的所有单词。GNMT的提出有效的解决了上述问题。
......@@ -1218,7 +1219,7 @@ L(\mathbf{Y},\hat{\mathbf{Y}}) = \sum_{j=1}^n L_{\textrm{ce}}(\mathbf{y}_j,\hat{
% 表
\begin{table}[htp]
\centering
\caption{GNMT与其它翻译模型对比\cite{Wu2016GooglesNM}}
\caption{GNMT与当时最优秀的模型}
\label{tab:gnmt vs state-of-the-art models}
\begin{tabular}{l l l l}
\multicolumn{1}{l|}{\multirow{2}{*}{\#}} & \multicolumn{2}{c}{\textbf{BLEU}} & \multirow{2}{*}{\textbf{CPU decoding time}} \\
......@@ -1300,8 +1301,8 @@ L(\mathbf{Y},\hat{\mathbf{Y}}) = \sum_{j=1}^n L_{\textrm{ce}}(\mathbf{y}_j,\hat{
% 图3.10
\begin{figure}[htp]
\centering
\input{./Chapter6/Figures/figure-Dependencies-between-words-in-a-recurrent-neural-network}
\caption{注意力机制中单词之间的依赖关系}
\input{./Chapter6/Figures/figure-Dependencies-between-words-of-Attention}
\caption{注意力机制中单词之间的依赖关系}
\label{fig:6-35}
\end{figure}
%----------------------------------------------
......@@ -1319,14 +1320,14 @@ L(\mathbf{Y},\hat{\mathbf{Y}}) = \sum_{j=1}^n L_{\textrm{ce}}(\mathbf{y}_j,\hat{
%----------------------------------------------
\parinterval 举个例子,如图\ref{fig:6-36}所示,一个汉语句子包含5个词。这里,我们用$\mathbf{h}$(``你'')表示``你''当前的表示结果。如果把``你''看作目标,这时$\mathrm{query}$就是$\mathbf{h}$(``你''),$\mathrm{key}$$\mathrm{value}$\\是图中所有位置的表示,即:{$\mathbf{h}$(``你'')、$\mathbf{h}$(``什么'')、$\mathbf{h}$(``也'')、$\mathbf{h}$(``没'')、$\mathbf{h}$(``学'')}。在自注意力模型中,首先计算$\mathrm{query}$$\mathrm{key}$的相关度,这里用$\alpha_i$表示$\mathbf{h}$(``你'')和位置$i$的表示之间的相关性。然后,把$\alpha_i$作为权重,对不同位置上的$\mathrm{value}$进行加权求和。最终,得到新的表示结果$\tilde{\mathbf{h}}$ (``你'' ):
\begin{equation}
\begin{eqnarray}
\tilde{\mathbf{h}} (\textrm{``你''} ) = \alpha_0 {\mathbf{h}} (\textrm{``你''} )
+ \alpha_1 {\mathbf{h}} (\textrm{``什么 ''})
+ \alpha_2 {\mathbf{h}} (\textrm{``也''} )
+ \alpha_3 {\mathbf{h}} (\textrm{``没''} )
+\alpha_4 {\mathbf{h}} (\textrm{``学''} )
\label{eqC6.40}
\end{equation}
\end{eqnarray}
\parinterval 同理,也可以用同样的方法处理这个句子中的其它单词。可以看出,在注意力机制中,我们并不是使用类似于循环神经网络的记忆能力去访问历史信息。序列中所有单词之间的信息都是通过同一种操作($\mathrm{query}$$\mathrm{key}$的相关度)进行处理。这样,表示结果$\tilde{\mathbf{h}} (\textrm{``你''})$在包含``你''这个单词的信息的同时,也包含了序列中其它词的信息。也就是,序列中每一个位置的表示结果中,都包含了其它位置的信息。从这个角度说,$\tilde{\mathbf{h}} (\textrm{``你''})$已经不在是单词''你''自身的表示结果,而是一种在单词``你''的位置上的全局信息的表示。
......@@ -1405,15 +1406,15 @@ L(\mathbf{Y},\hat{\mathbf{Y}}) = \sum_{j=1}^n L_{\textrm{ce}}(\mathbf{y}_j,\hat{
%----------------------------------------------
\parinterval 位置编码的计算方式有很多种,Transformer使用不同频率的正余弦函数:
\begin{equation}
\begin{eqnarray}
\textrm{PE}(pos,2i) = \textrm{sin} (\frac{pos}{10000^{2i/d_{model}}})
\label{eqC6.41}
\end{equation}
\end{eqnarray}
%----------------------------------------------
\begin{equation}
\begin{eqnarray}
\textrm{PE}(pos,2i+1) = \textrm{cos} (\frac{pos}{10000^{2i/d_{model}}})
\label{eqC6.42}
\end{equation}
\end{eqnarray}
\noindent 式中PE($\cdot$)表示位置编码的函数,$pos$表示单词的位置,$i$代表位置编码向量中的第几维。因为,正余弦函数的编码各占一半,因此当位置编码的维度为512时,$i$的范围是0-255。在Transformer中,位置编码的维度和词嵌入向量的维度相同,模型通过将二者相加作为模型输入,如图\ref{fig:6-41}所示。
......@@ -1428,25 +1429,21 @@ L(\mathbf{Y},\hat{\mathbf{Y}}) = \sum_{j=1}^n L_{\textrm{ce}}(\mathbf{y}_j,\hat{
%----------------------------------------------
\parinterval 那么为什么通过这种计算方式可以很好的表示位置信息?有三方面原因。首先,正余弦函数是具有上下界的周期函数,用正余弦函数可将长度不同的序列的位置编码的范围都固定到[-1,1],这样在与词的编码进行相加时,不至于产生太大差距。另外位置编码的不同维度对应不同的正余弦曲线,这为多维的表示空间赋予一定意义。最后,根据三角函数的性质:
\begin{equation}
\begin{array}{ll}
\textrm{sin}(\alpha + \beta) = \textrm{sin}\alpha \textrm{cos} \beta + \textrm{cos} \alpha \textrm{sin} \beta \\
\textrm{cos}(\alpha + \beta) = \textrm{cos} \alpha \textrm{cos} \beta - \textrm{sin} \alpha \textrm{sin} \beta
\end{array}
%------------------------
\begin{eqnarray}
\textrm{sin}(\alpha + \beta) &=& \textrm{sin}\alpha \textrm{cos} \beta + \textrm{cos} \alpha \textrm{sin} \beta \nonumber \\
\textrm{cos}(\alpha + \beta) &=& \textrm{cos} \alpha \textrm{cos} \beta - \textrm{sin} \alpha \textrm{sin} \beta
\label{eqC6.43}
\end{equation}
\end{eqnarray}
\parinterval 可以得到``$pos+k$''的位置编码为:
\begin{equation}
\begin{array}{ll}
\textrm{PE}(pos+k,2i) = \textrm{PE}(pos,2i) \times \textrm{PE}(k,2i+1)
+ \textrm{PE}(pos,2i+1) \times \textrm{PE}(k,2i) \\
\textrm{PE}(pos+k ,2i+1) = \textrm{PE}(pos,2i+1) \times \textrm{PE}(k,2i+1)
- \textrm{PE}(pos,2i) \times \textrm{PE}(k,2i)
\end{array}
\begin{eqnarray}
\textrm{PE}(pos+k,2i) &=& \textrm{PE}(pos,2i) \times \textrm{PE}(k,2i+1)
+ \textrm{PE}(pos,2i+1) \times \textrm{PE}(k,2i) \nonumber \\
\textrm{PE}(pos+k ,2i+1) &=& \textrm{PE}(pos,2i+1) \times \textrm{PE}(k,2i+1)
- \textrm{PE}(pos,2i) \times \textrm{PE}(k,2i) \nonumber \\
\label{eqC6.44}
\end{equation}
\end{eqnarray}
\noindent 即对于任意固定的偏移量$k$$\textrm{PE}(pos+k)$能被表示成$\textrm{PE}(pos)$的线性函数,换句话说,位置编码可以表示词之间的距离。在实践中发现,位置编码对Transformer系统的性能有很大影响。对其进行改进也会带来性能的进一步提升\cite{Shaw2018SelfAttentionWR}
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
......@@ -1469,11 +1466,11 @@ L(\mathbf{Y},\hat{\mathbf{Y}}) = \sum_{j=1}^n L_{\textrm{ce}}(\mathbf{y}_j,\hat{
\parinterval 在得到$\mathbf{Q}$$\mathbf{K}$$\mathbf{V}$后,我们便可以进行注意力机制的运算,这个过程可以被形式化为:
\begin{equation}
\begin{eqnarray}
\textrm{Attention}(\mathbf{Q},\mathbf{K},\mathbf{V}) = \textrm{Softmax}
( \frac{\mathbf{Q}\mathbf{K}^{T}} {\sqrt{d_k}} + \mathbf{Mask} ) \mathbf{V}
\label{eqC6.45}
\end{equation}
\end{eqnarray}
\noindent 首先,我们通过对$\mathbf{Q}$$\mathbf{K}$的转置进行点乘操作,计算得到一个维度大小为$L \times L$的相关性矩阵,即$\mathbf{Q}\mathbf{K}^{T}$,它表示一个序列上任意两个位置($i, i’$)的相关性。再通过系数1/$\sqrt{d_k}$进行放缩操作,放缩可以尽量减少相关性矩阵的方差,具体体现在运算过程中实数矩阵中的数值不会过大,有利于模型训练。在此基础上,我们通过对相关性矩阵累加一个掩码矩阵,来屏蔽掉矩阵中的无用信息。比如,在编码端对句子的补齐,在解码端则屏蔽掉未来信息,这一部分内容将在下一小节进行详细介绍。随后我们使用Softmax函数对相关性矩阵在行的维度上进行归一化操作,这可以理解为对第$i$行进行归一化,结果对应了$\mathbf{V}$中的不同位置上向量的注意力权重。对于$\mathrm{value}$的加权求和,可以直接用相关性性系数和$\mathbf{V}$进行矩阵乘法得到,即$\textrm{Softmax}
( \frac{\mathbf{Q}\mathbf{K}^{T}} {\sqrt{d_k}} + \mathbf{Mask} )$$\mathbf{V}$进行矩阵乘。最终我们就到了自注意力的输出,它和输入的$\mathbf{V}$的大小是一模一样的。图\ref{fig:6-43}展示了点乘注意力计算的全过程。
......@@ -1547,8 +1544,10 @@ L(\mathbf{Y},\hat{\mathbf{Y}}) = \sum_{j=1}^n L_{\textrm{ce}}(\mathbf{y}_j,\hat{
\parinterval 多头机制具体的计算公式如下:
%-------------------------------------------------------
\begin{eqnarray}
\textrm{MultiHead}(\mathbf{Q}, \mathbf{K} , \mathbf{V})& = & \textrm{Concat} (\mathbf{head}_1, ... , \mathbf{head}_h ) \mathbf{W}^o \\
\textrm{where} \mathbf{head}_i & = &\textrm{Attention} (\mathbf{Q}\mathbf{W}_i^Q , \mathbf{K}\mathbf{W}_i^K , \mathbf{V}\mathbf{W}_i^V )
\textrm{MultiHead}(\mathbf{Q}, \mathbf{K} , \mathbf{V})& =&
\textrm{Concat} (\mathbf{head}_1, ... , \mathbf{head}_h ) \mathbf{W}^o \nonumber \\
\textrm{where} \mathbf{head}_i & = &\textrm{Attention} (\mathbf{Q}\mathbf{W}_i^Q ,
\mathbf{K}\mathbf{W}_i^K , \mathbf{V}\mathbf{W}_i^V )
\label{eqC6.46}
\end{eqnarray}
......@@ -1571,10 +1570,10 @@ L(\mathbf{Y},\hat{\mathbf{Y}}) = \sum_{j=1}^n L_{\textrm{ce}}(\mathbf{y}_j,\hat{
\parinterval 残差连接从广义上讲也叫短连接(short-cut connection),指的是这种短距离的连接。它的思想很简单,就是把层和层之间的距离拉近。如图\ref{fig:6-47}所示,子层1通过残差连接跳过了子层2,直接和子层3进行信息传递。使信息传递变得更高效,有效解决了深层网络训练过程中容易出现的梯度消失/爆炸问题,使得深层网络的训练更加容易。其计算公式为:
\begin{equation}
\begin{eqnarray}
x_{l+1} = x_l + \digamma (x_l)
\label{eqC6.47}
\end{equation}
\end{eqnarray}
\noindent 其中$\digamma (x_l)$是子层运算。如果$l=2$,那么公式\ref{eqC6.47}可以解释为,第3层的输出等于第2层的输出加上第二层的输入。图\ref{fig:6-48}中的红色方框展示了Transformer中残差连接的位置。
......@@ -1590,10 +1589,10 @@ x_{l+1} = x_l + \digamma (x_l)
\parinterval 在Transformer的训练过程中,由于引入了残差操作,将前面所有层的输出加到一起。这样会导致不同层(或子层)的结果之间的差异性很大,造成训练过程不稳定、训练时间较长。为了避免这种情况,在每层中加入了层正则化操作\cite{Ba2016LayerN}。层正则化的计算公式如下:
\begin{equation}
\begin{eqnarray}
\textrm{LN}(x) = g \cdot \frac{x- \mu} {\sigma} + b
\label{eqC6.48}
\end{equation}
\end{eqnarray}
\noindent 该公式使用均值$\mu$和方差$\sigma$对样本进行平移缩放,将数据规范化为均值为0,方差为1的标准分布。$g$$b$是可学习的参数。
......@@ -1624,10 +1623,10 @@ x_{l+1} = x_l + \digamma (x_l)
\parinterval Transformer使用了全连接网络。全连接网络的作用主要体现在将经过注意力操作之后的表示映射到新的空间中,新的空间会有利于接下来的非线性变换等操作。实验证明,去掉全连接网络会对模型的性能造成影响。Transformer的全连接前馈神经网络包含两次线性变换和一次非线性变换(ReLU激活函数:ReLU$(x)=\textrm{max}(0,x)$),每层的前馈神经网络参数不共享,计算公式如下:
%---------------------------
\begin{equation}
\begin{eqnarray}
\textrm{FFN}(x) = \textrm{max} (0,\mathbf{x}\mathbf{W}_1 + \mathbf{b}_1)\mathbf{W}_2 + \mathbf{b}_2
\label{eqC6.49}
\end{equation}
\end{eqnarray}
\noindent 其中,$\mathbf{W}_1$$\mathbf{W}_2$$\mathbf{b}_1$$\mathbf{b}_2$为模型的参数。通常情况下,前馈神经网络的隐层维度要比注意力部分的隐层维度大,比如,注意力部分的隐层维度为512,前馈神经网络部分的隐层维度为2048。当然,继续增大前馈神经网络的隐层大小,比如设为4096,甚至8192,还可以带来性能的增益,但是前馈部分的存储消耗较大,需要更大规模GPU设备的支持。因此在具体实现时,往往需要在翻译准确性和存储/速度之间找到一个平衡。
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
......@@ -1651,10 +1650,10 @@ x_{l+1} = x_l + \digamma (x_l)
\item Transformer在学习率中同样应用了学习率预热(warmup)策略,其计算公式如下:
\begin{equation}
\begin{eqnarray}
lrate = d_{model}^{-0.5} \cdot \textrm{min} (step^{-0.5} , step \cdot warmup\_steps^{-1.5})
\label{eqC6.50}
\end{equation}
\end{eqnarray}
其中,$step$表示更新的次数(或步数)。通常设置网络更新的前4000步为预热阶段即$warmup\_steps=4000$。Transformer的学习率曲线如图\ref{fig:6-52}所示。在训练初期,学习率从一个较小的初始值逐渐增大(线性增长),当到达一定的步数,学习率再逐渐减小。这样做可以减缓在训练初期的不稳定现象,同时在模型达到相对稳定之后,通过逐渐减小的学习率让模型进行更细致的调整。这种学习率的调整方法是Transformer的一个很大的工程贡献。
\end{itemize}
......@@ -1664,7 +1663,7 @@ lrate = d_{model}^{-0.5} \cdot \textrm{min} (step^{-0.5} , step \cdot warmup\_st
\begin{figure}[htp]
\centering
\input{./Chapter6/Figures/figure-lrate-of-transformer}
\caption{Transformer模型的学习率曲线}
\caption{Transformer模型的学习率调整曲线}
\label{fig:6-52}
\end{figure}
%----------------------------------------------
......@@ -1705,12 +1704,12 @@ lrate = d_{model}^{-0.5} \cdot \textrm{min} (step^{-0.5} , step \cdot warmup\_st
% 表
\begin{table}[htp]
\centering
\caption{三种Transformer模型的对比}
\caption{三种Transformer的实验对比}
\label{tab:word-translation-examples}
\begin{tabular}{l | l l l}
\multirow{2}{*}{\#} & \multicolumn{2}{c}{BLEU} & \multirow{2}{*}{params} \\
& EN-DE & EN-FR & \\ \hline
\multirow{2}{*}{\#} & \multicolumn{2}{c}{\textbf{BLEU}} & \multirow{2}{*}{\textbf{params}} \\
& \textbf{EN-DE} & \textbf{EN-FR} & \\ \hline
Transformer Base & 27.3 & 38.1 & 65$\times 10^{6}$ \\
Transformer Big & 28.4 & 41.8 & 213$\times 10^{6}$ \\
Transformer Deep(48层) & 30.2 & 43.1 & 194$\times 10^{6}$ \\
......
Markdown 格式
0%
您添加了 0 到此讨论。请谨慎行事。
请先完成此评论的编辑!
注册 或者 后发表评论