Attention by 3B1B

我们希望构建一个模型:接收一段文本,预测下一个词

输入文本被切为小块,即 tokens,transformer 第一步将 tokens 关联到一个称为嵌入向量的高维向量(Words -> Embedding -> Vectors),向量的方向可以对应语义

transformer 的目标是使它们不单单编码单个词,还能融入更丰富的上下文

初始的 token 嵌入本质是没有上下文参照的查找表,不同语句的同一个词对应同一个向量,要经过注意力层,周围的信息才能传递到该嵌入向量

嵌入空间中有多个方向编码了一个 token 的不同含义,训练好的注意力模块能计算出需要给初始的泛型嵌入向量加个什么向量,才能把它移动到上下文对应的具体方向上

注意力模块不仅精细化了一个词的含义,还允许模型相互传递这些嵌入向量所蕴含的信息,甚至可以传递很远,且新嵌入向量的信息比单个词丰富的多

所有向量流经网络后,经过了许多层的注意力模块,此时预测下一个 token 的计算过程,完全基于序列中最后一个向量

每个词的初始嵌入是一个高维向量,只编码了该单词的含义,与上下文无关,当然向量还编码了词的位置信息,这个向量足以说明这个词是什么,以及它在文中的位置

我们用 E 表示这些嵌入向量,最好的目标是通过一系列计算,产生一组新的、更为精准的嵌入向量,比如那些用形容词修饰的名词所对应的向量

假定一个场景:每个名词都在问:"我前面有形容词吗",这样的提问被编码为了另一个向量,我们称它为这个词的"查询" Query,查询向量的维度比嵌入向量小的多,比如 128 维

要得到查询向量,先取一个矩阵,记为 ,再乘以嵌入向量,,这样就给每个 token 算出一个查询向量(矩阵内部的数值都是模型的参数)

这个矩阵在某个注意力头中的作用,非常难解释,但是我们还是想象一个它也许能学会的例子

假设这个查询矩阵,将嵌入空间中的名词映射到较小的查询空间中的某个方向(12288 维 -> 128 维),用向量来编码"寻找前置形容词"的概念

同时我们还需要第二个矩阵,叫做"键矩阵",也会与每个嵌入向量相乘,产生第二个向量序列,称为"键" Key,可以把它视为想要回答"查询" Query

和查询矩阵一样,它也会将嵌入向量映射到相同的低维度空间

当键与查询的方向对齐时,就能认为它们相匹配

比如键矩阵会将形容词"毛茸茸的"映射到和名词"生物"对应的查询向量高度对齐的方向上

为了衡量每个键与每个查询的匹配程度,我们要计算所有可能的键-查询对之间的点积(这里圆点越大,点积就越大,键与查询就越对齐)

网格中的值,可以是负无穷到正无穷的任何实数,这个分数代表与每个词其它词的相关程度

这些分数的用法就是对每一列加权求和,权重为相关性,这样数值就不能是无穷大,而是要介于 0 和 1 之间,并且每列总和为 1

所以对每列应用 softmax 函数进行归一化,此时就能将每一列看作权重,表示左侧的键与顶部的查询的相关度,我们称这个网格为注意力模式 Attention Pattern

为了数值稳定性,建议将所有点积除以键-查询空间维度的平方根,整个表达式外层的 softmax 函数应理解为逐列的计算

在训练过程中,对给定示例文本跑模型时,模型会根据正确预测出下一个词的概率高低,来进行奖惩,并稍微调整各个权重

而效率更高的一种方法是,让它同时预测每个初始 token 子序列之后,所有可能的下一个 token

比如之前的序列既可以预测 creatrue 的下一个 token,和 the 的下一个 token

就注意力模式而言,意味着不能让后词影响前词,不然就会泄露接下来的答案

也就是说我们希望左下方,这些代表后方 token 影响前方的位置,能被强制变为 0

常见方法是在应用 softmax 之前,先把它们设为负无穷,在应用 softmax 后就都会变为 0,但列仍保持归一化,这一过程称为掩码 Masking

关于注意力模式,值得一提的是,其大小等于上下文长度的平方,这就是为什么上下文长度会成为大语言模型的巨大瓶颈

出于对更大上下文窗口的渴求,注意力机制出现了一些变体,旨在使上下文更具扩展性

算出该模式,就能让模型推断出每个词与其他哪些词有关,然后就是去更新嵌入向量,把每个词的信息传递给与之相关的其他词

这个方法要用到第三个矩阵,称之为"值矩阵" Value,将它乘以前面那个词的嵌入向量,得到的就是"值向量" Value Vector,这个就是要给后词的嵌入向量所加的向量

因此这个值向量与嵌入向量处于同一个高维空间

此时再来看网格图,就不用管键和查询了,毕竟计算出注意力模式后,这些都用不着了

这时用值矩阵分别乘以嵌入向量,就可以得到一系列值向量,对于网格中的每一列,需要给每个值向量乘以该列的对应权重

最后,为了更新该列对应的嵌入向量,也就是最开始没有上下文含义的词嵌入向量,我们要将该列中所有带权值向量加和,得到想要引入的变化量 ,然后把它加入到原始嵌入向量上(残差连接),预期得到一个更精准的向量,编码了更丰富的上下文信息

值矩阵是一个 12288 x 12288 的方阵(1.5 亿参数),因为它的输入输出都存在于高维的嵌入空间

更高效的做法是让值矩阵所需的参数量,等于键矩阵和查询矩阵的参数量之和,对于并行运行多个注意力头来说,这一点很重要

具体做法是,将值矩阵分解为两个小矩阵相乘,建议把它整体视为一个线性映射,输入和输出都在这个高维的嵌入空间,只不过是实践中分为两个步骤

右边的第一个矩阵的行数较少,通常等于键-查询空间的维度,可以看作是将较大的嵌入向量降维到较小的空间(value down matrix)

左侧的第二个矩阵,则是从小空间映射回嵌入空间,得到用于实际更新的向量(value up matrix)

这种操作的实质就是对大矩阵进行"低秩分解"(LoRA)

交叉注意力涉及的模型,会处理两种不同类型的数据,比如原文与正在被翻译出来的译文,或是语音音频与正在被转录出来的文字

和自注意力唯一的区别是,键和查询矩阵作用于不同的数据集

例如文本翻译模型中,键可能来自一种语言,而查询来自另一种语言,这个注意力模式就可以描述一种语言中的哪些词对应另一种语言中的哪些词

这种情况下,通常不会用到掩码,因为不存在后面 token 影响前面 token 的问题

Transformer 内完整的注意力模块,由多头注意力组成,大量并行地执行这些操作,每个头都有不同的键、查询和值矩阵

对于每个 token,每个头都会给出一个到加入到该位置上的嵌入向量的变化量,我们需要将这些变化量加起来,然后给该位置的初始嵌入向量加上这个加和,这个总和就是多头注意力模块输出的一列

总的来说,通过并行多头运算,模型能学习到根据上下文改变语义的多种方式

前面说到值矩阵被分成两个子矩阵相乘,每个注意力头都会有这对矩阵,这种设计是可行的,但是论文中的写法有些不同

这些 value up matrix 会合在一起被称为"输出矩阵",与整个多头注意力模块相关联

而单个注意力头的值矩阵,则单指第一步的矩阵 value down matrix

流经 Transformer 的数据,不只是经过单个注意力模块,它之后还会经过多层感知器 MLP 模块,并且它还会多次重复这两种操作

这意味着,某个词吸收了一些上下文信息后,含义细致的嵌入向量还有更多机会被周围含义细致的嵌入向量所影响

越是接近网络深处,每个嵌入向量就会从其他嵌入向量中吸收越多的含义,理想的话,对于输入的内容,能够提炼出更高级、更抽象的概念(包括情感等)

尽管注意力模块参数量很大,但也只占网络参数量的

因而尽管注意力机制吸引了所有的注意力,但实际上更多的参数来自于其它模块

最后,其实注意力成功的原因并不在于它能实现什么特定行为,而是它的可并行性

相关推荐
钟智强2 小时前
线性映射(Linear Mapping)原理详解:机器学习中的数学基石
人工智能·算法·机器学习
PHOSKEY2 小时前
光子精密QM系列闪测仪如何实现VR注塑外壳大型面平面度的秒级检测
机器学习·计算机视觉
红尘炼丹客2 小时前
简析大模型(LLM)技术与量化交易
人工智能·金融
samroom2 小时前
langchain+ollama+Next.js实现AI对话聊天框
javascript·人工智能·langchain
西西o2 小时前
面向Agentic Coding的未来:豆包Doubao-Seed-Code模型深度测评与实战
人工智能
LO嘉嘉VE2 小时前
学习笔记十六:多变量决策树
决策树·机器学习
行者常至为者常成2 小时前
基于LangGraph的自我改进智能体:Reflection与Reflexion技术详解与实现
人工智能
菠菠萝宝2 小时前
【Java手搓RAGFlow】-9- RAG对话实现
java·开发语言·人工智能·llm·jenkins·openai
大佬,救命!!!3 小时前
最新的python3.14版本下仿真环境配置深度学习机器学习相关
开发语言·人工智能·python·深度学习·机器学习·学习笔记·环境配置