引言:模型输出的真正面目
当你在ChatGPT中输入一个问题,屏幕上逐字显现答案时,你是否想过:模型内部发生了什么?它是如何决定下一个词的?
很多人以为大语言模型直接输出文字,这是一个普遍的误解。事实上,模型的输出是一个由数万个数字组成的向量——每个数字对应词表中的一个词,代表该词成为"下一个词"的原始分数。这个分数,在技术术语中被称为Logit。
理解从Logit到最终文字的完整链路,是掌握大模型工作原理的关键。这条链路涉及概率转换、采样策略、参数调控等多个环节,每个环节都蕴含着深刻的设计哲学和工程权衡。
一、Logits:模型输出的"原始语言"
1.1 什么是Logits
假设一个模型的词表大小为50,000(这在现代大模型中并不算大),那么对于每一次预测,模型都会输出50,000个数值,每个数值对应词表中的一个词。
这些数值有什么特点?最关键的一点是:它们不是概率。
Logits可以是负数,可以大于1,也可以是任何实数。它们之间没有固定的和,也没有固定的范围。它们只是模型对每个词的"偏爱程度"——分数越高,模型越倾向于选择这个词。
以GPT-2为例,当输入"I have a dream"时,模型对下一个词的预测可能如下:
| Token | Logit | 说明 |
|---|---|---|
| of | 2.85 | 最高分 |
| that | 1.92 | 次高分 |
| . | 1.45 | 句号也很有可能 |
| a | 0.87 | 继续添加内容 |
| the | -0.23 | 可能性较低 |
| banana | -5.67 | 几乎不可能 |
1.2 Logits从何而来
Logits的生成过程涉及Transformer架构的核心机制。简单来说:
flowchart LR
A[输入文本] --> B[Tokenization<br/>分词]
B --> C[Token Embedding<br/>词嵌入]
C --> D[Positional Encoding<br/>位置编码]
D --> E[Transformer Layers<br/>多层注意力]
E --> F[Linear Layer<br/>线性层]
F --> G[Logits<br/>原始分数]
模型的最后一层是一个简单的线性层,将Transformer输出的隐藏状态映射到词表大小的维度。这个线性层的权重矩阵形状为 [hidden_size, vocab_size],其中vocab_size可能达到数万甚至数十万。
一个有趣的细节:许多模型采用"权重共享"(Weight Tying)技术,让词嵌入层和输出层共享相同的权重。这不仅减少了参数量,还能提升模型性能——因为"理解一个词"和"预测一个词"本质上是相关联的任务。
二、Softmax:从原始分数到概率分布
2.1 为什么需要Softmax
Logits虽然表示了模型的偏好,但它有几个问题:
- 不可解释:一个Logit为2.85到底意味着什么?我们无法直观理解
- 不可比较:不同时刻、不同上下文下的Logits范围可能完全不同
- 不可采样:我们无法直接从Logits中随机选择
Softmax函数解决了这些问题,将Logits转换为概率分布。
2.2 Softmax的数学原理
Softmax的定义如下:
$$\text{softmax}(x_i) = \frac{e^{x_i}}{\sum_{j} e^{x_j}}$$对于词表中的每个词,我们计算其Logit的指数,然后除以所有词Logit指数的和。这个操作有三个重要性质:
- 非负性:指数函数保证结果始终为正
- 归一化:所有概率之和为1
- 保序性:Logit越高的词,概率也越高
让我们用之前的例子:
| Token | Logit | $e^{\text{logit}}$ | Probability |
|---|---|---|---|
| of | 2.85 | 17.29 | 68.6% |
| that | 1.92 | 6.82 | 25.3% |
| . | 1.45 | 4.26 | 5.6% |
| a | 0.87 | 2.39 | 0.5% |
| … | … | … | … |
现在,“of"有68.6%的概率成为下一个词,这个结果直观且可解释。
2.3 Softmax的计算复杂度
对于词表大小为$V$的模型,Softmax需要计算$V$个指数函数和一次求和。当$V$很大时(如GPT-4的词表约10万),这个计算并不廉价。
实践中,许多优化技术被采用:
- 分层Softmax:将词表组织成树结构,将复杂度从$O(V)$降到$O(\log V)$
- 自适应Softmax:根据词频将词表分成多个簇,高频词更容易被访问
- 采样估计:训练时使用采样方法近似计算完整的Softmax
三、解码策略:从概率到选择的博弈
有了概率分布,下一个问题就是:如何从中选择一个词?这就是解码策略的核心。
flowchart TB
subgraph 输入
A[概率分布 P]
end
subgraph 确定性方法
B[贪婪搜索]
C[束搜索]
end
subgraph 随机采样
D[Temperature采样]
E[Top-K采样]
F[Top-P采样]
G[Min-P采样]
end
subgraph 高级方法
H[对比解码]
I[典型采样]
J[Mirostat]
end
A --> B
A --> C
A --> D
A --> E
A --> F
A --> G
A --> H
A --> I
A --> J
B --> K[输出Token]
C --> K
D --> K
E --> K
F --> K
G --> K
H --> K
I --> K
J --> K
3.1 确定性解码:贪婪搜索
贪婪搜索(Greedy Search) 是最简单直接的方法:每次选择概率最高的词。
$$w_t = \arg\max_{w} P(w | w_1, ..., w_{t-1})$$这种方法简单高效,但有一个致命缺陷:短视。它只考虑当前最优,而不考虑整体序列质量。
举个例子,假设模型要续写"The capital of France is”:
- 贪婪搜索可能输出:“Paris. The capital of France is Paris. The capital…”
- 更好的输出应该是:“Paris, a city known for…”
为什么会这样?因为"Paris"后面接"句号"在训练数据中很常见,而句号后接"The"也很常见,从而形成重复循环。
3.2 确定性解码:束搜索
束搜索(Beam Search) 是贪婪搜索的改进版本。它不是每次只保留一个候选,而是保留$k$个最有可能的序列(称为"束"),在最后选择整体得分最高的序列。
flowchart TD
subgraph Step1["时刻 t=1"]
A1["输入: The capital of France is"]
B1["候选: Paris (0.72), the (0.15), located (0.08)"]
end
subgraph Step2["时刻 t=2"]
A2["Paris → 句号 (0.31), , (0.28)"]
B2["the → capital (0.45)"]
C2["located → in (0.67)"]
end
subgraph Step3["时刻 t=3"]
A3["Paris, → a (0.22)"]
B3["Paris. → The (0.18)"]
C3["located in → Paris (0.89)"]
end
Step1 --> Step2 --> Step3
束搜索的优势在于能够考虑更长的上下文依赖,但它仍然有两个问题:
- 计算开销:需要维护$k$条序列,计算量是贪婪搜索的$k$倍
- 重复问题:研究(Holtzman et al., 2020)表明,束搜索容易产生"神经文本退化"——生成重复、空洞的文本
3.3 随机采样的哲学
确定性方法的问题促使研究者转向随机采样:从概率分布中随机选择,而不是确定性地选择最高概率。
这背后的哲学是深刻的:人类语言本身就具有随机性和多样性。如果问十个人"The capital of France is"后面接什么,他们可能给出略有不同的答案。模型应该模拟这种多样性。
随机采样的核心是:概率越高的词,被选中的可能性越大,但不是必然被选中。
3.4 Temperature:控制"创意"的旋钮
Temperature(温度) 是控制采样随机性的核心参数。它通过调整Softmax的计算方式来改变概率分布:
$$\text{softmax}(x_i) = \frac{e^{x_i / T}}{\sum_{j} e^{x_j / T}}$$温度$T$的作用可以形象地理解为"对比度调节":
flowchart LR
subgraph 低温["低温 T=0.2"]
A1["of: 99.3%"]
B1["that: 0.7%"]
C1["其他: ~0%"]
end
subgraph 中温["中温 T=1.0"]
A2["of: 68.6%"]
B2["that: 25.3%"]
C2[".: 5.6%"]
end
subgraph 高温["高温 T=2.0"]
A3["of: 42.1%"]
B3["that: 31.2%"]
C3[".: 18.5%"]
D3["a: 8.2%"]
end
- 低温度(T < 1):增强对比度。高概率词变得更突出,低概率词更加被抑制。极端情况下$T \to 0$,结果退化为贪婪搜索。
- 高温度(T > 1):降低对比度。概率分布变得更加平坦,低概率词有更多机会被选中。极端情况下$T \to \infty$,分布变为均匀随机。
| Token | 原始概率 (T=1.0) | T=0.5 | T=2.0 |
|---|---|---|---|
| of | 68.6% | 92.8% | 42.1% |
| that | 25.3% | 6.8% | 31.2% |
| . | 5.6% | 0.4% | 18.5% |
| a | 0.5% | ~0% | 8.2% |
温度的命名源自统计物理学中的玻尔兹曼分布,其中温度参数控制粒子能量状态的分布——这是一个深刻的数学类比。
3.5 Top-K采样:固定数量的候选池
Top-K采样是2018年由Fan等人提出的经典方法。它的核心思想很简单:只从概率最高的$K$个词中采样,其余全部排除。
def top_k_sampling(probs, k):
# 获取概率最高的k个词的索引
top_k_indices = np.argsort(probs)[-k:]
# 其他词概率设为0
filtered = np.zeros_like(probs)
filtered[top_k_indices] = probs[top_k_indices]
# 重新归一化
return filtered / filtered.sum()
Top-K的优点是简单直观,但它有一个根本缺陷:$K$是固定的,但模型的"置信度"是变化的。
考虑两种场景:
- “The capital of France is __":只有"Paris"是合理的,此时$K=10$太大
- “My favorite food is __":可能有数百种合理答案,此时$K=10$太小
一个固定的$K$无法适应这种变化。
3.6 Top-P采样(Nucleus Sampling):动态候选池
2020年,Holtzman等人在论文《The Curious Case of Neural Text Degeneration》中提出了Nucleus Sampling(核采样),也称为Top-P采样。
核心思想是:不固定候选词数量,而是固定候选词的累计概率。具体做法是:
- 将词按概率降序排列
- 累加概率,直到总和达到阈值$p$(如0.9)
- 只从这个"核"中采样
flowchart LR
subgraph 排序后["按概率排序"]
A["Paris: 0.72"]
B["the: 0.15"]
C["located: 0.08"]
D["known: 0.03"]
E["..."]
end
subgraph 累计["累计概率计算"]
F["0.72"]
G["0.72 + 0.15 = 0.87"]
H["0.87 + 0.08 = 0.95 ✓"]
end
排序后 --> 累计
当$p=0.9$时,只需要前三个词(Paris, the, located)就能覆盖90%的概率质量。这种方法的关键优势是自适应性:
- 当模型很确定时(如预测"Paris”),候选池可能只有1-2个词
- 当模型不确定时,候选池会自动扩大,包含更多可能的选择
3.7 Min-P采样:置信度感知的截断
2025年,Nguyen等人在ICLR会议上发表的论文提出了Min-P采样,这是一种更加智能的动态截断方法。
Min-P的核心洞察是:截断阈值应该与模型对最可能词的置信度成比例。
$$\text{threshold} = p_{\max} \times \rho$$其中$p_{\max}$是最高概率词的概率,$\rho$是Min-P参数(通常设为0.05-0.1)。
flowchart TB
subgraph 高置信度场景["高置信度场景: max_p = 0.90"]
A1["阈值 = 0.90 × 0.1 = 0.09"]
B1["只有高概率词通过"]
C1["输出更加确定"]
end
subgraph 低置信度场景["低置信度场景: max_p = 0.15"]
A2["阈值 = 0.15 × 0.1 = 0.015"]
B2["更多词通过筛选"]
C2["输出更多样"]
end
高置信度场景 --> 结果
低置信度场景 --> 结果
结果["Min-P自适应调整"]
def min_p_sampling(probs, min_p=0.1):
# 计算动态阈值
threshold = np.max(probs) * min_p
# 低于阈值的词概率设为0
filtered = np.where(probs >= threshold, probs, 0.0)
# 重新归一化
return filtered / filtered.sum()
Min-P的优势在于:
| 场景 | 最高概率 | 阈值(min_p=0.1) | 效果 |
|---|---|---|---|
| 高置信度 | “Paris” = 0.90 | 0.09 | 非常严格,只有高质量候选 |
| 低置信度 | “maybe” = 0.05 | 0.005 | 相对宽松,允许更多多样性 |
实验表明,Min-P在高温度设置下表现尤其出色,能够在保持创意的同时避免产生无意义的输出。该方法已被Hugging Face Transformers、vLLM、llama.cpp等主流框架原生支持。
3.8 高级解码策略一览
除了上述主流方法,研究界还提出了许多高级解码策略:
对比解码(Contrastive Decoding):同时使用一个"专家模型"和一个"业余模型”,增强专家模型认为好而业余模型认为差的词的概率。这可以抑制那些"表面合理但实际不佳"的选择。
典型采样(Typical Sampling):不是选择高概率词,而是选择"典型惊讶度"的词。基于信息论,人类语言中每个词的信息量接近期望熵,而非简单的高概率。
Mirostat:一种自适应方法,实时监控生成文本的困惑度(Perplexity),动态调整截断参数以保持输出的稳定质量。
四、神经文本退化:为什么"聪明"的模型会陷入重复
4.1 问题现象
2020年,Holtzman等人在论文《The Curious Case of Neural Text Degeneration》中揭示了一个令人困扰的现象:即使是训练良好的大型语言模型,在使用确定性解码方法(如贪婪搜索或束搜索)时,也会产生高度重复、毫无意义的文本。
示例:
I have a dream. I have a dream. I have a dream. I have a dream...
这被称为神经文本退化(Neural Text Degeneration)。
4.2 根本原因
为什么会发生这种情况?研究者们提出了多种解释:
flowchart TD
A[神经文本退化] --> B[训练数据重复模式]
A --> C[似然目标局限]
A --> D[自我强化机制]
B --> B1[模型学习重复n-gram]
B --> B2[推理时放大10倍以上]
C --> C1[专注下一个词预测]
C --> C2[忽略序列质量]
D --> D1[重复上下文触发]
D --> D2[继续重复成为"正确"选择]
训练数据中的重复模式:2023年的研究发现,训练数据中重复n-gram的比例与模型生成文本的重复率存在强相关性。模型在学习过程中"记住"了这些重复模式,在推理时被放大了超过10倍。
似然目标的局限:传统的最大似然训练目标专注于预测下一个词,而非生成好的序列。模型学会了"在特定语境下选择概率最高的词",但这可能与"生成有意义的完整文本"相冲突。
自我强化机制:一旦模型开始重复,它会不断"强化"这种行为。因为重复的上下文与训练数据中的重复模式匹配,模型会认为继续重复是"正确"的选择。
4.3 解决方案
针对神经文本退化,研究界提出了多种解决方案:
采样方法替代确定性方法:Top-P、Min-P等采样方法本质上是在打破确定性,引入随机性来避免重复循环。
重复惩罚(Repetition Penalty):对已生成的词施加惩罚,降低其被再次选中的概率:
$$\text{logit}'(w) = \text{logit}(w) / \lambda \quad \text{if } w \in \text{已生成词}$$频率惩罚与存在惩罚:OpenAI提出的两种变体:
- 频率惩罚:惩罚与已出现次数成正比
- 存在惩罚:只要出现过就施加固定惩罚
训练数据改进:在训练阶段使用"重复Dropout"技术,随机屏蔽对重复词的注意力,从根源上减少模型对重复模式的依赖。
五、训练 vs 推理:同一个目标,不同的过程
理解训练和推理的区别,有助于深入把握大模型的工作原理。
5.1 训练阶段:并行预测
在训练阶段,模型的目标是最大化训练数据的似然。对于一个输入序列$w = (w_1, w_2, ..., w_t)$,训练目标是:
$$\mathcal{L} = -\sum_{i=1}^{t} \log P(w_i | w_1, ..., w_{i-1})$$关键在于:训练时,所有位置的计算是并行的。由于因果注意力机制,位置$i$的输出只能看到位置$1$到$i-1$的信息,因此可以在一次前向传播中计算所有位置的损失。
这意味着训练时模型能够"看到"整个序列的上下文,即使它被训练预测每一个位置。
5.2 推理阶段:串行生成
推理阶段则完全不同。模型需要自回归地生成文本:
flowchart LR
A["输入: The cat sat on the"] --> B["预测: mat"]
B --> C["输入: The cat sat on the mat"]
C --> D["预测: ."]
D --> E["输入: The cat sat on the mat."]
E --> F["预测: <EOS>"]
每次生成一个词,然后将其加入输入序列,继续预测下一个词。这个过程是完全串行的,无法并行化(因为每一步都依赖前一步的输出)。
5.3 关键差异
| 维度 | 训练 | 推理 |
|---|---|---|
| 计算模式 | 并行 | 串行 |
| 输入 | 完整的训练序列 | 逐步增长的序列 |
| 目标 | 最大化似然 | 生成有意义文本 |
| Ground Truth | 有(训练标签) | 无 |
| 计算效率 | 高(一次前向) | 低(多次前向) |
这种差异导致了一个称为曝光偏差(Exposure Bias) 的问题:训练时模型总是看到"正确"的前文,而推理时模型可能生成"不完美"的前文,但模型从未在训练中学会如何处理这种情况。
六、参数协同:处理顺序很重要
在使用多种采样策略时,参数的处理顺序会显著影响最终结果。不同框架的实现顺序不同,这可能导致相同的参数设置产生不同的输出。
6.1 典型处理流程
以llama.cpp为例,默认的采样器处理顺序是:
logits → penalties → dry → top_n_sigma → top_k → typical → top_p → min_p → xtc → temperature → sample
关键观察:
-
惩罚先执行:重复惩罚、频率惩罚等在截断之前应用,确保被惩罚的词在后续处理中处于劣势
-
温度最后执行:在
llama.cpp中,温度在所有截断操作之后应用。这意味着高温不会"污染"候选池——低质量词已经被过滤掉了 -
截断方法有顺序:Top-K、Top-P、Min-P按特定顺序执行,每种方法处理的是前一步的输出
6.2 框架差异
Hugging Face Transformers:温度在Softmax之前应用,这意味着高温会影响后续所有截断操作的输入。
OpenAI API:不暴露处理顺序,但已知温度和Top-P是联动调整的。
vLLM:采用类似llama.cpp的顺序,但支持自定义采样器链。
这种差异意味着:在框架A上调优的参数,直接迁移到框架B可能产生完全不同的效果。实践中,建议在目标部署框架上进行参数调优。
6.3 参数组合建议
对于开源部署(支持Min-P):
| 任务类型 | Temperature | Min-P | 其他 |
|---|---|---|---|
| 代码生成 | 0.0 - 0.2 | 0.1 | 语法要求精确 |
| 数学推理 | 0.0 - 0.3 | 0.1 | 逻辑链条脆弱 |
| 事实问答 | 0.3 - 0.7 | 0.1 | 平衡准确与自然 |
| 日常对话 | 0.7 - 1.0 | 0.05 | 需要一定随机性 |
| 创意写作 | 1.0 - 1.5 | 0.05 | 高多样性不牺牲连贯 |
| 头脑风暴 | 1.2 - 1.8 | 0.02-0.05 | 追求最大多样性 |
对于商业API(仅支持Top-P):
| 任务类型 | Temperature | Top-P |
|---|---|---|
| 代码生成 | 0.0 - 0.2 | 0.95 |
| 数学推理 | 0.0 - 0.3 | 0.95 |
| 事实问答 | 0.3 - 0.7 | 0.9 |
| 日常对话 | 0.7 - 1.0 | 0.9 |
| 创意写作 | 1.0 - 1.5 | 0.9 |
七、各API提供商的默认参数
了解各平台的默认参数设置,有助于理解它们的"开箱即用"行为:
| 提供商 | Temperature | Top-P | Top-K | 惩罚参数 |
|---|---|---|---|---|
| OpenAI (GPT-4o) | 1.0 | 1.0 | 不暴露 | freq=0, presence=0 |
| Anthropic (Claude) | 1.0 | 未设置 | 未设置 | 不暴露 |
| Google (Gemini) | 1.0 | 0.95 | 40 | freq=0, presence=0 |
| Meta (Llama via vLLM) | 1.0 | 1.0 | 禁用 | rep_penalty=1.0 |
| DeepSeek | 1.0 | 未设置 | 不暴露 | freq=0, presence=0 |
值得注意的是,DeepSeek使用了一个隐藏的线性映射:内部温度 = 0.1 + 0.2 × API温度。这意味着API温度1.0实际对应内部温度0.3,这是一种基于用户习惯的优化。
7.1 推理模型的特殊限制
OpenAI的o1、o3系列和Anthropic的Claude with Extended Thinking等推理模型有特殊的参数限制:
- 固定参数:温度固定为1.0,Top-P固定为1.0,用户无法修改
- 原因:推理模型内部运行多条思维链,然后选择最佳结果。如果温度为0,所有链会收敛到相同的贪婪路径,失去多路径探索的意义
八、总结与实践建议
8.1 核心要点回顾
大模型文本生成是一个多阶段的技术链路:
- Logits生成:模型输出原始分数,一个词对应一个分数
- Softmax转换:将分数转换为概率分布,总和为1
- 解码策略:从概率分布中选择下一个词,方法多样,各有权衡
- 参数调控:Temperature、Top-K、Top-P、Min-P等参数影响生成的确定性与多样性
flowchart LR
A[输入文本] --> B[Transformer<br/>处理]
B --> C[Logits<br/>原始分数]
C --> D[Softmax<br/>概率转换]
D --> E[采样策略<br/>解码选择]
E --> F[输出Token]
F --> G{是否结束?}
G -->|否| A
G -->|是| H[完成]
8.2 最佳实践
对于生产环境部署:
- 优先使用Min-P(如果支持)而非Top-P
- Temperature和截断参数分开调优:先确定截断参数,再调整温度
- 针对具体任务验证参数效果,不要盲目复制默认值
对于研究实验:
- 明确记录所使用的框架和版本
- 报告完整的采样参数配置
- 考虑不同参数设置下的性能范围
对于应用开发:
- 不同API提供商的行为可能不同,需要分别测试
- 考虑添加重复惩罚作为通用保护措施
- 对于关键应用,考虑实现自定义采样逻辑
8.3 未来展望
解码策略的研究仍在快速发展。近期的重要方向包括:
- 更智能的自适应方法:根据上下文动态调整参数
- 与模型架构协同设计:让模型本身"知道"何时应该更确定或更随机
- 多目标优化:同时考虑质量、多样性、安全性等多个维度
理解这条从Logits到文字的技术链路,不仅能帮助我们更好地使用大模型,也能让我们更深入地思考:机器生成与人类创造之间的本质联系是什么?当模型"选择"一个词时,它究竟在做什么?这些问题或许没有标准答案,但探索它们本身就是理解AI的重要一步。
参考文献
- Holtzman, A., et al. (2020). “The Curious Case of Neural Text Degeneration.” ICLR 2020.
- Fan, A., et al. (2018). “Hierarchical Neural Story Generation.” ACL 2018.
- Nguyen, M., et al. (2025). “Turning Up the Heat: Min-p Sampling for Creative and Coherent LLM Outputs.” ICLR 2025 (Oral).
- Welleck, S., et al. (2020). “Neural Text Degeneration with Unlikelihood Training.” ICML 2020.
- Radford, A., et al. (2019). “Language Models are Unsupervised Multitask Learners.” OpenAI Technical Report.
- Keskar, N.S., et al. (2019). “CTRL: A Conditional Transformer Language Model for Controllable Generation.” arXiv preprint.
- Basu, S., et al. (2021). “Mirostat: A Neural Text Decoding Algorithm that Directly Controls Perplexity.” ICLR 2021.
- Li, X., et al. (2023). “Contrastive Decoding: Open-ended Text Generation as Optimization.” ACL 2023.
- Meister, C., et al. (2022). “Typical Decoding for Natural Language Generation.” TACL 2022.
- Tang, Z., et al. (2025). “Top-n-sigma: Temperature-Invariant Truncation for LLM Sampling.” ACL 2025.