type
status
date
slug
summary
tags
category
icon
password
1. 大语言模型的推理加速方案
1.1. 为什么KV Cache不在training中使用只在inference中使用
回答:因为训练(Training)和推理(Inference)的计算方式完全不同。
解释:
- 训练 (Training) 是“并行”的: 为了高效利用 GPU,我们一次性将整个完整序列(例如,一个完整的句子)输入模型,并使用 Causal Mask (注意力掩码) 来防止位置 i 的 token "偷看" 到位置 j > i 的 token。

- 推理 (Inference) 是“串行”的: 我们一次只生成一个新 token,然后把它添加到输入序列中,再生成下一个。
KV Cache 正是为了优化这种“串行”的、逐字生成的推理过程而设计的。
KV Cache的存储方式
两个不同的句子是否需要重新计算所有的k和v的矩阵?
新的句子中相同的字符是否需要重新计算QKV?
回答:是的,必须重新计算。因为同一个词在句中的位置(Positional encoding)和上下文表示(Contextual representation)可能不同。
换一种说法:
p1: what are the two steps in LLM inference?
prefill and decode 预填充和解码
由于self-attention, 多个token输入的时候,可以做成keys Matrix x Queries Matrix进行并行计算,
- Prefill (预填充) 阶段:负责创建和填充初始的 KV Cache。
- Decode (解码) 阶段:负责使用和扩展这个 KV Cache。


怎么加速推理?

关键在于延迟和吞吐量。
Latency (延迟) 和 Throughput (吞吐量) 是衡量系统性能的两个关键指标,它们描述的是不同的东西:
- Latency关注的是响应时间。
- Througtput关注的是单位时间内系统能处理的操作数量(流量)。
提问:
- Why multi-head attention?
- 多角度看问题。multi-head attention是设置多个注意力机制,详见子空间。
- Theory: subspace 子空间
- 每个注意力头都有自己的QKV矩阵
- 由于初始化矩阵不同,所以训练后会学到不同的投影方式。(如一个学会动词和主语之间关系,一个学会同义词之间的关联性)
- 多个注意力头在各自的小空间里独立学习,最后拼起来。怎么拼起来看下面。
- Compute: parallel 并行计算多注意力头
- gpu可以同时计算所有头,不是使用loop。而是批处理矩阵(batched matrix multiply, BMM)。比如原本要输入[BatchSize=2(两句句子), SeqLen(每句10个词), 512(模型维度)] [2,10,512]。
- Reshape(逻辑拆分)。将维度拆分成多个头[2,10,8,64]。
- Transpose(转置)。 都这么转 [2,8,10,64]。
- 矩阵乘法。 中的 [2,8,64,10]。相乘的时候pytorch会自动识别后两维是批次维度,并行处理完结果就是注意力分数矩阵 [2,8,10,10]。
- How to use CUDA to optimized multi-head attention
- 由于MHA只有在计算 的时候是在显存里,读结果的scale, mask,softmax都是在内存,所以有优化空间。
- FlashAttention 是 MHA 优化技术。
- 内核融合,将各步骤都融合到一个 CUDA 内核里完成。
- 分块(Tiling):在计算 的时候,是一个大矩阵,可能放不进片上内存(SRAM,计算速度快)。将这个矩阵分成小块(Tiles),在SRAM上计算每个结果的Softmax,然后累加起来。
1.2. tensor parallelism和pipeline parallelism(并行)
这两个并行策略的作用:解决大模型过大一张显卡的显存装不下的问题。通过切分模型,分别在不同显卡中运算。
- Pipeline parallelism(流水线并行):
- 模型纵向切分
- 不同GPU处理不同层(GPU1: 1-10Layers, GPU2: 11-20Layers, …)。显卡之间是串行的,一个处理完传输结果到下一个,最后出结果。
- 优点:这样所有模型利用率拉满,在训练的时候用效果好。
- 缺点:推理的时候延迟很大 。
- Tensor parallelism(张量并行):
- 模型横向切分
- 所有GPU同时在一个Layer上工作,最后拼成结果。
- 就是利用了 BMM 的原理,把不同的头分出来,然后装到不同显卡里计算。
- 优点:延迟很低
- 缺点:每一层处理的结果都必须共享并求和(All-Reduce),才能进行下一层计算,所以受通信速度的影响(需要NVLink的高速网络进行数据通信)
特性 | Tensor Parallelism (TP, 张量并行) | Pipeline Parallelism (PP, 流水线并行) |
核心思想 | 层内并行 (Intra-layer Parallelism) | 层间并行 (Inter-layer Parallelism) |
切分方式 | 横向切分:把单层的权重矩阵(如 W_Q, W_K, W_V)“切碎” | 纵向切分:把多层(Layers)“切断”成不同的“阶段” (Stage) |
通信开销 | 极高且频繁。每计算完一层,GPU 间都需通信 (All-Reduce) | 低且不频繁。只在两个“阶段”的边界处通信 (Point-to-Point) |
带宽依赖 | 极高。必须使用 NVLink 这样的高速总线,基本限于单机 | 较低。可以使用 InfiniBand/Ethernet,可以跨服务器(节点) |
主要优点 | 低延迟。所有 GPU 同时计算,响应快。 | 高吞吐 (训练时)。可跨节点扩展,装下超大模型。 |
主要缺点 | 扩展性差。受限于单机 GPU 数量 (如 8 卡) | 延迟极高。串行计算,总延迟是所有阶段之和。 |
关键问题 | 通信是瓶颈。 | “流水线气泡” (Bubble):大量 GPU 处于空闲等待状态。 |
设备 | 最好是同一个host,多张显卡 | 可以是不同host |
- Sequence parallelism(序列并行):(最新方案,可输入超长tokens)
- 前面介绍的两种策略TP和PP,在每块GPU中都需要存储和处理完整序列长度(Full Sequence Length)的激活值(在训练反向传播时,模型必须在显存里保留所有中间计算结果(Attention layer, FFN layer的输出等),这就是激活值)。而激活值的显存占用量与序列长度 (输入的tokens长度)和批次大小 (一个GPU同时并行处理的独立样本数量)成正比。所以,当 很长时,激活值会比模型权重还大,成为新的显存瓶颈。导致就算TP和PP把权重分得再碎,激活值都有可能让显存爆。
- 解决方法:既然 很长,那把 也切了。
- 问题是,self-attention对于上下文有依赖,切开会破坏这种依赖。
- self-attention有依赖,但是FFM/MLP(前馈网络)的序列没有依赖,对每个token都是独立计算的。
- SP和TP需要一起用。
- FFN/MLP layer
- 输入:[S, B, H]
- 切分:在输入FFN前,先把输入切成8份。
- 每个GPU独立计算。
- Attention layer
- 将所有GPU的FFN结果拼回完整序列,并共享到所有GPU(All-Gather)。
- 使用TP策略。
- 通信(Reduce-Scatter):
- 所有GPU执行一次 Reduce-Scatter(求和-分散)。就是所有TP结果相加,然后做切分(第1步的切分成8份)。输入下一个FFN。

1.2.1. FFN
FFN 通常是一个非常简单的两层全连接神经网络 (MLP):


1.3. Quantization
FP32 → FP4 大幅减少模型参数量来做到加速。
FP32: -128~+127 (256)
FP4: -8~+7 (16)
操作步骤:


关键点:在推理时,模型会用 INT8 整数进行极快的矩阵乘法(INT8 计算比 FP32 快得多),只在最后需要输出时,才用 S 和 Z 把结果“反量化”回 FP32。
例子:

zero point是将量化值和原始值对齐的操作。

1.3.1. 量化的主要策略
1.3.1.1. Post-Trainging Quantization (PTQ - 训练后量化)
- 训练高精度模型后,冻结参数。
- 小批量样本推理,记录每一层的权重和激活值矩阵的最大和最小值。
- 根据量化值和记录的值计算S和Z。
- 所有权重从FP32转换为INT8,甚至INT4。
1.3.1.2. Quantization-aware training (QAT - 量化感知训练)
由于量化对精度的损失很大,所有需要QAT。
策略:在训练时就模拟量化。
- 前向传播 Forward pass
- 拿到FP32权重,量化为INT8,倒回FP32。
- 反向传播 Backward pass
- 计算梯度。(注意梯度回绕过round函数,因为它不可导)
- 使用梯度更新FP32权重
这样模型就会在训练中自己优化量化造成的误差。
注意细节:
S 和 Z 是针对谁设计的?
- Per-Tensor(逐张量)
- 就是整个权重只给一组S和Z。
- 缺点:这样如果权重中有异常值,导致原始值范围巨大 → S 巨大,导致其他值被压缩成0,精度崩塌。
- Per-Channel / Per-Group(逐通道 / 逐组)
- LLM里的标准做法。
- 对权重的每一行(或每一列)都独立计算一组S和Z。
- 比如:nxn的矩阵,会获得n组S和Z。
- 优点: 极大地隔离了异常值,精度保持得非常好。
- 缺点:如下面的矩阵,最后一行转换后值相等了,就会不可取分。

在LLM上量化会有巨大的损失(这里RTN是指Round-to-Nearest(四舍五入))

针对 LLM 的特殊挑战:激活值异常点 (Outliers)
LLM 的量化有一个大难题:
- 权重 (Weights) 很“乖”,是漂亮的正态分布(钟形曲线),很容易量化。
- 激活值 (Activations)(即 MHA 和 FFN 的中间输出)很“野”。它们 99.9% 的值都接近 0,但有几个极其巨大的“异常值”。
这些异常值会毁了 Per-Tensor 的量化。
解决方案 (如 LLM.int8() / SmoothQuant):
- 这是一种“混合精度”量化。
- 它在计算时,动态地检测出这些“异常值”所在的维度。
- 99.9% 的“正常”计算用 INT8 完成。
- 0.1% 的“异常”计算,切换回 FP16 来处理。
- 这样既保证了速度,又保证了精度。
而更高级的 GPTQ / AWQ / QLoRA (NF4) 等 4-bit 量化,则是在 PTQ 的基础上,增加了“智能调整”步骤:它们会在量化前,就“重构”权重矩阵,把量化误差的伤害降到最低。
策略:保留一部分全精度,如图loss降回原本的值。

问题:哪些行保留?哪些行量化?
- 看哪一行数值大就保留哪一行。→ 实验发现有26%要保留。
- 看X(取列的平均)乘这一行获得activation数值大(说明活跃)。(AWQ)
问题:这样权重里有的是FP32有的是INT8怎么办?
如果这一行activation大,那这一行 S 值乘2来凸显出这一行重要。(AWQ)
在数学约定中激活值是 ,但在工程约定中是 (为了方便批处理)




1.3.1.3. Activation-aware Weight Quantization (激活感知权重Z化 AWQ)
AWQ 是一种极快且高精度的训练后量化 (PTQ) 方法。它的核心洞察是:“我们不需要保护所有的权重,我们只需要保护那些与‘异常激活值’相乘的 1% 的‘显著权重’(Salient Weights) 就够了。”
原理:
这个 s 是一个缩放因子 (Scale)。这个等式看起来毫无意义,但 AWQ 的魔力在于:
1. 这个 s 是逐通道 (Per-Channel) 的。
2. 这个 s 是激活感知的。
AWQ的工作流程:
推理前执行一次:
- 搜索 (Search / Observe)
- 运用少量数据通过模型。
- 观察激活值X,识别出包含异常值的通道。
- 标记这些通道对应的权重为显著权重。
- 计算并缩放 (Scale & Apply)
- AWQ 为每一个权重通道(Channel) 计算一个最佳缩放因子 。
- 目标:找到一个 ,使得预缩放后的权重 在被四舍五入 (RTN) 时,误差最小。
- 量化与保存 (Quantize & Save)
- 将预缩放后的 矩阵,用最简单、最快的 RTN 量化为 INT4 整数 。
- 将这个 (INT4 矩阵) 和 s (FP16 向量) 保存下来。
推理时:
- 加载 INT4 权重 和 FP16 缩放 。
- 执行计算 。
- 这个 操作可以被 CUDA 内核高度优化(先反量化 ,再与 相乘),速度极快。
1.4. Flash Attention
vllm一般用的都是flash attention。
简单来说,Flash Attention 的核心贡献是:让注意力计算变得又快又省显存,从而使处理超长序列(如 128K 甚至更长的上下文)成为可能。
它的发明人 Tri Dao 的核心洞察是:标准注意力的瓶颈不在于计算(FLOPs),而在于显存的读写(Memory I/O)。
标准注意力的操作过程:

出现的问题是:GPU 的计算核心(SRAM,片上内存)速度极快,但容量很小;而 GPU 的显存(HBM)容量很大,但速度相对很慢。更糟糕的是,它必须在 HBM 中完整地创建(物化)那个 的 S 和 P 矩阵。当序列长度 N 很大时(比如 64K), 是一个天文数字,这会耗尽所有显存。
解决方法:
FlashAttention 采用两种技术,将所有计算步骤“融合”到一个 CUDA 内核(Kernel)中:
- 内核融合(Kernel Fusion)
FlashAttention把所有计算步骤都放到GPU里不需要传进传出。
- 分块/瓦片技术(Tiling)

注意基础概念:
CUDA概念:显卡的高带宽显存(HBM,速度慢容量大);高速片上内存(on-chip memory);这个内存中有静态RAM(SRAM,速度快容量小)。
FlashAttention 简单来说就是用了两层for循环:第一层循环Q;第二层循环K和V。
伪代码如下:
2. Reinforcement learning frameworks
TODO
资料
- 谷歌ML电子书:https://jax-ml.github.io/scaling-book/index:
- 英伟达博客:https://developer.nvidia.com/blog/mastering-llm-techniques-inference-optimization/
- Lilian网红博客:https://lilianweng.github.io/posts/2023-01-10-inference-optimization/ (long article with quantization, etc)
- 硬核ML博客:https://ralphmao.github.io/ML-software-system/
论文
- DeepSeek V3 Technical Report
- Mooncake: KV cache
- DistServe: disaggregated serving