理解大模型:从概率机器到认知伙伴
当我们第一次与ChatGPT对话时,那种感觉确实有些奇妙——我们输入一段文字,模型便以惊人的流畅度回应,仿佛在和一位博学的朋友交谈。但如果你仔细思考这个问题,一个更深层的谜题就会浮现:这套系统究竟是凭什么做到的?一个被训练来预测“下一个词”的数学模型,怎么就能写出文章、编写代码、甚至似乎理解了我们的意图?
这个问题正是本章要探讨的核心。我们将深入大语言模型的内部世界,从最底层的数学原理讲起,一路攀升到对模型行为的完整理解。通过这次旅程,你会明白大模型并非什么神秘的“思维机器”,而是一套精妙的概率系统——但正是这套系统,在达到一定规模后,展现出了令人惊叹的、几乎可以被称作“理解”的能力。
让我们从一个最基本的问题开始:模型是如何处理语言的?
语言的数字化困境
在探讨Transformer之前,我们有必要理解一个根本性的挑战:计算机如何理解语言?
人类语言是一种高度结构化的信息系统,但这种结构并非显式的规则,而是蕴含在词汇的选择、排列组合、以及上下文关系中。“苹果很好吃”和“好吃很苹果”传达的是完全不同的意思,尽管两句话使用了几乎相同的词汇。语言的这种特性使得简单的字符匹配无法真正捕捉语义——我们需要的不是表面的文字,而是文字背后所指代的概念、关系和意图。
传统计算机处理这个问题的方式有两种。一种是基于规则的系统,由语言学家手工编写语法规则和词典,模型根据这些规则解析句子结构。这种方法在封闭领域(如数学公式、特定格式文档)可以工作,但面对开放世界的自然语言时,规则的数量会爆炸式增长,而且语言本身还在不断演变。
另一种是统计自然语言处理。这种方法不再试图显式编码语法规则,而是从大量文本中统计词汇共现的概率。例如,“医生”和“医院”经常一起出现,“猫”和“喵”也有很强的关联性。通过这些统计信息,系统可以一定程度上理解词语之间的关系。但这种方法的局限很明显——它只能捕捉表层的共现规律,无法深入理解语义。
真正的突破来自分布式表示(Distributed Representation)的思想。其核心洞察是:词语的含义可以由它出现的上下文来定义。如果两个词在各种语境下都能相互替换,那么它们很可能具有相似的含义。这就是著名的“分布假说”(Distributional Hypothesis)。
基于这一思想,研究者开发了词嵌入(Word Embedding)技术。在数学上,词嵌入将每个词映射为一个稠密的向量——你可以把它想象成一个高维空间中的坐标点。在这个空间中,语义相近的词会被放置在彼此靠近的位置。“国王”和“女王”会很接近,因为它们都和皇室相关;“狗”和“猫”也会聚在一起,因为它们都是宠物、都和“主人”“宠物店”等词汇共同出现。
著名的Word2Vec模型展示了这种表示的力量。例如,通过简单的向量运算:`vec("国王") - vec("男人") + vec("女人") ≈ vec("女王")`。这种“语义算术”能力让人们第一次看到,语言可以被真正地“代数化”处理。
然而,词嵌入有一个根本性的局限:它是静态的。每个词在所有语境下都对应同一个向量。但我们知道,同一个词在不同语境下往往有不同的含义。“bank”可以是银行,也可以是河岸;“芯片”可能是食物中的土豆片,也可能是电子元件中的半导体芯片。静态词向量无法区分这些不同的含义。
更大的问题在于,词嵌入无法处理更复杂的语言现象。一个词的含义往往取决于它与其他词的关系网络——不仅是相邻的词,还包括句子中远距离的依赖、省略的部分、指代关系等等。理解“我看到那只松鼠爬上树”,我们需要知道“我”是主语、“看到”是谓语、“松鼠”是宾语,同时“爬上”的主语也是“松鼠”。这种关系跨越了多个词语,简单的共现统计无法捕捉。
这正是Transformer架构诞生的背景。
Transformer:注意力机制的革命
2017年,Google的研究团队发表了一篇名为《Attention Is All You Need》的论文。这篇论文提出了一种全新的序列处理架构,完全放弃了之前主流的循环神经网络(RNN)和卷积神经网络(CNN),转而完全依赖注意力机制(Attention Mechanism)。这篇论文被引用超过十万次,成为深度学习史上最具影响力的论文之一,而它所提出的Transformer架构至今仍是大语言模型的核心基础。
要理解Transformer的价值,我们需要回顾一下序列处理的传统方法。
循环神经网络的困境
在Transformer出现之前,处理序列数据的主流方法是循环神经网络(RNN)及其变体,如LSTM(长短期记忆网络)和GRU(门控循环单元)。RNN的核心思想是按顺序处理序列中的元素,每一步的输出不仅取决于当前输入,还取决于上一步的“隐藏状态”。这模拟了人类阅读时“理解是逐步累积的”过程。
然而,RNN存在一个根本性的缺陷:长距离依赖问题。当序列很长时,信息需要经过多次传递才能从一端到达另一端。在这个过程中,早期的信息会逐渐被稀释或丢失。你可以把它想象成在电话游戏中传话——传到最后一个人时,信息可能已经面目全非。
虽然LSTM和GRU通过引入门控机制部分缓解了这个问题,但它们在处理非常长的序列时仍然表现不佳。更重要的是,RNN的序列处理本质上是顺序的——必须从头到尾逐步计算,这使得并行化变得极为困难,训练速度受到严重制约。
注意力机制的本质
注意力机制的灵感来自人类视觉注意力。人类在看一个场景时,不会平等地处理所有信息,而是有选择地聚焦于重要的区域。类似地,在处理一段文本时,我们不会平等地关注每个词,而是根据任务的需要动态地调整关注点。
在机器翻译中,当我们翻译一个词时,通常需要参考原文中与之相关的其他词。例如,将中文“他送给我一朵花”翻译成英文时,翻译“花”时需要参考“送”和“一朵”,翻译“给”时需要参考“送”和“我”。这种跨距离的依赖关系在传统RNN中很难捕捉,但注意力机制可以直接建模。
具体来说,注意力机制通过查询-键-值(Query-Key-Value)框架来工作。想象你正在图书馆找书。“查询”是你心中想要的书籍描述(比如“关于量子物理的科普书”),“键”是每本书的书名和标签,而“值”则是书的实际内容。注意力机制会计算你的查询与每个键的相似度,然后根据相似度加权求和对应的值。
在Transformer中,每个词都被表示为三个向量:查询向量(Q)、键向量(K)和值向量(V)。这三个向量通过线性变换从词的嵌入表示中生成。对于序列中的每个词,它会与其他所有词计算注意力分数。注意力分数衡量的是当前位置对其他位置的关注程度。
注意力分数的计算过程可以表示为:
$$\text{Attention}(Q, K, V) = \text{softmax}\left(\frac{QK^T}{\sqrt{d_k}}\right)V$$
其中 $d_k$ 是键向量的维度。这个公式的直觉是:首先计算查询和键的点积,得到原始的注意力分数;然后除以 $\sqrt{d_k}$ 进行缩放(这是为了防止点积值过大导致 softmax 梯度消失);最后通过 softmax 将分数归一化为概率分布,用这个分布对值向量进行加权平均。
多头注意力:并行看世界
单一的注意力头只能捕捉一种类型的关系。但在自然语言中,词语之间的关系是多维度、多层次的。“主语-谓语”是一种关系,“指代关系”是另一种,“语义相似”又是第三种。
为了捕捉这些多样的关系,Transformer引入了多头注意力(Multi-Head Attention)。其思想很简单:并行运行多组注意力机制,每组使用不同的 $Q, K, V$ 投影,然后综合所有头的输出:
$$\text{MultiHead}(Q, K, V) = \text{Concat}(\text{head}_1, \ldots, \text{head}_h)W^O$$
其中每个 $\text{head}_i = \text{Attention}(QW_i^Q, KW_i^K, VW_i^V)$。
不同的注意力头会学习关注不同的模式。例如,一个头可能专注于捕捉语法主谓关系,另一个头可能关注词汇的语义相似性,还有一个头可能捕捉位置相邻的词之间的关系。通过这种方式,模型能够同时从多个角度理解文本。
位置编码:让序列有顺序
Transformer 架构中有一个微妙但关键的设计:注意力机制本身是位置无关的。也就是说,如果不额外提供位置信息,模型无法区分“猫追狗”和“狗追猫”——因为这两个句子的词语完全相同,只是顺序不同。
为了解决这个问题,Transformer 使用了位置编码(Positional Encoding)。其思想是在每个词的嵌入向量中添加一个与其位置相关的信号。论文中使用了正弦和余弦函数的组合:
$$PE_{(pos,2i)} = \sin\left(\frac{pos}{10000^{2i/d_{model}}}\right)$$ $$PE_{(pos,2i+1)} = \cos\left(\frac{pos}{10000^{2i/d_{model}}}\right)$$
其中 $pos$ 是位置,$i$ 是维度索引。这种设计的精妙之处在于,对于任何固定的偏移 $k$,$PE_{pos+k}$ 可以表示为 $PE_{pos}$ 的线性函数,这意味着模型可以轻松学习通过相对位置来注意。
后续的研究者还提出了多种其他位置编码方案,如旋转位置编码(RoPE)、相对位置编码(Relative Positional Encoding)等,这些方案在效率和泛化性上各有优势。
Transformer的整体架构
现在我们可以将所有这些组件组合起来,看看完整的Transformer架构。
标准的Transformer采用了编码器-解码器(Encoder-Decoder)结构,最初设计用于机器翻译任务。编码器负责处理源语言序列,解码器负责生成目标语言序列。
编码器由多个层(Layer)堆叠而成,每层包含两个子层: 1. 多头自注意力层:对输入序列进行自注意力计算,捕捉词与词之间的关系 2. 前馈神经网络层:对每个位置独立应用相同的非线性变换
每个子层都使用了残差连接(Residual Connection)和层归一化(Layer Normalization)。残差连接允许梯度直接流过,缓解深层网络的训练困难;层归一化则稳定了训练过程。
解码器在编码器的基础上增加了一个掩码多头注意力层(Masked Multi-Head Attention),确保在生成第 $t$ 个词时,只能看到第 $1$ 到 $t-1$ 个词的信息——因为第 $t$ 个词本身是待预测的目标,不应该被看到。
```mermaid graph TB subgraph 编码器端 A1[输入嵌入 + 位置编码] --> B1[多头自注意力] B1 --> C1[Add & Norm] C1 --> D1[前馈神经网络] D1 --> E1[Add & Norm] E1 --> F1[堆叠 N 层] end
subgraph 解码器端 A2[输出嵌入 + 位置编码] --> B2[掩码多头注意力] B2 --> C2[Add & Norm] C2 --> D2[编码器-解码器注意力] D2 --> E2[Add & Norm] E2 --> F2[前馈神经网络] F2 --> E3[Add & Norm] E3 --> G2[堆叠 N 层] end
F1 --> D2 G2 --> H[线性层 + Softmax] H --> I[输出概率分布] ```
GPT系列模型只使用了Transformer的解码器部分,这被称为仅解码器架构(Decoder-only)。这种设计更适合语言建模任务——给定前面的词,预测下一个词。BERT则只使用了编码器部分,采用掩码语言模型(Masked Language Model)目标,随机遮盖输入中的一些词然后预测它们。
Token化:语言如何被切分
在理解了Transformer的工作原理后,一个更基础的问题浮现出来:语言是如何被输入模型的?
你可能以为模型直接处理的是单词或汉字。但实际情况要复杂得多。现代大语言模型使用的是一种被称为子词分词(Subword Tokenization)的技术,而分词的基本单元被称为 Token。
为什么需要子词分词?
如果简单地按空格切分英文文本,我们很快会遇到问题。首先是词汇表覆盖率的问题:自然语言中存在大量低频词,如果为每个词分配一个独立的表示,词汇表会变得极其庞大,而许多词只出现很少的次数,模型难以学到好的表示。
其次是词形变化和组合的问题。英文中有大量的词根、词缀组合:run、runs、running、runner,虽然形态不同,但核心语义相近。如果把它们当作完全不同的词处理,模型需要为每种形态单独学习,效率很低。
中文的情况更特殊。中文没有天然的空格分隔,词与词之间的边界并不像英文那样清晰。“南京市长江大桥”可以切分为“南京|市|长|江|大桥”,也可以是“南京市长|江大桥”——不同的切分方式传达了不同的含义。
主流分词算法
现代大语言模型主要使用三种分词算法:BPE(Byte Pair Encoding)、WordPiece和SentencePiece。这些算法的共同思想是:既不是按字符切分,也不是按完整单词切分,而是找到一种介于两者之间的平衡。
BPE算法的核心思想非常简洁:它从一个字符级别的词汇表开始,然后反复合并最频繁相邻的字符对,直到达到预设的词汇表大小。例如,如果“t”和“h”在文本中频繁连续出现(如在"the"、"this"、"that"等词中),BPE会将它们合并为一个新的单元“th”。这个过程不断迭代,最终词汇表中会包含高频的词根、词缀、甚至完整单词。
以句子“低低地飞”为例,假设使用一个简单的中文分词方案,可能被切分为:`低 | 低 | 地 | 飞`——这意味着4个Token。而如果使用BPE风格的子词分词,可能会合并连续的相同字符:`低低 | 地 | 飞`——变成3个Token。更复杂的模型甚至可能将“低低”进一步拆分,取决于词汇表的构建方式。
Token的成本账
理解Token的概念对于高效使用大模型至关重要,因为Token数量直接影响API调用的成本和模型的计算开销。
让我们做一些具体的计算。以英文为例,平均而言,一个Token大约对应4个字符或3/4个单词。在中文环境下,由于汉字的信息密度更高,一个Token大约对应1到2个汉字。这意味着,用中文与模型交流,相同内容的Token消耗可能是英文的1.5到2倍。
GPT-4Turbo的上下文窗口达到128K Token,如果全部用来存储中文文本,大约可以容纳约10万到20万字——这相当于一部中篇小说的篇幅。但如果你需要在对话中引用很长的文档,这个数字会迅速消耗。
Token化还带来了一些有趣的现象。例如,某些看似简短的查询可能消耗大量Token,因为模型实际上在内部处理的是一个很长的思考过程(Chain-of-Thought推理)。而一些看似复杂的任务,如果恰好可以用模型词汇表中已有的组合来表达,反而会比较经济。
语义表示的层级结构
Token不仅仅是语言的处理单元,更是语义表示的基础。让我们深入一层,看看这些Token的向量表示是如何组织的。
现代大语言模型使用嵌套的表示层级:
第一层是Token嵌入。每个Token被映射为一个高维向量(GPT-3使用12288维,Llama 2使用4096维),这个向量编码了Token的基本语义特征。这些向量是通过在大规模语料上的训练习得的,语义相近的词在向量空间中距离较近。
第二层是Transformer层处理。每个Transformer层都会对所有Token的表示进行进一步处理,通过注意力机制建模Token之间的关系。每经过一层,Token的表示就更加上下文相关——它不仅包含了自身的信息,还融入了它在当前语境中的意义。
第三层是任务相关的表示。模型最后一层的输出可以被视为Token的最终表示。对于不同的下游任务,可以使用这些表示来做分类、生成等任务。在语言模型中,我们通常使用最后一个Token的表示(或者所有Token表示的加权平均)来预测下一个Token。
这种层级结构带来一个重要现象:不同层的表示编码了不同粒度的信息。较低层更关注词汇级别的信息(如词性、形态),中间层可能编码句法结构,深层则更倾向于语义和任务相关的信息。这也是为什么在分析模型行为时,我们需要关注不同层的激活模式。
规模的力量:涌现现象
如果对大语言模型的发展史进行一个概括,最核心的主题可以用一个词来总结:规模(Scale)。
从GPT-1(1.17亿参数)到GPT-2(15亿参数)再到GPT-3(1750亿参数),模型的能力随着参数规模的增长而显著提升。参数规模的增长不仅仅是简单的量变,而是带来了质的变化——研究者将这种现象称为涌现能力(Emergent Abilities)。
什么是涌现能力?
“涌现”一词来自复杂系统理论,指的是当系统达到一定规模或复杂度时,突然展现出此前不存在的能力。这些能力无法从系统的组成成分中直接预测,只有在实际运行时才会显现。
举一个直观的例子:冰的流动性是水的涌现属性。单看一个水分子,你无法预测它会流动;只有当大量水分子聚集在一起,在特定温度条件下,流动这一宏观现象才会出现。
大语言模型的涌现能力与此类似。当模型的规模突破某个临界点时,它会突然展现出一些在小模型上完全不存在的能力。
2022年,Google的研究者在论文《Emergent Abilities of Large Language Models》中系统性地研究了这一现象。他们发现,许多能力确实表现出明显的涌现模式:
- **算术能力**:小模型无法正确进行两位数乘法,但当规模超过某个阈值后,突然能够正确计算
- **多步推理**:小模型只能进行单步推理(如简单的是非判断),但大模型可以进行多步逻辑推演
- **代码理解与生成**:小模型只能生成碎片化的代码片段,大模型可以理解复杂的代码库并生成完整的程序
- **上下文学习**:小模型需要示例才能学习新任务,大模型可以从指令中直接学习(Zero-shot)