Q、K、V 和几层矩阵乘法,第一次看公式很容易卡住。换个角度就通了:序列里每个位置都在问一个问题——"为了更新自己的表示,我应该从别的位置读多少信息?"注意力权重,本质是一张动态的信息路由图。
三个角色一句话讲清
- Query:当前位置想找什么信息;
- Key:每个位置提供什么线索,供别人匹配;
- Value:匹配之后真正被读取的内容。
每个 token 的表示经线性变换得到这三者,用 Q 和 K 的相似度算权重,再对 V 加权汇总。缩放点积注意力写成:
Attention(Q,K,V) = softmax(QK^T / sqrt(d_k)) V
除以 sqrt(d_k) 不是仪式感——点积随维度增大而变大,不缩放的话 softmax 会过早饱和,梯度几乎消失。多头注意力则是让多组投影并行建立不同的关系视角(指代、句法、主题各管一摊),再组合。
位置编码和掩码:两个容易被低估的组件
自注意力本身不知道 token 的先后次序。两个组件补上这个缺口:
位置编码把顺序注入表示。没有它,模型分不清"狗咬人"和"人咬狗"。
因果掩码决定模型"能不能看到未来"。做自回归生成时,当前位置不能偷看后面的 token,否则训练目标直接泄漏答案;做双向编码时,一个位置又能读左右两边。看起来只是矩阵里某些位置置零,实际决定了这个模型是在理解整段输入,还是根据前文续写。
增量点(C类):掩码选择和训练目标是绑定的,不能混用。 把双向编码的掩码套到生成任务上,训练时模型看到的就是答案本身——损失会掉得很快,生成时却完全不能用。工程上排查"模型生成时表现远差于训练指标"的问题,掩码与推理模式不匹配是高频根因之一。
平方成本:长上下文贵的数学根源
标准自注意力的计算量和注意力矩阵存储随序列长度近似平方增长。上下文翻倍,朴素实现下注意力开销接近四倍。这一条直接解释了三个热门方向存在的理由:
- KV Cache——把历史 token 的 K、V 存下来复用,省掉重复计算;
- 稀疏注意力——只让部分位置对交互,砍掉路由图的规模;
- 长上下文优化——让"支持 128K"不只是参数表上的数字。
增量点(D类):评估长上下文模型的两个必测项。 看到"支持更长上下文"的宣传,测两件事而不是信参数表:一是大海捞针类测试——把关键信息埋在超长文本的不同深度位置,看召回率随深度的衰减曲线;二是同任务下不同上下文长度的显存和延迟曲线,确认增长是线性的还是平方的。两条曲线合起来才构成"这个长上下文能不能用"的判定。
指代消解:一个最小例子
"小王把书放在桌上,因为他要出门。"——判断"他"指谁,需要把这个位置和前面的"小王"建立联系。不同的注意力头可能分别关注指代关系、句法关系或主题词,多个头叠加才形成丰富表示。
但要克制外推:这个例子只帮助理解,不代表某个头永远对应某种人类概念。模型会按训练任务自己找有用的关联。能确定的只有一件事:它通过动态加权让不同位置的信息交互,而不是每个 token 独立处理。看注意力热力图可以做调试参考,但别把它当成"模型为什么这么想"的完整解释——真正的表示是很多层、很多头共同形成的。
增量点(A类):注意力变体的适用边界
实践中不必死磕标准注意力,几个变体各有地盘:
- 线性注意力/状态空间路线:把历史压进固定大小状态,推理成本与序列长度线性——适合超长文本,代价是精确回溯能力弱;
- 滑窗注意力:只在局部窗口内交互,配合层间信息传递近似全局——适合局部依赖为主的任务;
- FlashAttention 类实现:不改变数学,只优化访存,训练推理都值得默认开启。
选型的判断依据还是那句话:你的任务依赖是局部的还是全局的,回溯需求强不强。
收束
Transformer 不是一个模型,是一套可组合的模块。注意力负责跨位置传信息,前馈网络逐位置做非线性变换,残差和归一化保证深层流动。理解这些边界,比死记某个实现里的类名有用得多——下次遇到"支持更长上下文"的模型,先问两问:长文本任务里真能找到关键内容吗?这种能力的推理成本还接受得了吗?

评论0