Decode-Only架构
Decode-Only架构
1. Softmax 公式
1.1 公式说明
Softmax 起源于 统计力学 和 概率论,传统的概率分布是由 Softmax 公式 计算得到的:
$$
softmax(x_i) = exp(x_i) / Σexp(x_j)
$$
其中:
x_i:第 i 个元素的原始分数exp(x_i):e 的 x_i 次方Σexp(x_j):所有元素的 exp 值之和
它的作用是能 将任意数值转换为概率分布 且 满足概率的基本要求(≥0,和为1)
比如现在有["GPT", "AI", "小明", "老师"] 经过矩阵运算得出原始分数为 [5.0, 3.0, 1.0, 0.5] 的候选词,其中 5.0 比 3.0 大,说明 "GPT" 比 "AI" 更可能出现,但这些数字不是 概率*(概率应该在0-1之间,且和为1)*
目标:转换为概率
希望得到如概率分布为 [0.5, 0.3, 0.2, 0] 这种 每个值在 0-1 之间,且所有值相加为 1
1.2 为什么要使用 exp
比如使用最原始的 相加求和再相除 直接归一化行不行
原始分数 = [5.0, 3.0, 1.0, 0.5]
总和 = 5.0 + 3.0 + 1.0 + 0.5 = 9.5
概率 = [5.0/9.5, 3.0/9.5, 1.0/9.5, 0.5/9.5]
= [0.53, 0.32, 0.11, 0.05]这样虽然看起来可以,但有如果概率是负数怎么办?
原始分数 = [2.0, 1.0, -1.0, -2.0]
总和?? = 2.0 + 1.0 + (-1.0) + (-2.0) = 0因此 通过 exp 的特性把负数变正数,exp(x) 的特性:
- exp(正数) = 很大的正数
- exp(0) = 1
- exp(负数) = 很小的正数(但仍然是正数!)
例子:
exp(2.0) = 7.39
exp(1.0) = 2.72
exp(-1.0) = 0.37 # 负数变正数了!
exp(-2.0) = 0.14 # 负数变正数了!此时,所有的值都变成正数了!✅
但此时总和依然 不是 1 ,因此再依据最原始的 相加求和再相除
相加求和 = 7.39 + 2.72 + 0.37 + 0.14 = 10.62
除以总和 概率归一化 = [7.39/10.62, 2.72/10.62, 0.37/10.62, 0.14/10.62]
= [0.7, 0.26, 0.03, 0.01]2. 掩码自注意力 (Masked Self-Attention) 。
在 Decoder-Only 架构中,这个机制变得至关重要。它的工作原理非常巧妙,其本质如下:
GPT 的掩码本质: 对注意力分数矩阵应用一个布尔掩码矩阵,将需要屏蔽的位置设为 -inf。是 在数值上做加法/替换,然后利用 Softmax 的数学特性 来实现屏蔽。
# 1. 注意力分数矩阵(原始)
attention_scores = [
[2.5, 1.8, 0.3],
[3.2, 2.1, 1.5],
[1.0, 0.8, 2.0]
]
# 2. 掩码矩阵(布尔矩阵)
mask = [
[False, True, True ], # True = 需要屏蔽
[False, False, True ],
[False, False, False]
]
# 3. 应用掩码(矩阵操作)
masked_scores = attention_scores.masked_fill(mask, -inf)
# 结果:True的位置变成-inf,False的位置保持不变用具体例子解释 GPT 掩码机制,说明它如何通过"大负数"实现
具体步骤演示
假设我们有一个句子:"我 爱 你",计算第2个词"爱"的注意力时:
步骤1:计算注意力分数矩阵
位置: [0:我] [1:爱] [2:你]
[0:我] 2.5 1.8 0.3
[1:爱] `3.2 2.1 1.5` ← 这是"爱"对所有词的注意力分数
[2:你] 1.0 0.8 2.0步骤2:应用掩码(关键步骤)
在预测"爱"时,不能看 "你"(位置2),所以把位置2的分数替换为 "-inf"(或一个很大的负数,如 -1e9):
位置: [0:我] [1:爱] [2:你]
[0:我] 2.5 -inf -inf ← "我"不能看"爱"和"你"
[1:爱] 3.2 2.1 -inf ← "爱"不能看"你"
[2:你] 1.0 0.8 2.0 ← "你"可以看所有(但实际也不能看未来)步骤3:使用 Softmax 公式进行归一化
对 "爱" 这一行 [3.2, 2.1, -inf] 计算:
import math
# exp(3.2) = e^3.2
result1 = math.exp(3.2)
print(result1) # 输出: 24.532530197109352
# exp(2.1) = e^2.1
result2 = math.exp(2.1)
print(result2) # 输出: 8.16616991256765
"""
exp(3.2) = 24.53
exp(2.1) = 8.17
exp(-inf) = 0 ← 关键!e的负无穷次方 = 0
总和 = 24.53 + 8.17 + 0 = 32.70
最终概率:
P(我) = 24.53 / 32.70 = 0.75 (75%)
P(爱) = 8.17 / 32.70 = 0.25 (25%)
P(你) = 0 / 32.70 = 0 (0%) ← 被完全屏蔽了!
"""为什么这样有效?
- 数学特性:
exp(-inf) = 0,所以-inf经过 Softmax 后概率为 0 - 归一化保证: Softmax 保证所有概率和为 1,被屏蔽位置的概率被分配给其他位置
3. 提示工程
3.1 提示工程的本质
:::success
提示工程 = 通过设计提示词来引导概率分布
:::
举例:
普通提示,如下提示词会导致 概率分布较均匀,生成结果不确定
prompt1 = "写一个故事" probs1 = softmax(model(prompt1))精心设计的提示,会使 概率分布更集中在相关词汇上
prompt2 = "写一个关于AI的科幻故事,主角是一个机器人" probs2 = softmax(model(prompt2)) # "机器人"、"AI"、"未来"等词概率更高
3.2 采样参数
采样参数的本质就是在此基础上,根据不同策略"重新调整"或"截断"分布,从而改变大模型输出的下一个token
3.2.1 Temperature
温度 是控制模型输出 "随机性" 与 "确定性" 的关键参数, 这个和物理中的温度也很类似:
温度高 → 粒子运动剧烈 → 更随机温度低 → 粒子运动缓慢 → 更有序
其原理是: 引入温度 系数 T > 0 时, 将 Softmax 公式改写为
$$
p_i(T) = exp(z_i / T) / Σexp(z_j / T)
$$
其中:
z_i:第 i 个原始分数T:温度参数(T > 0)exp(z_i / T):先除以 T,再取指数
它的作用是相当于 "缩放" 原始分数 如:
# 原始分数
z = [5.0, 3.0, 1.0, 0.5]
# 标准 Softmax(T = 1)
exp(5.0 / 1) = exp(5.0) = 148.41
exp(3.0 / 1) = exp(3.0) = 20.09
# 温度 Softmax(T = 2)
exp(5.0 / 2) = exp(2.5) = 12.18 # 缩小了!
exp(3.0 / 2) = exp(1.5) = 4.48 # 缩小了!
# 温度 Softmax(T = 0.5)
exp(5.0 / 0.5) = exp(10.0) = 22026.47 # 变大了!
exp(3.0 / 0.5) = exp(6.0) = 403.43 # 变大了!当T变小时,原始分数所占权重*(高概率)*变大,分布 "更加陡峭",生成更 "保守" 且 重复率更高 的文本。
当T变大时,原始分数所占权重*(高概率)*缩小,分布 "更加平坦",生成更 "多样" 但可能出现 不连贯 的内容。
相关信息
技巧:
**低温度(0 ⩽⩽ Temperature << 0.3)**输出更 "精准、确定"
- 场景: 问答、数据计算、代码生成、法律条文解读、技术文档撰写、学术概念解释等。
**中温度(0.3 ⩽⩽ Temperature << 0.7)**输出 "平衡、自然"
- 场景: 客服交互、聊天机器人、如邮件撰写、产品文案、简单故事创作等。
**高温度(0.7 ⩽⩽ Temperature << 2)**输出 "创新、发散"
- 场景:诗歌创作、科幻故事构思、广告 slogan brainstorm、艺术灵感启发、发散性思考。
3.2.2 Top-K
其原理是: 将所有 token 按概率从高到低排序,取排名前 k 个的 token 组成 "候选集",随后对筛选出的 k 个 token 的概率进行 "归一化":
$$
p̂_i = p_i / Σp_j (j ∈ 候选集)
$$
其中:
p_i:原始概率候选集:概率最高的 k个词p̂_i:重新归一化后的概率
假设词汇表有 10 个词,并经过 Softmax 后得出了概率分布如下,然后前几个词概率高,最后 1 个词 概率很低,只有 0.005
# 假设词汇表有10个词(简化)
vocab = ["的", "是", "在", "了", "和", "有", "我", "你", "他", "她"]
# 原始概率分布(经过Softmax)
probabilities = {
"的": 0.40,
"是": 0.30,
"在": 0.15,
"了": 0.10,
"和": 0.03,
"有": 0.01,
"我": 0.005,
"你": 0.003,
"他": 0.001,
"她": 0.0005
}
# 验证:所有概率和 = 1.0 ✅如果进行 随机采样,则可能选到概率很低的词,假设选到了概率只有 0.0001 的词,则意味着 → 生成质量差
**目标:**只从高概率的词中采样
**步骤1:**按概率从高到低排序
sorted_probs = [ ("的", 0.40), # 第1名 ("是", 0.30), # 第2名 ("在", 0.15), # 第3名 ("了", 0.10), # 第4名 ("和", 0.03), # 第5名 ("有", 0.01), # 第6名 ("我", 0.005), # 第7名 ("你", 0.003), # 第8名 ("他", 0.001), # 第9名 ("她", 0.0005) # 第10名 ]**步骤2:选择前 k 个(假设 k=3)
候选集 = [ ("的", 0.40), ("是", 0.30), ("在", 0.15) ] # 候选集的概率和 候选集概率和 = 0.40 + 0.30 + 0.15 = 0.85**步骤3:**对候选集的概率重新归一化,套公式:
p̂_i = p_i / Σp_j (j ∈ 候选集)p̂_的 = 0.40 / 0.85 = 0.47 p̂_是 = 0.30 / 0.85 = 0.35 p̂_在 = 0.15 / 0.85 = 0.18验证:
0.47 + 0.35 + 0.18 = 1.0✅
此时新的概率分布为(只包含候选集)
new_probs = {
"的": 0.47,
"是": 0.35,
"在": 0.18,
# 其他词的概率 = 0(被排除了)
"了": 0.0,
"和": 0.0,
# ...
}后续只会 根据新的概率分布 从候选集这 3个词 中随机采样
next_token = sample(new_probs)next_token 则可能选到:
- "的"(47%概率)
- "是"(35%概率)
- "在"(18%概率)
3.2.3 Top-p
其原理是: 将所有 token 按概率从高到低排序,从排序后的第一个 token 开始,逐步累加概率*,*依次加入 集合 S,直到累积和首次达到或超过 阈值 p 时:
$$
i∈S
∑
p(i)≥p
$$
当前 集合 S 就是 "核集合", 最后只对 集合 S 中的 token 重新归一化,再进行采样。
当模型预测每个词(token)的概率时,整个词表可能有 几万个候选,Softmax 把这些词转成概率分布。但即便某个字符概率只有 0.01%,如果只用普通采样,它也有机会被选中,导致输出可能突然 "跳车"。
**目标:**只在 "累积概率重要" 的词里抽样。
:::success
Top-p: 能动态适应不同分布的 "长尾" 特性,对概率分布不均匀的极端情况 的适应性更好。
:::
3.2.4 各参数区别
| 方法 | 控制参数 | 含义 | 行为 |
|---|---|---|---|
| 温度 | T | 调整概率形状***(陡 / 平)*** | 调整 所有词的 **概率,**不削减候选,影响全局 |
| Top-k | k | 固定保留 k 个 | 限制 候选词 **数量,**不看具体概率大小 |
| Top-p | p | 动态覆盖累计概率 | 自适应分布、数量不定 |
常见组合:
温度采样(T=0.8)+ Top-k(k=50) ,即先平滑分布,再限制候选词