【機器學習2021】Transformer-李宏毅

225 阅读12分钟

自注意力的运作原理

自注意力运作的过程

真正的好处:给一个完整的输入,可同时产生每一个时间点语言模型预测的下一个token,可并行。 image.png

    接下来介绍下向量b1 产生的过程,了解产生向量b1的过程后,剩下向量b2、b3、b4 产 生的过程以此类推。怎么产生向量b1呢?如图6.17所示,第一个步骤是根据a1找出输入序 列里面跟a1 相关的其他向量。自注意力的目的是考虑整个序列,但是又不希望把整个序列所 有的信息包在一个窗口里面。所以有一个特别的机制,这个机制是根据向量a1找出整个很长 的序列里面哪些部分是重要的,哪些部分跟判断a1是哪一个标签是有关系的。每一个向量跟 a1 的关联的程度可以用数值α来表示。

    自注意力的模块如何自动决定两个向量之间的关联性 呢?给它两个向量a1跟a4,它怎么计算出一个数值α呢?我们需要一个计算注意力的模块。 怎么计算α?比较常见的做法是用点积(dotproduct)

image.png

    接下来如何把它套用在自注意力模型里面呢?自注意力模型一般采用查询-键-值(Query Key-Value,QKV)模式。分别计算 a1 与 a2、a3、a4 之间的关联性 α。如图 6.19 所示,把 a1 乘上Wq 得到q1。q 称为查询(query),它就像是我们使用搜索引擎查找相关文章所使用的关键字,所以称之为查询.

  • Wq:定义“要关注什么”。
  • Wk:定义“哪些特征值得关注”。
  • Wv:定义“关注后提取什么信息”。

image.png     接下来下来要去把a2、a3、a4 乘上Wk 得到向量k,向量k称为键(key)。把查询q1 跟键 k2 算内积(inner-product)就得到 α1,2。α1,2 代表查询是 q1 提供的,键是 k2 提供的时候, q1 跟 k2 之间的关联性。关联性α也被称为注意力的分数。计算q1与k2的内积也就是计算 a1 与 a2 的注意力的分数。计算出a1 与a2 的关联性以后,接下来还需要计算a1与a3、a4 的关联性。把a3乘上Wk得到键k3,a4 乘上Wk 得到键k4,再把键k3跟查询q1做内积, 得到a1 与a3 之间的关联性,即a1跟a3的注意力分数。把k4跟q1做点积,得到α1,4,即 a1 跟 a4 之间的关联性。

image.png     一般在实践的时候,如图6.20所示,a1 也会跟自己算关联性,把a1 乘上Wk得到k1。 用q1 跟k1 去计算a1 与自己的关联性。计算出a1跟每一个向量的关联性以后,接下来会对 所有的关联性做一个softmax 操作,如下所示,把 α 全部取 e 的指数,再把指数的值 全部加起来做归一化(normalize)得到 α′。这里的 softmax 操作跟分类的 softmax 操作是一 模一样的。

α1,i=exp(α1,i)/jexp(α1,j)\alpha _ { 1 , i } ^ { \prime } = e x p ( \alpha _ { 1 , i } ) / \sum _ { j } e x p ( \alpha _ { 1 , j } )

所以本来有一组α,通过softmax 就得到一组α′。

Q:为什么要用softmax?

A:这边不一定要用softmax,可以用别的激活函数,比如ReLU。有人尝试使用ReLU, 结果发现还比softmax 好一点。所以不一定要用softmax,softmax 只是最常见的,我 们可以尝试其他激活函数,看能不能试出比softmax更好的结果。

image.png

    得到α′ 以后,接下来根据α′ 去抽取出序列里面重要的信息。 如图6.21所示,根据α可 知哪些向量跟a1是最有关系的,接下来我们要根据关联性,即注意力的分数来抽取重要的信 息。把向量a1 到a4 乘上Wv得到新的向量:v1、v2、v3 和v4,接下来把每一个向量都去乘上注意力的分数α′,再把它们加起来,如下式所示。

b1=iα1,ivib ^ { 1 } = \sum _ { i } \alpha _ { 1 , i } ^ { \prime } v ^ { i }

    如果a1 跟a2 的关联性很强,即α1,2α′_{1,2} 的值很大。在做加权和(weightedsum)以后,得到的b1 的值就可能会比较接近v2,所以谁的注意力的分数最大,谁的v就会主导(dominant) 抽出来的结果。这边我们讲述了如何从一整个序列得到b1。同理,可以计算出b2到b4。

自注意力的运作过程(矩阵乘法)

image.png     不只是q1 要对k1 到k4 计算注意力,q2 也要对k1 到k4 计算注意力。 我们把q2 也乘上k1到k4,得到α2,1 到α2,4。现在的操作是一模一样的,把q3 乘k1 到k4,把q4 乘上k1 到k4 可以得到注意力的分数 image.png 如图6.24 所示,如果从矩阵操作的角度来看注意力计算这个操作,把q1 跟k1 做内积, 得到α1,1。q1 乘上 (k1)T,也就是 q1 跟 k1 做内积。【同理,α1,2 是 q1 跟 k2 做内积,α1,3 是 q1 跟 k3 做内积,α1,4 就是 q1 跟 k4 做内积。】这四个步骤的操作,其实可以把它拼起来,看 作是矩阵跟向量相乘。q1 乘k1,q1 乘k2,q1 乘 k3,q1 乘 k4 这四个动作,可以看作是把 (k1)T 到 (k4)T 拼起来当作是一个矩阵的四行,把这个矩阵乘上q1 可得到注意力分数的矩阵, 矩阵的每一行都是注意力的分数,即α1,1 到α1,4。 image.png     如图6.26 所示,通过两个矩阵的相乘就得到注意力的分数。一个矩阵的行就是k,即k1 到k4。另外一个矩阵的列就是q,即q1 到q4。把k所形成的矩阵KT乘上q所形成的矩阵Q就得到这些注意力的分数。假设K的列是k1到k4,在这边相乘的时候,要对矩阵K 做一下转置得到KT,KT 乘上Q就得到矩阵A,A里面存的就是Q跟K 之间的注意力 的分数。对注意力的分数做一下归一化(normalization),比如使用softmax,A的每一列做softmax,每一列里面的值相加是1。 softmax不是唯一的选项,完全可以选择其他的操 作,比如ReLU之类的,得到的结果也不会比较差。由于把α做softmax操作以后,它得到 的值有异于α的原始值,所以用A′来表示通过softmax以后的结果。 image.png     图6.27 所示,计算出 A′ 以后,需要把 v1 到 v4 乘上对应的 α 再相加得到b。如果 把v1 到v4 当成是矩阵V 的4个列拼起来,则把A′的第一个列乘上V 就得到b1,把A′ 的第二个列乘上V 得到b2,以此类推。所以等于把矩阵A′乘上矩阵V 得到矩阵O。矩阵 O 里面的每一个列就是自注意力的输出b1 到b4。所以整个自注意力的操作过程可分为以下 步骤,先产生了q、k和v,再根据q去找出相关的位置,然后对v做加权和。这一串操作 就是一连串矩阵的乘法。 image.png     如图6.28 所示,自注意力的输入是一组的向量,将这排向量拼起来可得到矩阵I。输入 I 分别乘上三个矩阵:Wq、Wk 跟Wv ,得到三个矩阵Q、K和V。接下来Q乘上KT得到矩阵A。把矩阵A做一些处理可得到A′,A′称为注意力矩阵(attentionmatrix)。把 A′ 再乘上V 就得到自注意力层的输出O。自注意力的操作较为复杂,但自注意力层里面唯 一需要学的参数就只有Wq、Wk跟Wv。只有Wq、Wk、Wv是未知的,需要通过训练数 据把它学习出来的。其他的操作都没有未知的参数,都是人为设定好的,都不需要通过训练数 据学习。 image.png     其实还有其他的计算方式,如图(b)所示,有另外一个叫做相加(additive)的计算方式,其计算方法就是把两个向量通过Wq、Wk得到q和k,但不是把它们做点积,而是把 q 和k“串”起来“丢”到一个tanh函数,再乘上矩阵W得到α。总之,有非常多不同的方法可 以计算注意力,可以计算关联程度α。但我们都只用点积这个方法, 这也是目前最常用的方法,也是用在Transformer 里面的方法。

image.png

多头注意力

    在使用自注意力计算相关性的时候,就是用q去找相关的k。但是相关有很多种 不同的形式,所以也许可以有多个q,不同的q负责不同种类的相关性,这就是多头注意力。 如图6.29 所示,

  • 先把 a 乘上一个矩阵得到q,
  • 接下来再把q 乘上另外两个矩阵,
  • 分别得到 q1、q2。

    用两个上标,qi,1 跟 qi,2 代表有两个头,i 代表的是位置,1 跟2代表是这个位置的 第几个q,这个问题里面有两种不同的相关性,所以需要产生两种不同的头来找两种不同的相 关性。既然q有两个,k也就要有两个,v也就要有两个。怎么从q得到q1、q2,怎么从k 得到k1、k2,怎么从v 得到v1、v2?其实就是把q、k、v 分别乘上两个矩阵,得到不同的 头。

image.png     如图6.30 所示,我们可以使用另外一个头做相同的事情。q2 只对k2 做注意力,在做加 权和的时候,只对v2做加权和得到bi,2。如果有多个头,如8个头、16个头,操作也是一样 的。

image.png 注意:WqW^q Wq,1W^{q,1}Wq,2W^{q,2} 等权重矩阵是相互独立的可学习参数,它们之间没有直接的数学关系.分别随机初始化,并在训练过程中通过反向传播独立更新。

WQW^QWq,kW^{q,k} 的职责分离:

  • WQW^Q 的作用: 将输入向量 aia^i 投影到初始查询空间(维度为 dmodeld_{\text{model}}),生成全局的查询表示 qiq^i
qi=WQai q^i = W^Q a^i
  • Wq,kW^{q,k} 的作用: 将全局查询 qiq^i 进一步投影到不同注意力头的子空间(如 dkd_k 维),生成针对不同相关性类型的查询头 qi,1,qi,2q^{i,1}, q^{i,2} 等。
qi,1=Wq,1qi,qi,2=Wq,2qi q^{i,1} = W^{q,1} q^i, \quad q^{i,2} = W^{q,2} q^i

    如图6.31 所示,得到bi,1 跟 bi,2,可能会把 bi,1 跟 bi,2 接起来,再通过一个变换,即再 乘上一个矩阵然后得到bi,再送到下一层去,这就是自注意力的变形——多头自注意力。 image.png     将多个注意力头的输出拼接后使用的变换矩阵通常称为 输出投影矩阵(Output Projection Matrix) ,记为 WOW^O

1. 多头注意力的输出拼接

  • 假设有 h 个注意力头,每个头生成一个输出向量 i(k)i^{(k)}(k=1,2,...,h),维度为 dvd_v,接后的向量维度为 h×dvh × d_v
    例如:若 h=8,dv=64d_v=64,拼接后维度为 8×64=512,也是注意力输入维度。
  • 输出投影矩阵WOW^O 是通过模型训练学习得到的参数

2. 输出投影矩阵 WOW^O 的作用

  • 降维与整合
    • 拼接后的高维向量需要通过WOW^O映射回原始维度dmodeld_{model}(与输入向量维度一致)。
    • 公式: bi=Concat(bi(1),bi(2),...,bi(h))WO b_i = \text{Concat}(b_i^{(1)}, b_i^{(2)}, ..., b_i^{(h)}) \cdot W_O
  • 其中,WOW^O 的维度为 (h × d_v) × d_model
  • 信息融合
    • 不同注意力头可能捕捉到不同类型的相关性(如语法、语义、指代等), WOW^O 负责将这些异构信息融合为统一的表示。

3. 具体示例

假设输入维度 dmodel=512d_{model}=512,使用 h=8 个注意力头,每个头的 dv=64d_v=64

  • 每个头的输出:bi(k)R64b_i^{(k)} ∈ ℝ^{64}(共8个头)。
  • 拼接结果:Concat(bi(1),...,bi(8))R512Concat(b_i^{(1)}, ..., b_i^{(8)}) ∈ ℝ^{512}
  • 投影矩阵 WOW_O:维度为 512×512。
  • 最终输出:bi=Concat(...)WOR512b_i = Concat(...) ⋅ W_O ∈ ℝ^{512},与输入维度一致。

4. 为什么需要WOW^O

  • 维度匹配:确保多头注意力的输出与输入维度相同,便于残差连接和后续层处理。
  • 增强表达能力:通过线性变换整合不同注意力头的信息,提升模型灵活性。
  • 减少计算量:若直接使用拼接后的高维向量,后续计算成本会显著增加,而投影到原始维度可保持计算效率。

对比单个bi计算图列: image.png

位置编码

    讲到目前为止,自注意力层少了一个也许很重要的信息,即位置的信息。对一个自注意力 层而言,每一个输入是出现在序列的最前面还是最后面,它是完全没有这个信息的。有人可能 会问:输入不是有位置1、2、3、4吗?但1、2、3、4是作图的时候,为了帮助大家理解所标 上的一个编号。对自注意力而言,位置1、位置2、位置3跟位置4没有任何差别,这四个位置的操作是一模一样的。 它来说,q1跟q4的距离并没有特别远,1跟4的距离并没有特别 远,2跟3的距离也没有特别近,对它来说就是天涯若比邻,所有的位置之间的距离都是一样 的,没有谁在整个序列的最前面,也没有谁在整个序列的最后面。但是这可能会有一个问题:

    位置的信息被忽略了,而有时候位置的信息很重要。举个例子,在做词性标注的时候,我们知 道动词比较不容易出现在句首,如果某一个词汇它是放在句首的,它是动词的可能性就比较低,位置的信息往往也是有用的。可是到目前为止,自注意力的操作里面没有位置的信息。因此做自注意力的时候,如果我们觉得位置的信息很重要,需要考虑位置信息时,就要用到位置编码(positional encoding)。如图 6.32 所示,位置编码为每一个位置设定一个向量,即位置向量(positional vector)。位置向量用 ei 来表示,上标 i 代表位置,不同的位置就有不同 的向量,不同的位置都有一个专属的e,把e加到ai上面就结束了。这相当于告诉自注意力 位置的信息,如果看到ai 被加上ei,它就知道现在出现的位置应该是在i这个位置。

image.png

    最早的Transformer 论文 “Attention Is All You Need” 用的 ei 如图 6.33 所示。图上面每 一列就代表一个e,第一个位置就是e1,第二个位置就是e2,第三个位置就是e3,以此类推。 每一个位置的a都有一个专属的e。 模型在处理输入的时候,它可以知道现在的输入的位置 的信息,这个位置向量是人为设定的。人为设定的向量有很多问题,假设在定这个向量的时候 只定到128,但是序列的长度是129,怎么办呢?在最早的“AttentionIs All You Need” 论文 中,其位置向量是通过正弦函数和余弦函数所产生的,避免了人为设定向量固定长度的尴尬。 image.png

Q:为什么要通过正弦函数和余弦函数产生向量,有其他选择吗?为什么一定要这样产 生手工的位置向量呢?

A:不一定要通过正、余弦函数来产生向量,我们可以提出新的方法。此外,不一定 要这样产生手工的向量,位置编码仍然是一个尚待研究的问题,甚至位置编码是可以 根据数据学出来的。有关位置编码,可以参考论文 “Learning to Encode Position for Transformer with Continuous Dynamical Model”,该论文比较了不同的位置编码方法 并提出了新的位置编码。

如图6.34a 所示,最早的位置编码是用正弦函数所产生的,图6.34a中每一行代表一个位 置向量。

如图6.34b所示,位置编码还可以使用循环神经网络生成。

总之,位置编码可通过各 种不同的方法来产生。目前还不知道哪一种方法最好,这是一个尚待研究的问题。所以不用纠 结为什么正弦函数最好,我们永远可以提出新的做法。 image.png [2] LIU X, YU H F, DHILLON I S, et al. Learning to encode position for transformer with continuous dynamical model[C]//International Conference on Machine Learning(ICML). 2020: 6327–6335.

Encoder

什么是Encoder,每个输入向量对应一个输出向量(如句子有N个词,则输出N个向量)就是一句话:输入一排向量,输出同样长的向量,

image.png

Transformer 里面加入了残差连接(residual connection)的设计,如图 7.12 所示,最 左边的向量b输入到自注意力层后得到向量a,输出向量a加上其输入向量b得到新的输 出。得到残差的结果以后,再做层归一化(layer normalization)。层归一化比批量归一化更简单,不需要考虑批量的信息,而批量归一化需要考虑批量的信息。层归一化输入一个向量,输出另外一个向量。层归一化会计算输入向量的平均值和标准差。

  • 批量归一化是对不同样本不同特征的同一个维度去计算均值跟标准差。
  • 层归一化是对同一个特征、同一个样本里面不同的维度去计算均值跟标准差,接着做个归一化。

35a3cf2409f1bc4099e90ca721d11e84.png

Q: 为什么Transformer 中使用层归一化,而不使用批量归一化?

A: 论文“PowerNorm: Rethinking Batch Normalization in Transformers”解释了在 Transformers 里面批量归一化不如层归一化的原因,并提出能量归一化(power nor malization)。能量归一化跟层归一化性能差不多,甚至好一点。

decoder

maskedself-attention

通过一个掩码(mask)来阻止每个位置选择其后面的输入信息。

image.png

一般自注意力产生b2 的过程如图7.20 所示。掩蔽自注意力的计算过程如图 7.21 所示, 我们只拿q2 和k1、k2 计算注意力,最后只计算v1 跟v2 的加权和。不管a2 右边的地方, 只考虑a1、a2、q1、q2、k1 以及 k2。输出 b2 的时候,只考虑了 a1 和 a2,没有考虑到a3 和a4

image.png

Q: 为什么需要在注意力中加掩码?

A: 一开始解码器的输出是一个一个产生的,所以是先有a1 再有a2,再有 a3,再有 a4。这跟原来的自注意力不一样,原来的自注意力a1 跟a4 是一次整个输进去模型里 面的。编码器是一次把a1 跟a4 都整个都读进去。但是对解码器而言,先有a1 才有 a2,才有a3 才有a4。所以实际上当我们有a2,要计算b2 的时候,没有a3 跟a4 的, 所以无法考虑a3 a4。解码器的输出是一个一个产生的,所以只能考虑其左边的东西, 没有办法考虑其右边的东西。

  我们无法从输入序列的长度知道输出序列的长度,因此解码器必须决 定输出的序列的长度。给定一个输入序列,机器可以自己学到输出序列的长度。但在目前的解码器运作的机制里面,机器不知道什么时候应该停下来,如图7.22所示,机器产生完“习”以 后,还可以继续重复一模一样的过程,把“习”当做输入,解码器可能就会输出“惯”,接下来就 一直持续下去,永远都不会停下来。

image.png

  如图7.23 所示,要让解码器停止运作,需要特别准备一个特别的符号<EOS><EOS>。产生完 “习”以后,再把“习”当作解码器的输入以后,解码器就要能够输出<EOS><EOS>解码器看到 编码器输出的嵌入、<EOS><EOS>、“机”、“器”、“学”、“习”以后,其产生出来的向量里面<EOS><EOS>的概率必须是最大的,于是输出,整个解码器产生序列的过程就结束了。

非自回归解码器

  1. 自回归模型(AR)

    • 生成方式:逐词生成,每一步的输出依赖于之前生成的词。例如,输入 <BOS> 生成第一个词 W1,再将 W1作为输入生成 W2,直到生成 <EOS>
    • 优点:生成质量高,词与词之间的依赖关系被显式建模。
    • 缺点:生成速度慢,无法并行计算(每一步需等待前一步结果)。
  2. 非自回归模型(NAR)

    • 生成方式:一次性生成整个序列。例如,输入多个 <BOS> 词元(如 4 个),直接输出 4 个词(如中文句子)。
    • 优点:生成速度快,可完全并行化;非自回归的解码器比较能够控制它输出的长度。
    • 缺点:词与词之间的依赖关系被弱化,可能导致生成质量下降。
    • 应用:非自回归模型(NAR)在控制输出序列长度上确实有独特优势,尤其是在语音合成(TTS)这类对时序敏感的任务中。具体实现:
      • 长度预测与动态调整
      • 长度预测器(分类器)的作用:
        • 它是一个小型神经网络,输入是文本(如“你好”),输出是预测的音频时间步数 NN
        • 例如,输入“你好”,预测需要生成 N=200N=200 个时间步的音频。
      • 控制语速的关键操作:
        • 加速:将预测长度 NN 除以2 → 实际生成 N=100N'=100 个时间步。原本分布在200步的内容被压缩到100步 → 播放速度加倍。
        • 减速:将预测长度 NN 乘以2 → 实际生成 N=400N'=400 个时间步。原本200步的内容被拉长到400步 → 播放速度减半。 因为输出的长度是未知的,所以当做非自回归解码器输入的<BOS>的数量也是未知的,因此有如下两个做法:
  • 用分类器来解决这个问题。用分类器“吃”编码器的输入,输出是一个数字,该数字代表解码器应该要输出的长度。比如分类器输出4,非自回归的解码器就会“吃”4个<BOS>的词元,产生4个中文的字。

  • 给编码器一堆 <BOS> 的词元。假设输出的句子的长度有上限,绝对不会超过 300 个 字。给编码器300个<BOS>,就会输出300个字,输出<EOS>右边的的输出就当它没有输出。

image.png   平行化是非自回归解码器最大的优势,但非自回归的解码器的性能(performance)往往都不如自回归的解码器。所以很多研究试图让非自回归的解码器的性能越来越好,去逼近自回归的解码器。要让非自回归的解码器跟自回归的解码器性能一样好,必须要使用非常多的技巧。

编码器-解码器注意力

image.png

  解码器中编码器-解码 器注意力的来自编码器的输出,查询来自解码器中前一个层的输出。

image.png

  所以解码器就是凭借着产生一个q,去编码器这边抽取信息出来,当做接下来的解码器的全连接网络的输入。假设产生“机”,输入<BOS>、“机”,产生一个向量。这个向量一样乘上一个线性变换得到一个查询q′。q′ 会跟k1、k2、k3 计算注意力的分数。接着用注意力分数跟v1、v2、v3 做加权和,加起来得到v′,最后交给全连接网络处理。 编码器和解码器都有很多层,但在原始论文中解码器是拿编码器最后一层的输出但不一定要这样,读者可参考论文“Rethinking and Improving Natural Language Generation with Layer-Wise Multi-View Decoding”

Transformer 的训练过程

图7.29中做了四次分类问题,希望这些分类的问题交叉熵总和越小越好。训练的时候,解码器输出的不是只有“机器学习”这四个中文字,还要输出<BOS>。所以解码 器的最终第五个位置输出的向量跟<BOS>的独热向量的交叉熵越小越好。我们把标准答案 给解码器,希望解码器的输出跟正确答案越接近越好。

image.png

假设目标序列为“机器学习”,训练过程分解为以下步骤:

时间步解码器输入目标输出意义
1<BOS>根据 <BOS> 预测第一个字符“机”
2<BOS> + 机根据 <BOS> 和“机”预测第二个字符“器”
3<BOS> + 机 + 器根据 <BOS>、已生成的“机”和“器”预测第三个字符“学”
4<BOS> + 机 + 器 + 学根据已生成的所有字符预测第四个字符“习”
5<BOS> + 机 + 器 + 学 + 习<EOS>根据完整序列预测结束符 <EOS>

每一步的交叉熵损失:将解码器的输出概率分布与真实标签(如“机”、“器”、“学”、“习”、“ <BOS>”)计算交叉熵。总损失:所有时间步损失的平均或求和。

7.7 序列到序列模型训练常用技巧

7.7.1 复制机制 image.png

在做摘要的时候,我们可能更需要复制的技巧。做摘要需要搜集大量的文章,每一篇文章 都有人写的摘要,训练一个序列到序列的模型就结束了。要训练机器产生合理的句子,通常需要百万篇文章,这些文章都要有人标的摘要。在做摘要的时候,很多的词汇就是直接从原来的文章里面复制出来的,所以对摘要任务而言,从文章里面直接复制一些信息出来是一个很关键的能力,最早有从输入复制东西的能力的模型叫做指针网络(pointernetwork),后来还有 一个变形叫做复制网络(copynetwork)

7.7.2 引导注意力
如果做语音合成的时候,机器的注意力是颠三倒四的,它先看最后面,接下来再看 前面,再胡乱看整个句子,显然这样的注意力是有问题的,没有办法合出好的结果。因此引导 注意力会强迫注意力有一个固定的样貌,如果我们对这个问题本身就已经有理解,知道对于 语音合成这样的问题,注意力的位置都应该由左向右,不如就直接把这个限制放进训练里面, 要求机器学到注意力就应该要由左向右
image.png

7.7.3 束搜索

image.png 机器先读一段句子,接下来它要把这个句子的后半段完成,如果用束搜索,会发现说机器不 断讲重复的话。如果不用束搜索,加一些随机性,虽然结果不一定完全好,但是看起来至少是 比较正常的句子。有时候对解码器来说,没有找出分数最高的路,反而结果是比较好的,这个 就是要看任务本身的特性。假设任务的答案非常明确,比如语音识别,说一句话,识别的结果 就只有一个可能。对这种任务而言,通常束搜索就会比较有帮助。但如果任务需要机器发挥一 点创造力,束搜索比较没有帮助

7.7.4 加入噪声 在做语音合成的时候,解码器加噪声,这是完全违背正常的机器学习的做法。在训练的时 候会加噪声,让机器看过更多不同的可能性,这会让模型比较鲁棒,比较能够对抗它在测试 的时候没有看过的状况。但在测试的时候居然还要加一些噪声,这不是把测试的状况弄得更 困难,结果更差。但语音合成神奇的地方是,模型训练好以后。测试的时候要加入一些噪声, 合出来的声音才会好。用正常的解码的方法产生出来的声音听不太出来是人声,产生出比较 好的声音是需要一些随机性的。对于语音合成或句子完成任务,解码器找出最好的结果不一 定是人类觉得最好的结果,反而是奇怪的结果,加入一些随机性的结果反而会是比较好的。

7.7.5 使用强化学习训练
接下来还有另外一个问题,我们评估的标准用的是BLEU(BiLingualEvaluation Under study)分数。虽然 BLEU 最先是用于评估机器翻译的结果,但现在它已经被广泛用于评价许多应用输出序列的质量。解码器先产生一个完整的句子,再去跟正确的答案一整句做比较,拿两个句子之间做比较算出BLEU分数。 但训练的时候,每一个词汇是分开考虑的,最小化的是交叉熵,最小化交叉熵不一定可以最大化BLEU分数。但在做验证的时候,并不是挑交叉熵最低的模型,而是挑BLEU分数最高的模型。一种可能的想法:训练的损失设置成BLEU 分数乘一个负号,最小化损失等价于最大化BLEU分数。但BLEU分数很复杂,如果要计算 两个句子之间的BLEU分数,损失根本无法做微分。我们之所以采用交叉熵,而且是每一个 中文的字分开来算,就是因为这样才有办法处理。 遇到优化无法解决的问题,可以用强化学习 训练。具体来讲,遇到无法优化的损失函数,把损失函数当成强化学习的奖励,把解码器当成 智能体,可参考论文“Sequence Level Training with Recurrent Neural Networks”。

7.7.6 计划采样

如图7.32所示,测试的时候,解码器看到的是自己的输出,因此它会看到一些错误的东西。 但是在训练的时候,解码器看到的是完全正确的,这种不一致的现象叫做曝光偏差(exposure bias)。

image.png

假设解码器在训练的时候永远只看过正确的东西,在测试的时候,只要有一个错,就会一 步错步步错。因为解码器从来没有看过错的东西,它看到错的东西会非常的惊奇,接下来它 产生的结果可能都会错掉。有一个可以的思考的方向是:给解码器的输入加一些错误的东西, 不要给解码器都是正确的答案,偶尔给它一些错的东西,它反而会学得更好,这一技巧称为计 划采样(scheduled sampling)
但是计划采样会 伤害到Transformer 的平行化的能力,所以 Transformer 的计划采样另有招数,其跟原来最 早提在这个LSTM 上被提出来的招数也不太一样。读者可参考论文“Scheduled Sampling for Transformers”[7]、“Parallel Scheduled Sampling”[8]

参考推荐资料:

第四讲:Transformer 的时代要结束了吗?介紹 Transformer 的竞争者们_哔哩哔哩_bilibili

13.【李宏毅机器学习2021】Transformer (下)_哔哩哔哩_bilibili