Transformer 是深度学习领域的阶段性成果或者说是具有里程碑意义的成果,最初用于处理自然语言处理任务,由 Vaswani 等人在 2017 年提出。目前在Bert和ChatGPT上几乎都有它的影子。它的核心特征是自注意力机制,这使得模型能够有效地处理序列数据中的长距离依赖问题。由于其出色的并行处理能力和优异的性能,Transformer 已成为当今自然语言处理领域的基石技术。
论文名:Attention is all you need
论文创新点包括:
1. 利用layer-normal:助于避免训练过程中的梯度消失问题,提高模型的稳定性。
2. 位置编码:由于 Transformer 不使用递归或卷积,它通过位置编码来加入序列中元素的位置信息。
3. 自注意力机制:它允许模型在处理序列的每个元素时同时考虑序列中的所有其他元素,从而捕捉元素之间的关系。
4. 多头注意力:Transformer 通过并行的多头注意力机制来捕获序列中不同位置的信息,增强模型的学习能力。
5. 代码能够并行处理。

我们将分模块来详细介绍下Transformer的处理流程。
一、Encoder部分
Encoder部分主要包括: input Embedding (输入嵌入) / Positional Encoding(位置编码) / Multi-Head Attention 多头注意力机制 / Feed Forward 前馈网络
1.1 input Embedding 层
input Embedding (输入嵌入层): 将输入的单词或者符号转换成固定维度的向量表示,使其能够被模型处理。(因为计算机本身并不能处理文字等信息,需要将其转为向量来处理。)

例如:输入句子是 "Hi how are you", input Embedding 层主要是将每个单词映射到长度相等的向量(这里的向量长度是等于3,但实际中一般较大,可以是225、1024等等,也可以自己设定)。
如下,这里我们就将单词"Hi"映射为长度为3的向量[0.1, 0.54, 0.29],[0.1, 0.54, 0.29]被称为嵌入向量。

1.2 Positional Encoding(位置编码)
由于Transformer模型本身不具备处理序列顺序的能力,但因为在文本信息的处理时,当前单词是跟前后单词有关联系的,因此需要在输入嵌入层( input Embedding)后加入位置编码(position encoding),以提供位置信息;方便后面的模型训练能够获取文本的位置信息,从而更精准地来进行模型训练。
位置编码通常是一组与嵌入向量维度相同的向量,它们通过特定的数学函数生成,并与嵌入向量相加,具体下面会说明。
位置编码的维度要和嵌入向量的维度一样的原因是因为位置编码是要和嵌入向量的维度相加,因此维度需要一致。
(这里的位置编码内容描述的比较多,如果已经掌握的可以直接跳到下一小节。)
首先,我们先看原文中的位置编码函数是如下定义的:

其中, dmodel是 input Embedding嵌入向量的维度,pos 是单词在序列中的位置,i 是嵌入向量中的维度索引。
举个栗子:假设输入数据为[Hi, how, are, you],通过 input Embedding 后将每个单词映射为3为的嵌入向量,如下:
[[0.1, 0.54, 0.29], [2.1, 3.8, 0.36], [1.5, 0.18, 2.2]]
接着,我们需要计算位置编码;那么对于单词 "Hi"(位置为0), "how"(位置为1),"are"(位置为2),"you"(位置为3)的位置编码分别是:

(PS:这里的约等于的值可能算的不是很对,大家不要介意,只要看大概是什么样的流程即可)
简单地说,当位置编码为偶数时使用sin函数,当位置编码为奇数时使用cos函数;对于位置2、3的编码以此类推。
从上可以得到:
-
第一个单词 "Hi", 它的位置编码 -> [0, 1, 0]
-
第二个单词 "how", 它的位置编码 -> [0.01745, 0.9998, 0.0000376]
-
第三个单词.......
然后,我们将位置编码向量加到嵌入向量上,得到位置感知的嵌入:
-
"Hi" 的最终嵌入 -> [0.1 + 0, 0.54 + 1, 0.29 + 0]
-
"how" 的最终嵌入 -> [2.1 +0.01745, 3.8 + 0.9998, 0.36 + 0.0000376]
-
......
Q:可能有人会问:为什么这里的位置编码要这么复杂,用sin和cons函数;为什么不直接使用one-hot编码?
A:原因有三:第一,One-hot编码的维度与序列的长度直接相关。在处理长序列时,如果序列长度较长(比如100),这将导致维度非常高,从而增加了计算复杂性和模型参数。相比之下,Transformer中的位置编码使用正弦和余弦函数,其维度仅与嵌入维度$$d_{model}$$相关,与序列长度无关,因此更加高效。
第二,用正弦和余弦函数作为位置编码允许模型更好地泛化到不同长度的序列。One-hot编码难以适应序列长度的变化,因为每个位置都有一个固定的、唯一的表示,这在处理比训练时更长的序列时会遇到问题。而基于正弦和余弦的位置编码通过数学函数生成,可以应对任意长度的序列。
第三,正弦和余弦位置编码通过其波形的性质可以让模型捕捉到单词之间的相对位置信息。举个例子,假设我们有一个很简短的句子:"Hello World",我们将其输入到Transformer模型中。为简化起见,我们假设模型的嵌入维度是2,这意味着每个单词的位置编码将是一个2维向量。假设位置0的位置编码是 [0, 1],位置1的位置编码是 [0.0001, 1];,模型可能会发现当两个词的位置编码在某一维度上的差异是特定模式时(如在我们的例子中,第一个维度的微小变化),这两个词在句子中可能具有特定的相对关系。这种机制使得Transformer能够处理序列数据,理解词语之间的关系,即使它的自注意力机制本身不直接处理序列顺序。
1.3 Multi-Head Attention (多头注意力机制)
对于多头注意力机制的理解,可以看下之前的推文。
1.4 Norm (层归一化)
Transformer中主要利用layer-normal层归一化,而并不是批归一化,这有助于避免训练过程中的梯度消失问题,提高模型的稳定性。
使用层归一化的原因在于:在处理自然语言任务时,序列的长度通常是变化的。层归一化因为是对单个样本中的所有特征进行归一化,所以能够更好地处理这种可变长度的情况。而批归一化则依赖于整个批次的数据统计,这在处理小批次或可变长度的序列时可能不太有效。此外,Transformer模型特别依赖于捕捉长期依赖关系(即序列中相隔较远的元素之间的关系),而层归一化有助于缓解训练过程中可能出现的梯度消失问题,从而更有效地学习这些长期依赖关系。
什么时候使用:在残差连接(Residual Connection)之后,Transformer模型中的每个子层都伴随一个残差连接,然后紧接着一个层归一化操作。具体来说,对于每个子层(例如自注意力或前馈网络),输入首先通过子层自身,然后将子层的输出与输入进行相加(残差连接),最后对这个相加的结果进行层归一化。
举个栗子。假设我们有一个神经网络,正在处理以下4个样本的小批次,每个样本有2个特征:
批次数据:
样本1: [1, 3]
样本2: [2, 4]
样本3: [3, 2]
样本4: [4, 1]
在批归一化中,我们对每个特征在整个批次中进行归一化。以第一个特征为例,其均值和标准差分别为:
均值 = (1 + 2 + 3 + 4) / 4 = 2.5
标准差 = sqrt(((1-2.5)² + (2-2.5)² + (3-2.5)² + (4-2.5)²) / 4) ≈ 1.29
然后,对每个样本的这个特征进行归一化:
归一化后的特征1:
样本1: (1 - 2.5) / 1.29 ≈ -1.16
样本2: (2 - 2.5) / 1.29 ≈ -0.39
样本3: (3 - 2.5) / 1.29 ≈ 0.39
样本4: (4 - 2.5) / 1.29 ≈ 1.16
层归一化操作中,对于同样的数据,如果我们使用层归一化,那么归一化是在每个样本内部进行的。
以样本1为例:
样本1: [1, 3]
对于样本1,我们计算其所有特征的均值和标准差:
均值 = (1 + 3) / 2 = 2
标准差 = sqrt(((1-2)² + (3-2)²) / 2) ≈ 1.41
然后对样本1的每个特征进行归一化:
归一化后的样本1:
特征1: (1 - 2) / 1.41 ≈ -0.71
特征2: (3 - 2) / 1.41 ≈ 0.71
对于其他样本,我们也会重复这一过程。
简单地说:(1)批归一化是跨样本对每个特征分别归一化,每个特征的归一化基于整个批次的统计数据。(2)层归一化是在每个样本内部进行的,每个样本的所有特征都根据该样本的统计数据进行归一化。
1.5 残差连接
在下面红色框里的残差连接,主要是将多头注意力机制的输出向量加到原始输入向量(添加过位置编码后的Embedding向量)上,在经过层归一化。

1.6 Feed Forward (前馈网络)
其实在Transformer原文中 Feed Forward 的全称是 Position-wise Feed-Forward Networks (点对点前馈神经网络,简称FFN)。
其实他就是两个全连接层:第一个全连接层将输入的维度扩展(例如,从512维扩展到2048维),接着是一个激活函数(通常是ReLU或GELU),然后是第二个全连接层,将维度从扩展的维度缩减回原始维度(例如,从2048维缩减回512维)。
前馈网络处理完后,先对其进行一个残差连接,再进行层归一化处理。
以上就是编码器部分的所有组件,编码器的作用主要是为了将输入编码为连续表示,并带有注意力信息;有助于帮助解码器在解码过程中关注输入中的重要词汇。当然,需要注意的是,可以将编码器堆叠 N 次,以进一步编码信息,其中每一层都有机会学习不同的注意力表示,从而提高Transformer的预测能力;如下图所示。

二. Decoder部分
写在前面。
Decoderde的任务是生成文本序列,需要注意的是解码器是自回归的,Decoder部分主要包括:Masked Multi-Head Attention 具有掩码的多头注意力机制 / Multi-Head Attention 多头注意力机制 / Feed Forward 前馈网络 / 分类器。
Q:什么是自回归?
A:在Transformer模型中,自回归任务指的是一种序列生成任务,其中模型在生成每个新元素时都依赖于之前已生成的序列。简言之,就是模型在预测下一个输出时,会使用到目前为止已经生成的所有输出作为上下文信息。这也是为什么ChatGPT的回答是一个字一个字往外蹦的原因。
Q:在详细介绍之前,我们需要先厘清Decoder部分的输入数据由哪些?看到图中Decoder部分的输入有个Outputs,难免会有些疑惑。
A:在Transformer模型中,解码器(Decoder)部分的输入通常包括两个主要部分:
1. 编码器的输出:图中可以看到编码器(Encoder)和解码器(Decoder)部分有一个连线,编码器(Encoder)的输出是解码器的一部分输入,这个应该也是最容易理解的来。在编码器-解码器架构中,编码器首先处理源序列(例如英文句子),产生一个包含序列信息的表示,然后传递给解码器。解码器利用这些信息来帮助生成目标序列(例如法文句子)。
2. 目标序列的前缀:这部分也就是大家在图中看到Decoder部分最下方的Outputs;这个前缀是目标序列当前已知的部分,解码器的任务是基于这个前缀生成序列的下一部分。例如,在机器翻译任务中,如果源语言句子是英文,目标语言句子是法文,那么解码器的输入就是目前已经生成的法文句子部分。当然,在Transformer模型的解码器刚开始工作时,并没有现成的序列前缀,通常会使用一个特殊的起始符号(例如"<sos>",代表“start of sequence”,也有的用的是"<bos>")作为序列的初始输入。这个起始符号的作用是表示序列的开始,为模型提供一个明确的起点。
例如,假设目标序列是“Hello World”,那么解码器的输入序列将是“<sos> Hello World”,其中“<sos>”是起始符号。
2.1 Output Embedding层 和 Positional Encoding(位置编码)
在Decoder部分,也可以看到有Embedding 和 Positional Encoding层,如下图所示。

在训练阶段,目标序列是已知的,整个已知的目标序列(包括起始符号,通常是“<sos>”)一次性转换为索引,然后通过嵌入层转换为密集的向量表示。然后,这些嵌入向量会被加上位置编码,以引入序列中单词的位置信息。加上位置编码的嵌入向量作为解码器的输入,用于模型的训练过程。
这里的目标序列可以理解为输入的序列,就说输入的文本数据。
2.2 Masked Multi-Head Attention(具有掩码的多头注意力机制)
由于在Decoder中的Embedding层 和 Positional Encoding层是对目标序列所有单词都进行了嵌入,但我们利用Transformer模型在生成序列时,是一个个单词往外蹦的;那么,确保在预测序列的特定位置时,模型只能使用到该位置之前的信息,其后面的信息就不能被注意力机制看到(也就是保证模型在训练的时候只能看到当前单词之前的单词,不能看到之后的),从而防止信息泄露。就需要想办法去遮挡后面的信息。

例如,我们在使用自注意力机制的时候,会计算当前单词a^2和其他单词(a^1,a^3,a^4)的关系,如下图所示。

但是呢,当我们在Transformer中的Decoder中开始需要生成序列时,当前位置需要预测的单词,只能允许和前面的信息有关,就比如我们要预测a^2是什么单词,那我们只能使用a^1和a^2的信息,并不能用到a^3和a^4的信息,如下图所示。

那如何在Transformer网络中去遮挡后面的信息呢?
主要是通过在自注意力机制中应用一个掩码(Mask)来实现的。准确地说,还是通过矩阵来进行操作。
例如,现在有段话:“i am fine”, 我们提前计算好了他们之间的注意力得分,如下图所示。(这里的<start>和之前的<sos>是一样的)

但当在计算单词 “am” 的注意力得分时,只能访问它自己和它之前的单词,就不能获得 “am”之后的单词信息,比如 “fine”,因为 “fine” 是之后才会生成的单词;如下图所示。

我们可以先解释下这张图:
-
当我们访问到<start>位置时,只能获取<start>和它自己的注意力得分,其他的不能获取
-
当我们访问到 I 位置时,只能获取 I 和 <start>, 以及 I 和 它自己的注意力得分,其他的不能获取
-
当我们访问到 am 位置时,只能获取 am 和 <start>, am 和 I, 以及 am 和 它自己的注意力得分,其他的不能获取。以此类推......
为了防止解码器看到未来的信息,就需要在已得到的注意力分数矩阵式加上一个mask机制(或者叫mask矩阵),如下图所示。

其中,-inf表示负无穷大。
当以上得到的橙色矩阵再经过sigmoid函数时,相对“当前单词”的“未来单词”的注意力得分就会变为0,这样就不会访问到未来信息。

2.3 Multi-Head Attention(多头注意力机制)
这里的多头注意力机制的原理是和Encoder部分一样的,具体计算过程可以参考Encoder部分。

但需要注意的是,这一部分主要是将解码器当前生成的序列与原始输入序列(经过编码器处理的)联系起来,用于生成下一个目标单词。这部分的注意力机制作用主要有两个:
- 连接源序列和目标序列:
通过关注编码器的输出,解码器可以根据需要从源序列中提取相关的上下文信息;
- 动态关注不同部分:
同时,在解码过程中,模型可能会选择关注输入序列的不同部分。
-
举个栗子: 假设我们正在进行英译法的机器翻译任务。给定一个英文句子(比如 "The cat sits on the mat"),经过编码器处理后,解码器开始逐步生成法文翻译。
-
当解码器准备生成下一个法文词时,不带掩码的编码器-解码器注意力机制会参考整个英文句子的编码(Encoder的结果)表示。
-
这个机制允许解码器在生成每个法文词时都能够根据需要关注英文句子中的相应部分,比如在生成“le chat”(猫)时,可能会特别关注“the cat”的编码表示。
2.4 Feed Forward(前馈网络)
参考Encoder部分的 Feed Forward 。
2.5 分类器
最后,由一个线性层和一个softmax来得到单词概率。

2.6 生成序列停止
不知道大家有没有注意一个问题:Transformer模型并没有定义结果的输出长度,那整个序列就会一直生成下去。那程序什么时候停止呢?
就是在模型输出"<eos>"(代表“end of sequence”)时停止。
三. 总结
这一部分,我对Transformer中的每个部分的作用做了一个总结,仅供参考。

如何系统的去学习大模型LLM ?
大模型时代,火爆出圈的LLM大模型让程序员们开始重新评估自己的本领。 “AI会取代那些行业?”“谁的饭碗又将不保了?”等问题热议不断。
事实上,抢你饭碗的不是AI,而是会利用AI的人。
继科大讯飞、阿里、华为等巨头公司发布AI产品后,很多中小企业也陆续进场!超高年薪,挖掘AI大模型人才! 如今大厂老板们,也更倾向于会AI的人,普通程序员,还有应对的机会吗?
与其焦虑……
不如成为「掌握AI工具的技术人」,毕竟AI时代,谁先尝试,谁就能占得先机!
但是LLM相关的内容很多,现在网上的老课程老教材关于LLM又太少。所以现在小白入门就只能靠自学,学习成本和门槛很高。
针对所有自学遇到困难的同学们,我帮大家系统梳理大模型学习脉络,将这份 LLM大模型资料 分享出来:包括LLM大模型书籍、640套大模型行业报告、LLM大模型学习视频、LLM大模型学习路线、开源大模型学习教程等
一、LLM大模型经典书籍
AI大模型已经成为了当今科技领域的一大热点,那以下这些大模型书籍就是非常不错的学习资源。

二、640套LLM大模型报告合集
这套包含640份报告的合集,涵盖了大模型的理论研究、技术实现、行业应用等多个方面。无论您是科研人员、工程师,还是对AI大模型感兴趣的爱好者,这套报告合集都将为您提供宝贵的信息和启示。(几乎涵盖所有行业)

三、LLM大模型系列视频教程

四、LLM大模型开源教程(LLaLA/Meta/chatglm/chatgpt)

这份 LLM大模型资料 包括LLM大模型书籍、640套大模型行业报告、LLM大模型学习视频、LLM大模型学习路线、开源大模型学习教程等
😝有需要的小伙伴,可以 下方小卡片领取🆓↓↓↓
1325

被折叠的 条评论
为什么被折叠?



