端侧 AI · 15 天工程路线
目录首页 English
DAY 10

Attention 机制

把序列依赖变成可并行计算的显式数据流

建议阅读:约 20 分钟

学习目标

从 Attention 的对齐问题出发,理解缩放点积、Query、Key、Value、多头注意力、causal mask 与位置交互,并能说明其并行优势、二次复杂度和 I/O 边界。

本章关键词

关键词解释ESP32 工程类比
Attention用 Query 与 Key 的匹配分数对 Value 加权聚合的信息交换机制。像按当前查询同时检索多个带索引的 DMA 描述符。
Multi-head把表示投影到多个子空间并行执行注意力,再拼接输出。像并行运行多组过滤规则,各自观察不同协议特征。
Causal mask阻止当前位置访问未来 token 的上三角可见性约束。像接收状态机只能读取已经到达的字节。
Positional encoding向无循环的注意力网络注入 token 顺序或相对距离信息。像给每个环形缓冲区元素附带单调序号。

承上:回顾与定位

上一章先建立了完整 Transformer 架构,明确 Attention 只是 block 中负责跨位置通信的子层。本章把这个大概念单独展开,追踪 Q、K、V、mask、多头和位置如何共同决定信息聚合。

从源头看今天

历史发展脉络

Attention 从改善 encoder–decoder 对长句的压缩瓶颈开始,随后成为 Transformer 的核心数据流,并扩展到双向预训练、跨模态与 I/O-aware kernel。结构创新与系统优化共同决定它今天能处理多长的上下文。

2014

可学习对齐缓解固定长度编码瓶颈

Bahdanau 等人在神经机器翻译中让 decoder 每一步对 encoder 状态计算对齐权重,不再要求一个固定向量承载整句信息。

神经机器翻译 Attention 原始论文 ↗
2017

Transformer 以多头 Attention 取代循环主干

缩放点积、多头 self-attention、位置编码和 causal mask 被组织成可并行训练的 encoder–decoder 架构。

Transformer 原始论文 ↗
2018

BERT 用双向 self-attention 建立通用语言表示

Masked language modeling 让表示同时利用左右上下文,展示 Transformer encoder 预训练迁移到多类理解任务的能力。

BERT 原始论文 ↗
2019

Transformer-XL 引入跨片段记忆与相对位置

跨 segment 复用隐藏状态并采用相对位置编码,使语言模型能够处理比固定训练片段更长的依赖。

Transformer-XL 原始论文 ↗
2020

Vision Transformer 把纯 Transformer 主干带到图像

图像被切成 patch 序列后直接进入 Transformer,说明 attention 的位置交互机制并不局限于自然语言。

Vision Transformer 原始论文 ↗
2022

FlashAttention 把瓶颈定位到 HBM 数据移动

I/O-aware 分块在不近似 attention 结果的前提下减少 HBM 读写,表明相同数学公式可因内存层级调度产生巨大实现差异。

FlashAttention 原始论文 ↗
今天为什么仍然重要: 端侧实现既要保留 Q/K/V、mask 和位置语义,也要面对序列平方计算与内存层级。先建立小矩阵正确性基线,再选择融合、分块、低精度或硬件 backend。
借熟悉的系统建立直觉

类比图解

一座并行检索、分频道汇总的交换矩阵

每个输入端口发出查询,多套匹配电路分别按语法、位置或语义线索给可见端口打分,再从对应数据通道读取内容。各频道结果拼接后进入本地处理单元。矩阵可以同时服务整批输入,但如果下一个输入本身尚未产生,就不能提前处理。

查询描述符 Query:当前位置想寻找什么
端口索引 Key:每个位置如何被匹配
端口数据 Value:匹配后实际取回的信息
多组匹配频道 多个 attention head 的并行子空间

类比的边界: 权重不是人类可直接命名的“语法头”或“事实头”,attention score 也不能单独证明模型的因果解释;类比只描述数据流与并行结构。

本章讲解

论文的第一性原理:缩短串行依赖

论文先把问题拆成三项:每层要花多少计算、多少步骤必须串行、远距离 token 之间要经过多长的路径。Transformer 保留 encoder–decoder 骨架,却用 multi-head self-attention 和逐位置 FFN 替代循环结构与卷积,并用 residual connection、LayerNorm 和 positional encoding 补齐训练稳定性与顺序信息。于是整段输入可以高度并行处理,远距离依赖的路径缩短;但这不等于生成也能并行,decoder 仍按已生成前缀自回归地产生下一个 token。

从公式看懂缩放点积、多头与因果屏蔽

核心公式是 Attention(Q,K,V)=softmax(QKᵀ/√d_k)V。d_k 变大时,点积的方差也会变大,直接送入 softmax 容易饱和、梯度变小;除以 √d_k 是数值稳定措施。Multi-head attention 先用不同的线性投影进入多个表示子空间,再并行计算、拼接并投影回来;causal mask 则把未来位置的分数设为不可见。先在 4 个 token 的小矩阵上验证这三件事,再谈 kernel 或 cache。

没有循环之后,位置信息必须显式进入模型

注意力本身可以同时看见一组位置,却不会自动知道顺序;论文因此把正弦/余弦 positional encoding 加到 embedding 上,并比较了 learned positional embedding。这个选择是模型契约的一部分:tokenizer、位置编码、causal mask 和 cache 的 position 必须一致。端侧工程不能只搬运权重文件,改动其中任一项都要用金向量检查输出是否仍然一致。

从论文的并行性落到 Prefill 与 Decode

论文表中的 O(1) sequential operations 描述的是一层 self-attention 在整段序列上的计算,不是说自回归输出没有顺序。Prefill 一次处理已有 prompt,适合在 token 维并行;Decode 每轮只追加一个新 token,必须等待上一步采样结果,并读取历史 K/V。因此现代 runtime 把一次吞吐导向的 prefill 与多次低延迟 decode 分开计时,不能用论文的并行性结论掩盖 decode 的带宽瓶颈。

一个 Transformer block 不只有 Attention

Attention 负责让位置之间交换信息,逐位置 FFN 则对每个位置应用相同的非线性变换;残差连接为深层网络保留短路径,LayerNorm 稳定各层数值尺度。工程分析应把 QKV 投影、attention score、value 聚合、输出投影和 FFN 分开记账。现代 LLM 中 FFN 权重往往占据大量参数,而长上下文下 attention 的中间矩阵和 K/V 状态又成为显著内存与带宽来源。

Self-attention 的优势来自路径与并行,不是免费计算

论文用每层复杂度、必须串行的操作数和任意位置间最大路径长度比较循环、卷积与 self-attention。Self-attention 缩短远距离依赖路径并允许训练时并行处理序列,却需构造随序列长度平方增长的相关性矩阵。短到中等序列时优势明显;长上下文中则需要稀疏、分块、滑窗或 I/O-aware kernel 等优化,而且这些方法各自改变计算、可见范围或数据移动,不能混称为同一种加速。

从公式到实现要检查 mask、位置与数值稳定性

实现错误常藏在广播后的 mask 方向、padding 与 causal mask 的组合、位置编号偏移、softmax 前的 dtype 和多头 reshape 顺序。建立小矩阵金向量:固定 Q/K/V,保存缩放前后分数、mask 后分数、softmax 权重与最终输出;检查每行权重和为 1,未来位置权重为 0。这样后续优化 kernel、量化或 KV cache 时,能够定位第一个破坏语义的边界。

让数据真正跑起来

动态过程演示

一个 token 如何通过多头 Self-Attention 读取上下文

播放器沿张量路径展示投影、打分、屏蔽、归一化、聚合与输出,而不是把 Attention 隐藏在一个黑盒节点里。

步骤 1 / 6

嵌入位置 · X = token embedding + position

为每个位置建立带顺序的表示

观察点

Attention 本身不会自动产生顺序

循环 / 返回条件: 每个 Transformer block 都重复这条路径;训练时多个位置可并行,生成时新的位置仍必须等待上一 token 被选择。

查看静态全景图
token ids → embedding + position
                 │
Q = XWq, K = XWk, V = XWv
                 │
scores = QKᵀ/√dₖ + mask → softmax → weighted V
                 │
          residual + norm → FFN → residual + norm

代码或命令示例

scores = Q @ K.T / sqrt(d_k)
scores = scores + causal_mask
weights = softmax(scores, axis=-1)
context = weights @ V
output = concat(heads) @ W_o

动手实验

读《Attention Is All You Need》的摘要、第 3.1–3.5 节与第 4 节。用 4 个 token、2 维向量手算并实现 softmax(QKᵀ/√d_k)V;切换 causal mask,确认位置 i 的输出不依赖未来位置。最后将序列长度从 4 翻倍到 8、16,记录 attention score 矩阵元素数如何增长。
实验记录与导出

工程陷阱

避免误判: 把 Attention 当成“自动理解重点”的解释器,或把训练阶段的并行性误读成生成阶段没有依赖。Attention 是可学习的加权数据流,其行为由权重、位置、mask 与输入共同决定,并仍承担 O(n²) 的长序列代价。

核心测试

完成 3 道单选题后提交;提交前不会显示答案。

1. 论文为什么要把 QKᵀ 除以 √d_k?
2. Causal mask 在 decoder self-attention 中保证什么?
3. 序列长度翻倍时,完整 attention score 矩阵的元素数约如何变化?

一起把本章讲清楚

在 GitHub 上讨论本章

登录 GitHub 后提问、补充实测或分享你的实现;评论会保存在本课程的 GitHub Discussions 中。

评论区需要 JavaScript;也可以直接打开 GitHub 讨论区: 打开 GitHub 讨论区 ↗

延伸阅读

启下:下一章如何使用本章能力

下一章只讨论 KV Cache:旧 token 的 K/V 为什么可复用、每新增 token 需要多少内存,以及 GQA、分页和量化如何改变容量与带宽。

下一天: Day 11 · KV Cache