DeepSeek-v2 Routed Scaling Factor 应用时机详解

背景 DeepSeek-V2/V3 系列模型采用了 MoE(Mixture of Experts)架构,其中 routed_scaling_factor 是一个重要的超参数,用于缩放 routed expert 的输出。该系数来自模型 config,在 DeepseekV2MoE.__init__ 中初始化: self.routed_scaling_factor = config.routed_scaling_factor 默认值通常为 1.0,但 DeepSeek-V2 系列(如 deepseek-v2、deepseek-coder-v2)设置的典型值是 2.5 或 1.0,取决于具体子模型。 控制开关 在 vLLM 的 deepseek_v2.py 中,关键代码如下: apply_routed_scale_to_output = not self.is_rocm_aiter_moe_enabled routed_scaling_factor=self.routed_scaling_factor, apply_routed_scale_to_output=not self.is_rocm_aiter_moe_enabled, 这个 bool 值决定了 routed_scaling_factor 由谁处理——是 kernel 内部还是 runner 外部。 ...

June 1, 2026 · 2 min · 280 words

vLLM embed.py 扩展:添加非 EngineArgs 自定义参数

背景 vLLM 官方示例 examples/basic/offline_inference/embed.py 展示了一个标准的 Embedding 推理流程,其参数解析采用如下模式: parser = FlexibleArgumentParser() parser = EngineArgs.add_cli_args(parser) args = parser.parse_args() llm = LLM(**vars(args)) 核心流程是: 创建 FlexibleArgumentParser 通过 EngineArgs.add_cli_args(parser) 将 EngineArgs 的所有字段注册为 CLI 参数 解析参数后通过 LLM(**vars(args)) 直接解包传给 LLM 构造函数 这种模式对纯 EngineArgs 场景工作良好,但当你需要添加业务相关的自定义参数(如 --batch-size、--input-file)时,就会遇到一个问题:非 EngineArgs 的参数会被一起传给 LLM(),导致 TypeError。 问题所在 LLM.__init__ 只接受 EngineArgs 中定义的字段。如果在 parser 上添加了额外的自定义参数,vars(args) 会包含这些多余字段,直接解包传入 LLM() 会导致类似这样的错误: TypeError: LLM.__init__() got an unexpected keyword argument 'custom_param' 解决方案的核心思路是:在将参数传给 LLM() 之前,把自定义参数剥离出来。 三种解决方案 方法一:手动按字段过滤(最直观) def parse_args(): parser = FlexibleArgumentParser() parser = EngineArgs.add_cli_args(parser) parser.add_argument("--custom-param", type=str, default=None) parser.add_argument("--batch-size", type=int, default=32) return parser.parse_args() def main(args: Namespace): engine_args = {k: v for k, v in vars(args).items() if k in EngineArgs.__dataclass_fields__} llm = LLM(**engine_args) print(f"Custom param: {args.custom_param}") print(f"Batch size: {args.batch_size}") 原理:EngineArgs 是一个 dataclass,__dataclass_fields__ 包含所有声明字段的元信息。遍历 vars(args) 字典,只保留 key 存在于 __dataclass_fields__ 中的条目即可。 ...

June 1, 2026 · 2 min · 327 words

DeepSeek MLA 在 DCP 分布式环境中的 Prefill 阶段解析

前言 DeepSeek 提出的 MLA(Multi-head Latent Attention)通过将 KV 压缩到低维 latent 空间,大幅降低了推理时的 KV cache 开销。但在 DCP(Decode Context Parallel,即上下文并行)分布式环境下,MLA 的 prefill 阶段设计与 decode 阶段有显著差异。本文从实现角度展开分析。 什么是 DCP DCP(Decode Context Parallel)是一种将 KV cache 按序列维度切分到多个 GPU 的分布式策略。每个 rank 只持有完整 KV cache 的 1/dcp_world_size,从而减少单卡显存占用,支持更长的上下文。 与更常见的 DP(Data Parallel,扛并发)和 EP(Expert Parallel,分摊 MoE 参数显存)不同,DCP 解决的是单请求长上下文场景下 KV cache 放不下的问题。 MLA Prefill vs Decode:两条不同的路径 MLA 在 prefill 和 decode 阶段走了截然不同的计算路径: Prefill (forward_mha) Decode (forward_mqa) KV 形态 完整 MHA(N 头) Latent(1 头) Head dim P+R(~192) Lkv+R(~576) 计算特性 Sq ≈ Skv,计算密集 Sq ≪ Skv,避免显存搬运 Prefill 走 MHA 路径:kv_c 通过 W_UK/W_UV 解压成完整多头 K/V(N 个头),然后做标准的多头注意力。因为 prefill 时新 token 数和 context 长度在同一量级,展开 KV 做计算密集的 attention 是划算的。 ...

June 1, 2026 · 3 min · 557 words

vLLM GPU UBatchWrapper 中的 Barrier 机制解析

背景:什么是 UBatchWrapper 在 vLLM 的 GPU 推理引擎中,UBatchWrapper(位于 vllm/v1/worker/gpu_ubatch_wrapper.py)是一个模型包装器。它拦截对原始模型的调用,在内部将一次大 batch 的 forward 拆分成多个 micro-batch(ubatch),并利用多线程 + CUDA stream 实现计算与通信的重叠。 核心目标:解决 MoE 模型中 all2all 通信开销大的问题——让一个 ubatch 在做计算时,另一个 ubatch 的通信已经在背后并行执行。 线程模型与同步原语 threading.Barrier:集结号 UBatchWrapper 在初始化时创建一个 threading.Barrier: self.ready_barrier = threading.Barrier(num_ubatches + 1) threading.Barrier 不关心具体有哪些线程,只计数。内部维护一个计数器,每当有线程调用 barrier.wait(),计数器就 +1。当总数达到构造时指定的 parties 值(这里是 num_ubatches + 1),所有正在 wait() 的线程同时被释放,计数器归零。 这里的 +1 包含了 N 个 ubatch 线程 + 1 个主线程。 ready_barrier.wait() 在三处被调用: 文件 行号 调用方 gpu_ubatch_wrapper.py 261 主线程 在 _capture_ubatches 中 gpu_ubatch_wrapper.py 325 主线程 在 _run_ubatches 中 ubatching.py 56 每个 ubatch 线程 在 UBatchContext.__enter__ 中 少一个线程到达,所有人全部卡住。 ...

June 1, 2026 · 4 min · 776 words

mhc_pre_torch 的数学公式与 CUDA 代码解释

背景 mHC(multi-Head Combinatorial)是 DeepSeek V4 模型中引入的一种多头残差混合机制。它将传统 Transformer 中单一的残差向量扩展为 $M$ 个并行的残差副本(multi-head residual),并在每个 block 前后通过可学习的门控和组合矩阵对多头残差进行变换。 本文以 mhc_pre_torch 为核心,从数学公式出发逐行对照 PyTorch 代码,并延伸至 mhc_post_torch 和整个 mHC 流水线,帮助读者完整理解这一算子的设计思路与实现细节。 ...

June 1, 2026 · 5 min · 993 words

vLLM Cascade Attention:用法、场景与原理解析

概述 Cascade Attention(级联注意力)是 vLLM 推理引擎中针对多请求共享长前缀场景的一种注意力优化技术。它将标准 attention 拆解为 prefix(前缀)和 suffix(后缀)两个阶段,显著降低 KV cache 的全局内存读取量,在共享 system prompt 的批量推理场景中可实现最高数十倍的 attention 加速。 本文将深入剖析 cascade attention 的设计思想、使用方式、适用场景、实现原理,并与 FlashAttention、FlashDecoding 等其他优化技术进行对比。 一、Cascade Attention 的核心思想 标准 Attention 的冗余 在大语言模型的批量推理中,多个请求往往共享一个较长的 system prompt。例如: Chatbot 场景:所有请求共享 “You are a helpful assistant…” 等 system prompt Document QA:多用户对同一篇文档提问,文档内容为公共前缀 Self-Consistency:对同一 prompt 采样多条推理路径 标准 attention 的处理方式是每个 request 独立计算其完整的注意力——包括共享的 system prompt。这意味着同一份前缀 KV cache 被重复加载多次。 Cascade 的拆解思路 Cascade attention 将一次 attention 计算拆成三步: Prefix 阶段:将所有请求的 query 拼成一个"大序列",对共享前缀做一次非因果(bidirectional)attention Suffix 阶段:每个请求各自对其独有的后缀做因果(causal)attention Merge:通过 LSE(log-sum-exp)rescaling 将两阶段结果加权合并 数学上等价于标准 attention,但计算量和显存带宽需求大幅降低。 ...

June 1, 2026 · 6 min · 1143 words

vLLM TorchDynamo 编译:FX Graph 分割原理与实践

背景 vLLM 利用 PyTorch 2.x 的 torch.compile 路径,通过 TorchDynamo 捕获模型计算图,再经过图分割(graph splitting)和分段编译(piecewise compilation)来优化 GPU kernel 执行效率。本文将深入剖析 FX Graph 的分割原理及其背后的设计思想。 一、TorchDynamo 编译概览 TorchDynamo 是一个 Python 级别的 JIT 编译器,它通过 PEP 523 的 frame evaluation callback 在 Python 字节码执行之前捕获计算图。vLLM 利用这一机制,将模型 forward 函数中的计算捕获为 fx.GraphModule,然后送入自定义后端 VllmBackend 进行编译。 编译流程大致如下: model.forward() └── TorchDynamo 捕获计算图 └── fx.GraphModule (原始完整图) └── VllmBackend.__call__() ├── split_graph() → 图分割 ├── PiecewiseCompileInterpreter → 分段编译 └── codegen → 生成胶水函数 └── 返回可调用对象给 Dynamo 二、FX Graph 分割:split_graph 的工作原理 2.1 为什么需要分割 vLLM 的模型计算中包含两种性质不同的算子: ...

June 1, 2026 · 4 min · 754 words

DeepSeek Attention 中为什么除以 √d_k — 从代码到数学

引言 在 Transformer 的 Scaled Dot-Product Attention 中,有一个看似简单却至关重要的操作: scores = Q @ K^T / math.sqrt(d_k) 这个 ÷√d_k 几乎出现在每一个 Attention 实现中。DeepSeek 的 MLA(Multi-head Latent Attention)也不例外。本文从 DeepSeek V4 的 vLLM 实现代码出发,深入探讨这个缩放因子的数学动机、工程实现,以及 DeepSeek 特有的优化变体。 标准 Attention 中的缩放因子 Softmax 的"饱和"问题 原始 Attention 计算公式为: Attention(Q, K, V) = softmax(QK^T / √d_k) V 设 Q、K 的每个元素是独立同分布、均值为 0、方差为 1 的随机变量。对于向量 q 和 k(维度为 d_k),其点积的均值和方差为: E[q·k] = Σ E[q_i·k_i] = 0 Var(q·k) = Σ Var(q_i·k_i) = d_k 即点积的方差正比于 d_k。当 d_k 较大时(如 128、512),点积的绝对值会很大,导致 softmax 进入梯度极小的饱和区: 当某个 x_i 远大于其他值时,e^{x_i} 会主导分母,softmax 输出接近 one-hot,梯度趋近于 0,训练难以收敛。 ...

June 1, 2026 · 4 min · 721 words

DeepSeek MLA 中 QKV Head Dimension 的处理差异

引言 Multi-head Latent Attention(MLA)是 DeepSeek-V2/V3 系列模型中最核心的架构创新之一。它在标准 Multi-Head Attention(MHA)的基础上引入了低秩压缩,大幅降低了 KV cache 的显存占用,同时保持了与 MHA 相当的模型质量。 本文从 QKV head dimension 处理差异 这一视角切入,深入分析 MLA 的设计原理、vLLM 中的具体实现,以及这种设计带来的性能收益。 1. 标准 MHA 回顾 在标准 MHA 中,给定输入序列 X ∈ ℝ^{S×D},Q、K、V 通过三个独立的线性变换得到: Q = X @ W_Q → [S, H, d_head] K = X @ W_K → [S, H, d_head] V = X @ W_V → [S, H, d_head] 其中 d_head = D / H,三者完全相等。注意力计算为: Attention(Q, K, V) = softmax(Q @ K^T / √d_head) @ V → [S, H, d_head] 输出再经 W_O 映射回 D 维。这种 Q/K/V 共享同一 head dim 的设计深入人心,以至于很多人默认这是注意力机制的"必须要求"。 ...

June 1, 2026 · 5 min · 909 words

DeepSeek V3 MoE 模块计算与通信逻辑详解

概述 DeepSeek V3 的 MoE(Mixture of Experts)模块是其核心组成部分,采用 Shared + Routed Expert 架构。本文基于 vLLM 代码库,深入分析其计算流程、通信模式、量化方案以及性能优化策略。 ...

June 1, 2026 · 6 min · 1086 words