LLM 解码是指将模型预测的概率分布转换为实际文本的过程。每一步,模型都会给出一个词汇表中所有可能单词的概率,我们需要从中选择一个或多个词来构建最终的句子。解码策略的不同会直接影响生成文本的质量、连贯性以及多样性。
常见的解码策略包括贪心搜索、束搜索和采样方法。每种方法有其优缺点,适用于不同的任务和场景。
1. 贪心搜索(Greedy Search)
该种方法的特点是解码时,每一步都选择概率最高的词。优点是计算简单,速度快。缺点则是容易错失全局最优解,导致生成的文本质量下降。
示例: 假设模型预测 Hello 的下一个单词分布如下:
词 | 概率 |
---|---|
world | 0.6 |
there | 0.3 |
everyone | 0.1 |
贪心搜索会直接选择概率最高的 world 作为下一个选择,即生成的句子为:Hello world。
2. 束搜索(Beam Search)
Beam Search 可以理解为一种经过优化的贪心搜索方法,它的特点是,在每一步都保留 k 个路径,而不是仅仅选择当前概率最大的路径,直到达到最大长度或遇到结束标记。其优点是考虑多个候选项,提升生成文本的流畅度。缺点则是计算开销较大。可能导致文本模式化,缺乏多样性。
示例:假设我们正在进行一个简单的机器翻译任务,目标是将英文句子 hello 翻译成法语。我们假设在每一步生成一个词,并根据当前的上下文选择下一个最可能的词。
- 初始步骤:
- 初始词(空句子) → 候选词:
bonjour(0.5)
,salut(0.3)
,coucou(0.2)
- 选择 top-2:
bonjour
,salut
- 初始词(空句子) → 候选词:
- 第一步扩展:
- 对于
bonjour
→ 候选词:tout(0.4)
,le(0.3)
,la(0.2)
,mon(0.1)
- 路径:
bonjour tout
(0.5 × 0.4 = 0.2),bonjour le
(0.5 × 0.3 = 0.15)
- 路径:
- 对于
salut
→ 候选词:tout (0.5)
,mon (0.3)
,la (0.2)
- 路径:
salut tout
(0.3 × 0.5 = 0.15),salut mon
(0.3 × 0.3 = 0.09)
- 路径:
- 选择 top-2:
bonjour tout
(0.2),salut tout
(0.15)
- 对于
- 第二步扩展:
- 对于
bonjour tout
→ 候选词:est(0.6)
,la(0.3)
,ce(0.1)
- 路径:
bonjour tout est
(0.2 × 0.6 = 0.12),bonjour tout la
(0.2 × 0.3 = 0.06)
- 路径:
- 对于
salut tout
→ 候选词:est(0.7)
,la(0.2)
,ce(0.1)
- 路径:
salut tout est
(0.15 × 0.7 = 0.105),salut tout la
(0.15 × 0.2 = 0.03)
- 路径:
- 选择 top-2:
bonjour tout est
(0.12),salut tout est
(0.105)
- 对于
- 最终选择:
- 最终选择累积概率最高的路径:
bonjour tout est
- 最终选择累积概率最高的路径:
通过这个过程,我们会发现:k 的大小决定了每个时间步保留多少个候选路径。较小的 k
值意味着搜索空间较小,计算量较低,但可能会错过最优解;而较大的 k
值则意味着更大范围的探索,可能会得到更好的结果,但计算量也会显著增加。
一般来说,k
值的选择需要综合考虑计算资源和任务的具体要求。通常,k
取值为 5 或 10 是较为常见的选择,但也可以根据实际情况调整。
4. 采样(Sampling)
该方法的特点是在解码时,按照不同的概率分布随机选择下一个单词,而不是固定选择最高概率的单词。优点是生成文本更加多样化,避免重复模式。缺点则是可能生成不合理或不连贯的内容。
采样方法常见的变体:
- Top-K 采样:只从
k
个最高概率的单词中进行随机采样。 - Top-P 采样(核采样):选取累积概率达到
p
的词进行随机采样。
示例(当前模型预测的 token 及概率):
Token | 概率 |
---|---|
world | 0.5 |
there | 0.3 |
everyone | 0.1 |
guys | 0.05 |
folks | 0.05 |
- Top-K (
k=2
) → 仅保留{world, there}
,随机选一个。 - Top-P (
p=0.8
) → 只保留{world, there}
,因累积概率达到 0.8,忽略其余。
4. 解码组合
贪心解码(Greedy Decoding)是一种最简单直接的解码方法,其条件是 num_beams=1
且 do_sample=False
,意味着在每一步中都选择当前概率最高的单词作为输出。由于其确定性高,生成结果唯一,但容易陷入局部最优解,导致文本缺乏自然性和多样性。
对比搜索(Contrastive Search)则通过 penalty_alpha>0
和 top_k>1
来引入对比和惩罚机制,以避免生成重复或不自然的内容。这种方法鼓励生成更加多样化的文本,适用于需要减少重复或增强对比性的场景。
多项式采样(Multinomial Sampling)要求 num_beams=1
且 do_sample=True
,即根据单词的概率分布进行随机采样,而不是仅选择概率最高的单词。其特点是引入随机性,使生成结果更加丰富多样,适合需要创造性和随机性的文本生成任务。
束搜索解码(Beam-Search Decoding)在 num_beams>1
且 do_sample=False
时使用。它通过在每一步保留多个候选序列,并最终选择概率最高的序列,从而提升生成文本的质量。这种方法适合需要高质量、确定性文本生成的场景,但计算复杂度较高。
束搜索多项式采样(Beam-Search Multinomial Sampling)结合了束搜索和多项式采样的优点,其条件是 num_beams>1
且 do_sample=True
。该方法既能保证一定的探索深度,又引入随机性,使生成文本兼具高质量和多样性,适合需要平衡稳定性和创意的应用。
多样化束搜索解码(Diverse Beam-Search Decoding)则通过 num_beams>1
和 num_beam_groups>1
,将束分成多个组,每组独立生成文本,从而鼓励生成更加多样化的结果。这种方法适用于需要多个不同候选文本的场景,例如文本摘要和机器翻译,有助于避免生成过于相似的内容。
注释源码:python3.10/site-packages/transformers/generation/configuration_utils.py 98 行