Fenrier Lab

如何解释 top_p 和 temperature 参数对 LLM 生成多样性的影响

总所周知,在调用 LLM 的时候,如果想让模型的生成结果更加多样化,可以通过调高 top_p 或者 temperature 来实现,反之,如果调低这两个参数,则生成的结果会更加倾向同质化,总之,两种方式的应用场景不同。这篇文章我们通过示例从原理上来解释为何这两个参数能够控制 LLM 生成结果的多样性。

首先需要知道,LLM 的输出结果只是下一个 token 的概率分布,具体生成框架(比如 transformers 的 generate 函数)负责生成过程。如果采用贪心策略,每次都选择概率最大的 token,那么就不存在所谓的调整空间,也就是说当设置 do_sample=False 时,top_ptemperature 参数是不起作用的。而当设置 do_sample=True 时,生成框架才会根据概率对 token 进行采样,这时 top_ptemperature 参数才会发挥作用。

为了更好的说明,我们使用 gpt2 模型产生一个概率分布

tokenizer = AutoTokenizer.from_pretrained("gpt2")
model = AutoModelForCausalLM.from_pretrained("gpt2").cuda()
model.eval()

text = "hello, this is my favorite"
input_ids = tokenizer.encode(text, return_tensors="pt").cuda()
attention_mask = torch.ones_like(input_ids).cuda()
with torch.no_grad():
    outputs = model(input_ids, attention_mask = attention_mask)

logits=outputs["logits"][0, -1, :]

这里的 logits 就是下一个token的未归一化概率分布,如果我们设置了 temperature 参数,那么生成框架会对这个 logits 进行调整,具体来说就是对其除以 temperature。然后再通过 softmax 将 logits 变换为归一化的概率分布,并在这个分布的基础上进行采样。下面我们使用 temperature=0.9 以及 temperature=0.1 为例,看看这两种情况对归一化概率的影响

temperature = 0.9
logits = logits / temperature
probs = F.softmax(logits, dim=-1).cpu().numpy()
## sort
sorted_idx = np.argsort(probs)[::-1]
sorted_probs = probs[sorted_idx][:20]

## plot
plt.plot(sorted_probs)

这里我们绘制出了概率值最大的前20个数据

接下来我们将 temperature 设置为 0.1,其他不变,再次绘制概率值最大的前20个数据

可以看到相对于 temperature=1 的情况,这时概率的分布更集中了,生成框架会更倾向于选择概率最大的 token,于是生成结果的多样性也就变小了。

通过这个例子我们也可以理解为什么这个参数被命名为 temperature。我们知道在物理世界中,温度越高的环境,熵越大,对应到概率世界中,熵越大,概率的不确定性越大,也就是概率分布越不集中,这就是第一种情况,而当温度越低,熵越小,概率分布就越集中,这就是第二种情况。所以 temperature 本质是在控制概率分布的熵,从而影响生成结果的多样性。

接下来我们再考虑 top_p 的具体作用,top_p 实际上是个阈值参数,它对 logits 的修改有点绕,我们一步一步说明(具体代码见 transformers 的 src/transformers/generation/logits_process.py 文件 TopPLogitsWarper 类)

  1. 首先对 logits 按从小到大的顺序排序;
  2. 使用 softmax 计算归一化概率,然后计算累计概率,如下图所示
  3. 过滤掉小于 1-top_p 的值,并将其所在的 token 的概率设为负无穷;
  4. 重新计算归一化概率,然后进行采样。

可以发现,top_p 越小,则过滤掉的小概率 token 越多,采样时的可选项目就越少,生成结果的多样性也就越小。我们使用一个例子来说明,分别设置 top_p = 0.9top_p = 0.1

top_p = 0.9

sorted_logits, sorted_indices = torch.sort(logits, 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 - top_p)

# scatter sorted tensors to original indexing
indices_to_remove = sorted_indices_to_remove.scatter(0, sorted_indices, sorted_indices_to_remove)
scores_processed = logits.masked_fill(indices_to_remove, -float('inf'))

probs = F.softmax(scores_processed, dim=-1)
## sort 
sorted_probs, sorted_indices = torch.sort(probs, descending=True)

## top 20
plt.plot(sorted_probs[:20].cpu().numpy())

这里我们借用了 transfromers 的代码,绘制出概率值最大的前20个数据

而当 top_p=0.1 时,情况类似于 temperature=0.1,可以看到概率分布的集中度也变大了。

通过上面的分析与实例,我们可以看到 top_ptemperature 这两个参数是如何影响 LLM 生成结果的多样性的。temperature 控制了概率分布的熵,从而影响生成结果的多样性,而 top_p 则是通过过滤掉小概率的 token,减少采样的可选项,从而影响生成结果的多样性。

最后,如果我们用概率分布的熵来量化生成结果的多样性,那么 temperaturetop_p 在同样数值的情况下,哪个参数的影响会更大?在不同模型之间会不会有一些规律?感兴趣的同学可以实验验证一下。

本文遵守 CC-BY-NC-4.0 许可协议。

Creative Commons License

欢迎转载,转载需注明出处,且禁止用于商业目的。