深度学习(9)Transformer*-p2

二、李宏毅 - Transformer_decoder P2

2.1 Decoder – Autoregressive (AT)

Decoder其实有两种,接下来会花比较多时间介绍,比较常见的 ==Autoregressive Decoder(自回归解码器)==,这个 Autoregressive 的 Decoder,是怎么运作的。

语音辨识,来当作例子来说明,或用在作业里面的机器翻译,其实是一模一样的,你只是把输入输出,改成不同的东西而已。语音辨识就是输入一段声音,输出一串文字,你会把一段声音输入给 Encoder,比如说你对机器说,机器学习,机器收到一段声音讯号,声音讯号 进入 Encoder以后,输出会是什么,输出会变成一排 Vector。

image-20220615160428118

Encoder 做的事情,就是输入一个 Vector Sequence,输出另外一个 Vector Sequence。接下来,就轮到 Decoder 运作了,Decoder 要做的事情就是产生输出,也就是产生语音辨识的结果,

Decoder 怎么产生这个语音辨识的结果?

image-20220615160726062

Decoder 做的事情,就是把 Encoder 的输出先读进去,至于怎么读进去,这个我们等一下再讲 我们先,你先假设 Somehow 就是有某种方法,把 Encoder 的输出读到 Decoder 里面,这步我们等一下再处理。

Decoder 怎么产生一段文字?

首先,你要先给它一个特殊的符号,这个特殊的符号,代表开始,在助教的投影片里面,是写 Begin Of Sentence,缩写是 BOS

image-20220615160908630

BOS就是 Begin 的意思,这个是一个 Special 的 Token,你就是在你的个 Lexicon 里面,你就在你可能,本来 Decoder 可能产生的文字里面,多加一个特殊的字,这个字就代表了 BEGIN,代表了开始这个事情。

在这个机器学习里面,假设你要处理 NLP 的问题,每一个 Token,你都可以把它用一个 One-Hot 的 Vector 来表示,One-Hot Vector 就其中一维是 1,其他都是 0,所以 BEGIN 也是用 One-Hot Vector 来表示,其中一维是 1,其他是 0。 接下来Decoder 会吐出一个向量,这个 Vector 的长度很长,跟你的 Vocabulary 的 Size 是一样的。

image-20220615161211480

#### Vocabulary Size 则是什么意思?

你就先想好说,你的 Decoder 输出的单位是什么,假设我们今天做的是中文的语音辨识,我们 Decoder 输出的是中文,你这边的 Vocabulary 的 Size ,可能就是中文的方块字的数目。用 Subword 当作英文的单位,就有一些方法,可以把英文的字首字根切出来,拿字首字根当作单位,如果中文的话,我觉得就比较单纯,通常今天你可能就用中文的这个方块字,来当作单位。

每一个中文的字,都会对应到一个数值,因为在产生这个向量之前,你通常会先跑一个 Softmax,就跟做分类一样,所以这一个向量里面的分数,它是一个 Distribution,也就是,它这个向量里面的值,它全部加起来,总和 会是 1

image-20220615162226148

分数最高的一个中文字,它就是最终的输出。在这个例子里面,机的分数最高,所以机,就当做是这个 Decoder 第一个输出。然后接下来,你把“机”当做是 Decoder 新的 Input,原来 Decoder 的 Input,只有 BEGIN 这个特别的符号,现在它除了 BEGIN 以外,它还有“机”作为它的 Input。

image-20220615162308793

所以 Decoder 现在它有两个输入

  • 一个是 BEGIN 这个符号
  • 一个是“机”

根据这两个输入,它输出一个蓝色的向量,根据这个蓝色的向量里面,给每一个中文的字的分数,我们会决定第二个输出,哪一个字的分数最高,它就是输出,假设"器"的分数最高,"器"就是输出

然后现在 Decoder

  • 看到了 BEGIN
  • 看到了"机"
  • 看到了"器"

它接下来,还要再决定接下来要输出什么,它可能,就输出"学",这一个过程就反覆的持续下去

所以现在 Decode

  • 看到了 BEGIN

  • 看到了"机"

  • 看到了"器"

  • 还有"学"

Encoder 这边其实也有输入,等一下再讲 Encoder 的输入,Decoder 是怎么处理的,所以 Decoder 看到 Encoder 这边的输入,看到"机" 看到"器" 看到"学",决定接下来输出一个向量,这个向量里面,"习"这个中文字的分数最高的,所以它就输出"习"。

image-20220615162732493

然后这个 Process ,就反覆持续下去,这边有一个关键的地方,我们特别用红色的虚线把它标出来。

image-20220615162754592

Decoder 看到的输入,其实是它在前一个时间点自己的输出,Decoder 会把自己的输出,当做接下来的输入。

如果Decoder 看到错误的输入,让 Decoder 看到自己产生出来的错误的输入,再被 Decoder 自己吃进去,会不会造成 ==Error Propagation== 的问题.

Error Propagation 的问题就是,一步错 步步错这样,就是在这个地方,如果不小心把机器的“器”,不小心写成天气的"气",会不会接下来就整个句子都坏掉了,都没有办法再产生正确的词汇了?

有可能,这个等一下,我们最后会稍微讲一下,这个问题要怎么处理,我们现在,先无视这个问题,继续走下去

我们来看一下这个 Decoder内部的结构长什么样子?

image-20220615162953318

那我们这边,把 Encoder 的部分先暂时省略掉,那在 Transformer 里面,Decoder 的结构,长得是这个样子的,看起来有点复杂,比 Encoder 还稍微复杂一点,那我们现在先把 Encoder 跟 Decoder 放在一起。

image-20220615163023898

稍微比较一下它们之间的差异,那你会发现说,如果我们把 Decoder 中间这一块,中间这一块把它盖起来,其实 Encoder 跟 Decoder,并没有那么大的差别

image-20220615163100379

你看 Encoder 这边,Multi-Head Attention,然后 Add & Norm,Feed Forward,Add & Norm,重复 N 次,Decoder 其实也是一样。

当我们把中间这一块遮起来以后,我们等一下再讲,遮起来这一块里面做了什么事,但当我们把中间这块遮起来以后, 那 Decoder 也是,有一个 Multi-Head Attention,Add & Norm,然后 Feed Forward,然后 Add & Norm,所以 Encoder 跟 Decoder,其实并没有非常大的差别,除了中间这一块不一样的地方,那只是最后,我们可能会再做一个 Softmax,使得它的输出变成一个机率,那这边有一个稍微不一样的地方是,在 Decoder 这边,Multi-Head Attention 这一个 Block 上面,还加了一个 ==Masked==,

这个 Masked 的意思是这样子的,这是我们原来的 Self-Attention ,Input 一排 Vector,Output 另外一排 Vector,这一排 Vector 每一个输出,都要看过完整的 Input 以后,才做决定,所以输出 \(b^1\) 的时候,其实是根据 \(a^1\)\(a^4\) 所有的资讯,去输出 \(b^1\)

image-20220615163239723

当我们把 Self-Attention,转成 Masked Attention 的时候,它的不同点是,现在我们不能再看右边的部分,也就是产生 \(b^1\) 的时候,我们只能考虑 \(a^1\) 的资讯,你不能够再考虑 \(a^2\) \(a^3\) \(a^4\)。产生 \(b^2\) 的时候,你只能考虑 \(a^1\) \(a^2\) 的资讯,不能再考虑 \(a^3\) \(a^4\) 的资讯。产生 \(b^3\) 的时候,你就不能考虑 \(a^4\) 的资讯。产生 \(b^4\) 的时候,你可以用整个 Input Sequence 的资讯,这个就是 Masked 的 Self-Attention。

image-20220615163708618

讲得更具体一点,你做的事情是,当我们要产生 \(b^2\) 的时候,我们只拿第二个位置的 Query \(b^2\),去跟第一个位置的 Key,和第二个位置的 Key,去计算 Attention,第三个位置跟第四个位置,就不管它,不去计算 Attention。

image-20220615163452245

我们这样子不去管这个 \(a^2\) 右边的地方,只考虑 \(a^1\)\(a^2\),只考虑 \(q^1\) \(q^2\),只考虑 \(k^1\) \(k^2\),\(q^2\) 只跟 \(k^1\)\(k^2\) 去计算 Attention,然后最后只计算 \(b^1\)\(b^2\) 的 Weighted Sum。然后当我们输出这个 \(b^2\) 的时候,\(b^2\) 就只考虑了 \(a^1\)\(a^2\),就没有考虑到 \(a^3\)\(a^4\)

那为什么会这样,为什么需要加 Masked ?

image-20220615163642567

这件事情其实非常地直觉:我们一开始 Decoder 的运作方式,它是一个一个输出,所以是先有 \(a^1\) 再有 \(a^2\),再有 \(a^3\) 再有 \(a^4\)这跟原来的 Self-Attention 不一样,原来的 Self-Attention,\(a^1\)\(a^4\) 是一次整个输进去你的 Model 里面的,在我们讲 Encoder 的时候,Encoder 是一次把 \(a^1\)\(a^4\),都整个都读进去。但是对 Decoder 而言,先有 \(a^1\) 才有 \(a^2\),才有 \(a^3\) 才有 \(a^4\),所以实际上,当你有 \(a^2\),你要计算 \(b^2\) 的时候,你是没有 \(a^3\)\(a^4\) 的,所以你根本就没有办法把 \(a^3\) \(a^4\) 考虑进来。

所以这就是为什么,在那个 Decoder 的那个图上面,Transformer 原始的 Paper 特别跟你强调说,那不是一个一般的 Attention, 这是一个 Masked 的 Self-Attention,意思只是想要告诉你说,Decoder 它的 Tokent,它输出的东西是一个一个产生的,所以它只能考虑它左边的东西,它没有办法考虑它右边的东西。

讲了 Decoder 的运作方式,但是这边,还有一个非常关键的问题,Decoder 必须自己决定,输出的 Sequence 的长度

可是到底输出的 Sequence 的长度应该是多少,我们不知道。

image-20220615164352622

你没有办法轻易的从输入的 Sequence 的长度,就知道输出的 Sequence 的长度是多少,并不是说,输入是 4 个向量,输出一定就是 4 个向量。这边在这个例子里面,输入跟输出的长度是一样的,但是你知道实际上在你真正的应用里面,并不是这样,输入跟输出长度的关係,是非常复杂的,我们其实是期待机器可以自己学到,今天给它一个 Input Sequence 的时候,Output 的 Sequence 应该要多长。

但在我们目前的这整个 Decoder的这个运作的机制里面,机器不知道它什么时候应该停下来,它产生完习以后,它还可以继续重复一模一样的 Process,就把习,当做输入,然后也许 Decoder ,就会接一个惯,然后接下来,就一直持续下去,永远都不会停下来

我们要让 Decoder 做的事情,也是一样,要让它可以输出一个断,所以你要特别准备一个特别的符号,这个符号,就叫做断,我们这边,用 END 来表示这个特殊的符号。

image-20220615164518484

所以除了所有中文的方块字,还有 BEGIN 以外,你还要准备一个特殊的符号,叫做"断",那其实在助教的程式里面,它是把 BEGIN 跟 END,就是开始跟这个断,用同一个符号来表示。

反正这个,这个 BEGIN 只会在输入的时候出现,断只会在输出的时候出现,所以在助教的程式里面,如果你仔细研究一下的话,会发现说 END 跟 BEGIN,用的其实是同一个符号,但你用不同的符号,也是完全可以的,也完全没有问题

所以我们现在,当把"习"当作输入以后,就 Decoder 看到 Encoder 输出的这个 Embedding,看到了 "BEGIN",然后"机" "器" "学" "习"以后,看到这些资讯以后 它要知道说,这个语音辨识的结果已经结束了,不需要再产生更多的词汇了。

它产生出来的向量END,就是断的那个符号,它的机率必须要是最大的,然后你就输出断这个符号,那整个运作的过程,整个 Decoder 产生 Sequence 的过程,就结束了这个就是 ==Autoregressive Decoder==,它运作的方式。

2.2 Decoder – Non-autoregressive (NAT)

Non-Autoregressive ,通常缩写成 NAT,所以有时候 Autoregressive 的 Model,也缩写成 AT,Non-Autoregressive 的 Model 是怎么运作的。先输入 BEGIN,然后出现 w1,然后把 w1 当做输入,输出 w2,直到输出 END 为止

那 ==NAT== 是这样,它不是依次产生

image-20220615164801974

就假设我们现在产生是中文的句子,它不是依次产生一个字,它是一次把整个句子都产生出来。NAT 的 Decoder可能吃的是一整排的 BEGIN 的 Token,你就把一堆一排 BEGIN 的 Token 都丢给它,让它一次产生一排 Token 就结束了

举例来说,如果你丢给它 4 个 BEGIN 的 Token,它就产生 4 个中文的字,变成一个句子,就结束了,所以它只要一个步骤,就可以完成句子的生成,这边你可能会问一个问题:刚才不是说不知道输出的长度应该是多少吗,那我们这边怎么知道 BEGIN 要放多少个,当做 NAT Decoder 的收入?

image-20220615172838842

没错 这件事没有办法很自然的知道,没有办法很直接的知道,所以有几个,所以有几个做法

  • 一个做法是,你另外learn一个 Classifier,这个 Classifier ,它吃 Encoder 的 Input,然后输出是一个数字,这个数字代表 Decoder 应该要输出的长度,这是一种可能的做法
  • 另一种可能做法就是,你就不管三七二十一,给它一堆 BEGIN 的 Token,你就假设说,你现在输出的句子的长度,绝对不会超过 300 个字,你就假设一个句子长度的上限,然后 BEGIN ,你就给它 300 个 BEGIN,然后就会输出 300 个字嘛,然后,你再看看什么地方输出 END,输出 END 右边的,就当做它没有输出,就结束了,这是另外一种处理 NAT 的这个 Decoder,它应该输出的长度的方法

NAT 的 Decoder,最近它之所以是一个热门研究主题,就是它虽然表面上看起来有种种的厉害之处,尤其是平行化是它最大的优势,但是 NAT 的 Decoder ,它的 Performance,往往都不如 AT 的 Decoder

2.3 Encoder-Decoder

接下来就要讲Encoder 跟 Decoder它们中间是怎么传递资讯的了,也就是我们要讲,刚才我们刻意把它遮起来的那一块。

image-20220615173000109

这块叫做 ==Cross Attention==,它是连接 Encoder 跟 Decoder 之间的桥樑,那这一块里面啊,会发现有两个输入来自于 Encoder,Encoder 提供两个箭头,然后 Decoder 提供了一个箭头,所以从左边这两个箭头,Decoder 可以读到 Encoder 的输出。

那这个模组实际上是怎么运作的呢,那我们就实际把它运作的过程跟大家展示一下,这个是你的 Encoder:

image-20220615173054575

输入一排向量,输出一排向量,我们叫它 \(a^1 a^2 a^3\)

接下来 轮到你的 Decoder,你的 Decoder 呢,会先吃 BEGIN 当做,BEGIN 这个 Special 的 Token,那 BEGIN 这个 Special 的 Token 读进来以后,你可能会经过 Self-Attention,这个 Self-Attention 是有做 Mask 的,然后得到一个向量,就是 Self-Attention 就算是有做 Mask,还是一样输入多少长度的向量,输出就是多少向量

所以输入一个向量 输出一个向量,然后接下来把这个向量呢,乘上一个矩阵做一个 Transform,得到一个 Query 叫做 q:

image-20220615173148542

然后这边的 \(a^1 a^2 a^3\) 呢,也都产生 Key,Key1 Key2 Key3,那把这个 q 跟 \(k^1 k^2 k^3\),去计算 Attention 的分数,得到 \(α_1 α_2 α_3\),当然你可能一样会做 Softmax,把它稍微做一下 Normalization,所以我这边加一个 ',代表它可能是做过 Normalization。接下来再把 \(α_1 α_2 α_3\),就乘上 \(v^1 v^2 v^3\),再把它 Weighted Sum 加起来会得到 v。

image-20220615173220252

那这一个 V,就是接下来会丢到 Fully-Connected 的,Network 做接下来的处理,那这个步骤就是 q 来自于 Decoder,k 跟 v 来自于 Encoder,这个步骤就叫做 Cross Attention。 Decoder 就是凭藉著产生一个 q,去 Encoder 这边抽取资讯出来,当做接下来的 Decoder 的,Fully-Connected 的 Network 的 Input。

当然这个,就现在假设产生第二个,第一个这个中文的字产生一个“机”,接下来的运作也是一模一样的。

image-20220615173332499

输入 BEGIN 输入机,产生一个向量,这个向量一样乘上一个 Linear 的 Transform,得到 q',得到一个 Query,这个 Query 一样跟 \(k^1 k^2 k^3\),去计算 Attention 的分数,一样跟 \(v^1 v^2 v^3\) 做 Weighted Sum 做加权,然后加起来得到 v',交给接下来 Fully-Connected Network 做处理,所以这就是Cross Attention 的运作的过程。

也许有人会有疑问:那这个 Encoder 有很多层啊,Decoder 也有很多层啊,从刚才的讲解里面好像听起来,这个 Decoder 不管哪一层,都是拿 Encoder 的最后一层的输出这样对吗?

对,在原始 Paper 里面的实做是这样子,那一定要这样吗?

不一定要这样,你永远可以自己兜一些新的想法,所以我这边就是引用一篇论文告诉你说,也有人尝试不同的 Cross Attension 的方式。

image-20220615173812815

Encoder 这边有很多层,Decoder 这边有很多层,为什么 Decoder 这边每一层都一定要看,Encoder 的最后一层输出呢,能不能够有各式各样不同的连接方式,这完全可以当做一个研究的问题来 Study。

2.4 Training

已经清楚说 Input 一个 Sequence,是怎么得到最终的输出,那接下来就进入训练的部分。

image-20220615173844330

刚才讲的都还只是,假设你模型训练好以后它是怎么运作的,它是怎么做 Testing 的,它是怎么做 Inference 的,Inference 就是 Testing ,那是怎么做训练的呢?

接下来就要讲怎么做训练,那如果是做语音辨识,那你要有训练资料,你要收集一大堆的声音讯号,每一句声音讯号都要有工读生来听打一下,打出说它的这个对应的词汇是什么?

image-20220615173903283

工读生听这段是机器学习,他就把机器学习四个字打出来,所以就知道说你的这个 Transformer,应该要学到 听到这段声音讯号,它的输出就是机器学习这四个中文字。

那怎么让机器学到这件事呢? 我们已经知道说输入这段声音讯号,第一个应该要输出的中文字是“机”,所以今天当我们把 BEGIN,丢给这个 Encoder 的时候,它第一个输出应该要跟“机”越接近越好。

image-20220615174107627

“机”这个字会被表示成一个 One-Hot 的 Vector,在这个 Vector 里面,只有机对应的那个维度是 1,其他都是 0,这是正确答案,那我们的 Decoder,它的输出是一个 Distribution,是一个机率的分布,我们会希望这一个机率的分布,跟这个 One-Hot 的 Vector 越接近越好。所以你会去计算这个 Ground Truth,跟这个 Distribution 它们之间的 Cross Entropy,然后我们希望这个 ==Cross Entropy== 的值,越小越好。

image-20220615174938615

它就跟分类很像,刚才助教在讲解作业的时候也有提到这件事情,你可以想成每一次我们在产生,每一次 Decoder 在产生一个中文字的时候,其实就是做了一次分类的问题,中文字假设有四千个,那就是做有四千个类别的分类的问题

所以实际上训练的时候这个样子,我们已经知道输出应该是“机器学习”这四个字,就告诉你的 Decoder ,现在你第一次的输出 第二次的输出,第三次的输出 第四次输出,应该分别就是“机” “器” “学”跟“习”,这四个中文字的 One-Hot Vector,我们希望我们的输出,跟这四个字的 One-Hot Vector 越接近越好

image-20220615175011374

在训练的时候,每一个输出都会有一个 Cross Entropy,每一个输出跟 One-Hot Vector,跟它对应的正确答案都有一个 Cross Entropy,我们要希望所有的 Cross Entropy 的总和最小越小越好。所以这边做了四次分类的问题,我们希望这些分类的问题,它总合起来的 Cross Entropy 越小越好,还有 END 这个符号

image-20220615175531572

那这个就是 Decoder 的训练,把 Ground Truth ,正确答案给它,希望 Decoder 的输出跟正确答案越接近越好

那这边有一件值得我们注意的事情,在训练的时候我们会给 Decoder 看正确答案,也就是我们会告诉它说

  • 在已经有 "BEGIN",在有"机"的情况下你就要输出"器"
  • 有 "BEGIN" 有"机" 有"器"的情况下输出"学"
  • 有 "BEGIN" 有"机" 有"器" 有"学"的情况下输出"习"
  • 有 "BEGIN" 有"机" 有"器" 有"学" 有"习"的情况下,你就要输出"断"

在 Decoder 训练的时候,我们会在输入的时候给它正确的答案,那这件事情叫做 ==Teacher Forcing==

那这个时候你马上就会有一个问题了?

  • 训练的时候,Decoder 有偷看到正确答案了
  • 但是测试的时候,显然没有正确答案可以给 Decoder 看

刚才也有强调说在真正使用这个模型,在 Inference 的时候,Decoder 看到的是自己的输入,这中间显然有一个 ==Mismatch==,那等一下我们会有一页投影片的说明,有什么样可能的解决方式。

2.5 Tips

那接下来,不侷限于 Transformer ,讲一些训练这种 Sequence To Sequence Model 的Tips

Copy Mechanism

在我们刚才的讨论里面,我们都要求 Decoder 自己产生输出,但是对很多任务而言,也许 Decoder 没有必要自己创造输出出来,它需要做的事情,也许是从输入的东西里面复製一些东西出来。

像这种复製的行为在哪些任务会用得上呢,一个例子是做聊天机器人。

image-20220615175700028

  • 人对机器说:你好 我是库洛洛,

  • 机器应该回答说:库洛洛你好 很高兴认识你

对机器来说,它其实没有必要创造库洛洛这个词汇,这对机器来说一定会是一个非常怪异的词汇,所以它可能很难,在训练资料里面可能一次也没有出现过,所以它不太可能正确地产生这段词汇出来。

但是假设今天机器它在学的时候,它学到的是看到输入的时候说我是某某某,就直接把某某某,不管这边是什么复製出来说某某某你好。

那这样子机器的训练显然会比较容易,它显然比较有可能得到正确的结果,所以复製对于对话来说,可能是一个需要的技术 需要的能力。

Guided Attention

机器就是一个黑盒子,有时候它里面学到什么东西,你实在是搞不清楚,那有时候它会犯非常低级的错误。但是对语音辨识 语音合成,Guiding Attention,可能就是一个比较重要的技术

Guiding Attention 要做的事情就是,要求机器它在做 Attention 的时候,是有固定的方式的,举例来说,对语音合成或者是语音辨识来说,我们想像中的 Attention,应该就是由左向右。

image-20220615175853638

在这个例子里面,我们用红色的这个曲线,来代表 Attention 的分数,这个越高就代表 Attention 的值越大

我们以语音合成为例,那你的输入就是一串文字,那你在合成声音的时候,显然是由左念到右,所以机器应该是,先看最左边输入的词汇产生声音,再看中间的词汇产生声音,再看右边的词汇产生声音

如果你今天在做语音合成的时候,你发现机器的 Attention,是颠三倒四的,它先看最后面,接下来再看前面,那再胡乱看整个句子,那显然有些是做错了,显然有些是,Something is wrong,有些是做错了,

所以 Guiding Attention 要做的事情就是,强迫 Attention 有一个固定的样貌,那如果你对这个问题,本身就已经有理解知道说,语音合成 TTS 这样的问题,你的 Attention 的分数,Attention 的位置都应该由左向右,那不如就直接把这个限制,放进你的 Training 里面,要求机器学到 Attention,就应该要由左向右。

Optimizing Evaluation Metrics?

在作业里面,我们评估的标准用的是,BLEU Score,BLEU Score 是你的 Decoder,先产生一个完整的句子以后,再去跟正确的答案一整句做比较,我们是拿两个句子之间做比较,才算出 BLEU Score。

但我们在训练的时候显然不是这样,训练的时候,每一个词汇是分开考虑的,训练的时候,我们 Minimize 的是 Cross Entropy,Minimize Cross Entropy,真的可以 Maximize BLEU Score 吗?

image-20220615180128331

不一定,因为这两个根本就是,它们可能有一点点的关联,但它们又没有那么直接相关,它们根本就是两个不同的数值,所以我们 Minimize Cross Entropy,不见得可以让 BLEU Score 比较大。

所以你发现说在助教的程式里面,助教在做 Validation 的时候,并不是拿 Cross Entropy 来挑最好的 Model,而是挑 BLEU Score 最高的那一个 Model,所以我们训练的时候,是看 Cross Entropy,但是我们实际上你作业真正评估的时候,看的是 BLEU Score,所以你 Validation Set,其实应该考虑用 BLEU Score

那接下来有人就会想说,那我们能不能在 Training 的时候,就考虑 BLEU Score 呢,我们能不能够训练的时候就说,我的 Loss 就是,BLEU Score 乘一个负号,那我们要 Minimize 那个 Loss,假设你的 Loss 是,BLEU Score乘一个负号,它也等于就是 Maximize BLEU Score。但是这件事实际上没有那么容易,你当然可以把 BLEU Score,当做你训练的时候,你要最大化的一个目标,但是 BLEU Score 本身很复杂,它是不能微分的。

这边之所以採用 Cross Entropy,而且是每一个中文的字分开来算,就是因为这样我们才有办法处理,如果你是要计算,两个句子之间的 BLEU Score,这一个 Loss,根本就没有办法做微分,那怎么办呢?这边就教大家一个口诀,遇到你在 Optimization 无法解决的问题,==用 RL 硬 Train 一发==就对了这样,遇到你无法 Optimize 的 Loss Function,把它当做是 RL 的 Reward,把你的 Decoder 当做是 Agent,它当作是 RL,Reinforcement Learning 的问题硬做。

Scheduled Sampling (计划采样)

那我们要讲到,我们刚才反覆提到的问题了,就是训练跟测试居然是不一致

测试的时候,Decoder 看到的是自己的输出,所以测试的时候,Decoder 会看到一些错误的东西,但是在训练的时候,Decoder 看到的是完全正确的,那这个不一致的现象叫做,==Exposure Bias==。

image-20220615181122702

假设 Decoder 在训练的时候,永远只看过正确的东西,那在测试的时候,你只要有一个错,那就会一步错 步步错,因为对 Decoder 来说,它从来没有看过错的东西,它看到错的东西会非常的惊奇,然后接下来它产生的结果可能都会错掉。

所以要怎么解决这个问题呢?

有一个可以的思考的方向是,给 Decoder 的输入加一些错误的东西,就这么直觉,你不要给 Decoder 都是正确的答案,偶尔给它一些错的东西,它反而会学得更好,这一招叫做,==Scheduled Sampling==,它不是那个 Schedule Learning Rate,刚才助教有讲 Schedule Learning Rate,那是另外一件事,不相干的事情,这个是 Scheduled Sampling。

image-20220615181204628

Scheduled Sampling 其实很早就有了,这个是 15 年的 Paper,很早就有 Scheduled Sampling,在还没有 Transformer,只有 LSTM 的时候,就已经有 Scheduled Sampling,但是 Scheduled Sampling 这一招,它其实会伤害到,Transformer 的平行化的能力,那细节可以再自己去了解一下,所以对 Transformer 来说,它的 Scheduled Sampling,另有招数跟传统的招数,跟原来最早提在,这个 LSTM上被提出来的招数,也不太一样,那我把一些 Reference 的,列在这边给大家参考。

image-20220615181229880

Transformer 和种种的训练技巧,这个我们已经讲完了 Encoder,讲完了 Decoder,也讲完了它们中间的关係,也讲了怎么训练,也讲了种种的 Tip。