无论是想怎样学习大模型,transformer都是一个绕不开的话题。transformer的出现彻底改变了nlp领域,进一步推动了大模型的产生,可以说,transformer就是大模型开发的鼻祖。
可能只通过说大家会有些不理解。大家可以看下方的大语言模型进化树。
上述进化树中,同一分支上的模型关系更近。基于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技术的发展。
在下文中, 将逐一深入探讨 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 任务上的表现,也体现了在设计深度学习模型时考虑数据的内在结构的重要性。