引言:模型输出的真正面目

当你在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虽然表示了模型的偏好,但它有几个问题:

  1. 不可解释:一个Logit为2.85到底意味着什么?我们无法直观理解
  2. 不可比较:不同时刻、不同上下文下的Logits范围可能完全不同
  3. 不可采样:我们无法直接从Logits中随机选择

Softmax函数解决了这些问题,将Logits转换为概率分布。

2.2 Softmax的数学原理

Softmax的定义如下:

$$\text{softmax}(x_i) = \frac{e^{x_i}}{\sum_{j} e^{x_j}}$$

对于词表中的每个词,我们计算其Logit的指数,然后除以所有词Logit指数的和。这个操作有三个重要性质:

  1. 非负性:指数函数保证结果始终为正
  2. 归一化:所有概率之和为1
  3. 保序性: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

束搜索的优势在于能够考虑更长的上下文依赖,但它仍然有两个问题:

  1. 计算开销:需要维护$k$条序列,计算量是贪婪搜索的$k$倍
  2. 重复问题:研究(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采样

核心思想是:不固定候选词数量,而是固定候选词的累计概率。具体做法是:

  1. 将词按概率降序排列
  2. 累加概率,直到总和达到阈值$p$(如0.9)
  3. 只从这个"核"中采样
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["预测: &lt;EOS&gt;"]

每次生成一个词,然后将其加入输入序列,继续预测下一个词。这个过程是完全串行的,无法并行化(因为每一步都依赖前一步的输出)。

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

关键观察:

  1. 惩罚先执行:重复惩罚、频率惩罚等在截断之前应用,确保被惩罚的词在后续处理中处于劣势

  2. 温度最后执行:在llama.cpp中,温度在所有截断操作之后应用。这意味着高温不会"污染"候选池——低质量词已经被过滤掉了

  3. 截断方法有顺序: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 核心要点回顾

大模型文本生成是一个多阶段的技术链路:

  1. Logits生成:模型输出原始分数,一个词对应一个分数
  2. Softmax转换:将分数转换为概率分布,总和为1
  3. 解码策略:从概率分布中选择下一个词,方法多样,各有权衡
  4. 参数调控: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的重要一步。


参考文献

  1. Holtzman, A., et al. (2020). “The Curious Case of Neural Text Degeneration.” ICLR 2020.
  2. Fan, A., et al. (2018). “Hierarchical Neural Story Generation.” ACL 2018.
  3. Nguyen, M., et al. (2025). “Turning Up the Heat: Min-p Sampling for Creative and Coherent LLM Outputs.” ICLR 2025 (Oral).
  4. Welleck, S., et al. (2020). “Neural Text Degeneration with Unlikelihood Training.” ICML 2020.
  5. Radford, A., et al. (2019). “Language Models are Unsupervised Multitask Learners.” OpenAI Technical Report.
  6. Keskar, N.S., et al. (2019). “CTRL: A Conditional Transformer Language Model for Controllable Generation.” arXiv preprint.
  7. Basu, S., et al. (2021). “Mirostat: A Neural Text Decoding Algorithm that Directly Controls Perplexity.” ICLR 2021.
  8. Li, X., et al. (2023). “Contrastive Decoding: Open-ended Text Generation as Optimization.” ACL 2023.
  9. Meister, C., et al. (2022). “Typical Decoding for Natural Language Generation.” TACL 2022.
  10. Tang, Z., et al. (2025). “Top-n-sigma: Temperature-Invariant Truncation for LLM Sampling.” ACL 2025.