llama.cpp 的粒子散射采样器
摘要
本文介绍了一个 llama.cpp 的实验性采样器,名为 'scatter',它对按等级排序的令牌应用局部扩散,以平滑顶级候选之间的概率分布,从而在不增加尾部概率的情况下实现更具创造性的文本生成。
https://github.com/IceFog72/llama.cpp 我在 llama.cpp 中添加了一个名为 scatter 的实验性采样器。简而言之:它在已经选定的顶级候选内部轻微平滑模型的下一个令牌概率分布。它的目的是使生成过程更灵活,而不必像通常那样“提高温度并唤醒垃圾尾部”。它借用了光散射的隐喻,但实现并非真正的物理模拟。实际操作要简单得多:对令牌等级进行廉价的局部扩散/移动平均步骤。将模型的下一个令牌分布想象成一束光。最强候选为等级 1,次强为等级 2,依此类推。scatter 允许相邻等级交换少量概率质量。等级 1 可以将一些质量分给等级 2、3、4 等。等级 5 可以与相邻等级交换。但它不会将随机的深层尾部令牌引入。这就是关键:展平分布的头部,而不会将概率泄漏到深层尾部。
状态:已实现并作为 llama.cpp 的实验性采样器进行了测试。当前实现的内容:
原生采样器 API:
llama_sampler_init_scatter(...)
llama_sampler_init_scatter_ext(...)
采样链名称:scatter
采样链字符:r
包含在 xtc 和 temperature 之间的默认采样链中
默认禁用:使用默认参数返回一个空操作采样器
固定散射强度
可选的自适应强度(使用熵反馈)
可选的重复令牌吸收
可选的碰撞/平均自由程门控
tests/test-sampling.cpp 中的不变性测试
它试图解决什么问题?
温度是生硬的。如果你提高温度,你会展平整个分布。这可以使模型更具创造性,但也会给弱的尾部令牌更多的概率。有时这没问题。有时会导致奇怪的词语选择、格式错误、错误的标识符或不连贯的跳跃。scatter 更加局部化。它只在前面的采样器已经过滤分布后,在选定的 top-K 候选集内操作。因此,如果 top-k、top-p、min-p、XTC 等已经移除了不良候选,scatter 只重塑幸存者。所以,它不做的是:“让一切更随机,包括尾部。”它做的是:“取最强的幸存候选,并局部软化相邻等级之间的差异。”
工作原理
采样器在前面的采样器已经定义了候选“介质”后运行。推荐顺序:
penalties -> dry -> top_n_sigma -> top_k -> typ_p -> top_p -> min_p -> xtc -> scatter -> temperature -> dist
因此,当 scatter 运行时,候选列表已经被常规采样器过滤。每个生成的令牌,它执行以下操作。
1. 碰撞门控
首先,scatter 可能决定不对该令牌做任何操作。标志为:
--scatter-collision N
默认:--scatter-collision 1.0
当 collision = 1.0 时,每个令牌都进行散射。
当 collision = 0.25 时,只有大约 25% 的时间触发散射。
这使得平均自由程大约为 4 个令牌。
如果不触发散射,采样器将完全不对候选做任何操作:
不排序
不截断
不重新归一化
不回写
如果你希望偶尔出现更强的“偏转”而不是持续微弱的平滑,这很有用。
2. 等级空间扩散
采样器取前 k 个幸存候选,按 logit 排序,并 softmax 为概率。然后它在等级距离上应用局部高斯平滑核:
K_ij = exp(-((i - j)^2) / (2 * radius^2))
q_i = sum_j K_ij * p_j / sum_j K_ij
通俗地说:
等级接近的令牌共享更多概率
等级相距较远的令牌共享很少或没有
等级距离重要,而不是令牌含义
核按行归一化,因此概率质量保持可控
然后直接分布和散射分布混合:
p_i = normalize((1 - strength) * p_i + strength * q_i)
因此:
strength = 0.0 表示无散射
strength = 0.1 表示大部分原始分布,轻微平滑
strength = 0.3 表示更强的局部展平
核仅依赖于等级距离,因此计算一次并缓存。
采样器还可以多次重复此扩散步骤:
--scatter-steps N
粗略地说,多个步骤类似于更宽的模糊:n 步 ≈ 半径为 radius * sqrt(n) 的一步。因此通常应保持步骤数较低。
3. 自适应强度
还有一个可选的自适应模式:
--scatter-adaptive
它使用当前 top-K 分布的归一化熵:
H_norm = -sum_i p_i * log(p_i) / log(K)
解释:
H_norm = 0.0 -> 非常尖锐的分布
H_norm = 1.0 -> 非常分散的分布
然后采样器将该熵与目标比较:
--scatter-entropy-target 0.55
如果分布比目标更尖锐,采样器会增加有效散射强度。
如果分布已经分散,它会降低有效散射强度。
概念上:
H_norm < target: 尖锐光束 -> 更密集介质 -> 更强散射
H_norm > target: 分散 -> 更稀薄介质 -> 更弱散射
自适应强度被限制在:
--scatter-strength-min N
--scatter-strength-max N
示例:
--scatter-adaptive \
--scatter-strength 0.14 \
--scatter-strength-min 0.02 \
--scatter-strength-max 0.30 \
--scatter-entropy-target 0.55
重要提示:自适应模式在模型自信时推高强度。这是故意的,精神上与 XTC 类似,但自信的分布往往有充分的理由。这可能适合创意散文,但对于代码、数学、JSON、精确名称和严格指令遵循有风险。
4. 可选重复令牌吸收
有一个可选的重复相关功能:
--scatter-absorption N
--scatter-absorption-last-n N
如果令牌最近出现,它可以失去一些散射质量:
p_i *= exp(-absorption * repeat_count_i)
这并不意味着取代常规重复惩罚或 DRY。它是一个仅限于 top-K 散射介质的软性额外效果。你可以将其视为仅应用于当前在介质中的候选的小频率惩罚。谨慎使用。强吸收可能损害:
名称
风格标记
对话
标点
有意重复
重复的结构令牌
精确格式
一个较轻的值更安全:
--scatter-absorption 0.06
--scatter-absorption-last-n 64
5. 回写
散射后,最终概率转换回 logit:
log(max(p_i, eps))
然后候选列表被截断为 top-K 介质。因此,当散射触发时,只保留前 --scatter-k 个候选。
重要行为:顺序稳定性
scatter 被设计为顺序稳定的。行归一化高斯核保持排序分布的等级顺序,直到浮点噪声。因此,如果顶级令牌在散射前是等级 1,那么在散射后它应该仍是等级 1。这意味着:
argmax 被保留
贪婪解码不受影响
采样器不会激进地重新排序候选
它主要软化相邻等级之间的概率差距
有意的例外是吸收。如果启用重复令牌吸收,重复令牌可能会降级。这是与温度的主要区别之一。温度可以提升深层尾部令牌。scatter 仅在选定的 top-K 介质内局部移动概率。
测试
tests/test-sampling.cpp 检查:
顺序稳定性
argmax 保留
归一化
截断
collision-0 空操作行为
合成分布上的吸收行为
CLI 参考
标志 默认值 含义
--scatter-k N 64 Top-K 散射介质。这些是参与散射的候选。触发散射时也截断为此大小。
--scatter-strength N 0.0 原始分布和散射分布之间的混合。0.0 表示禁用。
--scatter-radius N 2.5 高斯等级半径。更高意味着概率在更宽的等级邻域内移动。
--scatter-steps N 1 重复扩散次数。
--scatter-adaptive off 启用熵反馈强度。
--scatter-strength-min N 0.02 自适应强度的下限
相似文章
扩展想法:llama-server 与自定义采样器
一个为 llama-server 设计的原型扩展,支持自定义采样逻辑,并附带一个循环检测器示例,无需维护独立分支。
ggml-org/llama.cpp
llama.cpp 是一个开源 C/C++ 库,用于在本地硬件上高效运行 LLM 推理,支持多种量化方法和多后端(CPU、GPU 等)。
这是我的 llama.cpp NVFP4/MXFP6 GGUF 量化工具
作者介绍了一款开源的 GGUF 量化工具,用于 llama.cpp,能够创建 NVFP4 和 MXFP6 量化模型,并采用 RSF、张量提升、动态量化等先进技术,质量优于现有方法(如 ModelOpt)。
在树莓派上使用 llama.cpp
关于使用 llama.cpp 在树莓派设备上运行大型语言模型进行本地推理的指南。
LlamaStation v0.9——面向Windows的llama.cpp图形界面,支持多后端、TurboQuant、MTP等
LlamaStation v0.9 是 llama.cpp 的 Windows 图形界面,提供简洁的界面和完整的参数控制,支持多个后端(官方、TurboQuant、AtomicChat、BeeLlama),实时显存监控、模型专属配置文件、语音模式和无头模式,所有这些都不需要像 Ollama 这样的中间层。