关于transformer的学习
- 一、前言
- 二、初识Transformer
- 2.1 总览
- 2.2 encoder
- 2.3 decoder
- 三. 流程与细节
- 1、输入
- 2、self-attention
一、前言
我本身是从事图像算法行业的,在之前主要是做传统的图像算法,后来接触了基于CNN的神经网络图像算法,包括图像分类,目标检测,图像分割等场景。对于Transformer的了解,我一直停留在其在NLP领域的优异表现,对于图像算法中的应用,知之甚少,因此对于基于该框架的模型,也是一直没有下定决心好好去学习。然而现在在视觉应用中,Transformer也同样大放异彩,逐步的刷新着人们对于智能的认知,尤其是在自动驾驶,机器人领域,大模型的普遍应用,也让我不得不来窥探一下这其中究竟有着怎么样的绝妙的算法设计,虽然道路是艰苦的,但是我想行,只要经过不断的坚持努力,没有啃不下来的硬骨头,Transformer同样也能成为我工作中的攻城利器!
二、初识Transformer
在网上搜索之后,发现了一篇针对transformer讲解的非常好的一篇博客,是一位国外的大神写的全英文的博客,因此我的笔记内容会将参考他的文章来进行我个人的一个理解总结,由于本人英语水平有限,如果我的理解有什么不到位的地方,希望大家能在评论区帮我指出问题,我们一起探讨一起进步~~
2.1 总览
我们首先将transformer
模型视为一个黑匣子,在机器翻译任务场景下,它将接收一种语言的句子,并以另一种语言输出翻译的结果,如下图所示。
我们再打开transformer
进入内部看一下,我们可以看到它是由一个encoders组件
和一个decoders组件
组成的,并且两者之间是存在联系的(耦合),如下图所示。
事实上,encoders组件
是一个由多个单独的encoder
堆栈组成的一个结构,他们是一个自下而上的顺序流结构,在作者的paper中使用了六个这样的encoder
来进行堆叠,当然,6并没有特别的讲究之处,你也可以用不同数量的encoder
来堆叠你的encoders组件
。同样的,decoders组件
用同样个数的decoder
进行堆叠,如下图所示。
2.2 encoder
每一个encoder
在结构上都是相同的,但是他们不共享权重,各自拥有独立的权重,每一个都可以被拆分成两个子部分:self-attention
和Feed Forward Neural Network(FFNN)
。
encoder
的输入首先流过self-attention
层,这个层的作用是帮助encoder
关注于句子中的特定单词,我们将会在下面的部分详细的介绍自注意力层
。自注意力层
的输出将会作为输入喂到FFNN
中作为输入。
自注意力层
的输出将会被喂到一个前馈神经网络中去。完全相同的前馈网络被独立的应用在每一个位置(即相同的前馈网络但是不相同的权重)。
2.3 decoder
decoder
拥有完全相同的这些层(即self-attention层和FFPN层,仅结构上相同),但是在decoder
中介于这两者之间还有一个注意力层来帮助decoder
来关注输入句子的相关部分(与seq2seq模型的注意力类似)。
三. 流程与细节
在上一节中,我们已经大概了解了transformer的总体架构,接下去我们将带入向量/张量并观察他们是如何在这些组成部分中流动并最终从输入得到我们的输出的。
1、输入
与一般的NLP应用场景一样,我们先从使用词嵌入算法将每个输入单词转成一个个向量开始(这里以boxes的形式来代替词嵌入后的向量来展示我们的输入):
这里的每一个单词都被嵌入成了一个长度为512的向量。用4个boxes来表示这个向量。
这样的词嵌入仅仅会发生在最底层的encoder
,对于所有的encoder
而言,他们的输入都是一个将每一个单词都嵌入成512长度的向量的列表集合,但是不同的是,只有最底层的encoder
接受的输入是通过词嵌入算法转化而来的,而其他层的encoder
的输入都将是上一个encoder
的输出。而这个列表的大小是一个我们可设置的超参数,即我们的训练数据集中最长句子的长度。
将每一个单词嵌入我们的输入序列中之后,每个单词都会分别流经encoder
的两个层,得到encoder
的输出吗,如下图所示:
这里,我们开始看到Transformer的一个重要的属性——每个位置上的单词都会有在encoder中拥有自己的流经路径。
在self-attention
层中,这些路径存在互相依赖的关系。而FFNN
中的路径并不存在这些依赖关系,因此,在流经FFNN的路径中可以并行处理。接下去我们将以一个更短的句子作为输入,来看看在encoder
的内部到底发生了些什么。
正如我们前文所提及的,一个encoder
将会接收一个向量组成的列表来作为输入。encoder
将这个列表传入到self-attention
中来处理其中的词向量,然后将这些词向量输入到FFNN
中去,然后将每个输出r1,r2
作为下一个encoder
的输入:
2、self-attention
假设下面的句子是我们想要翻译的输入句子:
”The animal didn’t cross the street because it was too tired”
问题来了,句子中的it到底代表的是什么意思呢?它是指向street呢还是指向animal呢?这对于人类来说是一个很简单的问题,但是对于算法而言,这一点都不简单。
当模型处理单词it时,self-attention
会将它与animal联系在一起。当模型处理每个单词时(句子中的每个位置),self-attention
允许它在输入序列的其他位置寻找线索,这些线索可以帮助它更好地编码这个单词。如果你熟悉RNN,那么可以想想我们应该如何去探寻这个隐藏的联系,即将之前处理过的单词/向量的表示与当前正在处理的单词/向量的表示结合起来。self-attention
是Transformer用来将对其他相关单词的“理解”转化为我们当前正在处理的单词的方法。
记得查看Tensor2Tensor笔记本,在那里面您可以加载Transformer模型,并使用这个可视化来查看。
让我们首先来看看它是如何使用self-attention
来使用向量,然后进一步解释它是如何使用矩阵来进行计算的。
计算self-attention
的第一步是根据encoder
的每一个输入向量创建三个向量(在这个例子中,每一个输入向量是输入句子中的每一个被词嵌入的单词)。然后针对每一个单词,我们得到一个Query
向量,一个key
向量,一个value
向量。这些向量是根据我们的输入的词嵌入向量乘以我们刚才创建的三个参数可训练的矩阵得到的。
注意到,这些新的向量在维度上是小于词嵌入的向量的,他们的维度是长度为64的向量,而词嵌入或者encoder
输入/输出的向量长度是512。这些新的向量没有必要变得更小,这是一种为了让多头注意力的计算变得更加流畅的方式。