Commit 2dfaa569 by zhoutao

合并分支 'zhoutao' 到 'caorunzhe'

update 7.5.1

查看合并请求 !42
parents 1ce63433 83c358e9
......@@ -1174,33 +1174,33 @@ b &=& \omega_{\textrm{high}}\cdot |\mathbf{x}|
\end{figure}
%-------------------------------------------
\parinterval$x_l$$x_{l+1}$表示第$l$子层的输入和输出\footnote[13]{这里沿用Transformer中的定义,每一层(Layer)包含多个子层(Sub-layer)。比如,对于Transformer编码器,每一层包含一个自注意力子层和一个前馈神经网络子层。所有子层都需要进行层归一化和残差连接。}$y_l$表示中间的临时输出;$\textrm{LN}(\cdot)$表示层归一化操作\cite{ba2016layer},帮助减少子层输出分布的方差。从而让训练变得更稳定;$\textrm{F}(\cdot)$表示子层所对应的函数,比如前馈神经网络、自注意力网络等。下面分别对Post-Norm和Pre-Norm进行简单的描述。
\parinterval$x_l$$x_{l+1}$表示第$l$子层的输入和输出\footnote[13]{这里沿用Transformer中的定义,每一层(Layer)包含多个子层(Sub-layer)。比如,对于Transformer编码器,每一层包含一个自注意力子层和一个前馈神经网络子层。所有子层都需要进行层归一化和残差连接。}$y_l$表示中间的临时输出;$\textrm{LN}(\cdot)$表示层归一化操作\cite{ba2016layer},帮助减少子层输出分布的方差。从而让训练变得更稳定;$\mathcal{F}(\cdot)$表示子层所对应的函数,比如前馈神经网络、自注意力网络等。下面分别对Post-Norm和Pre-Norm进行简单的描述。
\begin{itemize}
\vspace{0.5em}
\item Post-Norm:早期的Transformer遵循的是Post-Norm结构\cite{vaswani2017attention}。也就是,层正则化作用于 每一子层的输入和输出的残差结果上,如图\ref{fig:7.5-1}(a)所示。可以表示如下:
\begin{eqnarray}
x_{l+1}=\textrm{LN}(x_l+\textrm{F}(x_l;\theta_l))
x_{l+1}=\textrm{LN}(x_l+\mathcal{F}(x_l;\theta_l))
\label{eq:7.5-1}
\end{eqnarray}
其中,$\theta_l$是子层$l$的参数。
\vspace{0.5em}
\item Pre-Norm:通过调整层正则化的位置,将其放置于每一子层的输入之前,得到了Pre-Norm结构,如图\ref{fig:7.5-1}(b)所示。其思想与He等人的思想一致\cite{DBLP:conf/eccv/HeZRS16},也被广泛应用于最新的Transformer开源系统中\cite{VaswaniTensor2Tensor}\cite{Ottfairseq}\cite{KleinOpenNMT},公式如下:
\begin{eqnarray}
x_{l+1}=x_l+\textrm{F}(\textrm{LN}(x_l);\theta_l)
x_{l+1}=x_l+\mathcal{F}(\textrm{LN}(x_l);\theta_l)
\label{eq:7.5-2}
\end{eqnarray}
\end{itemize}
\parinterval 从上述公式可以看到Pre-Norm结构可以通过残差路径将底层网络的输出直接暴露给上层网络;另一方面从反向传播的角度看,使用Pre-Norm结构,顶层的梯度可以更容易地反馈到底层网络。这里以一个含有$L$个子层的结构为例。令$Loss$表示整个神经网络输出上的损失,$x_L$为顶层的输出。对于Post-Norm结构,根据链式法则,损失$Loss$相对于$x_l$的梯度可以表示为:
\begin{eqnarray}
\frac{\partial Loss}{\partial x_l}=\frac{\partial Loss}{\partial x_L} \times \prod_{k=l}^{L-1}\frac{\partial \textrm{LN}(y_k)}{\partial y_k} \times \prod_{k=l}^{L-1}(1+\frac{\partial \textrm{F}(x_k;\theta_k)}{\partial x_k})
\frac{\partial Loss}{\partial x_l}=\frac{\partial Loss}{\partial x_L} \times \prod_{k=l}^{L-1}\frac{\partial \textrm{LN}(y_k)}{\partial y_k} \times \prod_{k=l}^{L-1}(1+\frac{\partial \mathcal{F}(x_k;\theta_k)}{\partial x_k})
\label{eq:7.5-3}
\end{eqnarray}
其中$\prod_{k=l}^{L-1}\frac{\partial \textrm{LN}(y_k)}{\partial y_k}$表示在反向传播过程中经过层正则化得到的复合函数导数,$\prod_{k=l}^{L-1}(1+\frac{\partial \textrm{F}(x_k;\theta_k)}{\partial x_k})$代表每个子层间残差连接的导数。
其中$\prod_{k=l}^{L-1}\frac{\partial \textrm{LN}(y_k)}{\partial y_k}$表示在反向传播过程中经过层正则化得到的复合函数导数,$\prod_{k=l}^{L-1}(1+\frac{\partial \mathcal{F}(x_k;\theta_k)}{\partial x_k})$代表每个子层间残差连接的导数。
\parinterval 类似的,也能得到Pre-Norm结构的梯度计算结果,如下式所示:
\begin{eqnarray}
\frac{\partial Loss}{\partial x_l}=\frac{\partial Loss}{\partial x_L} \times (1+\sum_{k=l}^{L-1}\frac{\partial \textrm{F}(\textrm{LN}(x_k);\theta_k)}{\partial x_l})
\frac{\partial Loss}{\partial x_l}=\frac{\partial Loss}{\partial x_L} \times (1+\sum_{k=l}^{L-1}\frac{\partial \mathcal{F}(\textrm{LN}(x_k);\theta_k)}{\partial x_l})
\label{eq:7.5-4}
\end{eqnarray}
......@@ -1228,17 +1228,17 @@ x_{l+1}=x_l+\textrm{F}(\textrm{LN}(x_l);\theta_l)
%%%%%%%%%%%%%%%%%%
\subsubsection{层聚合}
\parinterval 尽管使用Pre-Norm结构可以很容易地训练深层Transformer模型,但从信息传递的角度看,Transformer模型中第$n$层的输入仅仅依赖于前一层的输出。虽然残差连接可以将信息跨层传递,但是对于很深的网络,整个模型的输入和输出之间仍需要很多次残差连接才能进行有效的传递。为了使上层的网络可以更加方便地访问下层网络的信息,一种思路是引入更多跨层的连接。最简单的一种方法是直接将所有层的输出都连接到最上层,达到聚合多层信息的目的\cite{DBLP:conf/emnlp/BapnaCFCW18}\cite{wang-etal-2018-multi-layer}。另一种更加有效的方式是使用{\small\bfnew{动态线性层聚合方法}}\index{动态线性层聚合方法}(Dynamic Linear Combination of Layers,DLCL)\index{Dynamic Linear Combination of Layers,DLCL}。在每一层的输入中不仅考虑前一层的输出,而是将前面所有层的中间结果(包括词嵌入)进行线性聚合,理论上等价于常微分方程中的高阶求解方法\cite{WangLearning}。以Pre-Norm结构为例,具体做法如下:
\parinterval 尽管使用Pre-Norm结构可以很容易地训练深层Transformer模型,但从信息传递的角度看,Transformer模型中第$n$层的输入仅仅依赖于前一层的输出。虽然残差连接可以将信息跨层传递,但是对于很深的网络,整个模型的输入和输出之间仍需要很多次残差连接才能进行有效的传递。为了使上层的网络可以更加方便地访问下层网络的信息,一种方法是直接引入更多跨层的连接。最简单的一种方法是直接将所有层的输出都连接到最上层,达到聚合多层信息的目的\cite{DBLP:conf/emnlp/BapnaCFCW18}\cite{wang-etal-2018-multi-layer}。另一种更加有效的方式是使用{\small\bfnew{动态线性层聚合方法}}\index{动态线性层聚合方法}(Dynamic Linear Combination of Layers,DLCL)\index{Dynamic Linear Combination of Layers,DLCL}。在每一层的输入中不仅考虑前一层的输出,而是将前面所有层的中间结果(包括词嵌入)进行线性聚合,理论上等价于常微分方程中的高阶求解方法\cite{WangLearning}。以Pre-Norm结构为例,具体做法如下:
\begin{itemize}
\vspace{0.5em}
\item 对于每一层的输出$x_{l+1}$,对其进行层正则化,得到
\item 对于每一层的输出$x_{l+1}$,对其进行层正则化,得到每一层的信息的表示
\begin{eqnarray}
z_{l}=\textrm{LN}(x_{l+1})
\label{eq:7.5-5}
\end{eqnarray}
注意,$z_0$表示词嵌入层的输出,$z_l(l>0)$表示Transformer网络中的各个子层。
\vspace{0.5em}
\item 定义一个维度为$(L+1)\times(L+1)$的权值矩阵$\mathbf{W}$,矩阵中每一行表示之前各子层对当前子层计算的贡献度,其中$L$是编码端(或解码端)的层数。令$\mathbf{W}_{l,i}$代表权值矩阵$\mathbf{W}$$l$$i$列的权重,则层聚合的输出为$z_i$的线性加权和:
\item 定义一个维度为$(L+1)\times(L+1)$的权值矩阵$\mathbf{W}$,矩阵中每一行表示之前各子层对当前子层计算的贡献度,其中$L$是编码端(或解码端)的层数。令$\mathbf{W}_{l,i}$代表权值矩阵$\mathbf{W}$$l$行第$i$列的权重,则层聚合的输出为$z_i$的线性加权和:
\begin{eqnarray}
g_l=\sum_{i=0}^{l}z_i\times \mathbf{W}_{l,i}
\label{eq:7.5-6}
......@@ -1256,23 +1256,21 @@ $g_l$会作为输入的一部分送入第$l+1$个子层。其网络的结构图\
\end{figure}
%-------------------------------------------
\parinterval 权值矩阵$\mathbf{W}$是一个下三角矩阵。开始时,对矩阵参数的每行进行平均初始化,即初始化矩阵$\mathbf{W}_0$的每一行各个位置的值为$1/M,M \in (1,2,3 \cdots L+1)$。 伴随着神经网络的训练,网络通过反向传播算法来不断更新$\mathbf{W}$中每一行不同位置权重的大小。
\parinterval 可以看到,权值矩阵$\mathbf{W}$是一个下三角矩阵。开始时,对矩阵参数的每行进行平均初始化,即初始化矩阵$\mathbf{W}_0$的每一行各个位置的值为$1/M,M \in (1,2,3 \cdots L+1)$。 伴随着神经网络的训练,网络通过反向传播算法来不断更新$\mathbf{W}$中每一行不同位置权重的大小。
\parinterval 动态线性层聚合的一个好处是,系统可以自动学习不同子层对当前子层的贡献度。在实验中也发现,离当前子层更近的部分贡献度(权重)会更大,这也是符合直觉的。
%%%%%%%%%%%%%%%%%%
\subsubsection{深层模型的训练加速}
\parinterval 相较于宽网络,训练这种窄而深的神经网络有更快的收敛速度,但伴随着训练数据的增加,以及模型进一步的加深,神经网络的训练代价成为不可忽视的问题。例如,在几千万甚至上亿的双语平行语料上训练一个48层的Transformer模型需要将几周的时间能达到收敛\footnote[14]{训练时间的估算是在单台8卡Titan V GPU服务器上得到的。}。因此,在保证模型精度不变的前提下如何高效地完成深层网络的训练也是至关重要的。在实践中能够发现,深层网络中相邻层之间具有一定的相似性。因此,一个想法是:能否通过不断复用浅层网络的参数来初始化更深层的网络,渐进式的训练深层网络,避免从头训练整个网络,进而达到加速深层网络训练的目的。
\parinterval 尽管训练这种窄而深的神经网络对比宽网络有更快的收敛速度,但伴随着训练数据的增加,以及模型进一步的加深,神经网络的训练代价成为不可忽视的问题。例如,在几千万甚至上亿的双语平行语料上训练一个48层的Transformer模型需要将几周的时间能达到收敛\footnote[14]{训练时间的估算是在单台8卡Titan V GPU服务器上得到的}。因此,在保证模型精度不变的前提下如何高效地完成深层网络的训练也是至关重要的。在实践中能够发现,深层网络中相邻层之间具有一定的相似性。因此,一个想法是:能否通过不断复用浅层网络的参数来初始化更深层的网络,渐进式的训练深层网络,避免从头训练整个网络,进而达到加速深层网络训练的目的。
%%%%%%%%%%%%%%%%%%
\vspace{0.5em}
\noindent {\small\bfnew{a) 渐进式训练}}
\vspace{0.5em}
\subsubsection{渐进式训练}
\parinterval 所谓渐进式训练是指从浅层网络开始,在训练过程中逐渐增加训练的深度。一种比较简单的方法是将网络分为浅层部分和深层部分,之后分别进行训练,最终达到提高模型翻译性能的目的\cite{DBLP:conf/acl/WuWXTGQLL19}
\parinterval 另一种方式是动态构建深层网络,并尽可能复用浅层网络的训练结果。假设开始的时候模型包含$h$层网络,然后训练这个模型至收敛。之后,直接拷贝这$h$层网络(包括参数),并堆叠出一个$2h$层的模型。之后继续训练,重复这个过程。进行$n$次之后就得到了$(n +1)\times h$层的模型。图\ref{fig:7.5-3}给出了在编码端使用渐进式训练的示意图。
\parinterval 另一种方式是动态构建深层网络,并尽可能复用浅层网络的训练结果。假设开始的时候模型包含$h$层网络,然后训练这个模型至收敛。之后,直接拷贝这$h$层网络(包括参数),并堆叠出一个$2h$层的模型。之后继续训练,重复这个过程。进行$n$次之后就得到了$n\times h$层的模型。图\ref{fig:7.5-3}给出了在编码端使用渐进式训练的示意图。
%----------------------------------------------
% 图7.5.3
......@@ -1287,14 +1285,9 @@ $g_l$会作为输入的一部分送入第$l+1$个子层。其网络的结构图\
\parinterval 渐进式训练的好处在于深层模型并不是从头开始训练。每一次堆叠,都相当于利用``浅''模型给``深''模型提供了一个很好的初始点,这样深层模型的训练会更加容易。
%%%%%%%%%%%%%%%%%%
\vspace{0.5em}
\noindent {\small\bfnew{b) 分组稠密连接}}
\vspace{0.5em}
\parinterval 很多研究者已经发现深层网络不同层之间的稠密连接能够很明显地提高信息传递的效率\cite{WangLearning}\cite{DBLP:journals/corr/HuangLW16a}\cite{DBLP:journals/corr/abs-1810-10181}\cite{DBLP:conf/acl/WuWXTGQLL19}。与此同时,对之前层信息的不断复用有助于得到更好的表示,但随之而来的是网络计算代价过大的问题。由于动态线性层聚合方法(DLCL)在每一次聚合时都需要重新计算之前每一层的贡献度,因此伴随着编码端整体深度的不断增加,这部分的计算代价变的不可忽略。例如,一个基于动态层聚合的48层Transformer模型的训练时间比不使用动态层聚合慢近1.9倍。同时,缓存中间结果也增加了显存的使用量,尽管使用了FP16计算,每张12G显存的GPU上计算的词也不能超过2048 个,这导致训练开销急剧增大。
\parinterval 缓解这个问题的一种方法是使用更稀疏的层间连接方式。其核心思想与动态线性层聚合是类似的,不同点在于可以通过调整层之间连接的稠密程度来降低训练代价。比如,可以将每$p$层分为一组,之后动态线性层聚合只在不同组之间进行。这样,通过调节$p$值的大小可以控制网络中连接的稠密程度,作为一种训练代价与翻译性能之间的权衡。显然,标准的Transformer模型\cite{vaswani2017attention}和DLCL模型\cite{WangLearning}都可以看作是该方法的一种特例。如图\ref{fig:7.5-4}所示:当$p=1$时,每一个单独的块被看作一个独立的组,这等价于基于动态层聚合的DLCL模型;当$p=\infty$时,这等价于正常的Transformer模型。值得注意的是,如果配合渐进式训练。在分组稠密连接中可以设置$p=h$
\subsubsection{分组稠密连接}
\parinterval 很多研究者已经发现深层网络不同层之间的稠密连接能够很明显地提高信息传递的效率\cite{WangLearning}\cite{DBLP:journals/corr/HuangLW16a}\cite{DBLP:journals/corr/abs-1810-10181}\cite{DBLP:conf/acl/WuWXTGQLL19}。与此同时,对之前层信息的不断复用有助于得到更好的表示,但随之而来的是网络计算代价过大的问题。由于动态线性层聚合方法(DLCL)在每一次聚合时都需要重新计算之前每一层表示对当前层网络输入的贡献度,因此伴随着编码端整体深度的不断增加,这部分的计算代价变的不可忽略。例如,一个基于动态层聚合的48层Transformer模型的训练时间比不使用动态层聚合慢近1.9倍。同时,缓存中间结果也增加了显存的使用量,尽管使用了FP16计算,每张12G显存的GPU上计算的词也不能超过2048个,这导致训练开销急剧增大。
%----------------------------------------------
% 图7.5.4
......@@ -1306,14 +1299,14 @@ $g_l$会作为输入的一部分送入第$l+1$个子层。其网络的结构图\
\end{figure}
%-------------------------------------------
\parinterval 缓解这个问题的一种方法是使用更稀疏的层间连接方式。其核心思想与动态线性层聚合是类似的,不同点在于可以通过调整层之间连接的稠密程度来降低训练代价。比如,可以将每$p$层分为一组,之后动态线性层聚合只在不同组之间进行。这样,通过调节$p$值的大小可以控制网络中连接的稠密程度,作为一种训练代价与翻译性能之间的权衡。显然,标准的Transformer模型\cite{vaswani2017attention}和DLCL模型\cite{WangLearning}都可以看作是该方法的一种特例。如图\ref{fig:7.5-4}所示:当$p=1$时,每一个单独的块被看作一个独立的组,这等价于基于动态层聚合的DLCL模型;当$p=\infty$时,这等价于正常的Transformer模型。值得注意的是,如果配合渐进式训练。在分组稠密连接中可以设置$p=h$
%%%%%%%%%%%%%%%%%%
\vspace{0.5em}
\noindent {\small\bfnew{c) 学习率重置策略}}
\vspace{0.5em}
\subsubsection{学习率重置策略}
\parinterval 尽管渐进式训练策略与分组稠密连接结构可以加速深层网络的训练,但使用传统的学习率衰减策略会导致堆叠深层模型时的学习率较小,因此模型无法快速地达到收敛状态,同时也影响最终的模型性能。
\parinterval\ref{fig:7.5-5}中的红色曲线描绘了标准的Transformer模型的学习率曲线\cite{vaswani2017attention}可以看到当模型训练到40k步时,网络的学习率值对比峰值有明显的差距,而此时刚开始训练最终的深层模型,过小的学习率并不利于后期深层网络的充分训练。
\parinterval\ref{fig:7.5-5}中的红色曲线描绘了标准的Transformer模型的学习率曲线(WMT英德任务),可以看到当模型训练到40k步时,网络的学习率值对比峰值有明显的差距,而此时刚开始训练最终的深层模型,过小的学习率并不利于后期深层网络的充分训练。
%----------------------------------------------
% 图7.5.5
......@@ -1325,7 +1318,7 @@ $g_l$会作为输入的一部分送入第$l+1$个子层。其网络的结构图\
\end{figure}
%-------------------------------------------
\parinterval 针对该问题的一个解决方案是修改学习率曲线的衰减策略。图中蓝色的曲线是修改后的学习率曲线。首先在训练的初期让网络快速的达到学习率的峰值(线性递增),之后的每一次网络深度增加$h$时,都会将当前的学习率值重置到峰值点。之后,根据训练的步数对其进行相应的衰减。具体的步骤如下:
\parinterval 针对该问题的一个解决方案是修改学习率曲线的衰减策略。图中蓝色的曲线是修改后的学习率曲线。首先在训练的初期让网络快速的达到学习率的峰值(线性递增),之后的每一次$p$层网络变为$2p$层网络时,都会将当前的学习率值重置到峰值点。之后,根据训练的步数对其进行相应的衰减。具体的步骤如下:
\begin{itemize}
\vspace{0.5em}
\item 在训练的初期,模型先经历一个学习率预热的过程:
......@@ -1343,14 +1336,14 @@ lr=d_{model}^{-0.5}\cdot step\_num^{-0.5}
这里$step\_num$代表学习率重置后更新的步数。
\end{itemize}
\parinterval 综合使用渐进式训练、分组稠密连接、学习率重置策略可以在保证翻译品质不变的前提下,缩减近40\%的训练时间(40层编码器)。同时,加速比伴随着模型的加深与数据集的增大会进一步扩大。
\parinterval 综合使用渐进式训练、分组稠密连接、学习率重置策略可以在保证翻译品质不变的前提下,缩减近40\%的训练时间(40层编码器)。同时,加速比伴随着模型的加深与数据集的增大会进一步扩大。
%%%%%%%%%%%%%%%%%%
\subsubsection{深层模型的鲁棒性训练}
\parinterval 伴随着网络加深的同时,还会面临另外一个比较严峻的问题\ \dash \ 过拟合。由于参数量的增大,深层网络的输入与输出分布之间的差异也会越来越大,然而不同子层之间的{\small\bfnew{相互适应}}\index{相互适应}(Co-adaptation)\index{Co-adaptation}也会更加的明显,导致任意子层网络对其他子层的依赖过大。这对于训练阶段是有帮助的,因为不同子层可以协同工作从而更好地拟合训练数据。然而这种方式也降低了模型的泛化能力,即深层网络更容易陷入过拟合问题。
\parinterval 伴随着网络加深的同时,还会面临另外一个比较严峻的问题\ \dash \ 过拟合。由于参数量的增大,深层网络的输入与输出分布之间的差异也会越来越大,然而不同子层之间的{\small\bfnew{相互适应}}\index{相互适应}(Co-adaptation)\index{Co-adaptation}也会更加的明显,导致任意子层网络对其他子层的依赖过大。这对于训练阶段是有帮助的,因为不同子层可以协同工作从而更好地拟合训练数据。然而这种方式也降低了模型的泛化能力,即深层网络更容易陷入过拟合问题。
\parinterval 通常,可以使用Dropout手段用来缓解过拟合问题(见\ref{subsection-7.3.1}节)。不幸的是,尽管目前Transformer模型使用了多种Dropout手段(如Residual Dropout、Attention Dropout、 ReLU Dropout等),过拟合问题在深层网络中仍然存在。从图\ref{fig:7.5-6}中可以看到,深层网络对比浅层网络在训练集和校验集的困惑度上都有显著的优势,然而神经网络在训练一段时间后出现校验集困惑度上涨的现象,说明模型已经过拟合于训练数据。
\parinterval 通常,可以使用Dropout手段用来缓解过拟合问题(见\ref{subsection-7.3.1}节)。不幸的是,尽管目前Transformer模型使用了多种Dropout手段(如Residual Dropout、Attention Dropout、 ReLU Dropout等),过拟合问题在深层网络中仍然存在。从图\ref{fig:7.5-6}中可以看到,深层网络对比浅层网络在训练集和校验集的困惑度上都有显著的优势,然而网络在训练一段时间后出现校验集困惑度上涨的现象,说明模型已经过拟合于训练数据。
%----------------------------------------------
% 图7.5.6
......@@ -1364,21 +1357,21 @@ lr=d_{model}^{-0.5}\cdot step\_num^{-0.5}
\parinterval\ref{subsection-7.3.1}节提到的Layer Dropout方法可以有效地缓解这个问题。以编码端为例, Layer Dropout的过程可以被描述为:在训练过程中,对自注意力子层或前馈神经网络子层进行随机丢弃,以减少不同子层之间的相互适应。这里选择Pre-Norm结构作为基础架构,它可以被描述为:
\begin{eqnarray}
x_{l+1}=\textrm{F}(\textrm{LN}(x_l))+x_l
x_{l+1}=\mathcal{F}(\textrm{LN}(x_l))+x_l
\label{eq:7.5-9}
\end{eqnarray}
其中$\textrm{LN}( \cdot )$表示层正则化函数, $\textrm{F}( \cdot )$表示自注意力机制或者前馈神经网络,$x_l$表示第$l$个子层的输出。之后,使用一个掩码$M$(值为0或1)来控制每一子层是正常计算还是丢弃。于是,该子层的计算公式可以被重写为:
其中$\textrm{LN}( \cdot )$表示层正则化函数, $\mathcal{F}( \cdot )$表示自注意力机制或者前馈神经网络,$x_l$表示第$l$个子层的输出。之后,使用一个掩码$M$(值为0或1)来控制每一子层是正常计算还是丢弃。于是,该子层的计算公式可以被重写为:
\begin{eqnarray}
x_{l+1}=M \cdot \textrm{F}(\textrm{LN}(x_l))+x_l
x_{l+1}=M \cdot \mathcal{F}(\textrm{LN}(x_l))+x_l
\label{eq:7.5-10}
\end{eqnarray}
$M=0$代表该子层被丢弃,而$M=1$代表正常进行当前子层的计算。
$M=0$代表该子层被丢弃,而$M=1$代表正常进行当前子层的计算。图ref{fig:7.5-7}展示了这个方法与标准Transformer之间的区别。
\parinterval 除此之外,有研究者已经发现残差网络中底层的子网络对最终的输出有很大的影响,上层网络是通过对底层网络得到的结果不断修正来拟合训练目标\cite{journals/corr/GreffSS16}。该结论同样适用于Transformer模型,比如,在训练中,残差支路以及底层的梯度范数通常比较大,这也间接表明底层网络在整个优化的过程中需要更大程度的更新。考虑到这个因素,在设计每一个子层被丢弃的概率时可以采用自底向上逐渐增大的策略,保证底层的网络相比于顶层更容易保留下来。这里用$L$来代表编码端的层数,$l$代表当前的子层的编号,那么$M$可以通过以下的方式得到:
\parinterval 除此之外,有研究者已经发现残差网络中底层的子网络通过对输入进行抽象得到的表示对最终的输出有很大的影响,上层网络是通过对底层网络得到的表示不断修正来拟合训练目标\cite{journals/corr/GreffSS16}。该结论同样适用于Transformer模型,比如,在训练中,残差支路以及底层的梯度范数通常比较大,这也间接表明底层网络在整个优化的过程中需要更大的更新。考虑到这个因素,在设计每一个子层被丢弃的概率时可以采用自底向上线性增大的策略,保证底层的网络相比于顶层更容易保留下来。这里用$L$来代表编码端块的个数,$l$代表当前的子层的编号,那么$M$可以通过以下的方式得到:
\begin{eqnarray}
M = \left\{\begin{array}{ll}
0&P \leq p_l\\
1&P > p_l
0&\textrm{p} \leqslant p_l\\
1&\textrm{p} > p_l
\end{array}\right.
\label{eq:7.5-11}
\end{eqnarray}
......@@ -1387,7 +1380,7 @@ M = \left\{\begin{array}{ll}
p_l=\frac{l}{2L}\cdot \varphi
\label{eq:7.5-12}
\end{eqnarray}
这里,$1 \leq l \leq 2L$ ,且$\varphi$是预先设定的超参数。
这里,$1 \leqslant l \leqslant 2L$ ,且$\varphi$是预先设定的超参数。
\parinterval 在Layer Dropout中,一个由$2L$个子层构成的残差网络,其顶层的输出相当于是$2^{2L}$个子网络的聚合结果。通过随机丢弃$n$个子层,则会屏蔽掉$2^n$个子网络的输出,将子网络的总体数量降低至$2^{2L-n}$。如图\ref{fig:7.5-7}所示的残差网络展开图,当有3个子层时,从输入到输出共存在8条路径,当删除子层sublayer2后,从输入到输出路径的路径则会减少到4条。
......@@ -1404,7 +1397,7 @@ p_l=\frac{l}{2L}\cdot \varphi
%--7.5.2 单语数据的使用---------------------
\subsection{单语数据的使用}\label{subsection-4.2.6}
\parinterval 在统计机器翻译时代,使用单语数据训练语言模型是构建机器翻译系统的关键步骤。好的语言模型往往会带来性能的增益。而这个现象在神经机器翻译中似乎并不明显,因为在大多数神经机器翻译的范式中,并不要求使用大规模单语数据来帮助机器翻译系统。甚至,连语言模型都不会作为一个独立的模块。这一方面是由于神经机器翻译系统的解码端本身就起着语言模型的作用,另一方面是由于数据的增多使得翻译模型可以更好的捕捉目标语言的规律。
\parinterval 在统计机器翻译时代,使用单语数据训练语言模型是构建机器翻译系统的关键步骤。好的语言模型往往会带来性能的增益。而这个现象在神经机器翻译中似乎并不明显,因为在大多数神经机器翻译的范式中,并不要求使用大规模单语数据来帮助机器翻译系统。甚至,连语言模型都不会作为一个独立的模块。这一方面是由于神经机器翻译系统的解码端本身就起着语言模型的作用,另一方面是由于数据的增多使得翻译模型可以更好的捕捉目标语言的规律。
\parinterval 但是,双语数据总是有限的。很多场景下,单语数据的规模会远大于双语数据。比如,在专利翻译的很多细分领域中,双语数据的规模十分有限,但是有大量的和领域相关的单语数据。如果能够让这些单语数据发挥作用,显然是一种非常好的选择。
......@@ -1432,7 +1425,7 @@ p_l=\frac{l}{2L}\cdot \varphi
\vspace{0.3em}
\end{itemize}
\parinterval 使用单语数据构建(双语)伪数据属于后者,它也是一种典型的{\small\bfnew{数据增强}}\index{数据增强}(Data Augmentation)\index{Data Augmentation}方法。一种常用做法是{\small\bfnew{回译}}\index{回译}(Back Translation)\index{Back Translation}\cite{DBLP:conf/acl/SennrichHB16}\cite{DBLP:conf/emnlp/EdunovOAG18}:训练一个从目标语翻译到源语的系统,也就是一个反向翻译系统;之后,用这个系统翻译目标语言单语数据;最后将单语数据(目标语言)和翻译的结果(源语言)作为训练数据,送入源语言到目标语言的翻译系统。这种做法不需要更改模型结构就能很好的利用单语数据,因此也被广泛采用。图\ref{fig:application-process-of-back-translation}给出了回译方法的一个简要流程。
\parinterval 使用单语数据构建(双语)伪数据属于后者,它也是一种典型的{\small\bfnew{数据增强}}\index{数据增强}(Data Augmentation)\index{Data Augmentation}方法。一种常用做法是{\small\bfnew{回译}}\index{回译}(Back Translation)\index{Back Translation}\cite{DBLP:conf/acl/SennrichHB16}\cite{DBLP:conf/emnlp/EdunovOAG18}:训练一个从目标语翻译到源语的系统,也就是一个反向翻译系统;之后,用这个系统翻译目标语言单语数据;最后将单语数据(目标语言)和翻译的结果(源语言)作为训练数据,送入源语言到目标语言的翻译系统。这种做法不需要更改任何模型结构,就能很好的利用单语数据,因此也被广泛采用。图\ref{fig:application-process-of-back-translation}给出了回译方法的一个简要流程。
%----------------------------------------------
% 图
\begin{figure}[htp]
......@@ -1443,7 +1436,7 @@ p_l=\frac{l}{2L}\cdot \varphi
\end{figure}
%-------------------------------------------
\parinterval 在理想情况下,生成的伪数据和真实数据分布越接近越好。不过,在实践中发现,即使一些简单的策略也能带来性能的增长。比如,在一些低资源的语种,仅仅通过将目标语句子复制到源语端构造的伪数据都能为模型带来增益\cite{DBLP:conf/wmt/CurreyBH17}。相比这些简单的构造策略,利用目标语言单语数据进行回译可以获得更高质量的伪数据。因为目标语是正确的句子,这种方法可以保证译文的流畅度。这也间接达到了对目标语言进行语言建模的目的。在富资源的翻译任务中,通常对回译产生的源语句子添加一些噪声,比如随机删除、替换一些词,或者交换两个词的位置,这样可以为模型提供一些训练噪声。而在低资源的语种上,由于双语数据稀缺,模型需要更多的高质量双语数据,不加噪声反而具有更好的效果。
\parinterval 在理想情况下,生成的伪数据和真实数据分布越接近越好。不过,在实践中发现,即使一些简单的策略也能带来性能的增长。比如,在一些低资源的语种,仅仅通过将目标语句子复制到源语端构造的伪数据都能为模型带来增益\cite{DBLP:conf/wmt/CurreyBH17}。相比这些简单的构造策略,利用目标语言单语数据进行回译可以获得更高质量的伪数据。因为目标语是正确的句子,这种方法可以保证译文的流畅度。这也间接达到了对目标语言进行语言建模的目的。在富资源的语种中,通常对回译产生的源语句子添加一些噪音,比如随机删除、替换一些词,或者交换两个词的位置,这样可以为模型提供一些训练噪声。而在低资源的语种上,由于双语数据稀缺,模型需要更多的高质量双语数据,不加噪音反而具有更好的效果。
\parinterval 回译方法的一个问题是:反向翻译模型的训练只依赖于有限的双语数据,生成的源语言端伪数据的质量难以保证。为此,可以采用{\small\bfnew{迭代式回译}}\index{迭代式回译}(Iterative Back Translation)\index{Iterative Back Translation}的方法,同时利用源语端和目标语端的单语数据,不断通过回译的方式来提升前向和反向翻译模型的性能。图\ref{fig:example-of-iterative-back-translation}展示了迭代式回译的框架。首先使用双语数据训练一个前向翻译模型,然后利用源语言单语数据通过回译的方式来提升反向翻译模型的性能,最后由反向翻译模型和目标端单语数据生成的伪数据来提升前向翻译模型的性能。可以看出,这个往复的过程是闭环的,因此可以一直进行下去,直到两个翻译模型的性能不再提升。
%----------------------------------------------
......@@ -1456,12 +1449,12 @@ p_l=\frac{l}{2L}\cdot \varphi
\end{figure}
%-------------------------------------------
\parinterval 与回译的方法类似,源语言的单语数据也可以通过一个双语数据训练的翻译模型获得对应的目标语,构造{\small\bfnew{前向翻译}}\index{前向翻译}(Forward Translation)\index{Forward Translation}的伪数据。与回译方法相反,前向翻译伪数据中源语端是真实的,而目标语端是机器翻译系统生成的,构造的伪数据对译文的流畅性并没有太大保证。其主要作用是提升翻译模型中编码器的效果。大多数情况下,前向翻译方法带来的性能提升效果要弱于回译。
\parinterval 与回译的方法类似,源语言的单语数据也可以通过一个双语数据训练的翻译模型获得对应的目标语,构造{\small\bfnew{前向翻译}}\index{前向翻译}(Forward Translation)\index{Forward Translation}的伪数据。与回译方法相反,前向翻译伪数据中源语端是真实的,而目标语端是生成的,构造的伪数据对译文的流畅性并没有太大帮助,其主要作用是丰富了训练数据中源语的表示,提升翻译模型中编码器的性能。大多数情况下,前向翻译方法带来的性能提升效果要弱于回译。
%%%%%%%%%%%%%%%%%%
\subsubsection{预训练}
\parinterval 编码器-解码器框架天然就包含了对输入(源语言)和输出(目标语言)进行表示学习的问题。比如,在编码端需要学习一种{\small\bfnew{分布式表示}}\index{分布式表示}(Distributed Representation)\index{Distributed Representation}来表示源语言句子的信息,这种分布式表示既包含单词的表示也包括整个序列的表示。因此,可以使用更大规模的源语言单语数据完成编码器的训练。
\parinterval 编码器-解码器框架天然就包含了对输入(源语言)和输出(目标语言)进行表示学习的问题。比如,在编码端需要学习一种分布式表示(Distributed Representation)来表示源语言句子的信息,这种分布式表示既包含单词的表示也包括整个序列的表示。因此,可以使用更大规模的源语言单语数据完成编码器的训练。
\parinterval 实现上述想法的一种手段是{\small\bfnew{预训练}}\index{预训练}(Pre-training)\index{Pre-training}。常用的方法是将机器翻译模型中的一部分(比如,编码器)单独提抽取出来,之后用语言建模等方式在大规模单语数据上进行训练。得到的优化后的参数后,将其重新放入神经机器翻译模型中,作为模型的初始值。最后,神经机器翻译模型在双语数据上进行{\small\bfnew{微调}}\index{微调}(Fine-tuning)\index{Fine-tuning},以得到最终的翻译模型。图\ref{fig:figure-encoder-fin}给出了机器翻译编码器预训练流程的示意图。
%----------------------------------------------
......@@ -1477,25 +1470,19 @@ p_l=\frac{l}{2L}\cdot \varphi
\parinterval 预训练的做法相当于对目标任务进行了简化,将表示模型的学习任务从目标任务中分离出来了。这样,可以学习一种更加通用的模型,具有更好的泛化能力。此外,预训练的任务相比于机器翻译要简单许多,比如语言模型或者句子调序等。将预训练任务的结果作为机器翻译模型的初始值可以减轻目标任务上的学习负担。在第六章中已经介绍了几种基于预训练方法,如ELMO、GPT和BERT等。这些模型的结构和神经机器翻译是兼容的,比如,BERT使用的就是Transformer模型。因此可以直接使用这些模型进行面向机器翻译的预训练。
%%%%%%%%%%%%%%%%%%
\vspace{0.5em}
\noindent {\small\bfnew{a) 词嵌入预训练}}
\vspace{0.5em}
\noindent {\small\bfnew{词嵌入预训练}}
\parinterval 词嵌入可以被看作是对每个独立单词进行的表示学习,在自然语言处理的众多任务中都扮演着重要角色\cite{DBLP:journals/corr/abs-1901-09069}。因此,可以使用第五章介绍的词嵌入方法,在外部单语数据上训练得到词嵌入,并把它作为神经机器翻译系统的词嵌入输入。
\parinterval 需要注意的是,在神经机器翻译中使用预训练的词嵌入有两种方法。一种方法是直接将词嵌入作为固定的输入,也就是,在训练机器翻译模型的过程中,不调整词嵌入的参数。这样做的目的是完全将词嵌入模块独立出来,机器翻译可以被看作是在固定的词嵌入输入上进行的建模。另一种方法是仍然遵循``预训练+微调''的策略,将词嵌入作为翻译模型的初始值。之后在机器翻译训练过程中,词嵌入模型结果会被进一步更新。近些年,在词嵌入预训练的基础上进行微调的方法受到研究者更多的青睐。
\parinterval 需要注意的是,在神经机器翻译中使用预训练的词嵌入有两种方法。一种方法是直接将词嵌入作为固定的输入,也就是在训练机器翻译模型的过程中,并不调整词嵌入的参数。这样做的目的是完全将词嵌入模块独立出来,机器翻译可以被看作是在固定的词嵌入输入上进行的建模。另一种方法是仍然遵循``预训练+微调''的策略,将词嵌入作为翻译模型的初始值。之后在机器翻译训练过程中,词嵌入模型结果会被进一步更新。近些年,在词嵌入预训练的基础上进行微调的方法受到研究者更多的青睐。
%%%%%%%%%%%%%%%%%%
\vspace{0.5em}
\noindent {\small\bfnew{b) 编码器预训练}}
\vspace{0.5em}
\noindent {\small\bfnew{编码器预训练}}
\parinterval 编码器在神经机器翻译中的作用是对源语句子中的信息进行抽象和提取,将离散的词序列编码成一组上下文相关的向量表示,本质上就是一个源语端的句子表示模型。因此,可以使用预训练好的句子级表示模型(比如,BERT和XLM等),来初始化编码器参数。然而在实践中发现,这种参数初始化的方法在一些富资源语种上提升效果并不明显甚至反而有些下降\cite{DBLP:journals/corr/abs-2002-06823}。原因可能在于预训练模型和编码器虽然都是对句子进行表示,但是由于目标任务不一致,二者的参数状态还是存在区别的。因此,也有一些做法将预训练模型和翻译模型在结构上进行融合,将预训练句子模型作为一个独立的模块来为编码器或者解码器提供句子级表示信息\cite{DBLP:journals/corr/abs-2002-06823}
%%%%%%%%%%%%%%%%%%
\vspace{0.5em}
\noindent {\small\bfnew{c) 序列到序列预训练}}
\vspace{0.5em}
\noindent {\small\bfnew{序列到序列预训练}}
\parinterval 传统的预训练模型都是针对自然语言理解任务设计的,比如情感分类和命名实体识别等任务。其目的是获得更好的句子表示结果,并用于下游任务。而在机器翻译和文本摘要等序列到序列的语言生成任务,不只包含源语言表示学习的问题,还有序列到序列的映射,以及目标端序列生成的问题,这些知识是无法通过(源语言)单语数据学习到的。为了能够在序列到序列任务上更好的使用单语数据,可以同时使用源语言和目标语言单语数据的预训练。
%----------------------------------------------
......@@ -1515,7 +1502,7 @@ p_l=\frac{l}{2L}\cdot \varphi
\parinterval {\small\bfnew{多任务学习}}\index{多任务学习}(Multitask Learning)\index{Multitask Learning}是机器学习的一个子领域,是指同时学习多个独立但是相关的任务\cite{DBLP:journals/corr/Ruder17a}。多任务学习通过模型共享的方式,对多个模型进行学习,而这些模型都对应不同的任务,这样不同模型可以互相``促进''。在神经机器翻译中,为了使用单语数据,可以将翻译任务作为主任务,同时设置一些仅使用单语数据的子任务,通过这些子任务来捕捉单语数据中的语言知识\cite{DBLP:conf/emnlp/DomhanH17}
\parinterval 语言模型是使用目标端单语数据最直接的方式,但是翻译模型需要依赖于源语言,并不能直接融合进行多任务学习。针对这个问题,可以对原有翻译模型结构进行修改,在解码器中增加了一个语言模型子层,将这个子层用于语言模型任务(图\ref{fig:target-side-multi-task-learning})。在训练过程中,分别将双语数据和单语数据送入翻译模型和语言模型进行计算,得到的损失相加用于整体模型参数的梯度计算和参数更新,其中语言模型的参数是翻译模型的一部分。
\parinterval 语言模型是使用目标端单语数据最直接的方式,但是翻译模型作为一个受限的语言模型,还需要依赖于源语,并不能直接融合进行多任务学习。针对这个问题,对原有翻译模型结构进行了修改,在解码器中增加了一个语言模型子层,将这个子层用于语言模型任务(图\ref{fig:target-side-multi-task-learning})。在训练过程中,分别将双语数据和单语数据送入翻译模型和语言模型进行计算,得到的损失相加用于整体模型参数的梯度计算和参数更新,其中语言模型的参数是翻译模型的一部分。
%----------------------------------------------
% 图
\begin{figure}[htp]
......@@ -1532,34 +1519,32 @@ p_l=\frac{l}{2L}\cdot \varphi
\subsection{知识精炼}
\label{subsection-7.5.3}
\parinterval 理想的机器翻译系统应该是品质好、速度块、存储占用少。不过现实的机器翻译系统往往需要用运行速度和存储空间来换取翻译品质,比如,\ref{subsection-7.3.2}节提到的增大模型容量的方法就是通过增加模型参数量来达到更好的函数拟合效果,但是这也导致系统变得更加笨。在很多场景下,这样的模型甚至无法使用。比如,Transformer-Big等``大''模型通常在专用GPU服务器上运行,在手机等受限环境下仍很难应用。
\parinterval 理想的机器翻译系统应该是品质好、速度块、存储占用少。不过现实的机器翻译系统往往需要用运行速度和存储空间来换取翻译品质,比如,\ref{subsection-7.3.2}节提到的增大模型容量的方法就是通过增加模型参数量来达到更好的函数拟合效果,但是这也导致系统变得更加笨。在很多场景下,这样的模型甚至无法使用。比如,Transformer-Big等``大''模型通常在专用GPU服务器上运行,在手机等受限环境下仍很难应用。
\parinterval 另一方面,直接训练``小''模型的效果往往并不理想,其翻译品质与``大''模型相比仍有比较明显的差距。比如,在Transformer中,使用一个48层的编码器要比传统的6层编码器在BLEU上高出1-2个点,而且两者翻译结果的人工评价的区别也十分明显。
\parinterval 因此,一种有趣的想法是把``大''模型的知识传递给``小''模型,让``小''模型可以更好的进行学习。这类似于,教小孩子学习数学,是请一个权威数学家(数据中的标准答案),还是请一个小学数学教师(``大''模型)。这就是知识精炼的基本思想。
\parinterval 面对小模型难以训练的问题,一种有趣的想法是把``大''模型的知识传递给``小''模型,让``小''模型可以更好的进行学习。这类似于,教小孩子学习数学,是请一个权威数学家(数据中的标准答案),还是请一个小学数学教师(``大''模型)。这就是知识精炼的基本思想。
%%%%%%%%%%%%%%%%%%
\subsubsection{什么是知识精炼}
\parinterval 通常,{\small\bfnew{知识精炼}}\index{知识精炼}(Knowledge Distillation)\index{Knowledge Distillation}可以被看作是一种知识迁移的手段\cite{Hinton2015Distilling}。如果把``大''模型的知识迁移到``小''模型,这种方法的直接结果就是{\small\bfnew{模型压缩}}\index{模型压缩}(Model Compression)\index{Model Compression}。当然,理论上也可以把``小''模型的知识迁移到``大''模型,比如,将迁移后得到的``大''模型作为初始状态,之后继续训练该模型,以期望取得加速训练收敛的效果。不过,在实践中更多是使用``大''模型到``小''模型的迁移,这也是本节讨论的重点。
\parinterval 通常,知识精炼可以被看作是一种知识迁移的手段\cite{Hinton2015Distilling}。如果把``大''模型的知识迁移到``小''模型,这种方法的直接结果就是{\small\bfnew{模型压缩}}\index{模型压缩}(Model Compression)\index{Model Compression}。当然,理论上也可以把``小''模型的知识迁移到``大''模型,比如,将迁移后得到的``大''模型作为初始状态,之后继续训练该模型,以期望取得加速收敛的效果。不过,在实践中更多是使用``大''模型到``小''模型的迁移,这也是本节讨论的重点。
\parinterval 知识精炼基于两个假设:
\begin{itemize}
\vspace{0.3em}
\item ``知识''在模型间是可迁移的。也就是说,一个模型中蕴含 的规律可以被另一个模型使用。最典型的例子就是预训练模型(见\ref{subsection-4.2.6})。使用单语数据学习到的表示模型,在双语的翻译任务中仍然可以发挥很好的作用。也就是,把单语语言模型学习到的知识迁移到双语翻译中对句子表示的任务中;
\item ``知识''在模型间是可迁移的。也就是说,一个模型中蕴含的规律可以被另一个模型使用。最典型的例子就是预训练模型(见\ref{subsection-4.2.6})。使用单语数据学习到的表示模型,在双语的翻译任务中仍然可以发挥很好的作用。也就是,把单语语言模型学习到的知识迁移到双语翻译中对句子表示的任务中;
\vspace{0.3em}
\item 模型所蕴含的``知识''比原始数据中的``知识''更容易被学习到。比如,机器翻译中大量使用的回译(伪数据)方法,就把模型的输出作为数据让系统进行学习。
\vspace{0.3em}
\end{itemize}
\parinterval 这里所说的第二个假设对应了机器学习中的一大类问题\ \dash \ {\small\bfnew{学习难度}}\index{学习难度}(Learning Difficulty)\index{Learning Difficulty}。所谓难度是指:在给定一个模型的情况下,需要花费多少代价对目标任务进行学习。如果目标任务很简单,同时模型与任务很匹配,那学习难度就会降低。如果目标任务很复杂,同时模型与其匹配程度很低,那学习难度就会很大。在自然语言处理任务中,这个问题的一种表现是:在很好的数据上学习的模型的翻译质量可能仍然很``差''。即使训练数据是完美的,但是模型仍然无法做到完美的学习。这可能是因为建模的不合理,导致模型无法描述目标任务中复杂的规律。也就是,纵然数据很好,但是模型学不到其中的``知识''。在机器翻译中这个问题体现的尤为明显。比如,在机器翻译系统$n$-best结果中挑选最好的译文(成为Oracle)作为训练样本让系统重新学习,系统仍然达不到Oracle的水平。
\parinterval 知识精炼本身也体现了一种``自学习''的思想。即利用模型(自己)的预测来教模型(自己)。这样既保证了知识可以向更轻量的模型迁移,同时也避免了模型从原始数据中学习难度大的问题。虽然``大''模型的预测中也会有错误,但是这种预测更符合建模的假设,因此``小''模型反倒更容易从不完美的信息中学习\footnote[15]{很多时候,``大''模型和``小''模型都是基于同一种架构,因此二者对问题的假设和模型结构都是相似的。}到更多的知识。
\parinterval 这里所说的第二个假设对应了机器学习中的一大类问题\ \dash \ {\small\bfnew{学习难度}}\index{学习难度}(Learning Difficulty)\index{Learning Difficulty}。所谓难度是指:在给定一个模型的情况下,需要花费多少代价对目标任务进行学习。如果目标任务很简单,同时模型与任务很匹配,那学习难度就会降低。如果目标任务很复杂,同时模型与其匹配程度很低,那学习难度就会很大。在自然语言处理任务中,这个问题的一种表现是:在很好的数据中学习的模型的翻译质量可能仍然很差。即使训练数据是完美的,但是模型仍然无法做到完美的学习。这可能是因为建模的不合理,导致模型无法描述目标任务中复杂的规律。也就是纵然数据很好,但是模型学不到其中的``知识''。在机器翻译中这个问题体现的尤为明显。比如,在机器翻译系统$n$-best结果中挑选最好的译文(成为Oracle)作为训练样本让系统重新学习,系统仍然达不到Oracle的水平。
\parinterval 这也类似于,刚开始学习围棋的人从职业九段身上可能什么也学不到,但是向一个业余初段的选手学习可能更容易入门。另外,也有研究表明:在机器翻译中,相比于`` 小''模型,``大''模型更容易进行优化,也更容易找到更好的模型收敛状态。因此在需要一个性能优越、存储较小的模型时,也会考虑将大模型压缩得到更轻量模型的手段\cite{DBLP:journals/corr/abs-2002-11794,DBLP:conf/iclr/FrankleC19}
\parinterval 知识精炼本身也体现了一种``自学习''的思想。即利用模型(自己)的预测来教模型(自己)。这样既保证了知识可以向更轻量的模型迁移,同时也避免了模型从原始数据中学习难度大的问题。虽然``大''模型的预测中也会有错误,但是这种预测是更符合建模的假设的,因此``小''模型反倒更容易从不完美的信息中学习\footnote[15]{很多时候,``大''模型和``小''模型都是基于同一种架构,因此二者对问题的假设和模型结构都是相似的。}到更多的知识。类似于,刚开始学习围棋的人从职业九段身上可能什么也学不到,但是向一个业余初段的选手学习可能更容易入门。另外,也有研究表明:在机器翻译中,相比于``小''模型,``大''模型更容易进行优化,也更容易找到更好的模型收敛状态。因此在需要一个性能优越,存储较小的模型时,也会考虑将大模型压缩得到更轻量模型的手段\cite{DBLP:journals/corr/abs-2002-11794,DBLP:conf/iclr/FrankleC19}
\parinterval 通常把``大''模型看作的传授知识的``教师'',被称作{\small\bfnew{教师模型}}\index{教师模型}(Teacher Model)\index{Teacher Model};把``小''模型看作是接收知识的``学生'',被称作{\small\bfnew{学生模型}}\index{学生模型}(Student Model)\index{Student Model}。比如,可以把Transformer-Big模型看作是教师模型,把Transformer-Base模型看作是学生模型。
\parinterval 通常把``大''模型看作的传授知识的``教师'',被称作{\small\bfnew{教师模型}}\index{教师模型}(Teacher Model)\index{Teacher Model};把``小''模型看作是接收知识的``学生'',被称作{\small\bfnew{学生模型}}\index{学生模型}(Student Model)\index{Student Model}。比如,可以把Transformer-Big看作是教师模型,把Transformer-Base看作是学生模型。
%%%%%%%%%%%%%%%%%%
\subsubsection{知识精炼的基本方法}
......@@ -1570,22 +1555,22 @@ p_l=\frac{l}{2L}\cdot \varphi
\vspace{0.3em}
\item {\small\bfnew{基于单词的知识精炼}}\index{基于单词的知识精炼}(Word-level Knowledge Distillation)\index{Word-level Knowledge Distillation}。该方法的目标是使得学生模型的预测(分布)尽可能逼近教师模型的预测(分布)。令$\textbf{x}=\{x_1,\ldots,x_m\}$$\textbf{y}=\{y_1,\ldots,y_n\}$分别表示输入和输出(数据中的答案)序列,$V$表示目标语言词表,$n$表示译文序列的长度,则基于单词的知识精炼的损失函数被定义为:
\begin{eqnarray}
Loss_{\textrm{word}} = - \sum_{j=1}^n \sum_{y_j \in V} \textrm{P}_{\textrm{t}} (y_{\textrm{j}}|\textbf{x})\textrm{logP}_{\textrm{s}}(y_j|\textbf{x})
L_{\textrm{word}} = - \sum_{j=1}^n \sum_{y_j \in V} \textrm{P}_{\textrm{t}} (y_{\textrm{j}}|\textbf{x})\textrm{logP}_{\textrm{s}}(y_j|\textbf{x})
\label{eqa7.5.3.2-1}
\end{eqnarray}
这里, $\textrm{P}_{\textrm{s}}(y_j|\textbf{x})$$\textrm{P}_{\textrm{t}} (y_i|\textbf{x})$分别表示学生模型和教师模型在$j$位置的输出的概率。公式\ref{eqa7.5.3.2-1}实际上在最小化教师模型和学生模型输出分布之间的交叉熵。
\vspace{0.3em}
\item {\small\bfnew{基于序列的知识精炼}}\index{基于序列的知识精炼}(Sequence-level Knowledge Distillation)\index{Sequence-level Knowledge Distillation}。除了单词一级的拟合,基于序列的知识精炼希望在序列整体上进行拟合。其损失函数被定义为:
\begin{eqnarray}
Loss_{\textrm{seq}} = - \sum_{\textrm{y}}\textrm{P}_{\textrm{t}} (\textbf{y}|\textbf{x})\textrm{logP}_{\textrm{s}}(\textbf{y}|\textbf{x})
L_{\textrm{seq}} = - \sum_{\textrm{y}}\textrm{P}_{\textrm{t}} (\textbf{y}|\textbf{x})\textrm{logP}_{\textrm{s}}(\textbf{y}|\textbf{x})
\label{eqa7.5.3.2-2}
\end{eqnarray}
公式\ref{eqa7.5.3.2-2}要求遍历所有可能的译文序列,并进行求和,当词表大小为$V$,序列长度为$L$时则可能的序列的数量有$V$$L$次幂,这么多的译文将消耗大量的计算资源。因此,会考虑用教师模型的真实输出序列$\hat{\textbf{y}}$来代替整个空间,即假设$\textrm{P}_{\textrm{t}}(\hat{\textbf{y}}|\textbf{x})=1$。于是,目标函数变为:
\begin{eqnarray}
Loss_{\textrm{seq}} = - \textrm{logP}_{\textrm{s}}(\hat{\textbf{y}} | \textbf{x})
L_{\textrm{seq}} = - \textrm{logP}_{\textrm{s}}(\hat{\textbf{y}} | \textbf{x})
\label{eqa7.5.3.2-3}
\end{eqnarray}
这样的损失函数带来最直接的好处是,知识精炼的流程会非常简单。因为只需要利用教师模型将训练数据(源语言)翻译一遍,之后把它的输出替换为训练数据的目标语言部分。之后,利用得到的新的双语数据训练学生模型即可,图\ref{fig:difference-between-word-level-and-sequence-level-in-knowledge-distillation}展示了简化后词级和序列级的不同,其中词一级知识精炼的解码端输入为真实双语数据的目标语言,并以教师模型输出的概率分布作为学习目标,而序列级则直接将教师模型推断后得到的结果作为解码端的输入,并将解码结果的One-hot向量作为学习目标。
这样的损失函数带来最直接的好处是,知识精炼的流程会非常简单。因为只需要利用教师模型将训练数据(源语言)翻译一遍,之后把它的输出替换为训练数据的目标语言部分。之后,利用得到的新的双语数据训练学生模型即可,图\ref{fig:difference-between-word-level-and-sequence-level-in-knowledge-distillation}展示了简化后词级和序列级的不同,其中词一级知识精炼的解码端输入为真实双语数据的目标语言,并以teacher模型输出的概率分布作为学习目标,而序列级则直接将teacher推断后得到的结果作为解码端的输入,并将解码结果的One-hot向量作为学习目标。
\vspace{0.3em}
\end{itemize}
%----------------------------------------------
......@@ -1598,7 +1583,7 @@ Loss_{\textrm{seq}} = - \textrm{logP}_{\textrm{s}}(\hat{\textbf{y}} | \textbf{x}
\end{figure}
%-------------------------------------------
\parinterval 本质上,基于单词的知识精炼和传统的语言模型等问题的建模方式是一致的。在传统方法中,训练数据中的答案会被看作是一个One-hot分布,之后让模型去尽可能拟合这种分布。而这里,答案不再是一个One-hot分布,而是由教师模型生成的真实分布,但是损失函数的形式是一模一样的。在具体实现时,一个容易出现的问题是在词级别的知识精炼中,教师模型的Softmax可能会生成非常尖锐的分布。这时需要考虑对分布进行平滑,提高模型的泛化能力\footnote[16]{比如,可以在Softmax函数中加入一个参数$\alpha$,如$\textrm{Softmax}(s_i)=\frac{exp(s_i/\alpha)}{\sum_j exp(s_i/\alpha)}$。这样可以通过$\alpha$控制分布的平滑程度。
\parinterval 本质上,基于单词的知识精炼和传统的语言模型等问题的建模方式是一致的。在传统方法中,训练数据中的答案会被看作是一个One-hot分布,之后让模型去尽可能拟合这种分布。而这里,答案不再是一个One-hot分布,而是由教师模型生成的真实分布,但是损失函数的形式是一模一样的。在具体实现时,一个容易出现的问题是在词级别的知识精炼中,teacher模型的Softmax可能会生成非常尖锐的分布。这时需要考虑对分布进行平滑,提高模型的泛化能力\footnote[16]{比如,可以在Softmax函数中加入一个参数$\alpha$,如$\textrm{Softmax}(s_i)=\frac{exp(s_i/\alpha)}{\sum_j exp(s_i/\alpha)}$。这样可以通过$\alpha$控制分布的平滑程度。
}
\parinterval 除了在模型最后输出的分布上进行知识精炼,同样可以使用教师模型对学生模型的{\small\bfnew{中间层输出}}\index{中间层输出}(Hint-based Knowledge Transfer)\index{Hint-based Knowledge Transfer}{\small\bfnew{注意力分布}}\index{注意力分布}(Attention To Attention Transfer)\index{Attention To Attention Transfer}进行约束。而对翻译常用的Transformer架构,也有研究者使用更精细的精炼方式对模型各个位置的知识重新设计了知识迁移的方法\cite{DBLP:journals/corr/abs-1909-10351}
......@@ -1612,7 +1597,7 @@ Loss_{\textrm{seq}} = - \textrm{logP}_{\textrm{s}}(\hat{\textbf{y}} | \textbf{x}
\begin{itemize}
\vspace{0.3em}
\item 固定教师模型,通过减少模型容量的方式设计学生模型。比如,可以使用容量较大的模型作为教师模型(如:Transformer-Big或Transformer-Deep),然后通过将神经网络变``窄''、变``浅''的方式得到学生模型。例如,可以用Transformer-Big做教师模型,然后把Transformer-Big的解码器变为一层网络,作为学生模型。
\item 固定教师模型,通过减少模型容量的方式设计学生模型。比如,可以使用容量较大的模型作为教师模型(如:Transformer-Big或Transformer-Deep),然后通过将神经网络变``窄''、变``浅''的方式得到学生模型。我们可以用Transformer-Big做教师模型,然后把Transformer-Big的解码器变为一层网络,作为学生模型。
\vspace{0.3em}
\item 固定学生模型,通过模型集成的方式设计教师模型。可以组合多个模型生成更高质量的译文(见\ref{subsection-7.4.3}节)。比如,融合多个Transformer-Big模型(不同参数初始化方式),之后学习一个Transformer-Base模型。
\vspace{0.3em}
......@@ -1630,23 +1615,21 @@ Loss_{\textrm{seq}} = - \textrm{logP}_{\textrm{s}}(\hat{\textbf{y}} | \textbf{x}
\end{figure}
%-------------------------------------------
\parinterval 如果倾向于使用更少的存储,更快的推理速度,则可以使用更小的学生模型。值得注意的是,对于Transformer模型来说,减少解码端的层数会明显加速推断过程。特别是对于基于深层编码器的Transformer-Deep,适当减少解码端层数往往不会带来翻译品质的下降。可以根据不同任务的需求,选择合适的学生模型,来平衡存储、推断速度和模型品质之间的关系。
\parinterval 如果倾向于使用更少的存储,更快的推理速度,则可以使用更小的学生模型。值得注意的是,对于Transformer模型来说,减少解码端的层数会给推理速度带来巨大的提升。特别是对于基于深层编码器的Transformer-Deep,适当减少解码端层数往往不会带来翻译品质的下降。可以根据不同任务的需求,选择适当大小的学生模型,来平衡存储、推断速度和模型品质之间的关系。
\subsection{双向训练}
\label{subsection-7.5.4}
\parinterval 到目前为止,神经机器翻译系统都是每次一次训练一个方向的模型,比如,给定中英的双语数据,一次只训练一个中到英或者英到中的翻译系统。既然两个方向的系统都使用同样的双语数据进行训练,那么是否可以一次训练同时得到两个方向的翻译系统呢?
\parinterval 回顾神经机器翻译系统的建模过程,给定一个互译的句对$(\mathbf s,\mathbf t)$,一个从源语言句子$\mathbf s$到目标语言句子$\mathbf t$的翻译被表示为求条件概率$\textrm{P}(\mathbf t|\mathbf s)$的问题。类似地,一个从目标语言句子$\mathbf t$到源语言句子$\mathbf s$的翻译可以表示为$\textrm{P}(\mathbf s|\mathbf t)$。通常来说,神经机器翻译的训练一次只得到一个方向的模型,也就是$\textrm{P}(\mathbf t|\mathbf s)$或者$\textrm{P}(\mathbf s|\mathbf t)$。这意味着$\textrm{P}(\mathbf t|\mathbf s)$$\textrm{P}(\mathbf s|\mathbf t)$之间是互相独立的。$\textrm{P}(\mathbf t|\mathbf s)$$\textrm{P}(\mathbf s|\mathbf t)$是否真的没有关系呢?比如,$\mathbf s$$\mathbf t$是相同大小的向量,且$\mathbf s$$\mathbf t$的变换是一个线性变换,也就是与一个方阵$\mathbf{W}$做矩阵乘法:
\parinterval 回顾神经机器翻译系统的建模过程,给定一个互译的句对$(\mathbf s,\mathbf t)$,一个从源语言句子$\mathbf s$到目标语言句子$\mathbf t$的翻译被表示为求条件概率$\textrm{P}(\mathbf t|\mathbf s)$的问题。类似地,一个从目标语言句子$\mathbf t$到源语言句子$\mathbf s$的翻译可以表示为$\textrm{P}(\mathbf s|\mathbf t)$。通常来说,神经机器翻译的训练一次只得到一个方向的模型,也就是$\textrm{P}(\mathbf t|\mathbf s)$或者$\textrm{P}(\mathbf s|\mathbf t)$。这意味着$\textrm{P}(\mathbf t|\mathbf s)$$\textrm{P}(\mathbf s|\mathbf t)$之间是互相独立的。$\textrm{P}(\mathbf t|\mathbf s)$$\textrm{P}(\mathbf s|\mathbf t)$是否真的没有关系呢?比如,$\mathbf s$$\mathbf t$是相同大小的向量,且$\mathbf s$$\mathbf t$的变换是一个线性变换,也就是与一个方阵$\mathbf{W}$做矩阵乘法:
\begin{eqnarray}
\mathbf t = \mathbf s \cdot \mathbf{W}
\label{eqC7.5.4.1.1}
\end{eqnarray}
\parinterval 这里可以把$\mathbf s$$\mathbf t$都看作分布式的向量表示;$\mathbf{W}$应当是一个满秩矩阵,否则对于任意一个$\mathbf s$经过$\mathbf{W}$变换得到的$\mathbf t$只落在所有可能的$\mathbf t$的一个子空间内,即在给定$\mathbf{W}$的情况下有些$\mathbf t$不能被任何一个$\mathbf s$表达,而这不符合常识,因为不管是什么句子,我们总能找到它的一种译文。若$\mathbf{W}$是满秩矩阵说明$\mathbf{W}$可逆,也就是给定$\mathbf s$$\mathbf t$的变换$\mathbf{W}$下,$\mathbf t$$\mathbf s$的变换必然是$\mathbf{W}$的逆而不是其他矩阵。
\parinterval 这个例子说明$\textrm{P}(\mathbf t|\mathbf s)$$\textrm{P}(\mathbf s|\mathbf t)$直觉上应当存在联系。当然,$\mathbf s$$\mathbf t$之间是否存在简单的线性变换关系并没有结论,但是上面的例子给出了一种对源语言句子和目标语言句子进行相互转化的思路。实际上,研究人员已经通过一些数学技巧用目标函数来把$\textrm{P}(\mathbf t|\mathbf s)$$\textrm{P}(\mathbf s|\mathbf t)$联系起来,这样训练神经机器翻译系统一次就可以同时得到两个方向的翻译模型,使得训练变得更加高效\cite{Hassan2018AchievingHP}
\parinterval 这里可以把$\mathbf s$$\mathbf t$都看作分布式的向量表示;$\mathbf{W}$应当是一个满秩矩阵,否则对于任意一个$\mathbf s$经过$\mathbf{W}$变换得到的$\mathbf t$只落在所有可能的$\mathbf t$的一个子空间内,即在给定$\mathbf{W}$的情况下有些$\mathbf t$不能被任何一个$\mathbf s$表达,而这不符合常识,因为不管是什么句子,我们总能找到它的一种译文。若$\mathbf{W}$是满秩矩阵说明$\mathbf{W}$可逆,也就是给定$\mathbf s$$\mathbf t$的变换$\mathbf{W}$下,$\mathbf t$$\mathbf s$的变换必然是$\mathbf{W}$的逆而不是其他矩阵。这个例子说明$\textrm{P}(\mathbf t|\mathbf s)$$\textrm{P}(\mathbf s|\mathbf t)$直觉上应当存在联系。当然,$\mathbf s$$\mathbf t$之间是否存在简单的线性变换关系并没有结论,但是上面的例子给出了一种对源语言句子和目标语言句子进行相互转化的思路。实际上,研究人员已经通过一些数学技巧用目标函数来把$\textrm{P}(\mathbf t|\mathbf s)$$\textrm{P}(\mathbf s|\mathbf t)$联系起来,这样训练神经机器翻译系统一次就可以同时得到两个方向的翻译模型,使得训练变得更加高效\cite{Hassan2018AchievingHP}
%%%%%%%%%%%%%%%%%%
\subsubsection{有监督对偶学习}
......@@ -1654,14 +1637,13 @@ Loss_{\textrm{seq}} = - \textrm{logP}_{\textrm{s}}(\hat{\textbf{y}} | \textbf{x}
\parinterval 除了用条件概率$\textrm{P}(\mathbf t|\mathbf s)$建模翻译问题,还可以使用联合分布$\textrm{P}(\mathbf s,\mathbf t)$进行建模\cite{DBLP:journals/corr/XiaQCBYL17}。根据条件概率的定义,有:
\begin{eqnarray}
\textrm{P}(\mathbf s,\mathbf t) &=& \textrm{P}(\mathbf s)\textrm{P}(\mathbf t|\mathbf s) \nonumber \\
&=& \textrm{P}(\mathbf{t})\textrm{P}(\mathbf s|\mathbf t)
&=& \textrm{P}(t)\textrm{P}(\mathbf s|\mathbf t)
\label{eqC7.5.4.1.1}
\end{eqnarray}
\parinterval 公式\ref{eqC7.5.4.1.1}很自然地把两个方向的翻译模型$\textrm{P}(\mathbf t|\mathbf s)$$\textrm{P}(\mathbf s|\mathbf t)$以及两个语言模型$\textrm{P}(\mathbf s)$$\textrm{P}(\mathbf t)$联系起来:$\textrm{P}(\mathbf s)\textrm{P}(\mathbf t|\mathbf s)$应该与$\textrm{P}(\mathbf t)\textrm{P}(\mathbf s|\mathbf t)$接近,因为它们都表达了同一个联合分布$\textrm{P}(\mathbf s,\mathbf t)$。因此,在构建训练两个方向的翻译模型的目标函数时,除了它们单独训练时各自使用的极大似然估计目标函数,可以额外增加一个目标项来鼓励两个方向的翻译模型去满足公式\ref{eqC7.5.4.1.1}
\begin{eqnarray}
Loss_{\textrm{bi}} = (\textrm{log P}(\mathbf s) + \textrm{log P}(\mathbf t|\mathbf s) - \textrm{log P}(\mathbf t) - \textrm{log P}(\mathbf s|\mathbf t))^{2}
\mathcal{L} = (\textrm{log P}(\mathbf s) + \textrm{log P}(\mathbf t|\mathbf s) - \textrm{log P}(\mathbf t) - \textrm{log P}(\mathbf s|\mathbf t))^{2}
\label{eqC7.5.4.1.2}
\end{eqnarray}
......@@ -1677,7 +1659,7 @@ Loss_{\textrm{bi}} = (\textrm{log P}(\mathbf s) + \textrm{log P}(\mathbf t|\math
\label{eqC7.5.4.2.1}
\end{eqnarray}
\noindent 公式\ref{eqC7.5.4.2.1}假设$\textrm{P}(\mathbf s|\mathbf t)=\textrm{P}(\mathbf s|\mathbf s,\mathbf t)$。这个假设显然是成立的,因为当知道一个句子的译文时,并不需要知道它的源文就可以把它翻译回去。如果直接优化(最大化)公式\ref{eqC7.5.4.2.1}右侧,相当于对这个等式$\textrm{P}(\mathbf s|\mathbf t)$$\textrm{P}(\mathbf t|\mathbf s)$施加了{\small\bfnew{循环一致性}}\index{循环一致性}(Circle Consistency)\index{Circle Consistency}的约束\cite{DBLP:conf/iccv/ZhuPIE17}。也就是,对于一个句子$\mathbf s$,通过$\textrm{P}(\mathbf t|\mathbf s)$把它翻译成$\mathbf t$后,根据$\textrm{P}(\mathbf s|\mathbf t)$应该能重新翻译出$\mathbf s$,如图\ref{fig:7-35}所示。公式\ref{eqC7.5.4.2.1}给出了同时优化$\textrm{P}(\mathbf s|\mathbf t)$$\textrm{P}(\mathbf t|\mathbf s)$的一个目标函数形式。这个目标函数一个额外的好处是它本质上是在学习一个由$\textrm{P}(\mathbf s|\mathbf t)$$\textrm{P}(\mathbf t|\mathbf s)$组成的语言模型$\textrm{P}(\mathbf s)$,而$\textrm{P}(\mathbf s)$的学习依赖于单语数据,这意味着这个目标函数可以很自然地直接使用大量单语数据来同时训练两个翻译模型。相同的结论可以推广到$\textrm{P}(\mathbf t)$\cite{DBLP:conf/nips/HeXQWYLM16}
\noindent 公式\ref{eqC7.5.4.2.1}假设$\textrm{P}(\mathbf s|\mathbf t)=\textrm{P}(\mathbf s|\mathbf s,\mathbf t)$。这个假设显然是成立的,因为当知道一个句子的译文时,并不需要知道它的源文就可以把它翻译回去。如果直接优化(最大化)公式\ref{eqC7.5.4.2.1}右侧,相当于对这个等式$\textrm{P}(\mathbf s|\mathbf t)$$\textrm{P}(\mathbf t|\mathbf s)$施加了{\small\bfnew{循环一致性}}\index{循环一致性}(Circle Consistency)\index{Circle Consistency}的约束\cite{DBLP:conf/iccv/ZhuPIE17},也就是对于一个句子$\mathbf s$,通过$\textrm{P}(\mathbf t|\mathbf s)$把它翻译成$\mathbf t$后,根据$\textrm{P}(\mathbf s|\mathbf t)$应该能重新翻译出$\mathbf s$,如图\ref{fig:7-35}所示。公式\ref{eqC7.5.4.2.1}给出了同时优化$\textrm{P}(\mathbf s|\mathbf t)$$\textrm{P}(\mathbf t|\mathbf s)$的一个目标函数形式。这个目标函数的一个额外的好处是它本质上是在学习一个由$\textrm{P}(\mathbf s|\mathbf t)$$\textrm{P}(\mathbf t|\mathbf s)$组成的语言模型$\textrm{P}(\mathbf s)$,而$\textrm{P}(\mathbf s)$的学习依赖于单语数据,这意味着这个目标函数可以很自然地直接使用大量单语数据来同时训练两个翻译模型。相同的结论可以推广到$\textrm{P}(\mathbf t)$\cite{DBLP:conf/nips/HeXQWYLM16}
%----------------------------------------------
% 图7.
......@@ -1693,7 +1675,7 @@ Loss_{\textrm{bi}} = (\textrm{log P}(\mathbf s) + \textrm{log P}(\mathbf t|\math
\vspace{0.5em}
\begin{itemize}
\item 计算公式\ref{eqC7.5.4.2.1}要枚举所有可能的隐变量$\mathbf t$的取值,也就是,枚举所有可能产生的目标语句子,而这是不可能的,因此一般会通过平均多个随机产生的$\mathbf t$对应的损失来近似真正的目标函数值;
\item 计算公式\ref{eqC7.5.4.2.1}要枚举所有可能的隐变量$\mathbf t$的取值,也就是所有可能产生的目标语句子,而这是不可能的,因此一般会通过平均多个随机产生的$\mathbf t$对应的损失来近似真正的目标函数值;
\vspace{0.5em}
\item 从公式\ref{eqC7.5.4.2.1}可以看到,在$\textrm{P}(\mathbf s)$上计算完目标函数值后,得到的梯度首先传递给$\textrm{P}(\mathbf s|\mathbf t)$,然后通过$\textrm{P}(\mathbf s|\mathbf t)$传递给$\textrm{P}(\mathbf t|\mathbf s)$。由于$\textrm{P}(\mathbf s|\mathbf t)$的输入$\mathbf t$$\textrm{P}(\mathbf t|\mathbf s)$采样得到,而采样操作不可导,导致梯度的传播在$\textrm{P}(\mathbf t|\mathbf s)$的输出处断开了,因此$\textrm{P}(\mathbf t|\mathbf s)$接收不到任何梯度来进行更新。常见的解决方案是使用策略梯度\cite{DBLP:conf/nips/SuttonMSM99}。它把$\textrm{P}(\mathbf t|\mathbf s)$采样得到的$\mathbf t$当成$\textrm{P}(\mathbf t|\mathbf s)$的目标来学习,并使用$\textrm{log P}(\mathbf s|\mathbf t)$$\textrm{P}(\mathbf t|\mathbf s)$的损失进行加权。但是由于仅使用少量样本来近似真正的目标函数,得到的策略梯度方差非常大,系统无法稳定学习,特别是训练的初期,因此通常会需要先使用双语数据预训练两个方向的翻译模型,然后把公式\ref{eqC7.5.4.2.1}作为正常训练的一个正则化项使用。
\end{itemize}
......@@ -1704,35 +1686,34 @@ Loss_{\textrm{bi}} = (\textrm{log P}(\mathbf s) + \textrm{log P}(\mathbf t|\math
\parinterval 重新回顾公式\ref{eqC7.5.4.2.1}对应的目标函数,无监督对偶学习跟回译(假设现在只在一个句对$(\mathbf s,\mathbf t)$上做回译)之间有着很深的内在联系:给定一个句子$\mathbf s$,无监督对偶学习和回译都首先用$\textrm{P}(\mathbf t|\mathbf s)$$\mathbf s$翻译成$\mathbf t$,然后无监督对偶学习最大化$\textrm{P}(\mathbf s|\mathbf t)\textrm{P}(\mathbf t|\mathbf s)$,而回译则是最大化$\textrm{P}(\mathbf s|\mathbf t)$。可以看到,当无监督对偶学习假设$\textrm{P}(\mathbf t|\mathbf s)$是一个完美的翻译模型的时候,它与回译是等价的。此外,在共享两个方向的模型参数$\theta$的情况下,可以看到无监督对偶学习的梯度为$\frac{\partial \textrm{P}(\mathbf s)}{\partial \theta} =\textrm{P}(\mathbf t|\mathbf s) \frac{\partial \textrm{P}(\mathbf s|\mathbf t)}{\partial \theta}+\textrm{P}(\mathbf s|\mathbf t) \frac{\partial \textrm{P}(\mathbf t|\mathbf s)}{\partial \theta} $,而回译的梯度为$\frac{\partial \textrm{P}(\mathbf s|\mathbf t)}{\partial \theta}$。从这个角度出发,无监督对偶学习与回译都在优化语言模型$\textrm{P}(\mathbf s)$这个目标函数,只不过回译使用对$\theta$有偏的梯度估计。
\parinterval 这个事实说明对回译进行适当的增广后应该能取得与无监督对偶学习相似的结果。{\small\bfnew{ 翻译中回译}}\index{翻译中回译}(On-the-fly Back-translation)\index{On-the-fly Back-translation}就是这样一个例子。一般回译的过程是先把数据集里所有$\mathbf s$都翻译出来,然后只训练$\textrm{P}(\mathbf s|\mathbf t)$。区别于回译,从数据集中采集到一个$\mathbf s$之后,翻译中回译立刻把$\mathbf s$翻译成$\mathbf t$,然后训练$\textrm{P}(\mathbf s|\mathbf t)$,并且下一步迭代中采集一个$\mathbf t$然后训练$\textrm{P}(\mathbf t|\mathbf s)$,这样交替更新$\textrm{P}(\mathbf s|\mathbf t)$$\textrm{P}(\mathbf t|\mathbf s)$
\parinterval 尽管翻译中回译无法像无监督对偶学习那样在一个样本里通过梯度把$\textrm{P}(\mathbf s|\mathbf t)$的信息传到$\textrm{P}(\mathbf t|\mathbf s)$,但是它交替更新$\textrm{P}(\mathbf s|\mathbf t)$$\textrm{P}(\mathbf t|\mathbf s)$的策略允许$\textrm{P}(\mathbf s|\mathbf t)$在两个样本间通过其产生的输出$\mathbf s$来把信息传递到$\textrm{P}(\mathbf t|\mathbf s)$,因此也能获得相近的效果,并且在实现和计算上都非常高效。翻译中回译已经在无监督神经机器翻译系统训练中被广泛使用\cite{lample2019cross}
\parinterval 这个事实说明对回译进行适当的增广后应该能取得与无监督对偶学习相似的结果。{\small\bfnew{ 翻译中回译}}\index{翻译中回译}(On-the-fly Back-translation)\index{On-the-fly Back-translation}就是这样一个例子。一般回译的过程是先把数据集里所有$\mathbf s$都翻译出来,然后只训练$\textrm{P}(\mathbf s|\mathbf t)$。区别于回译,从数据集中采集到一个$\mathbf s$之后,翻译中回译立刻把$\mathbf s$翻译成$\mathbf t$,然后训练$\textrm{P}(\mathbf s|\mathbf t)$,并且下一步迭代中采集一个$\mathbf t$然后训练$\textrm{P}(\mathbf t|\mathbf s)$,这样交替更新$\textrm{P}(\mathbf s|\mathbf t)$$\textrm{P}(\mathbf t|\mathbf s)$。尽管翻译中回译无法像无监督对偶学习那样在一个样本里通过梯度把$\textrm{P}(\mathbf s|\mathbf t)$的信息传到$\textrm{P}(\mathbf t|\mathbf s)$,但是它交替更新$\textrm{P}(\mathbf s|\mathbf t)$$\textrm{P}(\mathbf t|\mathbf s)$的策略允许$\textrm{P}(\mathbf s|\mathbf t)$在两个样本间通过其产生的输出$\mathbf s$来把信息传递到$\textrm{P}(\mathbf t|\mathbf s)$,因此也能获得相近的效果,并且在实现和计算上都非常高效。翻译中回译已经在无监督神经机器翻译系统训练中被广泛使用\cite{lample2019cross}
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
\sectionnewpage
\section{小结及深入阅读}
\parinterval 神经机器翻译的模型和技术方法已经十分丰富,无论是对基础问题的研究,还是研发实际可用的系统,人们都会面临很多选择。本章从构建一个足以参加机器翻译比赛的系统出发,对神经机器翻译的数据处理、建模与训练、推断的基本问题进行了介绍。其中的许多方法已经在实践中得到验证,具有较好的参考意义。此外,本章也对一些前沿方法进行了讨论,旨在为读者提供更全面的思路
\parinterval 神经机器翻译的模型和技术方法已经十分丰富,无论是对基础问题的研究,还是研发实际可用的系统,人们都会面临很多选择。本章,从构建一个足以参加机器翻译比赛的系统出发,对神经机器翻译的数据处理、建模与训练、推断的基本问题进行了介绍。其中的许多方法已经在实践中得到验证,具有较好的参考意义。此外,本章也对一些前沿方法进行了讨论,旨在挖掘更具潜力的方向
\parinterval 只不过,神经机器翻译涉及的问题非常广泛。除了以上内容,还有很多方向值得关注:
\parinterval 除了以上内容,还有一些方向值得关注:
\vspace{0.5em}
\begin{itemize}
\item 无指导机器翻译。无指导机器翻译由于其不需要双语语料即可训练翻译模型的特性,在稀缺资源机器翻译的场景中有非常大的潜力而得到广泛的关注。目前无指导机器翻译主要有两种范式:第一种先得到词典的翻译,然后得到短语表的翻译和相应的统计机器翻译系统,最后使用统计机器翻译系统生成伪双语平行语料训练神经机器翻译系统\cite{DBLP:conf/acl/ArtetxeLA19};第二种是先预训练语言模型来初始化神经机器翻译系统的编码器和解码器,然后使用翻译中回译以及降噪自编码器来训练神经机器翻译系统\cite{lample2019cross}。尽管目前无指导机器翻译在富资源的语种上取得了很大进展,但是离实际应用还有很远距离。比如,目前无指导系统都依赖于大量单语数据,而实际上稀缺资源的语种不但双语语料少,单语语料也少;此外,这些系统还无法在远距离如中英这些字母表重合少,需要大范围调序的语种对上取得可接受的结果;使用大量单语训练无指导系统还面临数据来自于不同领域的问题\cite{DBLP:journals/corr/abs-2004-05516}。设计更鲁棒、单语数据使用更高效的无指导机器翻译方法乃至新范式会是未来的趋势。
\vspace{0.5em}
\item 图片翻译。由于人类语言潜在的歧义性,传统的神经机器翻译在单句翻译中可能会出现歧义。为此,一些研究工作在翻译过程中尝试引入更多的上下文信息,比如多模态翻译、基于树的翻译或者篇章级翻译。图片翻译的目标就是在给定一个图片和其源语描述的情况下,生成目标语言的描述。一般做法就是通过一个额外的编码器来提取图像特征\cite{elliott2015multilingual,DBLP:conf/acl/HitschlerSR16},然后通过权重门控机制、注意力网络等融合到系统中\cite{DBLP:conf/wmt/HuangLSOD16}
\item 无指导机器翻译。无指导机器翻译由于其不需要双语语料即可训练翻译模型的特性,在稀缺资源机器翻译的场景中有非常大的潜力而得到广泛的关注。目前无指导机器翻译主要有两种范式:第一种先得到词典的翻译,然后得到短语表的翻译和相应的统计机器翻译系统,最后使用统计机器翻译系统生成伪双语平行语料训练神经机器翻译系统\cite{DBLP:conf/acl/ArtetxeLA19};第二种是先预训练语言模型来初始化神经机器翻译系统的编码器和解码器,然后使用翻译中回译以及降噪自编码器来训练神经机器翻译系统\cite{lample2019cross}。尽管目前无指导机器翻译在富资源的语种上取得了很大进展,但是离实际应用还有很远距离。比如,目前无指导系统都依赖于大量单语数据,而实际上稀缺资源的语种不但双语语料少,单语语料也少;此外,这些系统还无法在远距离如中英这些字母表重合少,需要大范围调序的语种对上取得可接受的结果;使用大量单语训练无指导系统还面临数据来自于不同领域的问题\cite{DBLP:journals/corr/abs-2004-05516}。设计更鲁棒,使用单语数据更高效的无指导机器翻译方法乃至新范式会是未来的趋势。
\vspace{0.5em}
\item 语音翻译。在日常生活中,语音翻译也是有很大的需求。针对语音到文本翻译的特点,最简单的做法是使用自动语音识别(ASR)将语音转换成文本,然后送入文本翻译模型进行翻译\cite{DBLP:conf/icassp/Ney99,DBLP:conf/interspeech/MatusovKN05}。然而为了避免流水线中的错误传播和高延迟问题,端到端的语音翻译是近些年的热点\cite{DBLP:conf/naacl/DuongACBC16,DBLP:journals/corr/BerardPSB16}。针对语音翻译数据稀缺的问题,一些研究工作采用各种方法来进行缓解,包括预训练\cite{DBLP:conf/naacl/BansalKLLG19}、 多任务学习\cite{DBLP:conf/naacl/DuongACBC16,DBLP:conf/icassp/BerardBKP18}、课程学习\cite{DBLP:journals/corr/abs-1802-06003}、注意力传递\cite{DBLP:journals/tacl/SperberNNW19}和知识精炼\cite{DBLP:conf/interspeech/LiuXZHWWZ19,DBLP:conf/icassp/JiaJMWCCALW19}
\item 更多上下文信息的建模。由于人类语言潜在的歧义性,传统的神经机器翻译在单句翻译中可能会出现歧义。为此,一些研究工作在翻译过程中尝试引入更多的上下文信息,比如多模态翻译、基于树的翻译或者篇章级翻译。多模态翻译的目标就是在给定一个图片和其源语描述的情况下,生成目标语言的描述。一般做法就是通过一个额外的编码器来提取图像特征\cite{elliott2015multilingual,DBLP:conf/acl/HitschlerSR16},然后通过权重门控机制、注意力网络等融合到系统中\cite{DBLP:conf/wmt/HuangLSOD16}
\parinterval 基于树的翻译是指在翻译模型中引入句法结构树或依存树,从而引入更多的句法信息。一种常用的做法是将句法树进行序列化,从而保留序列到序列的模型结构\cite{DBLP:conf/emnlp/CurreyH18,DBLP:conf/acl/SaundersSGB18,DBLP:conf/wmt/NadejdeRSDJKB17}。在此基础上,一些研究工作引入了更多的解析结果\cite{DBLP:conf/acl/SumitaUZTM18,DBLP:conf/coling/ZaremoodiH18}。同时,也有一些研究工作直接使用Tree-LSTMs等网络结构\cite{DBLP:conf/acl/TaiSM15,DBLP:conf/iclr/ShenTSC19}来直接表示树结构,并将其应用到神经机器翻译模型中\cite{DBLP:conf/acl/EriguchiHT16,Yang2017TowardsBH,DBLP:conf/acl/ChenHCC17}
\parinterval 篇章级翻译是为了引入篇章级上下文信息,来处理篇章翻译中译文不连贯,主谓不一致等歧义现象。为此,一些研究人员针对该问题进行了改进,主要可以分为两类方法:一种是将当前句子与上下文进行句子级的拼接,不改变模型的结构\cite{DBLP:conf/discomt/TiedemannS17},另外一种是采用额外的编码器来捕获篇章信息\cite{DBLP:journals/corr/JeanLFC17,DBLP:journals/corr/abs-1805-10163,DBLP:conf/emnlp/ZhangLSZXZL18}。编码器的结构除了传统的RNN、自注意力网络,还有利用层级注意力来编码之前的多句上文\cite{Werlen2018DocumentLevelNM,tan-etal-2019-hierarchical},使用可选择的稀疏注意力机制对整个文档进行篇章建模\cite{DBLP:conf/naacl/MarufMH19},使用记忆网络、缓存机制等对篇章中的关键词进行提取\cite{DBLP:conf/coling/KuangXLZ18,DBLP:journals/tacl/TuLSZ18}或者采用两阶段解码的方式\cite{DBLP:conf/aaai/XiongH0W19,DBLP:conf/acl/VoitaST19}。除了从建模角度引入上下文信息,也有一些工作使用篇章级修正模型\cite{DBLP:conf/emnlp/VoitaST19}或者语言模型\cite{DBLP:journals/corr/abs-1910-00553}对句子级翻译模型的译文进行修正,或者通过自学习在解码过程中保持翻译连贯性\cite{DBLP:journals/corr/abs-2003-05259}
\vspace{0.5em}
\item 基于句法树的翻译。一种常用的做法是将句法树进行序列化,从而保留序列到序列的模型结构\cite{DBLP:conf/emnlp/CurreyH18,DBLP:conf/acl/SaundersSGB18,DBLP:conf/wmt/NadejdeRSDJKB17}。在此基础上,一些研究工作引入了更多的解析结果\cite{DBLP:conf/acl/SumitaUZTM18,DBLP:conf/coling/ZaremoodiH18}。同时,也有一些研究工作直接使用Tree-LSTMs等网络结构\cite{DBLP:conf/acl/TaiSM15,DBLP:conf/iclr/ShenTSC19}来直接表示树结构,并将其应用到神经机器翻译模型中\cite{DBLP:conf/acl/EriguchiHT16,Yang2017TowardsBH,DBLP:conf/acl/ChenHCC17}
\item 语音翻译。在日常生活中,语音翻译也是有很大的需求。针对语音到文本翻译的特点,最简单的做法是使用自动语音识别(ASR)将语音转换成文本,然后送入文本翻译模型进行翻译\cite{DBLP:conf/icassp/Ney99,DBLP:conf/interspeech/MatusovKN05}。然而为了避免流水线中的错误传播和高延迟问题,现在通常采用端到端的建模做法\cite{DBLP:conf/naacl/DuongACBC16,DBLP:journals/corr/BerardPSB16}。同时,针对语音翻译数据稀缺的问题,一些研究工作采用各种方法来进行缓解,包括预训练\cite{DBLP:conf/naacl/BansalKLLG19}、多任务学习\cite{DBLP:conf/naacl/DuongACBC16,DBLP:conf/icassp/BerardBKP18}、课程学习\cite{DBLP:journals/corr/abs-1802-06003}、注意力传递\cite{DBLP:journals/tacl/SperberNNW19}和知识精炼\cite{DBLP:conf/interspeech/LiuXZHWWZ19,DBLP:conf/icassp/JiaJMWCCALW19}
\vspace{0.5em}
\item 篇章级翻译。篇章级翻译是为了引入篇章级上下文信息,来处理篇章翻译中译文不连贯,主谓不一致等歧义现象({\red 引用SMT时代关于篇章翻译论文,包括我们MT Summit的论文})。为此,一些研究人员针对该问题进行了改进,主要可以分为两种方法:第一种是将当前句子与上下文进行句子级的拼接,不改变模型的结构\cite{DBLP:conf/discomt/TiedemannS17},另外一种是采用额外的编码器来捕获篇章信息\cite{DBLP:journals/corr/JeanLFC17,DBLP:journals/corr/abs-1805-10163,DBLP:conf/emnlp/ZhangLSZXZL18}。编码器的结构除了传统的RNN、自注意力网络,还有利用层级注意力来编码之前的多句上文\cite{Werlen2018DocumentLevelNM,tan-etal-2019-hierarchical},使用可选择的稀疏注意力机制对整个文档进行篇章建模\cite{DBLP:conf/naacl/MarufMH19},使用记忆网络、缓存机制等对篇章中的关键词进行提取\cite{DBLP:conf/coling/KuangXLZ18,DBLP:journals/tacl/TuLSZ18}或者采用两阶段解码的方式\cite{DBLP:conf/aaai/XiongH0W19,DBLP:conf/acl/VoitaST19}。除了从建模角度引入上下文信息,也有一些工作使用篇章级修正模型\cite{DBLP:conf/emnlp/VoitaST19}或者语言模型\cite{DBLP:journals/corr/abs-1910-00553}对句子级翻译模型的译文进行修正,或者通过自学习在解码过程中保持翻译连贯性\cite{DBLP:journals/corr/abs-2003-05259}
\item 多语言翻译。神经机器翻译模型经过训练,通常可以将一种固定的源语言翻译成另一种固定的目标语言,但考虑到世界上有成千上万种语言,为每种语言对训练一个单独的模型非常耗资源。相比于单一语言对的神经机器翻译,多语言神经机器翻译具有开发跨语言对相似性的潜力,而且可以节约大量的训练成本\cite{DBLP:journals/tacl/JohnsonSLKWCTVW17}
\parinterval 多语言神经机器翻译旨在训练涵盖多种语言翻译的单一模型。多语言神经机器翻译系统可以根据它们在不同翻译语言对之间共享的组件进行分类。一种常见的做法是通过语言标签指定源语言合目标语言的同时,共享整个神经网络结构(编码器和解码器)\cite{DBLP:journals/corr/HaNW16,DBLP:journals/corr/abs-1711-07893}。除此之外,还可以使用共享的编码器,但针对每种目标语言使用单独的解码器进行一对多的多语言翻译\cite{DBLP:conf/naacl/FiratCB16}。还有一些方法为每种源语言和目标语言都使用单独的编码器和解码器,但会共享其中的一些组件\cite{luong2015multi-task,DBLP:conf/naacl/FiratCB16},比如说,共享其中的注意力机制结构\cite{luong2015multi-task,DBLP:conf/naacl/FiratCB16}多语言神经机器翻译不仅可以减少训练单一语言对神经机器翻译的训练代价,还可以有效的解决低资源神经机器翻译\cite{DBLP:journals/tacl/JohnsonSLKWCTVW17}以及多源神经机器翻译问题\cite{Och2001Statistical}
\vspace{0.5em}
\item 多语言翻译。相比于面向单一语言对的系统,多语言神经机器翻译可以同时得到多种语言之间的机器翻译系统,节约大量的训练成本\cite{DBLP:journals/tacl/JohnsonSLKWCTVW17}。多语言神经机器翻译旨在训练涵盖多种语言翻译的统一模型。一种常见的做法在所有语言上共享整个神经网络结构(编码器和解码器),同时用语言标签指示不同的语言\cite{DBLP:journals/corr/HaNW16,DBLP:journals/corr/abs-1711-07893}。 除此之外,还可以使用共享的编码器,但针对每种目标语言使用单独的解码器进行一对多的多语言翻译\cite{DBLP:conf/naacl/FiratCB16}。还有一些方法为每种源语言和目标语言都使用单独的编码器和解码器,但会共享其中的一些组件\cite{luong2015multi-task,DBLP:conf/naacl/FiratCB16},比如说,共享其中的注意力模型\cite{luong2015multi-task,DBLP:conf/naacl/FiratCB16}。由于不同语言间的模型是共享的(或者部分共享的),多语言神经机器翻译方法可以降低训练代价,而且还可以有效的解决低资源神经机器翻译\cite{DBLP:journals/tacl/JohnsonSLKWCTVW17}以及多源神经机器翻译问题\cite{Och2001Statistical}
\vspace{0.5em}
\item 结构搜索。除了由研究人员手工设计神经网络结构之外,近些年{\small\bfnew{神经架构搜索}}\index{神经架构搜索}(Neural Architecture Search;NAS)\index{Neural Architecture Search}也逐渐在包括机器翻译在内的自然语言处理任务中得到广泛关注\cite{DBLP:journals/jmlr/ElskenMH19}。不同于前文提到的基于循环神经网络、Transformer结构的机器翻译模型,网络结构搜索旨在通过自动的方式根据提供的训练数据自动学习到最适合于当前任务的神经网络模型结构。目前而言,网络结构搜索的方法已经在自然语言处理的各项任务中崭露头角,在语言模型、命名实体识别等任务中获得优异的成绩\cite{DBLP:conf/iclr/ZophL17,DBLP:conf/emnlp/JiangHXZZ19,liyinqiaoESS},但对于机器翻译任务而言,由于其任务的复杂性,网络结构的搜索空间往往比较大,很难直接对其空间进行搜索,因此研究人员更倾向于对基于现有经验设计的模型结构进行改良。一些研究者提出使用进化算法,在Transformer结构基础上对模型结构进行演化,得到更加高效且建模能力更强的机器翻译模型({\red 参考文献!Evolved Transformer})。也有研究者通过将神经网络结构映射到连续空间上进行优化来获得优于初始结构的模型\cite{Luo2018Neural}
\item 结构搜索。除了由研究人员手工设计神经网络结构之外,近些年{\small\bfnew{网络结构搜索技术}}\index{网络结构搜索技术}(Neural Architecture Search;NAS)\index{Neural Architecture Search;NAS}也逐渐在包括机器翻译在内的自然语言处理任务中得到广泛关注\cite{DBLP:journals/jmlr/ElskenMH19}。不同于前文提到的基于循环神经网络、Transformer结构的机器翻译模型,网络结构搜索旨在通过自动的方式根据提供的训练数据自动学习到最适合于当前任务的神经网络模型结构,这种方式能够有效将研究人员从模型结构设计者的位置上“解救”出来,让计算机能够像学网络参数一样学习神经网络模型的结构。目前而言,网络结构搜索的方法已经在自然语言处理的各项任务中崭露头角,在语言模型、命名实体识别等任务中获得优异的成绩\cite{DBLP:conf/iclr/ZophL17,DBLP:conf/emnlp/JiangHXZZ19,liyinqiaoESS},但对于机器翻译任务而言,由于其任务的复杂性,网络结构的搜索空间往往比较大,很难直接对其空间进行搜索,因此研究人员更倾向于对基于现有经验设计的模型结构进行改良。谷歌大脑团队在The Evolved Transformer文章中提出使用进化算法,在Transformer结构基础上对模型结构进行演化,得到更加高效且建模能力更强的机器翻译模型。微软团队也在Neural Architecture Optimization\cite{Luo2018Neural}论文中提出NAO的方法,通过将神经网络结构映射到连续空间上进行优化来获得优于初始结构的模型,NAO方法在WMT19机器翻译评测任务中也进行了使用,在英语-芬兰语以及芬兰语-英语的任务上均取得了优异的成绩。
\vspace{0.5em}
\item其它机器翻译框架的结合。尽管神经机器翻译在自动评价和人工评价上都取得比统计机器翻译优异的结果,神经机器翻译仍然面临一些统计机器翻译没有的问题\cite{DBLP:conf/aclnmt/KoehnK17},如神经机器翻译系统会产生漏译的现象。一个解决的思路就是把统计机器翻译系统和神经机器翻译系统进行结合。目前的方法主要分为两种,一种是模型的改进,比如在神经机器翻译里建模统计机器翻译的概念或者使用统计机器翻译系统的模块,如词对齐,覆盖度等等\cite{DBLP:conf/aaai/HeHWW16},或者是把神经机器翻译系统结合到统计机器翻译系统中,如作为一个特征\cite{DBLP:journals/corr/GulcehreFXCBLBS15};第二种是系统融合,在不改变模型的情况下,把来自神经机器翻译系统的输出和统计机器翻译系统的输出进行融合,得到更好的结果,如使用重排序\cite{DBLP:conf/ijcnlp/KhayrallahKDPK17,DBLP:conf/acl/StahlbergHWB16,DBLP:conf/aclwat/NeubigMN15,DBLP:conf/naacl/GrundkiewiczJ18},后处理\cite{niehues-etal-2016-pre},或者把统计机器翻译系统的输出作为神经机器翻译系统解码的约束条件等等\cite{DBLP:conf/eacl/GispertBHS17}。除此之外,也可以把神经机器翻译与翻译记忆相融合({\red 参考文献!引用Guoping Huang的论文2篇}),在机器翻译应用中也是非常有趣的方向。
\item统计机器翻译的结合。尽管神经机器翻译在自动评价和人工评价上都取得比统计机器翻译优异的结果,神经机器翻译仍然面临一些统计机器翻译没有的问题\cite{DBLP:conf/aclnmt/KoehnK17},如神经机器翻译系统会产生漏译的现象,也就是源语句子的一些短语甚至从句没有被翻译,而统计机器翻译因为是把源语里所有短语都翻译出来后进行拼装,因此不会产生这种译文对原文的忠实度低的问题。一个解决的思路就是把统计机器翻译系统和神经机器翻译系统进行结合。目前的方法主要分为两种,一种是模型的改进,比如在神经机器翻译里建模统计机器翻译的概念或者使用统计机器翻译系统的模块,如词对齐,覆盖度等等\cite{DBLP:conf/aaai/HeHWW16},或者是把神经机器翻译系统结合到统计机器翻译系统中,如作为一个特征\cite{DBLP:journals/corr/GulcehreFXCBLBS15};第二种是系统融合,在不改变模型的情况下,把来自神经机器翻译系统的输出和统计机器翻译系统的输出进行融合,得到更好的结果,如使用重排序\cite{DBLP:conf/ijcnlp/KhayrallahKDPK17,DBLP:conf/acl/StahlbergHWB16,DBLP:conf/aclwat/NeubigMN15,DBLP:conf/naacl/GrundkiewiczJ18},后处理\cite{niehues-etal-2016-pre},或者把统计机器翻译系统的输出作为神经机器翻译系统解码的约束条件等等\cite{DBLP:conf/eacl/GispertBHS17}。除此之外,也可以把神经机器翻译与翻译记忆相融合({\red 参考文献!引用Guoping Huang的论文2篇}),在机器翻译应用中也是非常有趣的方向。
......
......@@ -6,13 +6,13 @@
\begin{scope}[minimum height = 20pt]
\node [anchor=east] (x1) at (-0.5em, 0) {$x_l$};
\node [anchor=west,draw=green,fill=green!20,inner xsep=5pt] (F1) at ([xshift=2em]x1.east){$\textrm{F}$};
\node [anchor=west,draw=green,fill=green!20,inner xsep=5pt] (F1) at ([xshift=2em]x1.east){$\mathcal{F}$};
\node [anchor=west,circle,draw,minimum size=1em] (n1) at ([xshift=2em]F1.east) {};
\node [anchor=west,draw=green,fill=green!20,inner xsep=5pt] (ln1) at ([xshift=2em]n1.east){\textrm{LN}};
\node [anchor=west] (x2) at ([xshift=2em]ln1.east) {$x_{l+l}$};
\node [anchor=north] (x3) at ([yshift=-5em]x1.south) {$x_l$};
\node [anchor=west,draw=green,fill=green!20,inner xsep=5pt] (F2) at ([xshift=2em]x3.east){$\textrm{F}$};
\node [anchor=west,draw=green,fill=green!20,inner xsep=5pt] (F2) at ([xshift=2em]x3.east){$\mathcal{F}$};
\node [anchor=west,draw=green,fill=green!20,inner xsep=5pt] (ln2) at ([xshift=2em]F2.east){\textrm{LN}};
\node [anchor=west,circle,draw,,minimum size=1em] (n2) at ([xshift=2em]ln2.east){};
\node [anchor=west] (x4) at ([xshift=2em]n2.east) {$x_{l+l}$};
......
......@@ -4,21 +4,21 @@
\node [anchor=north,rectangle, inner sep=0mm,minimum height=1.2em,minimum width=2em,rounded corners=5pt,thick] (n1) at (0, 0) {编码端};
\node [anchor=west,rectangle, inner sep=0mm,minimum height=1.2em,minimum width=0em,rounded corners=5pt,thick] (n2) at ([xshift=3.5em,yshift=-0.5em]n1.east) {$x_1$};
\node [anchor=west,rectangle, inner sep=0mm,minimum height=1.2em,minimum width=0em,rounded corners=5pt,thick] (n2) at ([xshift=3.5em,yshift=-0.5em]n1.east) {$z_0$};
\node [anchor=west,rectangle,draw, inner sep=0mm,minimum height=1.2em,minimum width=3em,fill=orange!20,rounded corners=5pt,thick] (n3) at ([xshift=3.5em,yshift=0em]n2.east) {$x_2$};
\node [anchor=west,rectangle,draw, inner sep=0mm,minimum height=1.2em,minimum width=3em,fill=orange!20,rounded corners=5pt,thick] (n3) at ([xshift=3.5em,yshift=0em]n2.east) {$z_1$};
\node [anchor=west,rectangle,draw, inner sep=0mm,minimum height=1.2em,minimum width=3em,fill=orange!20,rounded corners=5pt,thick] (n4) at ([xshift=3.5em,yshift=0em]n3.east) {$x_3$};
\node [anchor=west,rectangle,draw, inner sep=0mm,minimum height=1.2em,minimum width=3em,fill=orange!20,rounded corners=5pt,thick] (n4) at ([xshift=3.5em,yshift=0em]n3.east) {$z_2$};
\node [anchor=west,rectangle, inner sep=0mm,minimum height=1.2em,minimum width=1em,rounded corners=5pt,thick] (n6) at ([xshift=1.5em,yshift=0em]n4.east) {$\ldots$};
\node [anchor=west,rectangle,draw, inner sep=0mm,minimum height=1.2em,minimum width=3em,fill=orange!20,rounded corners=5pt,thick] (n5) at ([xshift=3.5em,yshift=0em]n6.east) {$x_{l+1}$};
\node [anchor=west,rectangle,draw, inner sep=0mm,minimum height=1.2em,minimum width=3em,fill=orange!20,rounded corners=5pt,thick] (n5) at ([xshift=3.5em,yshift=0em]n6.east) {$z_{l}$};
\node [anchor=west,rectangle,draw, inner sep=0mm,minimum height=1.2em,minimum width=3em,fill=orange!20,rounded corners=5pt,thick] (n7) at ([xshift=1.5em,yshift=0em]n5.east) {$x_{l+2}$};
\node [anchor=west,rectangle,draw, inner sep=0mm,minimum height=1.2em,minimum width=3em,fill=orange!20,rounded corners=5pt,thick] (n7) at ([xshift=1.5em,yshift=0em]n5.east) {$z_{l+1}$};
\node [anchor=north,rectangle,draw, inner sep=0mm,minimum height=1.2em,minimum width=15em,fill=teal!17,rounded corners=5pt,thick] (n8) at ([xshift=0em,yshift=-3em]n4.south) {层正则化};
\node [anchor=north,rectangle,draw, inner sep=0mm,minimum height=1.2em,minimum width=15em,fill=purple!17,rounded corners=5pt,thick] (n9) at ([xshift=0em,yshift=-1em]n8.south) {$z_0\ \quad z_1\ \quad z_2\quad \ldots \quad\ z_l$};
\node [anchor=north,rectangle,draw, inner sep=0mm,minimum height=1.2em,minimum width=15em,fill=purple!17,rounded corners=5pt,thick] (n9) at ([xshift=0em,yshift=-1em]n8.south) {$L_0\ \quad L_1\ \quad L_2\quad \ldots \quad\ L_l$};
\node [anchor=north,rectangle,draw, inner sep=0mm,minimum height=1.2em,minimum width=15em,fill=teal!17,rounded corners=5pt,thick] (n10) at ([xshift=0em,yshift=-2em]n9.south) {权重累加};
......
%%%------------------------------------------------------------------------------------------------------------
%%% 短语系统的问题 - 一个实例
%%
\begin{center}
\begin{tikzpicture}
\begin{scope}[scale=0.7]
\begin{scope}[scale=0.6]
\node [anchor=east,fill=red!50,draw,rounded corners=3pt] (s11) at (-0.5em, 0) {sublayer1};
\node [anchor=east,fill=red!50,draw,rounded corners=3pt] (s11) at (-0.5em, 0) {\footnotesize{sublayer1}};
\node [anchor=west,draw,circle,line width=1pt] (c11) at ([xshift=2em]s11.east) {};
\node [anchor=north,fill=red!10,draw,dashed,rounded corners=3pt] (s21) at ([yshift=-3em]s11.south) {sublayer1};
\node [anchor=west, draw,circle,dashed,line width=1pt] (c21) at ([xshift=2em]s21.east) {};
\node [anchor=west,fill=red!10,draw,dashed,rounded corners=3pt] (s22) at ([xshift=2em]c21.east) {sublayer2};
\node [anchor=west, draw,circle,dashed,line width=1pt] (c22) at ([xshift=2em]s22.east) {};
\node [anchor=north,fill=red!10,draw,dotted,rounded corners=3pt] (s21) at ([yshift=-3em]s11.south) {\footnotesize{sublayer1}};
\node [anchor=west, draw,circle,dotted,line width=1pt] (c21) at ([xshift=2em]s21.east) {};
\node [anchor=west,fill=red!10,draw,dotted,rounded corners=3pt] (s22) at ([xshift=2em]c21.east) {\footnotesize{sublayer2}};
\node [anchor=west, draw,circle,dotted,line width=1pt] (c22) at ([xshift=2em]s22.east) {};
\node [anchor=north,fill=red!50,draw,rounded corners=3pt] (s31) at ([yshift=-3em]s21.south) {sublayer1};
\node [anchor=north,fill=red!50,draw,rounded corners=3pt] (s31) at ([yshift=-3em]s21.south) {\footnotesize{sublayer1}};
\node [anchor=west,draw,circle,line width=1pt] (c31) at ([xshift=2em]s31.east) {};
\node [anchor=north,fill=red!10,draw,dashed,rounded corners=3pt] (s41) at ([yshift=-3em]s31.south) {sublayer1};
\node [anchor=north,fill=red!10,draw,dotted,rounded corners=3pt] (s41) at ([yshift=-3em]s31.south) {\footnotesize{sublayer1}};
\node [anchor=east, draw,circle,line width=1pt] (c44) at ([xshift=-2em]s41.west) {};
\node [anchor=west, draw,circle,dashed,line width=1pt] (c41) at ([xshift=2em]s41.east) {};
\node [anchor=west,fill=red!10,draw,dashed,rounded corners=3pt] (s42) at ([xshift=2em]c41.east) {sublayer2};
\node [anchor=west, draw,circle,dashed,line width=1pt] (c42) at ([xshift=2em]s42.east) {};
\node [anchor=west,fill=red!50,draw,rounded corners=3pt] (s43) at ([xshift=2em]c42.east) {sublayer3};
\node [anchor=west, draw,circle,dotted,line width=1pt] (c41) at ([xshift=2em]s41.east) {};
\node [anchor=west,fill=red!10,draw,dotted,rounded corners=3pt] (s42) at ([xshift=2em]c41.east) {\footnotesize{sublayer2}};
\node [anchor=west, draw,circle,dotted,line width=1pt] (c42) at ([xshift=2em]s42.east) {};
\node [anchor=west,fill=red!50,draw,rounded corners=3pt] (s43) at ([xshift=2em]c42.east) {\footnotesize{sublayer3}};
\node [anchor=west, draw,circle,line width=1pt] (c43) at ([xshift=2em]s43.east) {};
\draw[-,rounded corners,line width=1pt] (c44.east) -- ([xshift=0.8em]c44.east) -- ([xshift=-1.2em,yshift=2.2em]s11.west) -- ([xshift=2.7em,,yshift=2.2em]s11.east) -- (c11.north);
\draw[-,rounded corners,line width=1pt] (c44.east) -- ([xshift=0.8em]c44.east) -- ([xshift=-1.2em,yshift=2.3em]s11.west) -- ([xshift=2.8em,,yshift=2.3em]s11.east) -- (c11.north);
\draw[-,rounded corners,line width=1pt] (c44.east) -- ([xshift=0.8em]c44.east) -- ([xshift=-1.2em]s11.west) -- (s11.west);
\draw[-,rounded corners,line width=1pt] (s11.east) -- (c11.west);
\draw[-,rounded corners,line width=1pt] (c11.east) -- ([xshift=11.3em]c11.east) -- (c22.north);
\draw[-,rounded corners,line width=1pt,dashed] (c44.east) -- ([xshift=0.8em]c44.east) -- ([xshift=-1.2em,yshift=2.2em]s21.west) -- ([xshift=2.7em,,yshift=2.2em]s21.east) -- (c21.north);
\draw[-,rounded corners,line width=1pt,dashed] (c44.east) -- ([xshift=0.8em]c44.east) -- ([xshift=-1.2em]s21.west) -- (s21.west);
\draw[-,rounded corners,line width=1pt,dashed] (s21.east) -- (c21.west);
\draw[-,rounded corners,line width=1pt,dashed] (c21.east) -- (s22.west);
\draw[-,rounded corners,line width=1pt,dashed] (s22.east) -- (c22.west);
\draw[-,rounded corners,line width=1pt,dotted] (c44.east) -- ([xshift=0.8em]c44.east) -- ([xshift=-1.2em,yshift=2.3em]s21.west) -- ([xshift=2.7em,,yshift=2.3em]s21.east) -- (c21.north);
\draw[-,rounded corners,line width=1pt,dotted] (c44.east) -- ([xshift=0.8em]c44.east) -- ([xshift=-1.2em]s21.west) -- (s21.west);
\draw[-,rounded corners,line width=1pt,dotted] (s21.east) -- (c21.west);
\draw[-,rounded corners,line width=1pt,dotted] (c21.east) -- (s22.west);
\draw[-,rounded corners,line width=1pt,dotted] (s22.east) -- (c22.west);
\draw[-,rounded corners,line width=1pt] (c22.east) -- ([xshift=11.3em]c22.east) -- (c43.north);
\draw[-,rounded corners,line width=1pt] (c44.east) -- ([xshift=0.8em]c44.east) -- ([xshift=-1.2em,yshift=2.2em]s31.west) -- ([xshift=2.7em,,yshift=2.2em]s31.east) -- (c31.north);
\draw[-,rounded corners,line width=1pt] (c44.east) -- ([xshift=0.8em]c44.east) -- ([xshift=-1.2em,yshift=2.3em]s31.west) -- ([xshift=2.7em,,yshift=2.3em]s31.east) -- (c31.north);
\draw[-,rounded corners,line width=1pt] (c44.east) -- ([xshift=0.8em]c44.east) -- ([xshift=-1.2em]s31.west) -- (s31.west);
\draw[-,rounded corners,line width=1pt] (s31.east) -- (c31.west);
\draw[-,rounded corners,line width=1pt] (c31.east) -- ([xshift=11.3em]c31.east) -- (c42.north);
\draw[-,rounded corners,line width=1pt,dashed] (c44.east) -- ([xshift=0.8em]c44.east) -- ([xshift=-1.2em,yshift=2.2em]s41.west) -- ([xshift=2.7em,,yshift=2.2em]s41.east) -- (c41.north);
\draw[-,rounded corners,line width=1pt,dashed] (c44.east) -- (s41.west);
\draw[-,rounded corners,line width=1pt,dashed] (s41.east) -- (c41.west);
\draw[-,rounded corners,line width=1pt,dashed] (c41.east) -- (s42.west);
\draw[-,rounded corners,line width=1pt,dashed] (s42.east) -- (c42.west);
\draw[-,rounded corners,line width=1pt,dotted] (c44.east) -- ([xshift=0.8em]c44.east) -- ([xshift=-1.2em,yshift=2.3em]s41.west) -- ([xshift=2.7em,,yshift=2.3em]s41.east) -- (c41.north);
\draw[-,rounded corners,line width=1pt,dotted] (c44.east) -- (s41.west);
\draw[-,rounded corners,line width=1pt,dotted] (s41.east) -- (c41.west);
\draw[-,rounded corners,line width=1pt,dotted] (c41.east) -- (s42.west);
\draw[-,rounded corners,line width=1pt,dotted] (s42.east) -- (c42.west);
\draw[-,rounded corners,line width=1pt] (c42.east) -- (s43.west);
\draw[-,rounded corners,line width=1pt] (s43.east) -- (c43.west);
\draw[->,rounded corners,line width=1pt] (c43.east) -- ([xshift=2em]c43.east);
......
\begin{center}
\begin{tikzpicture}
\begin{tikzpicture}[scale=1.3]
\footnotesize{
\begin{axis}[
width=.40\textwidth,
height=.30\textwidth,
legend style={at={(0.60,0.08)}, anchor=south west},
xlabel={\footnotesize{更新次数(10k)}},
ylabel={\footnotesize{学习率 (\scriptsize{$10^{-3}$}}},
xlabel={\scriptsize{更新次数(10k)}},
ylabel={\scriptsize{学习率 ($10^{-3}$}},
ylabel style={yshift=-1em},xlabel style={yshift=0.0em},
yticklabel style={/pgf/number format/precision=2,/pgf/number format/fixed zerofill},
ymin=0,ymax=2.2, ytick={0.5, 1, 1.5, 2},
......
......@@ -4,57 +4,57 @@
\begin{tikzpicture}
\begin{scope}
\node [anchor=east,fill=orange!20,draw=orange,rounded corners=3pt,minimum height=1.4em,minimum width=1.4em] (s11) at (-0.5em, 0) {$\times h$};
\node [rectangle,anchor=west,fill=blue!20,draw=blue,rounded corners=3pt,minimum height=1.4em,minimum width=1.5em] (s12) at ([xshift=1.5em]s11.east) {};
\node [anchor=east,fill=orange!20,draw,rounded corners=3pt,minimum height=1.6em,minimum width=1.6em] (s11) at (-0.5em, 0) {\footnotesize{$\times h$}};
\node [rectangle,anchor=west,fill=blue!20,draw,rounded corners=3pt,minimum height=1.6em,minimum width=1.6em] (s12) at ([xshift=1.2em]s11.east) {};
\node [anchor=north,fill=orange!20,draw=orange,rounded corners=3pt,minimum height=1.4em,minimum width=1.4em] (s21) at ([yshift=-1.8em]s11.south) {$\times h$};
\node [anchor=west,fill=orange!20,draw=red,rounded corners=3pt,minimum height=1.4em,minimum width=1.4em,dashed] (s22) at ([xshift=1.5em]s21.east) {$\times h$};
\node [anchor=west,fill=blue!20,draw=blue,rounded corners=3pt,minimum height=1.4em,minimum width=1.5em] (s23) at ([xshift=1.5em]s22.east) {};
\node [anchor=north,fill=orange!20,draw,rounded corners=3pt,minimum height=1.6em,minimum width=1.6em] (s21) at ([yshift=-1.2em]s11.south) {\footnotesize{$\times h$}};
\node [anchor=west,fill=orange!20,draw=red,rounded corners=3pt,minimum height=1.6em,minimum width=1.6em,dashed] (s22) at ([xshift=1.2em]s21.east) {\footnotesize{$\times h$}};
\node [anchor=west,fill=blue!20,draw,rounded corners=3pt,minimum height=1.6em,minimum width=1.6em] (s23) at ([xshift=1.2em]s22.east) {};
\node [anchor=north,fill=orange!20,draw=orange,rounded corners=3pt,minimum height=1.4em,minimum width=1.4em] (s31) at ([yshift=-1.8em]s21.south) {$\times h$};
\node [anchor=west,fill=orange!20,draw=orange,rounded corners=3pt,minimum height=1.4em,minimum width=1.4em] (s32) at ([xshift=1.5em]s31.east) {$\times h$};
\node [anchor=west,fill=orange!20,draw=red,rounded corners=3pt,minimum height=1.4em,minimum width=1.4em,dashed] (s33) at ([xshift=1.5em]s32.east) {$\times h$};
\node [anchor=west,fill=blue!20,draw=blue,rounded corners=3pt,minimum height=1.4em,minimum width=1.5em] (s34) at ([xshift=1.5em]s33.east) {};
\node [anchor=north,fill=orange!20,draw,rounded corners=3pt,minimum height=1.6em,minimum width=1.6em] (s31) at ([yshift=-1.2em]s21.south) {\footnotesize{$\times h$}};
\node [anchor=west,fill=orange!20,draw,rounded corners=3pt,minimum height=1.6em,minimum width=1.6em] (s32) at ([xshift=1.2em]s31.east) {\footnotesize{$\times h$}};
\node [anchor=west,fill=orange!20,draw=red,rounded corners=3pt,minimum height=1.6em,minimum width=1.6em,dashed] (s33) at ([xshift=1.2em]s32.east) {\footnotesize{$\times h$}};
\node [anchor=west,fill=blue!20,draw,rounded corners=3pt,minimum height=1.6em,minimum width=1.6em] (s34) at ([xshift=1.2em]s33.east) {};
\node [anchor=north,fill=orange!20,draw=orange,rounded corners=3pt,minimum height=1.4em,minimum width=1.4em] (s41) at ([yshift=-1.8em]s31.south) {$\times h$};
\node [anchor=west,fill=orange!20,draw=orange,rounded corners=3pt,minimum height=1.4em,minimum width=1.4em] (s42) at ([xshift=1.5em]s41.east) {$\times h$};
\node [anchor=west,fill=orange!20,draw=orange,rounded corners=3pt,minimum height=1.4em,minimum width=1.4em] (s43) at ([xshift=1.5em]s42.east) {$\times h$};
\node [anchor=west,fill=orange!20,draw=red,rounded corners=3pt,minimum height=1.4em,minimum width=1.4em,dashed] (s44) at ([xshift=1.5em]s43.east) {$\times h$};
\node [anchor=west,fill=blue!20,draw=blue,rounded corners=3pt,minimum height=1.4em,minimum width=1.5em] (s45) at ([xshift=1.5em]s44.east) {};
\node [anchor=north,fill=orange!20,draw,rounded corners=3pt,minimum height=1.6em,minimum width=1.6em] (s41) at ([yshift=-1.2em]s31.south) {\footnotesize{$\times h$}};
\node [anchor=west,fill=orange!20,draw,rounded corners=3pt,minimum height=1.6em,minimum width=1.6em] (s42) at ([xshift=1.2em]s41.east) {\footnotesize{$\times h$}};
\node [anchor=west,fill=orange!20,draw,rounded corners=3pt,minimum height=1.6em,minimum width=1.6em] (s43) at ([xshift=1.2em]s42.east) {\footnotesize{$\times h$}};
\node [anchor=west,fill=orange!20,draw=red,rounded corners=3pt,minimum height=1.6em,minimum width=1.6em,dashed] (s44) at ([xshift=1.2em]s43.east) {\footnotesize{$\times h$}};
\node [anchor=west,fill=blue!20,draw,rounded corners=3pt,minimum height=1.6em,minimum width=1.6em] (s45) at ([xshift=1.2em]s44.east) {};
\node [anchor=east] (p1) at ([xshift=-2em]s11.west) {step 1};
\node [anchor=east] (p2) at ([xshift=-2em]s21.west) {step 2};
\node [anchor=east] (p3) at ([xshift=-2em]s31.west) {step 3};
\node [anchor=east] (p4) at ([xshift=-2em]s41.west) {step 4};
\node [anchor=east] (p1) at ([xshift=-2em]s11.west) {\footnotesize{step 1}};
\node [anchor=east] (p2) at ([xshift=-2em]s21.west) {\footnotesize{step 2}};
\node [anchor=east] (p3) at ([xshift=-2em]s31.west) {\footnotesize{step 3}};
\node [anchor=east] (p4) at ([xshift=-2em]s41.west) {\footnotesize{step 4}};
\node [anchor=south,fill=orange!20,draw=orange,rounded corners=3pt,minimum height=1.4em,minimum width=1.4em] (b1) at ([xshift=-0.2em,yshift=2em]p1.north) {};
\node [anchor=west] (b2) at (b1.east) {:编码器};
\node [anchor=west,fill=blue!20,draw=blue,rounded corners=3pt,minimum height=1.4em,minimum width=1.4em] (b3) at ([xshift=1em]b2.east) {};
\node [anchor=west] (b4) at (b3.east) {:解码器};
\node [anchor=west] (b5) at ([xshift=2.5em]b4.east) {:拷贝};
\draw[-latex,thick,red,dashed] ([xshift=0.2em]b4.east) -- (b5.west);
\node [anchor=south,fill=orange!20,draw,rounded corners=3pt,minimum height=1.4em,minimum width=1.4em] (b1) at ([xshift=-0.2em,yshift=1.6em]p1.north) {};
\node [anchor=west] (b2) at (b1.east) {\footnotesize{:编码器}};
\node [anchor=west,fill=blue!20,draw,rounded corners=3pt,minimum height=1.4em,minimum width=1.4em] (b3) at ([xshift=1em]b2.east) {};
\node [anchor=west] (b4) at (b3.east) {\footnotesize{:解码器}};
\node [anchor=west] (b5) at ([xshift=2em]b4.east) {\footnotesize{:拷贝}};
\draw[-latex,thick,red,dashed] ([xshift=0.5em]b4.east) -- (b5.west);
\draw [-latex, line width=0.8pt] ([xshift=-1.5em]s11.west) -- (s11.west);
\draw [-latex, line width=0.8pt] ([xshift=-1.2em]s11.west) -- (s11.west);
\draw [-latex, line width=0.8pt] (s11.east) -- (s12.west);
\draw [-latex, line width=0.8pt] (s12.east) -- ([xshift=1.5em]s12.east);
\draw [-latex, line width=0.8pt] (s12.east) -- ([xshift=1.2em]s12.east);
\draw [-latex, line width=0.8pt] ([xshift=-1.5em]s21.west) -- (s21.west);
\draw [-latex, line width=0.8pt] ([xshift=-1.2em]s21.west) -- (s21.west);
\draw [-latex, line width=0.8pt] (s21.east) -- (s22.west);
\draw [-latex, line width=0.8pt] (s22.east) -- (s23.west);
\draw [-latex, line width=0.8pt] (s23.east) -- ([xshift=1.5em]s23.east);
\draw [-latex, line width=0.8pt] (s23.east) -- ([xshift=1.2em]s23.east);
\draw [-latex, line width=0.8pt] ([xshift=-1.5em]s31.west) -- (s31.west);
\draw [-latex, line width=0.8pt] ([xshift=-1.2em]s31.west) -- (s31.west);
\draw [-latex, line width=0.8pt] (s31.east) -- (s32.west);
\draw [-latex, line width=0.8pt] (s32.east) -- (s33.west);
\draw [-latex, line width=0.8pt] (s33.east) -- (s34.west);
\draw [-latex, line width=0.8pt] (s34.east) -- ([xshift=1.5em]s34.east);
\draw [-latex, line width=0.8pt] (s34.east) -- ([xshift=1.2em]s34.east);
\draw [-latex, line width=0.8pt] ([xshift=-1.5em]s41.west) -- (s41.west);
\draw [-latex, line width=0.8pt] ([xshift=-1.2em]s41.west) -- (s41.west);
\draw [-latex, line width=0.8pt] (s41.east) -- (s42.west);
\draw [-latex, line width=0.8pt] (s42.east) -- (s43.west);
\draw [-latex, line width=0.8pt] (s43.east) -- (s44.west);
\draw [-latex, line width=0.8pt] (s44.east) -- (s45.west);
\draw [-latex, line width=0.8pt] (s45.east) -- ([xshift=1.5em]s45.east);
\draw [-latex, line width=0.8pt] (s45.east) -- ([xshift=1.2em]s45.east);
\draw[-latex,thick,red,dashed] (s11.south)..controls +(south:1em) and +(north:1.2em)..(s22.north);
\draw[-latex,thick,red,dashed] (s22.south)..controls +(south:1em) and +(north:1.2em)..(s33.north);
......
%%%------------------------------------------------------------------------------------------------------------
%%% 短语系统的问题 - 一个实例
\begin{center}
\begin{tikzpicture}
\begin{scope}
......@@ -29,10 +28,10 @@
\node [anchor=east] (p3) at ([xshift=-4em]s31.west) {$p=2$};
\node [anchor=east] (p4) at ([xshift=-4em]s41.west) {$p=4$};
\node [anchor=north] (p5) at ([yshift=-1em]p3.south) {$\cdots$};
\node [anchor=south,fill=orange!20,draw,rounded corners=3pt,minimum height=1.4em,minimum width=1.4em] (b1) at ([xshift=-0.6em,yshift=2em]p1.north) {};
\node [anchor=west] (b2) at (b1.east) {:Layer};
\node [anchor=south,fill=orange!20,draw,rounded corners=3pt,minimum height=1.4em,minimum width=1.4em] (b1) at ([xshift=-0.6em,yshift=1.2em]p1.north) {};
\node [anchor=west] (b2) at (b1.east) {\footnotesize{:Layer}};
\node [anchor=west,draw=red,rounded corners=3pt,minimum height=1.4em,minimum width=1.4em,dashed,line width=0.8pt] (b3) at ([xshift=1em]b2.east) {};
\node [anchor=west] (b4) at (b3.east) {:Block};
\node [anchor=west] (b4) at (b3.east) {\footnotesize{:Block}};
\draw [-latex, line width=0.8pt] ([xshift=-2em]s11.west) -- (s11.west);
\draw [-latex, line width=0.8pt] (s11.east) -- (s12.west);
......
Markdown 格式
0%
您添加了 0 到此讨论。请谨慎行事。
请先完成此评论的编辑!
注册 或者 后发表评论