问题描述
调用openai API,使用templature = 0,每次返回的内容仍有一些不同
>>> client = OpenAI(
... api_key=api_key,
... base_url=api_base)
#第一次尝试
>>> response = client.chat.completions.create(model='gpt-3.5-turbo',messages=[{"role": "user", "content": "who are you"}],temperature=0)
>>> response.choices[0].message.content
'I am an artificial intelligence assistant created to help answer questions and provide information. How can I assist you today?'
#第二次尝试
>>> response = client.chat.completions.create(model='gpt-3.5-turbo',messages=[{"role": "user", "content": "who are you"}],temperature=0)
>>> response.choices[0].message.content
'I am an AI assistant designed to help answer questions and provide information to the best of my abilities. How can I assist you today?'
#第三次尝试
>>> response = client.chat.completions.create(model='gpt-3.5-turbo',messages=[{"role": "user", "content": "who are you"}],temperature=0)
>>> response.choices[0].message.content
'I am a language model AI created to assist with answering questions and engaging in conversations.'
可以发现多次调用api进行文本生成,得到的回复有些许差别
temperlature介绍
在文本生成的过程中,可以通过设置采样温度值,控制文本生成的多样性。如下是温度参数的使用流程:
- 语言模型首先根据已有文本,计算生成词汇表中每个词所对应的负对数概率。
比如:在生成下一个词时,模型可能会给出以下对数概率:Token A: -1.2 Token B: -0.5 Token C: -2.3 Token D: -0.1
- 将这些负对数概率除以温度值:log_prob_scaled = log_prob / temperature
比如:当温度值为0.5时,概率分布变为:
可以发现,通过除以一个小于0的温度值,使得概率分布变得更加极端。Token A: -1.2/0.5 = -2.4 Token B: -0.5/0.5 = -1.0 Token C: -2.3/0.5 = -4.6 Token D: -0.1/0.5 = -0.2
- 应用softmax函数,将这些负对数概率转换为总和为1的概率分布。
通过一个例子来检验代码
import numpy as np
import matplotlib.pyplot as pltdef softmax(logits, temperature=1.0):"""计算给定logits和温度的softmax概率分布"""exp_logits = np.exp(logits / temperature)return exp_logits / np.sum(exp_logits)def plot_temperature_effect(logits, temperatures):"""绘制不同温度下的概率分布"""plt.figure(figsize=(10, 6))for T in temperatures:probabilities = softmax(logits, T)plt.plot(probabilities, label=f'Temperature = {T}')plt.title('Effect of Temperature on Probability Distribution')plt.xlabel('Token Index')plt.ylabel('Probability')plt.xticks(np.arange(len(logits)), [f'Token {i}' for i in range(len(logits))])plt.legend()plt.grid()plt.show()# 示例logits(可以是模型输出的logit值)
logits = np.array([0.1,1,2.3,1.5,2.1,1.2,1.5,0.1,3.2,3.32,2.32,2.01,0.3,1.25])# 不同的温度值
temperatures = [0.5,1, 2.0]# 绘制效果
plot_temperature_effect(logits, temperatures)
从上图可以看出,温度值为1时,是原本的分布,温度值为0.5时,概率分布变得更加极端,温度值为2时,概率分布变得更加平缓。
那么,在调用openai API时,设置temperature=0,为什么还会出现不同的结果呢?
参考https://community.openai.com/t/a-question-on-determinism/8185/2,可能有如下2个原因:
- 2个token的对数差异很小:在调用openai API时,设置temperature=0,只是使得概率分布变得更加极端,但是仍然可能有2个token排名为第一第二,但他们之间的对数概率差异很小,使得采样时仍然有一定的随机性。
- 大语言模型推理的并行操作的不确定性:大模型推理时的并行操作会引入不确定,比如计算a*b*c时,可能计算(a*b)*c,也可能计算a*(b*c),这会使得最终的结果有一定的差异。
而模型推理时是以自回归方式的方式进行的,一旦在某个time step,模型选择了某个token,那么之后生成的文本很可能就会发散,导致最终的文本生成结果出现差异。
在本地进行推理是否会有变化?
上面讨论的是由openai提供的推理服务,那么我们在本地进行推理时,是否会有变化?
进行实验使用qwen2.5_7b_instruct模型,在本地进行推理。采样参数为:
temperature=0.01,max_tokens=512, top_p=1
重复多次,观察结果是否一致。
结果如下:
#输入:
为什么今天是礼拜五#第一次回复
今天是否是礼拜五取决于你所在的地区使用的是哪种日历系统以及当前的日期。礼拜五是每周的第五天,如果你想知道今天是否是礼拜五,可以查看你所在地的日期。如果你是在一个使用公历(格里高利历)的地区,你可以查看当前的日期来确定。例如,如果今天的日期是2023年10月6日,那么在公历系统中,今天就是礼拜五。
#第二次
今天是否是礼拜五取决于你所在的地区使用的是哪种日历系统以及当前的日期。礼拜五是每周的第五天,如果你想知道今天是否是礼拜五,可以查看你所在地的日期。如果你是在一个使用公历(格里高利历)的地区,你可以查看当前的日期来确定。例如,如果今天的日期是2023年10月6日,那么在公历系统中,今天就是礼拜五。
#第三次
今天是否是礼拜五取决于你所在的地区和采用的日历系统。如果你是在使用公历(格里高利历),那么你可以查看当前的日期来确定今天是否是礼拜五。例如,如果今天的日期是2023年10月6日,那么在公历下今天就是礼拜五。如果你是在使用其他日历系统,比如伊斯兰历,那么礼拜五的日期会有所不同。
#第四次
今天是否是礼拜五取决于你所在的地区和采用的日历系统。如果你是在使用公历(格里高利历),那么你可以查看当前的日期来确定今天是否是礼拜五。例如,如果今天的日期是2023年10月6日,那么在公历下今天就是礼拜五。如果你是在使用其他日历系统,比如伊斯兰历,那么礼拜五的日期会有所不同。
#第五次
今天是否是礼拜五取决于你所在的地区和采用的日历系统。如果你是在使用公历(格里高利历),那么你可以查看当前的日期来确定今天是否是礼拜五。例如,如果今天的日期是2023年10月6日,那么在公历下今天就是礼拜五。如果你是在使用其他日历系统,比如伊斯兰历,那么礼拜五的日期会有所不同。
#第六次
今天是否是礼拜五取决于你所在的地区使用的是哪种日历系统以及当前的日期。礼拜五是每周的第五天,如果你想知道今天是否是礼拜五,可以查看你所在地的日期。如果你是在一个使用公历(格里高利历)的地区,你可以查看当前的日期来确定。例如,如果今天的日期是2023年10月6日,那么在公历系统中,今天就是礼拜五。
可以发现,5次推理的结果也并不是完全一致,会发现大概有2类回复,
第一种回复:
今天是否是礼拜五取决于你所在的地区使用的是哪种日历系统以及当前的日期。礼拜五是每周的第五天,如果你想知道今天是否是礼拜五,可以查看你所在地的日期。如果你是在一个使用公历(格里高利历)的地区,你可以查看当前的日期来确定。例如,如果今天的日期是2023年10月6日,那么在公历系统中,今天就是礼拜五。
第二种回复:
今天是否是礼拜五取决于你所在的地区和采用的日历系统。如果你是在使用公历(格里高利历),那么你可以查看当前的日期来确定今天是否是礼拜五。例如,如果今天的日期是2023年10月6日,那么在公历下今天就是礼拜五。如果你是在使用其他日历系统,比如伊斯兰历,那么礼拜五的日期会有所不同。
他们之间有一些细微的差别。说明模型可能在推理时,在生成“今天是否是礼拜五取决于你所在的地区”这句话之前都没什么争议,关键在在predict "今天是否是礼拜五取决于你所在的地区"的next token时,可能会有2个token排名为第一第二,但由于他们之间的差异很小,导致采样时有一定的随机性。
实验检验:
检查模型的推理过程,查看其推理的token序列和概率分布。
Time Step 12:
Candidates:
Token: 使用的, Log Probability: -1.0418
Token: 采用, Log Probability: -1.4168
Token: 使用, Log Probability: -1.9168
Token: 所, Log Probability: -1.9168
Token: 如何, Log Probability: -3.2918
…
Chosen Token: 使用的 (Probability: 0.0908)
可以发现“使用的”和“采用”的log概率差异很小。
检验每个推理步骤的词概率的代码:
#推理模型
messages = [{"role": "user", "content": "为什么今天是礼拜五"},{"role": "assistant", "content": "今天是否是礼拜五取决于你所在的地区"},
]
prompt = tokenizer.apply_chat_template(messages,tokenize=False,add_generation_prompt=True)
sampling_params = SamplingParams(temperature=0.01, top_p=1,logprobs=5,max_tokens=512)
outputs = model.generate(prompt, sampling_params)
for output in outputs:prompt = output.promptgenerated_text = output.outputs[0].textprint(f"Prompt: {prompt!r}, \n Generated text: {generated_text!r}")print(outputs[0].outputs[0].logprobs)