llama.cpp 的粒子散射采样器

Reddit r/LocalLLaMA 工具

摘要

本文介绍了一个 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 自适应强度的下限
查看原文

相似文章

ggml-org/llama.cpp

GitHub Trending (daily)

llama.cpp 是一个开源 C/C++ 库,用于在本地硬件上高效运行 LLM 推理,支持多种量化方法和多后端(CPU、GPU 等)。

这是我的 llama.cpp NVFP4/MXFP6 GGUF 量化工具

Reddit r/LocalLLaMA

作者介绍了一款开源的 GGUF 量化工具,用于 llama.cpp,能够创建 NVFP4 和 MXFP6 量化模型,并采用 RSF、张量提升、动态量化等先进技术,质量优于现有方法(如 ModelOpt)。