5 第五章
无论是MLP还是卷积神经网络,它们都是没有记忆的,因为上一次的输入或输出不会影响下一次的输出结果。
但日常生活中很多问题是有时序相关性的,例如股票、人类的语言、音乐等,它们的输出不仅取决于当下的输入,还取决于过去历史的输入。
为了解决记忆问题,人们发明了循环神经网络。
5.1 循环神经网络
循环神经网络还是从MLP出发,但我们可以换个角度重新审视全连接层:
对于记忆,网络里没有什么东西是有存储性质的,只有隐藏层和隐藏单元,回顾隐藏单元\(h_i = a[\theta_{i1} x_1 + \theta_{i2} x_2 + ... + \theta_{in} x_n + \theta_{i0}]\),它只是关于当前输入的加权求和而已。
然而这就够了,我认为一个很好的观点是一个事情的真相等于它所有发展的历史过程,即过程本身就包含了事情的本质。秉持这个观点,一次输入的所有记忆,其实就包含在了所有隐藏层的隐藏单元里。
因此为了获得记忆,我们只需要在输入时把上一次的隐藏层纳入考虑,如图所示:
其中黄颜色的是隐藏层之间的连接,满足:
\[ h_{(i, t)} = a\left[ (\omega_{i1} h_{(1, t-1)} + \omega_{i2} h_{(2, t-1)} + \dots + \omega_{im} h_{(m, t-1)}) \\+ (\theta_{i1} x_1 + \theta_{i2} x_2 + \dots + \theta_{in} x_n) \right] \]
所以循环神经网络基本上是在MLP的基础上,隐藏单元除了计算当前输入的加权求和,还会添加上一次计算得到的隐藏层所有隐藏单元的加权求和,即:
\[ [H_t] = a[\Omega · [x_t]+ W · [H_{t-1}] + \beta] \tag{5.1}\]
其中\(W\)是激活层之间的状态转移矩阵。
5.2 语义空间
智能界一直有几大不同类型的任务,例如图像处理、音频处理等,其中一个大类就是自然语言处理。我个人认为自然语言处理是其中难度最高的,或许没有之一。
为什么呢?至少我觉得语言和思维、意识等是深度绑定的,语言可能是一个范畴嵌套另一个范畴,然而这种嵌套也不意味着包含,两个范畴可能会相互嵌套,也许某种语境下这个范畴是另一个范畴更高等级的对象,然后在另一个情景下又反过来了。这种相互嵌套,甚至自我嵌套、反复、循环、分离、结合、交叉、穿越…的东西,和哲学家想探寻的关于我们自己意识里什么是“我”的东西很像。也许它们本就是同一个东西的不同面,因为没有语言,如何去表达思维呢?如果一个人说自己有很丰富的思想活动,但却没法用语言描述出来,那这种脑内的感觉,能否真正构成组成“自我”的坚实?人类意识真的能依靠这种朦胧不清的感觉来构建出如此复杂、完整、连贯的自我认知吗?答案是不知道,但我更相信语言、词汇的丰富度决定了一个人意识的边界及其丰富度。
考虑更糟糕的情况,甚至连“我”这个词,以及它所有相关连的意象,都只能在语言系统里去思考,我们试图用语言去解释一个可能比语言范畴大的多的多的“我”的概念或者意识。这是非常迷人的、又能让我们感到相当绝望。
毫无疑问语言是复杂的,但语言也有基本的评判标准,其实算不上标准,更像是一种心理衡量。上世纪五六十年代,美国心理学家奥斯古德做了大量研究之后发现,人类对于某个词汇或概念的评价,主要落在三个维度上,分别是:好坏(good-bad)、强弱(strong-weak)、快慢(active-passive)。
假设分别打分从-10~10分,那“导弹”打分则是[-9(坏)、8(强)、8(快)]。那“苹果”一词可能是[3(中性偏好)、-5(较弱)、-7(较慢)]。
这三个坐标可以画在一个三维坐标系里,这个关于所有词汇的语义坐标系就构成了奥斯古德语义空间:
在空间两个接近的向量可能就表示两个意思相近的词。例如“狗”和“猫”。
这种思想和大语言模型的词嵌入不谋而合,词嵌入实际上就是一种高维的语义空间,一个经典的例子是:
\[ \vec{v}_{\text{国王}} - \vec{v}_{\text{王后}} \approx \vec{v}_{\text{男人}} - \vec{v}_{\text{女人}} \]
即在向量空间中,“从男人到女人”的平移向量,与“从国王到王后”的平移向量几乎是完全平行且等长的:
且 图 5.4 中红色箭头的向量场方向是这个空间中关于“性别”的方向,或者在这个方向上描述的是与性别相关的东西。
那为什么不用三维的语义空间去量化词语呢,为什么大模型通常会用很高维的空间去量化,例如gpt3的量化是12288维?也就是用12288个数字代表一个词(严格地说是一个token)。
关键在于1984年提出的约翰逊-林登斯特劳斯定理,简单来说就是越是在高维空间中,任意两个向量越是近似正交或近似垂直的。
这导致高维空间里“基本上可以用的维度“比空间实际维数大得多(大约呈弱指数关系),这些“基本上可以用的维度”都能用来表示语言的不同特征。那语义空间的表达能力将随着维数升高而呈指数倍增长。
类似这种感觉:在三维空间里,我们只能找到3根互相垂直的坐标轴,多加一根就会互相干扰。但在 12288维空间里,大模型可以找到数以亿计的、几乎互不干扰的方向,每个方向都可以像那条红色向量场一样,独立表达一种全新的语义。
为什么独立性那么重要?因为语言除了词汇,还有特征。在三维空间里只有三个独立方向,那关于性别、歧视、讽刺、失落、金钱、变得迟钝、衰老等无数种特征的向量场就会被迫挤在一起,让模型根本无法学习。
5.3 自注意力机制
自注意力机制是Transformer模型的核心机制,它能让模型在处理序列数据时,动态地关注序列中不同位置的信息,从而更好地理解序列的含义。
以自然语言处理的单头自注意力机制为例。首先是对自然语言进行分词(token化),分词就是把句子拆成一个个单词或子词,为了简单起见就假设分词都是单词。然后把每个分词也就是token,量化为语义空间里的一个向量\(\mathbf{x}_i\)。\(\mathbf{x}_i\)通常是一个高维向量,例如gpt3的12288维、llama3的16384维等。
一个Transformer的自注意力块 \(sa[\cdot]\) 接受 \(N\) 个输入 \(\mathbf{x}_1 \sim \mathbf{x}_N\),其中\(\mathbf{x}_i\)的输入维度为\(d\),\(\mathbf{x}_i \in \mathbf{R}^{d\times 1}\)。
\(\mathbf{x}_i\)首先会经过一个线性变换(没有激活函数)变成相同维度的\(\mathbf{v}_i\):
\[ \mathbf{v}_i = \Omega_v \mathbf{x}_i + \beta_v \tag{5.2}\]
其中\(\Omega_v \in \mathbf{R}^{d \times d}\)是一个变换矩阵,\(\beta_v \in \mathbf{R}^{d \times 1}\)是偏置向量。
然后所有的自注意力输出\(sa_i[\cdot]\)是关于\(\mathbf{v}_1 \sim \mathbf{v}_N\)的加权和:
\[ sa_i[\cdot] = \sum_{j=1}^N a[\mathbf{x}_j, \mathbf{x}_i] \mathbf{v}_j \tag{5.3}\]
其中\(a[\mathbf{x}_j, \mathbf{x}_i]\)是第\(i\)个输入对第\(j\)个输入的注意力权重,满足\(\sum_{j=1}^N a[\mathbf{x}_j, \mathbf{x}_i] = 1\):
先不考虑注意力权重的计算方法,怎么理解\(\mathbf{v}_i\)代表啥呢?一个观点是\(\mathbf{v}_i\)代表的是类似 图 5.4 中红色箭头的特征方向,也就是说\(\mathbf{v}_i\)是语义空间里的“使…化”算子,例如文字“我买了个苹果手机”,在初始语义空间里,苹果向量只是保持它的本意,也就是水果,苹果向量和橘子、梨之类的向量是比较接近的。而手机向量则聚集在电子产品周围,和水果的距离较远。
当“手机”这个token输入并经过变换后,它的输出\(\mathbf{v}_{手机}\)可能代表一个向量场,然后某个向量沿着这个向量场移动,最终在语义空间里表达的含义则可能是“使这个向量手机化或电子化”,而注意力机制则是筛选出基于上下文,对于“苹果”这个向量,应该强调“手机化”还是“水果化”,或者“政治化”等等。
也就是说,transformer本质上在做这样一件事:对于原始的,不带任何上下文语境的token向量,transformer的注意力机制会引导每个向量在语义空间游走,使其富含关于上下文的信息。
所以\(sa_i[\cdot]\)可以被看作是基于给定输入或上下文之后产生的,用于给每个输入\(\mathbf{x}_i\)添加上“富含上下文信息”的位移向量。
例如对于输入序列 “我买了一个黄色的苹果手机”,然后观察目标词“苹果”的词向量是如何在语义空间中游走的:
1.初始状态 \(\mathbf{x}_{苹果}\):刚进入模型时,它只是一个孤立的词汇,在未结合上下文时默认停留在 “水果区”,与香蕉、橘子、梨等水果紧挨在一起。
2.第一步(吸收“手机”上下文):通过注意力权重 \(a[手机,苹果]\),吸收来自“手机”的“电子化”位移向量 \(\mathbf{v}_{手机}\),得到增量 \(\Delta \mathbf{x}_1 = a[手机,苹果] \cdot \mathbf{v}_{手机}\)。此时向量被拉出水果区,平移至 \(\mathbf{x}' = \mathbf{x}_{苹果} + \Delta \mathbf{x}_1\),定位到“苹果品牌的智能手机”。
3.第二步(吸收“黄色”上下文):再次吸收来自修饰词“黄色”的位移向量 \(\mathbf{v}_{黄色}\),得到增量 \(\Delta \mathbf{x}_2 = a[黄色,苹果] \cdot \mathbf{v}_{黄色}\)。最终向量游走到 \(\mathbf{x}'' = \mathbf{x}' + \Delta \mathbf{x}_2\)“黄色机身的苹果手机”。
这个过程如图 图 5.6 所示:
因此在transformer架构中,除了注意力机制,还有一个直接前馈网络,用于添加原始词向量:
5.4 注意力权重计算
注意力权重决定了当前token要吸收哪些上下文,并分别占多少。为了计算权重,分别引入两个线性变换:
\[ \begin{aligned} \mathbf{q}_n & = \Omega_q \mathbf{x}_n + \beta_q \\ \mathbf{k}_m & = \Omega_k \mathbf{x}_m + \beta_k \end{aligned} \tag{5.4}\]
其中\(\mathbf{q}_n\)和\(\mathbf{k}_m\)分别称为查询和键。\(\Omega_{q},\beta_q\)和\(\Omega_{k},\beta_k\)则是模型从海量训练文本中学习到的参数,它们会把\(\mathbf{x}_n\)和\(\mathbf{x}_m\)投射到另一个空间去,分别用\(\mathbf{q}_n\)和\(\mathbf{k}_m\)来代表。它俩点积\(\mathbf{k}_m^\top·\mathbf{q}_n\)的大小代表模型从海量文本里学习到的\(\mathbf{x}_n\)和\(\mathbf{x}_m\)的平均关联程度。
为了能够计算 \(\mathbf{q}_n\) 与 \(\mathbf{k}_m\) 的点积,它们必须具有相同的维度 \(d_k\)。在单头自注意力中,通常设 \(d_k = d\),而在多头自注意力中,每个头的维度则是 \(d_k = \frac{d}{H}\)。
由此可得\(\mathbf{x}_n\)对于\(\mathbf{x}_m\)的注意力权重为:
\[ a[\mathbf{x}_m,\mathbf{x}_n]={\text{softmax}}_m [\mathbf{k}_m^\top·\mathbf{q}_n] \tag{5.5}\]
其中 \(m\) 下标代表了对所有键的遍历。\(\text{softmax}\)是归一化函数。
以“我买了一个黄色的苹果手机”为例,整个自注意力权重矩阵如下表所示:
从这个表格中可以非常直观地观察到注意力的工作方式:
1.每一列代表一个词在主动向上下文提问: 以第6列[苹果](\(\mathbf{q}_6\))为例,它作为查询方,会去和句子中每一个词的键做点积计算关联度。结果显示它与 [手机](\(\mathbf{k}_7\))的关联度最高,分配了0.58(归一化了之后)的最大权重,然后修饰它的 [黄色](\(\mathbf{k}_4\))分配了0.29的权重,其余无关词的权重则接近 0。
2.纵向归一化: \[ a[\mathbf{x}_m, \mathbf{x}_n] = \frac{\exp(\mathbf{k}_m^\top \mathbf{q}_n)}{\sum_{j=1}^N \exp(\mathbf{k}_j^\top \mathbf{q}_n)} \]
因为点积计算出来的结果可以是任意值,只是依靠正负的大小判断关联性强弱,归一化函数可以把这种相对判断转化成比例。
3.得到位移向量\(sa_i[\cdot]\): 以第6列[苹果]为例,注意力机制将各token的\(\mathbf{v}\)按列权重加权求和,得到最终注入给[苹果]的语境修正量: \[ sa_6[\cdot] = 0.58 \mathbf{v}_{\text{手机}} + 0.29 \mathbf{v}_{\text{黄色}} + 0.13 \mathbf{v}_{\text{苹果}} + \dots \]
这正是 图 5.6 中由“手机化”和“黄色化”合成的紫色总位移向量。
值得注意的是关于某些词的“自我保留”(如第 5 列的 [的]),有些词自己对自己的自注意力很高。像“的”、“了”这类虚词或功能词,本身没有具象的实体语义,在很多注意力头中不需要去大量吸收其他词的语境来做“语义消歧”,就算加上自己的位移向量后也表示相同意思,因此它们仅仅将自身的语法属性原封不动地传递给下一层。
5.5 多头注意力
多头就是说不止一个注意力头在做注意力机制,而是 \(H\) 个注意力头同时做,每个注意力头都有自己独立的参数,都会计算出自己独立的\(sa[\cdot]\)。
为什么这样做,因为一个注意力头无法学习完语言所有可能存在的隐规则,多个注意力头都有自己独立的参数,它们学习到的注意力机制也就不相同,然后这些\(H\)个头共同完成对原始输入的“富义”化。
通常来说,如果输入维度依然是\(d\)维,但是有\(H\)个头,那么每个头的\(\mathbf{q}, \mathbf{k}, \mathbf{v}\)向量的维度都是 \(\frac{d}{H}\)。最后每个头的\(sa[\cdot]\)拼接在一起形成\(\text{Mhsa}[\cdot]\):
5.6 完整结构
一个transformer层的完整结构还包括输出后的一个MLP网络:
但这个MLP不是全连接的,它是分别对每个\(\mathbf{x}_i + \text{Mhsa}_i[\cdot]\)单独变换。
关于MLP层是干嘛的,Anthropic公司逆向了 transformer,发现MLP层的参数可能存储的是从海量文本中学来的关于输入的更多的“事实”。
因为注意力机制只是让每个token获得关于上下文的语义,然后就不提供更多的东西了。但是当大模型输入例如“特朗普”时,虽然输入没有上下文,但模型依然能够提供更丰富的信息,这些信息是没法由注意力机制提供。
可以认为这些额外的信息是由MLP层提供的,MLP层的参数存储了很多超越输入上下文的“事实”,这些“事实”也会被单独添加给每个\(\mathbf{x}_i + \text{Mhsa}_i[\cdot]\)。
关于 Transformer,非常推荐 3Blue1Brown 制作的可视化系列视频:
5.7 多个transformer层
图 5.11 是单个transformer层,以gpt3为例,它的每个transformer层有96个注意力头,而且它一共有96个transformer层。
为什么要这么多层?其实前文我们忽略了一个细节,那就是默认最开始token量化的时候,语义空间是有意义的。
但大部分模型训练的时候,输入会被随机初始量化,此时整个语义空间无比混乱,毫无规则可言。
对大模型来说,首先需要一层一层地来提取或总结单个token的语义,可能直到中间的30~40层大模型才只是先学会了如何把单个不带上下文的token合理地放入语义空间。
在30~40层之后,才是像前文提到的再用注意力机制让词语之间产生联系,构建上下文语义。