前言
2017年,谷歌团队推出一篇神经网络的论文,首次提出将”自注意力”机制引入深度学习中,这一机制可以按输入数据各部分重要性的不同而分配不同的权重。当ChatGPT震惊世人时,Transformer也随之进入大众视野。一夜之间,AI创业公司层出不穷,掌握算力的互联网寡头们争相推出自己的大语言模型,这些模型都基于Transformer神经网络架构,比如ChatGPT只使用了其中的解码器,DeBERTa只使用了其编码器,Flan-UL2则编码解码全都使用。
而对于用户来说,大语言模型还是一个黑盒,用户只知道输入一些简单指令模型便会产生一些输出,这些输出可能满足用户的需求,也有可能不满足,于是用户通调整指令的方式来得到不同输出的结果。从笼统,抽象的概括到指令精确的下发,这也推进了提示词工程的发展。很难评价是机器在学习人类还是人类在适应机器,亦或都有。
开发者的世界中可能了解得更多,比如使用LangChain或LlamaIndex构建RAG(检索增强生成)系统,使用提示词工程优化输出结果,设置temperature
等各类参数控制大模型创新性等……虽然比用户更接近黑盒,但依然存有很多无法解答的问题:为什么大语言模型会有上下文的限制?为什么现阶段的模型没有长期记忆?为什么要使用Transformer作为基础?
对于科学家来说上述问题可能很好回答,但大部分表述都是一些晦涩难懂的专有名词,谈论得更多的是向量,嵌入层,层归一化,矩阵乘积……以及一堆复杂的数学公式。在学术界热热闹闹讨论AGI未来的同时,这些专属名词构建出的壁垒让普通人难以望其颈背,无疑于在黑盒之上又蒙了一层神秘的面纱。
这当然不是科学家有意为之,但从也从侧面反映人工智能领域的复杂性,一个包含计算机科学,数学,认知科学,心理学等众多学科的领域要解释起来确实颇有难度。
本篇文章目的意在使用通俗语言解释这些专有名词,并通过数据流向的方式描绘“自注意力机制”在训练时的过程,但不会事无巨细地解释其中每一个细节。
向量
当我们谈论向量的时候,我们具体谈论的是哪一领域的‘向量’?是数学,物理学还是其他自然科学中的基本概念?
是理论数学中的定义:任何在称为向量空间的代数结构中的元素,并同时满足具有大小和方向两个性质的几何对象即可认为是向量。
还是物理领域中的定义:向量是空间中的箭头,它指向三维空间其中一点,以三元数组代表某个特定的对象,这个对象可以代表任意东西。
无论使用哪一领域的向量定义,最终都要回到一个根本性问题,如何让机器识别某一信息代表的具体意义?
对于机器而言,人类世界的语言并没有什么意义,无论是使用中文的’他’,还是英文中的’he’,机器能识别和处理只能是数值,例如0,1。为了让机器更好识别人类语言及真实世界,科学家们使用向量将文本转为数据,使得机器可以对文本进行数学运算;向量也可以包含多种特征,如词性,上下文等,这有助于提高模型对语言的理解能力。
假设使用一个二维坐标轴将人类语言词汇分布在上面,英文的’he’和中文的’他’可能会分布在不同轴上。“番茄”和“西红柿”只是两种不同叫法,指向的是同一种植物果实,却需要要占据两个向量,即使它们可能无比接近。
如果将一个二维空间升维成三维空间,’番茄’这一含义代表着三维空间的某个坐标(x,y,z),意义相近的词依旧分布在其附近。看似好像没有什么区别,但描述同一对象的方式却发生了改变。事实上向量可以是任意维度的,这取决于数据的复杂性和所需的特征数量,不同维度承载的特征数量是不一样的。通俗一点讲就是:向量的维度越高,代表的含义也就越多。高维向量可以捕捉更多的细节和信息,但这也导致了计算的复杂性。
向量是一切的基础,无论是模型训练还是使用AI应用,第一步都是将输入的文本/图片/音频等信息转换为向量,一般情况下我们将这些输入/输出的向量统称token
。为了方便理解,我们暂时将一个单词对应一个向量,即一组数字。
嵌入矩阵
通常情况下模型会包含一个预设的词汇库,它被称为”嵌入矩阵”。以ChatGPT-3为例,这个嵌入矩阵中包含了50257个token,12288个维度,里面可以是单词或标点符号……它们的初始值随机,但将基于数据进行学习。这是故意为之,如果所有嵌入向量都初始化为相同的值,那么模型在训练时无法区分不同的输入。使用随机值可以打破均匀性,避免训练开始时的梯度相似,同时也可以避免模型陷入局部最优解。
早在Transformer出现前,将单词转化为向量已经是机器学习中常见的做法,到如今Transformer几乎成为自然语言处理,视觉处理,多模态处理的基础模型。可见将人类所有语言词汇转变为向量并不能一蹴而就,这就像拥有一座铁矿并不意味着得到好钢,但它为接下来的淬炼奠定了基础。
这非常重要,举一个3Blue1Brown提出的例子:当模型在训练阶段调整权重时,以确定不同单词将如何被嵌入向量,它们最终的嵌入向量在空间中的方向,往往具备某种语义意义。
就像在谈论向量时那样描述的,意义相近的向量会分布的较为接近。如果取[女人]和[男人]的向量之差,从一个向量的尖端指向另一个尖端,便会发现这个向量差与[父亲]和[母亲]的向量差非常相似。假设你并不知道[母亲]这一词在向量空间中的分布,但是可以通过[父亲]这一词汇加上[女人]减去[男人]的方向,然后搜寻最接近该点的词向量来找到它。
上述例子足以说明,空间中的方向能够承载语义。反复强调它的重要性,是因为嵌入矩阵中的向量不能仅仅将其视为单个单词,它编码了单词的位置信息,还结合了上下文语境。在现实世界,不同的语境下同一词也代表不同的含义,“model”这一词是指艺术领域中展示服装的人类,是指计算机领域的数据结构?还是我们现在谈论的机器学习模型?
假如对模型提出一个问题:“the greatest thinker in Chain is ?”
“greatest”这个词向量会被网络中各个模块拉扯,最终指向一个更具象的方向或对象。如下图中所示,上下文中的Chain指明了向量被拉扯的方向,最终指向的方向范围可能会包含”孔子”这一具体的向量词。
一个训练得好的注意力模块目的就是:能计算出给初始的词向量加入什么样的向量,才能将它移动到上下文对应的具体方向上。
自注意力机制
本文开篇中提到过注意力机制可以按输入数据各部分重要性的不同而分配不同的权重,但在深度学习中模型的实际行为很难解释,且其多数计算都是矩阵向量乘法,注意力机制在矩阵中填满了可调的权重,这些权重由模型学习数据来进行调整,最终计算点积层归一化后得到输出的token。
自注意力的本质:
$$
AT(Q,K,V) = softmax(XX^T)X
$$
如果本文剩余篇幅只是例举公式,那么似乎很难让人理解,也违背了本文最初的承诺。这就像把向量矩阵呈现在读者面前,让读者自己计算token一样荒诞。作者将沿用上述例举的方式,尽可能避开公式的细节,抽象出机制的行为并绘制整个流程,可能尽管没有公式那么精确,但更容易帮助我们了解到底发生了什么。
在训练之初,输出文本创建向量组时,每个向量都是直接从嵌入矩阵中提取出来的。
然后这个向量组会流向三个向量矩阵:
1.Query [查询矩阵]的维度要比嵌入矩阵小很多。它由随机向量组做初始化,具体的行为模式是从数据中习得的。从数学的角度来看它们只是在做矩阵乘积,如果抽象成一个具体的行为,这更像是对输入的单词提出一系列问题。试想一下,一个优秀的读者在读某本书籍某篇文章时,一定会对自己所读的内容提出一系列问题,这有助于快速理解内核和作者想要表达出的思想。训练也是如此,通过一系列预设的随机数值,让模型在训练中抽象出那些系统问题。
2.Key [键矩阵]与查询矩阵相同,也会与嵌入向量相乘而产生。如果[查询矩阵]是对token
提出一系列问题,那么[键矩阵]则代表“想要回答的结果”。衡量每个[键]与每个[查询]的匹配程度,得到的查询矩阵会与键矩阵相乘,最终得到的点积如下图所示。如果圆点越大,代表点积也就越大。用机器学习的术语来描述就是:greatest
注意到了China
。如果按照现实意义进行概括就是:从各种问题和答案中选出匹配度最相符的。
为了数值的稳定性,所有的点积将会除以(键-查询空间维度的平方根)得到的结果将会被softmax函数处理后乘V矩阵。
在训练过程中,示例文本经过模型处理时,模型会根据正确预测出下一次的概率高低来进行奖惩,并稍微调整各个权重。为了让训练的效率最大化,在初始化token时让它同时预测,这样一个训练样本就能提供多次训练机会。
在引入注意力机制后,这意味着不能让后词影响到前词,不能让[答案]影响到[问题],从点积矩阵中反应出来便是:左下方的数值都会影响到右上方。通常情况下,在使用softmax之前都会将左下方的数值设置为负无穷,这样通过softmax函数后它们就会都变成0,这一过程叫做”掩码”。
在注意力模式下,掩码的大小等于上下文长度的平方。扩大上下文长度则需要更多的计算资源,这就是为什么上下文长度会成为大语言模型的瓶颈所在。
如果想要将一串数字作为概率分布,那么每个值都必须介于0到1之间,并且总和为1。在深度学习中,所有的操作都是在做矩阵向量乘法,那么得出的结果并不在0到1之间,总和也不为1。Softmax 函数主要作用就是将一组任意实数转换为表示概率分布的实数据,然后让这组实数符合概率分布的特征。
“the greatest thinker in China is ?” 这个例子中最有可能输出”Confucius”一词,但人们不希望在提出同一类型问题时模型输出的都是同一结果,这可能会陷入某些局部最优解。
Temperature 参数用于控制生成文本的随机性和创造性,当该参数较大时会给低值赋予更多权重,让概率分布得更均匀一些。如果该参数较小,那么较大的数值就会更占优一些。极端情况下将该参数设置为0,意味着所有权都给到最大值。通过调整该参数,同一问题可能得到不同的结果,当该参数较大时”Mencius”和”Sun Tzu”将被更容易命中。
3.Value [值矩阵]。相比查询矩阵和键矩阵,值矩阵要多几个数量级。当算出点积就能让模型推断出每个词与其他哪些词有关,比如”greatest”会与”china”有关。用”chain”这个词向量乘以值矩阵便会得到一个值向量,这个向量与嵌入向量处于同一个高维空间。上文中提到过:初始的词向量加入什么样的向量,才能将它移动到上下文对应的具体方向上。
向量网格中每一列中都会乘该列的对应权重(点积*值向量),最后计算所有列的和就是那个“拉扯”向量空间中的机制,通过这个机制就能得到一个更精准的向量,编码了更丰富的上下文信息,所得到的输出token也指向了某一范围。
计算过程
1.输入token,如单词,字符或其他类型。通过嵌入层被转换为词向量。
2.每个词向量分别计算查询矩阵,键矩阵和值矩阵。得到查询值,键和值向量
3.向量q1分别与k1,k2,k3做点积运算,得到初始的注意力值at1
4.使用softmax函数对注意力值at1进行归一化处理,得到st1
5.最后将st1与值向量v1相乘,得到新的向量wt1
6.将所有wt向量相加得到输出量
下图来源于《ChatGPT原理与架构》
自注意力机制是Transformer模型的核心组成部分,它计算输入中元素之前的权重,以捕获序列中的关键信息。通过该机制能直接对序列中任意两个元素计算出它们之间的关系,这提供了可观察性和解释性,对模型调试和优化也提供了依据。
但自注意力机制也存在局限性,如上下文问题。虽然它能有效捕捉元素之间的依赖关系,但面对极长的上下文时,计算和内存开销会变得巨大。在训练时尤其明显,通常情况下需要大量训练数据以达到最佳性能,这会增加很多成本。同时在小型数据集,比如移动端,AI嵌入式等特定领域匹配度会降低。
多头注意力机制
作为自注意力机制的一种扩展,多头注意力机制的主要目标是让模型能并行关注输入中多种不同类型信息。这样模型可以学习到更丰富且多元化的表达,从而提升模型能力与性能。通过增加注意力头的数量,扩大了模型的容量,使其能够处理更加复杂的任务。现在我们熟知的多模态大语言模型,既能处理图片,也能处理文本等任务。
Transformer 内完整的注意力模块就是由多头注意力组成,大量并行执行这些操作,每个头都有不同的键,查询,值矩阵……虽然根据Transformer的原论文中的实验结果表明,注意力头数量为8时可以达到最佳的效果,增加到16或32时并未显著提升性能。但ChatGPT-3中每个模块内依然使用了96个注意力头,这意味着在训练过程中将会产生96中不同的注意力模式,每个注意力头都有独特的值矩阵产生不同的值向量序列……按照本文述描自注意力机制,最终会有96个向量值“拉扯”最初的嵌入向量。
多头注意力机制的参数规模较大,为了优化这些问题也提出一系列优化策略来进行改进,比如局部多头注意力,稀疏多头注意力,分层多头注意力等。但这些不在文本讨论范围内,感兴趣的读者可以自行查阅相关资料。
注意力机制的成功的主要原因并不在于它能实现什么特定的行为,而是它的可并行性,这样使用GPU在短时间内可以进行大量计算。了解深度学习历史的读者可能会理解,仅依靠扩大模型规模就能为模型性能带来质的飞跃。
总结
本文详解了自注意力机制的流程,同时也对深度学习中部分专有名词进行了解释。如今Transformer模型已经在NLP领域占据了重要地位,但Transformer不仅仅只包含’注意力机制’,还包含了前馈神经网络,残差连接和位置编码等。训练出一个大语言模型也不仅仅只依靠Transformer就够了,还包括了预训练,人类反馈,微调,评估等。
这也重申了人工智能领域的复杂性,虽然本篇文章不能打破黑盒一探究竟,但能掀开面纱一角也足够了。
学习资料
《ChatGPT原理与架构》