第 42 课 · 基础 · 18 分钟

Python softmax 与温度

把原始分数变成不会溢出的概率分布。

softmaxlogits温度概率

情感模型吐出 4.2 和 -1.7 这样的分数,它们不是概率。softmax 把它们变成一个加起来等于一的分布。为什么先减掉最大值再取指数?

分类器经常输出一组原始分数,称为 logits。Softmax 把分数变成总和为一的正数,使其可以作为概率分布使用。关键技巧是在取指数前减去最大分数,避免大数值溢出。 你还会用对数损失衡量自信的错误,并把概率变成审核阈值。

取指数并归一化

Softmax 对每个 logit 取 exp,再除以总和。exp 让所有值变为正数并保持顺序,除法让结果总和为一。logit 越大,概率越大,但输出并不代表模型一定正确。

import math

def softmax(logits):
    exps = [math.exp(x) for x in logits]
    total = sum(exps)
    return [x / total for x in exps]

print([round(p, 3) for p in softmax([2, 0])])

正数,且总和为一

减去最大值保持稳定

exp(1000) 对浮点数来说太大,即使最终比例很普通。给每个 logit 减去最大值,可以在不改变比例的情况下平移所有数值。这是标准的稳定实现,不是近似。

import math

def softmax(logits):
    largest = max(logits)
    exps = [math.exp(x - largest) for x in logits]
    total = sum(exps)
    return [x / total for x in exps]

print([round(p, 3) for p in softmax([1000, 1000])])

先平移,再取指数

用温度改变尖锐程度

在 softmax 前把每个 logit 除以一个正温度。温度小于一会让最大分数更占优势;温度大于一会让分布更平缓。温度改变的是输出中的不确定性,不是底层证据。

import math

def softmax(logits, temperature=1.0):
    scaled = [x / temperature for x in logits]
    largest = max(scaled)
    exps = [math.exp(x - largest) for x in scaled]
    total = sum(exps)
    return [x / total for x in exps]

print([round(p, 3) for p in softmax([2, 0], 0.5)])
print([round(p, 3) for p in softmax([2, 0], 2.0)])

温度越低越尖锐

看整个分布,而不只看赢家

最大概率对应 argmax,但其他数值同样携带信息。[0.34, 0.33, 0.33] 与 [0.98, 0.01, 0.01] 的赢家相同,含义却完全不同。检查数值是否有限,并确认总和约等于一。

probs = [0.7, 0.2, 0.1]
winner = max(range(len(probs)), key=probs.__getitem__)
print(winner)
print(round(sum(probs), 3))

argmax 加上基本检查

对数损失惩罚自信的错误

对单条样本,对数损失是正确类别概率的负对数。以 0.9 的概率答对贡献很小;自信地答错贡献很大。对各样本损失取平均,并在取对数前截断精确的零。

import math

for probability in [0.9, 0.5, 0.01]:
    loss = -math.log(probability)
    print(probability, round(loss, 3))

置信度改变惩罚

把概率变成审核阈值

概率只有选定阈值后才会变成动作。如果自动答错的代价很高,就把不确定的样本送去审核。应在验证集上,根据审核与错误的相对成本选择阈值,而不是在测试集上选。

def action(probability, threshold=0.8):
    return "accept" if probability >= threshold else "review"

for probability in [0.95, 0.72, 0.40]:
    print(probability, action(probability))

置信度闸门,而不是猜测

本课要点

  • Softmax 把任意 logits 变成总和为一的正数。
  • 取 exp 前减去最大 logit,避免溢出。
  • 温度小于一会让分布更尖锐,大于一会更平缓。
  • 最大概率是 argmax,但整个分布都有信息。
  • 概率分布不等于正确性保证。
  • 对数损失惩罚自信的错误;阈值把概率变成考虑成本的动作。

常见错误

  • 直接对巨大 logits 取 exp,没有先减去最大值。
  • 归一化之后才应用温度,而不是在 softmax 前。
  • 把最高概率当成答案一定为真的证明。
  • 把 softmax 的最大值当成确定性,却不检查校准或错误成本。
轮到你

编写接受温度的稳定 softmax,对 logits [3, 1, 0] 分别用温度 0.5 和 2.0 打印保留三位小数的分布。

动手试试

改改变量、先预测输出,再运行代码。第一次点击“运行代码”时会下载 Python 运行时,可能需要几秒钟。

浏览器内 Python本地运行 · 无需账号
首次运行会从 CDN 下载 Pyodide。修改后点击“运行代码”。

练习本课

12 道题,作答后立即看到解释。

查看 12 道题答案开始练习
← 分词与向量最近邻分类 →