Commit f24a69ad by 单韦乔

合并分支 'shanweiqiao' 到 'caorunzhe'

13章-旧版内容整理

查看合并请求 !64
parents ceda763d f5a807e0
...@@ -27,4 +27,498 @@ ...@@ -27,4 +27,498 @@
% NEW SECTION % NEW SECTION
%---------------------------------------------------------------------------------------- %----------------------------------------------------------------------------------------
\section{} \sectionnewpage
\section{正则化}\label{subsection-13.1}
\parinterval {\small\bfnew{正则化}}\index{正则化}(Regularization)\index{Regularization}是机器学习中的经典技术,通常用于缓解{\small\bfnew{过拟合问题}}\index{过拟合问题}(The Overfitting Problem)\index{Overfitting Problem}。正则化的概念源自线性代数和代数几何。在实践中,它更多的是指对{\small\bfnew{反问题}}\index{反问题}(The Inverse Problem)\index{Inverse Problem}的一种求解方式。假设输入$x$和输出$y$之间存在一种映射$f$
\begin{eqnarray}
y = f(x)
\label{eq:13-1}
\end{eqnarray}
\noindent 反问题是指:当观测到$y$时,能否求出$x$。反问题对应了很多实际问题,比如,可以把$y$看作经过美化的图片,$x$看作原始的图片,反问题就对应了图片还原。机器翻译的训练也是一种反问题,因为可以把$y$看作是正确的译文,$x$看作是输入句子或者模型参数\footnote{在训练中,如果把源语言句子看作是不变的量,这时$f$的输入只有模型参数。}
\parinterval 理想的情况下,我们希望反问题的解是{\small\bfnew{适定的}}\index{适定的}(Well-posed)\index{Well-posed}。所谓适定解,需要满足三个条件:解是存在的、解是唯一的、解是稳定的(即$y$微小的变化会导致$x$微小的变化,也被称作解连续)。所有不存在唯一稳定解的问题都被称作{\small\bfnew{不适定问题}}\index{不适定问题}(Ill-posed Problem)\index{Ill-posed Problem}。对于机器学习问题,解的存在性比较容易理解。解的唯一性大多由问题决定。比如,如果把描述问题的函数$f(\cdot)$看作一个$n\times n$矩阵$\mathbf{A}$$x$$y$都看作是$n$维向量。那么$x$不唯一的原因在于$\mathbf{A}$不满秩(非奇异矩阵)。不过,存在性和唯一性并不会对机器学习方法造成太大困扰,因为在实践中往往会找到近似的解。
\parinterval 但是,解的稳定性却给神经机器翻译带来了很大的挑战。因为神经机器翻译模型非常复杂,里面存在大量的矩阵乘法和非线性变化。这导致$f(\cdot)$往往是不稳定的,也就是说,神经机器翻译中输出$y$ 的微小变化会导致输入$x$的巨大变化。比如,在系统研发中经常会发现,即使训练样本发生很小的变化,模型训练得到的参数都会有非常明显的区别。不仅如此,神经机器翻译模型参数解的稳定性还存在两方面问题:
\begin{itemize}
\vspace{0.5em}
\item 观测数据不充分。由于语言现象的多样性,训练样本只能覆盖非常有限的翻译现象。从样本的表示空间上看,对于没有观测样本的区域,根本无法知道真实解的样子,更不用说稳定性训练了。
\vspace{0.5em}
\item 数据中存在噪声。噪声问题是稳定性训练最大的挑战之一。因为,即使是很小的噪声,也可能会导致解的巨大变化。
\vspace{0.5em}
\end{itemize}
\parinterval 以上问题体现出来的现象就是过拟合。因为训练数据有限同时存在噪声,因此模型参数会过分拟合噪声数据。而且,这样的模型参数又与真实(理想)的模型参数相差很远。正则化正是针对这个问题。有时候,正则化也被称作{\small\bfnew{降噪}}\index{降噪}(Denoising)\index{Denoising},虽然它的出发点并不只是去除噪声的影响。图\ref{fig:13-11}对比了不同函数对二维空间中一些数据点的拟合情况。在过拟合现象中,函数可以完美的拟合所有的数据点,即使有些数据点是噪声。
%----------------------------------------------
\begin{figure}[htp]
\centering
\input{./Chapter13/Figures/figure-underfitting-vs-overfitting}
\caption{欠拟合 vs 过拟合}
\label{fig:13-11}
\end{figure}
%----------------------------------------------
\parinterval 正则化的一种实现是在训练目标中引入一个正则项。在神经机器翻译中,引入正则项的训练目标为:
\begin{eqnarray}
\widehat{\mathbf{w}}=\argmax_{\mathbf{w}}L(\mathbf{w}) + \lambda R(\mathbf{w})
\label{eq:13-2}
\end{eqnarray}
\noindent 其中,$L(\mathbf{w})$是损失函数,$R(\mathbf{w})$是正则项,$\lambda$是正则项的系数,用于控制正则化对训练影响的程度。$R(\mathbf{w})$通常也可以被看作是一种先验,因为在数据不充分且存在噪声的情况下,可以根据一些先验知识让模型偏向正确的方向一些,而不是一味地根据受噪声影响的不准确的$L(\mathbf{w})$进行优化。相应的,引入正则化后的模型可以获得更好的{\small\bfnew{泛化}}\index{泛化}(Generalization)\index{Generalization}能力,即模型在新的未见数据上表现会更好。
\parinterval 实践中已经证明,正则化方法有助于像神经机器翻译这样复杂的模型获得稳定的模型参数。甚至有些情况下,如果不引入正则化,训练得到的翻译模型根本无法使用。
%----------------------------------------------------------------------------------------
% NEW SUB-SECTION
%----------------------------------------------------------------------------------------
\subsection{L1/L2正则化}
\parinterval L1/L2正则化是常用的正则化方法。它们分别对应正则项是L1和L2范数的情况。具体来说,L1正则化是指
\begin{eqnarray}
R(\mathbf{w}) & = & \big| |\mathbf{w}| {\big|}_1 \\
& = &\sum_{w_i}|w_i| \nonumber
\label{eq:13-3}
\end{eqnarray}
\parinterval L2正则化是指
\begin{eqnarray}
R(\mathbf{w}) & = & (\big| |\mathbf{w}| {\big|}_2)^2 \\
& = &\sum_{w_i}{w_i}^2 \nonumber
\label{eq:13-4}
\end{eqnarray}
\parinterval 从几何的角度看,L1和L2正则项都是有物理意义的。二者都可以被看作是空间上的一个区域,比如,在二维平面上,L1范数表示一个以0点为中心的矩形,L2范数表示一个以0点为中心的圆。因此,优化问题可以被看作是在两个区域($L(\mathbf{w})$$R(\mathbf{w})$)叠加在一起所形成的区域上进行优化。由于L1和L2正则项都是在0点(坐标原点)附近形成的区域,因此优化的过程可以确保参数不会偏离0点太多。也就是说,L1和L2正则项引入了一个先验:模型的解不应该离0点太远。而L1和L2正则项实际上是在度量这个距离。
\parinterval 那为什么要用L1和L2正则项惩罚离0点远的解呢?这还要从模型复杂度谈起。实际上,对于神经机器翻译这样的模型来说,模型的容量是足够的。所谓容量可以被简单的理解为独立参数的个数 \footnote{关于模型容量,在\ref{section-13.2}节会有进一步讨论。}。也就是说,理论上存在一种模型可以完美的描述问题。但是,从目标函数拟合的角度来看,如果一个模型可以拟合很复杂的目标函数,那模型所表示的函数形态也会很复杂。这往往体现在模型中参数的值``偏大''。比如,用一个多项式函数拟合一些空间中的点,如果希望拟合得很好,各个项的系数往往是非零的。而且为了对每个点进行拟合,通常需要多项式中的某些项具有较大的系数,以获得函数在局部有较大的斜率。显然,这样的模型是很复杂的。而模型的复杂度可以用函数中的参数(比如多项式中各项的系数)的``值''进行度量,体现出来就是模型参数的范数。
\parinterval 因此,L1和L2正则项的目的是防止模型为了匹配少数(噪声)样本而导致模型的参数过大。反过来说,L1和L2正则项会鼓励那些参数值在0点附近的情况。从实践的角度看,这种方法可以很好的对统计模型的训练进行校正,得到泛化能力更强的模型。
%----------------------------------------------------------------------------------------
% NEW SUB-SECTION
%----------------------------------------------------------------------------------------
\subsection{标签平滑}
\parinterval 神经机器翻译在每个目标语位置$j$会输出一个分布$y_j$,这个分布描述了每个目标语言单词出现的可能性。在训练时,每个目标语言位置上的答案是一个单词,也就对应了One-hot分布$\tilde{y}_j$,它仅仅在正确答案那一维为1,其它维均为0。模型训练可以被看作是一个调整模型参数让$y_j$逼近$\tilde{y}_j$的过程。但是,$\tilde{y}_j$的每一个维度是一个非0即1的目标,这样也就无法考虑类别之间的相关性。具体来说,除非模型在答案那一维输出1,否则都会得到惩罚。即使模型把一部分概率分配给与答案相近的单词(比如同义词),这个相近的单词仍被视为完全错误的预测。
\parinterval {\small\bfnew{标签平滑}}\index{标签平滑}(Label Smoothing)\index{Label Smoothing}的思想很简单\cite{Szegedy_2016_CVPR}:答案所对应的单词不应该``独享''所有的概率,其它单词应该有机会作为答案。这个观点与第二章中语言模型的平滑非常类似。在复杂模型的参数估计中,往往需要给未见或者低频事件分配一些概率,以保证模型具有更好的泛化能力。具体实现时,标签平滑使用了一个额外的分布$q$,它是在词汇表$V$ 上的一个均匀分布,即$q(k)=\frac{1}{|V|}$,其中$q(k)$表示分布的第$k$维。然后,答案分布被重新定义为$\tilde{y}_j$$q$的线性插值:
\begin{eqnarray}
y_{j}^{ls}=(1-\alpha) \cdot \tilde{y}_j + \alpha \cdot q
\label{eq:13-5}
\end{eqnarray}
\noindent 这里$\alpha$表示一个系数,用于控制分布$q$的重要性。$y_{j}^{ls}$会被作为最终的答案分布用于模型的训练。
\parinterval 标签平滑实际上定义了一种``软''标签,使得所有标签都可以分到一些概率。一方面可以缓解数据中噪声的影响,另一方面目标分布会更合理(显然,真实的分布不应该是One-hot分布)。图\ref{fig:13-12}展示了标签平滑前后的损失函数计算结果的对比。
%----------------------------------------------
\begin{figure}[htp]
\centering
\input{./Chapter13/Figures/figure-label-smoothing}
\caption{不使用标签平滑 vs 使用标签平滑}
\label{fig:13-12}
\end{figure}
%----------------------------------------------
\parinterval 标签平滑也可以被看作是对损失函数的一种调整,并引入了额外的先验知识(即与$q$相关的部分)。只不过这种先验知识并不是通过线性插值的方式与原始损失函数进行融合(公式\ref{eq:13-2})。
%----------------------------------------------------------------------------------------
% NEW SUB-SECTION
%----------------------------------------------------------------------------------------
\subsection{Dropout}
\parinterval 神经机器翻译模型是一种典型的多层神经网络模型。每一层网络都包含若干神经元,负责接收前一层所有神经元的输出,并进行诸如乘法、加法等变换,并有选择的使用非线性的激活函数,最终得到当前层每个神经元的输出。从模型最终预测的角度看,每个神经元都在参与最终的预测。理想的情况下,我们希望每个神经元都能相互独立的做出``贡献''。这样的模型会更加健壮,因为即使一部分神经元不能正常工作,其它神经元仍然可以独立做出合理的预测。但是,随着每一层神经元数量的增加以及网络结构的复杂化,研究者发现神经元之间会出现{\small\bfnew{相互适应}}\index{相互适应}(Co-Adaptation)\index{Co-Adaptation}的现象。所谓相互适应是指,一个神经元对输出的贡献与同一层其它神经元的行为是相关的,也就是说这个神经元已经适应到它周围的``环境''中。
\parinterval 相互适应的好处在于神经网络可以处理更加复杂的问题,因为联合使用两个神经元要比单独使用每个神经元的表示能力强。这也类似于传统机器学习任务中往往会设计一些高阶特征,比如自然语言序列标注中对bi-gram和tri-gram的使用。不过另一方面,相互适应会导致模型变得更加``脆弱''。因为相互适应的神经元可以更好的描述训练数据中的现象,但是在测试数据上,由于很多现象是未见的,细微的扰动会导致神经元无法适应。具体体现出来就是过拟合问题。
\parinterval Dropout是解决这个问题的一种常用方法\cite{DBLP:journals/corr/abs-1207-0580}。方法很简单,在训练时随机让一部分神经元停止工作,这样每次参数更新中每个神经元周围的环境都在变化,它就不会过分适应到环境中。图\ref{fig:13-13}中给出了某一次参数训练中使用Dropout之前和之后的状态对比。
%----------------------------------------------
\begin{figure}[htp]
\centering
\input{./Chapter13/Figures/figure-network-with-dropout}
\caption{使用Dropout之前(左)和之后(右)神经网络状态的对比,其中虚线圆圈表示不工作的神经元,实线圆圈表示工作的神经元。}
\label{fig:13-13}
\end{figure}
%----------------------------------------------
\parinterval 具体实现时,可以设置一个参数$p\in (0,1)$。在每次参数更新所使用的前向和反向计算中,每个神经元都以概率$p$停止工作。相当于每层神经网络会有以$p$为比例的神经元被``屏蔽''掉。每一次参数更新中会随机屏蔽不同的神经元。图\ref{fig:13-14}给出了Dropout方法和传统方法计算方式的对比。
%----------------------------------------------
\begin{figure}[htp]
\centering
\input{./Chapter13/Figures/figure-computation-of-dropout}
\caption{使用Dropout之前(左)和之后(右)一层神经网络的计算}
\label{fig:13-14}
\end{figure}
%----------------------------------------------
\parinterval 对于新的样本,可以使用Dropout训练之后的模型对其进行推断,但是每个神经元的输出要乘以$1-p$,以保证每层神经元输出的期望和训练时是一样的。另一种常用的做法是,在训练时对每个神经元的输出乘以$\frac{1}{1-p}$,然后在推断时神经网络可以不经过任何调整就直接使用。
\parinterval Dropout方法的另一种解释是,训练中屏蔽掉一些神经元相当于从原始的神经网络中抽取出了一个子网络。这样,每次训练都在一个随机生成的子网络上进行,而不同子网络之间的参数是共享的。在推断时,则把所有的子网络集成到一起。这种思想也有一些{\small\bfnew{集成学习}}\index{集成学习}(Ensemble Learning)\index{Ensemble Learning}的味道。只不过Dropout中子模型(或子网络)是在指数级空间中采样出来的。由于Dropout可以很好的缓解复杂神经模型的过拟合问题,因此也成为了大多数神经机器翻译系统的标配。
%----------------------------------------------------------------------------------------
% NEW SUB-SECTION
%----------------------------------------------------------------------------------------
\subsection{Layer Dropout}
\parinterval 随时网络层数的增多,相互适应也会出现在不同层之间。特别是在引入残差网络之后,不同层的输出可以进行线性组合,因此不同层之间的相互影响会更加直接。对于这个问题,也可以使用Dropout的思想对不同层进行屏蔽。比如,可以使用一个开关来控制一个层能否发挥作用,这个开关以概率$p$被随机关闭,即该层有为$p$的可能性不工作。图\ref{fig:13-15}展示了Transformer多层网络引入Layer Dropout 前后的情况。可以看到,使用Layer Dropout后,开关M会被随机打开或者关闭,以达到屏蔽某一层计算的目的。由于使用了残差网络,关闭每一层相当于``跳过''这一层网络,因此Layer Dropout并不会影响神经网络中数据流的传递。
%----------------------------------------------
\begin{figure}[htp]
\centering
\input{./Chapter13/Figures/figure-norm}
\caption{标准Transformer网络(a) vs 引入Layer Dropout后的Transformer网络(b)}
\label{fig:13-15}
\end{figure}
%----------------------------------------------
\parinterval Layer Dropout可以被理解为在一个深网络(即原始网络)中随机采样出一个由若干层网络构成的``浅''网络。不同``浅''网络所对应的同一层的模型参数是共享的。这也达到了对指数级子网络高效训练的目的。需要注意的是,在推断阶段,每层的输出需要乘以$1-p$,确保训练时每层输出的期望和解码是一致的。Layer Dropout可以非常有效的缓解深层网路中的过拟合问题。在\ref{subsection-13.1}节还会看到Layer Dropout可以成功地帮助我们训练Deep Transformer模型。
%----------------------------------------------------------------------------------------
% NEW SECTION
%----------------------------------------------------------------------------------------
\sectionnewpage
\section{增大模型容量}\label{section-13.2}
\parinterval 神经机器翻译是一种典型的多层神经网络。一方面,可以通过设计合适的网络连接方式和激活函数来捕捉复杂的翻译现象;另一方面,越来越多的可用数据让模型能够得到更有效的训练。在训练数据较为充分的情况下,设计更加``复杂''的模型成为了提升系统性能的有效手段。比如,Transformer模型有两个常用配置Transformer-Base和Transformer-Big。其中,Transformer-Big比Transformer-Base使用了更多的神经元,相应的翻译品质更优\cite{NIPS2017_7181}
\parinterval 那么是否还有类似的方法可以改善系统性能呢?答案显然是肯定的。这里,把这类方法统称为基于大容量模型的方法。在传统机器学习的观点中,神经网络的性能不仅依赖于架构设计,同样与容量密切相关。那么什么是模型的{\small\bfnew{容量}}\index{容量}(Capacity)\index{Capacity}?简单理解,容量是指神经网络的参数量,即神经元之间连接权重的个数。另一种定义是把容量看作神经网络所能表示的假设空间大小\cite{DBLP:journals/nature/LeCunBH15},也就是神经网络能表示的不同函数所构成的空间。
\parinterval 而学习一个神经网络就是要找到一个``最优''的函数,它可以准确地拟合数据。当假设空间变大时,训练系统有机会找到更好的函数,但是同时也需要依赖更多的训练样本才能完成最优函数的搜索。相反,当假设空间变小时,训练系统会更容易完成函数搜索,但是很多优质的函数可能都没有被包含在假设空间里。这也体现了一种简单的辩证思想:如果训练(搜索)的代价高,会有更大的机会找到更好的解;另一方面,如果想少花力气进行训练(搜索),那就设计一个小一些的假设空间,在小一些规模的样本集上进行训练,当然搜索到的解可能不是最好的。
\parinterval 在很多机器翻译任务中,训练数据是相对充分的。这时增加模型容量是提升性能的一种很好的选择。常见的方法有三种:
\begin{itemize}
\vspace{0.5em}
\item 增加隐藏层维度:即增加网络宽度,加强每一层网络的线性拟合能力。
\vspace{0.5em}
\item 增加网络的整体层数:即增加网络深度,利用更多的线性和非线性变换来获得更复杂的特征抽取能力。
\vspace{0.5em}
\item 增大输入层和输出层的维度:即增强模型对词表中每个词的表示能力。
\end{itemize}
%----------------------------------------------------------------------------------------
% NEW SUB-SECTION
%----------------------------------------------------------------------------------------
\subsection{宽网络}
\parinterval 宽网络通常指隐藏层维度更大的网络,目前在图像处理领域和自然语言处理领域被广泛地使用。第五章已经验证了包含足够多神经元的多层前馈神经网络可以无限逼近任意复杂的连续函数\cite{Hornic1989Multilayer},这也在一定程度上说明了神经网络建模中神经元数目的重要性。
\parinterval 增大隐藏层神经元的数目是网络变宽的基本方式之一。例如,图像处理领域中提出的{\small\bfnew{宽残差网络}}\index{宽残差网络}(Wide Residual Network)\index{Wide Residual Network}使用更大的卷积核来提高每次卷积计算的精度\cite{DBLP:conf/bmvc/ZagoruykoK16};神经机器翻译中,Transformer-Big模型广受研究人员的认可\cite{NIPS2017_7181},它同样是一个典型的宽网络。对比基线模型Transformer-Base,Transformer-Big通过扩大隐藏层维度与滤波器(Filter)维度,取得了显著的翻译性能提升。表\ref{tab:13-2}是相应的参数设置。
%----------------------------------------------
\begin{table}[htp]
\centering
\caption{基线网络与宽网络的参数设置}
\begin{tabular}{ l | l l}
& Transformer-Base &Transformer-Big \\ \hline
\rule{0pt}{13pt} 词向量维度 & 512 &1024 \\
\rule{0pt}{13pt} 注意力头数 &8 &16 \\
\rule{0pt}{13pt} 隐藏层维度 &512 &1024 \\
\rule{0pt}{13pt} FFN子层映射维度 &2048 &4096
\end{tabular}
\label{tab:13-2}
\end{table}
%--------------------------------------
\parinterval 值得注意的是, Transformer模型中的前馈神经网络子层将隐藏层表示映射到更高维度的空间(通过一个Filter),之后经过激活函数Relu后再映射回原来的维度大小。这个操作对翻译模型的性能有明显的正向作用。从表\ref{tab:13-2}中可以看出,Filter的维度是普通隐藏层维度的四倍。通过增大Filter大小可以有效地扩展网络的宽度,比如,有些情况下可以将Filter增大到8192甚至更大。
\parinterval 但伴随着模型变宽,网络的整体参数量会显著增长\footnote{在一个全连接神经网络中,参数的数量与各层宽度呈平方关系。}。同时,宽网络需要更长的训练时间才能达到稳定的收敛状态。此外,训练宽网络时通常需要对一些超参数进行相应的调整,例如Dropout的大小,学习率的峰值等。
%----------------------------------------------------------------------------------------
% NEW SUB-SECTION
%----------------------------------------------------------------------------------------
\subsection{深网络}
\parinterval 虽然,理论上宽网络有能力拟合任意的函数,但是获得这种能力的代价是非常高的。在实践中,往往需要增加相当的宽度,以极大的训练代价才能换来少量的性能提升。当神经网络达到一定宽度后这种现象更为严重。``无限''增加宽度显然是不现实的。
\parinterval 因此,另一种思路是使用更深的网络以增加模型的容量。深网络是指包含更多层的神经网络。相比宽网络的参数量随着宽度呈平方增长,深网络的参数量随着深度呈线性增长。这带给深网络一个优点:在同样参数量下可以通过更多的非线性变换来对问题进行描述。这也赋予了深网络对复杂问题建模的能力。比如,在图像识别领域,很多先进的系统都是基于很深的神经网络,甚至在一些任务上最好的的结果需要1000 层以上的神经网络。
\parinterval 宽网络和深网络是增加模型表示能力的两个维度。宽网络相当于增强了模型线性变换的能力,将模型的输入在更高维度的空间上进行抽象;深网络通过引入更多的层构建了多个表示空间,通过逐层的变换,在多个表示空间上对输入进行多次抽象。二者在有些情况下甚至可以相互转换。
\parinterval 除了数学上的解释,深度神经网络也可以给分析、理解现实世界的问题提供有效的手段。很多时候,可以把一个多层神经网络看作是对一个复杂问题的拆解,每层(或每几层)是在处理一个子问题。例如,在人脸识别任务中,一个3层的神经网络中第一层主要提取低层次的简单特征,即边缘特征;第二层将简单的特征组合成更为复杂的特征,如器官特征;第三层针对第二层的输出进行进一步的抽象得到人脸的面部特征。这样,深网络通过不同层的逐层特征抽象可以在人脸识别数据集上超越人类的精度\cite{DBLP:journals/corr/HeZRS15}
\parinterval 类似的现象也出现在基于语言模型的预训练任务中。比如,研究人员通过使用{\small\bfnew{探测任务}}\index{探测任务}(Probing Task)\index{Probing Task}来分析12层的BERT模型中的不同层所表示的含义\cite{ethayarajh-2019-contextual,DBLP:conf/acl/JawaharSS19}
\begin{itemize}
\vspace{0.5em}
\item 浅层网络表示:网络的底层部分更擅长处理词串的{\small\bfnew{表面信息}}\index{表面信息}(Surface Information)\index{Surface Information},例如词性选择、词义消歧等。
\vspace{0.5em}
\item 中间层的表示:中间层部分更关注于{\small\bfnew{语法信息}}\index{语法信息}(Syntactic Information)\index{Syntactic Information}
\vspace{0.5em}
\item 顶层网络的表示:上层部分更擅长处理{\small\bfnew{语义信息}}\index{语义信息}(Semantic Information)\index{Semantic Information}
\vspace{0.5em}
\end{itemize}
\parinterval 目前在神经机器翻译领域,研究人员发现编码端的表示能力对翻译性能有较大的影响,因此加深编码网络是一种有效的改进系统的手段(如图\ref{fig:13-16} )。而且,增加编码端的深度对模型推断的速度并没有较大影响,因为整个序列可以通过GPU进行并行计算。
%----------------------------------------------
\begin{figure}[htp]
\centering
\input{./Chapter13/Figures/figure-increase-the-encoder}
\caption{增大神经机器翻译的编码端来增大模型的容量}
\label{fig:13-16}
\end{figure}
%----------------------------------------------
\parinterval 不过,深网络容易发生梯度消失和梯度爆炸问题。因此在使用深网络时,训练策略的选择是至关重要的。实际上,标准的Transformer模型已经是不太``浅''的神经网络,因此里面使用了残差连接来缓解梯度消失等问题。此外,为了避免过拟合,深层网络的训练也要与Dropout等正则化策略相配合,并且需要设计恰当的参数初始化方法和学习率调整策略。关于构建深层神经机器翻译的方法,本章\ref{subsection-7.5.1}节还会有进一步讨论。
%----------------------------------------------------------------------------------------
% NEW SUB-SECTION
%----------------------------------------------------------------------------------------
\subsection{增大输入层和输出层表示能力}
\parinterval 如前所述,神经机器翻译的原始输入是单词序列,包括源语言端和目标语言端。模型中的输入层将这种离散的单词表示转换成实数向量的表示,也就是常说的{\small\bfnew{词嵌入}}\index{词嵌入}(Embedding)\index{Embedding}。从实现的角度来看,输入层其实就是从一个词嵌入矩阵中提取对应的词向量表示,这个矩阵两个维度大小分别对应着词表大小和词嵌入的维度。词嵌入的维度也代表着模型对单词刻画的能力。因此适当增加词嵌入的维度也是一种增加模型容量的手段。通常,词嵌入和隐藏层的维度是一致的,这种设计也是为了便于系统实现。
\parinterval 当然,并不是说词嵌入的维度一定越大就越好。本质上,词嵌入是要在一个多维空间上有效的区分含有不同语义的单词。如果词表较大,更大的词嵌入维度会更有意义,因为需要更多的``特征''描述更多的语义。当词表较小时,增大词嵌入维度可能不会带来增益,相反会增加系统计算的负担。另一种策略是,动态选择词嵌入维度,比如,对于高频词使用较大的词嵌入维度,而对于低频词则使用较小的词嵌入维度\cite{DBLP:conf/iclr/BaevskiA19}。这种方法可以用同样的参数量处理更大的词表。
%----------------------------------------------------------------------------------------
% NEW SUB-SECTION
%----------------------------------------------------------------------------------------
\subsection{大模型的分布式计算}
\parinterval 伴随着模型容量的增大,复杂模型可能无法在单GPU上完成训练。比如,即使是不太复杂的Transformer-Base模型在很多任务上也需要在8张GPU进行训练。如何利用多个设备进行大模型的并行训练是一个很现实的问题。比较简单的策略是使用{\small\bfnew{数据并行}}\index{数据并行}(Data Parallelism)\index{Data Parallelism},即把一个批次分到多个GPU上进行训练,之后对多个GPU上的梯度进行汇总,并更新参数。不过,当模型规模增大到一定程度时,单GPU可能仍然无法处理。这个问题在GPU显存较小的时候会非常突出。这时需要考虑{\small\bfnew{模型并行}}\index{模型并行}(Model Parallelism)\index{Model Parallelism}。模型并行是指将模型分割成不同的部分,在不同的GPU上运行其中的一部分。例如,在训练深层LSTM模型时可以将不同层放置在不同GPU上,这种方式一定程度上能够加速模型的训练。对于更大的模型,如参数量为10亿的BERT-Large模型\cite{DBLP:conf/naacl/DevlinCLT19},同样可以使用这种策略。不过,模型并行中不同设备传输的延时会大大降低模型运行的效率,因此很多时候要考虑训练效率和模型性能之间的平衡。
%----------------------------------------------------------------------------------------
% NEW SUB-SECTION
%----------------------------------------------------------------------------------------
\subsection{大批量训练}
\parinterval 在第六章已经介绍了神经机器翻译模型需要使用梯度下降方法进行训练。其中,一项非常重要的技术就是{\small\bfnew{小批量训练}}\index{小批量训练}(Mini-batch Training)\index{Mini-batch Training},即每次使用多个样本来获取梯度并对模型参数进行更新。这里将每次参数更新使用的多个样本集合称为批次,将样本的数量称作批次的大小。在机器翻译中,通常用批次中的源语言/目标语言单词数或者句子数来表示批次大小。理论上,过小的批次会带来训练的不稳定,而且参数更新次数会大大增加。因此,很多研究者尝试增加批次大小来提高训练的稳定性。在Transformer模型中,使用更大的批次已经被验证是有效的。这种方法也被称作大批量训练。不过,这里所谓`` 大''批量是一个相对的概念。下面就一起看一看如何使用合适的批次大小来训练神经机器翻译模型。
%----------------------------------------------------------------------------------------
% NEW SUBSUB-SECTION
%----------------------------------------------------------------------------------------
\subsubsection{为什么需要大批量训练}
\parinterval 在模型训练的过程中,训练批次的大小对模型的收敛状态有很大影响,合理选择批次的大小往往会取得事半功倍的效果。较大的批次可以保证模型每次更新时梯度是在较多的样本上计算,其梯度结果更准确,有效地缓解训练中出现的性能震荡的问题。此外,较大的批次可以让模型在更新次数更少的情况下遍历整个数据集。同时大矩阵运算在GPU上的并行度更高,提高了设备的利用率。
\parinterval 然而,批次也不是越大越好,要根据训练数据集的规模与模型的容量做出合理的选择。此外,GPU显存的大小也对批次大小有约束,因为过大的批次可能无法放入GPU显存中。另一方面,在一些场景例中,如增量式训练、领域迁移,往往需要对模型进行微调。这时,常用的做法是使用小批次并固定较小的学习率,防止现有的模型参数发生较大的偏离。
\parinterval 大多数情况下,批次的大小是指单独一块GPU上的数据量,然而考虑到利用数据并行进行分布式训练时,批次大小等于所有GPU 中批次大小的和。下面以Transformer模型为例。通常Transformer-Base模型使用4096词/GPU的批次在8张GPU上进行训练,此时真实批次大小为$4096\times 8=32768$词。伴随着模型容量的进一步增加,例如Transformer-Big模型,由于训练过程中网络的中间表示要消耗大量的GPU显存,可能会考虑减小批次的大小并使用累计梯度的方式来保证稳定的训练。累计梯度是一种大批量训练的常用手段,即按照一定频率缓存多个相邻批次的梯度后再进行参数的更新。比如,为了获取大批次,可以考虑将累计的更新频率设置为2或4。图\ref{fig:13-17}给出了累计梯度的参数更新方法,可以看到使用累积梯度的方式可以减少设备的空闲时间。
%----------------------------------------------
\begin{figure}[htp]
\centering
\input{./Chapter13/Figures/figure-batch-generation-method}
\caption{生成批次的方式}
\label{fig:13-17}
\end{figure}
%----------------------------------------------
\parinterval 此外,前人工作表明,使用大批量训练复杂网络结构时要配合略大一些的学习率,加快模型在梯度方向上的更新速度,进而达到更优的翻译性能\cite{DBLP:conf/wmt/OttEGA18}。例如,深层网络也需要对学习率进行适当的调整才能发挥较好的性能。表\ref{tab:13-3}展示了30层网络在不同批次大小和学习率峰值的条件下的BLEU值(WMT14 En-De)\footnote{学习率峰值是指Transformer模型训练的预热阶段,学习率所到达的最高值。}。可以发现,在固定学习率峰值的条件下增大批次大小并不能带来性能上的增益,必须同时调整学习率的峰值。也有研究团队验证了Transformer-Big模型在128张GPU上进行分布式训练时,适当的增大学习率会带来明显的BLEU提升\cite{DBLP:conf/wmt/OttEGA18}\\ \\ \\
%----------------------------------------------
\begin{table}[htp]
\centering
\caption{深层Transformer不同批次大学和学习率峰值设置下的BLEU值}
\begin{tabular}{ l | l l }
\rule{0pt}{13pt} batch & lr & BLEU \\ \hline
\rule{0pt}{13pt} 4096 & 0.01 & 29.15 \\
\rule{0pt}{13pt} 8192 & 0.01 & 29.06 \\
\rule{0pt}{13pt} 8192 & 0.02 & 29.49
\end{tabular}
\label{tab:13-3}
\end{table}
%--------------------------------------
%----------------------------------------------------------------------------------------
% NEW SUBSUB-SECTION
%----------------------------------------------------------------------------------------
\subsubsection{如何构建批次}
\parinterval 由于不同句子之间的长度有明显的差异,这时批次所占用的显存/内存大小由其中最长句子的长度决定。通常使用{\small\bfnew{填充}}(Padding)的方式对一个批次中句长不足的部分用空白填充(见第六章)。但由于生成批次的方式不同,最终批次内的Padding数量各不相同,因此合理选择生成批次的方式也是至关重要的。通常有几种方法:
\begin{itemize}
\vspace{0.5em}
\item 随机生成:最简单的方式是从整个数据集中随机生成批次。这种方式可以有效地保证样本间的随机性,但随机生成的批次中不同句子之间的长度会有较大区别,因此Padding数量较多会导致显卡的利用率较低。
\vspace{0.5em}
\item 按句长排序:为了减少显卡利用率低的问题,可以根据源语言或者目标语言的句子长度进行排序,让相邻句长的样本更为相近(图\ref{fig:13-18} )。这样在同一个批次中不会因为句长差异过大造成设备利用率的降低。
%----------------------------------------------
\begin{figure}[htp]
\centering
\input{./Chapter13/Figures/figure-randomly-generation-vs-generate-by-sentence-length}
\caption{批次生成 - 随机生成 vs 按句长生成}
\label{fig:13-18}
\end{figure}
%----------------------------------------------
\vspace{0.5em}
\item 按词数构建批次:对比按照句长生成批次,按词数生成批次可以防止某些批次中句子整体长度特别长或者特别短的情况,保证不同批次之间整体的词数处于大致相同的范围,这样所得到的梯度也是可比较的。通常的做法是根据源语言词数、目标语言词数,或者源语言词数与目标语言词数的最大值等指标生成批次。
\vspace{0.5em}
\item 按课程学习的方式:考虑样本的``难度''也是生成批次的一种策略。比如,可以使用{\small\bfnew{课程学习}}\index{课程学习}(Curriculum Learning)\index{Curriculum Learning} 的思想\cite{DBLP:conf/icml/BengioLCW09},让系统先学习``简单''的样本,之后逐渐增加样本的难度,达到循序渐进的学习。具体来说,可以利用句子长度、词频等指标计算每个批次的``难度'',记为$d$。 之后,选择满足$d \leq c$的样本构建一个批次。这里,$c$表示难度的阈值,它可以随着训练的执行不断增大。
\vspace{0.5em}
\end{itemize}
%----------------------------------------------------------------------------------------
% NEW SECTION
%----------------------------------------------------------------------------------------
\sectionnewpage
\section{对抗样本训练}
%----------------------------------------------------------------------------------------
% NEW SECTION
%----------------------------------------------------------------------------------------
\sectionnewpage
\section{最小风险训练}
%----------------------------------------------------------------------------------------
% NEW SUB-SECTION
%----------------------------------------------------------------------------------------
\subsection{增强学习方法}
%----------------------------------------------------------------------------------------
% NEW SUB-SECTION
%----------------------------------------------------------------------------------------
\subsection{曝光偏置问题}
%----------------------------------------------------------------------------------------
% NEW SECTION
%----------------------------------------------------------------------------------------
\sectionnewpage
\subsection{知识精炼}\label{subsection-7.5.3}
\parinterval 理想的机器翻译系统应该是品质好、速度块、存储占用少。不过现实的机器翻译系统往往需要用运行速度和存储空间来换取翻译品质,比如,\ref{subsection-7.3.2}节提到的增大模型容量的方法就是通过增加模型参数量来达到更好的函数拟合效果,但是这也导致系统变得更加笨拙。在很多场景下,这样的模型甚至无法使用。比如,Transformer-Big等``大''模型通常在专用GPU服务器上运行,在手机等受限环境下仍很难应用。
\parinterval 另一方面,直接训练``小''模型的效果往往并不理想,其翻译品质与``大''模型相比仍有比较明显的差距。比如,在Transformer中,使用一个48层的编码器要比传统的6层编码器在BLEU上高出1-2个点,而且两者翻译结果的人工评价的区别也十分明显。
\parinterval 面对小模型难以训练的问题,一种有趣的想法是把``大''模型的知识传递给``小''模型,让``小''模型可以更好的进行学习。这类似于,教小孩子学习数学,是请一个权威数学家(数据中的标准答案),还是请一个小学数学教师(``大''模型)。这就是知识精炼的基本思想。
%----------------------------------------------------------------------------------------
% NEW SUB-SECTION
%----------------------------------------------------------------------------------------
\subsection{什么是知识精炼}
\parinterval 通常,知识精炼可以被看作是一种知识迁移的手段\cite{Hinton2015Distilling}。如果把``大''模型的知识迁移到``小''模型,这种方法的直接结果就是{\small\bfnew{模型压缩}}\index{模型压缩}(Model Compression)\index{Model Compression}。当然,理论上也可以把``小''模型的知识迁移到``大''模型,比如,将迁移后得到的``大''模型作为初始状态,之后继续训练该模型,以期望取得加速收敛的效果。不过,在实践中更多是使用``大''模型到``小''模型的迁移,这也是本节讨论的重点。
\parinterval 知识精炼基于两个假设:
\begin{itemize}
\vspace{0.5em}
\item ``知识''在模型间是可迁移的。也就是说,一个模型中蕴含的规律可以被另一个模型使用。最典型的例子就是预训练模型(见\ref{subsection-7.2.6})。使用单语数据学习到的表示模型,在双语的翻译任务中仍然可以发挥很好的作用。也就是,把单语语言模型学习到的知识迁移到双语翻译中对句子表示的任务中;
\vspace{0.5em}
\item 模型所蕴含的``知识''比原始数据中的``知识''更容易被学习到。比如,机器翻译中大量使用的回译(伪数据)方法,就把模型的输出作为数据让系统进行学习。
\vspace{0.5em}
\end{itemize}
\parinterval 这里所说的第二个假设对应了机器学习中的一大类问题\ \dash \ {\small\bfnew{学习难度}}\index{学习难度}(Learning Difficulty)\index{Learning Difficulty}。所谓难度是指:在给定一个模型的情况下,需要花费多少代价对目标任务进行学习。如果目标任务很简单,同时模型与任务很匹配,那学习难度就会降低。如果目标任务很复杂,同时模型与其匹配程度很低,那学习难度就会很大。在自然语言处理任务中,这个问题的一种表现是:在很好的数据中学习的模型的翻译质量可能仍然很差。即使训练数据是完美的,但是模型仍然无法做到完美的学习。这可能是因为建模的不合理,导致模型无法描述目标任务中复杂的规律。也就是纵然数据很好,但是模型学不到其中的``知识''。在机器翻译中这个问题体现的尤为明显。比如,在机器翻译系统$n$-best结果中挑选最好的译文(成为Oracle)作为训练样本让系统重新学习,系统仍然达不到Oracle的水平。
\parinterval 知识精炼本身也体现了一种``自学习''的思想。即利用模型(自己)的预测来教模型(自己)。这样既保证了知识可以向更轻量的模型迁移,同时也避免了模型从原始数据中学习难度大的问题。虽然``大''模型的预测中也会有错误,但是这种预测是更符合建模的假设的,因此``小''模型反倒更容易从不完美的信息中学习\footnote[15]{很多时候,``大''模型和``小''模型都是基于同一种架构,因此二者对问题的假设和模型结构都是相似的。}到更多的知识。类似于,刚开始学习围棋的人从职业九段身上可能什么也学不到,但是向一个业余初段的选手学习可能更容易入门。另外,也有研究表明:在机器翻译中,相比于``小''模型,``大''模型更容易进行优化,也更容易找到更好的模型收敛状态。因此在需要一个性能优越,存储较小的模型时,也会考虑将大模型压缩得到更轻量模型的手段\cite{DBLP:journals/corr/abs-2002-11794}
\parinterval 通常把``大''模型看作的传授知识的``教师'',被称作{\small\bfnew{教师模型}}\index{教师模型}(Teacher Model)\index{Teacher Model};把``小''模型看作是接收知识的``学生'',被称作{\small\bfnew{学生模型}}\index{学生模型}(Student Model)\index{Student Model}。比如,可以把Transformer-Big看作是教师模型,把Transformer-Base看作是学生模型。
%----------------------------------------------------------------------------------------
% NEW SUB-SECTION
%----------------------------------------------------------------------------------------
\subsection{知识精炼的基本方法}
\parinterval 知识精炼的基本思路是让学生模型所表示的函数尽可能去拟合教师模型所表示的函数\cite{Hinton2015Distilling}。通常有两种实现方式\cite{DBLP:conf/emnlp/KimR16}
\begin{itemize}
\vspace{0.5em}
\item {\small\bfnew{基于单词的知识精炼}}\index{基于单词的知识精炼}(Word-level Knowledge Distillation)\index{Word-level Knowledge Distillation}。该方法的目标是使得学生模型的预测(分布)尽可能逼近教师模型的预测(分布)。令$\mathbf{x}=\{x_1,\ldots,x_m\}$$\mathbf{y}=\{y_1,\ldots,y_n\}$分别表示输入和输出(数据中的答案)序列,$V$表示目标语言词表,$n$表示译文序列的长度,则基于单词的知识精炼的损失函数被定义为:
\begin{eqnarray}
L_{\textrm{word}} = - \sum_{j=1}^n \sum_{y_j \in V} \textrm{P}_{\textrm{t}} (y_{\textrm{j}}|\mathbf{x})\textrm{logP}_{\textrm{s}}(y_j|\mathbf{x})
\label{eq:13-28}
\end{eqnarray}
这里, $\textrm{P}_{\textrm{s}}(y_j|\mathbf{x})$$\textrm{P}_{\textrm{t}} (y_i|\mathbf{x})$分别表示学生模型和教师模型在$j$位置的输出的概率。公式\ref{eq:13-28}实际上在最小化教师模型和学生模型输出分布之间的交叉熵。
\vspace{0.5em}
\item {\small\bfnew{基于序列的知识精炼}}\index{基于序列的知识精炼}(Sequence-level Knowledge Distillation)\index{Sequence-level Knowledge Distillation}。除了单词一级的拟合,基于序列的知识精炼希望在序列整体上进行拟合。其损失函数被定义为:
\begin{eqnarray}
L_{\textrm{seq}} = - \sum_{\textrm{y}}\textrm{P}_{\textrm{t}} (\mathbf{y}|\mathbf{x})\textrm{logP}_{\textrm{s}}(\mathbf{y}|\mathbf{x})
\label{eq:13-29}
\end{eqnarray}
公式\ref{eq:13-29}要求遍历所有可能的译文序列,并进行求和,当词表大小为$V$,序列长度为$L$时,则可能的序列的数量有$V$$L$次幂,这么多的译文将消耗大量的计算资源。因此,会考虑用教师模型的真实输出序列$\hat{\mathbf{y}}$来代替整个空间,即假设$\textrm{P}_{\textrm{t}}(\hat{\mathbf{y}}|\mathbf{x})=1$。于是,目标函数变为:
\begin{eqnarray}
L_{\textrm{seq}} = - \textrm{logP}_{\textrm{s}}(\hat{\mathbf{y}} | \mathbf{x})
\label{eq:13-30}
\end{eqnarray}
这样的损失函数带来最直接的好处是,知识精炼的流程会非常简单。因为只需要利用教师模型将训练数据(源语言)翻译一遍,之后把它的输出替换为训练数据的目标语言部分。之后,利用得到的新的双语数据训练学生模型即可,图\ref{fig:13-41}展示了简化后词级和序列级的不同,其中词级知识精炼的解码端输入为真实双语数据的目标语言,并以teacher模型输出的概率分布作为学习目标,而序列级则直接将teacher推断后得到的结果作为解码端的输入,并将解码结果的One-hot向量作为学习目标。
\vspace{0.5em}
\end{itemize}
%----------------------------------------------
\begin{figure}[htp]
\centering
\input{./Chapter13/Figures/figure-difference-between-word-level-and-sequence-level-in-knowledge-distillation}
\caption{词级和序列级知识精炼的差异}
\label{fig:13-41}
\end{figure}
%-------------------------------------------
\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}
%----------------------------------------------------------------------------------------
% NEW SUB-SECTION
%----------------------------------------------------------------------------------------
\subsection{机器翻译中的知识精炼}
\parinterval 在神经机器翻译中,通常使用公式\ref{eq:13-30}的方法进行知识精炼,即通过教师模型构造伪数据,之后让学生模型从伪数据中学习。这样做的好处在于,系统研发人员不需要对系统进行任何修改,整个过程只需要调用教师模型和学生模型标准的训练和推断模块即可。
\parinterval 另一个问题是如何构造教师模型和学生模型。以Transformer为例,通常有两种思路:
\begin{itemize}
\vspace{0.5em}
\item 固定教师模型,通过减少模型容量的方式设计学生模型。比如,可以使用容量较大的模型作为教师模型(如:Transformer-Big或Transformer-Deep),然后通过将神经网络变``窄''、变``浅''的方式得到学生模型。我们可以用Transformer-Big做教师模型,然后把Transformer-Big的解码器变为一层网络,作为学生模型。
\vspace{0.5em}
\item 固定学生模型,通过模型集成的方式设计教师模型。可以组合多个模型生成更高质量的译文(见\ref{subsection-7.4.3}节)。比如,融合多个Transformer-Big模型(不同参数初始化方式),之后学习一个Transformer-Base模型。
\vspace{0.5em}
\end{itemize}
\parinterval 此外还可以采用迭代的知识精炼的方式。首先,通过模型集成得到较强的教师模型,再将知识迁移到不同的学生模型上,随后继续使用这些学生模型集成新的教师模型。不断的重复上述过程可以逐步提升集成模型的性能,如图\ref{fig:13-42}所示。值得注意的是,随着迭代次数的增加,集成所带来的收益也会随着子模型之间差异性的减小而减少。
%----------------------------------------------
\begin{figure}[htp]
\centering
\input{./Chapter13/Figures/figure-ensemble-knowledge-distillation}
\caption{迭代式知识精炼}
\label{fig:13-42}
\end{figure}
%-------------------------------------------
\parinterval 如果倾向于使用更少的存储,更快的推理速度,则可以使用更小的学生模型。值得注意的是,对于Transformer模型来说,减少解码端的层数会给推理速度带来巨大的提升。特别是对于基于深层编码器的Transformer-Deep,适当减少解码端层数往往不会带来翻译品质的下降。可以根据不同任务的需求,选择适当大小的学生模型,来平衡存储、推断速度和模型品质之间的关系。
%----------------------------------------------------------------------------------------
% NEW SECTION
%----------------------------------------------------------------------------------------
\sectionnewpage
\section{可解释性}
%----------------------------------------------------------------------------------------
% NEW SECTION
%----------------------------------------------------------------------------------------
\sectionnewpage
\section{小结及深入阅读}
Markdown 格式
0%
您添加了 0 到此讨论。请谨慎行事。
请先完成此评论的编辑!
注册 或者 后发表评论