首页 > 教程攻略 > ai资讯 >temperature,topk傻傻分不清?一文带你读懂LLM推理超参

temperature,topk傻傻分不清?一文带你读懂LLM推理超参

来源:互联网 时间:2026-08-23 14:04:06

平时用大模型做推理的时候,总会碰到几个让人又爱又恨的超参数——temperature、repetition penalty 这些。大家都知道 temperature 控制着输出的“随机性”,repetition penalty 则是防止模型反复念叨同一句话,但到底它们是怎么做到的?背后的机制可没那么玄乎。

这次直接从 transformers 4.43.1 的源码出发,把 temperature、top-p、repetition penalty 和 top-k 这四个参数的真实作用拆开来看看。所有代码都能在 Hugging Face 的仓库里找到,链接附在后面。

temperature,topk傻傻分不清?一文带你读懂LLM推理超参

下图是 LMDeploy API Server 的一张截图,展示了常用的推理超参数。OpenAI 接口也支持 temperature、top-p 和 repetition penalty,而 LMDeploy 额外多了个 top-k 参数。

Temperature

先看看 TemperatureLogitsWarper 类的实现。它在第 236 行,去掉文档和合法性校验后,核心逻辑就这么几行:

class TemperatureLogitsWarper(LogitsWarper):

    def __init__(self, temperature: float):
        self.temperature = temperature

    def __call__(self, input_ids: torch.LongTensor, scores: torch.FloatTensor) -> torch.FloatTensor:
        scores_processed = scores / self.temperature
        return scores_processed

temperature 的实质很简单:对模型输出的 logits(分类头在 softmax 之前的分数)做一次除法。因为 LLM 预测下一个 token 本质是个分类任务,temperature 就是放大或缩小 logits 之间的差异。加入温度参数的 softmax 公式是:p_i = exp(score_i / T) / sum_j exp(score_j / T)

举个实例:假设三个 token A、B、C 的原始 logits 分别是 0.1、0.5、0.9。temperature 取不同值时,概率分布的变化如下图:

随着 temperature 变大,三个 token 的概率差距逐渐缩小,原来概率低的 token A 被选中的机会显著增加——这就是“随机性增大”的本质。

Top-P

接着看第 411 行的 TopPLogitsWarper

class TopPLogitsWarper(LogitsWarper):

    def __init__(self, top_p: float, filter_value: float = -float("Inf"), min_tokens_to_keep: int = 1):
        top_p = float(top_p)
        self.top_p = top_p
        self.filter_value = filter_value
        self.min_tokens_to_keep = min_tokens_to_keep

    def __call__(self, input_ids: torch.LongTensor, scores: torch.FloatTensor) -> torch.FloatTensor:
        sorted_logits, sorted_indices = torch.sort(scores, descending=False)
        cumulative_probs = sorted_logits.softmax(dim=-1).cumsum(dim=-1)

        # Remove tokens with cumulative top_p above the threshold (token with 0 are kept)
        sorted_indices_to_remove = cumulative_probs <= (1 - self.top_p)
        # Keep at least min_tokens_to_keep
        sorted_indices_to_remove[..., -self.min_tokens_to_keep :] = 0

        # scatter sorted tensors to original indexing
        indices_to_remove = sorted_indices_to_remove.scatter(1, sorted_indices, sorted_indices_to_remove)
        scores_processed = scores.masked_fill(indices_to_remove, self.filter_value)
        return scores_processed

Top-P 的作用是只保留那些概率高且累计概率超过 top_p 参数的 token。继续用上面的例子:三个 token 经 softmax 后概率分别为 0.21、0.32、0.47。设 top_p = 0.7,则累计概率需大于 1 - 0.7 = 0.3 的 token 才被保留。由于 B 和 C 的概率和(0.32 + 0.47 = 0.79)已经超过 0.7,而 A 的概率 0.21 小于 0.3 的阈值,所以 A 被剔除,只剩 B 和 C。

最终输出的 logits 变成:A 为 0,B 为 0.5,C 为 0.9。

Repetition Penalty

第 302 行是 RepetitionPenaltyLogitsProcessor

class RepetitionPenaltyLogitsProcessor(LogitsProcessor):

    def __init__(self, penalty: float):
        self.penalty = penalty

    def __call__(self, input_ids: torch.LongTensor, scores: torch.FloatTensor) -> torch.FloatTensor:
        score = torch.gather(scores, 1, input_ids)

        # if score < 0 then repetition penalty has to be multiplied to reduce the token probabilities
        score = torch.where(score < 0, score * self.penalty, score / self.penalty)

        scores_processed = scores.scatter(1, input_ids, score)
        return scores_processed

Repetition Penalty 的思路非常直接:如果某个 token 已经出现在之前生成的序列里,就给它施加一个惩罚。具体做法是:对已生成的 token 的 logits,如果 score 是正数,就除以 penalty;如果是负数,就乘以 penalty。这样无论正负,都能降低这个 token 再次出现的概率。

假设模型已经输出了三个 token “AAA”,三个候选 token 的 logits 分别为 A:-0.5,B:0.1,C:-0.4。不加 penalty 时,softmax 后的概率是 A:0.25,B:0.47,C:0.28。注意 A 的概率仍不低,尽管它的 logits 是负的。如果 penalty 设为 2.0,A 的负 score 会再乘以 2 变成 -1.0,B 和 C 不变。这时 softmax 后概率变为 A:0.17,B:0.51,C:0.31,A 被明显抑制。

Top-K

最后是第 478 行的 TopKLogitsWarper

class TopKLogitsWarper(LogitsWarper):

    def __init__(self, top_k: int, filter_value: float = -float("Inf"), min_tokens_to_keep: int = 1):
        self.top_k = max(top_k, min_tokens_to_keep)
        self.filter_value = filter_value

    def __call__(self, input_ids: torch.LongTensor, scores: torch.FloatTensor) -> torch.FloatTensor:
        top_k = min(self.top_k, scores.size(-1))  # Safety check
        # Remove all tokens with a probability less than the last token of the top-k
        indices_to_remove = scores < torch.topk(scores, top_k)[0][..., -1, None]
        scores_processed = scores.masked_fill(indices_to_remove, self.filter_value)
        return scores_processed

Top-K 和 Top-P 功能类似,但策略不同:它只保留 logits 最大的 k 个 token。还用那个例子,logits 为 A:0.1,B:0.5,C:0.9。如果 top_k = 1,只保留 C,输出变成 A:0,B:0,C:0.9;如果 top_k = 2,保留 C 和 B,输出 A:0,B:0.5,C:0.9。虽然后来 OpenAI 接口移除了 top-k,但 transformers 里依然保留了它。

写在最后

读完源码可以总结成这样:

  • Temperature 通过缩放 logits 来增大输出的随机性,温度越高,概率分布越平缓。
  • Repetition Penalty 通过对已出现 token 的分数加权(正除负乘)来阻止模型反复输出相同内容。
  • Top-P 和 Top-K 都会砍掉低概率的 token,前者按累计概率阈值裁剪,后者直接按排名裁剪,两者都能在一定程度上保证生成质量。