你想过吗
我们在使用DeepSeek、豆包等AI软件时,是否发现每次输入同样的问题,得到的输出可能略有不同。这是为什么呢?明明我两次的输入都是一样的啊。
为什么
要去探究这个问题,就不得不回归到本质:是什么控制着大模型的内容生成?
在上一篇文章:站在AI风口的第一个AI程序:helloAI 中,我们实现了用Python连接通义千问大模型的简单chat。现在,我们再来看看发起大模型请求时的局部代码:
# 2. 发起流式请求
completion = client.chat.completions.create(
# 模型名字,不可乱填!!!可参考各模型官网
# model="qwen-plus", # 阿里千问
model="deepseek-v3.2", # deepseek
messages=[
{"role": "system", "content": "You are a helpful assistant."},
{"role": "user", "content": "iOS开发转型AI大模型应用开发该怎么学习?"}
],
# 通过 extra_body 设置 enable_thinking 开启思考模式
# extra_body={"enable_thinking": True},
stream=True,
stream_options={"include_usage": True}
)
显然,client.chat.completions.create中有很多配置,除了我们写的还有哪些配置呢?我们可以打开通义千问文档-OpenAI Chat作参考:
top_k 非OpenAI标准参数这里先不讨论,那么其他几个参数:什么采样温度、采样阈值看着都认识,但是到底什么意思?在大模型处理中怎么发挥作用的呢?
作为初学者看着晦涩难懂很正常,好在我们有一个heeloAI程序。我们可以实践一下看看他们的区别,这本身就会加深我们对这几个参数的理解。Talk is cheap,show you the code!
实践出真知
撸起袖子就是干
根据参数解释,temperature和top_p控制文本多样性,我们重点关注这两个参数。presence_penalty控制重复度,显然很好理解。
在操作之前,带着问题去实践是一个很好的思路。至少,我看到这两个参数会有以下疑问:
-
temperature到底怎么决定文本多样性的?
-
既然已经有了temperature,为什么还有个top_p参数?没有可以吗?如果不可以,他们之间是怎么协作的?
-
如果temperature=0,top_p=0.01,理论上生成的文本接近一个确定值,那么多次运行同一提示词,大模型输出会一定一致吗?
-
3的拓展:如果同一提示词两次的temperature和top_p一致,大模型输出会一定一致吗?
OK,接下来我们固定提示词:雨天的街道... 要求续写这个故事,得到的故事总字数在30字左右。 记录下我们程序运行的结果:
| 序号 | temperature | top_p | output | comment |
|---|---|---|---|---|
| 0 | 0.1 | 0.2 | 雨天的街道,伞下两人相遇,水花轻溅,脚步却未停 | 低t低p_1 |
| 1 | 0.1 | 0.2 | 雨天的街道,伞下两人相遇,水花轻溅,脚步却未停 | 低t低p_2 |
| 2 | 0.1 | 0.2 | 雨天的街道,伞下两人相遇,水花轻溅,脚步却未停 | 低t低p_3 |
| 3 | 0.1 | 0.8 | 雨天的街道,伞下两人相遇,水花轻溅,脚步却未停 | 低t高p-1 |
| 4 | 0.1 | 0.8 | 雨天的街道,一把红伞下,两个身影渐渐靠近。 | 低t高p-2 |
| 5 | 1 | 0.5 | 雨天的街道,她撑伞走过,水洼里映出模糊的霓虹 | 中t中p_1 |
| 6 | 1 | 0.5 | 雨天的街道,一把红伞下,两颗心悄然靠近 | 中t中p_2 |
| 7 | 1.6 | 0.2 | 雨天的街道,伞下两人并肩,水洼映着朦胧街灯与渐远的背影 | 高p低t-1 |
| 8 | 1.6 | 0.2 | 雨天的街道,伞下偶然相遇,水洼映出两张模糊笑脸。 | 高p低t-2 |
| 9 | 1.6 | 0.2 | 雨天的街道,湿漉漉的街道,路灯映着水洼,一个撑红伞的身影渐行渐远 | 高p低t-3 |
| 10 | 1.6 | 0.9 | 雨天的街道,我看到了不该看的事情 | 高p高t-1 |
| 11 | 1.6 | 0.9 | 雨天的街道,迟归少年静静看水,那头是他走散的整个童年 | 高p高t-2 |
| 12 | 1.6 | 0.9 | 雨天的街道,孩童于涟漪的轻笑倒映中微笑着踩着水滩而过,恍如一地搖曳太陽。 | 高p高t-3 |
思考ing
仔细观察上表的结果差异,显然我们可以得出:
- 低t低p时,故事意象:伞、人、水花、脚步,比较常见且多次生成结果一致
- 低t高p时,故事意象和1差不多,但是多次运行会有不同的结果
- 中t中p时,故事意象:新增霓虹、人物数量、心,且更加有故事性了(两颗心、她),同时逻辑也不混乱
- 高t低p时,更有故事感和画面感,叙事也比较自然;每次结果都不同
- 高t高p时,故事更加发散和具有创意,但是好像也会有意料之外的问题
- 我看了不该看的事情 ??什么鬼,和前面的文风直接大变
- 少年静静看水,那头是他走散的整个童年 写得好有诗意,有创意
- 孩童于涟漪的轻笑倒映中微笑着踩着水滩而过,恍如一地搖曳太陽 ?? 什么鬼?创意过头了吧,前面还勉强能读,后面直接繁体字而且句意不通啊
结合以上分析和API文档参数解释,我们可以大概反推出temperature和top_p的意义(个人理解):
-
temperature:采样温度,是给全局定调
- 值越高,产出越丰富越随机
- 如果很低,即使top_p再高也不管用(见1-4)
- 本质:大模型生成Token前,会计算候选词得分(logits),通过softMax函数得到概率分布。temperature本质是对logits进行了“缩放” (了解即可)
-
top_p:核采样阈值,是基于temperature做范围限制
- 值越高,候选池越大,结果越多样、丰富
- 基于temperature限制候选范围,结合使用防止混乱、无意义词加入
- 本质:在选择下一个词时,会将候选词概率累加,只从概率总和为top_p的前n个词中选择概率最大的
-
Top_k:结合top_p,这里也不难理解。
- 在候选池中选择生成的前k个词中选择概率最大的
综上,temperature和top_p的互补性大于替代性:
-
若只用temperature,高t可能导致无边界随机,一些意想不到甚至乱码的东西也可能被选中
-
若只用top_p,低p可能导致单调重复,没有创意
-
📢📢📢OpenAI GPT-4中建议:优先使用top_p(0.8-0.95),再使用temperature(0.5-1)进行微调。
回到DeepSeek、豆包等AI软件
了解了大模型生成内容丰富性原理后,那么问题又来了:我们开头的疑问,DeepSeek、豆包等AI软件我们直接使用并没有设置temperature和top_p,为什么还是每次输出的结果不同???
我猜测哈:
-
deepseek使用的是Moe机制,就是多专家协同处理一个问题。当第一次提出时,分析有专家A、B、C处理,当再次运行时本来也应该是A、B、C,但B在处理其他事情,这个时候让职责类似的F参与处理,也就是第2次是A、C、F处理的结果。所以可能有所不同。(个人猜测,未验证!!!)
-
生成策略的“最后1km”的不确定性,即使我们设置再使用temperature=0,每一步选择最高概率。但因为链路长度和计算复杂性,最终可能有相等概率的几个词,这里多选一的机制可能会造成差异。
- 理由:硬件层的“浮点幽灵👻”问题,像OpenAI的词向量维度有12288,多重矩阵计算下必然存在小数点误差。这样就会使得(A+B)+C ≠ A+(B+C),产生蝴蝶效应继而引发上述问题
-
哈哈,关于这点,你有更好更确切的解释吗?欢迎👏大家评论讨论哈区🏻