Commit 3a55dabc by 曹润柘

合并分支 'master' 到 'caorunzhe'

Master

查看合并请求 !600
parents ab3bed66 661996bc
...@@ -21,7 +21,7 @@ ...@@ -21,7 +21,7 @@
\node[layernode,anchor=north] (layer11) at ([yshift=-\hseg]layer01.south) {}; \node[layernode,anchor=north] (layer11) at ([yshift=-\hseg]layer01.south) {};
\node[attnnode,anchor=south] (attn11) at ([yshift=0.1\hnode]layer11.south) {}; \node[attnnode,anchor=south] (attn11) at ([yshift=0.1\hnode]layer11.south) {};
\node[anchor=north west,inner sep=4pt,font=\small] () at (attn11.north west) {Attention}; \node[anchor=north west,inner sep=4pt,font=\small] () at (attn11.north west) {注意力};
\node[anchor=south,inner sep=0pt] (out11) at ([yshift=0.3\hseg]attn11.north) {$\cdots$}; \node[anchor=south,inner sep=0pt] (out11) at ([yshift=0.3\hseg]attn11.north) {$\cdots$};
\node[thinnode,anchor=south west,thick,draw=dblue,text=black] (q11) at ([xshift=0.1\wseg,yshift=0.2\hseg]attn11.south west) {$Q^n$}; \node[thinnode,anchor=south west,thick,draw=dblue,text=black] (q11) at ([xshift=0.1\wseg,yshift=0.2\hseg]attn11.south west) {$Q^n$};
\node[thinnode,anchor=south,thick,draw=orange,text=black] (k11) at ([yshift=0.2\hseg]attn11.south) {$K^n$}; \node[thinnode,anchor=south,thick,draw=orange,text=black] (k11) at ([yshift=0.2\hseg]attn11.south) {$K^n$};
...@@ -41,7 +41,7 @@ ...@@ -41,7 +41,7 @@
\node[layernode,anchor=north] (layer12) at ([yshift=-\hseg]layer02.south) {}; \node[layernode,anchor=north] (layer12) at ([yshift=-\hseg]layer02.south) {};
\node[attnnode,anchor=south] (attn12) at ([yshift=0.1\hnode]layer12.south) {}; \node[attnnode,anchor=south] (attn12) at ([yshift=0.1\hnode]layer12.south) {};
\node[anchor=north west,inner sep=4pt,font=\small] () at (attn12.north west) {Attention}; \node[anchor=north west,inner sep=4pt,font=\small] () at (attn12.north west) {注意力};
\node[anchor=south,inner sep=0pt] (out12) at ([yshift=0.3\hseg]attn12.north) {$\cdots$}; \node[anchor=south,inner sep=0pt] (out12) at ([yshift=0.3\hseg]attn12.north) {$\cdots$};
\node[thinnode,anchor=south west,thick,draw=dblue!40,text=black!40] (q12) at ([xshift=0.1\wseg,yshift=0.2\hseg]attn12.south west) {$Q^n$}; \node[thinnode,anchor=south west,thick,draw=dblue!40,text=black!40] (q12) at ([xshift=0.1\wseg,yshift=0.2\hseg]attn12.south west) {$Q^n$};
\node[thinnode,anchor=south,thick,draw=orange!40,text=black!40] (k12) at ([yshift=0.2\hseg]attn12.south) {$K^n$}; \node[thinnode,anchor=south,thick,draw=orange!40,text=black!40] (k12) at ([yshift=0.2\hseg]attn12.south) {$K^n$};
...@@ -61,7 +61,7 @@ ...@@ -61,7 +61,7 @@
\node[layernode,anchor=north] (layer13) at ([yshift=-\hseg]layer03.south) {}; \node[layernode,anchor=north] (layer13) at ([yshift=-\hseg]layer03.south) {};
\node[attnnode,anchor=south] (attn13) at ([yshift=0.1\hnode]layer13.south) {}; \node[attnnode,anchor=south] (attn13) at ([yshift=0.1\hnode]layer13.south) {};
\node[anchor=north west,inner sep=4pt,font=\small] () at (attn13.north west) {Attention}; \node[anchor=north west,inner sep=4pt,font=\small] () at (attn13.north west) {注意力};
\node[anchor=south,inner sep=0pt] (out13) at ([yshift=0.3\hseg]attn13.north) {$\cdots$}; \node[anchor=south,inner sep=0pt] (out13) at ([yshift=0.3\hseg]attn13.north) {$\cdots$};
\node[thinnode,anchor=south west,thick,draw=dblue!40,text=black!40] (q13) at ([xshift=0.1\wseg,yshift=0.2\hseg]attn13.south west) {$Q^n$}; \node[thinnode,anchor=south west,thick,draw=dblue!40,text=black!40] (q13) at ([xshift=0.1\wseg,yshift=0.2\hseg]attn13.south west) {$Q^n$};
\node[thinnode,anchor=south,thick,draw=orange!40,text=black!40] (k13) at ([yshift=0.2\hseg]attn13.south) {$K^n$}; \node[thinnode,anchor=south,thick,draw=orange!40,text=black!40] (k13) at ([yshift=0.2\hseg]attn13.south) {$K^n$};
...@@ -84,7 +84,7 @@ ...@@ -84,7 +84,7 @@
{ {
\node[layernode,anchor=north] (layer\i\j) at ([yshift=-0.8\hseg]layer\k\j.south) {}; \node[layernode,anchor=north] (layer\i\j) at ([yshift=-0.8\hseg]layer\k\j.south) {};
\node[attnnode,anchor=south] (attn\i\j) at ([yshift=0.1\hnode]layer\i\j.south) {}; \node[attnnode,anchor=south] (attn\i\j) at ([yshift=0.1\hnode]layer\i\j.south) {};
\node[anchor=north west,inner sep=4pt,font=\small] () at (attn\i\j.north west) {Attention}; \node[anchor=north west,inner sep=4pt,font=\small] () at (attn\i\j.north west) {注意力};
\node[anchor=south,inner sep=0pt] (out\i\j) at ([yshift=0.3\hseg]attn\i\j.north) {$\cdots$}; \node[anchor=south,inner sep=0pt] (out\i\j) at ([yshift=0.3\hseg]attn\i\j.north) {$\cdots$};
\node[thinnode,anchor=south west,thick,draw=dblue!\q,text=black] (q\i\j) at ([xshift=0.1\wseg,yshift=0.2\hseg]attn\i\j.south west) {$Q^m$}; \node[thinnode,anchor=south west,thick,draw=dblue!\q,text=black] (q\i\j) at ([xshift=0.1\wseg,yshift=0.2\hseg]attn\i\j.south west) {$Q^m$};
...@@ -119,9 +119,9 @@ ...@@ -119,9 +119,9 @@
\draw[->,thick] ([yshift=-0.15em]dot3\i.north) -- ([yshift=-0.3em]attn2\i.south); \draw[->,thick] ([yshift=-0.15em]dot3\i.north) -- ([yshift=-0.3em]attn2\i.south);
} }
\node[anchor=north,align=left,inner sep=1pt,font=\footnotesize] () at (dot31.south) {(a) Standard Transformer Attention}; \node[anchor=north,align=left,inner sep=1pt,font=\footnotesize] () at (dot31.south) {(a) 标准的多层自注意力};
\node[anchor=north,align=left,inner sep=1pt,font=\footnotesize] () at (dot32.south) {(b) \textsc{San} Self-Attention}; \node[anchor=north,align=left,inner sep=1pt,font=\footnotesize] () at (dot32.south) {(b) 共享自注意力};
\node[anchor=north,align=left,inner sep=1pt,font=\footnotesize] () at (dot33.south) {(c) \textsc{San} Encoder-Decoder Attention}; \node[anchor=north,align=left,inner sep=1pt,font=\footnotesize] () at (dot33.south) {(c) 共享编码-解码注意力};
\end{scope} \end{scope}
\end{tikzpicture} \end{tikzpicture}
\ No newline at end of file
...@@ -46,7 +46,7 @@ ...@@ -46,7 +46,7 @@
\node[p,anchor=south,minimum height=0.6em] (w3_7) at ([xshift=0.3em]w3_6.south east){}; \node[p,anchor=south,minimum height=0.6em] (w3_7) at ([xshift=0.3em]w3_6.south east){};
\node[p,anchor=south,minimum height=0.8em] (w3_8) at ([xshift=0.3em]w3_7.south east){}; \node[p,anchor=south,minimum height=0.8em] (w3_8) at ([xshift=0.3em]w3_7.south east){};
\node[inner sep=0pt,font=\scriptsize] at ([yshift=0.3em]w1_2.north){thanks}; \node[inner sep=0pt,font=\scriptsize] at ([yshift=0.3em]w1_2.north){Thanks};
\node[inner sep=0pt,font=\scriptsize] at ([yshift=0.3em]w2_2.north){a}; \node[inner sep=0pt,font=\scriptsize] at ([yshift=0.3em]w2_2.north){a};
\node[inner sep=0pt,font=\scriptsize] at ([yshift=0.3em]w2_5.north){to}; \node[inner sep=0pt,font=\scriptsize] at ([yshift=0.3em]w2_5.north){to};
\node[inner sep=0pt,font=\scriptsize] at ([yshift=0.3em]w3_2.north){lot}; \node[inner sep=0pt,font=\scriptsize] at ([yshift=0.3em]w3_2.north){lot};
...@@ -74,10 +74,10 @@ ...@@ -74,10 +74,10 @@
\draw[-latex, very thick, ublue] ([yshift=-1.2em]box2.south) -- (box2.south); \draw[-latex, very thick, ublue] ([yshift=-1.2em]box2.south) -- (box2.south);
\draw[-latex, very thick, ublue] ([yshift=-1.2em]box3.south) -- (box3.south); \draw[-latex, very thick, ublue] ([yshift=-1.2em]box3.south) -- (box3.south);
\node[tgt,anchor=west] (tgt1) at ([xshift=2em]box3.east) {thanks a lot}; \node[tgt,anchor=west,align=left] (tgt1) at ([xshift=2em]box3.east) {Thanks a lot};
\node[tgt,,anchor=north](tgt2) at ([yshift=-1em]tgt1.south) {thanks to you}; \node[tgt,,anchor=north,align=left](tgt2) at ([yshift=-1em]tgt1.south) {Thanks to you};
\node[tgt,,anchor=north] (tgt3) at ([yshift=-1em]tgt2.south) {thanks a you}; \node[tgt,,anchor=north,align=left] (tgt3) at ([yshift=-1em]tgt2.south) {Thanks a you};
\node[tgt,,anchor=north] (tgt4) at ([yshift=-1em]tgt3.south) {thanks to lot}; \node[tgt,,anchor=north,align=left] (tgt4) at ([yshift=-1em]tgt3.south) {Thanks to lot};
\node[text=ugreen] at ([xshift=1em]tgt1.east){\ding{51}}; \node[text=ugreen] at ([xshift=1em]tgt1.east){\ding{51}};
\node[text=ugreen] at ([xshift=1em]tgt2.east){\ding{51}}; \node[text=ugreen] at ([xshift=1em]tgt2.east){\ding{51}};
\node[text=red] at ([xshift=1em]tgt3.east){\ding{55}}; \node[text=red] at ([xshift=1em]tgt3.east){\ding{55}};
......
...@@ -50,7 +50,7 @@ ...@@ -50,7 +50,7 @@
\draw[-latex, very thick, ublue] (encoder.east) -- (attention.west); \draw[-latex, very thick, ublue] (encoder.east) -- (attention.west);
\draw[-latex, very thick, ublue] (attention.east) -- (decoder.west); \draw[-latex, very thick, ublue] (attention.east) -- (decoder.west);
\draw[decorate,decoration={brace, mirror},ublue, very thick] ([yshift=-0.4em]de1.-135) -- node[font=\scriptsize,text=black,yshift=-1em]{predict traget length \& get position embedding}([yshift=-0.4em]de6.-45); \draw[decorate,decoration={brace, mirror},ublue, very thick] ([yshift=-0.4em]de1.-135) -- node[font=\scriptsize,text=black,yshift=-1em]{预测译文长度 \& 计算位置编码}([yshift=-0.4em]de6.-45);
%\begin{pgfonlayer}{background} %\begin{pgfonlayer}{background}
%{ %{
......
...@@ -266,7 +266,7 @@ b &=& \omega_{\textrm{high}}\cdot |\seq{x}| \label{eq:14-4} ...@@ -266,7 +266,7 @@ b &=& \omega_{\textrm{high}}\cdot |\seq{x}| \label{eq:14-4}
\section{轻量模型}\label{sec:14-3} \section{轻量模型}\label{sec:14-3}
\parinterval 翻译速度和翻译精度之间的平衡是机器翻译系统研发中的常见问题。即使是以提升翻译品质为目标的任务(如用BLEU进行评价),也不得不考虑翻译速度的影响。比如,在WMT 和CCMT 的一些任务中可能会使用反向翻译构造伪数据,涉及大量的机器翻译过程;无监督机器翻译中也会频繁地使用神经机器翻译系统构造训练数据。如果翻译速度过慢会增大实验的周期。从应用的角度看,在很多场景下翻译速度甚至比翻译品质更重要。比如,在线翻译和一些小设备上的机器翻译系统都需要保证相对低的翻译时延,以满足用户体验的最基本要求。虽然,我们希望能有一套又好又快的翻译系统,但是现实的情况是:往往需要通过牺牲一些翻译品质来换取翻译速度的提升。下面就列举一些常用的神经机器翻译轻量模型和加速方法。这些方法通常是应用在解码端,因为相比编码端,神经机器翻译的解码端是推断过程中最耗时的部分。 \parinterval 翻译速度和翻译精度之间的平衡是机器翻译系统研发中的常见问题。即使是以提升翻译品质为目标的任务(如用BLEU进行评价),也不得不考虑翻译速度的影响。比如,在很多任务中会使用反向翻译构造伪数据,涉及对大规模单语数据的翻译;无监督机器翻译中也会频繁地使用神经机器翻译系统构造训练数据。如果翻译速度过慢会增大实验的周期。从应用的角度看,在很多场景下翻译速度甚至比翻译品质更重要。比如,在线翻译和一些小设备上的机器翻译系统都需要保证相对低的翻译时延,以满足用户体验的最基本要求。虽然,我们希望能有一套又好又快的翻译系统,但是现实的情况是:往往需要通过牺牲一些翻译品质来换取翻译速度的提升。下面就列举一些常用的神经机器翻译轻量模型和加速方法。这些方法通常是应用在解码端,因为相比编码端,神经机器翻译的解码端是推断过程中最耗时的部分。
%---------------------------------------------------------------------------------------- %----------------------------------------------------------------------------------------
% NEW SUBSUB-SECTION % NEW SUBSUB-SECTION
...@@ -274,7 +274,7 @@ b &=& \omega_{\textrm{high}}\cdot |\seq{x}| \label{eq:14-4} ...@@ -274,7 +274,7 @@ b &=& \omega_{\textrm{high}}\cdot |\seq{x}| \label{eq:14-4}
\subsection{输出层的词汇选择} \subsection{输出层的词汇选择}
\parinterval 神经机器翻译需要对输入和输出的单词进行分布式表示,比如,每一个单词都用一个512 维向量进行表示。但是,由于真实的词表通常很大,因此计算并保存这些单词的向量表示会消耗较多的计算和存储资源。特别是对于基于Softmax 的输出层,使用大词表往往会占用较多的系统运算时间。虽然可以通过BPE 和限制词汇表规模的方法降低输出层计算的负担\upcite{Gage1994ANA,DBLP:conf/acl/SennrichHB16a},但是为了获得可接受的翻译品质,词汇表也不能过小,因此输出层的计算仍然十分耗时。 \parinterval 神经机器翻译需要对输入和输出的单词进行分布式表示,比如,每一个单词都用一个512 维向量进行表示。但是,由于真实的词表通常很大,因此计算并保存这些单词的向量表示会消耗较多的计算和存储资源。特别是对于基于Softmax 的输出层,使用大词表往往会占用较多的系统运算时间。虽然可以通过BPE 和限制词汇表规模的方法降低输出层计算的负担\upcite{DBLP:conf/acl/SennrichHB16a},但是为了获得可接受的翻译品质,词汇表也不能过小,因此输出层的计算仍然十分耗时。
\parinterval 对于这个问题,可以通过改变输出层的网络结构进行缓解\upcite{DBLP:conf/acl/JeanCMB15}。一种比较简单的方法是对可能输出的单词进行筛选,简称词汇选择。这里,可以利用类似于统计机器翻译的翻译表,获得每个源语言单词最可能的译文。在翻译过程中,利用注意力机制找到每个目标语位置对应的源语言位置,之后获得这些源语言单词最可能的翻译候选。之后,Softmax 只需要在这个有限的翻译候选单词集合上进行计算,大大降低了输出层的计算量。尤其对于CPU 上的系统,这个方法往往会带来明显的速度提升,同时保证翻译品质。图\ref{fig:14-4}给出了词汇选择方法的示意图。 \parinterval 对于这个问题,可以通过改变输出层的网络结构进行缓解\upcite{DBLP:conf/acl/JeanCMB15}。一种比较简单的方法是对可能输出的单词进行筛选,简称词汇选择。这里,可以利用类似于统计机器翻译的翻译表,获得每个源语言单词最可能的译文。在翻译过程中,利用注意力机制找到每个目标语位置对应的源语言位置,之后获得这些源语言单词最可能的翻译候选。之后,Softmax 只需要在这个有限的翻译候选单词集合上进行计算,大大降低了输出层的计算量。尤其对于CPU 上的系统,这个方法往往会带来明显的速度提升,同时保证翻译品质。图\ref{fig:14-4}给出了词汇选择方法的示意图。
...@@ -295,9 +295,9 @@ b &=& \omega_{\textrm{high}}\cdot |\seq{x}| \label{eq:14-4} ...@@ -295,9 +295,9 @@ b &=& \omega_{\textrm{high}}\cdot |\seq{x}| \label{eq:14-4}
\subsection{消除冗余计算} \subsection{消除冗余计算}
\parinterval 消除不必要的计算是加速机器翻译的常用技术。比如,在统计机器翻译时代,假设重组就是一种典型的避免冗余计算的手段(\chapterfour)。对于神经机器翻译中的Transformer 模型,消除冗余计算的一种简单有效的方法是对解码端的注意力结果进行缓存。在生成每个目标语译文时,Transformer 模型会对当前位置之前的所有位置进行自注意力操作,但是这些计算里只有和当前位置相关的计算是“新” 的,前面位置之间的注意力结果已经在之前的解码步骤里计算过,因此可以对其进行缓存。 \parinterval 消除不必要的计算是加速机器翻译系统的另一种方法。比如,在统计机器翻译时代,假设重组就是一种典型的避免冗余计算的手段(见\chapterseven)。对于神经机器翻译中的Transformer 模型,消除冗余计算的一种简单有效的方法是对解码端的注意力结果进行缓存。在生成每个目标语译文时,Transformer 模型会对当前位置之前的所有位置进行自注意力操作,但是这些计算里只有和当前位置相关的计算是“新” 的,前面位置之间的注意力结果已经在之前的解码步骤里计算过,因此可以对其进行缓存。
\parinterval 此外,由于Transformer 模型较为复杂,还存在很多冗余。比如,Transformer 的每一层会包含自注意力机制、层正则化、残差连接、前馈神经网络等多种不同的结构。同时,不同结构之间还会包含一些线性变换。多层Transformer(通常为6 层)模型会更加复杂。但是,这些层可能在做相似的事情,甚至有些计算根本就是重复的。图\ref{fig:14-5}中展示了解码端自注意力和编码-解码注意力中不同层的注意力权重的相似性,这里的相似性利用JensenShannon散度进行度量\upcite{61115}。可以看到,自注意力中,2-5层之间的注意力权重的分布非常相似。编码-解码注意力也有类似的现象,临近的层之间有非常相似的注意力权重。这个现象说明:在多层神经网络中有些计算是冗余的,因此很自然的想法是消除这些冗余使得机器翻译变得更“轻”。 \parinterval 此外,由于Transformer 模型较为复杂,还存在很多冗余。比如,Transformer 的每一层会包含自注意力机制、层正则化、残差连接、前馈神经网络等多种不同的结构。同时,不同结构之间还会包含一些线性变换。多层Transformer(通常为6 层)模型会更加复杂。但是,这些层可能在做相似的事情,甚至有些计算根本就是重复的。图\ref{fig:14-5}中展示了解码端自注意力和编码-解码注意力中不同层的注意力权重的相似性,这里的相似性利用Jensen-Shannon散度进行度量\upcite{61115}。可以看到,自注意力中,2-5层之间的注意力权重的分布非常相似。编码-解码注意力也有类似的现象,临近的层之间有非常相似的注意力权重。这个现象说明:在多层神经网络中有些计算是冗余的,因此很自然的想法是消除这些冗余使得机器翻译变得更“轻”。
%---------------------------------------------- %----------------------------------------------
\begin{figure}[htp] \begin{figure}[htp]
...@@ -307,7 +307,7 @@ b &=& \omega_{\textrm{high}}\cdot |\seq{x}| \label{eq:14-4} ...@@ -307,7 +307,7 @@ b &=& \omega_{\textrm{high}}\cdot |\seq{x}| \label{eq:14-4}
\label{fig:14-5} \label{fig:14-5}
\end{figure} \end{figure}
%---------------------------------------------- %----------------------------------------------
\parinterval 一种方法是将不同层的注意力权重进行共享,这样上层的注意力权重可以复用下层的注意力权重\upcite{Xiao2019SharingAW}。在编码-解码注意力中,由于注意力机制中输入的Value 都是一样的\footnote{在Transformer 解码端,编码解码注意力输入的Value 是编码端的输出,因此是相同的(详见\chaptertwelve 关于Transformer 模型的内容)。},我们甚至可以直接复用前一层注意力计算的结果。图\ref{fig:14-6}给出了不同方法的对比,其中$S$表示注意力权重,$A$表示注意机制的输出。可以看到,使用共享的思想,可以大大减少冗余的计算。 \parinterval 一种方法是将不同层的注意力权重进行共享,这样上层的注意力权重可以复用下层的注意力权重\upcite{Xiao2019SharingAW}。在编码-解码注意力中,由于注意力机制中输入的Value 都是一样的\footnote{在Transformer 解码端,编码解码注意力输入的Value 是编码端的输出,因此是相同的(\chaptertwelve},我们甚至可以直接复用前一层注意力计算的结果。图\ref{fig:14-6}给出了不同方法的对比,其中$S$表示注意力权重,$A$表示注意模型的输出。可以看到,使用共享的思想,可以大大减少冗余的计算。
%---------------------------------------------- %----------------------------------------------
\begin{figure}[htp] \begin{figure}[htp]
...@@ -318,9 +318,9 @@ b &=& \omega_{\textrm{high}}\cdot |\seq{x}| \label{eq:14-4} ...@@ -318,9 +318,9 @@ b &=& \omega_{\textrm{high}}\cdot |\seq{x}| \label{eq:14-4}
\end{figure} \end{figure}
%---------------------------------------------- %----------------------------------------------
\parinterval 另一种方法是对不同层的参数进行共享。这种方法虽然不能带来直接的提速,但是可以大大减小模型的体积。比如,可以重复使用同一层的参数完成多层的计算。极端一些的情况下,六层网络可以只使用一层网络的参数\upcite{DBLP:conf/aaai/DabreF19}。不过,在深层模型中(层数> 20),浅层部分的差异往往较大,而深层(远离输)之间的相似度会更高。这时可以考虑对深层的部分进行更多的共享。 \parinterval 另一种方法是对不同层的参数进行共享。这种方法虽然不能带来直接的提速,但是可以大大减小模型的体积。比如,可以重复使用同一层的参数完成多层的计算。极端一些的情况下,六层网络可以只使用一层网络的参数\upcite{DBLP:conf/aaai/DabreF19}。不过,在深层模型中(层数> 20),浅层部分的差异往往较大,而深层(远离输)之间的相似度会更高。这时可以考虑对深层的部分进行更多的共享。
\parinterval 减少冗余计算也代表了一种剪枝的思想。本质上,是利用模型参数的稀疏性假设\upcite{Narang2017BlockSparseRN,Gale2019TheSO}:一部分参数对模型整体的行为影响不大,因此可以直接被抛弃掉。这类方法也被使用在神经机器翻译模型的不同部分。比如,对于Transformer模型,也有研究发现多头注意力中的有些头是有冗余的\upcite{Michel2019AreSH},因此可以直接对其进行剪枝\upcite{DBLP:journals/corr/abs-1905-09418} \parinterval 减少冗余计算也代表了一种剪枝的思想。本质上,这类方法利用了模型参数的稀疏性假设\upcite{Narang2017BlockSparseRN,Gale2019TheSO}:一部分参数对模型整体的行为影响不大,因此可以直接被抛弃掉。这类方法也被使用在神经机器翻译模型的不同部分。比如,对于Transformer模型,也有研究发现多头注意力中的有些头是有冗余的\upcite{Michel2019AreSH},因此可以直接对其进行剪枝\upcite{DBLP:journals/corr/abs-1905-09418}
%---------------------------------------------------------------------------------------- %----------------------------------------------------------------------------------------
% NEW SUBSUB-SECTION % NEW SUBSUB-SECTION
...@@ -332,11 +332,11 @@ b &=& \omega_{\textrm{high}}\cdot |\seq{x}| \label{eq:14-4} ...@@ -332,11 +332,11 @@ b &=& \omega_{\textrm{high}}\cdot |\seq{x}| \label{eq:14-4}
\parinterval 比较简单的做法是把解码端的网络变得更“浅”、更“窄”。所谓浅网络是指使用更少的层构建神经网络,比如,使用3 层,甚至1 层网络的Transformer 解码器。所谓窄网络是指将网络中某些层中神经元的数量减少。不过,直接训练这样的小模型会带来翻译品质的下降。这时会考虑使用知识蒸馏(也称作知识精炼)等技术来提升小模型的品质。 \parinterval 比较简单的做法是把解码端的网络变得更“浅”、更“窄”。所谓浅网络是指使用更少的层构建神经网络,比如,使用3 层,甚至1 层网络的Transformer 解码器。所谓窄网络是指将网络中某些层中神经元的数量减少。不过,直接训练这样的小模型会带来翻译品质的下降。这时会考虑使用知识蒸馏(也称作知识精炼)等技术来提升小模型的品质。
\parinterval 另一种思路是化简Transformer 解码端的神经网络。比如,可以使用平均注意力机制代替原始Transformer 中的自注意力机制\upcite{DBLP:journals/corr/abs-1805-00631},也可以使用运算更轻的卷积操作代替注意力模块\upcite{Wu2019PayLA}。前面提到的基于共享注意力机制的模型也是一种典型的轻量模型\upcite{Xiao2019SharingAW} \parinterval 另一种思路是化简Transformer 解码端的神经网络。比如,可以使用平均注意力机制代替原始Transformer 中的自注意力机制\upcite{DBLP:journals/corr/abs-1805-00631},也可以使用运算更轻的卷积操作代替注意力模块\upcite{Wu2019PayLA}。前面提到的基于共享注意力机制的模型也是一种典型的轻量模型\upcite{Xiao2019SharingAW}这些方法本质上也是对对注意力模型的结构的优化,这类思想在近几年也受到了很多关注 \upcite{Kitaev2020ReformerTE,Katharopoulos2020TransformersAR,DBLP:journals/corr/abs-2006-04768}
\parinterval 此外,使用异构神经网络也是一种平衡精度和速度的有效方法。在很多研究中发现,基于Transformer 的编码器对翻译品质的影响更大,而解码端的作用会小一些。因此,一种想法是使用更快速的解码端结构,比如,用基于循环神经网络的解码端代替基于Transformer 的解码端\upcite{Chen2018TheBO}。这样,既能发挥Transformer 在编码上的优势,同时也能利用循环神经网络在解码端速度上的优势。使用类似的思想,也可以用卷积网络等结构进行解码端网络的设计。此外,也有研究者对注意力机制进行优化,以达到加速Transformer模型的目的\upcite{DBLP:journals/corr/abs-1805-00631,Kitaev2020ReformerTE,Katharopoulos2020TransformersAR,DBLP:journals/corr/abs-2006-04768} \parinterval 此外,使用异构神经网络也是一种平衡精度和速度的有效方法。在很多研究中发现,基于Transformer 的编码器对翻译品质的影响更大,而解码端的作用会小一些。因此,一种想法是使用更快速的解码端结构,比如,用基于循环神经网络的解码端代替基于Transformer 的解码端\upcite{Chen2018TheBO}。这样,既能发挥Transformer 在编码上的优势,同时也能利用循环神经网络在解码端速度上的优势。使用类似的思想,也可以用卷积神经网络等结构进行解码端的设计
\parinterval 针对轻量级Transformer模型的设计也包括层级的结构剪枝,这类方法试图通过跳过某些操作或者某些层来降低计算量。典型的相关工作是样本自适应网络结构,如 FastBERT\upcite{Liu2020FastBERTAS}、Depth Adaptive Transformer\upcite{Elbayad2020DepthAdaptiveT} 和LayerDrop\upcite{DBLP:conf/iclr/FanGJ20}等,与传统的Transformer的解码过程不同,这类网络结构在推断时不需要计算全部的解码层,而是根据输入自动选择模型的部分层进行计算,达到加速和减少参数量的目的。此外,矩阵分解也是一种轻量级模型解决方案,这类方法通过矩阵分解的方法提升计算效率,通过简化复杂的矩阵计算来达到加速模型训练和推断的目的。例如 Adaptive Input Representations\upcite{DBLP:conf/iclr/BaevskiA19}提出词频自适应表示,词频越高则对应的词向量维度越大,反之越小,该方法可以显著减少词向量矩阵大小。此外还有一些工作尝试消除注意力机制中的冗余计算,对层与层之间的参数进行共享\upcite{Xiao2019SharingAW}或者是对跨层参数进行共享\upcite{Lan2020ALBERTAL},以达到加速Transformer模型的目的\upcite{DBLP:journals/corr/abs-1805-00631,Kitaev2020ReformerTE,Katharopoulos2020TransformersAR,DBLP:journals/corr/abs-2006-04768} \parinterval 针对轻量级Transformer模型的设计也包括层级的结构剪枝,这类方法试图通过跳过某些操作或者某些层来降低计算量。典型的相关工作是样本自适应网络结构,如 FastBERT\upcite{Liu2020FastBERTAS}、Depth Adaptive Transformer\upcite{Elbayad2020DepthAdaptiveT} 和LayerDrop\upcite{DBLP:conf/iclr/FanGJ20}等,与传统的Transformer的解码过程不同,这类网络结构在推断时不需要计算全部的解码层,而是根据输入自动选择模型的部分层进行计算,达到加速和减少参数量的目的。此外,矩阵分解也是一种轻量级模型解决方案,这类方法通过矩阵分解的方法提升计算效率,通过简化复杂的矩阵计算来达到加速模型训练和推断的目的。例如, 有研究人员提出词频自适应表示方法,词频越高则对应的词向量维度越大,反之越小,该方法可以显著减少词向量参数矩阵大小\upcite{DBLP:conf/iclr/BaevskiA19}
%---------------------------------------------------------------------------------------- %----------------------------------------------------------------------------------------
% NEW SUBSUB-SECTION % NEW SUBSUB-SECTION
...@@ -344,13 +344,13 @@ b &=& \omega_{\textrm{high}}\cdot |\seq{x}| \label{eq:14-4} ...@@ -344,13 +344,13 @@ b &=& \omega_{\textrm{high}}\cdot |\seq{x}| \label{eq:14-4}
\subsection{批量推断} \subsection{批量推断}
\parinterval 深度学习时代下,使用GPU(图形处理单元)已经成为绝大多数神经网络模型研究的基本要求。特别是对于机器翻译这样的复杂任务,GPU 的并行运算能力会带来明显的速度提升。为了充分利用GPU 的并行能力,可以同时对多个句子进行翻译,即{\small\sffamily\bfseries{批量推断}}\index{批量推断}(Batch Inference)\index{Batch Inference} \parinterval 深度学习时代下,使用图形处理单元(GPU)已经成为大规模使用神经网络方法的前提。特别是对于机器翻译这样的复杂任务,GPU 的并行运算能力会带来明显的速度提升。为了充分利用GPU 的并行能力,可以同时对多个句子进行翻译,即{\small\sffamily\bfseries{批量推断}}\index{批量推断}(Batch Inference)\index{Batch Inference}
\parinterval\chaptersix 已经介绍了神经机器翻译中{\small\sffamily\bfseries{批量处理}}\index{批量处理}(Batching)\index{Batching}的基本概念,其实现并不困难,不过有两方面问题需要注意: \parinterval\chapterten 已经介绍了神经机器翻译中{\small\sffamily\bfseries{批量处理}}\index{批量处理}(Batching)\index{Batching}的基本概念,其实现并不困难,不过有两方面问题需要注意:
\begin{itemize} \begin{itemize}
\vspace{0.5em} \vspace{0.5em}
\item 批次生成策略。对于源语言文本预先给定的情况,通常是按句子长度组织每个批次,即:把长度相似的句子放到一个批次里。这样做的好处是可以尽可能保证一个批次中的内容是“满” 的,否则如果句长差异过大会造成批次中有很多位置用占位符填充,产生无用计算。对于实时翻译的情况,批次的组织较为复杂。由于有翻译时延的限制,可能无法等到有足够多的句子就要进行翻译。常见的做法是,设置一个等待的时间,在同一个时间段中的句子可以放到一个批次中(或者几个批次中)。对于高并发的情况,也可以考虑使用不同的Bucket保存不同长度范围的句子,之后将同一个Bucket 中的句子进行批量推断。 \item 批次生成策略。对于源语言文本预先给定的情况,通常是按句子长度组织每个批次,即:把长度相似的句子放到一个批次里。这样做的好处是可以尽可能保证一个批次中的内容是“满” 的,否则如果句长差异过大会造成批次中有很多位置用占位符填充,产生无用计算。对于实时翻译的情况,批次的组织较为复杂。由于有翻译时延的限制,可能无法等到有足够多的句子就要进行翻译。常见的做法是,设置一个等待的时间,在同一个时间段中的句子可以放到一个批次中(或者几个批次中)。对于高并发的情况,也可以考虑使用不同的Bucket保存不同长度范围的句子,之后将同一个Bucket 中的句子进行批量推断。这个问题在{\chaptereighteen}中还会做进一步讨论。
\vspace{0.5em} \vspace{0.5em}
\item 批次大小的选择。一个批次中的句子数量越多,GPU 设备的利用率越高,系统吞吐越大。但是,一个批次中所有句子翻译结束后才能拿到翻译结果,因此批次中有些句子即使已经翻译结束也要等待其它没有完成的句子。也就是说,从单个句子来看,批次越大翻译的延时越长,这也导致在翻译实时性要求较高的场景中,不能使用过大的批次。而且,大批次对GPU 显存的消耗更大,因此也需要根据具体任务合理选择批次大小。为了说明这些问题,图\ref{fig:14-7}展示了不同批次大小下的吞吐、时延和显存消耗。 \item 批次大小的选择。一个批次中的句子数量越多,GPU 设备的利用率越高,系统吞吐越大。但是,一个批次中所有句子翻译结束后才能拿到翻译结果,因此批次中有些句子即使已经翻译结束也要等待其它没有完成的句子。也就是说,从单个句子来看,批次越大翻译的延时越长,这也导致在翻译实时性要求较高的场景中,不能使用过大的批次。而且,大批次对GPU 显存的消耗更大,因此也需要根据具体任务合理选择批次大小。为了说明这些问题,图\ref{fig:14-7}展示了不同批次大小下的吞吐、时延和显存消耗。
\vspace{0.5em} \vspace{0.5em}
...@@ -375,7 +375,7 @@ b &=& \omega_{\textrm{high}}\cdot |\seq{x}| \label{eq:14-4} ...@@ -375,7 +375,7 @@ b &=& \omega_{\textrm{high}}\cdot |\seq{x}| \label{eq:14-4}
\begin{itemize} \begin{itemize}
\vspace{0.5em} \vspace{0.5em}
\item 半精度运算。半精度运算是随着近几年GPU 技术发展而逐渐流行的一种运算方式。简单来说,半精度的表示要比单精度需要更少的存储单元,所表示的浮点数范围也相应的变小。不过,实践中已经证明神经机器翻译中的许多运算用半精度计算就可以满足对精度的要求。因此,直接使用半精度运算可以大大加速系统的训练和推断进程,同时对翻译品质的影响很小。不过,需要注意的是,在分布式训练的时候,由于参数服务器需要对多个计算节点上的梯度进行累加,因此保存参数的部分仍然会使用单精度浮点以保证多次累加之后不会造成精度的损失。 \item 半精度浮点运算。半精度浮点运算是随着近几年GPU 技术发展而逐渐流行的一种运算方式。简单来说,半精度的表示要比单精度需要更少的存储单元,所表示的浮点数范围也相应的变小。不过,实践中已经证明神经机器翻译中的许多运算用半精度计算就可以满足对精度的要求。因此,直接使用半精度运算可以大大加速系统的训练和推断进程,同时对翻译品质的影响很小。不过,需要注意的是,在分布式训练的时候,由于参数服务器需要对多个计算节点上的梯度进行累加,因此保存参数的部分仍然会使用单精度浮点以保证多次累加之后不会造成精度过大的损失。
\vspace{0.5em} \vspace{0.5em}
\item 整型运算。整数运算是一种比浮点运算“轻” 很多的运算。无论是芯片占用面积、能耗还是处理单次运算的时钟周期数,整数运算相比浮点运算都有着明显的优势。因此,使用整数运算也是很有潜力的加速手段。不过,整数的表示和浮点数有着很大的不同。一个基本的问题是,整数是不连续的,因此无法准确的刻画浮点数中很小的小数。对于这个问题,一种解决方法是利用“量化+ 反量化+ 缩放” 的策略让整数运算近似浮点运算的效果\upcite{DBLP:journals/corr/abs-1906-00532,DBLP:conf/cvpr/JacobKCZTHAK18,DBLP:journals/corr/abs-1910-10485}。所谓“量化” 就是把一个浮点数离散化为一个整数,“反量化” 是这个过程的逆过程。由于浮点数可能超出整数的范围,因此会引入一个缩放因子。在量化前将浮点数缩放到整数可以表示的范围,反量化前再缩放回原始浮点数的表示范围。这种方法在理论上可以带来很好的加速效果。不过由于量化和反量化的操作本身也有时间消耗,而且在不同处理器上的表现差异较大。因此不同的实现方式带来的加速效果并不相同,需要通过实验测算。 \item 整型运算。整数运算是一种比浮点运算“轻” 很多的运算。无论是芯片占用面积、能耗还是处理单次运算的时钟周期数,整数运算相比浮点运算都有着明显的优势。因此,使用整数运算也是很有潜力的加速手段。不过,整数的表示和浮点数有着很大的不同。一个基本的问题是,整数是不连续的,因此无法准确的刻画浮点数中很小的小数。对于这个问题,一种解决方法是利用“量化+ 反量化+ 缩放” 的策略让整数运算近似浮点运算的效果\upcite{DBLP:journals/corr/abs-1906-00532,DBLP:conf/cvpr/JacobKCZTHAK18,DBLP:journals/corr/abs-1910-10485}。所谓“量化” 就是把一个浮点数离散化为一个整数,“反量化” 是这个过程的逆过程。由于浮点数可能超出整数的范围,因此会引入一个缩放因子。在量化前将浮点数缩放到整数可以表示的范围,反量化前再缩放回原始浮点数的表示范围。这种方法在理论上可以带来很好的加速效果。不过由于量化和反量化的操作本身也有时间消耗,而且在不同处理器上的表现差异较大。因此不同的实现方式带来的加速效果并不相同,需要通过实验测算。
\vspace{0.5em} \vspace{0.5em}
...@@ -386,7 +386,7 @@ b &=& \omega_{\textrm{high}}\cdot |\seq{x}| \label{eq:14-4} ...@@ -386,7 +386,7 @@ b &=& \omega_{\textrm{high}}\cdot |\seq{x}| \label{eq:14-4}
%---------------------------------------------- %----------------------------------------------
\begin{table}[htp] \begin{table}[htp]
\centering \centering
\caption{不同计算精度的芯片的运算速度对比\protect\footnotemark} \caption{不同计算精度的运算速度对比\protect\footnotemark}
\begin{tabular}{ l | l l l l l} \begin{tabular}{ l | l l l l l}
\rule{0pt}{13pt} 指标 & FP32 &INT32 &INT16 &INT8 &INT4 \\ \hline \rule{0pt}{13pt} 指标 & FP32 &INT32 &INT16 &INT8 &INT4 \\ \hline
\rule{0pt}{13pt} 速度 & 1$\times$ & 3$\sim$4$\times$ & $\approx$4$\times$ & 4$\sim$6$\times$ & $\approx$8$\times$ \rule{0pt}{13pt} 速度 & 1$\times$ & 3$\sim$4$\times$ & $\approx$4$\times$ & 4$\sim$6$\times$ & $\approx$8$\times$
...@@ -404,7 +404,7 @@ b &=& \omega_{\textrm{high}}\cdot |\seq{x}| \label{eq:14-4} ...@@ -404,7 +404,7 @@ b &=& \omega_{\textrm{high}}\cdot |\seq{x}| \label{eq:14-4}
\section{非自回归翻译} \section{非自回归翻译}
\parinterval 目前大多数神经机器翻译模型都使用了编码器-解码器框架来实现,编码器将源语句的表示送入到解码器来生成目标句子;解码器通常从左到右逐字地生成目标句子,也就是,第$j$个目标词的生成依赖于先前生成的$j-1$个目标词。这种翻译方式也被称作{\small\sffamily\bfseries{自回归解码}}\index{自回归解码}(Auto-regressive Decoding)\index{Auto-regressive Decoding}\upcite{bahdanau2014neural,DBLP:journals/corr/GehringAGYD17,vaswani2017attention}。虽然最近提出的基于卷积或者自注意力的模型使得训练过程高度并行化,加快了训练速度。但由于推断过程自回归的特性,模型无法同时生成目标语的所有单词,这导致模型的推断过程非常缓慢,这对于神经机器的实际应用是个很大的挑战。因此,如何设计一个在训练和推断阶段都能够并行化的模型是目前研究的热点之一。 \parinterval 目前大多数神经机器翻译模型都使用了编码器-解码器框架来实现,编码器的输出会被送入到解码器,解码器自左向右逐词生成目标语言句子,也就是,第$j$个目标语言单词的生成依赖于先前生成的$j-1$个词。这种翻译方式也被称作{\small\sffamily\bfseries{自回归解码}}\index{自回归解码}(Autoregressive Decoding)\index{Autoregressive Decoding}。虽然以Transformer为代表的模型使得训练过程高度并行化,加快了训练速度。但由于推断过程自回归的特性,模型无法同时生成目标语的所有单词,这导致模型的推断过程非常缓慢,这对于神经机器的实际应用是个很大的挑战。因此,如何设计一个在训练和推断阶段都能够并行化的模型是目前研究的热点之一。
%---------------------------------------------------------------------------------------- %----------------------------------------------------------------------------------------
% NEW SUBSUB-SECTION % NEW SUBSUB-SECTION
...@@ -412,14 +412,14 @@ b &=& \omega_{\textrm{high}}\cdot |\seq{x}| \label{eq:14-4} ...@@ -412,14 +412,14 @@ b &=& \omega_{\textrm{high}}\cdot |\seq{x}| \label{eq:14-4}
\subsection{自回归VS非自回归} \subsection{自回归VS非自回归}
\parinterval 目前主流的神经机器翻译的推断是一种{\small\sffamily\bfseries{自回归翻译}}\index{自回归翻译}(Autoregressive Translation)\index{Autoregressive Translation}过程。所谓自回归是一种描述时间序列生成的方式。对于目标序列$\seq{y}=\{y_1,\dots,y_n\}$,自回归模型假设$j$时刻状态$y_j$的生成依赖于之前的状态$\{y_1,\dots,y_{j-1}\}$,而且$y_j$$\{y_1,\dots,y_{j-1}\}$构成线性关系,那么生成$y_j$就是自回归的序列生成过程。神经机器翻译借用了这个概念,但是并不要求线性模型。对于输入的源语言序列$\seq{x}=\{x_1,\dots,x_m\}$,用自回归翻译模型生成译文序列$\seq{y}=\{y_1,\dots,y_n\}$的概率可以被定义为: \parinterval 目前主流的神经机器翻译的推断是一种{\small\sffamily\bfseries{自回归翻译}}\index{自回归翻译}(Autoregressive Translation)\index{Autoregressive Translation}过程。所谓自回归是一种描述时间序列生成的方式。对于目标序列$\seq{y}=\{y_1,\dots,y_n\}$,自回归模型假设$j$时刻状态$y_j$的生成依赖于之前的状态$\{y_1,\dots,y_{j-1}\}$,而且$y_j$$\{y_1,\dots,y_{j-1}\}$构成线性关系,那么生成$y_j$就是自回归的序列生成过程。神经机器翻译借用了这个概念,但是并不要求使用线性模型。对于输入的源语言序列$\seq{x}=\{x_1,\dots,x_m\}$,用自回归翻译模型生成译文序列$\seq{y}=\{y_1,\dots,y_n\}$的概率可以被定义为:
\begin{eqnarray} \begin{eqnarray}
\funp{P}(\seq{y}|\seq{x}) &=& \prod_{j=1}^n {\funp{P}(y_j|y_{<j},\seq{x})} \funp{P}(\seq{y}|\seq{x}) &=& \prod_{j=1}^n {\funp{P}(y_j|y_{<j},\seq{x})}
\label{eq:14-8} \label{eq:14-8}
\end{eqnarray} \end{eqnarray}
\noindent 即译文单词$y_{j}$的生成依赖前面已经生成的单词序列$\{y_1,\dots,y_{j-1}\}$和源语言序列$\{x_1,\dots,x_m\}$。这种自回归的翻译方式符合人们阅读和生成句子时的习惯。它在机器翻译等任务上也取得了较好的性能,特别是配合束搜索也能够有效的寻找近似最优译文。但是,由于解码器的每个步骤必须顺序地而不是并行地运行,自回归翻译模型会阻碍不同译文单词生成的并行化。特别是在GPU 上,翻译的自回归性会大大降低计算的并行度,导致推断过程的效率比较低下,设备利用率低。 \noindent 即译文单词$y_{j}$的生成依赖前面已经生成的单词序列$y_{<j}=\{y_1,\dots,y_{j-1}\}$和源语言序列$\{x_1,\dots,x_m\}$。这种自回归的翻译方式符合人们阅读和生成句子时的习惯。它在机器翻译等任务上也取得了较好的性能,特别是配合束搜索也能够有效的寻找近似最优译文。但是,由于解码器的每个步骤必须顺序地而不是并行地运行,自回归翻译模型会阻碍不同译文单词生成的并行化。特别是在GPU 上,翻译的自回归性会大大降低计算的并行度,导致推断过程的效率比较低下,设备利用率低。
\parinterval 对于这个问题,研究者也考虑移除翻译的自归回性,进行{\small\sffamily\bfseries{非自回归翻译}}\index{非自回归翻译}(Non-Autoregressive Translation,NAT)\index{Non-Autoregressive Translation}\upcite{Gu2017NonAutoregressiveNM}。一个简单的非自回归翻译模型将问题建模为: \parinterval 对于这个问题,研究者也考虑移除翻译的自归回性,进行{\small\sffamily\bfseries{非自回归翻译}}\index{非自回归翻译}(Non-Autoregressive Translation,NAT)\index{Non-Autoregressive Translation}\upcite{Gu2017NonAutoregressiveNM}。一个简单的非自回归翻译模型将问题建模为:
...@@ -436,9 +436,9 @@ b &=& \omega_{\textrm{high}}\cdot |\seq{x}| \label{eq:14-4} ...@@ -436,9 +436,9 @@ b &=& \omega_{\textrm{high}}\cdot |\seq{x}| \label{eq:14-4}
\subsection{非自回归翻译模型的结构} \subsection{非自回归翻译模型的结构}
\parinterval 在介绍非自回归模型的具体结构之前,先来想想如何实现一个简单的非自回归翻译模型。这里用标准的Transformer来举例。首先为了一次性能够生成所有的词,需要将解码端的对未来信息屏蔽的矩阵丢弃从而去掉模型的自回归性。此外,还要考虑要生成的目标句子有多长。自回归模型每步的输入是上一步解码出的结果,当预测到终止符<eos>时序列的生成就自动停止了,然而非自回归模型却没有这样的特性,因此还需要一个长度预测器来预测出其长度,之后再用这个长度得到每个位置的表示,进而完成整个序列的生成。 \parinterval 在介绍非自回归模型的具体结构之前,先来看看如何实现一个简单的非自回归翻译模型。这里用标准的Transformer来举例。首先为了一次性能够生成所有的词,需要丢弃解码端对未来信息屏蔽的矩阵,从而去掉模型的自回归性。此外,还要考虑生成一问的长度。自回归模型每步的输入是上一步解码出的结果,当预测到终止符<eos>时序列的生成就自动停止了,然而非自回归模型却没有这样的特性,因此还需要一个长度预测器来预测出其长度,之后再用这个长度得到每个位置的表示,进而完成整个序列的生成。
\parinterval\ref{fig:14-12}就是一个最简单的非自回归翻译模型,在推断过程就可以一次性解码出整个目标序列。但是这样得到的模型所翻译出的句子质量很低。比如,在IWSLT英德等数据上的BLEU值只有个位数,而现在最好的自回归模型已经能够达到30左右的BLEU值。这是因为每个位置词的分布$\funp{P}(y_j)$只依赖于源语言句子$\seq{x}$,使得模型对真实目标分布的近似性很差,缺乏了关键的序列依赖信息 \parinterval\ref{fig:14-12}就是一个最简单的非自回归翻译模型,它的推断过程可以一次性解码出整个目标序列。但是这样得到的模型所翻译出的句子质量很低。比如,在IWSLT英德等数据上的BLEU值只有个位数,而现在最好的自回归模型已经能够达到30左右的BLEU值。这是因为每个位置词的分布$\funp{P}(y_j)$只依赖于源语言句子$\seq{x}$,使得$\funp{P}(y_j)$的预测不准确
%---------------------------------------------------------------------- %----------------------------------------------------------------------
\begin{figure}[htp] \begin{figure}[htp]
...@@ -449,7 +449,7 @@ b &=& \omega_{\textrm{high}}\cdot |\seq{x}| \label{eq:14-4} ...@@ -449,7 +449,7 @@ b &=& \omega_{\textrm{high}}\cdot |\seq{x}| \label{eq:14-4}
\end{figure} \end{figure}
%---------------------------------------------------------------------- %----------------------------------------------------------------------
\parinterval 完全独立地对每个词建模,会出现什么问题呢?来看一个例子,将中文“谢谢你”翻译成英文,可以翻译成“thanks to you”或者“thanks a lot”。假设生成这两种翻译的概率是相等的,即一半的概率是“thanks to you”,另一半的概率是“thanks a lot”。由于非自回归模型的条件独立性假设,解码时第二个词“to”和“a”的概率是差不多大的,第三个词“you”和“lot”的概率差不多大的,会使得模型生成出“thanks to lot”或者“thanks a you”这样错误的翻译,如图\ref{fig:14-13}所示。这便是影响句子质量的关键问题,称之为{\small\sffamily\bfseries{多峰问题}}\index{多峰问题}(Multi-modality Problem)\index{Multi-modality Problem}\upcite{Gu2017NonAutoregressiveNM}。针对非自回归模型难以处理多峰问题进行改进是提升非自回归模型质量的关键。 \parinterval 完全独立地对每个词建模,会出现什么问题呢?来看一个例子,将中文“谢谢你”翻译成英文,可以翻译成“Thanks to you”或者“Thanks a lot”。假设生成这两种翻译的概率是相等的,即一半的概率是“Thanks to you”,另一半的概率是“Thanks a lot”。由于非自回归模型的条件独立性假设,解码时第二个词“to”和“a”的概率是差不多大的,第三个词“you”和“lot”的概率差不多大的,会使得模型生成出“Thanks to lot”或者“Thanks a you”这样错误的翻译,如图\ref{fig:14-13}所示。这便是影响句子质量的关键问题,称之为{\small\sffamily\bfseries{多峰问题}}\index{多峰问题}(Multi-modality Problem)\index{Multi-modality Problem}\upcite{Gu2017NonAutoregressiveNM}。针对非自回归模型难以处理多峰问题进行改进是提升非自回归模型质量的关键。
%---------------------------------------------------------------------- %----------------------------------------------------------------------
\begin{figure}[htp] \begin{figure}[htp]
...@@ -460,7 +460,7 @@ b &=& \omega_{\textrm{high}}\cdot |\seq{x}| \label{eq:14-4} ...@@ -460,7 +460,7 @@ b &=& \omega_{\textrm{high}}\cdot |\seq{x}| \label{eq:14-4}
\end{figure} \end{figure}
%---------------------------------------------------------------------- %----------------------------------------------------------------------
\parinterval 因此,非自回归翻译方面的研究大多集中在针对以上问题的求解\upcite{Wei2019ImitationLF,Shao2019RetrievingSI,Akoury2019SyntacticallyST,Guo2020FineTuningBC,Ran2020LearningTR}。有三个角度:使用繁衍率来预测长度、使用句子级知识蒸馏来降低学习难度、使用自回归模型打分来挑选好的翻译。下面将依次对这些方法进行介绍。 \parinterval 因此,非自回归翻译方面的研究大多集中在针对以上问题的求解。有三个角度:使用繁衍率预测译文长度、使用句子级知识蒸馏来降低学习难度、使用自回归模型进行翻译候选打分。下面将依次对这些方法进行介绍。
%---------------------------------------------------------------------------------------- %----------------------------------------------------------------------------------------
% NEW SUBSUB-SECTION % NEW SUBSUB-SECTION
...@@ -468,7 +468,7 @@ b &=& \omega_{\textrm{high}}\cdot |\seq{x}| \label{eq:14-4} ...@@ -468,7 +468,7 @@ b &=& \omega_{\textrm{high}}\cdot |\seq{x}| \label{eq:14-4}
\subsubsection{1. 基于繁衍率的非自回归模型} \subsubsection{1. 基于繁衍率的非自回归模型}
\parinterval\ref{fig:14-14}给出了基于繁衍率的非自回归模型的结构\upcite{Gu2017NonAutoregressiveNM},由以下四个模块组成:编码器,解码器,繁衍率预测器和解码端的位置注意力模块。 \parinterval\ref{fig:14-14}给出了基于繁衍率的Transformer非自回归模型的结构\upcite{Gu2017NonAutoregressiveNM},由以下四个模块组成:编码器,解码器,繁衍率预测器和解码端的位置注意力模块。
%---------------------------------------------------------------------- %----------------------------------------------------------------------
\begin{figure}[htp] \begin{figure}[htp]
...@@ -479,7 +479,7 @@ b &=& \omega_{\textrm{high}}\cdot |\seq{x}| \label{eq:14-4} ...@@ -479,7 +479,7 @@ b &=& \omega_{\textrm{high}}\cdot |\seq{x}| \label{eq:14-4}
\end{figure} \end{figure}
%---------------------------------------------------------------------- %----------------------------------------------------------------------
\parinterval 与自回归翻译模型类似,Transformer模型的编码器和解码器都完全由前馈神经网络和多头注意力模块组成。在非自回归模型在解码开始之前,非自回归模型需要知道目标句子的长度,以便并行生成所有单词。更重要的是,非自回归模型需要一次性生成出所有的目标词,因此不能像自回归模型那样用已生成的词作为第一个解码器层的输入。那么非自回归模型解码器的输入是什么呢?如果完全省略第一个解码器层的输入,或者仅使用位置嵌入,将会导致非常差的性能。这里使用繁衍率来解决这个问题,繁衍率指的是对于每个源语言单词预测所对应的目标语单词的个数(见\chapterthree)。翻译过程取决于繁衍率序列,最终目标句子长度则由所有源语言单词对应的繁衍率之和决定。这个繁衍率序列可以通过外部词对齐工具来得到,从而来训练这个繁衍率预测器。但由于外部词对齐系统的会出现错误,因此在模型收敛之后,需要在繁衍率预测器上加一个强化学习的损失来进行微调。 \parinterval 与自回归翻译模型类似,Transformer模型的编码器和解码器都完全由前馈神经网络和多头注意力模块组成。在非自回归模型在解码开始之前,非自回归模型需要知道目标句子的长度,以便并行生成所有单词。更重要的是,非自回归模型需要一次性生成出所有的目标词,因此不能像自回归模型那样用已生成的词作为第一个解码器层的输入。那么非自回归模型解码器的输入是什么呢?如果完全省略第一个解码器层的输入,或者仅使用位置嵌入,将会导致非常差的性能。这里使用繁衍率来解决这个问题,繁衍率指的是对于每个源语言单词预测所对应的目标语单词的个数(见\chapterthree)。翻译过程取决于繁衍率序列(图\ref{fig:14-14}中的数字1\ 1\ 2\ 0\ 1),最终目标句子长度则由所有源语言单词对应的繁衍率之和决定。这个繁衍率序列可以通过外部词对齐工具来得到,从而来训练这个繁衍率预测器。但由于外部词对齐系统的会出现错误,因此在模型收敛之后,需要在繁衍率预测器上加一个强化学习的损失来进行微调。
\parinterval 另外,在每个解码器层中还包括额外的位置注意力模块,该模块与Transformer模型的其它部分中使用的多头注意力机制相同,如下: \parinterval 另外,在每个解码器层中还包括额外的位置注意力模块,该模块与Transformer模型的其它部分中使用的多头注意力机制相同,如下:
...@@ -488,7 +488,7 @@ b &=& \omega_{\textrm{high}}\cdot |\seq{x}| \label{eq:14-4} ...@@ -488,7 +488,7 @@ b &=& \omega_{\textrm{high}}\cdot |\seq{x}| \label{eq:14-4}
\label{eq:14-10} \label{eq:14-10}
\end{eqnarray} \end{eqnarray}
\noindent 其中$d_k$表示模型的隐层大小,其中位置编码作为$\mathbi{Q}$$\mathbi{K}$,解码端上一层的输出作为$\mathbi{V}$。将位置信息直接结合到注意力过程中,比单独的位置嵌入提供了更强的位置信息,同时该附加信息可能还会提高解码器执行局部重排序的能力。 \noindent 其中$d_k$表示模型的隐层大小,其中位置编码作为$\mathbi{Q}$$\mathbi{K}$,解码端上一层的输出作为$\mathbi{V}$。将位置信息直接结合到注意力过程中,比单独的位置嵌入提供了更强的位置信息,同时该附加信息可能还会提高解码器执行局部重排序的能力。
%---------------------------------------------------------------------------------------- %----------------------------------------------------------------------------------------
% NEW SUBSUB-SECTION % NEW SUBSUB-SECTION
...@@ -496,11 +496,9 @@ b &=& \omega_{\textrm{high}}\cdot |\seq{x}| \label{eq:14-4} ...@@ -496,11 +496,9 @@ b &=& \omega_{\textrm{high}}\cdot |\seq{x}| \label{eq:14-4}
\subsubsection{2. 句子级知识蒸馏} \subsubsection{2. 句子级知识蒸馏}
\parinterval 知识蒸馏的基本思路是让学生模型所表示的函数尽可能去拟合教师模型所表示的函数(\chapterthirteen 中将会有更加详细地介绍)。如果想要训练一个小模型,同时想让它的性能与大模型一样好。这时我们可以把大模型看作传授知识的“教师”,把小模型看作接受知识的“学生”。在训练时,先将输入送给教师模型,让它预测出概率分布,作为小模型的监督信息来计算损失函数,进而完成小模型的训练。 \parinterval 知识蒸馏的基本思路是让学生模型所表示的函数尽可能去拟合教师模型所表示的函数(\chapterthirteen)。如果想要训练一个小模型,同时希望它的性能与大模型一样好,这时可以把大模型看作传授知识的“教师”,把小模型看作接受知识的“学生”。在训练时,先将输入送给教师模型,让它预测出概率分布,作为小模型的监督信息来计算损失函数,进而完成小模型的训练。
\parinterval 类似的,可以让自回归模型作为“教师”,非自回归模型作为“学生”。把自回归神经机器翻译生成的句子作为新的训练样本,送给非自回归机器翻译进行学习\upcite{Gu2017NonAutoregressiveNM,Lee2018DeterministicNN,Zhou2020UnderstandingKD,Guo2020FineTuningBC}。这种方式能够一定程度上解决多峰问题。 \parinterval 类似的,可以让自回归模型作为“教师”,非自回归模型作为“学生”。把自回归神经机器翻译生成的句子作为新的训练样本,送给非自回归机器翻译进行学习\upcite{Gu2017NonAutoregressiveNM,Lee2018DeterministicNN,Zhou2020UnderstandingKD,Guo2020FineTuningBC}。这种方式能够一定程度上解决多峰问题。因为,经过训练的自回归模型会始终将相同的源语言句子翻译成相同的译文。这样的操作得到的数据集噪声更少,能够降低非自回归模型学习的难度。
\parinterval 因为,经过训练的自回归模型会始终将中文“谢谢你”翻译成相同的英文结果,如生成“thanks to you”而不会出现“thanks a lot”的结果。这样的操作得到的数据集噪声更少,能够降低非自回归模型学习的难度。
%---------------------------------------------------------------------------------------- %----------------------------------------------------------------------------------------
% NEW SUBSUB-SECTION % NEW SUBSUB-SECTION
...@@ -508,7 +506,7 @@ b &=& \omega_{\textrm{high}}\cdot |\seq{x}| \label{eq:14-4} ...@@ -508,7 +506,7 @@ b &=& \omega_{\textrm{high}}\cdot |\seq{x}| \label{eq:14-4}
\subsubsection{3.自回归模型打分} \subsubsection{3.自回归模型打分}
\parinterval 通过采样不同的繁衍率序列,可以得到多个不同的翻译候选。之后,把这些不同的译文再交给自回归模型来评分,选择一个最好的结果作为最终的翻译。在这里,可以使用强制解码同时对多个译文进行打分,因此这个过程可以充分并行。通常,这种方法能够很有效的提升非自回归翻译模型的译文质量,并且同时保持较高的推断速度\upcite{Gu2017NonAutoregressiveNM,Wei2019ImitationLF,Guo2019NonAutoregressiveNM,Wang2019NonAutoregressiveMT,Ma2019FlowSeqNC} \parinterval 通过采样不同的繁衍率序列,可以得到多个不同的翻译候选。之后,把这些不同的译文再交给自回归模型来评分,选择一个最好的结果作为最终的翻译。在这里,可以使用强制解码同时对多个译文进行打分,因此这个过程可以充分并行。通常,这种方法能够很有效的提升非自回归翻译模型的译文质量,并且保持较高的推断速度\upcite{Gu2017NonAutoregressiveNM,Wei2019ImitationLF,Guo2019NonAutoregressiveNM,Wang2019NonAutoregressiveMT,Ma2019FlowSeqNC}。但是,缺点是需要同时部署自回归和非自回归两套系统
%---------------------------------------------------------------------------------------- %----------------------------------------------------------------------------------------
% NEW SUBSECTION % NEW SUBSECTION
...@@ -520,11 +518,11 @@ b &=& \omega_{\textrm{high}}\cdot |\seq{x}| \label{eq:14-4} ...@@ -520,11 +518,11 @@ b &=& \omega_{\textrm{high}}\cdot |\seq{x}| \label{eq:14-4}
\begin{itemize} \begin{itemize}
\vspace{0.5em} \vspace{0.5em}
\item 基于层级知识蒸馏的方法\upcite{Li2019HintBasedTF}。由于自回归模型和非自回归模型的结构相差不大,因此可以将翻译质量更高的自回归模型作为“教师”,通过给非自回归模型提供监督信号,使其逐块的学习前者的分布。研究者发现了两点非常有意思的现象:1)非自回归模型输出的重复单词的位置的隐藏状态非常相似。2)非自回归模型的注意力分布比自回归模型的分布更加分散。这两点发现启发了研究者使用自回归模型中的隐层状态来指导非自回归模型学习。通过计算两个模型隐层状态的距离以及注意力矩阵的KL散度\footnote{KL散度即相对熵}作为额外的损失来帮助非自回归模型的训练过程。 \item 基于层级知识蒸馏的方法\upcite{Li2019HintBasedTF}。由于自回归模型和非自回归模型的结构相差不大,因此可以将翻译质量更高的自回归模型作为“教师”,通过给非自回归模型提供监督信号,使其逐块的学习前者的分布。研究人员发现了两点非常有意思的现象:1)非自回归模型输出的重复单词的位置的隐藏状态非常相似。2)非自回归模型的注意力分布比自回归模型的分布更加分散。这两点发现启发了研究人员使用自回归模型中的隐层状态来指导非自回归模型学习。通过计算两个模型隐层状态的距离以及注意力矩阵的KL散度\footnote{KL散度即相对熵}作为额外的损失来帮助非自回归模型的训练过程。
\vspace{0.5em} \vspace{0.5em}
\item 基于模仿学习的方法\upcite{Wei2019ImitationLF}。这种观点认为非自回归模型可以从性能优越的自回归模型中学得知识。模仿学习是强化学习中的一个概念,即从专家那里学习正确的行为,与监督学习很相似\upcite{Ho2016ModelFreeIL,Ho2016GenerativeAI,Duan2017OneShotIL}。与其不同的是,模仿学习不是照搬专家的行为,而是学习专家为什么要那样做。换句话说,学习的不是专家的镜像,而是一个专家的行为分布。这里,可以将自回归模型作为专家,非自回归模型学习不同时间步和不同层的中的解码状态,最后将模仿学习的损失与交叉熵损失加权求和后作为最终的优化目标。 \item 基于模仿学习的方法\upcite{Wei2019ImitationLF}。这种观点认为非自回归模型可以从性能优越的自回归模型中学得知识。{\small\bfnew{模仿学习}}\index{模仿学习}(Imitation Learning\index{Imitation Learning})是强化学习中的一个概念,即从专家那里学习正确的行为,与监督学习很相似\upcite{Ho2016ModelFreeIL,Ho2016GenerativeAI,Duan2017OneShotIL}。与其不同的是,模仿学习不是照搬专家的行为,而是学习专家为什么要那样做。换句话说,学习的不是专家的镜像,而是一个专家的行为分布。这里,可以将自回归模型作为专家,非自回归模型学习不同时间步和不同层的解码状态,最后将模仿学习的损失与交叉熵损失加权求和后作为最终的优化目标。
\vspace{0.5em} \vspace{0.5em}
\item 添加额外的正则化项来显式的约束非自回归模型\upcite{Wang2019NonAutoregressiveMT}。非自回归模型的翻译结果中存在着两种非常严重的错误:重复翻译和不完整的翻译。第一种问题是因为解码器隐层状态中相邻的两个位置过于相似,因此翻译出来的单词也一样。对于第二个问题,通常将其归咎于非自回归模型在翻译的过程中丢失了一些源语句信息,从而造成了翻译效果的下降。针对这两个问题,可以通过在相邻隐层状态间添加相似度约束以及引入对偶学习的思想来计算一个重构损失。具体来说,对于目前正在进行的翻译$\seq{x}\to\seq{y}$,通过利用一个反向的自回归模型再将$\seq{y}$翻译成$\seq{x'}$,最后计算$\seq{x}$$\seq{x'}$的差异性作为损失。 \item 基于正则化因子的方法\upcite{Wang2019NonAutoregressiveMT}。非自回归模型的翻译结果中存在着两种非常严重的错误:重复翻译和不完整的翻译。第一种问题是因为解码器隐层状态中相邻的两个位置过于相似,因此翻译出来的单词也一样。对于第二个问题,通常将其归咎于非自回归模型在翻译的过程中丢失了一些源语句信息,从而造成了翻译效果的下降。针对这两个问题,可以通过在相邻隐层状态间添加相似度约束来计算一个重构损失。具体来说,对于目前正在进行的翻译$\seq{x}\to\seq{y}$,通过利用一个反向的自回归模型再将$\seq{y}$翻译成$\seq{x'}$,最后计算$\seq{x}$$\seq{x'}$的差异性作为损失。
\vspace{0.5em} \vspace{0.5em}
\end{itemize} \end{itemize}
......
Markdown 格式
0%
您添加了 0 到此讨论。请谨慎行事。
请先完成此评论的编辑!
注册 或者 后发表评论