A调度与批处理
- Prefill 预填充
- 处理prompt并建立各层KV的阶段,可分块进行;完成后产生首个输出。较长prefill常有较高算术强度,具体瓶颈需测量。
源码:
scheduler.py L29–55 · model_runner.prepare_prefill · 课程 01
- Decode 解码
- 每次只输入上一步采样出的 1 个 token,复用已有 KV cache 产出下一个 token 的阶段。访存密集——每步都要把整条序列的 K/V 读一遍。
源码:
scheduler.py L57–73 · model_runner.prepare_decode · 课程 01
- Continuous batching 连续批处理
- 每一轮都重新组 batch:谁做完了立刻退场,新请求随时插入,而不是等一整批全部结束。它是「吞吐能随并发上升」的根本原因。
源码:
scheduler.py 的 waiting / running 双队列 · 课程 01
- Chunked prefill 分块预填充
- 把长prompt的计算分成多轮;调度器可利用它与decode交错或混合,具体取决于实现。此nano版本同轮不混decode,vLLM可按预算混合。
nano-vllm 只对第一条序列允许分块:
scheduler.py L42–43;vLLM v1 默认混合 · 课程 07
- Preemption 抢占
- 显存不够时,把某些 running 序列的 block 全部释放、状态退回 waiting,等有空位再重新 prefill。代价是这部分的 KV 白算了。
源码:
scheduler.preempt L75–79 · 课程 03
- Batch 批
- 这一轮一起上 GPU 的序列集合。三个旋钮决定它的大小:
max_num_seqs(序列数上限)、max_num_batched_tokens(token 数上限)、以及显存里还剩多少 block。
源码:config.py L9–10 · scheduler.schedule
B显存与 KV 管理
- KV cache 键值缓存
- 缓存每一层注意力已经算过的 Key 和 Value,decode 时直接读取,避免把前缀重算一遍。固定层数和维度时,标准dense attention的单步重算可由O(t²)变为O(t);累计N步仍约O(N²),不是整段生成O(N)。代价是KV容量随有效上下文长度线性增长。
源码:
model_runner.allocate_kv_cache L103–121 · 课程 02
- Block 块
- KV 存储的最小分配单元,固定装
block_size 个 token(默认 256)。一条序列的 KV 由若干块拼成,块在物理显存里可以不连续。
源码:config.py L17 · block_manager.py 课程 02
- Block table 块表
- 每条序列自己的「逻辑块号 → 物理块号」数组,等价于操作系统的页表。注意力 kernel 靠它找到 KV 的真实地址。
源码:
sequence.block_table L28 · prepare_block_tables 课程 02
- Slot mapping 槽位映射
- 一个 int32 数组:本次前向的第 i 个 token 应该把 K/V 写到 KV cache 的第几个物理槽位。Triton 写入 kernel 全靠它。
源码:
store_kvcache_kernel · prepare_prefill L151–161 · 课程 04
- PagedAttention 分页注意力
- 借操作系统的分页思想管理 KV:按块分配、按块表寻址,块可以共享、可以复用,从而减少外部碎片与过量预留;每请求末块仍可能有空槽。vLLM 的立身之本。
论文:SOSP'23 §3 · 源码:
block_manager.py · 课程 02
- Prefix caching 前缀缓存
- 相同前缀的请求共享同一批 block:对前缀做链式哈希,命中就直接复用,靠引用计数保证没人用时才释放。
源码:
block_manager.hash_blocks L110–120 · can_allocate L58–73 · 课程 07
- ref_count 引用计数
- 一个 block 被几条序列共享。为0表示无活跃引用、可回收;内容与hash可能保留以便再次命中。完整前缀共享时通常增加计数。
源码:
block_manager.py L12 · allocate / deallocate · 课程 02
C计算与并行
- Compute-bound 算力受限
- 瓶颈在 GPU 的计算单元,矩阵乘越大越划算。prefill 是典型:一次几百上千 token,张量核心能跑满。
- Memory-bound 带宽受限
- 瓶颈在显存带宽,算力再快也要等数据搬过来。decode 是典型:每生成 1 个 token 要读完整条 KV。
- Arithmetic intensity 算术强度
- 每搬运 1 字节数据能做多少次浮点运算(FLOPs/byte)。它和硬件的「算力/带宽」比值比较,就能判断一个 kernel 是算力受限还是带宽受限。
- Tensor Parallelism 张量并行
- 把每层的权重沿维度切到多张卡上,每层末尾做一次 all-reduce 汇总。nano-vllm 用 NCCL 建组、用共享内存传方法名和参数。
源码:
model_runner.py L41–89 · layers/linear.py · 课程 05
- CUDA Graph CUDA 图
- 把一整串 kernel 的启动序列录下来,之后一次回放,省掉逐 kernel 的 launch 开销。decode 的 shape 固定,最适合录图。
源码:
model_runner.capture_cudagraph · 课程 06
- Sampling 采样
- 从 logits 里选下一个 token:贪心、temperature、top-k、top-p。nano-vllm 只实现了 temperature + 多项式采样。
源码:
layers/sampler.py · 课程 04
D指标与取舍
- TTFT 首 token 延迟
- Time To First Token:请求进来到吐出第一个 token 的时间,主要由 prefill 长度和排队时间决定。交互式场景最看它。
- TPOT / ITL 每 token 延迟
- TPOT通常是每请求首末输出间总时间除以后续token数;ITL是相邻输出事件间隔的序列,适合看分位数。输出少于2个时TPOT不定义。
- Throughput 吞吐
- 单位时间处理的 token 数(或请求数)。增加并发可能提高利用率,也会增加延迟或内存压力;收益并不单调,须在固定负载下测量。
- Goodput 有效吞吐
- 满足 SLA(比如 TPOT < 50ms)的那部分吞吐。真实服务优化的是它,不是裸吞吐。
EMoE 与规模化
- MoE 混合专家
- 每层有多组「专家」子网络,token 经 router 选出 top-k 个专家只走这几组计算。参数量大但每个 token 的激活计算量小。
DeepInfer:
model_executor/models/v4_modules/mlp.py · 课程 13
- Expert Parallelism 专家并行
- 把专家分到不同卡上,token 通过 all-to-all 被送到持有对应专家的卡,算完再收回来。通信量由路由结果决定,因此对负载不均极其敏感。
DeepInfer:
parallel_utils/ + vendor/DeepEP · 课程 13
- EPLB 专家并行负载均衡
- 给热门逻辑专家分配冗余物理副本,再把所有副本按「最小化各 step 的最大 rank 负载」贪心摊到各卡上。周期性触发,因为再平衡要搬权重。
源码:
model_executor/eplb/policy.py · 课程 13
- Redundant expert 冗余专家
- 同一个逻辑专家在多个物理槽位上的副本。物理专家数 = 逻辑专家数 + 冗余数。副本让热点专家可以并行服务多份流量。
- MLA 多头潜在注意力
- DeepSeek 的注意力变体:把 K/V 压到低维潜在空间缓存,显著缩小 KV cache。FlashMLA 是它的专用 kernel。
源码:
vendor/FlashMLA · 课程 12
- MTP / DFlash 多 token 预测 / 投机头
- MTP是多token预测;本地DFlash为投机流程产生draft。此提交DEEPINFER_USE_NEXTN_DECODE默认5,这是配置上限,不代表所有模型固定有5个预测层。
源码:
model_executor/models/mtp/dflash.py · 课程 14
- DSpark 置信度调度的投机解码
- 在 DFlash 的 draft 之上加一个置信度头,预测每个候选的接受概率;将逐位置confidence累乘并结合跨请求候选与耗时曲线分配验证预算;真正接受与否仍由验证及sampler决定。
源码:
dflash.py 的 ConfidenceHead · 课程 14
- Speculative decoding 投机解码
- 先猜 k 个 token,再用一次大模型前向批量验证;接受的部分直接采用,拒绝处从修正分布重采。拒绝采样保证输出分布不变。
vLLM:
scheduled_spec_decode_tokens · 课程 11
- Batch invariance 批不变性
- 同一请求在不同 batch 组成下得到完全相同的结果。因为浮点归约不满足结合律,这需要固定归约顺序的 kernel 路径。
DeepInfer:
DEEPINFER_BATCH_INVARIANT · 课程 14
- PD disaggregation 预填充-解码分离
- 把 prefill 与 decode 放到不同机器/集群,各自用最合适的硬件配比;KV 通过 KV connector 从 prefill 节点传到 decode 节点。
vLLM:
v1/distributed/kv_transfer/ · 课程 11
- KV connector KV 传输连接器
- PD 分离或 KV 复用时负责搬运 KV 的组件。块要先分配、但数据未到时不能登记进前缀缓存(
delay_cache_blocks)。
- Token / Embedding
- token是分词器输出的离散单位;token ID经embedding查表得到H维向量,token边界不等于汉字/单词边界。 图解与源码
- Hidden size / head_dim
- H是残差流宽度,d是每头宽度;H不必等于Hq×d,必须读取模型config。 图解与源码
- Q / K / V
- Query与Key形成匹配分数,Value提供加权汇总内容;三者是不同学习投影。 图解与源码
- Causal mask
- 约束query只看当前位置与过去;有p个缓存token的chunk第i行应允许j≤p+i。 图解与源码
- MHA / MQA / GQA
- 分别为每Q头一组KV、所有Q头共享一组KV、Q头分组共享KV;共享不代表query权重也相同。 图解与源码
- RoPE
- 按位置旋转Q/K的二维子空间,让点积携带相对位置信息;本地采用半切配对。 图解与源码
- RMSNorm
- 除以最后维的均方根并乘可学习γ,不减均值。 图解与源码
- Residual / Pre-Norm
- 残差将变换增量加回原状态;Pre-Norm在子层变换前归一化,本地可融合并延迟残差相加。 图解与源码
- SwiGLU
- [SiLU(xWg)⊙(xWu)]Wd;两路上投影、逐元素门控和下投影,逐token变换通道。 图解与源码
- Logits / Temperature
- logits是未归一化类别分数;temperature>0缩放后再softmax,T=0不能直接代入除法。 图解与源码
- Online softmax
- 分块维护最大值m、分母l与加权和o,合并时重缩放,最后o/l得到完整attention结果。 图解与源码
- In-flight / committed
- in-flight已调度但尚未完成回填;committed已接受并提交。computed账本在异步时可能乐观计入在途。 图解与源码
- query_start_loc / seq_lens
- 前者划分本轮packed query片段,后者描述各请求可读上下文长度;都不能替代物理block_table。 图解与源码
- YOCO bounded replay
- 对consumer层SWA状态进行有界后缀近似重建;窗口和回退覆盖约束不自动保证与全量重放严格等价。 图解与源码