SamplingParams¶
约 614 个字 11 行代码 预计阅读时间 2 分钟
sampling_params.py 定义了采样参数 dataclass,绑定到每个 Sequence 上控制生成行为。三个字段:temperature 控制随机性,max_tokens 限制生成长度,ignore_eos 决定是否忽略结束符。
为什么叫 sampling?¶
模型前向传播后输出的不是「下一个 token 是什么」,而是一个长度为 vocab_size 的 logits 向量,经过 softmax 后变成词表上的概率分布。从概率分布中随机抽取一个具体 token 的动作,在概率论里就叫 sampling(采样)。
LLM:从已知分布中直接抽取
模型输出 logits → softmax 得到具体长度(vocab_size)的离散概率分布。这个分布是显式的、确定的,你能看到每个 token 的确切概率。Sampler 做的就是从这个分布里按概率随机抽一个结果,一步完成,拿到的是一个具体 token。
Diffusion:通过迭代去噪逼近分布
模型不输出概率分布,它输出的是噪声预测(score function,即 \(\nabla_x \log p(x)\))。你看不到「这张图的概率是多少」,你只知道「往哪个方向走能让图更真实」。Sampling 从纯高斯噪声出发,每一步都用这个 score 去一点噪声,走几十到上千步,最终收敛到数据分布中的一张干净图片。整个过程是在连续空间 \(\mathbb{R}^d\) 中沿一条轨迹移动,不是从分布里直接抽。
Temperature¶
Temperature 只做一件事:控制 softmax 前 logits 的缩放比例,从而改变离散概率分布的熵。
- Temperature 在 softmax 之前把 logits 除以自己:\(logits / T\)
- T 小 → logits 被放大 → softmax 后高分的 token 概率更高、低分的更低 → 分布尖锐 → 模型「更自信」,几乎总选那几个头部 token
- T 大 → logits 被压缩 → 高分和低分的差距缩小 → 分布平坦 → 模型「更犹豫」,尾部 token 也有机会被抽到
在 nanovllm/layers/sampler.py 中:
假设模型输出的 logits 是:
Temperature = 1(正常)
logits 不变,softmax 后:
Top-3 就能拿走 66% 的概率。
Temperature = 2(高温 → 更平坦)
logits 除以 2:[1.0, 0.5, 0.25, 0.15, 0.05, -0.25],softmax 后:
Top-3 只能拿走 59%,你需要 Top-5 才能拿到 81%。
Temperature = 0.5(低温 → 更尖锐)
logits 除以 0.5:[4.0, 2.0, 1.0, 0.6, 0.2, -1.0],softmax 后:
Top-1 就拿走了 64%,Top-3 基本已是全部。
Source Code¶
from dataclasses import dataclass
@dataclass(slots=True)
class SamplingParams:
temperature: float = 1.0
max_tokens: int = 64
ignore_eos: bool = False
def __post_init__(self):
assert self.temperature > 1e-10, "greedy sampling is not permitted"
Last update: May 5, 2026
Discussion