Skip to content
项目
群组
代码片段
帮助
当前项目
正在载入...
登录 / 注册
切换导航面板
T
Toy-MT-Introduction
概览
Overview
Details
Activity
Cycle Analytics
版本库
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
问题
0
Issues
0
列表
Board
标记
里程碑
合并请求
0
Merge Requests
0
CI / CD
CI / CD
流水线
作业
日程表
图表
维基
Wiki
代码片段
Snippets
成员
Collapse sidebar
Close sidebar
活动
图像
聊天
创建新问题
作业
提交
Issue Boards
Open sidebar
NiuTrans
Toy-MT-Introduction
Commits
87a8c036
Commit
87a8c036
authored
May 10, 2020
by
曹润柘
Browse files
Options
Browse Files
Download
Plain Diff
合并分支 'caorunzhe' 到 'master'
Caorunzhe 查看合并请求
!126
parents
2b47026c
133c045f
显示空白字符变更
内嵌
并排
正在显示
4 个修改的文件
包含
82 行增加
和
82 行删除
+82
-82
Book/Chapter7/Chapter7.tex
+25
-25
Book/Chapter7/Figures/figure-batch-generation-method.tex
+37
-36
Book/Chapter7/Figures/figure-randomly-generation-vs-generate-by-sentence-length.tex
+20
-19
Book/Chapter7/Figures/figure-word-change.tex
+0
-2
没有找到文件。
Book/Chapter7/Chapter7.tex
查看文件 @
87a8c036
...
...
@@ -114,7 +114,7 @@
\sectionnewpage
\section
{
数据处理
}
\parinterval
同统计机器翻译一样,神经机器翻译也需要对输入和输
入
的句子进行分词,目的是得到翻译的最基本单元。但是,这里所说的单词并不是语言学上的单词,更多的是指面向机器翻译任务的最小翻译片段。比如,可以复用第二章中的自动分词系统对句子进行切分,之后在切分得到的``词''序列上完成翻译建模。
\parinterval
同统计机器翻译一样,神经机器翻译也需要对输入和输
出
的句子进行分词,目的是得到翻译的最基本单元。但是,这里所说的单词并不是语言学上的单词,更多的是指面向机器翻译任务的最小翻译片段。比如,可以复用第二章中的自动分词系统对句子进行切分,之后在切分得到的``词''序列上完成翻译建模。
\parinterval
自然语言的表达非常丰富,因此需要很多的单词才能表达不同的语义。但是,神经机器翻译系统对大词表的处理效率很低,比如,输出层在大规模词表上进行预测会有明显的速度下降,甚至无法进行计算。因此,在神经机器翻译中会使用受限的词表,比如包含30000-50000个单词的词表。另一方面,翻译新的句子时,受限词表会带来大量的
{
\small\bfnew
{
未登录词
}}
\index
{
未登录词
}
(Out of Vocabulary Word,OOV Word)
\index
{
Out of Vocabulary Word,OOV Word
}
,系统无法对其进行翻译。实际上,产生未登录词的原因一方面是由于词表大小受限,另一方面的原因在于分词的颗粒度过大。对于后者,一种方法是进一步对``单词''进行切分,以得到更小的单元,这样可以大大缓解单词颗粒度过大造成的数据稀疏问题。这个过程通常被称作
{
\small\bfnew
{
子词切分
}}
\index
{
子词切分
}
(Sub-word Segmentation)
\index
{
Sub-word Segmentation
}
。比如,以BPE为代表的子词切分方法已经成为了当今神经机器翻译所使用的标准方法,翻译效果显著超越基于传统分词的系统。
...
...
@@ -208,7 +208,7 @@
\vspace
{
0.5em
}
\end{itemize}
\parinterval
数据选择认为所有样本都是有用的,只是作用大小不同。因此,如果可以更充分的利用对机器翻译帮助更大的那部分数据,系统性能应该可以得到提升
\cite
{
wang-etal-2018-dynamic
}
比如,很多比赛系统中会使用测试数据与训练数据(源语言部分)进行匹配,选择一部与测试集更相关的数据,之后用这部分数据微调系统
\cite
{
DBLP:conf/wmt/LiLXLLLWZXWFCLL19,wang-etal-2018-tencent
}
;也可以对不同训练数据的集合进行加权,之后进行权重敏感的训练,以期望权重大的数据对模型产生更大的影响
\cite
{
wang-etal-2018-dynamic
}
。
\parinterval
数据选择认为所有样本都是有用的,只是作用大小不同。因此,如果可以更充分的利用对机器翻译帮助更大的那部分数据,系统性能应该可以得到提升
\cite
{
wang-etal-2018-dynamic
}
比如,很多比赛系统中会使用测试数据与训练数据(源语言部分)进行匹配,选择一部
分
与测试集更相关的数据,之后用这部分数据微调系统
\cite
{
DBLP:conf/wmt/LiLXLLLWZXWFCLL19,wang-etal-2018-tencent
}
;也可以对不同训练数据的集合进行加权,之后进行权重敏感的训练,以期望权重大的数据对模型产生更大的影响
\cite
{
wang-etal-2018-dynamic
}
。
\parinterval
数据过滤则认为数据中存在不太多的噪声,可以通过去除这种噪声提高数据整体的质量,进而提升训练效果。有很多方法,比如:过滤掉非对齐的样本、翻译质量极低的样本、重复样本等等。图
\ref
{
fig:7-6
}
展示了数据过滤的实例。通常数据过滤需要很多工程手段的综合运用,因此也非常考验系统研发团队对系统打磨的能力。
...
...
@@ -262,7 +262,7 @@
\subsection
{
子词切分
}
\parinterval
人类表达语言的方式是十分多样的,这也体现在单词的构成上
。
甚至我们都无法想象数据中存在的不同单词的数量。比如,如果使用简单的分词策略,WMT、CCMT等评测数据的英文词表大小都会在100万以上。当然,这里面也包括很多的数字和字母的混合,还有一些组合词。不过,如果不加限制,机器翻译所面对的词表确实很``大''。这也会导致系统速度变慢,模型变大。更严重的问题是,测试数据中的一些单词根本就没有在训练数据中出现过,这时会出现OOV翻译问题,即系统无法对未见单词进行翻译。在神经机器翻译中,通常会考虑使用更小的翻译单元来缓解以上问题。
\parinterval
人类表达语言的方式是十分多样的,这也体现在单词的构成上
,
甚至我们都无法想象数据中存在的不同单词的数量。比如,如果使用简单的分词策略,WMT、CCMT等评测数据的英文词表大小都会在100万以上。当然,这里面也包括很多的数字和字母的混合,还有一些组合词。不过,如果不加限制,机器翻译所面对的词表确实很``大''。这也会导致系统速度变慢,模型变大。更严重的问题是,测试数据中的一些单词根本就没有在训练数据中出现过,这时会出现OOV翻译问题,即系统无法对未见单词进行翻译。在神经机器翻译中,通常会考虑使用更小的翻译单元来缓解以上问题。
%----------------------------------------------------------------------------------------
% NEW SUBSUB-SECTION
...
...
@@ -367,7 +367,7 @@
\item
若出现``ab'',其后必出现``cd'',但是``cd''却可以作为独立的子词出现,则将``abcd''加入词表,去除``ab'',反之亦然,词表数目不变。
\end{itemize}
\parinterval
在得到了子词词表后,便需要对单词进行切分。BPE要求从较长的子词开始替换。首先,对子词词表按照字符长度从大到小进行排序。然后,对于每个单词,遍历子词词表,判断每个子词是不是当前词的子串,若是则进行替换切分。将单词中所有的子串替换为子词后,如果仍有子串
仍
未被替换,则将其用<UNK>代替,如图
\ref
{
fig:7-10
}
。
\parinterval
在得到了子词词表后,便需要对单词进行切分。BPE要求从较长的子词开始替换。首先,对子词词表按照字符长度从大到小进行排序。然后,对于每个单词,遍历子词词表,判断每个子词是不是当前词的子串,若是则进行替换切分。将单词中所有的子串替换为子词后,如果仍有子串未被替换,则将其用<UNK>代替,如图
\ref
{
fig:7-10
}
。
%----------------------------------------------
\begin{figure}
[htp]
...
...
@@ -420,7 +420,7 @@ y = f(x)
\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
$
的巨大变化。比如,在系统研发中经常会发现,即使训练样本发生很小的变化,模型训练得到的参数会有非常明显的区别。不仅如此,神经机器翻译模型参数解的稳定性还存在两方面问题:
\parinterval
但是,解的稳定性却给神经机器翻译带来了很大的挑战。因为神经机器翻译模型非常复杂,里面存在大量的矩阵乘法和非线性变化。这导致
$
f
(
\cdot
)
$
往往是不稳定的,也就是说,神经机器翻译中输出
$
y
$
的微小变化会导致输入
$
x
$
的巨大变化。比如,在系统研发中经常会发现,即使训练样本发生很小的变化,模型训练得到的参数
也
会有非常明显的区别。不仅如此,神经机器翻译模型参数解的稳定性还存在两方面问题:
\begin{itemize}
\vspace
{
0.5em
}
...
...
@@ -471,7 +471,7 @@ R(\mathbf{w}) & = & (\big| |\mathbf{w}| {\big|}_2)^2 \\
\label
{
eq:7-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正则项都是有物理意义的。二者都可以被看作是空间上的一个区域,比如,在二维平面上,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
{
subsection-7.3.2
}
节会有进一步讨论。
}
。也就是说,理论上存在一种模型可以完美的描述问题。但是,从目标函数拟合的角度来看,如果一个模型可以拟合很复杂的目标函数,那模型所表示的函数形态也会很复杂。这往往体现在模型中参数的值``偏大''。比如,用一个多项式函数拟合一些空间中的点,如果希望拟合得很好,各个项的系数往往是非零的。而且为了对每个点进行拟合,通常需要多项式中的某些项具有较大的系数,以获得函数在局部有较大的斜率。显然,这样的模型是很复杂的。而模型的复杂度可以用函数中的参数(比如多项式中各项的系数)的``值''进行度量,体现出来就是模型参数的范数。
...
...
@@ -504,7 +504,7 @@ y_{j}^{ls}=(1-\alpha) \cdot \tilde{y}_j + \alpha \cdot q
\end{figure}
%----------------------------------------------
\parinterval
标签平滑也可以被看作是对损失函数的一种调整,并引入了额外的先验知识(即与
$
q
$
相关的部分)。只不过这种先验知识并不是通过线性插值的方式与原始损失函数
融合的
(公式
\ref
{
eq:7-2
}
)。
\parinterval
标签平滑也可以被看作是对损失函数的一种调整,并引入了额外的先验知识(即与
$
q
$
相关的部分)。只不过这种先验知识并不是通过线性插值的方式与原始损失函数
进行融合
(公式
\ref
{
eq:7-2
}
)。
%----------------------------------------------------------------------------------------
% NEW SUBSUB-SECTION
...
...
@@ -548,7 +548,7 @@ y_{j}^{ls}=(1-\alpha) \cdot \tilde{y}_j + \alpha \cdot q
\subsubsection
{
Layer Dropout
}
\parinterval
随时网络层数的增多,相互适应也会出现在不同层之间。特别是在引入残差网络之后,不同层的输出可以进行线性组合,因此不同层之间的相互影响
用
会更加直接。对于这个问题,也可以使用Dropout的思想对不同层进行屏蔽。比如,可以使用一个开关来控制一个层能否发挥作用,这个开关以概率
$
p
$
被随机关闭,即该层有为
$
p
$
的可能性不工作。图
\ref
{
fig:7-15
}
展示了Transformer多层网络引入Layer Dropout 前后的情况。可以看到,使用Layer Dropout后,开关M会被随机打开或者关闭,以达到屏蔽某一层计算的目的。由于使用了残差网络,关闭每一层相当于``跳过''这一层网络,因此Layer Dropout并不会影响神经网络中数据流的传递。
\parinterval
随时网络层数的增多,相互适应也会出现在不同层之间。特别是在引入残差网络之后,不同层的输出可以进行线性组合,因此不同层之间的相互影响会更加直接。对于这个问题,也可以使用Dropout的思想对不同层进行屏蔽。比如,可以使用一个开关来控制一个层能否发挥作用,这个开关以概率
$
p
$
被随机关闭,即该层有为
$
p
$
的可能性不工作。图
\ref
{
fig:7-15
}
展示了Transformer多层网络引入Layer Dropout 前后的情况。可以看到,使用Layer Dropout后,开关M会被随机打开或者关闭,以达到屏蔽某一层计算的目的。由于使用了残差网络,关闭每一层相当于``跳过''这一层网络,因此Layer Dropout并不会影响神经网络中数据流的传递。
%----------------------------------------------
\begin{figure}
[htp]
...
...
@@ -611,7 +611,7 @@ y_{j}^{ls}=(1-\alpha) \cdot \tilde{y}_j + \alpha \cdot q
\end{table}
%--------------------------------------
\parinterval
值得注意的是, Transformer模型中的前馈神经网络子层
中
将隐藏层表示映射到更高维度的空间(通过一个Filter),之后经过激活函数Relu后再映射回原来的维度大小。这个操作对翻译模型的性能有明显的正向作用。从表
\ref
{
tab:7-2
}
中可以看出,Filter的维度是普通隐藏层维度的四倍。通过增大Filter大小可以有效地扩展网络的宽度,比如,有些情况下可以将Filter增大到8192甚至更大。
\parinterval
值得注意的是, Transformer模型中的前馈神经网络子层将隐藏层表示映射到更高维度的空间(通过一个Filter),之后经过激活函数Relu后再映射回原来的维度大小。这个操作对翻译模型的性能有明显的正向作用。从表
\ref
{
tab:7-2
}
中可以看出,Filter的维度是普通隐藏层维度的四倍。通过增大Filter大小可以有效地扩展网络的宽度,比如,有些情况下可以将Filter增大到8192甚至更大。
\parinterval
但伴随着模型变宽,网络的整体参数量会显著增长
\footnote
{
在一个全连接神经网络中,参数的数量与各层宽度呈平方关系。
}
。同时,宽网络需要更长的训练时间才能达到稳定的收敛状态。此外,训练宽网络时通常需要对一些超参数进行相应的调整,例如Dropout的大小,学习率的峰值等。
...
...
@@ -641,7 +641,7 @@ y_{j}^{ls}=(1-\alpha) \cdot \tilde{y}_j + \alpha \cdot q
\vspace
{
0.5em
}
\end{itemize}
\parinterval
目前在神经机器翻译领域,研究人员发现编码端的表示能力对翻译性能有较大的影响,因此
通过
加深编码网络是一种有效的改进系统的手段(如图
\ref
{
fig:7-16
}
)。而且,增加编码端的深度对模型推断的速度并没有较大影响,因为整个序列可以通过GPU进行并行计算。
\parinterval
目前在神经机器翻译领域,研究人员发现编码端的表示能力对翻译性能有较大的影响,因此加深编码网络是一种有效的改进系统的手段(如图
\ref
{
fig:7-16
}
)。而且,增加编码端的深度对模型推断的速度并没有较大影响,因为整个序列可以通过GPU进行并行计算。
%----------------------------------------------
\begin{figure}
[htp]
...
...
@@ -660,7 +660,7 @@ y_{j}^{ls}=(1-\alpha) \cdot \tilde{y}_j + \alpha \cdot q
\subsubsection
{
增大输入层和输出层表示能力
}
\parinterval
如前所述,神经机器翻译的原始输入是单词序列,包括源语言端和目标语言端。模型中的输入层将这种离散的单词表示
表示
转换成实数向量的表示,也就是常说的
{
\small\bfnew
{
词嵌入
}}
\index
{
词嵌入
}
(Embedding)
\index
{
Embedding
}
。从实现的角度来看,输入层其实就是从一个词嵌入矩阵中提取对应的词向量表示,这个矩阵两个维度大小分别对应着词表大小和词嵌入的维度。词嵌入的维度也代表着模型对单词刻画的能力。因此适当增加词嵌入的维度也是一种增加模型容量的手段。通常,词嵌入和隐藏层的维度是一致的,这种设计也是为了便于系统实现。
\parinterval
如前所述,神经机器翻译的原始输入是单词序列,包括源语言端和目标语言端。模型中的输入层将这种离散的单词表示转换成实数向量的表示,也就是常说的
{
\small\bfnew
{
词嵌入
}}
\index
{
词嵌入
}
(Embedding)
\index
{
Embedding
}
。从实现的角度来看,输入层其实就是从一个词嵌入矩阵中提取对应的词向量表示,这个矩阵两个维度大小分别对应着词表大小和词嵌入的维度。词嵌入的维度也代表着模型对单词刻画的能力。因此适当增加词嵌入的维度也是一种增加模型容量的手段。通常,词嵌入和隐藏层的维度是一致的,这种设计也是为了便于系统实现。
\parinterval
当然,并不是说词嵌入的维度一定越大就越好。本质上,词嵌入是要在一个多维空间上有效的区分含有不同语义的单词。如果词表较大,更大的词嵌入维度会更有意义,因为需要更多的``特征''描述更多的语义。当词表较小时,增大词嵌入维度可能不会带来增益,相反会增加系统计算的负担。另一种策略是,动态选择词嵌入维度,比如,对于高频词使用较大的词嵌入维度,而对于低频词则使用较小的词嵌入维度
\cite
{
DBLP:conf/iclr/BaevskiA19
}
。这种方法可以用同样的参数量处理更大的词表。
...
...
@@ -701,7 +701,7 @@ y_{j}^{ls}=(1-\alpha) \cdot \tilde{y}_j + \alpha \cdot q
\end{figure}
%----------------------------------------------
\parinterval
此外,前人工作表明,使用大批量训练复杂网络结构时要配合略大一些的学习率,加快模型在梯度方向上的更新速度,进而达到更优的翻译性能
\cite
{
DBLP:conf/wmt/OttEGA18
}
。例如,深层网络也需要对学习率进行适当的调整才能发挥较好的性能。表
\ref
{
tab:7-3
}
展示了30层网络在不同批次大小和学习率峰值的条件下的BLEU值(WMT14 En-De)
\footnote
{
学习率峰值是指Transformer模型训练的预热阶段,学习率所到达的最高值。
}
。可以发现,在固定学习率峰值的条件下增大批次大小并不能带来性能上的增益,必须同时调整条学习率的峰值。也有研究团队验证了,Transformer-Big模型在128张GPU上进行分布式训练时,适当的增大学习率会带来明显
性
的BLEU提升
\cite
{
DBLP:conf/wmt/OttEGA18
}
。
\parinterval
此外,前人工作表明,使用大批量训练复杂网络结构时要配合略大一些的学习率,加快模型在梯度方向上的更新速度,进而达到更优的翻译性能
\cite
{
DBLP:conf/wmt/OttEGA18
}
。例如,深层网络也需要对学习率进行适当的调整才能发挥较好的性能。表
\ref
{
tab:7-3
}
展示了30层网络在不同批次大小和学习率峰值的条件下的BLEU值(WMT14 En-De)
\footnote
{
学习率峰值是指Transformer模型训练的预热阶段,学习率所到达的最高值。
}
。可以发现,在固定学习率峰值的条件下增大批次大小并不能带来性能上的增益,必须同时调整条学习率的峰值。也有研究团队验证了,Transformer-Big模型在128张GPU上进行分布式训练时,适当的增大学习率会带来明显的BLEU提升
\cite
{
DBLP:conf/wmt/OttEGA18
}
。
%----------------------------------------------
\begin{table}
[htp]
...
...
@@ -727,7 +727,7 @@ y_{j}^{ls}=(1-\alpha) \cdot \tilde{y}_j + \alpha \cdot q
\begin{itemize}
\vspace
{
0.5em
}
\item
随机生成:最简单的方式是从整个数据集中随机生成批次。这种方式可以有效地保证样本间的随机性,但随机生成的批次中不同句子之间的长度会有
很
较大区别,因此Padding数量较多,导致显卡的利用率较低。
\item
随机生成:最简单的方式是从整个数据集中随机生成批次。这种方式可以有效地保证样本间的随机性,但随机生成的批次中不同句子之间的长度会有较大区别,因此Padding数量较多,导致显卡的利用率较低。
\vspace
{
0.5em
}
\item
按句长排序:为了减少显卡利用率低的问题,可以根据源语言或者目标语言的句子长度进行排序,让相邻句长的样本更为相近(图
\ref
{
fig:7-18
}
)。这样在同一个批次中不会因为句长差异过大造成设备利用率的降低。
...
...
@@ -855,7 +855,7 @@ y_{j}^{ls}=(1-\alpha) \cdot \tilde{y}_j + \alpha \cdot q
\parinterval
很多时候,我们需要在翻译速度和翻译精度之间进行平衡。即使是以提升翻译品质为目标的任务(如用BLEU评价),也不得不考虑翻译速度的影响。比如,在WMT和CCMT的一些任务中可能会使用反向翻译构造伪数据,需要大量的机器翻译;无指导机器翻译中也会频繁的使用神经机器翻译系统构造训练数据。如果翻译速度过慢会增大实验的周期。从应用的角度看,在很多场景下翻译速度甚至比品质更重要。比如,在线翻译和一些小设备上的机器翻译系统都需要保证相对低的翻译延时,以满足用户体验的最基本要求。虽然,我们希望能有一套又好又快的翻译系统,但是现实的情况是:往往需要通过牺牲一些翻译品质来换取速度的提升。
\parinterval
下面就列举一些常用的神经机器翻译加速方法。这些方法通常是应用在解码器端,因为相比编码器,神经机器翻译的解码
器
是推断过程中最耗时的部分。
\parinterval
下面就列举一些常用的神经机器翻译加速方法。这些方法通常是应用在解码器端,因为相比编码器,神经机器翻译的解码
端
是推断过程中最耗时的部分。
\vspace
{
0.5em
}
\noindent
{
\small\bfnew
{
a) 输出层的词汇选择
}}
...
...
@@ -920,13 +920,13 @@ y_{j}^{ls}=(1-\alpha) \cdot \tilde{y}_j + \alpha \cdot q
\noindent
{
\small\bfnew
{
d) 批量推断
}}
\vspace
{
0.5em
}
\parinterval
深度学习时代下,使用GPU(图形处理单元)已经
是成为的绝大多数神经网络模型研究的基本要求。特别是对于像
机器翻译这样的复杂任务, GPU的并行运算能力会带来明显的速度提升。为了充分利用GPU的并行能力,可以同时对多个句子进行翻译,即
{
\small\bfnew
{
批量推断
}}
\index
{
批量推断
}
(Batch Inference)
\index
{
Batch Inference
}
。
\parinterval
深度学习时代下,使用GPU(图形处理单元)已经
成为绝大多数神经网络模型研究的基本要求。特别是对于
机器翻译这样的复杂任务, GPU的并行运算能力会带来明显的速度提升。为了充分利用GPU的并行能力,可以同时对多个句子进行翻译,即
{
\small\bfnew
{
批量推断
}}
\index
{
批量推断
}
(Batch Inference)
\index
{
Batch Inference
}
。
\parinterval
在第六章已经介绍了神经机器翻译中
{
\small\bfnew
{
批量处理
}}
\index
{
批量处理
}
(Batching)
\index
{
Batching
}
的基本概念。其实现并不困难,不过有两方面问题需要注意:
\begin{itemize}
\vspace
{
0.5em
}
\item
批次生成策略。对于源语言文本预先给定的情况,通常是按句子长度组织每个批次,即:把长度相似的句
法
放到一个批次里。这样做的好处是可以尽可能保证一个批次中的内容是``满''的,否则如果句长差异过大会造成批次中有很多位置用占位符填充,产生无用计算。对于实时翻译的情况,批次的组织较为复杂。由于有翻译延时的限制,可能无法等到有足够多的句子就要进行翻译。常见的做法是,设置一个等待的时间,在同一个时间段中的句子可以放到一个批次中(或者几个批次中)。对于高并发的情况,也可以考虑使用不同的Bucket保存不同长度范围的句子,之后将同一个Bucket中的句子进行批量推断。
\item
批次生成策略。对于源语言文本预先给定的情况,通常是按句子长度组织每个批次,即:把长度相似的句
子
放到一个批次里。这样做的好处是可以尽可能保证一个批次中的内容是``满''的,否则如果句长差异过大会造成批次中有很多位置用占位符填充,产生无用计算。对于实时翻译的情况,批次的组织较为复杂。由于有翻译延时的限制,可能无法等到有足够多的句子就要进行翻译。常见的做法是,设置一个等待的时间,在同一个时间段中的句子可以放到一个批次中(或者几个批次中)。对于高并发的情况,也可以考虑使用不同的Bucket保存不同长度范围的句子,之后将同一个Bucket中的句子进行批量推断。
\vspace
{
0.5em
}
\item
批次大小的选择。一个批次中的句子数量越多,GPU设备的利用率越高,系统吞吐越大。但是,一个批次中所有句子翻译结束后才能拿到翻译结果,因此批次中有些句子即使已经翻译结束也要等待其它没有完成的句子。也就是说,从单个句子来看,批次越大翻译的延时越长,这也导致在翻译实时性要求较高的场景中,不能使用过大的批次。而且,大批次对GPU显存的消耗更大。因此合理选择批次大小也需要根据具体任务进行调整。为了说明这些问题,图
\ref
{
fig:7-23
}
展示了不同批次大小下的吞吐、延时和显存消耗。
\vspace
{
0.5em
}
...
...
@@ -1025,7 +1025,7 @@ y_{j}^{ls}=(1-\alpha) \cdot \tilde{y}_j + \alpha \cdot q
\vspace
{
0.5em
}
\item
机器同声传译。同声传译是机器翻译的一个重要的应用场景。由于同传对实时性的要求,机器翻译的速度是影响整个系统的关键要素。此外,为了保证更好的用户体验,往往需要在讲话者没说完前就开始翻译,也就是根据一句话的前缀进行翻译,当得到后面的内容后再对翻译进行调整。这些都对机器翻译提出了新的要求
\cite
{
DBLP:journals/corr/abs-1810-08398
}
。
\vspace
{
0.5em
}
\item
小设备上的机器翻译。在手机或者专用翻译设备上的机器翻译对速度也有很高的要求,同时需要考虑设备存储的限制。尤其
是
,CPU上的推断加速是这类场景中需要关注的。
\item
小设备上的机器翻译。在手机或者专用翻译设备上的机器翻译对速度也有很高的要求,同时需要考虑设备存储的限制。尤其,CPU上的推断加速是这类场景中需要关注的。
\vspace
{
0.5em
}
\end{itemize}
...
...
@@ -1105,7 +1105,7 @@ b &=& \omega_{\textrm{high}}\cdot |\mathbf{x}|
\vspace
{
0.5em
}
\item
机器翻译自动评价指标对过翻译和欠翻译并不敏感。众所周知,在机器翻译系统开发和调试过程中,使用较多的是BLEU等自动评价指标。但是,过翻译和欠翻译在BLEU这样的指标中是没有明确体现的
\footnote
{
BLEU中也有准确率和长度惩罚因子,但是并没有考虑源语言句子和译文之间的对应关系,因此无法捕捉过翻译和欠翻译。
}
。一个典型的例子是实词漏翻。在人翻译一个句子的时候,如果漏掉一个实词会带来很差甚至不正确的翻译结果,但是在BLEU等指标中可能只是影响几个
$
n
$
-gram的匹配。特别是,极大似然训练会使模型对过翻译和欠翻译``更加''不敏感,因为目标函数对这两个问题没有显性的考虑。
\vspace
{
0.5em
}
\item
神经机器翻译没有对过翻译和欠翻译建模。在统计机器翻译中,由于
有
覆盖度模型会保证所有单词都可以被翻译,且只被翻译一次,因此过翻译和欠翻译等问题很少出现。这也对应了翻译
{
\small\bfnew
{
充分性
}}
\index
{
充分性
}
(Adequacy)
\index
{
Adequacy
}
的问题,也就是机器翻译结果能否准确、完整的表达源文的意思。而在神经机器翻译中这个问题没有明确的模型与之对应。
\item
神经机器翻译没有对过翻译和欠翻译建模。在统计机器翻译中,由于覆盖度模型会保证所有单词都可以被翻译,且只被翻译一次,因此过翻译和欠翻译等问题很少出现。这也对应了翻译
{
\small\bfnew
{
充分性
}}
\index
{
充分性
}
(Adequacy)
\index
{
Adequacy
}
的问题,也就是机器翻译结果能否准确、完整的表达源文的意思。而在神经机器翻译中这个问题没有明确的模型与之对应。
\vspace
{
0.5em
}
\end{itemize}
...
...
@@ -1478,7 +1478,7 @@ x_{l+1}=M \cdot \mathcal{F}(\textrm{LN}(x_l))+x_l
\end{eqnarray}
$
M
=
0
$
代表该子层被丢弃,而
$
M
=
1
$
代表正常进行当前子层的计算。图ref
{
fig:7-34
}
展示了这个方法与标准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
\leqslant
p
_
l
\\
...
...
@@ -1572,7 +1572,7 @@ p_l=\frac{l}{2L}\cdot \varphi
\parinterval
编码器-解码器框架天然就包含了对输入(源语言)和输出(目标语言)进行表示学习的过程。比如,在编码端需要学习一种分布式表示(Distributed Representation)来表示源语言句子的信息,这种分布式表示既包含单词的表示也包括整个序列的表示。因此,可以使用更大规模的源语言单语数据完成编码器的训练。
\parinterval
实现上述想法的一种手段是
{
\small\bfnew
{
预训练
}}
\index
{
预训练
}
(Pre-training)
\index
{
Pre-training
}
。常用的方法是将机器翻译模型中的一部分(比如,编码器)单独提抽取出来,之后用语言建模等方式在大规模单语数据上进行训练。得到
的
优化后的参数后,将其重新放入神经机器翻译模型中,作为模型的初始值。最后,神经机器翻译模型在双语数据上进行
{
\small\bfnew
{
微调
}}
\index
{
微调
}
(Fine-tuning)
\index
{
Fine-tuning
}
,以得到最终的翻译模型。图
\ref
{
fig:7-37
}
给出了机器翻译编码器预训练流程的示意图。
\parinterval
实现上述想法的一种手段是
{
\small\bfnew
{
预训练
}}
\index
{
预训练
}
(Pre-training)
\index
{
Pre-training
}
。常用的方法是将机器翻译模型中的一部分(比如,编码器)单独提抽取出来,之后用语言建模等方式在大规模单语数据上进行训练。得到优化后的参数后,将其重新放入神经机器翻译模型中,作为模型的初始值。最后,神经机器翻译模型在双语数据上进行
{
\small\bfnew
{
微调
}}
\index
{
微调
}
(Fine-tuning)
\index
{
Fine-tuning
}
,以得到最终的翻译模型。图
\ref
{
fig:7-37
}
给出了机器翻译编码器预训练流程的示意图。
%----------------------------------------------
\begin{figure}
[htp]
...
...
@@ -1583,13 +1583,13 @@ p_l=\frac{l}{2L}\cdot \varphi
\end{figure}
%-------------------------------------------
\parinterval
预训练的做法相当于对目标任务进行了简化,将表示模型的学习任务从目标任务中分离出来了。这样,可以学习一种更加通用的模型,具有更好的泛化能力。此外,预训练的任务相比于机器翻译要简单许多,比如语言模型或者句子调序等。将预训练任务的结果作为机器翻译模型的初始值可以减轻目标任务上的学习负担。在第六章中已经介绍了几种基于预训练
方法
,如ELMO、GPT和BERT等。这些模型的结构和神经机器翻译是兼容的,比如,BERT使用的就是Transformer模型。因此可以直接使用这些模型进行面向机器翻译的预训练。
\parinterval
预训练的做法相当于对目标任务进行了简化,将表示模型的学习任务从目标任务中分离出来了。这样,可以学习一种更加通用的模型,具有更好的泛化能力。此外,预训练的任务相比于机器翻译要简单许多,比如语言模型或者句子调序等。将预训练任务的结果作为机器翻译模型的初始值可以减轻目标任务上的学习负担。在第六章中已经介绍了几种基于预训练
的模型
,如ELMO、GPT和BERT等。这些模型的结构和神经机器翻译是兼容的,比如,BERT使用的就是Transformer模型。因此可以直接使用这些模型进行面向机器翻译的预训练。
\noindent
{
\small\bfnew
{
词嵌入预训练
}}
\parinterval
词嵌入可以被看作是对每个独立单词进行的表示学习,在自然语言处理的众多任务中都扮演着重要角色
\cite
{
DBLP:journals/corr/abs-1901-09069
}
。因此,可以使用第五章介绍的词嵌入方法,在外部单语数据上训练得到词嵌入,并把它作为神经机器翻译系统的词嵌入输入。
\parinterval
需要注意的是,在神经机器翻译中使用预训练的词嵌入有两种方法。一种方法是直接将词嵌入作为固定的输入,也就是在训练机器翻译模型的过程中,并不调整词嵌入的参数。这样做的目的是完全将词嵌入模块独立出来,机器翻译可以被看作是在固定的词嵌入输入上进行的建模。另一种方法是仍然遵循``预训练+微调''的策略,将词嵌入作为翻译模型的初始值。之后在机器翻译训练过程中,词嵌入模型结果会被进一步更新。近些年,在词嵌入预训练的基础上进行微调的方法受到研究者
更
多的青睐。
\parinterval
需要注意的是,在神经机器翻译中使用预训练的词嵌入有两种方法。一种方法是直接将词嵌入作为固定的输入,也就是在训练机器翻译模型的过程中,并不调整词嵌入的参数。这样做的目的是完全将词嵌入模块独立出来,机器翻译可以被看作是在固定的词嵌入输入上进行的建模。另一种方法是仍然遵循``预训练+微调''的策略,将词嵌入作为翻译模型的初始值。之后在机器翻译训练过程中,词嵌入模型结果会被进一步更新。近些年,在词嵌入预训练的基础上进行微调的方法受到研究者
越来越
多的青睐。
\noindent
{
\small\bfnew
{
编码器预训练
}}
...
...
@@ -1618,7 +1618,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:7-39
}
)。在训练过程中,分别将双语数据和单语数据送入翻译模型和语言模型进行计算,得到的损失相加用于整体模型参数的梯度计算和参数更新,其中语言模型的参数是翻译模型的一部分。
\parinterval
语言模型是使用目标端单语数据最直接的方式,但是翻译模型作为一个受限的语言模型,还需要依赖于源语,并不能直接进行多任务学习。针对这个问题,对原有翻译模型结构进行了修改,在解码器中增加了一个语言模型子层,将这个子层用于语言模型任务(图
\ref
{
fig:7-39
}
)。在训练过程中,分别将双语数据和单语数据送入翻译模型和语言模型进行计算,得到的损失相加用于整体模型参数的梯度计算和参数更新,其中语言模型的参数是翻译模型的一部分。
%----------------------------------------------
\begin{figure}
[htp]
...
...
@@ -1855,11 +1855,11 @@ L_{\textrm{seq}} = - \textrm{logP}_{\textrm{s}}(\hat{\textbf{y}} | \textbf{x})
\vspace
{
0.5em
}
\item
多语言翻译。神经机器翻译模型经过训练,通常可以将一种固定的源语言翻译成另一种固定的目标语言,但考虑到世界上有成千上万种语言,为每种语言对训练一个单独的模型非常耗资源。相比于单一语言对的神经机器翻译,多语言神经机器翻译具有开发跨语言对相似性的潜力,而且可以节约大量的训练成本
\cite
{
DBLP:journals/tacl/JohnsonSLKWCTVW17
}
。
\parinterval
多语言神经机器翻译旨在训练涵盖多种语言翻译的单一模型。多语言神经机器翻译系统可以根据它们在不同翻译语言对之间共享的组件进行分类。一种常见的做法是通过语言标签指定源语言
合
目标语言的同时,共享整个神经网络结构(编码器和解码器)
\cite
{
DBLP:journals/corr/HaNW16,DBLP:journals/corr/abs-1711-07893
}
。除此之外,还可以使用共享的编码器,但针对每种目标语言使用单独的解码器进行一对多的多语言翻译
\cite
{
DBLP:conf/naacl/FiratCB16
}
。还有一些方法为每种源语言和目标语言都使用单独的编码器和解码器,但会共享其中的一些组件
\cite
{
DBLP:journals/corr/LuongLSVK15,DBLP:conf/naacl/FiratCB16
}
,比如说,共享其中的注意力机制结构
\cite
{
DBLP:journals/corr/LuongLSVK15,DBLP:conf/naacl/FiratCB16
}
多语言神经机器翻译不仅可以减少训练单一语言对神经机器翻译的训练代价,还可以有效的解决低资源神经机器翻译
\cite
{
DBLP:journals/tacl/JohnsonSLKWCTVW17
}
以及多源神经机器翻译问题
\cite
{
Och01statisticalmulti-source
}
。
\parinterval
多语言神经机器翻译旨在训练涵盖多种语言翻译的单一模型。多语言神经机器翻译系统可以根据它们在不同翻译语言对之间共享的组件进行分类。一种常见的做法是通过语言标签指定源语言
和
目标语言的同时,共享整个神经网络结构(编码器和解码器)
\cite
{
DBLP:journals/corr/HaNW16,DBLP:journals/corr/abs-1711-07893
}
。除此之外,还可以使用共享的编码器,但针对每种目标语言使用单独的解码器进行一对多的多语言翻译
\cite
{
DBLP:conf/naacl/FiratCB16
}
。还有一些方法为每种源语言和目标语言都使用单独的编码器和解码器,但会共享其中的一些组件
\cite
{
DBLP:journals/corr/LuongLSVK15,DBLP:conf/naacl/FiratCB16
}
,比如说,共享其中的注意力机制结构
\cite
{
DBLP:journals/corr/LuongLSVK15,DBLP:conf/naacl/FiratCB16
}
多语言神经机器翻译不仅可以减少训练单一语言对神经机器翻译的训练代价,还可以有效的解决低资源神经机器翻译
\cite
{
DBLP:journals/tacl/JohnsonSLKWCTVW17
}
以及多源神经机器翻译问题
\cite
{
Och01statisticalmulti-source
}
。
\vspace
{
0.5em
}
\item
结构搜索。除了由研究人员手工设计神经网络结构之外,近些年
{
\small\bfnew
{
网络结构搜索技术
}}
\index
{
网络结构搜索技术
}
(Neural Architecture Search;NAS)
\index
{
Neural Architecture Search;NAS
}
也逐渐在包括机器翻译在内的自然语言处理任务中得到广泛关注
\cite
{
elsken2019neural
}
。不同于前文提到的基于循环神经网络、Transformer结构的机器翻译模型,网络结构搜索旨在通过自动的方式根据提供的训练数据自动学习到最适合于当前任务的神经网络模型结构,这种方式能够有效将研究人员从模型结构设计者的位置上“解救”出来,让计算机能够像学网络参数一样学习神经网络模型的结构。目前而言,网络结构搜索的方法已经在自然语言处理的各项任务中崭露头角,在语言模型、命名实体识别等任务中获得优异的成绩
\cite
{
DBLP:conf/iclr/ZophL17,DBLP:conf/emnlp/JiangHXZZ19,liyinqiaoESS
}
,但对于机器翻译任务而言,由于其任务的复杂性,网络结构的搜索空间往往比较大,很难直接对其空间进行搜索,因此研究人员更倾向于对基于现有经验设计的模型结构进行改良。谷歌大脑团队在The Evolved Transformer文章中提出使用进化算法,在Transformer结构基础上对模型结构进行演化,得到更加高效且建模能力更强的机器翻译模型。微软团队也在Neural Architecture Optimization
\cite
{
DBLP:conf/nips/LuoTQCL18
}
论文中提出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
}
。除此之外,也可以把神经机器翻译与翻译记忆相融合
\cite
{
DBLP:conf/aaai/XiaHLS19,DBLP:conf/nlpcc/HeHLL19
}
,在机器翻译应用中也是非常有趣的方向。
\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
}
。除此之外,也可以把神经机器翻译与翻译记忆相融合
\cite
{
DBLP:conf/aaai/XiaHLS19,DBLP:conf/nlpcc/HeHLL19
}
,
这
在机器翻译应用中也是非常有趣的方向。
\end{itemize}
...
...
Book/Chapter7/Figures/figure-batch-generation-method.tex
查看文件 @
87a8c036
\begin{tikzpicture}
\tikzstyle
{
node
}
= [minimum height=1.0em,draw=teal,fill=teal!10]
\tikzstyle
{
legend
}
= [minimum height=1.0
em,minimum width=1.0
em,draw]
\tikzstyle
{
node2
}
= [minimum width=1.0
em,minimum height=4.1
em,draw=blue,fill=blue!10]
\node
[node,minimum width=2.8em]
(node1) at (0,0)
{}
;
\node
[node,minimum width=4.0em,anchor=north west]
(node2) at (node1.south west)
{}
;
\node
[node,minimum width=3.2em,anchor=north west]
(node3) at (node2.south west)
{}
;
\node
[node,minimum width=3.0em,anchor=north west]
(node4) at (node3.south west)
{}
;
\tikzstyle
{
node
}
= [minimum height=1.0
*1.2
em,draw=teal,fill=teal!10]
\tikzstyle
{
legend
}
= [minimum height=1.0
*1.2em,minimum width=1.0*1.2
em,draw]
\tikzstyle
{
node2
}
= [minimum width=1.0
*1.2em,minimum height=4.1*1.2
em,draw=blue,fill=blue!10]
\node
[node,minimum width=2.8
*1.2
em]
(node1) at (0,0)
{}
;
\node
[node,minimum width=4.0
*1.2
em,anchor=north west]
(node2) at (node1.south west)
{}
;
\node
[node,minimum width=3.2
*1.2
em,anchor=north west]
(node3) at (node2.south west)
{}
;
\node
[node,minimum width=3.0
*1.2
em,anchor=north west]
(node4) at (node3.south west)
{}
;
\node
[node2,anchor = north west]
(grad1) at ([xshift=1.2em]node1.north east)
{}
;
\node
[node,minimum width=3.7em,anchor=north west]
(node5) at (grad1.north east)
{}
;
\node
[node,minimum width=2.8em,anchor=north west]
(node6) at (node5.south west)
{}
;
\node
[node,minimum width=3.2em,anchor=north west]
(node7) at (node6.south west)
{}
;
\node
[node,minimum width=4.0em,anchor=north west]
(node8) at (node7.south west)
{}
;
\node
[font=\
script
size,anchor=east]
(line1) at (node1.west)
{
gpu1
}
;
\node
[font=\
script
size,anchor=east]
(line2) at (node2.west)
{
gpu2
}
;
\node
[font=\
script
size,anchor=east]
(line3) at (node3.west)
{
gpu3
}
;
\node
[font=\
script
size,anchor=east]
(line4) at (node4.west)
{
gpu4
}
;
\node
[node,minimum width=3.7
*1.2
em,anchor=north west]
(node5) at (grad1.north east)
{}
;
\node
[node,minimum width=2.8
*1.2
em,anchor=north west]
(node6) at (node5.south west)
{}
;
\node
[node,minimum width=3.2
*1.2
em,anchor=north west]
(node7) at (node6.south west)
{}
;
\node
[node,minimum width=4.0
*1.2
em,anchor=north west]
(node8) at (node7.south west)
{}
;
\node
[font=\
footnote
size,anchor=east]
(line1) at (node1.west)
{
gpu1
}
;
\node
[font=\
footnote
size,anchor=east]
(line2) at (node2.west)
{
gpu2
}
;
\node
[font=\
footnote
size,anchor=east]
(line3) at (node3.west)
{
gpu3
}
;
\node
[font=\
footnote
size,anchor=east]
(line4) at (node4.west)
{
gpu4
}
;
\node
[node2,anchor = north west]
(grad2) at ([xshift=0.3em]node5.north east)
{}
;
\draw
[->]
(-1.4em
,-3.62em) -- (9.5em,-3.6
2em);
\draw
[->]
(-1.4em
*1.2,-3.62*1.2em) -- (9em*1.2,-3.62*1.
2em);
\node
[node,minimum width=2.8
em]
(node9) at (15
em,0)
{}
;
\node
[node,minimum width=4.0em,anchor=north west]
(node10) at (node9.south west)
{}
;
\node
[node,minimum width=3.2em,anchor=north west]
(node11) at (node10.south west)
{}
;
\node
[node,minimum width=3.0em,anchor=north west]
(node12) at (node11.south west)
{}
;
\node
[node,minimum width=2.8
*1.2em]
(node9) at (16
em,0)
{}
;
\node
[node,minimum width=4.0
*1.2
em,anchor=north west]
(node10) at (node9.south west)
{}
;
\node
[node,minimum width=3.2
*1.2
em,anchor=north west]
(node11) at (node10.south west)
{}
;
\node
[node,minimum width=3.0
*1.2
em,anchor=north west]
(node12) at (node11.south west)
{}
;
\node
[node,minimum width=3.7em,anchor=north west]
(node13) at (node9.north east)
{}
;
\node
[node,minimum width=2.8em,anchor=north west]
(node14) at (node10.north east)
{}
;
\node
[node,minimum width=3.2em,anchor=north west]
(node15) at (node11.north east)
{}
;
\node
[node,minimum width=4.0em,anchor=north west]
(node16) at (node12.north east)
{}
;
\node
[node,minimum width=3.7
*1.2
em,anchor=north west]
(node13) at (node9.north east)
{}
;
\node
[node,minimum width=2.8
*1.2
em,anchor=north west]
(node14) at (node10.north east)
{}
;
\node
[node,minimum width=3.2
*1.2
em,anchor=north west]
(node15) at (node11.north east)
{}
;
\node
[node,minimum width=4.0
*1.2
em,anchor=north west]
(node16) at (node12.north east)
{}
;
\node
[node2,anchor = north west]
(grad3) at ([xshift=0.5em]node13.north east)
{}
;
\node
[font=\
script
size,anchor=east]
(line1) at (node9.west)
{
gpu1
}
;
\node
[font=\
script
size,anchor=east]
(line2) at (node10.west)
{
gpu2
}
;
\node
[font=\
script
size,anchor=east]
(line3) at (node11.west)
{
gpu3
}
;
\node
[font=\
script
size,anchor=east]
(line4) at (node12.west)
{
gpu4
}
;
\draw
[->]
(13.6
em,-3.62em) -- (22.2em,-3.6
2em);
\node
[font=\
footnote
size,anchor=east]
(line1) at (node9.west)
{
gpu1
}
;
\node
[font=\
footnote
size,anchor=east]
(line2) at (node10.west)
{
gpu2
}
;
\node
[font=\
footnote
size,anchor=east]
(line3) at (node11.west)
{
gpu3
}
;
\node
[font=\
footnote
size,anchor=east]
(line4) at (node12.west)
{
gpu4
}
;
\draw
[->]
(13.6
*1.2em,-3.62*1.2em) -- (20.5*1.2em,-3.62*1.
2em);
\begin{pgfonlayer}
{
background
}
\node
[rectangle,inner sep=-0.0em,draw] [fit = (node1) (node2) (node3) (node4)] (box1)
{}
;
\node
[rectangle,inner sep=-0.0em,draw] [fit = (node5) (node6) (node7) (node8)] (box2)
{}
;
\node
[rectangle,inner sep=-0.0em,draw] [fit = (node9) (node13) (node12) (node16)] (box2)
{}
;
\end{pgfonlayer}
\node
[font=\
script
size,anchor=north]
(legend1) at ([xshift=3em]node4.south)
{
一步一更新
}
;
\node
[font=\
script
size,anchor=north]
(legend2) at ([xshift=2.5em]node12.south)
{
累积两步更新
}
;
\node
[font=\
script
size,anchor=north]
(time1) at (grad2.south)
{
time
}
;
\node
[font=\
script
size,anchor=north]
(time1) at (grad3.south)
{
time
}
;
\node
[font=\
footnote
size,anchor=north]
(legend1) at ([xshift=3em]node4.south)
{
一步一更新
}
;
\node
[font=\
footnote
size,anchor=north]
(legend2) at ([xshift=2.5em]node12.south)
{
累积两步更新
}
;
\node
[font=\
footnote
size,anchor=north]
(time1) at (grad2.south)
{
time
}
;
\node
[font=\
footnote
size,anchor=north]
(time1) at (grad3.south)
{
time
}
;
\node
[legend]
(legend3) at (2em,2em)
{}
;
\node
[font=\
script
size,anchor=west]
(idle) at (legend3.east)
{
:空闲
}
;
\node
[font=\
footnote
size,anchor=west]
(idle) at (legend3.east)
{
:空闲
}
;
\node
[legend,anchor=west,draw=teal,fill=teal!10]
(legend4) at ([xshift = 2em]idle.east)
{}
;
\node
[font=\
script
size,anchor=west]
(FB) at (legend4.east)
{
:前向/反向
}
;
\node
[font=\
footnote
size,anchor=west]
(FB) at (legend4.east)
{
:前向/反向
}
;
\node
[legend,anchor=west,draw=blue,fill=blue!10]
(legend5) at ([xshift = 2em]FB.east)
{}
;
\node
[font=\
script
size,anchor=west]
(grad
_
sync) at (legend5.east)
{
:梯度更新
}
;
\node
[font=\
footnote
size,anchor=west]
(grad
_
sync) at (legend5.east)
{
:梯度更新
}
;
\end{tikzpicture}
\ No newline at end of file
Book/Chapter7/Figures/figure-randomly-generation-vs-generate-by-sentence-length.tex
查看文件 @
87a8c036
\begin{tikzpicture}
\tikzstyle
{
node
}
= [minimum height=1.0em,draw=teal,fill=teal!10]
\node
[node,minimum width=2.0em]
(sent1) at (0,0)
{}
;
\node
[node,minimum width=5.0em,anchor=north west]
(sent2) at (sent1.south west)
{}
;
\node
[node,minimum width=1.0em,anchor=north west]
(sent3) at (sent2.south west)
{}
;
\node
[node,minimum width=3.0em,anchor=north west]
(sent4) at (sent3.south west)
{}
;
\tikzstyle
{
node
}
= [minimum height=1.0
*1.2
em,draw=teal,fill=teal!10]
\node
[node,minimum width=2.0
*1.2
em]
(sent1) at (0,0)
{}
;
\node
[node,minimum width=5.0
*1.2
em,anchor=north west]
(sent2) at (sent1.south west)
{}
;
\node
[node,minimum width=1.0
*1.2
em,anchor=north west]
(sent3) at (sent2.south west)
{}
;
\node
[node,minimum width=3.0
*1.2
em,anchor=north west]
(sent4) at (sent3.south west)
{}
;
\node
[node,minimum width=4.0
em]
(sent5) at (12
em,0)
{}
;
\node
[node,minimum width=4.5em,anchor=north west]
(sent6) at (sent5.south west)
{}
;
\node
[node,minimum width=4.5em,anchor=north west]
(sent7) at (sent6.south west)
{}
;
\node
[node,minimum width=5em,anchor=north west]
(sent8) at (sent7.south west)
{}
;
\node
[node,minimum width=4.0
*1.2em]
(sent5) at (14
em,0)
{}
;
\node
[node,minimum width=4.5
*1.2
em,anchor=north west]
(sent6) at (sent5.south west)
{}
;
\node
[node,minimum width=4.5
*1.2
em,anchor=north west]
(sent7) at (sent6.south west)
{}
;
\node
[node,minimum width=5
*1.2
em,anchor=north west]
(sent8) at (sent7.south west)
{}
;
\node
[font=\
script
size,anchor=east]
(line1) at (sent1.west)
{
sent1
}
;
\node
[font=\
script
size,anchor=east]
(line2) at (sent2.west)
{
sent2
}
;
\node
[font=\
script
size,anchor=east]
(line3) at (sent3.west)
{
sent3
}
;
\node
[font=\
script
size,anchor=east]
(line4) at (sent4.west)
{
sent4
}
;
\node
[font=\
footnote
size,anchor=east]
(line1) at (sent1.west)
{
sent1
}
;
\node
[font=\
footnote
size,anchor=east]
(line2) at (sent2.west)
{
sent2
}
;
\node
[font=\
footnote
size,anchor=east]
(line3) at (sent3.west)
{
sent3
}
;
\node
[font=\
footnote
size,anchor=east]
(line4) at (sent4.west)
{
sent4
}
;
\node
[font=\
script
size,anchor=east]
(line5) at (sent5.west)
{
sent1
}
;
\node
[font=\
script
size,anchor=east]
(line6) at (sent6.west)
{
sent2
}
;
\node
[font=\
script
size,anchor=east]
(line7) at (sent7.west)
{
sent3
}
;
\node
[font=\
script
size,anchor=east]
(line8) at (sent8.west)
{
sent4
}
;
\node
[font=\
footnote
size,anchor=east]
(line5) at (sent5.west)
{
sent1
}
;
\node
[font=\
footnote
size,anchor=east]
(line6) at (sent6.west)
{
sent2
}
;
\node
[font=\
footnote
size,anchor=east]
(line7) at (sent7.west)
{
sent3
}
;
\node
[font=\
footnote
size,anchor=east]
(line8) at (sent8.west)
{
sent4
}
;
\begin{pgfonlayer}
{
background
}
\node
[rectangle,inner sep=-0.0em,draw] [fit = (sent1) (sent2) (sent3) (sent4)] (box1)
{}
;
\node
[rectangle,inner sep=-0.0em,draw] [fit = (sent5) (sent6) (sent7) (sent8)] (box2)
{}
;
\end{pgfonlayer}
\node
[font=\
scriptsize]
(node1) at ([yshift=-3
em]sent2.south)
{
随机生成
}
;
\node
[font=\
script
size]
(node2) at ([yshift=-1em]sent8.south)
{
排序生成
}
;
\node
[font=\
footnotesize]
(node1) at ([yshift=-3.4
em]sent2.south)
{
随机生成
}
;
\node
[font=\
footnote
size]
(node2) at ([yshift=-1em]sent8.south)
{
排序生成
}
;
\end{tikzpicture}
\ No newline at end of file
Book/Chapter7/Figures/figure-word-change.tex
查看文件 @
87a8c036
\begin{center}
\centerline
{
以英语为例:
}
\vspace
{
0.5em
}
\begin{tikzpicture}
\node
[rounded corners=3pt,minimum width=10.0em,minimum height=2.0em,draw,thick,fill=green!5,font=\scriptsize,drop shadow,inner sep=0.5em]
(left) at (0,0)
{
\begin{tabular}
{
c
}
...
...
编写
预览
Markdown
格式
0%
重试
或
添加新文件
添加附件
取消
您添加了
0
人
到此讨论。请谨慎行事。
请先完成此评论的编辑!
取消
请
注册
或者
登录
后发表评论