无论是想怎样学习大模型,transformer都是一个绕不开的话题。transformer的出现彻底改变了nlp领域,进一步推动了大模型的产生,可以说,transformer就是大模型开发的鼻祖。
可能只通过说大家会有些不理解。大家可以看下方的大语言模型进化树。
![](https://i-blog.csdnimg.cn/direct/6630618ae1c6499fa7c59f85d6e788db.jpeg)
上述进化树中,同一分支上的模型关系更近。基于transformer的模型显示为非灰色颜色:仅解码器模型显示为蓝色分支,仅编码器模型显示为粉红色分支,而编码器-解码器模型显示为绿色分支。时间轴上模型的垂直位置代表其发布日期。开源模型由实心方块表示,而闭源模型由空心方块表示。右下角的堆叠条形图显示来自各公司和机构的模型数量。
通过上方进化树,相信大家对transformer模型的地位便有所了解了。
1. transformer简介
为了更深入的了解transformer模型,我们首先从transformer的诞生聊起吧。transformer在2017年由Vaswani等人首次提出,它摒弃了之前流行的循环神经网络和卷积神经网络的架构,引入了自注意力机制( Self-Attention),显著提高了处理序列数据的能力和效率。 transformer模型的这种设计使其在处理长距离依赖问题时, 相比于传统的循环神经网络和长短期记忆网络(LSTM)表现得更加出色,至此, 开启了NLP技术的新篇章。
循环神经网络是一类用于处理序列数据的神经网络,能够在其内部维持一个状态, 用于捕捉序列中时间步之间的依赖关系。
卷积神经网络是一种深度学习模型, 特别适用于处理具有网格状拓扑结构的数据, 如图像,它通过使用卷积层来自动提取和学习空间特征。
transformer的核心思想是通过自注意力机制(self-attention mechanism),允许输入序列中的每个元素直接交互, 从而学习它们之间的关系。这一机制的引入, 使得模型能够在并行处理时捕获序列内的复杂依赖关系, 显著提高训练速度和效果。
模型主要由以下几个部分组成:
(1) 输入( Input): Transformer模型接收的输入通常是一系列经过嵌入( Embedding) 处理的词向量, 这些词向量能够代表输入文本的语义信息。输入部分还包括位置编码( Positional Encoding), 这是为了使模型能够理解单词在句子中的位置。
(2)编码器( Encoder):编码器由多个相同的层堆叠而成, 每一层包含两个主要的子层, 分别为自注意力机制层和前馈神经网络( Feed- Forward Neural Network, FFNN)。 自注意力机制层帮助编码器理解不同单词之间的关系,而前馈神经网络则负责在更高的抽象级别上处理每个单词。
(3)解码器( Decoder):解码器的结构与编码器类似, 但在自注意机制和前馈神经网络之间引入了一个额外的注意力层(编码器-解码器注意力),它用于聚焦编码器的输出。这样设计是为了在生成文本时, 解码器能够参考输入序列的每个部分, 从而更精准地预测下一个词。
(4)输出( Output):解码器的输出经过一个线性层和 softmax层处理, 转换成为最终的预测结果, 通常是下一个词的概率分布。
transformer模型通过其独特的自注意力机制和编解码器结构, 在 NLP任务中取得了巨大的成功。它的设计不仅优化了训练过程,还提高了模型处理长距离依赖和复杂序列模式的能力。如今, 基于 Transformer架构的模型(如BERT、GPT等)已经广泛应用于文本翻译、文本生成、情感分析等多个领域, 极大地推动了AI技术的发展。
![](https://i-blog.csdnimg.cn/direct/ea285dc7c6b2409a9bd38328b153d413.png)
在下文中, 将逐一深入探讨 transformer模型的各个组成部分, 并解析它们是如何协同工作以处理复杂的语言理解和生成任务的。
2. 输入预处理
声明:这里是帮没有nlp基础人速通,想要系统学习nlp可以看我其nlp专栏
这里将重点介绍输入预处理过程,这是确保数据能够被模型有效理解和处理的关键步骤。输入预处理涵盖了从原始文本到模型能够理解的数字化表示的转换过程,包括文本预处理、数据分词、嵌入矩阵构建、词元向量化以及位置编码等关键环节。
2.1 文本预处理
文本预处理是将原始文本转换成适合机器学习模型处理的格式的第一步,它对提高模型的性能和效果具有至关重要的作用。在处理自然语言数据时,可能面临着诸如噪声数据、不规则格式和语言多样性等挑战。有效的文本预处理不仅能够降低这些问题带来的影响,还能够增强模型对文本中信息的理解和捕捉能力。
以下是文本预处理的关键步骤:
(1) 清洗文本。
1)去除无用字符:从文本中去除无意义的字符, 如特殊符号、标点符号、数字(除非数字对上下文意义重大) 以及其他非文本元素(如HTML 标签)。
2)大小写统一:将所有字符转换为小写(或大写),以减少词汇的变体数量, 这有助于模型更好地学习和理解文本。
3) 空白字符处理:标准化空白字符, 去除多余的空格、制表符和换行符, 以保持文本的一致性。
(2)文本标准化。
1)词形还原( Lemmatization):将单词还原为其词根形式( Lemma), 以确保模型能够将不同形式的单词识别为相同的单词。例如, running、 ran 和 runs都会被还原为 run。
2)词干提取( Stemming):通过去除单词后缀将单词简化到其词干形式, 虽不如词形还原精确, 但处理速度更快。如 fishing、 fished都归结为 fish。
3)停用词去除:去除那些在文本中频繁出现但对于理解文本主要意义贡献不大的单词, 如“的”“是”“在”等, 这有助于模型将注意力集中于更有意义的词汇。
(3)文本分割。
将文本分割成单独的句子,这对于处理需要理解文本结构的任务尤为重要。
通过这些步骤, 文本数据被清洗和标准化, 转换为更适合深度学习模型处理的形式。文本预处理不仅有助于提高模型的训练效率和性能,也是确保模型能够理解和处理自然语言数据的关键。在接下来的小节中, 将详细探讨如何对这些预处理后的文本进行分词。
2.2 数据分词
数据分词是将文本预处理的结果进一步细分为模型能够理解和处理的最小单元, 称为“词元”( tokens)。这个步骤是NLP中的一个基本过程, 它直接影响模型的学习效果和处理能力。transformer模型通过一种灵活而高效的分词机制来处理各种语言和文本, 这种机制通常涉及基于词、子词或字符的分词方法。在下面,将探讨数据分词的不同策略及其对 transformer模型性能的影响。
1. 基于词的分词
基于词的分词是最直观的方法,它将文本直接分割为独立的单词。这种方法简单直接, 但面临词汇表大小膨胀和未知词汇( Out- Of- Vocabulary, OOV)问题。当遇到未见过的单词时,模型将难以处理, 这限制了其泛化能力。
2.基于子词的分词
基于子词的分词方法旨在克服基于词分词的局限性。它通过分解单词为更小的有意义的单元(如词根、前缀、后缀),来构建更加紧凑和高效的词汇表。这种方法能够有效处理未知词汇,并提高模型对新单词的泛化能力。 Byte Pair Encoding(BPE)算法是实现子词分词的一种流行方法,它通过统计最频繁的字符或字符对并将它们合并为一个单一的词元来动态构建词汇表。
3.基于字符的分词
基于字符的分词将文本分解为单个字符,这是最细粒度的分词方法。虽然这种方法产生的词汇表大小固定且较小,但它忽略了单词内部的语义结构, 可能会导致模型需要更长的学习时间来理解字符组合的含义。
在实践中, transformer模型通常采用基于子词的分词方法,这种方法为处理自然语言的多样性和复杂性方面提供了最佳的平衡。通过细粒度的分词, 模型能够更有效地捕捉语言的细微差别,并提高对新颖文本的处理能力。此外,子词分词减少了模型面临的OOV 问题, 使得模型能够更好地处理多语言环境下的文本数据。
数据分词作为输入预处理的一个关键步骤, 直接影响 transformer模型的性能和效率。通过选择适当的分词策略, 可以显著提高模型对文本的理解深度和处理灵活性。基于子词的分词方法,特别是BPE算法, 在实践中被广泛应用, 因为它结合了基于词和基于字符分词方法的优点,为 transformer模型处理复杂和多样的语言数据提供了坚实的基础。
2.3 嵌入矩阵构建
在完成文本的预处理和数据分词之后,下一步是将分词后的词元转换为模型可以理解的数值形式。这一转换过程通过构建嵌入矩阵( Embedding Matrix) 完成, 它是将离散的文本数据映射到连续的向量空间中的关键技术。嵌入矩阵不仅能够为每个词元提供一个唯一的数值表示,还能捕捉词元之间的复杂语义关系。本小节将探讨嵌入矩阵的构建过程及其在 transformer模型中的应用。
嵌入矩阵是一个高维空间中的向量集合,其中每个向量代表词汇表中的一个词元。这些向量通常是通过训练过程学习得到的, 以便能够捕捉词元之间的语义相似度。例如, 在嵌入空间中,语义相近的词元(如“国王”和“王后”) 的向量表示会彼此接近。
嵌入向量的维度(即向量的长度)是一个重要的超参数, 它决定了嵌入空间的复杂度和表达能力。维度过小可能无法充分捕捉词元之间的细微差别,而维度过大则可能导致计算效率降低和过拟合问题。
超参数是在开始学习过程之前设置的参数, 它们控制着训练过程的行为, 如学习率、隐藏层的数量, 而不是通过训练数据在学习过程中学习得到的。
嵌入矩阵在训练开始前需要被初始化。常见的初始化方法包括随机初始化和预训练嵌入的使用。预训练嵌入, 如GloVe( Global Vectors for Word Representation) 或 Word2Vec, 可以为模型提供一个良好的起点, 尤其在数据较少的情况下。
预训练嵌入是一种通过在大型文本数据集上预先训练得到的词向量,能够捕捉和表示单词之间的语义关系, 可直接用于提高各种自然语言处理任务的模型性能。
在模型训练过程中, 嵌入向量会根据任务(如文本分类、机器翻译)的目标函数进行调整,以更好地表示词元之间的语义关系。
(1)维度选择。在transformer模型中,嵌入矩阵扮演着至关重要的角色。模型的输入是通过查找嵌入矩阵中对应的向量来实现的,这些向量随后会被送入模型的编码器和解码器结构中进行处理。
(2)初始化。 transformer模型通过对嵌入向量进行细致的调整, 能够捕捉词元之间的复杂语义关系, 提高模型处理自然语言的能力。
(3)训练。 transformer模型将位置编码添加到词元的嵌入向量中, 以引入序列中词元的顺序信息。这一步骤对于模型理解文本结构和上下文关系至关重要。
下面通过一个简单的例子来展示这一过程。
一个词汇表( Vocabulary) 包含五个词元:[“国王”“王后”“男人”“女人”“孩子”], 将这些词元映射到一个二维向量空间中(即嵌入向量的维度为2)。这意味着每个词元将由一个两个元素组成的向量表示。下面是构建嵌入矩阵的步骤。
1)初始化嵌入矩阵。初始化一个嵌入矩阵。通过随机初始化, 得到的数据见下表。
词元 | 维度1 | 维度2 |
国王 | 0.2 | 0.8 |
王后 | 0.1 | 0.9 |
男人 | -0.1 | -0.2 |
女人 | -0.2 | -0.1 |
孩子 | 0.0 | 0.0 |
这个矩阵的每一行代表一个词元的嵌入向量。
2)训练嵌入向量。通过模型训练, 嵌入向量将根据词元之间的语义相似度进行调整。例如,“国王”和“王后”在语义上更接近,而“男人”和“女人”也是如此, 那么训练过程可能会使这些词元的嵌入向量在嵌入空间中彼此靠近。训练后的嵌入矩阵见下表。
词元 | 维度1 | 维度2 |
国王 | 0.5 | 0.5 |
王后 | 0.6 | 0.4 |
男人 | -0.4 | -0.5 |
女人 | -0.5 | -0.4 |
孩子 | 0.1 | 0.1 |
在这个例子中,可以看到“国王”和“王后”的向量在嵌入空间中比较接近,反映了它们在语义上的相似性。同样,“男人”和“女人”的向量也彼此接近,而“孩子”的位置则相对独立,表明其语义与其他词元的区别。
比较接近通常是指在嵌入空间中,词向量之间的距离较短, 这通过计算向量之间的余弦相似度、欧几里得距离或曼哈顿距离等数学方法来量化。
嵌入矩阵的构建是连接文本数据与 transformer模型的桥梁,它使模型能够以数学形式处理和理解自然语言。通过精心设计的嵌入层,transformer模型能够有效地捕捉和利用词元之间的语义关系, 为实现复杂的语言处理任务提供坚实的基础。在嵌入向量的帮助下, transformer模型能够进行深入的语言理解和生成, 展现出在多种NLP任务上的卓越性能。
2.4 词元向量化
在NLP中,将词元转换成数值表示是理解和处理文本数据的基础。词元向量化是这一转换过程的核心,它涉及将文本中的每个词元映射到高维空间中的向量。这些向量不仅代表了词元的身份, 还能捕捉词元之间的语义关系。接下来我们将探讨词元向量化在transformer模型中的实现和重要性。
词元向量化涉及以下几个关键步骤。
(1)词汇表构建:基于训练数据, 构建一个包含所有唯一词元的词汇表。每个词元在词汇表中有一个唯一的索引。
(2)向量映射:使用嵌入矩阵, 将每个词元映射到高维空间中的一个向量。这个过程通过查找词元在词汇表中的索引, 然后从嵌入矩阵中选择对应的向量来完成。
(3)向量优化:在模型的训练过程中,不断调整嵌入矩阵中的向量, 以更好地反映词元之间的语义和语法关系。
基于上的例子来进一步探讨词元向量化的过程。目标是将文本中的每个词元转换成对应的向量表示。这一过程包括以下几个关键步骤。
首先, 需要根据训练数据构建一个词汇表。在上面的例子中, 词汇表已经给出, 包含五个唯一词元:[“国王”“王后”男人”“女人”“孩子”]。在实际应用中, 词汇表的构建通常是通过分析整个训练数据集来完成的, 以确保覆盖所有的词元。每个词元在词汇表中拥有一个唯一的索引, 例如:
1 国王: | 0 |
2 王后: | 1 |
3 男人: | 2 |
4 女人: | 3 |
5 孩子: | 4 |
接着,使用嵌入矩阵将每个词元映射到高维空间中的一个向量。这个过程通过查找词元在词汇表中的索引, 然后从嵌入矩阵中选择对应的向量来完成。
如果要映射词元“国王”, 首先找到它在词汇表中的索引(0),然后选择嵌入矩阵中对应索引的向量([0.5,0.5])作为它的向量表示。
在 transformer模型中,词元向量化是处理输入数据的第一步。模型通过将输入文本中的每个词元转换为向量, 进而进行复杂的自注意力和前馈神经网络计算。这些向量化的词元能够有效地传递给模型丰富的语义信息, 为后续的处理步骤提供基础。
通过将词元转换为向量, 模型能够利用这些数值表示进行深入的语言理解和生成。这一过程不仅提高了模型的处理效率, 还增强了模型对文本语义的捕捉能力。随着训练的进行, 模型在这些向量上学习到的信息使得其在多种NLP 任务上表现出色。
2.5 位置编码
在处理自然语言时, 词序(即词在句子中的位置) 提供了重要的上下文信息, 有助于理解句子的意义。然而, 传统的词元向量化过程仅关注词元本身的语义表示(就像“我打你”和“你打我”对于模型来说是完全相同的), 却忽略了词元在文本中的位置关系。transformer模型通过引入位置编码( Positional Encoding) 来解决这一问题, 有效地将词序信息融入模型的输入表示中。
transformer模型的自注意力机制允许模型在处理每个词元时考虑到句子中的所有其他词元,但这种机制本身并不理解词元的顺序。如果没有位置信息, 模型就会丧失处理词序相关任务的能力,如理解“ not good”和“ good not”的区别。位置编码的引入, 使得模型能够学习到词元不仅仅基于其语义的关系, 还包括它们在句子中的相对或绝对位置关系。
transformer模型通过为每个词元的向量添加一个位置向量来实现位置编码, 这个位置向量有多种生成方式, 最常见的是基于正弦和余弦函数的方法。
对于每个位置 pos和每个维度i, 位置编码 PosEnc( pos,2i) 使用正弦函数, PosEnc( pos,2i+1)使用余弦函数。这样做的目的是让每个位置的位置编码向量能够在多维空间中唯一表示, 并且对于任意固定的偏移k, PosEnc( pos+k)能够通过 PosEnc( pos)线性表示, 这有助于模型理解位置间的相对关系。
为了更好地理解位置编码( Position Encoding) 在 transformer 模型中的应用, 下面可通过一个具体的例子来展示这一过程。对一个简单的句子进行编码, 该句子由四个词元组成, 例如,“我爱自然语言”。在该例子中,将展示如何为这些词元生成位置编码向量, 并将其添加到词元的嵌入向量中。
(1)词元嵌入。设定已经有每个词元的嵌入向量, 且嵌入向量的维度为4(为了简化示例)。这些嵌入向量是通过之前讨论的嵌入矩阵获得的。嵌入向量如下。
1 我: | [0.1, 0.2, 0.3, 0.4] |
2 爱: | [0.5, 0.6, 0.7, 0.8] |
3 自然: | [0.9, 1.0, 1.1, 1.2] |
4 语言: | [1.3, 1.4, 1.5, 1.6] |
(2)位置编码计算。位置编码使用基于正弦和余弦函数的方法生成。对于句子中的每个位置 pos(从0开始) 和每个维度i, 可以按照以下公式计算位置编码。
对于偶数维度2i:
对于奇数维度2i+1:
其中, 是嵌入向量的维度, 这里为4。
(3)计算。要为“我”(位置0)和“爱”(位置1)计算位置编码, 可以根据上述公式进行计算, 其中,=4。
1)位置0的位置编码向量(根据公式计算):[0.0, 1.0,0.0, 1.0]。
2)位置1的位置编码向量类似, 但会有所不同, 以反映不同的位置。
(4)添加位置编码到词元嵌入。将位置编码向量添加到相应词元的嵌入向量中。例如,“我”的嵌入向量是[0.1,0.2,0.3,0.4], 且其位置编码是[0.0,1.0,0.0,1.0], 则最终向量将是这两个向量的和, 即[0.1,1.2,0.3,1.4]。
通过这种方式,每个词元不仅携带了自己的语义信息, 还包含了其在句子中位置的信息。将位置编码与词元向量相加后的结果作为 transformer 模型的输入,使模型能够同时理解词元的内容和它们在句子中的排列顺序。
位置编码极大地增强了 transformer模型处理序列数据的能力,这使得模型不仅能够捕捉到词元之间的语义关系,还能理解这些关系如何随着词元在句子中位置的不同而改变。例如, 在处理语言中的时态、语态、修饰语结构等方面,位置信息的引入提供了必要的上下文支持。
位置编码是transformer模型的一个创新特点,它解决了模型在处理自然语言时对词序信息的需求。通过将位置信息与词元的语义表示相结合,模型能够更全面地理解文本,为进行更复杂的语言理解和生成任务提供了基础。位置编码的引入不仅提升了 transformer 模型在多种NLP 任务上的表现,也体现了在设计深度学习模型时考虑数据的内在结构的重要性。
3. 编码处理器(Bert)
transformer模型的编码器构成了模型处理输入数据的基础部分。编码器的设计使其能够处理复杂的序列数据, 捕获序列内部的细粒度依赖关系。它通过一系列的层来实现, 每一层都包含自注意力机制、残差连接( Residual Connection )、层归一化( Layer Normalization)以及前馈神经网络等关键组件。
以下是编码器的执行步骤, 详细解释了从自注意力机制开始的过程。
编码器的首要步骤是使用自注意力机制计算输入序列中所有单元之间的关系, 这一机制允许模型在处理每个单元时, 能够考虑到序列中的所有其他单元, 从而捕获它们之间的上下文关系。实现自注意力机制涉及以下三个主要步骤。
(1)计算查询( Query)、键( Key) 和值( Value) 向量:这些向量是通过对输入向量应用不同的线性变换得到的。
(2)计算注意力分数:模型计算查询向量与所有键向量之间的点积, 以得到注意力分数,表示各单元之间的关联度。
(3)加权值向量求和:使用这些注意力分数对值向量进行加权求和, 得到最终的输出向量。
值得注意的是, 编码器中采用多头注意力机制, 即将查询、键、值向量分割为多个头, 然后并行计算, 最后将结果合并。这使得模型能够在不同的表示子空间中捕获信息, 提高了处理效率和效果。
自注意力机制的输出首先通过残差连接,即直接将输入加到输出上, 然后进行层归一化。这一设计帮助避免了在深层网络中常见的梯度消失问题, 并有助于稳定训练过程。
自注意力机制和残差连接处理后的输出接着传递给前馈神经网络。该网络对每个位置的表示进行独立处理, 但对不同位置使用相同的参数。这一步骤通常包含两次线性变换和一个激活函数。
再次应用残差连接和层归一化, 步骤与自注意力机制相似, 前馈神经网络的输出也会经过残差连接和层归一化处理。这进一步增强了模型的学习能力,确保了信息在编码器各层中的有效流动。
3.1 编码器自注意力机制
在 transformer模型的编码器中,自注意力机制发挥着核心作用。它允许编码器在处理每个输入词元时,考虑到整个输入序列的所有词元。这种机制的引入显著提高了模型处理复杂文本、理解长距离依赖关系的能力。我们接着探讨编码器的自注意力机制如何工作,以及它对于提升模型性能的重要性。
自注意力机制通过计算输入序列中每个词元对于其他所有词元的注意力分数来工作, 这个过程可以分解为以下几个步骤。
(1)向量表示:首先, 对于输入序列中的每个词元, 模型通过嵌入层将其转换为向量表示。然后, 对每个词元向量应用三组不同的权重矩阵, 生成对应的查询、键和值向量。
权重矩阵是在神经网络中用于转换输入数据的参数集合, 通过与输入向量进行矩阵乘法操作,生成特定于不同任务(如查询、键、值向量生成)的新向量表示。
(2)注意力分数计算:对于序列中的每个词元,计算其查询向量与其他所有词元键向量的点积, 以得到注意力分数。这些分数表示每个词元对序列中其他词元的重要性。
(3)分数标准化:通过应用 Softmax函数对注意力分数进行标准化, 确保分数总和为1。这一步骤使得模型能够根据每个词元对序列中其他词元的相关性分配注意力。
(4)加权和计算:将标准化后的注意力分数与值向量相乘, 对所有词元进行加权求和, 以生成每个词元的输出向量。这一步骤产生的向量融合了整个序列的信息,反映了每个词元在序列中的上下文相关性。
自注意力机制的设计使得 transformer模型具有以下几个显著优势。
1)全局上下文理解:自注意力使模型能够在处理每个词元时, 充分考虑到整个输入序列的信息, 从而更好地理解词元间的上下文和关系。
2) 并行计算:与基于循环的模型相比,自注意力机制的计算可以高度并行化, 显著提高了处理效率。
3)长距离依赖:通过直接计算序列中任意两个词元间的关系, 自注意力机制有效地解决了长距离依赖问题, 这在传统的序列处理模型中是一个挑战。
编码器的自注意力机制允许模型在处理每个词元时,全面考虑整个序列的信息, 显著提升了模型对文本的理解能力。这一机制不仅加深了模型对序列内部复杂关系的捕捉,还提高了处理速度和效率, 使 transformer模型在多种NLP 任务上都表现出色。
3.2 自注意力机制的查询、键、值向量
自注意力机制的核心在于通过查询、键和值向量的互动来实现对输入序列的编码, 这一过程使得每个词元能够根据与其他词元的关系确定其上下文相关的表示。这里将介绍查询、键和值向量的概念、生成方式, 以及它们在自注意力机制中的作用。
在自注意力层中, 输入序列中的每个词元首先被转换为一个固定大小的向量表示, 通常是通过词嵌入得到的。接着, 这些向量通过三个不同的线性变换生成对应的查询、键和值向量。
1) 查询向量:代表了要评估的目标词元, 用于与序列中其他词元的键向量进行匹配。
2)键向量:与查询向量配对, 用于序列中每个词元的标识, 对应查询时的匹配对象。
3)值向量:一旦查询和键的匹配程度(即注意力权重)被确定, 值向量就用于计算最终的输出表示。
这三组向量是通过对输入向量应用不同的权重矩阵(这些矩阵是模型参数, 通过训练学习得到)得到的, 使得模型能够在不同的子空间中捕捉序列的不同特征。
为了更具体地说明如何从输入序列的词嵌入向量计算得到查询、键和值向量,下面通过一个具体示例进行说明。一个输入序列是“我爱”, 并且已经通过词嵌入得到了这些词元的向量表示。这次, 将引入不同的权重矩阵来生成查询、键和值向量。
(1) 输入词嵌入向量。
“我”: [1, 0]
“爱”: [0, 1]
(2)权重矩阵。为了简化, 设定每个权重矩阵是二维矩阵(实际应用中, 这些矩阵是通过训练学习得到的)。
查询权重矩阵:。
键权重矩阵:。
值权重矩阵:。
(3)计算查询、键和值向量。对于每个词嵌入向量, 将应用相应的权重矩阵来生成查询、键和值向量。具体的计算方法是将每个词嵌入向量与每个权重矩阵相乘。例如, 对于词元“我”的嵌入向量[1,0],其查询、键和值向量分别为:
1)查询向量[1,2]。
2)键向量[2,3]。
3)值向量[5,6]。
对于“爱”的嵌入向量[0, 1],其查询、键和值向量分别为:
1)查询向量[3,4]。
2) 键向量[4,5]。
3)值向量[7,8]。
查询、键和值向量共同工作,为模型提供了一种灵活的方式来编码和处理序列数据。查询、键和值向量使模型能够以高度灵活和效率的方式处理序列数据, 捕捉词元之间的复杂关系。通过这种机制, 每个词元能够获得一个丰富的上下文相关表示, 极大地提升了模型对文本的理解能力。自注意力机制这一独特设计是 transformer模型在多种NLP 任务中取得显著成绩的关键因素之一。
3.3 自注意力机制计算注意力分数
自注意力机制的核心环节之一是计算注意力分数, 这一过程决定了序列中的每个词元在当前词元的表示中的相对重要性。这些分数反映了词元间的相互影响力度,是构建深度语言理解的基石。本小节将探讨如何用自注意力机制计算这些注意力分数, 并分析其对模型性能的影响。
在自注意力机制中, 每个词元的查询向量与序列中所有词元的键向量进行点积操作, 以计算注意力分数。这一计算过程可以分解为以下几个步骤。
(1)向量准备:从输入序列生成查询、键和值向量, 这是通过将输入词元的嵌入表示分别乘以查询、键、值的权重矩阵完成的。
(2)点积计算:对于序列中的每个词元,计算其查询向量与所有键向量的点积, 从而得到一组原始的注意力分数。这些分数衡量了在特定查询下,序列中每个词元的相关性程度。
(3)缩放操作:点积结果通常会被缩放, 具体是除以键向量维度的平方根。这一步骤有助于避免在 Softmax归一化过程中出现梯度消失或爆炸的问题, 从而提高模型的稳定性和训练效率。
梯度爆炸是指在神经网络的训练过程中, 梯度的大小急剧增加至非常大的数值, 导致权重更新过大。
接着使用前面的例子, 其中包含两个词元, 分别为“我”和“爱”, 并已经计算出它们的查询、键和值向量。
(1) 向量准备。每个词元的查询、键和值向量。
“我”的查询向量: [1, 2], 键向量: [2, 3], 值向量 : [5, 6]
“爱”的查询向量: [3, 4], 键向量: [4, 5], 值向量: [7, 8]
(2)点积计算。对于序列中的每个词元,计算其查询向量与所有键向量的点积。这里有四个点积需要计算:
点积是通过将两个向量的对应元素相乘后再求和来计算的, 即对于两个向量a和b, 点积为 .
“我”的查询向量与“我”的键向量的点积
“我”的查询向量与“爱”的键向量的点积
“爱”的查询向量与“我”的键向量的点积
“爱”的查询向量与“爱”的键向量的点积
(3)缩放操作。每个点积的结果将被缩放,具体操作是除以键向量维度的平方根(在这个例子中是)。根据上述计算, 得到了缩放后的点积结果如下
“我”的查询向量与“我”的键向量的点积缩放结果: 5.66
“我”的查询向量与“爱”的键向量的点积缩放结果: 9.90
“爱”的查询向量与“我”的键向量的点积缩放结果: 12.73
“爱”的查询向量与“爱”的键向量的点积缩放结果: 22.63
通过这种方式计算得到的注意力分数使得模型在处理每个词元时,能够综合考虑整个序列的信息。这不仅增强了模型对于长距离依赖的捕捉能力,也使得模型能够更精准地理解和反映词元间的复杂关系。此外, 这种计算方法的并行性质大大提高了处理效率, 是transformer模型在多项任务上表现出色的关键因素之一。
3.4 自注意力机制 Softmax 标准化
在 transformer模型的自注意力机制中, Softmax标准化确保了模型能够根据每个词元对其他词元的相对重要性分配“注意力”。通过这一过程,模型生成的是一个概率分布, 指示了在给定上下文中每个词元的重要程度。这里将探讨 Softmax标准化的作用、过程及其对于模型性能的影响。
Softmax函数可以将自注意力机制中计算得到的原始注意力分数转换为概率分布, 其满足以下两个条件:
非负性:每个元素的输出值在0到1之间, 表示概率。
归一性:所有元素的输出值之和为1, 表示完整的概率分布。
这使得模型能够清晰地判断在处理每个词元时,序列中的其他词元相对于当前词元的重要性。在自注意力机制中, Softmax标准化应用于缩放后的注意力分数上, 具体步骤如下。
(1)应用 Softmax函数:对于给定词元的每个注意力分数, 应用 Softmax函数, 计算方式为将e的指数应用于每个分数, 然后除以所有e的指数之和。
其中, score是词元i缩放后的注意力分数, 分母是所有词元的缩放分数的e指数之和。
(2)生成概率分布: Softmax函数的输出为一个概率分布, 其中, 每个值表示在给定查询词元的上下文中, 对应键词元的相对重要性。
基于3.3例子的数据,可以得到通过 Softmax标准化处理后的注意力权重如下。
对于“我”的查询:
对“我”的注意力权重:0.014。
对“爱”的注意力权重:0.986。
对于“爱”的查询:
对“我”的注意力权重:0.00005。
对“爱”的注意力权重:0.9999。
Softmax标准化是自注意力机制中不可或缺的一环, 它有几个关键作用。
区分重要性:通过转换为概率分布, 模型能够更清晰地区分序列中哪些词元对当前词元更重要, 哪些较不重要。这有助于模型构建更准确的上下文表示。
增强模型的泛化能力: Softmax标准化使得模型在处理不同类型的输入时更加灵活,能够适应各种长度和结构的序列。
促进梯度流动: Softmax函数的归一化特性有利于梯度在模型中的流动, 避免了梯度消失或爆炸的问题, 从而提高了模型的训练稳定性和效率。
Softmax标准化通过将注意力分数转换为概率分布, 使得模型能够在处理每个词元时做出更加细致和准确的判断。这一步骤不仅提高了模型对序列内部结构的理解能力, 也增强了模型的训练稳定性和泛化性能, 是实现高效深度语言理解的关键环节。
3.5自注意力机制加权值向量
在 transformer模型的自注意力机制中, 加权值向量的计算是生成最终输出表示的关键步骤。经过 Softmax标准化的注意力分数指示了序列中各个词元对当前处理词元的重要性, 基于这些分数进行的加权和操作产生了融合全局上下文信息的词元表示。下面将探讨自注意力机制如何通过加权值向量来实现这一过程, 以及其对模型性能的影响。
加权值向量的计算包含以下几个步骤。
(1)应用注意力权重:对于序列中的每个词元, 将其对应的 Softmax标准化后的注意力分数应用于所有值向量。这一步骤通过将每个值向量乘以其对应的注意力权重来完成, 从而得到加权的值向量。
(2)求和得到输出:对于每个词元, 将其所有加权的值向量求和, 生成一个综合了整个输入序列信息的输出向量。这意味着每个词元的输出不仅包含自身的信息,还融入了序列中其他词元的上下文信息。
结合之前的数据进一步说明。首先,有两个词元“我”和“爱”, 以及它们对应的值向量。
“我”的值向量: [5, 6]
“爱”的值向量: [7, 8]
3.4计算得到了每个词元对于序列中所有词元(包括自己) 的Softmax标准化后的注意力权重。这些权重反映了在给定的查询词元上下文中,每个键词元的相对重要性。
对于“我”的查询, 其对“我”和“爱”的注意力权重分别是: 0.014 和 0.986
对于“爱”的查询,其对“我”和“爱”的注意力权重分别是: 0.00005 和 0.9999
将每个值向量乘以对应的注意力权重,得到加权的值向量。这表示在计算输出向量时, 每个词元的贡献将根据它们的注意力权重进行调整。
接下来, 对于每个查询词元, 将它针对序列中所有词元的加权值向量求和, 以生成一个综合了整个输入序列信息的输出向量。
对于“我”,将加权的值向量[5,6]和[7,8](根据其注意力权重调整过的) 进行求和, 得到输出向量[6.97, 7.97]。
0.014*5+7*0.986=6.97, 0.014*6+8*0.986=7.97
对于“爱”, 同样地, 将加权的值向量求和, 得到输出向量[7.00,8.00]。
这个过程允许模型在处理每个词元时考虑到序列中的所有其他词元,从而捕获语言数据中的复杂上下文关系。
3.6 多头注意力机制
每个注意力机制的执行被视为一个“头”, 因为单一头的信息表达能力有限, 所以通过并行运用多个头, 可以捕获和表达数据的多维度信息。多头注意力机制是 transformer 模型的一个创新点, 允许模型在不同的表示子空间中并行捕捉信息。通过这种方式,模型能够从多个维度理解数据, 增强了其捕捉复杂关系的能力。这里将探讨多头注意力机制的工作原理、实现及transformer模型性能的影响。
多头注意力机制通过将输入的查询、键和值向量分拆成多组向量, 并分别应用自注意力机制,以实现对不同子空间的并行处理。具体步骤如下。
(1) 分拆向量:对于每个输入向量(查询、键、值),模型将其分拆成多个较小的向量。例如,如果原始向量的维度是512, 而选择8个注意力“头”, 则每个头处理的向量维度将是64。
(2)独立应用自注意力:在每个表示子空间中, 模型独立地计算注意力分数, 应用 Softmax标准化, 并生成加权值向量。这一过程允许模型捕捉输入序列中不同类型的信息。
(3)合并输出:最后, 模型将所有头的输出向量合并回一个单一的向量, 以便进行进一步的处理。这通常通过连接( concatenation)所有头的输出向量, 然后应用一个线性变换来完成。
下面结合示例进一步说明。
对于每个头, 已经计算出其输出向量。合并这些不同头的输出, 以获得一个综合的表示。合并的方法通常是将所有头的输出向量拼接起来, 然后乘以另一个权重矩阵(有时称为输出权重矩阵),这个过程可以表示为
MultiHead(Q,K,V)= Concat(head₁,head₂,..., headn)
其中, head是第 i个头的输出向量,
是输出权重矩阵, 用于将拼接后的向量转换为最终的输出维度。
假设在一个两头注意力机制中, 对于“我”和“爱”。
第一个头的输出向量分别是[0.5, 0.8] 和[0.9, 0.1]。
第二个头的输出向量分别是[0.2, 0.3] 和[0.4, 0.5]。
则拼接这两个头的输出如下。
对于“我”: [0.5, 0.8, 0.2, 0.3]
对于“爱”: [0.9, 0.1, 0.4, 0.5]
最后, 输出权重矩阵将这个拼接的向量转换为最终的输出向量,完成多头注意力的合并。多头注意力机制的引入对 transformer模型具有以下几个重要意义。
提高表达能力:通过并行处理多个子空间, 模型能够同时捕捉输入序列不同方面的信息,如不同级别的语义和语法关系, 从而提高整体的表达能力。
增加灵活性:多头注意力机制使模型在处理各种复杂任务时更加灵活, 因为它可以学习到在特定任务中哪些信息更为重要。
改善长距离依赖捕捉:每个“头”关注序列的不同部分, 这有助于模型更好地处理长距离依赖问题, 提升了对长序列数据的理解。
多头注意力机制通过并行处理多个表示子空间,显著提升了模型的信息处理能力和性能。这一机制不仅增强了模型的表达能力,也提高了其对复杂语言结构的理解, 是模型在多种NLP任务中取得成功的重要因素。
3.7 编码器残差连接
在 transformer模型的编码器中, 残差连接允许模型在加深网络层数时, 防止性能退化, 确保了信息的有效流动。本小节将介绍残差连接的概念、作用以及其如何在 transformer 模型中被应用来增强模型的学习能力。
残差连接是一种网络结构设计,允许模型的输入直接跳过一些层而加到后面的层上。在数学上, 如果将一个层的输入表示为x, 该层的输出为F(x),则残差连接的输出将是F(x)+x。这种设计可以帮助模型学习到恒等映射( identity mapping), 使得深层网络的训练变得更加容易。
恒等映射是指一种函数或操作, 使得经过这个操作的输出与输入完全相同, 即输出值等于输入值, 这在帮助深层网络学习时保持信息流的完整性方面非常重要。
transformer模型中的每一个编码器层都包括残差连接,它们被应用于自注意力机制和前馈神经网络之后。具体而言,对于自注意力层和前馈神经网络, 模型首先计算它们的输出, 然后将这个输出与输入相加, 最后通过层归一化处理。
(1)自注意力残差连接:自注意力层的输出与其输入直接相加, 形成了一个残差连接。
(2)前馈神经网络残差连接:前馈神经网络层同样采用了输入与输出相加的方式, 形成另一个残差连接。
残差连接在 transformer模型中有着多重作用。
促进深层网络训练:残差连接帮助解决了随着网络加深导致的梯度消失或爆炸问题, 使得模型能够有效地训练更深层的网络结构。
增强学习能力:通过允许信息直接传递,残差连接使得模型在每一层都能接触到原始输入的信息, 从而增强了模型对输入数据的学习能力。
保持信息流动:残差连接确保了即使在深层网络中, 信息也能够有效地流动, 防止信息在传递过程中的丢失。
引入残差连接极大地提高了 transformer模型的性能,特别是在处理复杂的NLP 任务时。它使得模型能够深入学习到数据的细节, 同时保持了训练过程的稳定性。这一设计是 transformer能够有效处理各种任务的关键因素之一,显著提升了模型的准确性和可靠性。
3.8 编码器层归一化
层归一化在 transformer模型的编码器中负责在每个子层的输出上进行归一化处理, 以稳定训练过程并加速收敛。接下来将探讨层归一化的原理、在编码器中的应用,以及它对模型性能的影响。
层归一化是一种特殊的归一化技术,与批归一化( Batch Normalization)不同, 层归一化是对单个样本的所有特征进行归一化。具体而言,对于每个样本,层归一化会计算所有特征的平均值和标准差, 并使用这些统计量来归一化每个特征。数学上,对于给定的输入向量x, 层归一化的输出为
其中,μ和σ分别是向量x的均值和标准差,γ和β是可学习的参数, 用于调整归一化后数据的缩放和偏移。
下面以输入向量[1.0,2.0,3.0,4.0,5.0]为例进一步说明。
(1)计算均值(μ)。计算输入向量的均值。均值是指所有特征值的平均值, 计算公式是:
其中, 是输入向量中的第i个元素, N是向量中元素的总数。
(2)计算标准差(σ)。计算输入向量的标准差。标准差衡量的是每个特征值与均值的偏离程度, 计算公式是:
(3)归一化处理。用每个特征值减去均值并除以标准差来归一化输入向量:
(4)应用可学习参数(y和β)。使用可学习的参数(在该例子中, 简化为γ=1和β=0)来调整归一化后数据的缩放和偏移:
最后进行计算得到如下结果:
1)均值:输入向量的均值是 3.0。
2) 标准差:输入向量的标准差约是1.41。
3)归一化处理:归一化后的向量是[-1.41,-0.71,0.00,0.71,1.41]。
在该例子中,γ=1和β=0, 所以应用这些参数后的结果与归一化处理的结果相同。
在 transformer模型的编码器中, 层归一化被应用在每个子层(自注意力层和前馈神经网络层)的输出上以及在残差连接之后。这样做的目的是为了增强训练过程的稳定性, 并帮助模型更快地收敛。通过对每个子层的输出进行归一化,模型能够在训练过程中维持激活值分布的一致性,减少内部协变量偏移( Internal Covariate Shift)。
激活值是指神经网络中非线性激活函数的输出, 这些值作为网络中下一层的输入, 对模型的非线性表达能力至关重要。
协变量是指模型输入数据中的变量, 在统计学和机器学习中通常用来表示影响因变量(实验或模型中被预测或研究的变量, 通常作为输出结果) 的独立变量或特征。
层归一化对 Transformer模型性能的提升主要体现在以下几个方面。
训练稳定性:通过在每个子层后应用层归一化, 模型的训练过程变得更加稳定,从而减少了训练过程中的梯度消失或爆炸问题。
加速收敛:归一化有助于将激活值保持在一个合理的范围内, 这使得模型参数的学习更加有效, 进而加速了收敛速度。
增强泛化能力:层归一化还被认为能够提升模型的泛化能力, 虽然其具体机理仍在研究之 )中, 但实践证明, 包含层归一化的模型通常能够在多个任务上获得更好的性能。
3.9编码器前馈神经网络
在transformer模型的编码器中, 除了自注意力机制和残差连接外,前馈神经网络也是其核心组成部分之一。每个编码器层都包含一个前馈神经网络,该网络对自注意力层的输出进行进一步处理。下面将讨论前馈神经网络的结构、作用以及它对模型性能的贡献。
transformer模型中的前馈神经网络是由两层线性变换组成的, 这两层之间有一个ReLU( Rectified Linear Unit) 激活函数。第一层线性变换在 transformer 的前馈神经网络中起着将输入数据映射到一个更高维度空间的作用,它有助于模型捕获更复杂的特征和模式。通过这个变换, 模型可以在更广泛的特征空间中探索数据的内在联系, 为ReLU激活函数提供了丰富的输入, 使其能够引入非线性,从而增强模型的表达能力。第二层线性变换的作用是将ReLU激活后的数据映射回原始数据的维度, 或者是预定的输出维度, 以便于与 Transformer模型中的其他组件(如多头注意力机制的输出)进行整合。这一步骤是整个前馈神经网络的收尾, 它确保了网络输出可以适应模型中后续处理的需求, 如残差连接和层归一化, 进一步促进了模型中不同层之间的有效信息流动。
具体而言, 前馈神经网络可以表示为以下形式:
FFNN(x)=max(0,xW₁+b₁)W₂+b₂
其中, W₁和W₂是网络的权重矩阵, b₁和b₂是偏置项, x是自注意力层(或上一个前馈神经网络层)的输出。
下面以自注意力层的输出x是一个具有3个特征的向量[0.5,-0.4,0.3]为例进行说明。
每一层的权重矩阵和偏置项都是模型的参数。
(1)第一层线性变换:将自注意力层的输出x与第一层的权重矩阵W₁相乘,再加上偏置项b₁₀这里为了说明直接设定如下。
W1 = [[0.2, 0.3, 0.5], [0.1, -0.3, 0.4], [0.5, 0.2, -0.1]]
b1 = [0.1, 0.2, 0.3]
计算得到的结果是:[0.31,0.53,0.36]。
(2) ReLU 激活函数:对第一层的输出应用ReLU 激活函数。ReLU激活函数定义为 max(0,x),它将所有的负数转换为0, 而正数保持不变。
应用ReLU 激活函数后的结果仍为[0.31,0.53,0.36]。
(3)第二层线性变换: 将ReLU的输出与第二层的权重矩阵W₂相乘, 再加上偏置项b₂, 得到前馈网络的最终输出。权重和偏置直接设定如下。
W2 = [[0.4, -0.2, 0.1], [-0.1, 0.5, -0.3], [0.3, 0.1, 0.2]]
b2 = [-0.2, 0.1, 0.4]
最终的输出结果是[-0.021,0.339,0.344]。
值得注意的是, 尽管整个 transformer模型共享相同的前馈神经网络结构, 但每个编码器层中的前馈神经网络都有自己的参数, 这使得每层能够学习到不同的表示。
前馈神经网络在 transformer编码器中扮演着以下几个重要角色。
增加非线性:通过引入ReLU激活函数, 前馈神经网络为模型增加了非线性变换,这对于学习复杂的数据表示至关重要。
提供额外的抽象层:前馈神经网络允许模型在自注意力层捕获的信息基础上进一步进行抽象和转换, 增强了模型的表达能力。
独立处理每个位置:前馈神经网络在处理序列时对每个位置的词元独立操作, 这增加了模型对每个词元独特性的处理能力, 同时保持了操作的高效性。
前馈神经网络对于提升 Transformer模型的性能起到了关键作用。
增强模型的复杂度和灵活性:前馈神经网络使模型能够捕获更加复杂的特征, 并且通过参数的独立学习, 为不同的编码器层提供了灵活性。
促进深度学习:前馈神经网络的加入, 配合自注意力机制和残差连接, 支持模型的深层结构, 这对于处理复杂的自然语言任务是必要的。
提高准确性和泛化能力:通过在每个编码器层增加额外的非线性处理步骤, 前馈神经网络有助于提高模型在各种任务上的准确性和泛化能力。
4. 解码处理器
transformer模型的解码器是负责生成输出序列的部分,它采用与编码器相似但更复杂的结构,以适应序列生成的需求。解码器通过一系列的层来处理信息, 每一层都执行特定的功能, 包括输出嵌入、位置编码、掩蔽自注意力、编码器-解码器注意力、前馈神经网络以及残差连接和层归一化。
以下是解码器执行步骤的详细说明。
1 输出嵌入 ( Output Embedding)
解码器的第一步是将其输入序列(即之前生成的输出序列)转换成高维空间中的向量表示。这一过程类似于编码器的输入嵌入,它为模型提供了丰富的表示以捕获词汇的语义信息。
2 位置编码 ( Positional Encoding)
解码器同样引入位置编码来为序列中的每个元素提供位置信息, 这对于保持序列的顺序关系至关重要。位置编码与输出嵌入向量相加,使模型能够利用位置信息。
3.掩蔽自注意力 ( Masked Self- Attention)
为了维持自回归特性,即在生成当前位置的输出时只依赖于之前的输出, 解码器中的自注意力机制被修改为掩蔽形式。这通过在计算注意力分数时引入一个掩码来实现,防止模型“看到”当前位置之后的任何位置。
4.编码器-解码器注意力( Encoder- Decoder Attention)
这一步骤是解码器特有的,允许解码器使用当前已生成的序列(通过掩蔽自注意力处理过的)来“查询”编码器的输出。查询向量来自解码器,而键和值向量来自编码器。这一过程使解码器能够专注于输入序列中与当前生成步骤最相关的部分。
5. 前馈神经网络
解码器也包含一个前馈神经网络,该网络独立地处理每个位置的表示, 但对不同位置使用相同的参数。这一步骤与编码器中的前馈网络相似, 但参数是独立的。
6.残差连接和层归一化
每个掩蔽自注意力和编码器-解码器注意力的输出都会通过残差连接,然后进行层归一化处理。前馈网络的输出同样经过残差连接和层归一化处理。这些步骤有助于避免深层网络中的梯度消失问题, 同时提高训练的稳定性。
解码器是 transformer 模型生成输出序列的核心。它通过综合考虑之前的输出、编码器的信息以及当前位置的上下文来逐步生成序列。解码器内部的多个机制, 包括掩蔽自注意力和编码器-解码器注意力, 确保了模型在每一步都能做出基于全局信息的决策。残差连接和层归一化进一步增强了模型的学习能力, 使transformer能够有效地处理复杂的序列到序列转换任务。
4.1 掩蔽自注意力机制
在 transformer模型中, 注意力掩码机制( Attention Masking Mechanism) 可以确保模型在生成当前词元时, 只能使用之前的词元信息, 从而防止信息的泄露。这里将探讨注意力掩码机制的工作原理、应用场景以及它对模型性能的影响。
注意力掩码机制通过修改自注意力层的输入来实现。在计算注意力分数之前, 模型会引入一个掩码( Mask), 用于调整分数的大小, 使得某些不应被当前词元“看到”的位置的分数变得极小(在实践中通常设置为一个非常大的负数),这样经过 Softmax函数处理后, 这些位置的注意力权重接近于零。
在解码器的自注意力层中,掩码防止了当前位置之后的词元对当前词元的生成产生影响。这意味着, 对于序列中的第i个词元, 掩码将确保只有在它之前的词元(包括自身)在计算注意力时被考虑。
下面以一个简单的序列的注意力分数矩阵(未经过掩码处理),序列长度为4, 即有4个词元为例进行说明。
(1) 应用掩码前的注意力分数矩阵如下。
[
[1, 2, 3, 4],#词元1 对其他所有词元的注意力分数
[2, 3, 4, 1], # 词元2 对其他所有词元的注意力分数
[3, 4, 1, 2],#词元 3 对其他所有词元的注意力分数
[4, 1, 2, 3] # 词元4对其他所有词元的注意力分数
]
上述矩阵表示每个词元对序列中其他所有词元的原始注意力分数。
(2)构造掩码矩阵。现在处理的是解码器的自注意力层, 需要防止词元“看到”它之后的词元。为此,构造一个掩码矩阵, 使得每个词元只能“看到”它之前和它自己的位置。
[
[0, - inf, - inf, - inf], # 词元1 只能看到自己
[0, 0, - inf, - inf], # 词元2 能看到词元1和自己
[0, 0, 0, - inf], # 词元3能看到词元1、2和自己
[0, 0, 0, 0] # 词元 4 能看到所有人
]
(3) 通过矩阵加法应用掩码到注意力分数。
[[ 1, - inf, - inf, - inf],
[ 2, 3, - inf, - inf],
[ 3, 4, 1, - inf],
[ 4, 1, 2, 3]]
通过掩码, 将某些位置的分数设置为非常大的负数(这里用- inf表示), 从而确保在计算 Softmax时, 这些位置的注意力权重接近于零。
(4)计算 Softmax 后的注意力权重矩阵。
[[1. 0. , 0. , 0. ],
[0.26894142, 0.73105858, 0. , 0. ],
[0.25949646, 0.70538451, 0.03511903, 0. ],
[0.64391426, 0.0320586 , 0.08714432, 0.23688282]]
在该矩阵中,每一行的值表示给定词元对序列中其他词元的注意力权重。由于掩码的作用,每个词元只能“看到”它之前的词元和自己, 这反映在权重接近于零的位置。
在文本生成、机器翻译等任务中,解码器需要根据已生成的词元序列来预测下一个词元。注意力掩码机制确保模型在生成每个新词元时, 只依赖于先前的词元, 符合自回归生成的原则。
在训练阶段,由于整个目标序列是已知的, 存在信息泄露的风险, 因此, 需要用注意力掩码机制防止这种情况, 以确保模型的训练过程中不会使用未来的信息。
注意力掩码机制对提高 Transformer模型在序列生成任务中的性能至关重要。
提升模型的准确性:通过防止信息的泄露, 模型能够准确地学习序列之间的依赖关系, 提高生成任务的准确性。
增强模型的可靠性:掩码机制确保了模型生成过程的合理性, 使得模型在面对不同长度的序列时表现出更好的鲁棒性和可靠性。
促进学习效率:通过减少不必要的信息干扰, 掩码机制有助于模型更高效地学习序列的内在规律, 加快训练速度, 提高收敛效率。
4.2 编码器-解码器注意力
编码器-解码器注意力机制允许解码器层访问整个编码器的输出, 从而在生成序列时能够考虑到输入序列的全部信息。本小节将探讨编码器-解码器注意力的工作原理、实现以及对模型性能的影响。
编码器-解码器注意力机制的核心思想是让解码器能够“注意”到编码器输出的每个位置。具体实现时, 解码器的每个层都会接收到编码器的最终输出,以此作为其注意力机制的键和值向量, 而查询向量则来自于解码器前一层的输出。
具体实现过程如下。
(1)接收编码器输出:解码器的每个注意力层都会接收编码器输出的一个复制版本, 这个复制的输出在解码器中被用作键和值向量。
(2)生成查询向量:查询向量来源于解码器当前层的前一层输出。在第一层解码器中,查询向量来源于目标序列的嵌入表示。
(3)计算注意力权重:通过计算解码器的查询向量与编码器输出的键向量之间的点积, 然后应用 Softmax 函数来生成注意力权重。
(4)生成加权和输出:这些注意力权重被用于编码器输出的值向量, 可以通过加权求和来生成当前解码器层的输出。
为了具体说明编码器-解码器注意力机制, 下面以一个简化的例子进行演示。用户输入的是“你好”,要计算如何得到回答的第一个预测字。这里跳过实际的嵌入和编码过程, 直接使用编码器输出和解码器输入的示例向量来解释步骤。
(1)编码器输出向量(设定2个字的输出, 每个字由二维向量表示)。
“你”-> [1.0, 2.0]
“好” -> [2.0, 3.0]
(2)解码器输入向量(设定开始生成回答, 第一个字的嵌入表示)。
实际的 transformer模型中,解码器开始生成序列时, 通常会使用一个特殊的开始标记(如< start>或类似的标记), 它告诉模型开始生成回答或翻译的文本。
第一个预测字的嵌入表示 ->[0.5, 1.5]
(3) 编码器的每个输出向量将被用作键和值向量。
键向量:
K1: [1.0, 2.0]
K2: [2.0, 3.0]
值向量:
V1: [1.0, 2.0]
V2: [2.0, 3.0]
(4)生成查询向量。解码器的查询向量来自于解码器当前层的前一层输出。在第一层解码器中, 查询向量来源于目标序列的嵌入表示。
查询向量:
Q: [0.5, 1.5]
(5)计算注意力权重。注意力权重是通过计算解码器的查询向量与编码器输出的键向量之间的点积得到的, 然后应用 Softmax函数。
计算点积:
Score1 = Q · K1 = [0.5, 1.5] [1.0, 2.0] = 3.5
Score2 = Q · K2 = [0.5, 1.5] · [2.0, 3.0] = 6.0
对分数应用 Softmax函数, 将分数转换为总和为1的概率。 Softmax的计算包括对每个分数取指数, 然后除以所有指数的总和。应用 Softmax:
exp( Scorel) = e^3.5
exp(Score2) = e^6.0
总和 = exp(Score1) + exp(Score2)
Softmax(Score1) = exp(Score1) / 总和 = 0.07585818002124355
Softmax(Score2) = exp(Score2) / 总和 = 0.9241418199787566
(6)计算加权和。使用注意力权重对值向量进行加权求和, 这个加权和形成了这一解码步骤的注意力机制的输出。
输出 = Softmax(Score1) * V1+ Softmax(Score2) * V2 = [1.92414182, 2.92414182]
最终的输出向量[1.92414182,2.92414182]是通过将每个编码器输出的值向量与它们相对应的注意力权重相乘, 并将这些乘积相加得到的。该输出向量捕捉了解码器在特定解码步骤中, 基于注意力权重对编码器输出的综合表示。
编码器-解码器注意力机制极大地增强了 transformer模型处理序列到序列任务(如机器翻译、文本摘要等)的能力, 主要有以下几个好处。
提高翻译准确性:通过利用编码器的全部输出信息, 解码器能够更准确地理解源序列的语义, 从而生成更准确的目标序列。
增强上下文理解:这种注意力机制确保了解码器在生成每个词元时都能充分考虑输入序列的上下文信息, 提高了生成文本的连贯性和一致性。
促进模型泛化:编码器-解码器注意力使得模型能够在训练和推理时有效地处理不同长度的输入序列, 增强了模型的泛化能力。
编码器-解码器注意力机制通过解码器能够访问编码器的全部输出, 极大地提升了模型的性能, 使其在多种复杂任务中取得了卓越成绩。
5 输 出 生 成
在 transformer模型中,输出生成阶段是整个模型生成预测结果的最后一步, 直接关系到模型的最终性能和应用效果。这一阶段主要通过线性层和 Softmax层的协同工作来完成, 将解码器的复杂表示转换为对词汇表中每个词的具体预测。
5.1 Transformer线性层
在 transformer模型的输出阶段,线性层( Linear Layer) 起到了将解码器的输出转换为最终预测结果的关键作用。每个解码器层的输出首先通过线性层, 然后通过 Softmax层来生成对词汇表中每个词的概率分布。本小节将探讨线性层的作用、结构以及它对模型性能的影响。
线性层, 也被称为全连接层, 是深度学习中最基本的组件之一。在transformer模型中,线性层的主要作用是对解码器层的输出进行变换,并将其映射到一个与词汇表大小相同的空间中,为生成最终的输出序列做准备。
一个线性层简单地由一个权重矩阵W和一个偏置向量b组成。给定解码器输出向量x, 线性层的计算公式为y=xW+b。其中, y是映射后的向量, 其维度与模型的词汇表大小相同。这使得每个元素可以对应词汇表中的一个词。
为了进一步说明,下面将使用上个例子中的输出向量[1.92414182,2.92414182]作为输入。为了简化, 设定模型的词汇表大小为3, 即希望线性层的输出是一个三维向量, 每个维度对应词汇表中的一个词。
在大语言模型中,实际的词汇表大小通常是非常大的, 可能包含数万到数百万不同的词汇,以覆盖广泛的语言用途和领域。
(1)线性层参数。
1)权重矩阵:设定为一个2×3的矩阵, 因为输入是二维的, 而输出是三维的(与词汇表大小相匹配)。
2) 偏置向量:设定为一个三维向量。
设定权重矩阵和偏置向量如下。
W = [[0.1, 0.2, 0.3], [0.4, 0.5, 0.6]]
b = [0.1, 0.2, 0.3]
(2)线性层计算。线性层的输出y可以通过xW+b计算得到, 其中, xW是向量x与矩阵W的点积。具体计算如下。
xW的第一个元素是 1.92414182×0.1+2.92414182×0.4
xW的第二个元素是 1.92414182×0.2+2.92414182×0.5
xW的第三个元素是 1.92414182×0.3+2.92414182×0.6
然后将xW的每个元素分别加上偏置向量b的相应元素得到最终的输出向量y。
这个输出向量 y 表示在给定解码器输出的条件下, 经过线性层处理后得到的新向量, 其维度与模型的词汇表大小相同, 最终的输出向量y是:
y = [1.46207091,2.04689927,2.63172764]
线性层对 Transformer模型的性能有直接影响, 从以下三个方面进行分析。
精确度:通过精细的权重调整, 线性层可以帮助 transformer模型准确地预测下一个词元。它的参数在训练过程中被优化, 以最小化预测错误。
灵活性:线性层的简单性使得 transformer 模型易于调整和优化。它可以根据不同任务的需要调整输出空间的维度, 提供了模型设计的灵活性。
效率:尽管简单, 线性层在处理大规模词汇表时非常高效。配合模型的其他部分, 能够快速地处理和生成文本。
transformer模型中的线性层虽然结构简单, 但在将解码器输出转换为最终预测结果的过程中扮演了不可或缺的角色。它直接影响到模型的预测精度和效率,是模型输出阶段的关键组件。通过在模型训练过程中学习到的权重和偏置, 线性层能够有效地将解码器的复杂表示映射到具体的词汇预测上, 从而完成文本生成任务。
5.2 Transformer Softmax层
在 transformer模型的输出生成阶段, Softmax层负责将线性层的输出转换为最终的概率分布,从而确定每个可能词元的预测概率。本小节将详细探讨 Softmax层的作用、原理以及它对模型性能的影响。
Softmax层的主要作用是将线性层的输出(即对每个词元的未规范化分数, 也称为 logits)转换成一个概率分布,表明了在给定的上下文中,下一个词元是词汇表中每个词的概率。这一步是生成文本过程中的关键步骤, 因为它直接关系到模型预测的准确性。
给定一个向量z, 其中每个元素 z₁代表模型对词汇表中第i个词作为下一个词的预测分数, Softmax函数按如下公式计算每个词的概率:
其中, 分子是当前词元的预测分数的指数, 分母是词汇表中所有预测分数的指数之和。这样, Softmax层的输出是一个概率分布,所有元素的和为1。
下面结合上一节线性层的输出[1.46207091,2.04689927,2.63172764]进一步说明。
(1)设定线性层输出z。
z=[1.46207091,2.04689927,2.63172764]
(2)计算。
计算指数:对向量z中的每个元素计算指数。
计算指数之和:将所有指数值相加, 得到分母 。
计算概率分布:将每个元素的指数除以指数之和, 得到每个词的概率。
最后计算概率分布如下。
[0.16623529,0.29833964,0.53542506]
第一个词的概率是0.16623529。
第二个词的概率是 0.29833964。
第三个词的概率是 0.53542506。
这些概率表明模型预测下一个词为词汇表中第三个词的可能性最高,其次是第二个词, 最不可能的是第一个词。在生成文本或进行序列预测时, 模型会根据这个概率分布来选择下一个最可能的词元, 这里就是选择概率最高的第三个词。
Softmax层对 Transformer模型性能的提升主要体现在以下几个方面。
提高预测准确性:通过转换为概率分布, 模型能够清晰地表达对下一个词元的预测置信度,从而提高预测的准确性。
支持多类分类: Softmax层天然支持多类分类问题, 非常适合处理词汇预测任务, 因为它可以同时考虑所有可能的输出词元。
增强模型的解释性:输出的概率分布使得模型的决策过程更加透明, 有助于理解模型是如何基于当前上下文来生成下一个词元的。
transformer模型中的 Softmax层将线性层的输出转换为一个概率分布, 指导模型生成下一个最可能的词元。通过精确计算每个词元的预测概率, Softmax层极大地提高了模型在文本生成任务中的性能。