从概率分布中选择单个词元(采样、解码): AI 是怎么做选择题的?
#2025/12/29 #ai
大语言模型(LLM)写文章其实就像在玩一个“猜下一个词”的游戏。
当它写到“我正在开一辆……”时,它不会直接告诉你答案,而是先给出一个“候选名单”,并给每个候选词打分(概率)。
目录
- 📊 第一步:模型给出的“候选名单”
- 🕹️ 策略一:贪心解码 (Greedy Decoding) —— “无聊的学霸”
- 🎲 策略二:随机采样 (Sampling) —— “有趣的灵魂”
- 🔧 两个控制“脑洞”的参数
- 📝 总结
📊 第一步:模型给出的“候选名单”
假设模型计算完所有的数学公式后,给出了这样的概率分布(可以看作一个字典):
# 模型输出的概率分布
next_token_probs = {
"车": 0.40, # 可能性最高,40%
"卡车": 0.13, # 可能性一般,13%
"自行车": 0.08, # 可能性较低,8%
"大象": 0.02, # 离谱但不是不可能,2%
# ... 其他几万个词概率几乎为0
}
现在问题来了:
- 虽然“车”的分数最高,但我们一定要选它吗?
这就涉及到了解码策略(Decoding Strategy),也就是我们今天要讲的核心——怎么做决定。
🕹️ 策略一:贪心解码 (Greedy Decoding) —— “无聊的学霸”
规则:永远只选分数最高的那个词。
比喻:就像考试做选择题,你永远只选你觉得最对的那个选项,从来不猜。
代码逻辑:
def greedy_decoding(probs):
# max() 函数直接取最大值
return max(probs, key=probs.get)
# 结果:每次运行都会返回 "车"
print(greedy_decoding(next_token_probs))
- 优点:稳定、准确。
- 缺点:
- 太死板了!如果你让它讲笑话,它每次都会讲同一个笑话,因为每次概率最高的词都是固定的。这就解释了为什么把
Temperature(温度)设为 0时,AI 的回答总是一模一样的。
- 太死板了!如果你让它讲笑话,它每次都会讲同一个笑话,因为每次概率最高的词都是固定的。这就解释了为什么把
🎲 策略二:随机采样 (Sampling) —— “有趣的灵魂”
规则:
- 根据分数的比例,像转盘抽奖一样随机选。
比喻: - 虽然“车”的中奖区最大(40%),但转盘转起来后,指针也有可能停在“卡车”(13%)甚至“大象”(2%)的区域。
代码逻辑:
import random
def random_sampling(probs):
tokens = list(probs.keys())
weights = list(probs.values())
# choices 函数根据权重随机抽签
return random.choices(tokens, weights=weights, k=1)[0]
# 结果:
# 第1次运行 -> "车" (概率最大,最容易中)
# 第2次运行 -> "卡车" (有点意外,但通顺)
# 第3次运行 -> "大象" (非常有创意的故事走向!)
- 优点:有创造力!这是让 AI 写作、聊天变得生动、不重复的关键。
- 缺点:有时候会“抽风”,选出完全不通顺的词(比如“我正在开一辆…大象”)。
🔧 两个控制“脑洞”的参数
为了不让 AI 太死板,也不让它太疯狂,程序员发明了两个参数来微调这个“转盘”:
1. Temperature (温度)
- 作用:
- 控制概率分布的“贫富差距”。
- 低温 (接近0):
- 放大差距。高的更高,低的更低。结果几乎等于贪心解码(保守)。
- 高温 (比如1.0):
- 缩小差距。让低概率的词也有更多机会被选中(
更有创意,更疯狂)。
- 缩小差距。让低概率的词也有更多机会被选中(
2. Top-P (核采样 / Nucleus Sampling)
- 作用:
- 把那些
概率太低、太离谱的“垃圾选项”直接切掉,只在剩下的好词里抽奖。
- 把那些
- 逻辑:
- 比如设定
Top-P = 0.9,那就只把概率最高的几个词加起来,直到总和达到 90%,剩下的 10% 这种极其冷门的词(比如“大象”)根本不进入抽奖池。
- 比如设定
- 效果:
- 既保留了变化的乐趣,又防止了完全胡说八道。
📝 总结
- 模型输出 = 一堆带有概率的候选词。
- 解码(采样) = 决定到底选哪个词的算法。
- 贪心 = 永远选第一名(无聊但稳)。
- 采样 = 按概率抽奖(有趣但偶尔翻车)。