NLP——LLM推理时的生成方式

本文主要简单介绍 LLM 推理时的生成方式(偏简单记录)


整体说明


  • 说明:每一时间步都选择概率最大的词
  • 参数设置:do_sample = False, num_beams = 1
  • 缺点:生成文本可能出现重复现象
  • 此时,生成结果仅一条,若 num_return_sequences 参数大于1,代码会报错,说 Greedy Search 不支持这个参数大于 1
  • 注意:当 do_sample=False 时,temperature、top_k、top_p 等采样相关参数均不会生效
    • 因为这些参数的作用是 “调整概率采样的规则”,而 do_sample=False 本质是完全跳过 “概率采样” 流程,直接采用贪心搜索(每一步仅选概率最高的 token),自然无需依赖这些采样参数
    • 记忆:do_sample 是生成策略的 “总开关”,其优先级远高于 temperature/top_k/top_p

  • 说明:表示每一时刻均保留得分最高的 k 个序列,然后下一时刻用这 k 个序列继续生成
  • 参数设置:do_sample = False, num_beams = N (N > 1)
  • 缺点:仍然可能出现重复现象;会耗费更多算力
  • 此时,会生成多条结果

Multinomial sampling

  • 说明:多项式采样 ,每一个时间步,根据概率分布随机采样字(每个概率>0的字都有被选中的机会)
  • 参数设置:do_sample = True, num_beams = 1
  • 优点:解决了生成重复的问题
  • 缺点:可能会出现生成的文本不准守基本的语法

Beam-search multinomial sampling

  • 说明:Beam-search和Multinomial sampling的结合体,每个时间步从num_beams个字中采样
  • 参数设置:do_sample = True, num_beams = N (N > 1)
  • 优点:解决了重复生成的问题;效果相对num_beams=1效果也更好
  • 缺点:会耗费更多算力
  • 此时会同时生成多个结果,可通过参数num_return_sequences控制返回数量

惩罚重复:repetition_penalty

  • 说明:在每步时对之前出现过的词的概率做出惩罚,即降低出现过的字的采样概率,让模型趋向于解码出没出现过的词

  • 参数设置:repetition_penalty(float,取值范围>0)。默认为1,即代表不进行惩罚。值越大,即对重复的字做出更大的惩罚

  • 代码实现逻辑:

    1
    score = torch.where(score < 0, score*penalty, score/penalty)
    • 一般来说:penalty>1.0, 所以以下结论:
    • 如果字的概率score<0, 则score = score*penalty, 概率会越低;
    • 如果字的概率score>0, 则score = score/penalty, 同样概率也会变低

惩罚重复:presence_penalty

  • presence_penalty 是大模型里用来调节文本生成多样性的参数,
  • presence_penalty 作用机制是:如果某个 token 已经在已生成的文本中出现过,就给它的 logits 减去一个固定值(由 presence_penalty 控制)
    • 这样,模型会更倾向于选择那些还没出现过的新 token,从而减少重复、增加内容的新颖度
  • 取值范围:通常在 0 到 2 之间。0 表示不做任何惩罚,值越大越鼓励引入新概念
    • 经验值:从 0.5 开始尝试,若发现内容重复严重,可逐步提高到 1.0 左右;
    • 若希望更保守,可设为 0.1-0.3
  • 需结合 temperaturetop_p 等其他参数一起调优
  • 问题:为什么范围规定为 0-2?理论上可以把 presence_penalty 设到 2 以上,但实际没必要,原因主要有三点:
    • 边际效应递减 :随着值增大,对已出现 token 的惩罚强度线性增加,但带来的“新信息”增量却越来越小。超过 2 之后,几乎不会再显著提升多样性,反而容易让文本变得跳跃、不连贯
    • 稳定性风险 :大模型本身对 logits 的微小变化就比较敏感。值过大(>2)会剧烈扭曲概率分布,导致生成结果不可控,甚至出现语法错误或逻辑断裂
    • 经验验证上限 :主流框架(如 OpenAI、vLLM 等)在大量实验中发现,0–2 这个区间已经能覆盖从“轻微去重”到“强创新”之间的全部常用需求,因此把 2 设为硬上限,避免用户误用极端值

惩罚 n-gram:no_repeat_ngram_size

  • 说明:限制n-gram在生成结果中出现次数
  • 参数设置: no_repeat_ngram_size
    • 限制n-gram不出现2次。 (no_repeat_ngram_size=6即代表:6-gram不出现2次)
    • 用于控制重复词生成,默认是0,如果为N>0,则相应N-gram只出现一次
  • 要非常慎重使用

Temperature

  • 说明:通过温度,控制每个字的概率分布曲线。温度越低,分布曲线越陡峭,越容易采样到概率大的字。温度越高,分布曲线越平缓,增加了低概率字被采样到的机会
  • 参数设置:temperature(取值范围:0-1)设的越高,生成文本的自由创作空间越大;温度越低,生成的文本越偏保守
  • 本质是对softmax函数前的数据进行降温
    $$
    p_i = \frac{e^{\frac{y_i}{temperature}}}{\sum_i e^{\frac{y_i}{temperature}}}
    $$

Top-K 采样

  • 说明:每个时间步,会保留topK个字,然后对topk个字的概率重新归一化,最后在重新归一化后的这K个字中进行采样
  • 参数设置:top_k
  • 缺点:在分布陡峭的时候仍会采样到概率小的单词,或者在分布平缓的时候只能采样到部分可用单词
  • top_k=0(或 -1):不限制,包含所有 token

Top-P 采样(又称 Nucleus Sampling)

  • 说明:每个时间步,按照字出现的概率由高到底排序,当概率之和大于top-p的时候,就不取后面的样本了。然后对取到的这些字的概率重新归一化后,进行采样
  • 参数设置:top_p (取值范围:0-1)
  • top-P采样方法往往与 top-K 采样方法结合使用,每次选取两者中最小的采样范围进行采样,可以减少预测分布过于平缓时采样到极小概率单词的几率

长度惩罚:length_penalty

  • 说明:长度惩罚,Exponential penalty to the length that is used with beam-based generation.

  • 仅在Beam Search的数量大于1时生效

  • 常规的Beam Search句子的得分为概率取对数再求和,是一个负数(由对数单调性可知选择更大的得分对应的序列)
    $$
    sumLogProbs = \sum_{t=1}^{T} \log P(y_t|y_0,y_1,\cdot,y_{t-1})
    $$

  • 进一步地,经过长度惩罚的分数修正如下:
    $$
    seqScore = \frac{sumLogProbs}{tokenLen^{length\_penalty}}
    $$

  • 所以length_penalty大于0时分母大于1且随长度单调递增,从而得分也随长度单调递增,等价于鼓励生成长文本。反之,鼓励生成短文本

  • 代码实现如下:

    1
    seq_score = sum_log_probs / len(hyp) ** self.length_penalty
  • 参数设置:length_penalty, 默认是1.0

    1
    2
    3
    4
    length_penalty=1.0 # beam search分数会受到生成序列长度的惩罚
    length_penalty=0.0 # 无惩罚
    length_penalty<0.0 # 鼓励模型生成短句子
    length_penalty>0.0 # 鼓励模型生成长句子