本文档介绍了 llama.cpp 中的 token 采样系统,该系统负责根据模型的输出 logits(对数概率)在文本生成过程中选择下一个 token。Token 采样是直接影响生成文本质量、多样性和特性的关键组成部分。
有关模型加载和推理执行的信息,请参阅 上下文管理和推理。有关语法约束生成的详细信息,请参阅 语法约束生成。
llama.cpp 中的 token 采样系统遵循分层架构,具有多种采样算法,可以组合成采样链。该系统既提供了低级别的 llama_sampler 接口,也提供了一个更高级别的 common_sampler 包装器。
来源:src/llama-sampling.cpp1-2500 common/sampling.cpp103-131 common/sampling.h35-50
来源:src/llama-sampling.cpp379-409 common/sampling.cpp338-382 src/llama-sampling.cpp430-438
llama_sampler 接口提供了一个基于插件的架构,其中单个采样算法实现了通用接口。每个采样器都可以修改 token 概率分布并选择 token。
核心接口由 llama_sampler_i 结构体定义
来源:src/llama-sampling.cpp320-377 src/llama-sampling.cpp547-554 src/llama-sampling.cpp679-686
llama_token_data_array 结构体是在采样器之间传递的核心数据类型
| 字段 | 类型 | 目的 |
|---|---|---|
data | llama_token_data* | token 候选列表 |
size | size_t | 候选数量 |
selected | int32_t | 选定 token 的索引(无则为 -1) |
sorted | bool | 列表是否按 logit 排序 |
每个 llama_token_data 包含:
id: Token 标识符logit: 来自模型的原始 logit 值p: 概率(通过 softmax 计算)来源:src/llama-sampling.cpp379-409 tests/test-sampling.cpp15-19
贪心采样总是选择概率最高的 token。它是确定性的,提供最有可能的续写。
来源:src/llama-sampling.cpp534-545 src/llama-sampling.cpp556-561
Top-K 采样将候选 token 限制为概率最高的 K 个,然后从这个缩减的集合中进行采样。
当 k > 128 时,该实现对大型词汇表使用了优化的桶排序。
来源:src/llama-sampling.cpp228-303 src/llama-sampling.cpp665-668 src/llama-sampling.cpp688-695
Top-P 采样从累积概率超过阈值 P 的最小 token 集合中进行选择。
来源:src/llama-sampling.cpp708-734 src/llama-sampling.cpp754-762
Min-P 采样通过将概率低于 p * p_max 的 token 移除,其中 p_max 是最高的 token 概率。
来源:src/llama-sampling.cpp775-830 src/llama-sampling.cpp850-858
温度缩放通过将 logit 除以温度来调整概率分布的“锐度”。
temp = 0.0: 贪心(确定性)temp = 1.0: 分布不变temp > 1.0: 更随机(更平坦的分布)temp < 1.0: 随机性更小(更尖锐的分布)来源:src/llama-sampling.cpp179-201 src/llama-sampling.cpp969-972
DRY 采样通过降低导致重复序列出现的 token 的概率来惩罚重复序列。
来源: common/sampling.cpp234-244 tests/test-sampling.cpp161-182
采样器链允许按顺序应用多个采样算法。链中的每个采样器都会修改 token 概率分布,而最后一个采样器通常执行实际的 token 选择。
常见的采样链模式
| Mirostat | 标准链 |
|---|---|
temp → mirostat_v2 | penalties → dry → top_k → top_p → min_p → temp → dist |
来源: common/sampling.cpp225-287 src/llama-sampling.cpp482-527
当对链调用 llama_sampler_apply() 时,它会遍历所有采样器
来源: src/llama-sampling.cpp430-438 src/llama-sampling.cpp494-497
common_sampler 提供了一个更高级的接口,增加了语法支持、性能跟踪和 token 历史管理。
来源: common/sampling.cpp103-131 common/sampling.h35-50
common_sampler_sample() 函数实现了用于语法集成的两阶段采样方法
来源: common/sampling.cpp338-382 common/sampling.h58-61
采样系统支持两种类型的语法约束
使用 GBNF(Backus-Naur 形式的语法)进行结构化输出生成。
来源: common/sampling.cpp206-214
当使用 LLAMA_USE_LLGUIDANCE 编译时,支持更高级的语法系统。
来源: common/sampling.cpp157-164 common/sampling.h106-107
k > 128 时,使用优化的桶排序代替部分排序来源: src/llama-sampling.cpp248-298 common/sampling.cpp10-101
采样系统包含内置的性能跟踪功能
来源: src/llama-sampling.cpp421-428 common/sampling.cpp327-336
用于投机解码以进行草稿 token 验证
来源: examples/speculative/speculative.cpp240-416
多个独立的采样上下文,用于并发生成
来源: examples/parallel/parallel.cpp222-227 examples/parallel/parallel.cpp423-425