刘孟玄 Blog

「离开世界之前 一切都是过程」

FlashAttention:从 Safe Softmax 到分块计算

用在线归一化把 Attention 的中间结果留在片上

FlashAttention 的名字很容易让人以为它提出了一个新的 Attention 公式。实际上,它并没有改变 Attention 的数学结果:给定相同的 Q、K、V,输出仍然是普通的精确 Attention。 它真正改变的是计算过程:不把完整的 N×N 注意力分数矩阵和概率矩阵写回 HBM,而是把 Q、K、V 切成 tile,在 GPU 片上的 SRAM 和 registers 中完...

KV Cache 优化(四):Speculative Decoding 投机解码

不改变大模型答案分布,怎样一次推进多个 token?

前面三篇都在缩小或筛选 KV Cache。这一篇优化的是 Decode 的串行性这一瓶颈。 普通自回归生成一次只产生一个 token: 1 xₜ → xₜ₊₁ → xₜ₊₂ → xₜ₊₃ 每一步都要调用一次大模型,而大模型单 token Decode 的计算规模很小,却要读取大量权重和 KV Cache。Speculative Decoding(投机解码)采用“先猜、后验”的办法: ...

KV Cache 优化(三):局部注意力、StreamingLLM 与 KV Pruning

当上下文太长,哪些历史 token 值得继续保留?

前两篇分别减少了 KV head 的数量,或把每个 token 的 K/V 压缩成 latent。它们解决的是“每个 token 存得太宽”。这一篇换一个问题: 如果上下文已经长到几十万 token,是否真的需要保留每一个历史 token? Sliding Window Attention、StreamingLLM 和 Pruning KV Cache 都在减少历史状态,但方式不...

KV Cache 优化(二):深入理解 Multi-head Latent Attention

DeepSeek 如何用低秩潜在表示压缩每个 token 的 K/V

MQA 和 GQA 通过共享 K/V heads 减少 KV Cache。DeepSeek-V2 提出的 Multi-head Latent Attention(MLA)换了一个角度: 不直接缓存展开后的多头 K/V,而是先把它们压缩成一个低维潜在向量,只缓存这个更短的表示。 当后续 Query 需要读取历史信息时,再通过上投影恢复所需的 K/V;在经过代数变换的高效实现中,部分...

KV Cache 优化(一):从 MHA 到 MQA 与 GQA

少存几组 K/V,为什么就能明显改善 Decode?

标准 KV Cache 避免了自回归生成时对历史 token 的重复计算,但它也带来了新的问题:上下文越长、并发请求越多,缓存就越大。 对于每一层、每一个 token,模型都需要保存一组历史 Key 和 Value: $M_{KV}=2LBTN_{KV}D_h\times\text{bytes}$ 这里的 2 表示 K 和 V,L 是层数,B 是并发序列数,T 是上下文长度,N_KV ...

KV Cache:Transformer 推理中的增量计算

从 Prefill、Decode 到 K/V 的追加与显存带宽

大语言模型生成文本时,并不是每次都把已经处理过的整段文本重新计算一遍。它会把历史 token 在每一层产生的 Key 和 Value 保存下来,下一次生成时直接复用。这块保存下来的状态就是 KV Cache。 KV Cache 的核心可以先浓缩成一句话: Prefill 一次处理完整 Prompt 并建立缓存;Decode 每次只处理一个新 token,用它的 Query 查询历史...

Transformer 全貌与基础数据流

从 Encoder-Decoder、Pre/Post-Norm 到 Prefill 与 Decode

理解 Transformer,不能只记住 Attention 的公式。对 AI Infra 来说,更重要的是知道一段输入怎样依次经过 Embedding、Attention、FFN、残差和归一化,每一步产生什么形状,以及这些计算为什么会对应到 GEMM、Kernel 融合、KV Cache 和并行策略。 本文从原始 Transformer 的 Encoder-Decoder 结构出发,重点...

Transformer 架构快速入门

从 Self-Attention、多头机制与 RoPE 到 Decoder Block

学习 Transformer 时,我最开始能记住 Attention 的公式,却说不清公式里的每个张量究竟来自哪里,也不清楚“多头”为什么在代码里经常只是一次大矩阵乘法。继续往下看 RoPE 和 Decoder Block 后,新的问题又出现了:一个 token 为什么要旋转多组特征?相对位置到底发生在哪两个对象之间?多个 head 拼接以后为什么还要经过输出投影? 后来我发现,这些问题其...

数值计算与混合精度

从浮点数、Loss Scaling 到 Kernel 融合

神经网络里的公式通常是在实数上推导的,但 GPU 实际操作的是有限精度的浮点数。于是,同一个公式在纸面上是正确的,放进 FP16、BF16 或 FP8 的计算流程后,却可能遇到舍入误差、溢出、下溢和 NaN。 混合精度训练要解决的不是“低精度一定不准确”这个简单问题,而是要把不同工作分给合适的数值格式:大规模矩阵乘法用低精度换取吞吐,累加、归约和优化器更新在关键位置保留更高精度。 1 2...

优化、梯度稳定性与归一化

从 mini-batch、Adam 到 Residual、Norm 与梯度裁剪

反向传播解决了“怎样计算梯度”,但训练还没有完成。拿到梯度以后,仍然要回答几个工程上极其实际的问题:一次梯度该看多少数据?不同参数的梯度量级相差很大怎么办?网络堆深以后,梯度为什么会消失或爆炸?隐藏状态又该怎样保持稳定? 这一章将这些问题串成一条训练链路: 1 2 3 4 5 6 7 mini-batch 给出带噪声的梯度估计 ↓ SGD / Momentum / Ada...