大模型核心算法解剖:Attention is All You Need,七年后的我们在做什么
我要说一个可能颠覆你认知的观点:大模型最神奇的地方,不在它的"大脑",而在它的"学习方式"。
2017 年,Google 发表了那篇改变 AI 历史的论文——标题叫《Attention is All You Need》。七年后的今天,几乎所有的大语言模型(GPT、Claude、DeepSeek、Qwen……)都建立在这篇论文的框架之上。但如果你以为大模型只是"更大的神经网络",那你只看到了故事的表层。
今天,我们来把大模型的核心算法一层层拆开。不是教科书式的罗列,而是像解剖一台精密仪器——每个零件为什么要这样设计?它解决了什么问题?理解这些,你才能真正看懂 AI 行业的底层逻辑。
一、从"记住一切"到"知道该看什么"
在 Transformer 出现之前,AI 工程师们面临一个极其尴尬的局面:让机器理解一句话,传统做法是逐字逐句地"记住"——前面的词处理完了,才能处理下一个。这听起来很合理,但问题在于,如果一句话有 100 个词,模型在处理第 50 个词的时候,第 1 个词的信息已经模糊得像隔了一层雾。
这叫长距离依赖问题。就像你在读一本侦探小说,第 10 章出现的凶手线索和第 1 章埋下的伏笔遥相呼应,但你读到第 10 章时,第 1 章的内容已经记不清了。传统 RNN/LSTM 就是这么个"金鱼脑"。
注意力机制(Attention Mechanism)解决的就是这个问题。它的核心思想是:处理每个词的时候,不要只看相邻的词,而是让模型自己决定它应该"关注"前面的哪些词。
打一个形象的比喻:想象你在一个嘈杂的鸡尾酒会上听一个人说话。你的耳朵并不是把所有声音一视同仁地接收——你会自动"屏蔽"背景噪音,把注意力聚焦在说话人身上。注意力机制干的,就是给模型装上这样一双"智能耳朵"。
数学上,注意力分数是这样计算的:
import torch
import torch.nn.functional as F
def scaled_dot_product_attention(Q, K, V, mask=None):
d_k = Q.size(-1) # 缩放因子
scores = Q @ K.transpose(-2, -1) / (d_k ** 0.5) # QK^T / sqrt(d)
if mask is not None:
scores = scores.masked_fill(mask == 0, -1e9)
attention_weights = F.softmax(scores, dim=-1)
return attention_weights @ V, attention_weights
Q = x @ W_q # Query: 我在找什么
K = x @ W_k # Key: 我是什么
V = x @ W_v # Value: 我的内容
output, weights = scaled_dot_product_attention(Q, K, V)
那个 sqrt(d)(d 是向量维度)的缩放,看起来不起眼,但它防止了当维度很大时,点积结果过大导致 softmax 梯度消失。细节魔鬼,这句话就是了。
更重要的是,注意力机制是可以"并行"的。所有词的关系可以同时计算,不需要等前一个处理完再处理下一个。这让 GPU 的算力得以充分发挥,也让训练真正大规模的网络成为可能。
二、词的数学:Embedding 与位置编码
大模型不认字。它只认数字。
所以,第一步就是把词变成向量——这就是词嵌入(Word Embedding)。一个词被表示成一个高维向量(比如 768 维),在这个向量空间里,意思相近的词靠得近,"国王"减去"男人"再加上"女人",约等于"女王"。
import torch
import torch.nn as nn
vocab_size = 50000 # 词表大小
embedding_dim = 768 # 嵌入维度
embedding = nn.Embedding(vocab_size, embedding_dim)
# input: (batch_size, seq_len) -> 每个词是一个整数 ID
# output: (batch_size, seq_len, embedding_dim) -> 每个词变成 768 维向量
input_ids = torch.tensor([[1, 5423, 892, 0]]) # "I love cats"
word_vectors = embedding(input_ids)
print(word_vectors.shape) # torch.Size([1, 4, 768])
但这里有个问题:词嵌入只告诉你"这个词是什么意思",不告诉你"这个词在句子的哪个位置"。
"狗咬了我"和"我咬了狗",词完全一样,但意思完全相反。顺序不同,语义天差地别。
传统 RNN 靠时间步的顺序传递来解决这个问题。但 Transformer 没有循环结构,怎么注入位置信息?答案就是位置编码(Positional Encoding)。
import numpy as np
def positional_encoding(seq_len, d_model):
PE = np.zeros((seq_len, d_model))
position = np.arange(0, seq_len).reshape(-1, 1)
div_term = np.exp(np.arange(0, d_model, 2) * -(np.log(10000.0) / d_model))
PE[:, 0::2] = np.sin(position * div_term) # 偶数维度用 sin
PE[:, 1::2] = np.cos(position * div_term) # 奇数维度用 cos
return PE
# 每个位置都有唯一的位置编码,能泛化到更长序列
为什么用 sin/cos?因为它们有一个优雅的性质——任意两个位置的相对关系,可以通过线性变换推导出来。
三、Transformer:拆开看看到底是什么
Transformer 的架构,表面上看起来复杂,实际上逻辑非常清晰。我把它拆成三个核心模块来讲。
3.1 编码器与解码器:两种理解世界的角度
Transformer 最初是为机器翻译设计的,所以它有编码器(Encoder)和解码器(Decoder)两个部分。
- 编码器:把输入序列转成一个"理解向量",看完整个句子后形成对语义的全局把握。
- 解码器:在编码器的理解基础上,一个词一个词地生成输出,像一位同声传译员——听一段,翻译一段。
但今天的大语言模型,比如 GPT 系列,其实只用了解码器部分——单向、自回归地生成下一个词。为什么?因为"阅读理解"和"写作文",本质上是同一件事:你需要理解语言,然后创造语言。解码器足够了。
3.2 多头注意力:让模型"多角度思考"
只做一次注意力够吗?不够。
一个词在不同语境下,角色是不同的。"苹果"可能是水果,可能是手机公司,也可能是股票代码。如果只用一组 QKV,模型只能学到一种"关注方式"。
多头注意力(Multi-Head Attention) 就是让模型同时运行多组注意力,每组关注不同的语义关系:
class MultiHeadAttention(nn.Module):
def __init__(self, d_model=768, num_heads=12):
super().__init__()
self.num_heads = num_heads
self.d_k = d_model // num_heads # 每头的维度
self.W_q = nn.Linear(d_model, d_model)
self.W_k = nn.Linear(d_model, d_model)
self.W_v = nn.Linear(d_model, d_model)
self.W_o = nn.Linear(d_model, d_model) # 输出投影
def forward(self, x):
B, T, C = x.shape # batch, seq_len, d_model
Q = self.W_q(x).view(B, T, self.num_heads, self.d_k).transpose(1, 2)
K = self.W_k(x).view(B, T, self.num_heads, self.d_k).transpose(1, 2)
V = self.W_v(x).view(B, T, self.num_heads, self.d_k).transpose(1, 2)
out, _ = scaled_dot_product_attention(Q, K, V)
out = out.transpose(1, 2).contiguous().view(B, T, C)
return self.W_o(out)
# 12 头注意力 = 12 组不同的 QKV
# 有的头学语法关系,有的学语义关系,有的学指代关系
3.3 Add & Norm 与 FFN:被低估的功臣
在每个注意力层之间,你总能看到"Add & LayerNorm"——把输入和输出相加(残差连接),再做层归一化。这两件事看起来不起眼,但它们是深度学习训练的定海神针。
残差连接:让梯度畅通无阻地流回前面的层,解决深层网络的梯度消失问题。想象成一条高速公路——即使某个中间层学坏了,信息仍然可以从旁边的"捷径"绕过去。
层归一化:把每层的输出"拉平",让数值稳定在合理范围。没有它,大模型训练几步就会数值爆炸。
前馈网络(FFN):每个位置独立做两次线性变换 + 激活函数。本质上是一个"两步升维再降维"的操作——把信息投影到更高维空间,激活,再投影回来。可以理解为对每个词的"非线性思考"。
有意思的是,研究者后来发现 FFN 在 Transformer 中承担了记忆知识的功能,而注意力机制更多负责检索这些记忆。这两者配合,才构成了一个完整的"理解+记忆"系统。
四、预训练与微调:大模型的成长之路
一个人从小学读到博士,不是靠一个老师教的,而是分阶段、有目标地学习。大模型也一样。
4.1 预训练:吞下整个互联网
预训练的目标很简单:让模型学会"语言本身"。用海量的文本数据,让模型预测下一个词——这叫语言建模(Language Modeling)。
GPT-3 的训练数据据说有 3000 亿个 token,DeepSeek-V3 的训练用了 14.8 万亿 token。用这些数据训练后,模型学会了语法、语义、世界知识、甚至推理模式。
4.2 预训练关键技术一览
| 技术 | 作用 | 代表模型 |
|---|---|---|
| 海量语料混合 | 让模型同时学习代码、数学、论文、对话等多类型文本 | GPT-4、DeepSeek |
| 更长上下文窗口 | 从 2K 扩展到 128K token,让模型"看"得更远 | Claude 3、GPT-4 Turbo |
| 稀疏注意力 | 不计算所有 token 对的注意力,降低计算复杂度 | Longformer、BigBird |
| Flash Attention | IO感知的注意力实现,训练速度提升 2-4 倍 | 几乎所有新模型 |
4.3 微调:从通才到专才
预训练完的模型,是一个"通才"——什么都会一点,但什么都不精。微调(Fine-tuning)就是把它训练成"专才"的过程。
全参数微调效果好,但代价是:1750 亿参数的模型,需要对应 1750 亿参数的梯度存储、optimizer 状态和更新。在消费级硬件上基本不可能。
这就是为什么 LoRA、P-tuning 这类参数高效微调技术变得如此重要。我们后面单独讲。
五、让模型"听话":RLHF、LoRA 与 P-tuning
预训练模型会说话,但不一定"说对话"。RLHF 和各种微调技术,解决的是怎么让模型"听人类的话"。
5.1 RLHF:让 AI 的价值观对齐人类
RLHF(Reinforcement Learning from Human Feedback,基于人类反馈的强化学习)是让 GPT-3 进化到 ChatGPT 的关键技术。
它的三步走战略非常有意思:
第一步,SFT(有监督微调):用人工精心标注的高质量问答数据,训练模型学会"什么样的回答是对的"。
第二步,训练奖励模型(Reward Model):让人类对同一个问题的多个答案排序打分。模型学到一个"奖励函数"——能判断一个回答好还是不好。
第三步,PPO 强化学习:用奖励模型的反馈来优化模型的输出策略,让它越来越多地产生"人类认为好的"回答。
55.2 LoRA:低成本微调的魔法
回到全参数微调的问题:1750 亿参数,存储梯度、优化器状态、每个参数更新——简直是硬件噩梦。LoRA(Low-Rank Adaptation)的聪明之处在于:不要动原始权重,而是学习"权重更新"。
它的核心思想是:训练时不直接更新原始权重矩阵 W,而是学习 W 的"低秩分解":W + BA。其中 A 和 B 是两个小矩阵,参数量远小于 W。
import torch
import torch.nn as nn
class LoRALinear(nn.Module):
def __init__(self, original_layer, rank=4, alpha=8):
super().__init__()
self.original = original_layer
self.rank = rank
self.alpha = alpha
d_in, d_out = original_layer.weight.shape
# A: (d_in, rank), B: (rank, d_out)
# 比原始矩阵参数量小得多
self.lora_A = nn.Parameter(torch.zeros(d_in, rank))
self.lora_B = nn.Parameter(torch.zeros(rank, d_out))
nn.init.kaiming_uniform_(self.lora_A, a=5**0.5)
nn.init.zeros_(self.lora_B)
def forward(self, x):
# W + BA 的低秩更新
return self.original(x) +
(x @ self.lora_A @ self.lora_B) * (self.alpha / self.rank)
# 1750亿参数的模型,原来需要更新全部权重
# 用了 LoRA(rank=8),只需要更新约 0.1% 的参数量
# 一块消费级 RTX 4090 就能微调一个大模型!
LoRA 的精髓在于:大模型的"知识"大部分已经在了,训练只是在原有的知识框架上做微调。BA 两个小矩阵的乘积,代表了对原始权重的"修正量"。原始权重被冻结,只更新 BA——参数量从数十亿降到几百万。
5.3 P-tuning:让模型自己学会"提示"
P-tuning(Prompt Tuning)的思路又不一样。它的核心是:不改变模型的任何权重,而是在输入序列前面插入一组可学习的"虚拟 token"。
这些 token 在原始词表中不存在,它们的嵌入是随机初始化的,然后在训练过程中学习。和 LoRA 相比,P-tuning 改变的是模型的"输入提示"而不是内部权重。
为什么有效?因为大模型足够强大,它能根据输入提示"理解"你想让它做什么。P-tuning 相当于把"怎么用好这个模型"的know-how,编码进了提示本身。
5.4 其他微调技术对比
| 技术 | 修改什么 | 参数量 | 适用场景 |
|---|---|---|---|
| 全参数微调 | 所有权重 | 100% | 数据充足、有高端算力 |
| LoRA | 低秩矩阵 BA | 0.1%-5% | 消费级硬件、快速适配 |
| P-tuning | 输入端虚拟 token | 0.01%-1% | 提示工程、探索模型能力 |
| Adapter | 插入的小网络 | 1%-5% | 多任务学习 |
| QLoRA | 量化+LoRA | 极低 | 单卡微调超大模型 |
六、总结
好,我们从注意力机制一路讲到 LoRA,把大模型的"五脏六腑"都翻了个遍。来做个快速回顾。
- 注意力机制:让模型自己决定关注哪些词,解决了长距离依赖问题——这是整个 Transformer 的灵魂。
- 词嵌入 + 位置编码:把语言翻译成数学,让模型既知道"说什么",又知道"在哪说"。
- Transformer 架构:多头注意力、残差连接、层归一化、FFN——四个模块相互配合缺一不可。
- 预训练 + 微调:学会语言,再用人类反馈对齐,大模型才能从"能说话"到"说对话"。
- RLHF / LoRA / P-tuning:分别从"价值观对齐"和"低成本微调"两个维度,把大模型从实验室拉到了每个人都能用的现实。
我的看法:大模型的核心算法,说白了就是三件事——怎么理解语言(注意力)、怎么学习语言(预训练)、怎么服从指令(RLHF/微调)。这三条线交织在一起,构成了今天 AI 革命的技术基础。理解它们,不只是技术人员的需求——每一个用 AI 工具的人,都值得知道屏幕背后到底发生了什么。
下一步建议:
- 今天去 Hugging Face 上找一个预训练模型,用 LoRA 对它做一次微调实验——亲手跑一遍代码,感受会更深。
- 阅读《Attention is All You Need》原文,这篇 2017 年的论文至今读起来依然令人叹为观止。
大模型不是魔法。它的背后,是人类几十年 AI 研究积累的工程奇迹。理解了它的算法,你就理解了这个时代最大的技术变革。
参考资料
- Vaswani et al. - Attention is All You Need (2017)
- Brown et al. - Language Models are Few-Shot Learners (GPT-3)
- Hu et al. - LoRA: Low-Rank Adaptation of Large Language Models
- Liu et al. - PTuning: Prompt Tuning Can Be Comparable to Fine-tuning
- Ouyang et al. - Training language models to follow instructions with human feedback