用过 ChatGPT 就会觉得它像在聊天、会写代码。大语言模型(LLM)内部其实一直在做同一件事:根据已经出现的上文,预测下一个词。训练时在大量文本上学这个动作,生成时按概率挑一个接到后面,再预测下一个。
本文从这句话往下拆:模型看到的单位是什么,怎么变成向量,注意力和 Transformer 怎么工作,以及它是怎么训练、怎么对齐的。
预测下一个词
给模型一句话的开头:
「我早上起来喝了一杯……」
它对词表里每个候选算出「它是下一个的可能性」,得到一张概率表:咖啡 32% / 水 25% / 牛奶 11% / …。然后按这张表挑一个(比如「咖啡」),把「我早上起来喝了一杯咖啡」当成新的输入,再算下一张表。这样一路续下去,直到生成一个表示结束的特殊标记。这种「用自己的输出当下一步输入」的方式叫自回归。
写成公式,就是一个条件概率:已知前 个 token,给出第 个的分布。
- :第 个位置的 token。
- :它前面的所有 token,也就是上文。
- :模型的全部参数。
整段文本的联合概率,是把每个位置的条件概率连乘起来。这是概率的链式法则,也是语言模型的定义:
具体到一步:模型先对词表里每个词输出一个未归一化的分数,叫 logits,再用 softmax 压成一个和为 1 的概率分布。上面那张「咖啡 32% / 水 25%」就是这样来的。
Token
上面一直说「词」,模型实际处理和预测的单位叫 token。
我们读「苹果」是两个字。模型不按字、也不按词处理,而是按一种折中的单位:子词(subword)。常用词整块保留,生僻词拆成更小的片段,标点、空格也各占一块。切完,每一块映射到词表里的一个固定编号。
这一块就是 token(词元)。这套切分叫 tokenization,常见算法是 BPE,GPT-2 之后很多模型用的是按字节做的 BPE。按字的话序列太长、计算太贵;按整词的话词表会很大,也总会遇到没见过的新词。
上下文长度(比如 8K、128K)指的是一次能处理多少个 token。API 计费、速度、能塞多少资料,也都按 token 算。
嵌入
编号本身没有意义。99164 和 99165 相邻,代表的内容可能毫不相关。所以每个编号会经过一张查找表,映射成一个几百到几千维的实数向量。
这个映射叫 embedding,中文是嵌入:把离散的 token 嵌进连续向量空间。查出来的那个向量叫嵌入向量。Word2Vec 那会儿大家常说词向量,指的也是这种向量,不过那时的单位是词。现在切出来的是子词,叫嵌入更准确。
查找表给每个 token 的是一个固定的初始向量,和上下文无关。语义相近的 token,向量往往也比较近,但同一个写法仍可能对应不同意思。
Word2Vec 里有个常被拿来举例的运算:向量(国王) − 向量(男人) + 向量(女人) 会靠近 向量(女王)。那是静态词向量上的观察。GPT 这类模型的查找表不一定能干净地做出这种算术,消歧主要靠下一节的注意力。
注意力
查找表给「苹果」的初始向量是静态的。同一个词的意思常常取决于旁边的词:
- 「我啃了一口苹果」:水果。
- 「我在发布会上买的苹果」:公司。
处理「苹果」这个位置时,模型会回看序列里的每一个 token,按相关度分配权重,再按权重把信息加权汇总,得到一个掺入了上下文的新向量。看到「啃」「一口」权重高,就往水果偏;看到「发布会」「买」权重高,就往公司偏。
这个机制叫注意力(attention)。每个位置都在看同一段里的其它位置,所以也叫自注意力(self-attention)。
实现上,每个位置的向量会乘上三个可学习的矩阵 ,投影成三个角色:
- Query(Q):当前位置要找什么。
- Key(K):每个位置用来被检索的标签。
- Value(V):每个位置实际携带的内容。
Q 和所有 K 做点积得到相关度分数,缩放后再做 softmax,变成权重,再用权重对所有 V 加权求和。这就是缩放点积注意力:
- :每个 Query 和每个 Key 的点积,也就是「谁和谁相关」的分数。
- : 是 Q/K 的维度。除以它做缩放,避免点积过大把 softmax 推到饱和区。
- 乘 :按权重汇总上下文,得到该位置的新表示。
softmax(QKᵀ / √dₖ) 决定关注谁、关注多少,乘 V 是按这个比例把信息汇总过来。这里对整段两两算相关度,计算量随序列长度 是 ,长上下文贵,主要就贵在这里。
实际会并行跑多组 Q/K/V,叫多头注意力(multi-head)。不同的头可以学到不同的关系,输出拼接后再做一次线性变换。
Transformer
单层注意力只汇总一轮信息。真正的模型把「多头自注意力 + 前馈网络(FFN)」打包成一个 block,再叠几十到上百层。每个子层通常还配残差连接和层归一化,让梯度能穿过很深的网络。这套架构是 2017 年论文提出的 Transformer。GPT 这类模型只用它的解码器部分,并且加了因果掩码:每个位置只能看它左边的 token,不能偷看后面的答案。
注意力本身分不清先后:把词序打乱,加权求和的结果可以不变。所以要另外注入位置信息。早期用正弦位置编码(positional encoding),现在常见的是 RoPE(旋转位置编码)这类相对位置方案。
预训练
GPT 这类模型的预训练任务不是随机遮住中间某个词(那是 BERT 的做法),而是给定前面的 token,预测下一个。一段文本里,每个位置都可以当训练样本。
预测得到的分布和真实那个 token 越接近越好,否则就调整参数。因为答案就在文本里,不需要人工标注,所以叫自监督。这个阶段叫预训练(pre-training)。
目标等价于最小化交叉熵(负对数似然):
- :平均到每个 token 的损失,越小表示预测越准。
- :模型给真实 token 的概率。
- :真实 token 的概率越接近 1,这项越接近 0;越接近 0,惩罚越重。
有了损失,就用反向传播求每个参数的梯度,再用 Adam 一类优化器更新 。在大量 GPU 上对很多 token 重复这个过程,就是预训练。
衡量语言模型好坏的常用指标是困惑度(perplexity),等于 ,也就是平均交叉熵再取指数。可以粗略理解成:模型平均要在多少个词里犹豫。
为了把下一个词预测准,参数里会压进语法、事实、常识和一些代码结构。这些不是一条条写进去的,是这个训练目标的副产品。
对齐
刚预训练完的模型只会续写。你问「怎么煮咖啡」,它可能接「怎么煮咖啡才好喝?这是很多人的疑问」,像在补全网页。
后面还有第二阶段。先用「指令 / 优质回答」样本做监督微调(SFT),让它遇到提问就作答;再用人对多个回答的排序,让模型偏向人更满意的输出。经典方法是 RLHF(基于人类反馈的强化学习),也可以用更简单的 DPO。这个阶段统称对齐(alignment)。
预训练决定它从文本里学到了多少,对齐决定它会不会按问题来答。
生成时怎么挑词
有了概率分布,还要落到一个具体的 token。每次都挑概率最高的(greedy)容易呆板、重复,所以一般会随机采样,并用温度 调节分布有多尖:
- 接近 0:几乎总选最高分,更稳定,也可以复现。
- :就是原来的 softmax。
- :分布被抹平,低分词也有机会,更散,也更容易出错。
再配合截断:top-k 只在概率最高的 个里采,top-p(核采样)只在累积概率达到 的最小集合里采。
几个容易混的地方
它不是检索数据库。存的是参数,不是一篇篇原文,答案是现算的。同一问题多问几次,结果可能不同,因为采样带随机性。
「幻觉」是这套目标带来的副作用。它要接一个概率高的、读起来顺的 token,并不是要保证为真。手头没有确切事实时,流畅但错的下一词,往往比留白更像训练时见过的文本,于是它会编。
它没有跨轮的持久记忆。每次都是把当前这段上下文重新读一遍再预测,超出窗口的内容就看不见了。聊天产品看起来像有记忆,多半是系统把历史对话又塞回了上下文。
参数量大不一定更强。数据质量、训练时数据和参数的配比、对齐质量都有影响。Kaplan 等人总结过 scaling law:算力、数据、参数配比合适时,测试损失会比较平滑地下降。Chinchilla 后来指出,很多大模型其实数据不够,该把更多算力花在数据上。
延伸阅读
- Vaswani et al., 2017,《Attention Is All You Need》:Transformer 原论文。
- Jay Alammar,《The Illustrated Transformer》:Q/K/V 和多头注意力的图解。
- Andrej Karpathy,《Let’s build GPT》 / nanoGPT:从零写一个很小的 GPT。
- Radford et al.,GPT-2《Language Models are Unsupervised Multitask Learners》
- Kaplan et al., 2020,《Scaling Laws》;Hoffmann et al., 2022,Chinchilla
- Ouyang et al., 2022,《InstructGPT》:SFT + RLHF。