LLM的推理/transformer架构/vllm

LLM 推理的推理过程

QKV

将QKV三条独立线拆开原因,核心原因是 ‘参数专属 + 梯度解耦’,原因如下:

Details

把 Q、K、V 拆成 三条独立线性 而不是一个权重乘三次,核心原因是 ‘参数专属 + 梯度解耦’: 一份权重乘三遍 → Q/K/V 被迫共享同一参数空间,梯度累加在同一矩阵,导致: 更新方向被平均,query 要高频、key 要低秩、value 要高熵 的冲突需求互相拉扯; 秩被压缩,多头子空间重叠度↑,注意力退化趋同。 独立线性层 → 各学各的投影,梯度不打架,子空间正交性↑,模型容量直接×3,无需增加深度就能提升表达能力; 训练稳定、收敛更快,这是 Transformer 比单矩阵×3 更深却不难训的关键。

目前主流LLM都是基于transformer的Decoder-only架构,因为 Decoder-only 架构在“大规模无监督预训练”这个特定范式下,展现出了更好的可扩展性(Scalability)和任务通用性。

输入token经过transformer总体过程如下:
输入Token -> 嵌入 -> 加上位置编码 -> 通过N个Transformer层 -> 最终层归一化 -> 语言模型头 -> 概率分布 -> 输出Token

[!TIP]

让我们以 Llama2-7B(4096 序列长度,float16精度)为例,计算一下 batch_size = 1的理想推理速度。

  1. prefill(预填充,并行处理输入的 tokens):假设 prompt 的长度是 350 token,那么预填充所需要的时间 = number of tokens * ( number of parameters / accelerator compute bandwidth) = 350 * (2 * 7B) FLOP / 125 TFLOP/s = 39 ms(A10)。这个阶段主要是计算瓶颈。
  2. decoding(解码,逐个生成下一个 token。):time/token = total number of bytes moved (the model weights) / accelerator memory bandwidth = (2 * 7B) bytes / (600 GB/s) = 23 ms/token(A10)。这个阶段的瓶颈是带宽。

kvcache
原理:自回归生成时,把之前所有 token 已经算过的 K/V 矩阵缓存到 HBM,下次只算新 token 的 Q/K/V,然后拼接历史 K/V 做注意力,避免 O(n²) 重复计算。
数学公式
KVCache(字节) = B × L × n_kv_heads × head_dim × 2 × sizeof(dtype) × 层数
B:batch 内同时服务的序列条数
L:当前已生成 token 数(=seq_len)
n_kv_heads:GQA 压缩后的 KV 头数(若无压缩 = 原头数) n_kv_heads = n_h // G
head_dim:每个头的维度
2:K 与 V 各一份
sizeof(dtype):FP16/BF16→2字节;INT8/FP8→1字节;FP32→4字节

相关问题: kvcache节省了那部分计算以及具体计算案例?

Details

  1. FFN阶段本质上是两个矩阵乘计算,token之前互不影响,因此使用kv cache可以将计算量节省为原来的1/S
  2. RMSNorm本质是对每一个token的隐状态做归一化,token之间是互相独立的,因此计算量为原来的1/S
  3. Attention阶段由于Q和K做gemm,会得到一个shape为[S,S]的向量,在seqlen比较大的情况下,计算复杂度为O(S^2),使用kv cache之后,Attention计算复杂度变为O(S),计算Q、K、V的GEMM运算降为GEMV运算,整体计算量为原来的1/S;
  4. 其他的Embedding等计算量比较小,大约也为原来计算量的1/S;

以 Qwen2.5-7B 为例(BF16):
层数:28
隐藏维度:3584
KV头数:4
精度:BF16(2字节)
2×2×28×
28
3584

×4=0.5 MB per token

Transformer 架构

Encoder-only bert模型,能看到全文
decoder-only gpt,llama,deepseek模型,只看前面的词
Transformer 的 Encoder = “Self-Attention(让每个词关注下句子里的其它词) + FFN(每个词独立处理) + 残差” 重复堆叠

《Attention Is All You Need》中transformer架构,整体结构,线程 / 多线程 / 协程区别,以及对应细节如下:

Details

  1. 整体结构(左边灰色大框)
    Input → Encoder ×N → Decoder ×N → Output
    论文默认 N=6。
  2. Encoder 自身结构(右边虚线框)
    每层 =
    ├─ Multi-Head Self-Attention
    ├─ Add & LayerNorm(残差+归一化)
    ├─ Position-wise FFN(两线性+ReLU)
    └─ 再来一次 Add & LayerNorm
    输出继续喂给下一层 Encoder,同时复制一份给所有 Decoder 层做 cross-attention。

线程 / 多线程 / 协程:

维度 进程 线程 协程
操作系统可见
调度方 OS OS 用户空间(事件循环)
切换代价 最高(页表、内核) 高(内核态) 最低(用户态,只保存栈)
并行能力 ✅ 多核 ✅ 多核 ❌ 单线程内并发
典型场景 多核计算、故障隔离 I/O 密集、CPU 密集 高并发 I/O(异步)
一句话记忆 独立公司 项目组 个人
Python 模块 multiprocessing concurrent.futures.ThreadPoolExecutor asyncio

对应代码参考如下:
多线程(20 并发,阻塞 I/O)
with ThreadPoolExecutor(20) as ex: ex.map(requests.get, urls)
协程(20 k 并发,异步 I/O)
await asyncio.gather(*[aiohttp.get(u) for u in urls])

Decoder与Encoder对应差异:

模块 Encoder 每层 Decoder 每层 关键差异说明
1. Self-Attention 多头自注意力(有 mask) 多头自注意力(未来掩码) Decoder 只能看当前及之前位置
2. Cross-Attention 多头交叉注意力 Query 来自 Decoder,K/V 来自 Encoder
3. FFN 位置前馈 位置前馈 结构完全一致
4. 残差+LN 2 次 3 次 Decoder 多一次 Cross-Attention 的残差
5. 输入 源语 Embedding 已生成序列 Embedding Decoder 训练时右移一位(teacher forcing)
6. 输出 特征序列 下一个 token 概率 最后接 Linear + Softmax

Transformer 中典型的 Token-wise (“对每个 token 单独做同样的计算,token 之间不交换信息”)操作:
对于 Token-wise 操作(如FFN、Norm、新token的QKV投影),它们天然地只需要处理新 token 即可。计算量是固定的,与生成长度 S 无关

操作名称 功能 为什么是 Token-wise?
词嵌入 (Embedding) 将离散的 token ID 转换为高维向量。 查表操作,每个 token ID 独立地映射为一个向量。
线性投影/层 (Linear Layer) 如计算 Q, K, V 的投影层或 FFN 中的两个大矩阵乘。 矩阵乘法 X * W 可以看作是对 X 的每一行(即每个 token 的向量)进行独立的线性变换。
前馈网络 (FFN) 对每个 token 的特征进行非线性变换和增强。 本质上是两个连续的线性投影层加上激活函数,所以也是 token-wise 的。
层归一化 (LayerNorm) 对每个 token 的特征向量进行标准化。 计算一个 token 向量的均值和方差,然后用其来标准化这个同一token的向量。
残差连接 (Add) 将一层的输入和输出相加。 直接将对应位置的 token 向量相加。
激活函数 (e.g., ReLU, GELU, SiLU) 引入非线性。 对向量中的每个元素独立进行操作。

QKV计算:
Score = Q * K^T
缩放:为了防止点积结果过大导致 Softmax 梯度消失,将得分除以 Key 向量维度的平方根。Scaled_Score = Score / √d_k
应用 Softmax:Attention_Weights = Softmax(Scaled_Score)
加权求和:用注意力权重对 Value 向量进行加权求和,得到最终的输出。Output = Attention_Weights * V

前馈神经网络 (Feed-Forward Network, FFN)

残差连接 (Add) 和层归一化 (Norm)
残差连接 (Residual Connection):将子层的输入直接加到其输出上(Output = Sublayer(input) + input)。这有效地缓解了深层网络中的梯度消失问题,使得模型可以堆叠得很深。
层归一化 (Layer Normalization):对残差相加后的结果进行归一化,稳定训练过程,加快收敛
公式表示一个 Encoder Layer:
EncoderOutput = LayerNorm( SelfAttention(Input) + Input )
FinalOutput = LayerNorm( FFN(EncoderOutput) + EncoderOutput )

位置编码positional encoding
提供单词在序列中的绝对或相对位置信息,增加语言的有序性,使 Transformer 能够理解顺序。

ROPE位置编码
“把 Q、K 向量拆成二维一对,在每对构成的复平面上按位置序号等比例旋转不同角度,再点积;旋转差构成相对距离,点积随距离衰减——零参数量、可外推、相对位置一次到位。”
零参数量,长度外推、远程衰减、并行友好

动态NTK:
一句话概括:动态NTK就像给模型戴上一副渐进式老花镜——看近处(短文本)很清晰,看远处(长文本)虽然有点模糊,但还能分辨大体形状,不至于完全看不见。

本质:是RoPE位置编码的推理时“应急方案”,不是新训练方法。
目的:让用短文本训练的模型,能勉强处理长文本,而不需要重新训练。
代价:位置精度随距离下降,但总比完全失效好。
应用:几乎所有支持长上下文的现代大模型(如GPT-4o、Llama 3等)都用了类似技术。

Details

现在常用的是rope,rope好处:

收益 一句话解释
外推性强 训练 4k,推理 128k 不微调也能用,LLaMA-2 32k、ChatGLM-6B 32k/64k 全靠它。
无额外参数 旋转矩阵是固定的,0 可学习权重,过拟合风险低。
计算高效 仅需对 Q/K 做一次旋转,矩阵乘法可融合进注意力,GPU 友好。
长程衰减 角度随距离增大而“转得远”,远距离点积自然变小,抑制噪声。
缓存友好 KV-cache 里每个位置只存一次旋转后的向量,增量推理省内存。

ROPE公式计算
ROPE = 分块对角旋转矩阵 R(m,Θ) 乘以向量 x,这边向量 x 就是多头注意力里某一个头的单条 token 向量。整体保持相对位置信息且零参数。
其中
  Θ_i=10000^(−2i/d),i=0,1,…,d/2−1
结果:q_m、k_n 分别带上“相对距离”m−n 的旋转角,Attention 内积自然只与相对位置有关,而不再依赖绝对位置

旋转角度怎么来?
每维频率先定好(跟 Sinusoidal 相同):
θᵢ = 10000^(−2i/d) , i = 0,1,…,d/2−1
位置 m 的旋转角 = m·θᵢ
→ 越靠后的 token 转得越多;同一维度 i 越远转得越快(像时钟秒针)。

它的完整公式是?
注意力内积的魔法
查询 q 在位置 m,键 k 在位置 n,分别做 RoPE 后点积:
RoPE(q,m) · RoPE(k,n)
⇒ 只与相对距离 (m−n) 有关,绝对位置被消掉,天然相对位置编码;

MHA/GQA)原理
Multi-Head Attention多头注意力原理:

机制 实现要点 KV 缓存大小 质量-速度权衡
MHA 每头独享 K/V H·n·d 最高质量,最慢、最费显存
MQA 全部头共享 1 组 K/V 1·n·d 速度最快,显存最小,精度掉最多
GQA 头分成 G 组,组内共享 G·n·d 质量≈MHA,显存-速度居中;GPT-4、Llama2 采用
MLA 低秩投影后缓存潜向量 R·n·d (R≪H) 缓存比 MQA 还小,质量反超 MHA;DeepSeek-V2 已上线

这边「把 KV-Cache 压成低质矩阵」不是离线“降采样”,而是 在线投影:“先降维 → 再缓存 → 计算时升维”,三步全在 NPU 上完成,且 只存压缩后的 latent vectors。

在deepseek中,MLA 里,“MQA vs MHA”不再是两种静态结构,而是同一组低秩 latent 权重的两种“展开姿势”——
pre-fill 时拆成独立头(MHA mode),decode 时共享同一份 KV(MQA mode),靠 reshape 即时切换,无需额外参数,也不掉精度。

分组查询注意力 (Grouped-Query Attention, GQA)/原理:
将 n_heads 个查询头 (Query Heads) 分成 g 个组。

Details

1. 分组:将 n_heads 个查询头 (Query Heads) 分成 g 个组。 2. 共享:每组内的所有查询头共享同一套 K 和 V。 3. 操作: Q 的个数不变(仍是 n_heads)。 K 和 V 的个数减少到 g 个(n_heads >= g)。 如过 g = n_heads,GQA 退化为 MHA。 如果 g = 1,GQA 退化为 MQA(所有头共享一套 K, V),也就是多头查询注意力 (Multi-Query Attention, MQA)

GDN/KDA

MHA/MQA/GQA/MLA 无论怎样压缩,仍然线性随 n 增长——这是两条根本不同的技术路线。
GDN/KDA直接跳出“缓存 K/V 再复用”的思路,把历史压进常数级递归状态,于是 KV-cache 大小与序列长度 n 无关。使用的好处是打破显存墙,能做“百万 token 实时推理”。

两种技术路线的区别见下表:

Details

维度 MHA/MQA/GQA/MLA GDN / KDA
存储对象 显式 K/V 向量(或低秩投影) 隐式递归状态 S(d×d 矩阵)
内存-长度关系 O(n) n 多长 cache 多大 O(1) n 再长也只占 d×d
算子范式 Attention + 矩阵乘 线性递归 / 状态空间更新
门控粒度 无(除 MLA 的投影) 头级标量门(GDN) / 通道级向量门(KDA)
长文本外推 需 RoPE、NTK 等位置修正 递归天然带衰减,外推更稳

原理:
GDN 和 KDA 都是把传统 softmax attention 改成‘线性递归’风格的模块,目的只有一个:把 KV cache 从 O(n) 砍成 O(1),同时保住效果。GDN 是“头级粗粒度门控”,KDA 是“通道级细粒度门控”,公式同级,但 KDA 把遗忘门拆成 dk 个独立 α,结果更省显存、更长上下文、还略涨点
混合比例两家都选 3:1(线性层 : 全局层),全局层负责偶尔全局对账,线性层负责 99 % token 的常数内存推理。”

MOE原理
一个共享专家,若干路由专家组成,由门控网络选择top-k个专家。对应结构原理,计算不爆炸原因,好处如下:

Details

核心概念与架构
一个标准的MoE层主要由两个部分组成:

  1. 专家:
    这些专家本身就是一个前馈神经网络,通常是结构相同但参数不共享的小型全连接层。
    每个专家都倾向于在输入数据的某个特定子集或某种特定模式上“专业化”。
    例如,一个专家可能擅长处理数学问题,另一个可能擅长处理文学问题。

  2. 门控网络:
    这是一个路由机制,它的职责是“审阅”输入数据。
    根据输入,它会产生一个概率分布,决定将输入发送给哪些专家。
    最终,只有Top-K(通常K=1或2)个得分最高的专家会被激活来处理这个输入。

工作流程:
输入 → 门控网络 → 选择Top-K专家 → 输入被发送给选中的专家 → 专家们分别处理输入 → 门控网络根据得分加权求和专家们的输出 → 得到最终输出。

PageAttention原理:
“PagedAttention 把操作系统『分页内存』搬进 GPU:

  1. 逻辑页:KV-Cache 按 16-token 固定大小切成连续『页』;
  2. 物理帧:显存里不连续的空闲块,用 block-table 映射;
  3. 共享+写时复制:多序列可共用同一物理页,引用计数为 0 立即回收,显存碎片 <4%,吞吐提升 2× 以上。”

Mask原理

今天的大模型掩码全是下三角 Causal,可选 pad/文档屏蔽;形状统一写成 (B,1,L,L) Boolean,True 表示可见。

比如因果掩码:防止标签泄漏,应用在Decoder的自注意力层(在训练和推理中均使用)。
填充掩码 (Padding Mask):忽略填充符号,应用在Encoder和Decoder的自注意力层(主要用于处理批量数据)。

qwen3的mask如下:

Details

qwen3 | 掩码类型 | 形状 | 值 | 说明 | | ------------- | ---------------------------- | ---------------- | ------------- | | **默认 Causal** | `(B, 1, L, L)` | 下三角 1,其余 0 | 单条生成时完全自动 | | **序列级 mask** | `(B, L)` → 扩为 `(B, 1, L, L)` | 有效 token=1,pad=0 | 批处理时屏蔽右侧 pad | | **完全自定义** | `(B, 1, L, L)` | 用户任意 Bool | 支持人工控制可见范围 |

LLM 推理的核心指标

Details

- Time To First Token (TTFT): 首 Token 延迟,即从输入到输出第一个 token 的延迟。在在线的流式应用中,TTFT 是最重要的指标,因为它决定了用户体验。 - Time Per Output Token (TPOT): 每个输出 token 的延迟(不含首个Token)。在离线的批处理应用中,TPOT 是最重要的指标,因为它决定了整个推理过程的时间。 - Latency:延迟,即从输入到输出最后一个 token 的延迟。 Latency = (TTFT) + (TPOT) * (the number of tokens to be generated). Latency 可以转换为 Tokens Per Second (TPS):TPS = (the number of tokens to be generated) / Latency。 - Throughput:吞吐量,即每秒针对所有请求生成的 token 数。以上三个指标都针对单个请求,而吞吐量是针对所有并发请求的。

我们将 LLM 应用分为两种:

  • 在线流式应用:对 TTFT、TPOT、Latency 敏感,需要尽可能快的生成 token。
  • 离线批量应用:对 Throughput 敏感,需要在单位时间内尽可能多的生成 token。
    而实际在某种应用(如在线流式应用),我们也应该在Latency 和 Throughput 之间进行权衡,提高 Throughtput 可以提高硬件承担的并发数,从而降低推理成本。

LLM基座的推理能力

核心评估维度:
逻辑推理 比如mmlu(涵盖57个主题的多项选择题)
数学推理 GSM8K, MATH, AQuA-RAT
常识推理 HellaSwag, PIQA, ARC
多步推理 BigBench-Hard, DROP
代码推理 HumanEval, MBPP,livecodebench,livecodebench2025

LLM 推理的性能卡点

小模型常用的优化手段

Details

训练前:剪枝 → 裁词表 → 层数减半

训练:蒸馏 + ZeRO + 检查点

推理:量化 → GQA → FlashAttn → Continuous Batch

蒸馏
蒸馏具体步骤

Details

第一步:准备阶段——搭建师生框架 这个阶段的目标是准备好老师和学生,并确定教学大纲。

训练/选定教师模型:
我们需要一个强大的、已经训练好的复杂模型(如大型BERT、ResNet-50等)作为教师。这个模型在目标任务上要有很高的准确率。初始化学生模型:设计一个更小、更高效的模型作为学生(如小型BERT、TinyBERT、MobileNet等)。

核心思想:学生模型的能力天花板通常低于老师,我们的目标是让它无限逼近这个天花板。

确定蒸馏策略:
明确要蒸馏的知识形式。最经典和常用的是基于输出的蒸馏,即让学生模仿老师最终的输出预测。

第二步:训练阶段
前向传播:
将同一批训练数据分别输入教师模型和学生模型。对教师和学生的输出logits(分数)同时使用高温Softmax(温度T > 1) 进行软化,得到富含信息的“软标签”。

损失计算:
蒸馏损失:计算学生软标签与教师软标签之间的差异。这里通常使用 KL散度,因为它专门用于衡量两个概率分布的相似度。这一步是让学生学习老师的‘暗知识’——即类别间的相似性关系。
学生损失:计算学生模型的标准输出(T=1)与真实标签(硬标签)之间的交叉熵损失。这一步是保证学生不偏离正确的答案。
总损失:将两个损失进行加权合并,公式为:总损失 = α * 蒸馏损失 + (1 - α) * 学生损失。这里的 α 是一个超参数,用于平衡两种知识来源的重要性。

参数更新:只对学生模型进行反向传播,根据总损失更新学生模型的参数。教师模型的参数是冻结的、不更新的。

Q:“温度参数T的作用是什么?”
答:T是一个超参数,用于控制输出概率分布的平滑程度。T越大,分布越平缓,错误类别蕴含的相对信息(暗知识)就越明显。T=1就是标准的Softmax。高的T有助于学生更好地学习类别间的关系,但通常推理时会设回T=1。

Q:“为什么学生模型能学到比直接训练更好的效果?”
答:因为硬标签只提供了“是什么”的单一信息,而教师的软标签提供了“什么像什么”的丰富结构化信息。这相当于一个学生不仅知道了答案,还理解了整个知识体系的内在联系,因此泛化能力更强。

剪枝
宽度剪枝(Sparse/Width Pruning):砍掉不重要的 Attention head、FFN 中间维度,效果是参数 ↓30-50%,精度掉 <1%
深度剪枝:直接删掉冗余 Transformer 层,效果是6L 小模型可比 12L 大模型快 2×
主要思路是Attention head / FFN 宽度 → 用 梯度/激活/权重幅值 + 一次性重要性估计 给每个 head/neuron 打分,低于阈值直接置零,再微调恢复精度。
整层冗余 → 用 Block Influence / LayerDrop + 早期彩票 ticket 先“试删”再评估下游掉点,掉点<ε 的层即可永久剔除。

不同场景如何优化,比如短输入长输出,长输入短输出;
低并发低时延,高并发高时延场景:
短输入长输出情况下如何提升decode性能,TPOT效果?
在“短输入 + 长输出”场景里,Decode 阶段占 90 % 以上时间,TPOT(每输出 token 延迟)是主要矛盾。核心思路是 “让每步 Decode 算得少、访存量低、批得大”。具体可做 6 件事:

Details

  1. PD 分离 + 高 Decode 专用卡
    把 Prefill 与 Decode 部署到不同 GPU,Decode 卡只做自回归,消除 Prefill 抢占,TPOT 立刻平稳 。
  2. 连续批处理调大“Decode 池”
    在 vLLM / TensorRT-LLM 里用 MAX_UTILIZATION 策略,保持 32-64 个序列同时解码,单卡 TPOT 随 batch 增大而下降(内存带宽打满即可)。
  3. KV-Cache 压缩 + 显存换带宽
  • KV-int8/int4 量化:把 KV 头压到 4-8 bit,显存↓50 % → 同显存可放更大 batch → TPOT↓15-30 %(百度云千帆实测多轮对话降 30 % Token 重复计算 )。
  • GQA / MLA:把 KV 头数从 64→8 或 1,同样 batch 下带宽需求线性下降。
  1. 投机解码(MTP / Medusa)
    用 1 主 + 1-3 草稿模型并行跑,70 % 接受率下每步可吐 1.7 token;华为云 Ascend 实测 TPOT 从 100 ms→50 ms 。
  2. 长输出分段流水 & 前缀缓存
    把 8 k-32 k 生成分成多段,段间 KV 复用;Prefix Cache 命中时首段之后 TTFT≈0,等效 TPOT 再降 20-40 % 。
  3. 低比特 GEMM + 算子融合
    W8A8 或 W4A16 让 Decode 的 MatMul 计算量减半;vLLM 的 Marlin/cutlass INT8 kernel + 单步 fused-QKV 投影可把每步延迟再削 5-10 %。

落地顺序(性价比)
PD 分离 → 连续批处理调大 → KV-int8 → GQA/MLA → 投机解码 → 分段流水
按此阶梯,TPOT 通常可从 100 ms 级压到 30-50 ms,长输出越长收益越大。

长输入短输出 → TTFT(首 token 时间)≈ Prefill 耗时。
核心矛盾:O(n²) Attention 与 HBM 带宽。优化思路:“算得少、算得快、吃得下、吐得快”。

Details

1. chunked-prefill(必开) 把提示按 512-2048 token 切块,与 Decode 交替进 batch;HBM 读写从 O(n²) 变 O(k·n),TTFT 线性化,vLLM 默认开启后 128 k 输入 TTFT ↓40-60 %。 2. 长序列专用 Attention 内核 FlashAttention-2 / Flash-Decoding:SRAM 分块 + 并行归约,A100 上 64 k seq 提速 2.2× MLA / GQA:KV 头数 64→1-8,带宽需求同比例下降,TTFT 再减 20-30 %。 3. KV-cache 压缩 + 前缀缓存 KV-int8 / int4 量化:显存↓50 % → 同样卡可放更长序列或更大 batch,128 k 输入 OOM 率从 30 %→0。 Prefix Cache:命中后首段 KV 免算,重复系统提示场景 TTFT 直接 0 ms。 4. 4/8-bit 权重 GEMM W4A16/W8A8 让线性层计算量减半;cutlass/Marlin INT8 kernel 在 Prefill 阶段带宽瓶颈下仍可再削 10-15 % 延迟。 5. 多卡并行策略 - TP+SP(Tensor + Sequence Parallel):把 128 k 序列按 2k-4k token 切片到多卡,每卡 Attention 降到 (seq/TP)²,TTFT 随卡数线性下降(Megatron-LM 实测 8 卡↓8×)。 - PD 分离(Prefill 专用 4-8 卡,Decode 1 卡):Prefill 阶段独占高算力,无 Decode 抢占,TTFT 方差 <5 %。

算子侧面耗时分析:
prefill以及decode:

Details

Image

大模型架构Qwen、GPT系列、llama系列,Deepseek系列

Transformer架构(Self-Attention(让每个词关注下句子里的其它词) + FFN(每个词独立处理) + 残差)

  1. GPT 系列
    最纯正 Decoder-only + 原始 MHA,靠堆参数、堆数据、堆算力出奇迹;GPT-4 开始用 8×8 专家混合(MoE) 降成本,但官方细节未公开。
  2. Llama 系列
    把 MHA 换成 GQA(分组查询,32→8 组),KV-cache 砍 4×;用 RoPE + SwiGLU + RMSNorm,成为后续开源模型的“标准模板”。
  3. Qwen 系列
    像qwen3-80b-next,在 Llama 模板基础上再切 2/3 层做 Gated DeltaNet(GDN)线性 Attention,缓存 O(1);长文本 1M token 外推靠 NTK-RoPE 动态基频。
  4. DeepSeek 系列
    DeepSeek-V2 首推 MLA(Multi-head Latent Attention):把 KV 先低秩投影到 128 维潜向量,再还原,缓存再降 5-8×,效果反超 MHA。
    DeepSeek-MoE 用 共享+细粒度专家 分割,每 token 只激活 8.3% 参数,训练成本只有同规模 Dense 的 40%。
    DualPipe 调度:Prefill/Decode 两条流水线 chunk 级并行,TTFT 降 30%。
  5. 共同底层
    全是 Pre-Norm、RMSNorm、SwiGLU、RoPE、TP/PP/DP 三维并行,差异只在于“注意力变体 + 专家路由 + 长程外推”这三板斧;面试抓关键词:GQA、GDN、MLA、MoE、NTK-RoPE 即可

Qwen模型架构与数据流动

核心改进总结:RMSNorm + SwiGLU + RoPE 已成为新一代LLM(如LLaMA, Qwen等)的标准配置。

  1. RMSNorm (Root Mean Square Normalization): RMSNorm 把 减均值和学偏置两步都删了,只剩一个缩放向量 γ
  2. SwiGLU激活函数: 取代了传统的ReLU或GELU激活函数。SwiGLU是GLU(Gated Linear Unit)的一种,引入了门控机制,被证明在语言模型中能带来更好的性能。
  3. 旋转位置编码 (RoPE, Rotary Position Embedding): 取代了绝对或相对位置编码。RoPE通过旋转矩阵的方式将位置信息编码到注意力计算中,能更好地处理长序列,并具有很好的外推性( extrapolation)。
  4. 分组查询注意力 (GQA, Grouped-Query Attention): 在较大的模型(如Qwen2-7B/72B)中使用了GQA。它介于MHA(多头注意力)和MQA(多查询注意力)之间,在几乎不损失效果的情况下,极大地减少了推理时KV Cache的内存占用,提高了推理速度。
  5. 更长的上下文长度: Qwen2支持128K token的上下文长度,这得益于RoPE和相关的工程优化。
  6. Tokenizer改进: 使用了更高效的分词器,词汇表大小扩大到152K,压缩率更高(特别是对中文和代码),减少了序列长度,提升了处理效率。

RMSNorm以及LayerNorm公式

目前主流的都是rmsnorm
为什么 RMSNorm 更快?
少一次 reduce-mean:LayerNorm 要先算均值,再算方差;RMSNorm 只算一次 RMS。
通信量减半:并行场景下 reduce 次数从 2→1,GPU 空闲时间↓。
无 β 偏移:参数内存减半,加载/优化开销↓。

维度 LayerNorm RMSNorm
计算内容 减均值 → 除方差 直接除 RMS(无减均值)
参数量 2 倍(γ, β) 1 倍(仅 γ)
零均值 ✅ 强制 ❌ 不强制
速度 基准 7 %–64 %↑
大模型表现 持平 持平或略好

具体公式如下:

Details

LayerNorm: $\text{LayerNorm}(\mathbf{x}) = \frac{\mathbf{x} - \mu}{\sigma} \odot \mathbf{g} + \mathbf{b}$ 其中 $\mu = \frac{1}{H}\sum_{i=1}^H x_i$, $\sigma = \sqrt{\frac{1}{H}\sum_{i=1}^H (x_i - \mu)^2 + \epsilon}$, $\mathbf{g}$ 和 $\mathbf{b}$ 是可学习的增益和偏置参数。

RMSNorm:
$\text{RMSNorm}(\mathbf{x}) = \frac{\mathbf{x}}{\text{RMS}(\mathbf{x})} \odot \mathbf{g}$
其中 $\text{RMS}(\mathbf{x}) = \sqrt{\frac{1}{H}\sum_{i=1}^H x_i^2 + \epsilon}$, 通常省略偏置 $\mathbf{b}$。

Swiglu原理
SwiGLU的公式是什么?
SwiGLU是Swish激活函数和GLU(Gated Linear Unit)结构的结合。

公式:
$\text{SwiGLU}(x, W, V, b, c) = \text{Swish}(xW + b) \odot (xV + c)$
其中:

  • $x$ 是输入
  • $W, V$ 是权重矩阵
  • $b, c$ 是偏置(可选)
  • $\odot$ 是逐元素乘法(Hadamard product)
  • $\text{Swish}(x) = x \cdot \sigma(x)$, $\sigma$ 是sigmoid函数。

GLU:这种 (A) ⊙ (B) 的结构被称为“门控线性单元”(Gated Linear Unit)。Swish(xW1) 是“门”,它控制 (xV) 哪些部分可以通过。
在Transformer的FFN层中,通常用SwiGLU取代原来的ReLU激活

相比relu对应优势:

  1. 梯度更丝滑
    Swish(x)=x·σ(βx) 全程可导、无硬零断点,反向传播不会“神经元猝死”;ReLU 负半轴恒零,易死区。
  2. 表达能力≈2×参数
    把 FFN 切成两条支路(gate 与 up),再做逐元乘:
    y = Swish(W₁x) ⊙ (W₂x)
    相当于给每个神经元配了一个可学习的“开关”,参数量*2,但无任何额外推理成本(合并算子即可)。
  3. 实验收益稳定
    同样 FLOPs 下,SwiGLU 在多项语言建模任务上 ppl 平均再降 2–3%;Llama、Qwen、DeepSeek 等开源模型已把它当成“默认激活”。

Q,K,V计算的实际过程:

Details

  • Query (Q - 查询):可以理解为“当前正在关注的 token”发出的一个询问:“与我相关的信息是什么?”
  • Key (K - 键):可以理解为所有 token 提供的一个“标识”,用来匹配 Query。Query 会与所有 Key 进行相似度比较。
  • Value (V - 值):可以理解为每个 token 所包含的“实际信息”或“内容”。一旦通过 Q-K 匹配确定了哪些 token 重要,我们就对这些 token 的 Value 进行加权求和。

实际过程:

  1. 线性投影:通过三个权重矩阵 W^Q, W^K, W^V,将输入 X 分别投影到 Q, K, V 空间。
  2. Q = X * W^Q, K = X * W^K, V = X * W^V
  3. 计算注意力得分:计算 Query 和所有 Key 的点积,得到相似度得分。Score = Q * K^T
  4. 缩放:为了防止点积结果过大导致 Softmax 梯度消失,将得分除以 Key 向量维度的平方根。Scaled_Score = Score / √d_k
  5. 应用 Softmax:对缩放后的得分应用 Softmax 函数,得到归一化的注意力权重(所有权重和为1)。Attention_Weights = Softmax(Scaled_Score)
  6. 加权求和:用注意力权重对 Value 向量进行加权求和,得到最终的输出。Output = Attention_Weights * V

这个输出就包含了当前 token 从序列所有其他 token 那里聚合到的上下文信息。

  1. 多头自注意力机制 (Multi-Head Self-Attention)
  • “自” (Self) 的含义:输入序列自身内部元素之间进行注意力计算。例如,句子中的每个词都会与句子中的所有词(包括自己)进行关联,从而捕捉词与词之间的语义和语法关系。
  • attention核心公式:Attention(Q, K, V) = softmax(QK^T / √d_k) V
  • 让模型能够“同时看到”整个序列,并理解每个词在上下文中的真正含义。
  1. 前馈神经网络 (Feed-Forward Network, FFN)
  • 一个简单的全连接网络,通常包含一个隐藏层和激活函数(如 ReLU)。
  • 对自注意力层的输出进行非线性变换和空间映射,增强模型的表达能力。
  1. 残差连接 (Add) 和层归一化 (Norm)
  • 残差连接 (Residual Connection):将子层的输入直接加到其输出上(Output = Sublayer(input) + input)。这有效地缓解了深层网络中的梯度消失问题,使得模型可以堆叠得很深。
  • 层归一化 (Layer Normalization):对残差相加后的结果进行归一化,稳定训练过程,加快收敛
    公式表示一个 Encoder Layer:
    EncoderOutput = LayerNorm( SelfAttention(Input) + Input )
    FinalOutput = LayerNorm( FFN(EncoderOutput) + EncoderOutput )

Decoder解码器组成
根据 Encoder 产生的中间表示,自回归地(一个一个地)生成输出序列(如翻译后的句子)。

Details

  1. 掩码多头自注意力机制 (Masked Multi-Head Self-Attention)
  • “掩码” (Masked) 的含义:为了防止在训练时“偷看”未来信息(即解码第 t 个词时只能看到 1 到 t-1 的词),通过一个掩码矩阵将当前位置之后的所有信息屏蔽掉(设置为负无穷,softmax 后变为 0)。
  1. 多头交叉注意力机制 (Multi-Head Cross-Attention)
  • “交叉” (Cross) 的含义:Decoder 的表示 与 Encoder 的最终输出 进行注意力计算。
  • Query (Q) 来自 Masked Self-Attention 的输出。
  • Key (K) 和 Value (V) 来自 Encoder 的最终输出。
  • 这是 Encoder 和 Decoder 之间信息交互的桥梁,让 Decoder 在生成每一个词时都能有针对性地关注输入序列中最相关的部分。
  1. 前馈神经网络 (Feed-Forward Network, FFN)
    每个子层都伴随着残差连接和层归一化。

不同推理框架

目前推理框架包含vllm、SGlang、LMDeploy、TensorRT-LLM

四者对比:
图编译器(生成引擎) → TensorRT-LLM ,优化是预编译+算子融合+FP8-TC,编译慢,但是执行快
推理引擎(动态调度) → vLLM,适合需要处理大量并发请求的在线服务
前缀缓存 → SGLang。SGLang = “前端结构化生成语言 + 后端三层推理引擎”,用 RadixAttention 做 KV-Cache 前缀复用,再辅以 PD 分离、Rust 高并发 Router 与 多精度 Cube 内核,把大模型推理的延迟、吞吐、显存一起打下来。
服务框架(HTTP/gRPC+批处理)→ Triton,优化是动态批+并发执行+多模型编排
国产化/训练推理一体 → LMDeploy

sglang与vllm对应区别具体区别如下:
Sglang: @sgl.function → Frontend 编译成前缀图 → Runtime 用 RadixAttention 找 KV 复用点 → 扔给 vLLM 连续批解码 → 流式 yield 回前端,全程零手动 batch,长对话吞吐最高提 5 倍

Details

要“低延迟 + 复杂格式 + 长上下文”——上 SGLang; 要“稳态吞吐 + 多模型兼容 + 社区插件”——继续 vLLM; 也可混部:SGLang 扛在线实时流量,vLLM 扛离线批量任务,成本最优。

SGLang 的 6 个杀手锏特性

  1. RadixAttention —— 前缀感知缓存
    用 RadixTree 把不同 Prompt 的公共前缀自动复用,相同系统提示、Few-shot 示例只算一次,长模板场景 TTFT 降低 3×。
  2. 零开销 CPU 调度器 —— 纯异步 Python+C++ 双栈
    调度路径全异步,无 GIL 等待;单卡 8B 模型 Median TTFT 31 ms,仅为 vLLM 的 1/3。
  3. 预填充-解码分离架构 —— 并行算两个阶段
    预填充(Prompt)与解码(Generation)拆成两条 CUDA Stream,显存-计算重叠,ITL 比 vLLM 快 10×。
  4. 原生结构化生成 —— JSON/Regex 语法提前编译
    把 JSON Schema 直接编译成有限状态机,采样空间缩小 2 个数量级,复杂格式任务端到端提速 6×。
  5. 智能分页 KVCache —— 动态换入换出
    类似操作系统页表,显存不足时把冷块换到主机内存,单卡可跑 128 k 上下文不 OOM(官方数据,Llama-3.1-70B)[ ^75^ ]。
  6. 生产级稳定性 —— 99.95 % MTBF
    高负载崩溃率 0.01 %,低于 vLLM 的 0.5 %;故障恢复 <30 s

vllm推理框架架构

vLLM 采用分层架构设计,主要包括控制面和执行面。

请求调度

vLLM 的调度器 (Scheduler) 是大脑,其核心策略是 Continuous Batching (连续批处理)

Details

- 基于 Token 调度:以 Token 为最小调度单位 - 调度过程:Scheduler 维护 waiting(新请求)、running(正在处理)、swapped(因资源不足被换出的请求)队列。其调度优先级通常是:swapped > waiting > running,优先处理已被换出的请求以避免资源浪费,并在资源足够时从 waiting 队列加入新请求。 - 工作流程: 1. 新请求进入 waiting 队列。 2. Scheduler 根据调度策略(如 FCFS)、当前 running 队列的负载、空闲物理块等因素,决定将哪些 waiting 或 swapped 队列中的请求加入 running 队列以进行下一批计算。 3. Worker 执行 running 队列中请求的推理计算。 4. 生成 Token 后,更新序列状态。若请求完成则释放资源,否则根据情况放回 running 或换出到 swapped 队列。 5. 循环上述过程。

vllm推理整体流程

一条请求发送到vllm全过程:

主要分为五步:入口 → 调度 → 执行 → 采样 → 返回
prompt 进 vLLM → Scheduler 连续批 → ModelExecutor 做 Prefill/Decode → Sampler 选 token → PagedAttention 更新 KV-Cache → 回包(最终封装成 RequestOutput 返回用户),全程零拷贝、可 chunk、可并发;
请求进 api_server → 预算调度 scheduler.schedule() → Worker execute_model 一次 forward → sample 得 next_token → ZMQ (嵌入进程的异步通信库)流回客户端;token 完立即 free_blocks 回收 KV。

官方 release note(主线):
https://github.com/vllm-project/vllm/releases
昇腾插件 release note(Ascend 专属):
https://vllm-ascend.readthedocs.io/zh-cn/latest/user_guide/release_notes.html

vllm中v0与v1区别
具体细节如下

Details

v1 的“更好”主要体现在以下几个方面:

  1. 调度模型:从 Iteration 到 Step 的进化
    这是最核心的改进。

v0 (Iteration 模型):调度单位是一个“迭代”,引擎会一次性解码多个令牌,直到当前批次中所有序列都完成。这对于静态、规整的批处理很有效,但在面对持续到达、长度不一的流式请求时,会导致:
Head-of-Line Blocking(队头阻塞):一个生成长文本的请求会阻塞后面短请求的返回,增加延迟。
资源利用率不均衡:在迭代末尾,可能只有少数序列还在计算,GPU利用率下降。

v1 (Step 模型):调度单位是一个“时间步”(每次前向传播只生成一个令牌)。这使得引擎可以实现:
细粒度调度:每个时间步都可以重新评估哪些请求应该被调度、暂停或换出。
真正的连续批处理:新请求可以几乎无延迟地加入下一个时间步,而无需等待当前批次全部完成。这显著降低了尾延迟,提升了用户体验。

  1. 架构清晰度:从“引擎全能”到“职责分离”
    v0:核心的 LLMEngine 承担了太多职责,包括调度、执行、内存管理,导致逻辑耦合紧密,难以维护和扩展。
    v1:引入了清晰的角色分离:

Scheduler:专职负责调度决策(哪个请求该 RUNNING,哪个该 WAITING 或 SWAPPED)。
Worker:专职负责执行模型的前向传播。
Executor:作为协调者,驱动 Scheduler 和 Worker 的交互,并决定执行模式(如是否使用CUDA Graph)。

这种分离使得系统更模块化、更易于测试、也更利于未来引入新的调度策略和执行后端。

  1. 执行效率:对 CUDA Graph 的深度集成
    v0:虽然也支持 CUDA Graph,但其集成方式在动态调度场景下不够高效。
    v1:将模型执行(特别是预处理、解码、采样)深度编译成一系列CUDA Graph。在执行时,只需要“启动”这些预编译的图,而不是一次次发射单个Kernel。

好处:极大地减少了CPU开销和Kernel启动延迟,实现了 “内核零Python回跳” ,从而在保持调度灵活性的同时,达到了接近极限的GPU利用率。

  1. 功能与扩展性
    v1 原生更好地支持了更多高级特性,如:

Chunked Prefill:将长的提示处理(Prefill)阶段切分成多个块,与解码步骤交错进行,进一步减少了队头阻塞。
更好的抢占与恢复:基于新的调度状态,可以更优雅地处理高优先级请求的插队。

总结
如果用一句话概括,v0 到 v1 的演进是 从一个“高效的批处理系统”进化为了一个“高吞吐、低延迟的实时流式服务系统”。

v0 的核心贡献是解决了“内存”问题,证明了分页KV-Cache的巨大价值。

v1 的核心贡献是解决了“调度与执行”问题,通过细粒度的Step级调度、清晰的架构分离和极致的CUDA Graph优化,在保持高吞吐的同时,大幅降低了延迟,使vLLM真正成为生产级LLM服务的首选引擎。

vLLM V1 是一次意义重大的架构升级,把「调度-执行-IO」拆成独立进程,用增量通信换掉全局广播,默认打开 chunk-prefill、前缀缓存,对称张量并行和持久化批次等新优化,同等 GPU 下吞吐提升 10-30%,TTFT 降 30% 以上。

  1. 架构上

Prefill: num_computed_tokens=0;
Decode: num_computed_tokens=num_tokens-1,所以只有最后一个token需要被送进大模型作 Decode 生成;
Prefix caching: 让num_computed_tokens等于命中 KV 缓存的长度。
Jump decoding: 直接在请求后面增加希望解码的格式,并增加相应的num_tokens长度。
这样一改,可以直接砍掉swapped队列。在 V1 中,被抢占的请求是直接塞到waiting队列的头部,但它自己记录了自己算过多少token(num_computed_tokens),并知道它们的 KV cache 存在哪。这还保证了被抢占请求是比waiting队列中的请求优先级更高。总之,逻辑简化并且效率更高。

  1. 调度器
    第二个大改动是开了两个进程分别处理。一个是 GPU 密集型任务如 Transformer 执行,另一个是 CPU 密集型任务如 tokenization, multimodal input processing 和 de-tokenization。两个进程同时执行,加快速度。

  2. 优化的执行循环
    第三个,在张量并行中把输入处理也做并行化,实现了一个对称的并行结构。具体是在 EngineCore 进程中,将每一个 worker 用一个线程管理。

  3. 将 Attention 计算的部分从 CUDA 图中分离出来,使用 PyTorch 后端。这使得针对 Attention 进行优化的一些方法可以被应用进来,如Cascade Attention。

vllm架构整体细节部分:

Details

  1. 入口层(API & 协议)【6 分】
    “外部请求先进 openai/api_server.py,它把 REST/HTTP 转成内部 SARIF 协议,
    再交给 AsyncLLMEngine 做异步调度,天然支持连续批处理与 streaming 返回。”
  2. 调度器(Scheduler)【8 分】
    “Scheduler 维护三重队列:Waiting / Running / Swapped,
    每轮调度先看 GPU 显存水位,再按 prefix-hash 做 APC 匹配,把可复用 KV 块直接挂到 Running 队列,
    剩余 token 数 > max_num_batched_tokens 的切片会推迟到下一轮,保证计算密度。”
  3. 执行器(Worker / ModelRunner)【10 分】
    “Worker 里真正跑推理的是 ModelRunner,它把
    ① 输入 token-id → ② embedding lookup → ③ 逐层 TransformerBlock → ④ logits 输出
    全部 compile 成一张 CUDA graph,一次 launch 完成,内核零 Python 回跳;
    每层 TransformerBlock 内部调用 xFormers / FlashAttention / PagedAttention CUDA kernel,实现 KV-Cache 分页管理。”
  4. KV-Cache 存储(CacheEngine + BlockTable)【10 分】
    “KV-Cache 以 block_size=16 分页,逻辑块号到物理块号的映射存在 BlockTable;
    CacheEngine 提前 malloc 一整块 GPU memory pool,按 16-token 粒度切页,通过 ref-count 做 LRU 回收;
    APC 模块在 scheduler 阶段把命中页直接挂到 BlockTable,未命中页标记为‘待计算’,推理阶段只做增量填充。”
  5. 量化与 Kernel(Quantization + Custom Ops)【8 分】
    “量化层采用‘插件化’方案:compressed-tensors / AWQ / GPTQ / FP8 各自继承 QuantizationScheme,
    在 ModelRunner 里动态替换 Linear 层为 qlinear,kernel 侧一条融合算子完成 dequant+gemm,回写 FP16;
    KV-Cache 支持 C8 动态对称量化,scale 由 kernel 在线 reduce,zero-point 固定 0,输出直接 BF16,零回写。”
  6. 分布式(PP + TP + DP)【8 分】
    “30B 以上模型用 Ray 起多节点,PP 把层切到不同节点,TP 把单层权重按 hidden 维度切到 8 卡,
    通信后端统一走 PyTorch NCCL,vLLM 自己包了一层 Pynccl 做 all-gather / reduce-scatter,支持 CUDA graph 内嵌通信 kernel,无 Python GIL;
    DP 靠数据并行扩展 QPS,每份副本独立调度,负载均衡由 proxy 层轮询完成。”
  7. 内存与抢占(Swap + Recompute)【6 分】
    “当显存不足时,Scheduler 把 Swapped 队列整块 KV-Cache 通过 cudaMemcpyAsync 换到 CPU DRAM,
    下次调度再提前 async 预取;若仍不够,就砍掉最长序列的尾部 25 % 做 selective recomputation,保证正确性。”
    一句话收尾【4 分】
    “总结:vLLM=‘分页 KV-Cache + 连续批调度 + 融合 CUDA Kernel’ 三件套,把 LLM 推理做成显存可换页、计算可流水、协议可插拔的实时服务。”

推理任务的调度与抢占:

vllm采用了 FCFS(first-come-first-serve) 的策略;
vllm中块回收策略:All-or-Nothing

块恢复策略:Swapping 与 Recomputation

Swapping(交换):将被抢占请求的 KV Cache 块从 GPU 移动到 CPU 内存。当有空闲 GPU 块时再从 CPU 恢复回来继续执行。为了控制资源使用,被交换(swapped)到 CPU 内存中的 KV Cache 块数量,永远不会超过 GPU 中物理块的总数。
Recomputation(重计算):直接丢弃已生成的 KV Cache,待请求恢复后重新计算。
根据论文中的实验结果,Swapping 更适用于 block size 较大的场景,而 Recomputation 则在不同 block size 下的表现更为稳定。在中等 block size(16 到 64)范围内,两种方式的端到端性能基本相当。

HCCL

华为对应集合通信库,支持allreduce、broadcast、allgather、reduceScatter、AlltoAll等通信原语
broadcast:1到多,将数据从一个节点发送到所有节点
gather:多到1
scatter:1个npu数据切分到其它npu
reduce:多个npu获取数据并做规约运算

allreduce:从多个npu获取数据到所有npu并做归约运算(求和平均最大最小乘积ANDOR),规约+广播:所有节点都有最终结果
reduce scatter:规约后结果分散到不同节点
allgather:收集每个npu所有的数据到每个npu上
alltoallv:所有npu互相scatter和gather数据

简单总结:规约运算是AllReduce的核心计算步骤,负责将分散的数据合并;AllReduce是完整通信原语,包含规约和广播两个阶段。

前沿思想:

DSA

DeepSeek 稀疏注意力(DSA, DeepSeek Sparse Attention)的核心思路是
“先海选、后精算”:用极轻量的索引器闪电式筛出与当前查询最相关的 Top-k 个历史 token,再在这些“候选”上执行标准注意力,从而把 O(L²) 的平方复杂度降到 O(L·k)(k≪L)。整套机制在 MLA(Multi-Query Attention)框架下实现,兼顾长上下文精度与工程效率。

MHA:同时用 H 个固定头算注意力,显存 ∝ H;
DSA:细粒度稀疏注意力
• 动态分层稀疏:结合粗粒度压缩与细粒度选择,保留全局和局部信息。
• 硬件对齐设计:采用分块处理,适配GPU连续内存访问,优化Tensor Core利用

技术路线角度:每个 token 动态选 1 个“最优单头” 计算,显存 ≈ 1;(模型学会“抓关键”,只计算最相关的词关系子集)
靠在线路由把“多头多样性”转成“时序多样性”,KV 缓存与计算量都降 H 倍,长序列成本直降 50 % 以上。

DSA具体解决了NSA什么问题:

Details

DSA解决了NSA什么问题? DSA(DeepSeek Sparse Attention)主要解决了 NSA(Native Sparse Attention)在稀疏索引学习、计算效率与训练稳定性上的三大痛点,具体改进如下:


1️⃣ 索引学习更准:引入“注意力分数蒸馏”

  • NSA 只靠 LM Loss 端到端优化,没有直接监督“选哪些 token”,导致长文检索任务索引学歪。
  • DSA 额外加一条 Attn-Score 蒸馏损失,让 Indexer 的 Top-K 结果去拟合真实注意力分布,“选得准”被显式优化,长距离依赖召回率大幅提升。

2️⃣ 计算范式更简:三合一分支 → 单分支

  • NSA 维护三套独立 KV-Cache(压缩、选择、滑动),推理时要走三次 Attention,内存占用大、kernel 切换开销高
  • DSA 把“选 token”与“算 attention”解耦:
    闪电索引器一次性产出 Top-K 地址;
    主路径用同一套 KV 做 MQA 即可。
    单分支、单缓存、零额外参数,Prefill/Decode 全链路 kernel 融合更彻底,A100 上 Prefill 提速 2.1×、Decode 提速 2.3×

3️⃣ 稀疏粒度更细:Block-level → Token-level

  • NSA 以“块”为最小单位,块内冗余计算无法避免
  • DSA 直接在 token 粒度挑重点,Top-K 索引精度更高,短文本可无缝回退到稠密模式,零性能回退;长文本保持相同模型参数即可扩展到 128 K。

一句话总结:
DSA 用“注意力蒸馏 + 单分支 MQA + Token-level 稀疏”三板斧,把 NSA 的“多缓存、粗粒度、难训练”问题一次性解决,在同等模型尺寸下实现训练更快、推理更省、长文更准

DSA具体流程如下:

Details

一、总体流程(两阶段) 阶段 1 Lightning Indexer(海选) 低维投影:把高维 Q、K 先压到 128 维(可学习线性层),再量化为 FP8。 快速打分:执行一次小矩阵乘 index_score = ReLU(Q_index · K_index^T);ReLU 只取正相关,避免 Softmax 全局归一化开销。 跨头聚合:把多个 query head 的分数求和,得到每个查询 token 对所有历史 token 的“相关性向量” Iₜ。

阶段 2 Top-k 选择 + 稀疏 MLA(精算)
4. 选 Top-k:对 Iₜ 取 Top-2048 索引(训练固定 k=2048)。
5. 构造稀疏 KV:只把这些位置的主 KV 从缓存里 gather 出来(连续块访问,GPU 友好)。
6. 执行注意力:在筛后的 2048 个 KV 上算标准 MQA,输出上下文向量。

二、与 MLA 的耦合
采用 MQA 模式:所有 query head 共享同一组 KV,因此只需一次 Top-k 筛选即可服务全部头,避免重复存储与计算。
位置编码:仅对索引向量及主 KV 施加 RoPE,兼顾位置感知与效率。
持续训练:在 DeepSeek-V3.1-Terminus Checkpoint 上做两阶段继续训练——密集热身 → 稀疏微调,保证模型适应稀疏分布。

DSA = “FP8 低维 ReLU 海选” + “Top-k 稀疏 MLA”;
在 MLA 的 MQA 模式下,用一次轻量索引完成所有 query head 的候选筛选,
把平方复杂度压到线性,长文本 128 K 场景几乎无损精度,推理成本砍半

相关文章:https://mp.weixin.qq.com/s/-dBxaYyisXwIvPNRFZCrCQ

路线一:低秩压缩
路线二:层内混合稀疏(NSA)
路线三:层间混合稀疏 Gemini(GQA+SWA)
路线四:线性混合稀疏 TurboS(GQA+SSM)
GQA = “分组共享 KV 头”省带宽
SWA = “滑动窗口”砍计算量
SSM = “线性状态空间”全局建模不降长度

Details

GQA(Grouped-Query Attention)
把 Q 头分成 G 组,每组共享 1 份 K/V 头;组数 G 是“质量-速度”滑杆:G=1 等价于 MQA,G=H 退回到 MHA
效果:KV-Cache 内存带宽 ∝ G/H,推理时解码层只需加载 G 组键值,远小于原来 H 组。
SWA(Sliding-Window Attention / Stochastic-Weight-Averaging 两义)
在“层内混合稀疏”语境下一般取 Sliding-Window Attention(NSA 论文用法):
对每个 token 只计算附近 W 个位置的注意力,形成固定宽度窗口,复杂度从 O(n²) 降到 O(nW);跨层错位窗口后即可覆盖长距依赖,实现“局部密集 + 全局稀疏”的混合模式 。
另一义 Stochastic-Weight-Averaging 为优化器技巧,与稀疏无关,此处不展开。
SSM(State-Space Model,以 S4/S5 为代表)
把序列建模成线性时不变系统:
h′ = Ah + Bx, y = Ch + Dx
通过 HiPPO 初始化 A 并推导长卷积核,可在线性时间 O(n) 并行计算;既能像 CNN 一样全局卷积,又能像 RNN 一样逐步递归,因而被拿来替换部分注意力头,形成“注意力+SSM”的线性混合稀疏结构 。

AFD思想

Transformer模型中的Attention层和FFN层具有截然不同的计算和访存特性。
Attention层:在解码阶段通常是内存带宽瓶颈型的,需要频繁访问KV缓存,对内存带宽要求高。
FFN层(尤其是MoE模型中的专家):则更多是计算瓶颈型的,涉及大量矩阵运算,对计算能力要求高。

将两者分离,允许我们为它们分别匹配最合适的硬件资源。例如,可以将Attention模块部署在高带宽内存的GPU上,而将FFN/专家模块部署在高算力的GPU或NPU上,并通过高速网络连接。这种异构部署能够显著提升整体系统的吞吐量和资源利用率。

AFD作为一种前沿的系统架构思想,正受到业界越来越多的关注和应用:

vLLM的集成计划:高效能的LLM推理框架vLLM项目已经在GitHub上开启了关于为MoE模型引入ATTN-FFN解耦(AFD) 的提案和讨论,旨在未来版本中支持这一特性。
与Prefill-Decoding解耦的结合:AFD通常被构建在Prefill-Decoding (PD) 分离的架构之上,这使得系统设计可以更专注于优化解码阶段,从而实现更精细化的资源管理和调度

TPA(Tensor Product Attention)

背景通点:标准 MHA 的 KV 缓存 = O(T·h·d_h),序列一拉长显存指数级膨胀;MLA 虽压缩但难与 RoPE 直接兼容(旋转要作用在最终 key/token 维,而 MLA 存的是压缩向量)。
TPA 用上下文张量分解把 KV 缓存压到 1/10,即时重算全尺寸 key/query → 既省内存又天然兼容 RoPE,T6 模型已证明长序列 PPL 再降 12%,是 2025 首个**‘压缩+旋转’一举两得**的注意力升级。

SepLLM kv压缩

核心理念来源于一个关键观察:在 Transformer 的 KV Cache 中,有大量信息是冗余的,尤其是在处理语义相近的连续文本时。

SepLLM 的 KV Cache 压缩原理本质上是:通过在线、动态地识别并仅存储上下文序列中信息量最大、最具代表性的 token(骨干序列),同时辅以一个小的滑动窗口(最近序列)来保证局部语言模型效果,从而在极高地压缩显存占用的同时,最大限度地保持了模型的原生性能。 它是一种巧妙利用语义冗余的、高效且实用的推理加速技术。

Details

它将 KV Cache 中的信息分为两类:

骨干序列:一组稀疏的、具有代表性的 Key-Value 对。它们构成了当前上下文的“骨架”或“概要”,负责捕捉和保留整个序列的核心语义信息。
最近序列:最近生成的几个 token 的完整的 Key-Value 对。它们负责捕捉局部的、细粒度的语言模式和连贯性。

“分离” 就体现在这里:模型在推理时,会动态地、有选择地更新和维护 骨干序列,而 最近序列 则像滑动窗口一样固定不变。

具体步骤的话:

步骤 1:计算相似度并选择骨干
当一个新的 token 被生成并其 KV 向量准备加入缓存时,SepLLM 不会直接将其加入骨干序列。相反,它会执行以下操作:

  • 计算相似度:将新 token 的 Key 向量与当前 骨干序列 中所有已有的 Key 向量进行相似度比较(通常使用余弦相似度)。
  • 选择策略:

如果新 token 的 Key 与骨干序列中任何一个现有 Key 的相似度高于某个预设阈值,则认为这个新 token 的语义信息已经被现有的骨干节点所“代表”。此时,不将其加入骨干序列,从而避免了冗余。
如果新 token 的 Key 与所有骨干 Key 的相似度都低于阈值,则认为它带来了新的、独特的语义信息。此时,将其加入骨干序列,作为新的骨干节点。

通过这个动态选择过程,骨干序列只保留那些信息量最大、最具代表性的 token,形成了一个高度压缩的上下文概要。

步骤 2:构建混合 KV Cache 进行注意力计算
在计算注意力时,SepLLM 使用的是混合的 KV Cache:

混合KV Cache = 骨干序列 + 最近序列

  • 骨干序列:代表了从序列开始到现在的全局、压缩的语义上下文。
  • 最近序列:一个固定大小(例如 128 或 256)的滑动窗口,包含了最近生成的 token,保证了局部语言的流畅性和连贯性。

模型在计算注意力时,Query 会同时与这个混合 Cache 中的 Key 进行交互。这样,模型既能把握全局的语义脉络(通过骨干序列),又能确保下一个生成的词在语法和局部语境上是准确的(通过最近序列)。

步骤 3:维护与更新

  • 最近序列:像一个 FIFO(先进先出)队列,新的 token 加入,最老的 token 被移出(如果它不在骨干序列中)。
  • 骨干序列:根据上述相似度阈值策略动态增长。为了防止其无限膨胀,也可以设置一个最大骨干数量。当超过时,可以基于一些启发式方法(如最久未使用)合并或移除最不重要的骨干。

一张卡上的显存占用结构(以 7B 模型为例)

组件 占用大小(近似) 是否可调整
模型权重 ~14 GB ❌ 固定
KV Cache ~9–10 GB ✅ 调 gpu_memory_utilization
激活值 ~4–5 GB ✅ 调 max_num_seqsmax_model_len
非 Torch 显存 ~0.1–2 GB ❌ 较难控制

Mooncake

MoonCake:使用池化系统缓存50Mtoken, PrefixCache命中率可达50%左右;
Mooncake 则是“为 LLM 定制的分布式零拷贝缓存池”,后者在长文本、高带宽、高并发场景下把 TTFT 压得更低,吞吐更高。
幻方部署3FS存储系统,进行KVCache池化,E2E成本降低35%。Mooncake 的“零拷贝”指的是 GPU↔DRAM↔SSD 之间不走 CPU 内存拷贝。

客户在各服务化引擎上均有KV池化述求, 以HBM+DRAM+SSD为主
一句话
HBM = GPU 显存本体,放最热 KV;池化角色:L1 热池——当前 step/shot 正在用的 KV-Block,命中率要求 90%+
DRAM = 内存,放温数据,秒级换入;池化角色:L2 温池——最近 1–10 min 内复用、但 GPU 显存已换出的块;通过 RDMA 可跨节点秒级拉回
SSD = 盘,放冷数据,容量最大。池化角色:L3 冷池——小时-天级复用(历史长文、用户长期记忆);掉电不丢,可整池重启快速预热
三层组合成“HBM+DRAM+SSD”KV-Cache 池,兼顾显存节省、命中率、成本/GB。

L1/L2/L3/L4/L5

层级 典型位置 容量* 延迟** 共享范围 备注 / 其他叫法
L0 寄存器文件 几十 B-几 KB sub-ns 单线程独占 有时把寄存器叫 "L0"
L1 片上,同核心 16-128 KB ~1 ns 单核心 分 I-cache / D-cache;NPU 里叫 Unified Buffer
L2 片上,邻近核心 256 KB-几 MB 3-10 ns 多核共享 GPU 叫 Shared Memory;NPU 叫 L2 CacheTCM
L3 片上/片外 4-64 MB 10-40 ns 整芯片 CPU 常叫 LLC;GPU 无 L3,用 L2 顶到头
L4 片外 DRAM 8-512 GB 100-300 ns 全系统 就是 主存 / HBM;有人戏称 "L4"
L5 磁盘/网络 TB-PB ms-s 跨节点 Swap / NVMe / Ceph,戏称 "L5"

L1 最小最快最私有,L2 共享片上大容量,L3 整芯片末级缓存;再往下就是主存(L4)和磁盘(L5)。