推理
整理各种面试中常见的八股问题,涵盖 Python 基础、PyTorch 基础、算法与数据结构等内容
推理
技术链路
-
Profiling 系统
-
流程
请求 → tokenize → prefill(大矩阵) → decode(循环) → sampling/输出 | | | v v v TTFT相关 GPU算子/带宽 TPOT/尾延迟 \______________ Profiling ______________/ nsys(系统级) + ncu(kernel级) -
基础
- torch.profiler:定位算子、shape、trace 的起点
- Nsight Systems User Guide:定位 CPU→GPU 提交、Memcpy、并发,判断 “是不是 host 在拖后腿”
- Triton Inference Server Quickstart:最标准的在线推理 “容器化基线”
-
高级
- GenAI-Perf:直接给出 TTFT / TPOT /token throughput 等 LLM 关键指标,适合做压测回归
- Nsight Compute Profiling Guide:下钻到 kernel 级别,知道 SM、Memory、Tensor Core 谁在摆烂
- PyTorch “profiling torch.compile performance”:专门用来抓 graph break、编译收益与损耗
-
进阶
- MLPerf Inference(Datacenter):最权威的 “别人怎么测、你也怎么测” 的基准入口
- MLPerf Inference v5.0 LLM 任务解读:理解低延迟 LLM benchmark 的新口径与趋势
- GenAI-Perf analyze/sweep:把 “单点测量” 升级为 “参数扫描 + 自动报告”
-
验收标准
- 能同时报告:QPS、TTFT、TPOT、token/s、P50/P95(至少 5 个指标)
- 能用 nsys 说明:瓶颈在 host、PCIe/NVLink、kernel、mem 哪一层
- 能用 ncu 说清:关键 kernel 的 memory bound vs compute bound
- 能写出一份 “一页纸” 性能报告模板
- 能给出优化优先级排序(不是 “我觉得”,是 “证据链”)
-
-
Runtime 运行时
-
流程
用户请求流 ↓ [Scheduler/Batcher] —— 决定并发与排队策略 ↓ [KV Cache Manager] —— 决定显存占用/碎片/复用 ↓ [Kernel Backend] —— FlashAttention/FlashInfer/TRT 等决定单步效率 ↓ 输出指标:TTFT/TPOT/吞吐/稳定性 -
基础
- vLLM / PagedAttention:把 KV cache 当 “虚拟内存分页” 来管,显著降低碎片与浪费
- vLLM repo:连续 batching、paged KV、speculative、chunked prefill 等实战特性全集
- vLLM 官方博客(PagedAttention 入门):用最少背景理解 “为什么吞吐能起来”
-
高级
- SGLang:前端语言 + 运行时,靠 RadixAttention(KV 复用) 和 cFSM(结构化输出加速) 提升吞吐
- SGLang repo:把 “复杂 agent / 多次生成 / JSON 输出” 从工程灾难变成可控系统
- SGLang 文档站:把 runtime 能力、部署方式、特性讲清楚
-
进阶
- TensorRT-LLM:NVIDIA 官方 “重装机甲”,含 paged KV、inflight batching、量化、speculative 等
- TensorRT-LLM 文档:工程落地导向(部署、serve、API)
- MLC LLM + microserving:把 prefill-decode 解耦等 “跨引擎编排” 做成可编程 API
-
验收标准
- 能用同一模型在 vLLM 与 SGLang 跑出可对比的 TTFT/TPOT
- 能解释:continuous batching 与传统 batching 的差异与收益点
- 能说清楚:KV cache 的生命周期、碎片问题、以及框架如何缓解(PagedAttention/RadixAttention)
- 能把推理链路拆成:tokenize→prefill→decode→sampling→postprocess(并标出每段耗时)
- 能给出 “选型建议”:低延迟、长上下文、多并发、结构化输出,各用哪个栈更合理
-
-
Attention & KV Cache
-
流程
每步 decode: token → Q 历史 → K,V (KV cache 读取) ←—— 真正的大头:带宽/布局/碎片 ↓ Attention(Q,K,V) (FlashAttention-3 / FlashInfer 等优化这里) ↓ 写回新的 K,V 到 KV cache -
基础
- PagedAttention(vLLM):KV cache 管理的系统化范式
- FlashAttention-3:在 Hopper 上把 attention 利用率拉高,主打 “又快又准”
-
高级
- FlashInfer:可定制 attention engine + 调度,面向 serving 的 “可组合格式 / 异构 KV 存储”
- FlashInfer-Bench:用真实 trace 把 “AI 生成 kernel→基准→替换上线” 做成闭环
- FlashInfer 官方文章(bench 介绍):理解为什么基准要贴近真实 serving trace
-
进阶
- KIVI(2-bit KV cache 量化):把 KV cache 的 key/value 分别按更合理粒度量化,释放显存换吞吐
- Kitty(2-bit KV cache,动态精度提升):进一步追求 “2-bit 也要稳”
- DeepGEMM(FP8 GEMM kernels):当你需要更底层的 GEMM 能力(尤其 Hopper / 新架构)。同时,需要优化通讯能力(参考 DeepEP)
-
验收标准
- 能解释 attention 推理时的主要数据流:Q/K/V、KV cache、softmax、写回
- 能在长上下文场景下,复现实测:FlashAttention/FlashInfer 带来的收益(至少一个指标提升)
- 能用 “带宽 / 算力” 两句话说明:为什么 decode 往往更 memory-bound
- 能给出 KV cache 的显存占用公式,并据此估算 batch 上限
- 能提出 2 个 “KV cache 相关” 的优化动作,并说明副作用(精度 / 延迟 / 工程复杂度)
-
-
Quantization
-
流程
模型(权重/激活/KV) ↓ 选择目标:省显存?省带宽?提吞吐? [W8A8: SmoothQuant] —— 更通用、工程友好 [INT4 weight-only: AWQ/GPTQ] —— 更省显存/带宽,但看kernel与batch [KV Quant: KIVI] —— 长上下文/大并发时更“对症” ↓ 上线前必须:质量/稳定性 + 性能回归(TTFT/TPOT) -
基础
- SmoothQuant(W8A8):把 activation outlier 难题 “搬家” 到 weights,工程可落地
- GPTQ:经典 PTQ weight-only(3/4bit)路线,精度与速度的常用起点
- AWQ:用 activation 分布找 “关键权重通道”,4-bit 更稳更硬件友好
-
高级
- TensorRT-LLM 的量化能力概览:把 FP8/INT4/AWQ/SmoothQuant 等做成可用工具链
- Marlin(FP16×INT4 matmul):让 INT4 真正 “吃满 4x 理论收益” 的核武器之一
- MARLIN 实现:工程上理解为什么 “batch=1 很难快,但 batch=16~32 能接近理想”
-
进阶
- KIVI /Kitty(KV cache 量化):当你的瓶颈是 KV cache 而不是 weights 时,别只盯 weight-only
- vLLM 的多种量化接入(GPTQ/AWQ/FP8/INT8 等):关注 “能不能稳定跑 + 能不能服务化”
- Nsight Compute 指标体系:量化后别只看 token/s,要看 memory/load/TC utilization 怎么变
-
验收标准
- 能区分并选择:W8A8 vs weight-only INT4(场景、代价、收益)
- 能在同模型上跑通:FP16 baseline 与 INT4(至少一种)并输出精度对比
- 能解释:为什么有时 “更低 bit 反而更慢”(kernel/packing/ 带宽 / 并行度)
- 能给出 “量化失败排查清单”(数值爆炸、输出退化、吞吐无提升)
- 能写出一个可复用的 “量化评测脚本”(吞吐 + 延迟 + 简单质量指标)
-
-
Decode
-
Speculative 的关键不是 “猜”,而是 “猜一串、验证一串”:Speculative Sampling 给了经典无偏加速框架;Medusa 用多头直接预测多 token;EAGLE-2 用动态 draft tree 更激进;Block Verification 在验证侧继续抠出 5–8% 的稳定增益
-
流程
Target模型(慢但准) : 负责验证 Draft/Heads(快但糙) : 负责批量提案 循环: Draft 生成 token1..k → Target 一次性验证 → 接受前缀 → 继续 | | v v 提案越准/越快 验证越“成块”越省(Block Verification) -
基础
- Speculative Sampling:经典 speculative decoding,2–2.5× 解码加速的起点
- Medusa:不用外部 draft model,通过多 decoding heads 预测多 token,再并行验证
- Medusa repo:快速复现 “多头解码” 的工程入口
-
高级
- EAGLE-2:动态 draft tree,靠校准的置信度更激进地产生可接受 token
- Block Verification:把 token-level 验证升级为 block-level 联合验证,稳定榨出额外速度
- vLLM / TensorRT-LLM 对 speculative 的支持:关注 “能不能在 serving 上稳定收益”
-
进阶
- “Decoding Speculative Decoding” 系统化研究:当你要在产线上挑 draft 模型时,这类研究更值钱
- SGLang 的结构化输出加速(cFSM):很多场景不是 “生成文本”,而是 “生成可解析结构”
- GenAI-Perf:把 speculative 的收益拆成 TTFT/TPOT/acceptance 等可对比指标
-
验收标准
- 能解释 speculative 的正确性保证(分布不变)与实现要点
- 能在同模型上跑出:baseline vs speculative 的 TPOT 改善,并说明 TTFT 变化
- 能给出 “什么时候 speculative 不赚” 的判断(任务、温度、draft 质量、batch)
- 能输出一个 “acceptance length/ratio” 的统计图或表
- 能提出 1 个 “与量化 / 批处理 / 长上下文耦合” 的风险点,并给规避策略
-
-
系统架构
-
流程
(传统聚合) 请求 → [同一组GPU] prefill + decode 交织 → 互扰、尾延迟上天 (解耦 / 混合) 请求 → Prefill GPU池(擅长大矩阵) → KV/状态转移 → Decode GPU池(擅长循环出token) ↑ 调度器按 SLO 做 goodput 优化(TaiChi 思路) -
基础
- DistServe(OSDI’24):系统化论证并实现 prefill/decode 解耦,围绕 goodput 做调度
- Splitwise(ISCA):用 phase splitting 设计同 / 异构集群,优化吞吐 / 成本 / 功耗
- “Disaggregated Inference: 18 Months Later” 总结:了解最近为何 “突然变默认配置”
-
高级
- TaiChi(2025):把 prefill-decode 的 “聚合 / 解耦” 统一起来,面向不同 SLO 组合做最优 goodput
- DistServe 公开视频、课件:适合把论文落到 “怎么配资源、怎么调度” 的细节
- MLC microserving:把解耦、跨引擎编排做成 “几行 Python 可表达”
-
进阶
- 从 “goodput” 视角重读 DistServe/TaiChi:把系统目标从 QPS 升级为 “满足 SLO 的有效吞吐”
- SGLang / vLLM 的 kernel & runtime 生态:关注 “解耦之后的 KV、batch、graph、kernel” 如何协同
- 用真实 trace 做仿真 / 回放(参考 Splitwise/FlashInfer-Bench,Inference Perf,VIDUR,MorphServe,Mooncake):你的系统最终要对抗真实分布
-
验收标准
- 能清楚定义并计算:TTFT SLO、TPOT SLO、goodput(满足 SLO 的吞吐)
- 能解释 prefill/decode 互扰来自哪里(batch / 资源耦合 / 调度)
- 能给出一个简化的资源配置方案:prefill-heavy vs decode-heavy 的配比(并解释依据)
- 能复现一个 “小规模解耦” 实验(哪怕 2 机 / 2 卡),并报告 goodput 变化
- 能列出 3 个系统风险点(KV 迁移、网络、尾延迟、队列震荡)及缓解手段
-
-
Benchmark & 回归
-
把 GenAI-Perf(TTFT/TPOT/ 吞吐) 与 MLPerf Inference 这类权威口径纳入回归;MLCommons 也在持续迭代 Inference 结果与规则
-
流程
改动(量化/内核/调度/解耦) ↓ 固定压测配置(模型/上下文/并发/温度) ↓ GenAI-Perf 输出 TTFT/TPOT/P50/P95/token吞吐 ↓ 对齐/参考 MLPerf 规则与结果(能比才有意义) ↓ 上线门禁:回退就拦截 -
基础
- GenAI-Perf:LLM serving 指标一站式输出(TTFT/TPOT/token throughput)
- MLPerf Inference(Datacenter)入口:了解官方 workload / 规则 / 提交节奏
- Triton perf analyzer quick start:把 “压测” 纳入日常工程工具链
-
高级
- MLPerf Inference v5.0 解读:理解 LLM serving 的基准为何要围绕低延迟与真实约束
- Nsight Systems/Compute:把 regression 失败定位到 “host vs device vs kernel”
- SGLang release notes:跟进框架演进,避免你在 “旧问题” 上卷生卷死
-
进阶
- FlashInfer-Bench(参考 KernelBench,MLPerf Inference Rules,CUDA Runtime):把 “真实 trace + leaderboards + 动态替换” 作为长期能力建设
- TensorRT-LLM(参考 Orca,vAttention,CUDA Graphs):当你要追求极限性能 / 稳定部署时,参考其端到端能力组合
- FlashAttention-3/FlashInfer(参考 POD-Attention,KASCADE,SpecInfer):把 kernel 进步与系统指标绑定,形成 “可解释的性能提升”
-
验收标准
- 有一套固定的 benchmark 配置(模型、batch、context、并发、硬件)
- 每次改动都能输出同一张 “指标对比表”(至少 TTFT/TPOT/token/s)
- 能把 1 次性能回退定位到具体 commit / 配置 / 驱动变化
- 能解释 “为什么 MLPerf/GenAI-Perf 的指标口径与你线上一致 / 不一致”
- 能写出 “上线门禁”:什么指标退化会阻止合并
-
-
优化路线
你现在最痛的是哪一个? ├─ TTFT 很大(第一口慢) │ ├─ prompt 很长/上下文很长 → 优先:Prefill 优化/Chunked Prefill/更快的 GEMM/更强 prefill GPU │ ├─ CPU/调度慢 → 优先:nsys 找 host bottleneck;换更成熟 runtime(vLLM/TRT-LLM) │ └─ 频繁重复前缀 → 优先:prefix/KV 复用(运行时能力) │ ├─ TPOT 很大(续杯慢) │ ├─ decode 明显 memory-bound → 优先:Attention/KV(FlashAttention-3/FlashInfer)+ KV cache 管理 │ ├─ token-by-token 串行顶死 → 优先:Speculative / Medusa / EAGLE-2 + Block Verification │ └─ batch 太小吃不到量化收益 → 优先:continuous batching + 合理并发;必要时上 Marlin 类 INT4 kernel │ ├─ 显存爆了(batch 上不去/长上下文撑不住) │ ├─ 先看 KV cache 占用 → 优先:PagedAttention + KV Quant(KIVI) │ └─ 再看权重占用 → INT4 weight-only(AWQ/GPTQ) 或 W8A8(SmoothQuant) │ └─ 尾延迟/P95 爆炸(“最难伺候那 5%”) ├─ prefill/decode 互扰明显 → 直接考虑解耦(DistServe/Splitwise 思路) └─ SLO 既要 TTFT 又要 TPOT → TaiChi 类“聚合+解耦统一”路线
常见指标
| 简称 | 全称 | 含义 | 优化思路 |
|---|---|---|---|
| TTFT | Time To First Token | 从请求发起到第一个 token 输出的时延用户感知 “快不快” | 1. 降低 prefill 延迟 2. 减少排队调度延迟 3. 启用动态批处理、优先短请求 4. 模型量化、KV cache 预分配 5. 使用 PagedAttention 减少碎片 |
| TPOT | Time Per Output Token | 生成阶段平均每个输出 token 的耗时决定 “打字流畅度” | 1. 提升 decode 吞吐 2. 增大 batch、提高 GPU 利用率 3. 使用 Tensor Core、FP8/INT4 量化 4. 减少 KV cache 拷贝与访存 5. 连续批处理 Continuous Batching |
| ITL | Inter-Token Latency | 连续两个输出 token 之间的间隔基本等价 TPOT | 同 TPOT |
| E2EL | End-to-End Latency | 从请求开始到最后一个 token 输出完成的总耗时 | 1. 优化 TTFT + TPOT2. 限制 max tokens3. 减少超长序列拖慢整体 |
| RPS | Request Per Second | 每秒处理的请求数 | 1. 提升引擎并发能力 2. 动态批、优先级队列 3. 多实例 / 多卡部署 |
| QPS | Query Per Second | 每秒查询数(常与 RPS 混用) | 同 RPS |
| TPS | Token Per Second | 每秒模型输出的总 token 数(引擎核心吞吐) | 1. 提高 GPU 算力利用率 2. 增大有效 batch size3. 优化调度、减少空跑 |
| Goodput | Good Put | 符合时延 / 正确性要求的有效吞吐≠ 总吞吐(排除超时、错误、质量差) | 1. 降低 P99 尾延迟 2. 避免 OOM、重试、超时 3. 合理流控,不超负载 |
| SLO | Service Level Objective | 服务等级目标(性能 / 可用性承诺) | 按目标优化:如 P95 TTFT < 200ms、可用性 99.9% |
| P50 | 50th Percentile | 中位数延迟:50% 请求 ≤ 该值代表 “正常体验” | 优化平均路径即可 |
| P90 | 90th Percentile | 90% 请求 ≤ 该值 | 优化常见慢路径、减少小波动 |
| P95 | 95th Percentile | 95% 请求 ≤ 该值线上核心体验指标 | 优化批处理策略、避免请求阻塞 |
| P99 | 99th Percentile | 99% 请求 ≤ 该值代表尾延迟(Tail Latency) | 1. 解决超长序列、异常请求 2. 防抖动、防内存碎片 3. 队列隔离、超时控制 4. 预分配、pipeline 流水化 |
FlashAttention
- 介绍一下 FlashAttention,它主要优化了什么?
- FlashAttention 是 2022 年斯坦福提出的 IO 感知精确注意力算法,核心是通过分块计算、在线 Softmax、反向重计算,把标准 Attention 的显存复杂度从 O (N²) 降到 O (N)、速度提升 2–4 倍,数学完全等价、不丢精度
- FlashAttention 的出发点是:标准 attention 的瓶颈不是计算,而是 “attention matrix(n×n)” 的巨大 IO 开销,并且需要存储 、softmax 输出等中间结果,导致显存爆炸和带宽瓶颈
- FlashAttention 的核心优化点是:
- 按 tile(块)分块计算 ,在 SRAM 中完成 partial max、partial sum 和累积输出,最终直接得到结果,而不需要显式计算并写回 n×n attention matrix
- 在线 softmax(online softmax):在计算过程中动态维护 max 和 sum,避免了对整个 attention matrix 的存储和多次读写
- 反向传播时重计算 和 softmax 输出,节省了反向传播的显存需求
- FlashAttention-V1 的计算流程?反向传播的流程?访存量和通信量?需要写回 HBM 的有哪些内容?
- 前向传播:
- 按 tile 分块计算 ,得到 partial attention scores
- 在 SRAM 中维护 partial max 和 partial sum,完成在线 softmax
- 直接乘 V 得到输出,不写回 attention matrix
- 反向传播:
- 重计算 和 softmax 输出
- 计算 dQ、dK、dV,写回 dQ、dK、dV 到 HBM
- 访存量:
- 前向传播:读 Q/K/V,写输出(不写 attention matrix)
- 反向传播:重计算 和 softmax 输出,读 Q/K/V,写 dQ/dK/dV
- 需要写回 HBM 的内容:
- 前向传播:输出(不写 attention matrix)
- 反向传播:dQ、dK、dV
- 前向传播:
- 在线 Softmax 的推导
- 在线 Softmax 的核心是维护 partial max 和 partial sum,避免了对整个 attention matrix 的存储和多次读写
- 设当前 tile 的 attention scores 为 S,之前的 partial max 为 M,partial sum 为
- 更新 partial max:
- 更新 partial sum:
- 这样在计算过程中就动态维护了 max 和 sum,最终得到的 softmax 输出是正确的,而不需要存储整个 attention matrix
- FlashAttention-V2 又做了什么改进?访存量和通信量?需要写回 HBM 的有哪些内容?
- 循环顺序调换:V1 外层 K/V、V2 外层 Q
- 输出只写回 HBM 1 次,消除 O (N) 重复读写
- 并行度更高、FLOP 利用率从 25–40% → 更高
- 访存量:
- 前向传播:读 Q/K/V,写输出(不写 attention matrix)
- 反向传播:重计算 和 softmax 输出,读 Q/K/V,写 dQ/dK/dV
- 需要写回 HBM 的内容:
- 前向传播:输出(不写 attention matrix)
- 反向传播:dQ、dK、dV
- 了解 FlashAttention-V3 吗?
- 了解 FlashAttention-V4 吗?
- 为什么 decode 是 memory-bound?
- 在自回归推理(decode)阶段,每一步只生成 1 个 token,此时计算的特点是:
- Q 只有一个(当前 token)
- K/V 是历史所有 token(长度 t)
- attention 计算变成
- 这里 FLOPs 很少(O (t・d)),但问题在于:
- 每一步都要把整个 KV cache 从 HBM 读出来
- 计算量小,但访存量大
- GPU 的计算单元是没吃满的,瓶颈变成了 HBM 带宽 → 典型 memory-bound
- KV cache 为什么越来越大?
- KV cache 的大小是 layers × heads × seq_len × head_dim × 2(K + V)
- 随着序列长度增长(长上下文)、模型层数增加、head 数增加,KV cache 线性甚至接近指数级膨胀(在多 batch 时)
- 而 decode 是逐 token 增长的,cache 只会 “越来越大”,不会释放,这也是推理显存的核心压力来源
- IO-aware 是什么意思?具体怎么减少 IO?为什么标准 attention 慢?
- IO-aware 的核心意思是算法设计以 “减少 HBM ↔ SRAM 数据搬运” 为目标,而不是只看 FLOPs
- 标准 attention 的问题不在于计算,而在 IO:
- 先算 → 写回 HBM(n×n)
- 再读回来做 softmax
- 再写回
- 再读出来乘 V
- attention matrix()被反复读写,这是灾难性的 IO 开销
- 所以标准 attention 慢,本质是不是算不动,而是 “搬数据太多”
- FlashAttention 为什么不需要存 attention matrix?
- FlashAttention 的关键思想是按 tile(块)分块计算 + 在线 softmax(online softmax)
- 也就是说不一次性算完整 QK^T,而是分块算一部分(block of K/V),在 SRAM 中完成 partial max、partial sum 和累积输出
- 最终直接得到结果,而不需要显式 materialize n×n attention matrix
- tile size 怎么选?
- tile 的大小取决于:
- SRAM(shared memory /register)容量
- head_dim
- 是否能让数据完全驻留在片上
- 原则是:尽量让一个 tile 的 Q/K/V + 中间变量都放进 SRAM
- 通常会选一个让 occupancy 和带宽利用率最优的 block size,而不是纯理论最优
- tile 的大小取决于:
- SRAM / HBM 访问次数是多少?
- 标准 attention:
- Q/K/V:读一次
- attention matrix:写 + 读 + 写 + 读(多次)→ IO 是
- FlashAttention:
- Q:读一次
- K/V:按 tile 逐块读
- 不写 attention matrix → IO 变成 ,这就是数量级优化
- 标准 attention:
- 为什么是 IO-aware?
- 因为它优化的不是 FLOPs,而是 HBM 访问次数、数据复用(SRAM 内循环使用)
- 本质上是把 attention 从 compute + huge IO 变成 compute + minimal IO
- FlashAttention 什么时候不明显快?FlashAttention 为什么在短序列不明显?
- 短序列(比如 n < 512)时,attention matrix 本来就不大
- IO 不是瓶颈
- kernel launch / 调度开销占比更高
- 此时 FlashAttention 的优势(减少 IO)体现不出来,甚至可能略慢
- 长序列 → IO 成为瓶颈 → FlashAttention 很有用
- 短序列 → compute /launch 成为瓶颈 → 提升有限
- 短序列(比如 n < 512)时,attention matrix 本来就不大
- FlashAttention v2 相较 v1 的改进点
- 你的框架里用了 FlashAttention 吗?显存占用和 MFU 的改进如何?
- 我使用了类似 FlashAttention 或 xFormers fused kernel
- 显存:attention 不再需要 n² 中间矩阵,激活显存显著下降(尤其长序列)
- 吞吐:因为减少 IO + kernel fusion,step time 明显下降
- MFU:从 13.4% 提升到 34%(取决于模型和序列长度)
- FlashAttention + TP 怎么结合?
- FlashAttention 本质是单卡 kernel 优化,而 TP(Tensor Parallel)是跨卡切分
- 两者结合方式是:
- 每个 TP shard 上独立做 FlashAttention
- Q/K/V 已经按 head 或 hidden dim 切分
- 关键点在于:
- head parallel(最常见)
- 每张卡负责一部分 heads
- FlashAttention 直接在本地执行
- 不需要额外通信
- sequence parallel(更复杂)
- 需要跨卡 gather K/V
- 会引入通信 → 抵消一部分优化
- head parallel(最常见)
- 工程上最佳实践是 TP 按 head 切分 + 每卡用 FlashAttention
- 这样无额外通信,而 IO 优化完全保留
Sparse Attention
-
介绍一下稀疏注意力?有哪些类型?稀疏注意力主要用在什么场景?
-
BigBird 的稀疏注意力结构?
- 全局注意力:选定 g 个特殊 token(如 CLS、问题句),双向全连接:全局 token 关注所有 token,所有 token 也关注全局 token
- 窗口注意力:每个 token 仅关注左右各 w/2 个邻域 token(固定窗口),类似 CNN 感受野
- 随机注意力:每个 token 随机选择 r 个其他 token 建立连接(全局 + 窗口外的补充)
-
Longformer 的稀疏注意力结构?
- 窗口注意力:每个 token 只关注左右各 w/2 个相邻 token
- Global Attention(全局注意力)
-
Performer
-
Linformer
-
稀疏注意力对 KV Cache、推理速度的影响?
- 稀疏注意力几乎不减少 KV Cache 显存占用,甚至可能略微增加
- 不管你注意力是不是稀疏:
- 每一层、每个 token 的 K、V 依然要完整保存
- 因为下一层、下一个 token 生成时还会用到
- 稀疏只是 “不算某些 Q-K 对”,不是 “不存某些 KV”
- KV Cache 大小 = O (n × d × layers),和是否稀疏完全无关
- 预填充阶段(Prefill)速度明显变快
- 解码生成阶段(Decode)几乎没加速,甚至变慢
- 稀疏索引、不规则访存、掩码判断 → Kernel 开销变大 → 实际速度常常比普通注意力还慢一点
-
稀疏注意力和 FlashAttention 能不能一起用?
- FlashAttention-2 已原生支持块稀疏(Block-Sparse):
- 把注意力矩阵按块划分(如 128×128)
- 按稀疏模式(窗口 / 全局 / 随机)标记哪些块需要计算、哪些跳过
- 内核只加载 / 计算非零块,跳过零块,保持分块重计算、流水、数值稳定
- FlashAttention-2 已原生支持块稀疏(Block-Sparse):
-
为什么现在主流大模型不怎么用纯稀疏注意力?
- 表达能力与长程依赖丢失
- 训练不稳定、难收敛、难扩展
- 训练 - 推理不一致:训练用稠密 + 稀疏混合,推理纯稀疏
- 硬件效率 “理论美、实际差”:不规则内存访问,KV Cache 仍旧需要计算
-
介绍一下 Sliding Window Attention?
-
介绍一下 Linear Attention?Linear Attention 的原理和代码实现?
-
Linear Attention 的核心是把 改写为:
-
其中 是 feature map,使 attention 可以重排为:,从而把复杂度从 变成
-
简单实现
def linear_attention(q, k, v, eps=1e-6): q = torch.relu(q) + eps k = torch.relu(k) + eps kv = k.transpose(-2, -1) @ v # [d, d] z = 1 / (q @ k.sum(dim=-2, keepdim=True).transpose(-2, -1) + eps) out = (q @ kv) * z return out -
softmax 为什么不能 kernelize?
- 的问题在于 不是一个有限维的核函数展开(没有低维 使得 精确成立)
- 所以 Linear Attention 只能做近似
-
feature map 怎么选?
- feature map 的选择(如 ReLU、ELU+1)需要满足非负(避免 cancellation)、数值稳定、近似 exp kernel
-
数值稳定性怎么保证?
- 稳定性不足主要来自于:分母可能接近 0、累积误差(尤其长序列)
- 常见解决方案包括加 eps、normalization、分块计算等
-
-
Linear Attention 为什么能做到 ?代价是什么?
- 关键在于把 → ,其中 是一个 “全局 summary”,只需要 累加
- 代价主要有两个
- 第一,表达能力下降(softmax 的 sharp attention 没了,核函数抹平了 Softmax 的 “聚焦” 与 “对比”,导致注意力稀释、非线性表达受限,关键信息丢失)
- 第二,数值稳定性变差,尤其长序列(隐式欧拉离散化引入累积误差,更新矩阵低秩导致刚性系统不稳,长序列与大学习率下易发散)
-
为什么 Linear Attention 没取代 Softmax?为什么大模型最终还是用 softmax attention?
- 本质原因是:效果不够好
- softmax attention 的优势在于:
- 能做 “稀疏选择”(某些 token 权重大,其他接近 0)
- 表达能力强
- 而 linear attention 更像是 “加权平均”,区分能力弱
- 在大模型 scaling 下,这种差距会被放大,所以最终主流 LLM 还是回到 softmax(配合 FlashAttention 做工程优化)
KV Cache 优化
-
KV cache 是什么?KV cache 为什么只在推理用?
- KV cache 是在自回归推理时,把历史 token 的 Key 和 Value 缓存下来
- 这样生成第 t 个 token 时,不用重新计算前面 1~t-1 的 K/V,只需要算当前 token 的 Q,然后和缓存做 attention
- 它只在推理用,是因为:
- 训练时是 full sequence 并行(teacher forcing),所有 token 一次性算完,不需要 cache
- cache 会增加显存,而且训练不需要重复利用历史
- KV Cache 本质是空间换时间,用显存存历史 Key/Value,避免重复计算
-
为什么 Multi-Query attention 能优化 KV cache?
- Multi-Query Attention(MQA)优化 KV cache 的核心是多个 head 共享同一份 K/V,只保留不同的 Q
- 这样 KV cache 的大小从 num_heads × seq_len × head_dim 变成 1 × seq_len × head_dim,显存直接下降一个数量级
-
GQA 与 MQA 的区别、显存对比、适用场景?
- MQA 适用
- 极致低显存 / 高吞吐:移动端、边缘设备、超大规模批处理
- 延迟敏感、短文本为主:对话机器人、简单生成
- 代表:PaLM、GPT-4 推理优化、早期 T5
- GQA 适用(当前大模型主流)
- 长上下文 + 高效推理:LLaMA 2/3、Qwen、GLM、Falcon 标配
- 平衡:显存省 + 精度几乎不掉
- 推荐:7B/13B 用 GQA-4,70B 用 GQA-8
- MQA 适用
-
KV Cache 需要占用多少显存?公式计算?
- 2:同时存储 Key 与 Value 两份矩阵
- (num_layers):Transformer 模型总层数
- B (batch_size):批大小 / 并发请求数
- S (seq_len):上下文序列长度(Prompt + 已生成 Token 总数)
- (num_kv_heads):KV 头数
- 标准 MHA:
- GQA/MQA:(如 LLaMA 3 70B: )
- (head_dim):单个头维度 ()
- (dtype_bytes):精度字节数
- FP16/BF16: 2 Bytes
- INT8/FP8: 1 Byte
- FP32: 4 Bytes
-
KV Cache 导致了哪些需要优化的问题?相应地有哪些优化手段?
- 显存占用过大:KV Cache 随着序列长度、层数、batch 大小线性增长;相应地,可以通过 GQA/MQA、KV Cache 量化、Offloading 等方式优化
- 内存带宽瓶颈:KV Cache 体积大,推理时要反复读写缓存;相应优化手段如 PagedAttention 减少内存拷贝和碎片、连续内存排布 / 紧凑布局来提高缓存命中率、FlashAttention 减少 HBM 读写,同时不写回完整的 KV
- 长文本下性能急剧衰减:随着序列长度越大,生成 token 延迟越高,可以采用 SlidingWindowAttention、KV Cache 稀疏化、Chunked Attention 等方式优化
- 多并发调度低效(Batch 乱序、碎片):不同请求序列长度不同,会导致内存碎片严重,而且在动态 batch 下无法高效复用与扩容;相应地,可以通过 Continuous Batching、PagedAttention、Prefix Cache 等方式缓解
- 质量问题(KV Cache 带来的精度下降):选择式刷新 KV、动态压缩不重要的 KV
-
KV Cache 为什么不能跨请求共享?什么情况下可以共享?
- KV Cache 存储的是对每一层、每个位置的 token,计算出的 Key & Value,这两个值完全由输入 token 决定,不同输入就不同 KV
- 当两个请求的前缀 token 序列完全相同时,这 n 个位置的 KV 就可以完全复用、共享 —— 也即 Prefix Cache
- 在 PagedAttention 中,相同内容的块直接引用计数共享,不重复存储
-
为什么 KV Cache 量化比权重量化更容易掉点?
- 对权重量化是静态的,训练时就固定,可以通过量化感知训练(QAT)、微调 去适应低精度,即使量化误差大,模型也能学到 “容错表示”;而且权重全局共享,误差被大量 token 平均抵消
- 对 KV Cache 量化则是对推理时实时计算的激活值进行量化,误差会直接进入注意力 softmax,噪声会随生成一步步累积放大,而且没法修正,所以更容易掉点
-
什么是 PagedAttention?
- vllm 中的技术,把 KV Cache 像操作系统 “虚拟内存分页” 一样切成固定大小块,用块表映射、非连续存储、支持跨请求前缀共享,彻底解决显存碎片与浪费
- 实现细节
- 切块:把每个序列的 KV 分成固定大小 block(如 16 token)
- 块表(Block Table):每个请求维护一张表,记录逻辑 token → 物理 block 映射
- 非连续存储:KV 不必在显存里连续,允许碎片化但无浪费
- 前缀共享:多请求相同前缀共用物理 block(引用计数)
- 可换入换出:block 可在 GPU/CPU 间换入换出,支持超长上下文
-
什么是 RadixAttention?
- SGLang 中的技术,是一种 KV Cache 全局索引结构,用基数树(Radix Tree / 压缩前缀树)全局组织所有请求的 KV Cache,自动发现、共享、复用所有公共前缀,比 PagedAttention 前缀共享更彻底、更自动化
- 实现细节
- 所有请求序列看作 “字符串”,插入一棵共享基数树
- 相同路径(前缀)共用同一组 KV block
- 新请求进来:先在树里匹配最长前缀 → 直接复用 KV → 只计算新增后缀
- 带 LRU 驱逐、引用计数、跨 GPU 共享
-
什么是 Continuous Batching?
- 迭代级动态批调度 —— 请求随时进、随时出,GPU 永远满载,彻底解决静态批 “等最慢请求” 的浪费(也叫 Inflight Batching / Iteration Batching)
- 传统静态批:一批请求必须全部生成完才释放资源
- Continuous Batching:
- 每一步(iteration)只生成一个 token
- 某请求完成 → 立即踢出、新请求立即补上
- 批大小动态浮动、GPU 利用率接近 100%
- 配合 PagedAttention 内存管理,吞吐量提升 3–5 倍
-
什么是 Chunked Prefill?
- 把长 Prompt 的 Prefill 切成小 chunk 分步执行,避免长 Prompt 独占 GPU、阻塞解码、导致 OOM,并与 Decode 交错调度
- LLM 推理分为两个阶段,Prefill 计算 Prompt,其计算密集耗时较长,而 Decode 逐个生成 token,其访存密集 GPU 利用率低
- 超长 Prompt 一次性 Prefill 会 “霸占” GPU,导致正在 Decode 的请求卡住
- 因此可以把 Prompt 切成 chunk(如 512/1024 token)、逐块 Prefill、累积 KV Cache,调度器把 Prefill chunk 与 Decode 请求交错执行( Stall-Free Batching)
- 这样可以防止 OOM,降低首 Token 延迟(TTFT),提升吞吐
-
什么是 Speculative Decoding(投机解码)?
- 小模型草拟 + 大模型并行验证 —— 用廉价小模型快速猜多个 token,大模型一次验证通过就批量接受,大幅减少大模型前向次数
- 验证能成立的关键是小模型(Draft)和大模型(Target)基于同一套 Token 词典、同一类概率计算规则(如 Softmax 输出 Token 的条件概率),且二者的推理都是自回归式的(下一个 Token 的生成依赖前序所有 Token)
- 流程
- 小模型的作用:基于原始输入 ,快速生成 k 个候选 Token 序列 (即 “草拟”,贪心 / 采样生成,速度极快)
- 大模型的验证基础:不单独生成 Token,而是直接把「原始输入 + 小模型候选序列」拼接成完整序列 ,作为自身的输入做一次前向计算,一次性输出每个候选位置上的 Token 条件概率分布
- 接受规则:
- 逐 token 比对:一致则接受、直到第一个分歧点
- 接受部分直接输出;分歧点回退,大模型重生成
- 效果:平均每步生成 >1 token,速度提升 2–4 倍、输出分布不变(无损)
-
什么是 Prefix Cache / Prefix KV Cache?
- 跨请求复用公共前缀的 KV Cache—— 把系统提示、长文档、共享模板的 KV 缓存下来,后续请求直接复用,避免重复计算
- 缓存从开头连续 token 序列 的 KV,而新请求匹配最长公共前缀 → 直接加载缓存 KV,这样只需要计算后缀部分 → TTFT 大幅降低(常 2×+)
-
什么是 FlashDecoding?它和 FlashAttention 有什么区别?
- 长序列推理专用加速 —— 在 FlashAttention 基础上,对 KV 序列长度维度做并行拆分,让单 batch、长上下文也能打满 GPU 算力
- 原理
- 把长 KV 切成多个 chunk
- 并行用 FlashAttention 计算 Q 与每个 KV chunk 的注意力
- 记录每个块的 log-sum-exp(缩放因子)
- 最终合并所有块结果(reduction)
- 优势:长上下文(1k–128k)速度提升 4–8 倍,单 batch 也满卡
-
长文本下 KV Cache 稀疏化方法有哪些?
- 稀疏化:只保留 / 只计算对当前生成最关键的 KV,丢弃 / 压缩不重要部分
- 时间维度的稀疏化 —— 按 “重要性” 只保留部分 token 的 KV,丢弃其余
- Sliding Window Attention:只保留最近 N 个 token,完全丢失长程依赖
- StreamingLLM / Attention Sink:保留 初始 4–6 个 token(Sink)+ 最近窗口,丢弃中间,然而中间段落信息丢失,复杂推理仍掉点
- 通道 / 特征维度稀疏化 —— 对 KV 向量的维度(通道)做稀疏 / 剪枝
- MQA/GQA(分组查询注意力)
- MLA(Multi-Head Latent Attention):KV 投影到极低维隐空间,需要在模型训练时就支持
- 低秩与稀疏编码压缩:用更少参数近似表示 KV
- 量化 + 稀疏结合:先量化(FP8/FP4)减显存,再做 token/channel 稀疏
-
什么是 Attention Free Cache?
- 跳过完整的 Softmax 注意力计算,用更轻量的规则直接判断哪些 KV 重要、哪些可删
- 静态 AFC:滑动窗口、StreamingLLM、向量相似度 / 范数淘汰
- 动态 AFC:HashEvict / LSH 基(Attention Free 淘汰)
- 把 Q/K 向量哈希成短二进制码(SimHash)
- 用汉明距离近似 Q-K 相似度,直接淘汰汉明距离最大(最不相关)的 KV
-
什么是 pd 分离?什么是 AF 分离?
- pd 分离(Prefill-Decode)
- Prefill 阶段处理整个 prompt,计算密集,并行度较高
- Decode 阶段每次生成一个 token,内存带宽密集,需要反复读 KV Cache,算力闲置
- pd 分离把 Prefill 和 Decode 拆到不同硬件 / 集群
- Prefill 集群:强算力,只做 prompt 编码 + 生成 KV Cache
- Decode 集群:高带宽,只做逐 token 生成
- KV Cache 通过 RDMA/NVLink 高速迁移
- pd 分离主要解决同一 GPU 上 Prefill 与 Decode 资源争抢、互相干扰的问题,无法分别优化 TTFT(首 token)和 TPOT(逐 token 延迟)
- AF 分离(Attention-FFN)
- 把 Decode 阶段拆分为两块,把 Attention 和 FFN 分到不同硬件
- Attention 计算是状态密集型,依赖巨大且动态变化的 KV Cache,瓶颈主要是内存带宽、显存容量,负载不稳定且会随着上下文长度增长
- FFN 计算是与 KV Cache 无关的密集型计算,瓶颈主要是算力和批次大小,负载稳定
- AF 分离架构
- A 集群(Attention):存所有 KV Cache、做 QKV+Softmax
- F 集群(FFN):只跑两层线性 + 激活(占模型 80%+ 权重)
- 每一层:A → 通信 → F → 通信 → 下一层 A
- 为什么还需要 AF 分离?
- PD 只解决了 阶段间资源错配,但 Decode 内部依然严重浪费
- 通过 AF 分离,A 集群和 F 集群可以独立扩展
- A 集群:只加显存 / 带宽,应对 KV Cache 膨胀
- F 集群:只加算力 / 卡数,应对 FFN 计算量
- 同时,FFN 可以超批次进行并行,多个 A 实例的输出可以定向到同一个 F 实例,FFN 算力利用率拉满
- pd 分离(Prefill-Decode)
-
MTP 是什么?怎么应用?
- LLM 训练 + 推理加速技术,核心是一次前向,并行预测未来 N 个 token,不是只预测下 1 个
- 主干 Transformer 不变,加 N 个辅助预测头(共享底层,独立 Linear)
- 训练时:同时预测 ,多损失加权联合训练
- 推理时:用辅助头一次性生成 N 个候选 token,主头验证 / 接受 → 减少解码步数
- 训练:样本效率↑、长程依赖建模更强、收敛更快
- 推理:解码步数减少 N 倍 → 延迟 - 40%
70%、吞吐↑23× - 无损 / 微损精度,几乎无额外显存开销
-
MTP 是什么?它的基本原理?
-
DeepSeek 参照 Meta 的 MTP 设计,在实现上保留了序列推理的连接关系(causal chain)
-
整体架构
- Main Model:传统 decoder-only 主干网络,负责 next token 预测(第 0 个预测深度)
- MTP Module 1
D:D 个顺序串联的模块,分别负责预测第 1D 个后续 token(next next token、next³ token 等) - 共享机制:词表投影层(vocab_predict_head)全局共享,embedding 层在模块间共享参数
-
单个 MTP 模块结构
- Embedding Layer:接收输入 token 序列,生成 token embedding
- 双路 RMSNorm:
- 对前序模块的隐层输出做 RMSNorm 归一化
- 对当前位置的 token embedding 做 RMSNorm 归一化
- Concatenation + Linear Projection:拼接两路归一化结果,通过投影矩阵做线性变换,融合特征
- Transformer Block:独立的 Transformer 层,处理融合后的特征,提取序列上下文
- Output Head:共享的词表投影层 + Softmax,输出词表概率分布
- Cross-Entropy Loss:计算当前模块的预测损失
-
变量定义
- :输入序列总长度
- :预测深度( 对应 Main Model, 对应 MTP Module )
- :输入 token 的位置索引
- :隐层维度,:词表大小
-
第一步特征融合
- 输入:
- :第 层的隐层输出( 时为 Main Model 的隐层表征)
- :第 位置的 token embedding
- 处理:两路分别做 RMSNorm 归一化 → 拼接 → 投影矩阵 线性变换
- 输出:融合后的特征
- 输入:
-
第二步特征提取
- 输入:融合特征序列 (切片范围 ,保证 )
- 处理:第 个独立 Transformer 层 提取上下文特征
- 输出:第 预测深度的隐层表征
- :第 预测深度的输入 token 位置 需满足 ,因此有效输入范围为
-
第三步词表概率输出
- 输入:隐层表征
- 处理:共享的映射矩阵 OutHead∈RV×d 变换 + Softmax
- 输出:第 个输入 token 对应预测的第 位置 token 的概率分布
- 下标 :输入 预测的是序列中第 位的 token,对应 input 与 label 序列错位 位(Main Model 错位 1 位,MTP Module 1 错位 2 位,以此类推)
-
损失计算
- :label 范围,起始下标 (MTP Module k 第一个预测 token 为 ),结束下标 (eos token 位置)
- 到 :遍历所有有效预测位置,计算交叉熵损失
- 总损失:Main Model 损失 + 所有 MTP Module 损失加权求和,联合训练
-
训练模式
- 训练时直接使用样本中的 ground truth token 作为 MTP 模块的输入,而非上一模块的预测输出
- 避免预测误差累积,提升训练效果;推理时切换为 free-running 模式,用上一模块输出作为输入
-
-
MTP 的缺点是什么?
- MTP 训练时每一步都用 ground truth 输入(teacher forcing),但真实推理时前面的 token 是模型自己生成的,有误差
- MTP 因为预测更远,对误差累积更敏感,所以推理时更容易偏离训练分布 → 生成质量下降,这比普通 next-token 模型的 exposure bias 更严重
-
了解 vllm / SGLang 的架构设计吗?
- 最主流的 LLM 推理服务框架,核心都是解决高吞吐、低延迟、高显存利用率
- vllm:PagedAttention + Continuous Batching
- API Server:提供 AsyncLLMEngine 接口
- EngineCore
- Scheduler(Continuous Batching):动态混合不同阶段的请求,负责抢占、优先级、Token 级资源预算
- KVCacheManager(PagedAttention):负责将逻辑连续的 KV Cache 映射到物理非连续的地址空间中
- Executor:分发任务到 GPU Worker
- GPU Worker:一个 GPU 一个 Worker,负责模型权重、KV Cache、CUDA 核执行,并支持 TP/PP 分布式
- 缺点:KV Cache 仅请求内复用,跨请求前缀无法共享;复杂工作流支持弱
- SGLang:RadixAttention + 结构化编程
- 前端 Python DSL,负责结构化生成、多轮对话、Agent
- 后端
- Compiler:TVM 图优化、内存规划、代码生成
- Scheduler:CPU-GPU 双循环、前缀匹配、PD 分离
- RadixAttention:基数树(Radix Tree)组织 KV Cache,跨请求公共前缀全局复用,LRU 驱逐、热点 / 冷区分级
- 分布式引擎:TP/PP/DP 混合并行
-
KV 量化压缩
- 量化:FP8/INT8/INT4/2bit 混合
- 剪枝:Titanus(ACM 2025):级联剪枝 + 量化,KV 传输 -80%
模型剪枝
- 结构化剪枝
- 按通道 / 头 / 层剪:GPU 友好,无需稀疏库
- 典型:注意力头剪枝(保留 60–80% 头)、FFN 中间维度压缩
- 非结构化剪枝
- 随机 / 按重要性置零单个权重 → 稀疏矩阵
- 需 cuSPARSELt 等库,实际部署很少用
CUDA
- bank conflict、Memory Coalescing、occupancy、Kernel Launch Overhead、SM/SP/Block/Grid/Warp、SIMT/SIMD、Shared Memory / L2 / HBM
- SIMD、SPMD、SIMT 模型对比
- 什么是 memory coalescing?对访存带宽有什么影响?
- 内存合并的目标是让同一个 warp 内的线程访问连续且对齐的全局内存地址
- 这样 GPU 硬件可以把这些访问请求 “合并” 为一次大的 DRAM 访问请求(一次突发传输),效率比每个线程单独访问高很多
- 什么是 bank conflict?为什么会影响性能?如何避免?
- Shared Memory 分成 32 个 bank,而每个 bank 一个周期只能服务一个线程
- 同一个 warp 里,多个线程访问同一个 bank 的不同地址,硬件只能串行化服务,不能并行,这就叫 bank conflict
- 要避免 bank conflict,就要保证访问连续、不重叠,并利用填充(Padding)使得错开 bank,也可以利用 stride 互质、广播
- 如何在 CUDA kernel 里实现连续、合并的全局内存访问?
- 同一个 warp 内 32 个线程,访问全局内存的地址必须:连续 + 按线程顺序递增
- 线程 tid → 访问 base_addr + tid
- 线程 tid+1 → 访问 base_addr + tid+1
- 硬件自动合并为一次 128B 突发传输(最理想)
- 同时,必须让线程沿着行方向连续访问,不能按列访问,否则会导致无法合并内存访问
- 全局内存用 Memory Coalescing 读入 → 存入 Shared Memory → 计算时避免 Bank Conflict → 写回时再 Coalescing
- GPU 上的 occupancy 是什么?受哪些因素影响?
- Occupancy = 活跃 warp 占硬件最大可并发 warp 数的比例
- 一个 SM(流式多处理器)同一时间能 “挂起 / 切换” 的 warp 越多,隐藏访存延迟的能力越强
- Occupancy 本质衡量 GPU 有多忙、能不能用计算掩盖全局内存延迟
- CUDA 会取最小的那个作为实际活跃线程数:
- 线程块数量限制
- 每个线程块的线程数(block size)
- 寄存器使用数量(regs per thread)
- 共享内存使用量(shared memory per block)
- 是不是 occupancy 越高,kernel 性能一定越好?为什么?
- Occupancy 只解决 “延迟隐藏”,不解决 “实际工作量”
- 如果 kernel 是计算密集型,此时运行速度主要看算力,occupancy 够用来隐藏延迟即可
- 如果 kernel 是带宽密集型,运行速度主要看全局内存带宽
- 为了拉高 occupancy 往往要牺牲效率
- Occupancy 只解决 “延迟隐藏”,不解决 “实际工作量”
- 解释 SM、SP、warp、thread block、grid 之间的关系
- 什么是 SIMT?和 SIMD 的区别是什么?
- warp 基本执行单元是什么?warp divergence 为什么会降低性能?
- shared memory、L2 cache、HBM 之间的延迟与带宽差距大概是多少?
- shared memory 主要用来优化什么场景?有哪些局限?
- 什么是 kernel launch overhead?哪些情况会放大这个开销?
- 如何减少频繁 launch 小 kernel 带来的性能损失?
- 同一个 block 内的线程如何高效通信?
- 为什么 global memory 访问必须对齐才能高效?
- 如何在代码中判断 / 定位是否出现了 bank conflict?
- 动态并行(dynamic parallelism)会带来哪些额外 overhead?
- 如何通过调整 block size、grid size 来提升 occupancy?
- 为什么有些 kernel 明明算力没跑满,速度却上不去?
- warp shuffle 指令的作用是什么?相比 shared memory 有什么优势?
- L2 cache 对 Transformer 类算子(如 Attention、FFN)有什么影响?
- HBM 带宽瓶颈通常出现在哪些算子上?如何缓解?
- 什么是 latency hiding?GPU 是如何通过 warp 调度实现的?
- 为什么在 FlashAttention 中 shared memory 大小会直接限制分块策略?
- 寄存器 spilling 是什么?对 kernel 性能有什么影响?
量化
-
GPTQ、AWQ、SmoothQuant、INT8/INT4 权重 / 激活量化、量化对精度 / 速度的影响
-
什么是权重量化?什么是激活量化?
- 权重量化
- 把模型权重(Weight)从 FP32/FP16 映射到低精度整数(如 INT8/INT4)
- 权重是静态的,推理前就固定,通过量化可以减小模型体积、降低显存占用、加速矩阵乘法
- 激活量化
- 把模型推理过程中产生的特征图 / 激活值量化为低精度
- 激活是动态的,随着输入变化,主要是为了让整个计算链都用整数运算,实现端到端整数推理
- 量化难度更高,因为激活分布变化大,容易掉精度
- 权重量化
-
INT8 量化和 INT4 量化的主要区别是什么?
对比项 INT8 量化 INT4 量化 表示范围 256 个级别,精度高 16 个级别,精度低 模型压缩比 约为 FP16 的 1/2,FP32 的 1/4 约为 FP16 的 1/4,FP32 的 1/8 速度 / 显存 加速明显,显存降低中等 显存大幅降低,推理速度极快 精度损失 小,几乎不影响效果 大,容易显著掉点,需配合校准 / 微调 适用场景 生产环境、通用部署、追求稳 极端资源受限设备、大模型快速推理 -
对称量化和非对称量化有什么差异?各自适用场景?
-
对称量化
- 零点为 0,浮点 0 直接映射到整数 0,计算简单,适合权重量化
- 缺点是对分布不对称的数据(如激活 ReLU 输出全正)利用率低
-
非对称量化
- 零点可任意偏移,能更好地贴合实际数据分布
- 精度更高,适合激活值,能覆盖非对称分布
- 缺点是计算多一步减法,推理过程稍复杂
-
-
量化中的 scale 和 zero point 分别是什么作用?
- scale:浮点值域与整数值域的比例系数
- zero_point:浮点 0 对应的整数值
-
计算得到的中间值是什么精度?
- 标准流程
- INT4 权重、INT8 激活
- 乘积累加 → INT32 中间结果
- 再缩放 + 偏移 → 输出为下一层的激活(如 INT8/FP16)
- 标准流程
-
什么是 per-channel 量化?什么是 per-token 量化?
- per-tensor
- 整个 tensor 共用一个 scale
- 但是不同输出通道的数值分布差异极大,为了包住大值,scale 会很大,此时小值通道会被量化成 0,信息完全丢失
- per-channel
- 对权重的每个输出通道单独算一组 scale /zero_point
- 常用于权重量化,计算精度较高,计算开销增加较少
- per-token
- 对激活的每个 token(每个位置)单独量化,这是由于大模型里不同 token 的激活分布天差地别
- 如果整个激活 tensor 共用一个 scale,大值会把 scale 拉得很大,大量小值 token 直接量化崩掉,生成效果烂
- 主要用于 LLM 激活量化,不同 token 分布差异大,per-token 能显著提升精度
- 成本较高,推理时动态计算 scale
- per-tensor
-
为什么激活量化比权重量化更难、更容易掉点?
- 权重是静态固定分布,激活是动态、剧烈变化、极端分布,所以更难量化
- 权重在训练完成后固定不变,分布相对平滑、均匀、有界,通道之间差异虽大,但 per-channel 就能解决
- 激活随着输入动态变化,不同句子、不同 token 分布天差地别,经常出现长尾、 outliers(极端大值),经常高度稀疏、高度不对称
- 激活对异常值极度敏感,同时权重量化误差是静态一次性引入的,而激活量化误差是每层都产生、逐层累积、不断放大
- 因此激活必须在线动态量化,无法提前遍历所有可能分布,不可能把世界上所有文本都拿来算激活分布,所以激活永远只能实时估算,天生不准
- 同时,激活是非线性输出,分布高度不均匀,这种分布用对称量化会浪费一半表示空间,用非对称量化又增加计算复杂度,还容易引入偏移误差
- 而权重分布一般接近对称、近似高斯,很好量化
-
什么是 PTQ?
- PTQ 即 Post-Training Quantization,训练后量化
- 模型已经训练完了,不再反向传播更新参数,只通过少量校准数据 + 简单算法,把权重 / 激活从浮点量化成低精度整数(INT8/INT4)
- 不需要训练、不需要大量数据、不需要梯度,速度快、成本极低、工程友好,精度一般略低于原浮点模型,但损失可控,是目前大模型落地最主流的量化方式
- LLM 相关的 PTQ 技术
- GPTQ
- AWQ(Activation-aware Weight Quantization)
- SqueezeLLM
- ZeroQuant / LLM.int8 ()
- GGUF/GGML
-
GPTQ 量化的核心思想是什么?主要优化目标是什么?
-
以 “量化后模型输出尽量不变” 为目标,用二阶信息(海森矩阵)指导权重量化,逐列量化并把量化误差补偿到未量化列,让 INT4 量化几乎无损
-
不修改模型结构、不重新训练,把权重量化看成一个层输出重构问题,用 H≈XTX 海森矩阵衡量每个权重对输出的重要性
-
主要步骤
-
GPTQ 采用非对称量化,并逐层进行,以便在进入下一层之前,每一层都能独立处理
-
GPTQ 将层的权重转换为逆海森矩阵(inverse-Hessian),这是模型损失函数的二阶导数,表示模型的输出对每个权重变化的敏感程度
-
H 越大,说明这一列权重越敏感,量化误差影响越大
-
GPTQ 不是一次性量化整个矩阵,而是一列一列量化,即按照
[out_features, in_features]的 in_features 方向一列一列来 -
对当前权重列
- 根据分组(per-group)或 per-channel 计算 scale
- 量化得到
- 计算得到量化误差
-
不丢弃误差,而是把误差 “扔” 给后面还没量化的列,抵消掉
-
其中 g 由海森矩阵 H 计算得到,用于加权分配误差
-
这样,量化这一列带来的误差,被后续列抵消,从而避免误差累积爆炸
-
所有列量化完成后,得到整层 INT4 权重,存储每组 / 每通道的 scale、zero_point
-
-
按列逐个量化,量化后的误差直接补偿到剩余列,避免误差累积
-
优化目标
- 最小化量化前后层输出的差异,而不是简单最小化权重本身的误差
- 最终目标:INT4 下仍保持接近 FP16 的生成效果
-
-
GPTQ 是静态量化还是动态量化?支持在线推理吗?
- GPTQ 是典型的静态量化,scale、zero_point 都是离线一次性算好
- 在进行推理时,不再重新计算,不关心输入,属于 weight-only static quantization
- 进行在线推理时,INT4 权重存储 → 算子里反量化为 FP16 → 正常矩阵乘
-
AWQ 相比 GPTQ 改进了什么?为什么精度更高?
- GPTQ 只关注权重误差;AWQ 关注 “激活敏感的权重”,对重要权重保护,不强行量化
- 引入激活感知:GPTQ 不看激活大小,只看权重对输出的二阶影响;而 AWQ 显式统计激活,知道哪些通道的激活大、对结果关键
- 保护重要通道(channel-wise protection):对激活大、贡献大的通道,保留高精度(FP16),只对不重要通道量化,从而整体精度更高
- 速度更快,不需要像 GPTQ 那样逐列精细优化,量化速度快很多
- 对异常值更鲁棒,LLM 激活里的 outliers 不会轻易毁掉整层量化
-
AWQ 的激活感知权重量化具体在做什么?
-
根据激活值,找出重要的通道,即运行少量校准数据,统计每个输入通道的激活幅度
-
激活越大,说明这个通道对模型输出越关键
-
不是均匀量化所有权重,而是根据激活重要性做 “非均匀混合精度量化”
-
-
动态量化和静态量化的区别?GPTQ 和 AWQ 是什么类型的?
- 静态量化:离线提前算好 scale、zero_point,用一小批校准数据跑前向,统计分布,推理时不再变化、不再计算,和输入无关,如 GPTQ、AWQ
- 动态量化:推理时才计算 scale /zero_point,根据当前真实输入实时统计最大最小值,每次输入不一样,量化参数也不一样,能够适配各种输入分布
- 静态量化对分布变化大的激活不够精准,而动态量化则在推理时多一步统计开销,硬件不友好,速度慢
-
什么是 GGUF/GGML?
- GGUF/GGML 是为 CPU 设计的量化格式,不是为了极致精度,而是为了小体积 + CPU 跑得快
-
SmoothQuant 解决了什么问题?原理是什么?
-
LLM 量化的难点
- 权重 W:分布均匀、容易量化(INT4/INT8 都稳)
- 激活 X:存在固定通道的巨大离群点(比正常值大 10
1000 倍),直接量化会把 scale 拉得极大,大部分值只有 23 个有效量化级,精度崩掉
-
传统方案
- 只量化权重(W4A16):如 GPTQ/AWQ → 内存减半,但激活还是 FP16,计算不加速
- 强行 W8A8:精度掉太多,没法用
- LLM.int8 ():把离群点用 FP16 算 → 硬件不友好、速度慢
-
SmoothQuant 的目标是用数学等价变换,让激活和权重都能稳定 INT8 量化(W8A8),且兼容硬件 INT8 GEMM
-
SmoothQuant 引入逐通道缩放因子 s(向量):
- 激活侧:X 除以 s → 把大离群点 “压平”(平滑)
- 权重侧:W 乘以 s → 难度转移到权重(权重本来就好量化)
- 数学完全等价,输出 Y 不变
-
如何计算平滑因子 s
-
用校准数据(几十~几百条)离线统计激活每通道最大绝对值: 和权重对应输入通道最大绝对值:
-
平滑因子计算公式
-
α:平衡系数(通常 0.5~0.8)
- α=1:只缩激活 → 回到传统量化
- α=0:只缩权重 → 权重变大,但激活完全平滑
-
目标:让 和 的动态范围尽量均衡、都适合 INT8
-
-
-
SmoothQuant 为什么能同时稳定权重和激活量化?为什么它比直接剪异常值、动态量化更好?
- 剪去异常值会丢失信息,而动态量化则推理速度慢,硬件不友好
- 而 SmoothQuant 则离线静态量化,推理零开销,完全等价
-
什么是量化感知训练 QAT?和 PTQ 有什么区别?
-
QAT 即 Quantization-Aware Training,量化感知训练,模拟量化噪声再微调,精度高但麻烦
-
QAT 通过在模型训练 / 微调阶段,前向传播里模拟量化噪声,反向传播正常更新权重,让模型 “习惯” 量化误差,最终推理时量化几乎不掉点
-
在训练过程中,QAT 会引入所谓的伪量化(fake quants):首先将权重量化为如 INT4,然后再反量化为 FP32
-
首先,找到输入数据的分布,即找到 MIN 和 MAX 值
-
对于每一个算子,量化参数通过以下公式得到:
-
缩放因子 S:
-
零点偏移 Z:
-
量化值 Q:
-
Rmin,Rmax:原始浮点数据的最小 / 最大值
-
Qmin,Qmax:目标量化格式的最小 / 最大值(如 INT8 为 -128 和 127)
-
R:原始浮点数据
-
S:缩放因子,用于将浮点范围映射到整数范围
-
Z:零点偏移,用于对齐浮点零点与整数零点
-
-
FakeQuant 量化和反量化的完整过程可表示为:
-
量化:将浮点输入 x 除以缩放因子 s,四舍五入为整数,再减去零点 z,并通过 Clamp 限制在整数范围内
-
反量化:将量化后的整数加上零点 z,再乘以缩放因子 s,恢复为浮点数据
-
这一过程能够模拟量化到低比特操作的时候的精度损失,把该损失作用到网络模型中,传递给损失函数,让优化器去在训练过程中对该损失值进行优化
-
-
反向传播
-
在反向传播过程中,模型需要计算损失函数相对于每个权重和输入的梯度,梯度通过 FakeQuant 节点进行传递,这些节点将量化误差反映到梯度计算中,模型参数的更新因此包含了量化误差的影响,使模型更适应量化后的部署环境
-
量化操作里有 round、clamp,都是不可导 / 梯度为 0 的操作
-
按照前向传播的公式,因为量化后的权重是离散的,反向传播的时候对 W 求导数为 0:
-
因为梯度为 0,所以网络学习不到任何内容,权重 W 也不会更新:
-
可以使用直通估计器(Straight-Through Estimator,简 STE)简单地将梯度通过量化层传递,近似来计算梯度,这使得模型能够在前向传播中进行量化模拟,但在反向传播中仍然更新高精度的浮点参数
-
STE 近似假设量化操作的梯度为 1,从而允许梯度直接通过量化节点:
-
如果被量化的值在 范围内,STE 近似的结果为 1,否则为 0
-
这种方法使模型能够在训练期间适应量化噪声,从而在实际部署时能够更好地处理量化误差
-
-
假设在反向传播过程中没有进行量化,会根据梯度下降选择损失最小的权重,然而,如果该权重位于狭窄的极小值点,会导致更大的量化误差,因此 QAT 试图探索更宽的极小值点对应的损失曲面,来最小化量化误差
-
PTQ 仅简单将浮点权重压缩为低比特,而浮点模型通常收敛于狭窄尖锐的极小值点,轻微的量化扰动就会导致损失急剧上升
-
QAT 则在训练过程中主动寻找更宽、更平坦的极小值点,使模型对权重扰动和量化误差更不敏感,因此量化后的损失远低于 PTQ
-
-
哪些量化方法只量化权重?哪些同时量化激活?
- 只量化权重(Weight-only Quantization):GPTQ、AWQ、GGUF/GGML、SqueezeLLM
- 同时量化权重 + 激活(W&A Quantization):SmoothQuant、LLM.int8 ()、QAT、W8A8 全量化
-
量化在什么情况下能提升推理速度?什么情况下反而变慢?
- 提升推理速度
- 权重 + 激活都量化(W8A8):GEMM 完全在整数域进行,访存和计算双重加速
- 算子高度优化:专用 fused kernel 支持 INT4/INT8,访存效率显著提升
- 变慢的情况
- 只量化权重,不量化激活(W4A16 / W8A16):推理时权重需要实时反量化回 FP16,多了一步解量化开销,同时计算仍在 FP16,没有计算加速
- 动态量化:需要根据输入实时计算 scale,引入大量额外计算
- 提升推理速度
-
为什么量化后模型在长文本下精度下降更明显?量化引入的误差为什么会在自回归生成中累积放大?
- 长文本会让激活的动态范围更大、outlier 更多、量化误差逐层累积更严重,所以精度掉得比短文本更多
-
KV Cache 量化(INT8/INT4)和权重量化有什么不同?
-
量化对 attention 以及 FFN 影响有什么不一样?
- Attention 对量化误差更敏感,更容易崩,尤其是 INT4,这是因为 Attention 的核心是内积相似度,Q/K 微小的量化误差都会导致点积明显偏移,而 Softmax 会进一步放大微小差异
- FFN 更耐量化,INT4 基本无损,因为 FFN 的本质是高维特征转换,只需要大致正确的赋值,量化带来的小幅噪声会被 GeLU/SiLU 平滑掉;FFN 的参数量也较大,分布平滑、无极端异常通道
-
大模型推理中,GPTQ/AWQ/SmoothQuant 该如何选型?
维度 GPTQ AWQ SmoothQuant 核心思想 Hessian 感知,逐层误差补偿,优先量化影响小的权重 激活感知,识别重要权重并保护,重排 / 缩放 平滑因子转移量化难度,W+A 联合量化 量化对象 权重(W) 权重(W) 权重 + 激活(W+A) 位宽支持 INT4/3/2(极致压缩) INT4(主流) INT8(W8A8) 校准需求 中(512-2048 样本) 低(128-512 样本,更快) 低(轻量统计) 精度表现 4bit 下 PPL 损失最小(~<1%) 4bit 稳定,略逊 GPTQ(~1.5%) W8A8 几乎无掉点 推理速度 中(反量化开销) 中(反量化开销,AWQ 略快 GPTQ) 最快(INT8 硬件加速,TensorRT 最优) 部署栈 AutoGPTQ、llama.cpp、GGUF AutoAWQ、llama.cpp、GGUF TensorRT、FasterTransformer、ONNX 适用场景 极限压缩、长文本、追求极致精度 小样本 / 跨域、快速量化、稳定部署 生产级 INT8、最大化硬件吞吐