EN

LLM Notes

LLM 与强化学习学习笔记 - Transformer、RLHF、PPO、DPO 等技术深度解析

LLM 推理的非确定性:根因分析与 Batch Invariance 解决方案

2025-12-24 · Qi Lu · Views:

问题定义

在 LLM 推理服务中,相同的输入理应产生相同的输出。然而实际观测表明,即使采用贪婪解码(temperature=0),输出仍存在不确定性。以下实验数据来自 Thinking Machines Lab1

模型 采样次数 不同输出数 最频繁输出出现次数
Qwen3-235B-A22B 1000 80 78

这一现象与贪婪解码的数学定义矛盾:$\hat{y}_t = \arg\max_v p(v \mid y_{<t}, x)$ 应当是确定性的。

本文的目标是:(1) 定位非确定性的根本来源;(2) 设计可工程化部署的解决方案。


假说检验:并发浮点运算 vs. Batch Size 变化

假说 1:GPU 并发导致的浮点非关联性

主流假说认为,GPU 的并行计算引入了不确定性。其逻辑链条如下:

  1. 浮点加法不满足结合律:$(a + b) + c \neq a + (b + c)$
  2. GPU 并行 reduction 的执行顺序取决于线程调度
  3. 不同的执行顺序产生不同的累加结果
  4. 微小差异经 argmax 放大后改变输出 token

这一假说的典型支持证据是 CUDA 的 atomicAdd 操作的非确定性。

假说 1 的问题

Thinking Machines Lab1 的分析指出,现代 Transformer 推理中的核心操作并不依赖原子操作:

实验验证:在单 GPU、固定 batch size 条件下,同一输入的多次推理输出完全一致。这排除了线程级非确定性作为主要来源。

假说 2:Batch Size 变化导致数值路径分歧

真正的问题在于:kernel 的数值输出是 batch size 的函数

Batch Size 变化导致数值路径分歧

当推理服务采用动态 batching 时,同一请求在不同时刻可能被分配到不同大小的 batch 中。每个 kernel 的 tiling 策略、reduction 分块方式都可能随 batch size 变化,导致数值结果不同。


Batch Invariance 的数学定义

设 kernel $K$ 作用于输入张量 $X \in \mathbb{R}^{B \times N \times D}$,输出 $Y = K(X)$。

Batch Invariance 要求:对于任意 batch 中的样本 $x_i$,其输出 $y_i$ 仅取决于 $x_i$ 本身,而与 batch 中其他样本无关:

\[K(X)[i] = K'(x_i), \quad \forall i \in [1, B]\]

其中 $K’$ 是等价的单样本 kernel。

实际上,这一性质在标准 kernel 实现中并不成立。原因在于 tiling 策略的 batch 依赖性


关键 Kernel 的 Batch Variance 分析

RMSNorm

RMSNorm 计算如下:

\[\text{RMSNorm}(x) = \frac{x}{\text{RMS}(x)} \cdot \gamma, \quad \text{RMS}(x) = \sqrt{\frac{1}{D}\sum_{i=1}^{D} x_i^2 + \epsilon}\]

关键步骤是 reduction:$\sum_{i=1}^{D} x_i^2$。

标准 CUDA 实现通常采用 tree reduction

Tree Reduction 示意

问题所在:当 batch size 改变时,CUDA kernel 可能选择不同的 block size 和 grid 配置。不同配置下的 reduction 分块方式不同:

不同的分块方式产生不同的中间舍入误差,最终结果在 ULP(Unit in the Last Place)级别存在差异。

矩阵乘法

GEMM 的标准分块实现:$C = AB$,其中 $A \in \mathbb{R}^{M \times K}$,$B \in \mathbb{R}^{K \times N}$。

cuBLAS 根据矩阵尺寸和 GPU 架构选择最优 tiling 配置。例如:

配置 Tile Size Reduction 分块
小矩阵 64×64 K 维分 2 块
大矩阵 128×128 K 维分 4 块

当 batch size 改变时,等效的矩阵尺寸 $M’ = B \times M$ 发生变化,触发不同的 tiling 选择,导致 K 维 reduction 的分块方式不同。

数学表达:设 K 维被分为 $P$ 个块,每块大小 $k_p$:

\[C_{ij} = \sum_{p=1}^{P} \sum_{l \in \text{block}_p} A_{il} B_{lj}\]

浮点加法的顺序取决于 $P$ 和各块的边界划分。不同的 $P$ 产生不同的结果。

Attention

FlashAttention 的核心是 分块计算 + Online Softmax。Softmax 的增量更新公式:

\(m^{new} = \max(m^{old}, m^{(j)})\) \(\ell^{new} = e^{m^{old} - m^{new}} \ell^{old} + e^{m^{(j)} - m^{new}} \ell^{(j)}\) \(O^{new} = \frac{e^{m^{old} - m^{new}} \ell^{old} \cdot O^{old} + e^{m^{(j)} - m^{new}} \ell^{(j)} \cdot O^{(j)}}{\ell^{new}}\)

关键参数是 KV split size:将 KV cache 分成多少块进行增量计算。

Attention Split Size 影响

在 decoding 阶段,FlashAttention 根据 KV cache 长度和 GPU 配置动态选择 split size。不同的 split size 导致不同数量的 rescaling 操作,累积不同的舍入误差。


误差传播:从 ULP 到 Token 分歧

单个 kernel 的数值差异通常在 $10^{-6}$ 到 $10^{-8}$ 量级。如何导致 token 级别的分歧?

误差累积模型

设 Transformer 有 $L$ 层,每层的相对误差为 $\epsilon$。最终 logits 的相对误差约为:

\[\epsilon_{total} \approx L \cdot \epsilon\]

对于 $L = 80$(如 Llama-70B)、$\epsilon = 10^{-7}$:

\[\epsilon_{total} \approx 8 \times 10^{-6}\]

Argmax 的脆弱性

当两个 token 的概率接近时,微小的 logits 差异足以翻转 argmax:

\[\Delta \ell = \ell_1 - \ell_2\]

若 $|\Delta \ell| < \epsilon_{total}$,则结果不稳定。

实际观测表明,在 greedy decoding 中,约 1-5% 的 token 位置存在这种”脆弱”状态。一旦发生分歧,后续生成完全不同,呈现 蝴蝶效应

Token 分歧的蝴蝶效应


解决方案:Batch-Invariant Kernel 设计

设计原则

实现 batch invariance 的核心原则:

  1. 固定 tiling 配置:无论输入尺寸如何,使用固定的 block size 和 grid 配置
  2. 固定 reduction 顺序:确保 reduction 树结构与 batch size 无关
  3. 固定 split size:Attention 中使用固定的 KV split,不随序列长度动态调整

RMSNorm 的 Batch-Invariant 实现

关键修改:强制使用固定的 reduction 分块

# 标准实现(batch-variant)
def rmsnorm_standard(x, gamma, eps):
    # reduction 分块由 CUDA runtime 决定
    rms = torch.sqrt(torch.mean(x ** 2, dim=-1, keepdim=True) + eps)
    return x / rms * gamma

# Batch-invariant 实现
def rmsnorm_batch_invariant(x, gamma, eps, fixed_block_size=256):
    # 强制固定分块
    D = x.shape[-1]
    num_blocks = (D + fixed_block_size - 1) // fixed_block_size

    # 分块累加,固定顺序
    sq_sum = 0.0
    for i in range(num_blocks):
        start = i * fixed_block_size
        end = min(start + fixed_block_size, D)
        sq_sum = sq_sum + torch.sum(x[..., start:end] ** 2, dim=-1, keepdim=True)

    rms = torch.sqrt(sq_sum / D + eps)
    return x / rms * gamma

实际的 CUDA 实现需要确保 warp-level reduction 的顺序固定,通常通过显式的 __shfl_down_sync 序列实现。

MatMul 的 Batch-Invariant 实现

cuBLAS 的自动 tuning 会根据矩阵尺寸选择不同 kernel。解决方案:

  1. 禁用自动 tuning:强制使用固定的 GEMM kernel
  2. Padding 到固定尺寸:将矩阵 pad 到 $2^n$ 大小,确保相同的 tiling
# 使用 torch.Library 替换默认 kernel
import batch_invariant_ops

# 自动替换所有 matmul 为 batch-invariant 版本
# 内部实现固定 tile size = 128x128

Attention 的 Batch-Invariant 实现

关键:固定 KV split size

# FlashAttention batch-invariant 配置
flash_attn_func(
    q, k, v,
    deterministic=True,      # 启用确定性模式
    fixed_split_kv=64        # 固定 KV split 为 64
)

SGLang 的实现支持多种 attention 后端的 batch-invariant 模式:

后端 固定 Split Size 性能开销
FlashInfer 64 ~30%
FlashAttention 3 128 ~25%
Triton 64 ~40%

多 GPU 场景:AllReduce 的确定性

在 Tensor Parallelism 中,AllReduce 操作同样引入非确定性。NCCL 的默认实现使用 ring-based 或 tree-based 算法,reduction 顺序取决于 GPU 间通信延迟。

确定性 AllReduce

解决方案:使用固定顺序的 reduce-scatter + all-gather:

确定性 AllReduce

SGLang 实现了 deterministic tensor parallelism,确保多 GPU 场景下的完全可复现。


MoE 模型的额外挑战

Mixture-of-Experts(MoE)架构引入了 Dense 模型不存在的非确定性来源。以 Qwen3-235B-A22B、DeepSeek-V3 等模型为代表的 MoE 架构,其稀疏激活特性使得确定性推理面临额外挑战。

Token Routing 的非确定性

MoE 的核心是 门控网络(Gating Network),决定每个 token 被路由到哪些 expert:

\[G(x) = \text{TopK}(\text{softmax}(W_g \cdot x))\]

问题在于:当多个 expert 的门控分数接近时,微小的数值扰动可能改变 TopK 的选择结果。

MoE Token Routing 示意

Expert Capacity 与 Token Dropping

为保证计算效率,MoE 通常设置 Expert Capacity:每个 expert 能处理的最大 token 数。当某个 expert 接收的 token 超过容量时,多余的 token 被 丢弃(dropped),直接通过残差连接传递到下一层。

\[\text{Expert Capacity} = \frac{\text{Batch Tokens} \times \text{Capacity Factor}}{\text{Num Experts}}\]

Token dropping 的非确定性来源:

  1. Batch 组成变化:不同 batch 中的 token 分布不同,同一 token 可能在某些 batch 中被处理,在另一些中被丢弃
  2. 路由顺序依赖:当 capacity 接近饱和时,先到达的 token 被处理,后到达的被丢弃
  3. 负载不均衡:热门 expert 更容易触发 dropping

训练-推理不一致

研究发现,MoE 模型在训练和推理阶段的路由行为存在显著差异:

“Even under identical conditions, the routing framework can yield divergent expert selections across repeated forward passes.”

这种不一致在 RL 训练中尤为严重:

MoE 确定性推理的解决方案

1. 固定路由阈值

避免在门控分数接近时产生不稳定决策:

def deterministic_topk(scores, k, margin=1e-5):
    # 当分数差异小于 margin 时,使用固定的 tie-breaking 规则
    sorted_scores, indices = torch.sort(scores, descending=True)

    # 检测 tie 情况
    for i in range(k-1, len(sorted_scores)-1):
        if sorted_scores[i] - sorted_scores[i+1] < margin:
            # 使用 expert index 作为 tie-breaker
            pass

    return indices[:k]

2. 取消 Token Dropping

以计算效率换取确定性:

# 设置足够大的 capacity factor,确保不发生 dropping
config.moe_capacity_factor = 2.0  # 或更高
config.moe_drop_tokens = False

3. Soft MoE

使用软路由替代硬路由,每个 token 以加权方式分配给所有 expert:

\[y = \sum_{i=1}^{E} g_i(x) \cdot \text{Expert}_i(x)\]

Soft MoE 消除了离散的路由决策,但计算开销更高。

对 RL 训练的特殊影响

MoE 模型的 RL 训练面临双重挑战:

  1. 数值非确定性:前述的 batch variance 问题
  2. 结构非确定性:路由决策的不稳定性

研究表明,MoE RL 训练的不稳定性部分源于路由分布的漂移:

“The routing distribution has been identified as a pivotal factor contributing to the instability of MoE RL.”

实验数据显示,约 10% 的 router 在训练和推理间选择不同的 expert,94% 的 token 至少在一层选择了不同的 expert。

Routing Replay:R2 与 R3

为解决训练-推理路由不一致问题,研究者提出了 Routing Replay 机制,核心思想是在训练时重放推理阶段的路由决策。

R2:Vanilla Routing Replay

定义:重用 训练系统 在 rollout 阶段选择的 expert。

Rollout (Training System) → 记录路由决策 → Training 时重放

R3:Rollout Routing Replay

定义:重用 推理系统 在 rollout 阶段选择的 expert。

Rollout (Inference System) → 记录路由决策 → Training 时重放

R3 强制约束:在 rollout 阶段激活的特定 expert 必须在训练反向传播时严格重用。

R2 与 R3 对比

选择 R2 还是 R3?

场景 推荐方案 原因
Off-policy 程度小 R2 R3 对目标策略的改变代价大于收益
Off-policy 程度大 R3 保持一阶近似的有效性更重要

实现细节

R3 可与 KV Cache 集成:

# 对于每层每个 token prefix,存储对应的路由 mask
routing_cache = {}

def forward_with_replay(x, layer_idx, prefix_hash):
    if prefix_hash in routing_cache:
        # 命中缓存,重用路由决策
        mask = routing_cache[prefix_hash]
    else:
        # 计算新路由
        mask = compute_routing(x)
        routing_cache[prefix_hash] = mask

    # 使用 mask 进行 softmax gating,但不阻断梯度流
    return apply_routing(x, mask, allow_grad=True)

关键点:重放的 mask 用于 softmax gating 计算,但不阻止梯度流经标准 router 权重,确保 router 仍可训练。

其他解决方案

RSPO(Router-Shift Policy Optimization)

不同于 R2/R3 的硬约束,RSPO 采用软调整机制:

\[w_{rspo} = w_{is} \cdot \text{clip}(\text{router\_shift\_ratio}, 1-\epsilon, 1+\epsilon)\]

冻结 Router

最简单的方案是冻结 router 参数,但会损害模型适应性,通常不推荐。


性能分析

Batch-invariant kernels 的主要开销来源:

  1. 放弃动态优化:无法使用针对特定尺寸的最优 kernel
  2. 固定 tiling 的低效:小矩阵使用大 tile 造成资源浪费
  3. 额外的同步开销:确保固定执行顺序需要更多同步点

基准测试

方案 吞吐量 (tokens/s) 相对开销
标准 vLLM 1000 baseline
TML batch_invariant_ops 385 61.5%
SGLang + CUDA Graphs 657 34.3%

CUDA Graphs 通过预编译执行图,消除了 kernel launch 开销,显著减少了确定性模式的性能损失。

延迟分布

确定性模式的另一个优势是 延迟方差降低

标准模式:   P50=45ms, P99=120ms, stddev=25ms
确定性模式: P50=52ms, P99=58ms,  stddev=3ms

对于延迟敏感的应用,更低的方差可能比更低的均值更重要。


应用场景

RL 训练的可复现性

在 RLHF/RLVR 训练中,策略的 rollout 需要与训练步骤精确对应。非确定性推理导致:

  1. 调试困难:无法复现特定的失败案例
  2. 训练不稳定:相同 checkpoint 在不同机器上表现不一致
  3. 实验不可比较:无法区分算法改进和随机波动

SGLang 与 slime 的合作实现了 100% 可复现的 RL 训练:

“Taking this deterministic inference capability further, SGLang collaborated with the slime team to unlock 100% reproducible RL training.”

安全与合规

对于需要审计的 AI 系统,确定性行为是基本要求:

非确定性意味着无法追溯和解释特定输出的来源。

模型调试

当模型出现异常输出时,确定性推理允许:

  1. 精确复现问题
  2. 逐层检查中间状态
  3. 二分定位问题来源

相关工作

LayerCast(NeurIPS 2025)

Yuan et al. 提出了另一种思路:通过提高数值精度减少误差累积。

实验显示,LayerCast 将 DeepSeek-R1-Distill-Qwen-7B 的准确率波动从 9% 降低到 2%,但仍非完全确定。

OpenAI seed 参数

OpenAI API 提供 seed 参数以提高可复现性:

“If specified, our system will make a best effort to sample deterministically…”

但官方明确表示 不保证确定性,原因包括:

  1. 后端模型更新
  2. 负载均衡到不同硬件
  3. 系统配置变化

system_fingerprint 字段用于追踪配置变化,但无法保证相同 fingerprint 下的完全确定性。


总结

LLM 推理的非确定性源于 kernel 实现对 batch size 的敏感性,而非 GPU 的并发特性。通过设计 batch-invariant kernels,可以在工程层面实现完全确定的推理。

Dense 模型的关键技术点

  1. 固定 RMSNorm 的 reduction 分块
  2. 固定 MatMul 的 tiling 配置
  3. 固定 Attention 的 KV split size
  4. 多 GPU 场景使用确定性 AllReduce

MoE 模型的额外挑战

  1. Token routing 的离散决策在门控分数接近时不稳定
  2. Expert capacity 和 token dropping 引入 batch 依赖的非确定性
  3. 训练-推理路由不一致需要 Routing Replay(R2/R3)机制

性能代价约 30-60%,但在 RL 训练、模型调试、安全审计等场景中是必要的投入。


参考文献

[1] Thinking Machines Lab. Defeating Nondeterminism in LLM Inference. 2025.

[2] Yuan, J. et al. Understanding and Mitigating Numerical Sources of Nondeterminism in LLM Inference. NeurIPS 2025 (Oral).

[3] LMSYS Org. Towards Deterministic Inference in SGLang and Reproducible RL Training. 2025.

[4] Thinking Machines Lab. batch_invariant_ops. GitHub.

[5] vLLM Documentation. Batch Invariance.

[6] Dao, T. et al. FlashAttention-2: Faster Attention with Better Parallelism and Work Partitioning. 2023.

[7] Ma, W. et al. Stabilizing MoE Reinforcement Learning by Aligning Training and Inference Routers. 2025.

[8] Towards Stable and Effective Reinforcement Learning for Mixture-of-Experts. arXiv 2025.

← Back to Home

Comments