Wink Pings

Temperature=0 也不确定?同一个 prompt 跑 1000 次,出了 80 种答案

Temperature 0 在 LLM 推理中不保证确定性。Thinking Machines 实测 Qwen3-235B:同一 prompt 跑 1000 次,得到 80 个不同输出。问题不在 argmax,在 GPU 浮点加法顺序——batch size 一变,logits 微变,输出分叉。

Temperature 0 常被当成 LLM 的确定性开关。推理引擎在 temperature 0 时切换为贪心解码,每一步挑 logit 最大的 token。同一个 prompt,理论上每次输出都一样。

实际上不是。Avi Chawla 最近在 X 上拆解了这个问题。Thinking Machines 做过一个实测:把 "Tell me about Richard Feynman" 发给 Qwen3-235B,temperature 0,重复 1000 次,得到 80 个独特输出。

argmax 本身是确定的。变量出在 logits 的计算上——如果数值差一点点,argmax 就可能换一个 token。

浮点加法:顺序决定结果

GPU 用有限精度存数字。fp16 只有 11 个有效位,数字落在 1024 到 2048 之间时,小数点后没有任何空间。1024.4 被舍回 1024。

算 1024 + 0.4 + 0.4:

从左到右:1024 + 0.4 舍回 1024,再加 0.4 还是 1024。

先加小的:0.4 + 0.4 = 0.8,1024 + 0.8 舍入到 1025。

LLM 每次前向传播有几十亿次这样的加法。顺序一变,logits 跟着微变。

顺序为什么会变?

最常见的猜测是 GPU 并行线程完成顺序不可预测。不准确。典型前向传播的 kernel 按固定顺序计算,相同输入、相同 batch size 的矩阵乘法结果逐位一致。

真正的原因是服务器上还有其他请求。

推理服务器把多个用户的请求拼成 batch 一起跑。kernel 根据 batch 大小决定如何拆分工作:

  • batch 大:每个 GPU 核都忙,一次算完。
  • batch 小:核闲着,kernel 把长求和切块,分散到各核,最后合并。

拆分方式改变,加法顺序就变。batch 大小由那一刻有多少其他用户在用服务器决定。

微小差异翻转整个答案

同一 prompt 跑两次:

batch 8 时:Queens = 12.3417,New = 12.3415。argmax 选 Queens。

batch 32 时:Queens = 12.3414,New = 12.3416。argmax 选 New。

只有 logits 接近平局时才翻转。翻转后每个 token 都在不同前缀上生成,输出从此分叉。

Thinking Machines 测试中,1000 次运行前 102 个 token 一致。第 103 个 token,992 次输出 "Queens, New York",8 次输出 "New York City"。

解决方案:batch-invariant kernels

让 kernel 的拆分方式与 batch size 无关,比如 attention 固定 chunk size,哪怕牺牲并行度。Thinking Machines 测试后,1000 次运行完全一致。

代价是速度。Qwen3-8B 上,默认 vLLM 处理 1000 个请求 26 秒,确定性版本 55 秒,优化 attention kernel 后 42 秒。

问题不止 batch

评论区有人补充了多 GPU 场景的额外变量:NCCL all-reduce 的算法选择依赖消息大小,而消息大小由 batch size 决定;MoE 模型通过原子操作把 token 分发给专家,warp 调度竞态影响到达顺序;PagedAttention 的缓存块边界改变 reduction 树结构。

有人注意到一个更隐蔽的问题:缓存命中也会改变求和拆分方式。这意味着跑两次同样的 prompt 验证稳定性,第二次运行的条件已经被第一次改变了。

有网友的结论比较实际:要么付约 2 倍延迟换确定性内核,要么接受不确定性,把 eval 固定到专用副本上。

发布时间: 2026-10-27 03:07