专项练习 · 9 分钟阅读

Python softmax 练习:稳定性、温度与对数损失

softmax 看起来只有两行算术,细节却很重要:溢出、温度,以及概率和决策之间的区别。这些练习逐块搭建,再连接到损失函数。

归一化指数值

对每个 logit 取 exp,再除以总和。输出为正且总和为一。测试中要检查总和,因为静默的归一化错误会让后续指标失去意义。

import math

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

probs = softmax([1, 1])
print([round(p, 3) for p in probs])
print(round(sum(probs), 3))

检查过的分布

减去最大值

很大的 logit 在归一化前就会溢出。减去最大值可以在不改变比例的情况下平移所有数值。结果在数学上相同,在数值上安全。

import math

def stable_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 stable_softmax([1000, 1000])])

同样的答案,不再溢出

改变温度

温度在 softmax 前除 logits。小于一的值让最大分数更突出;大于一的值让分布更平缓。温度不会增加证据,只会改变模型的确定程度。

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)])

更尖锐或更平缓

计算真实类别的对数损失

如果真实类别的预测概率是 p,对数损失是 -log(p)。自信且正确时损失低;自信却错误时损失很大。取对数前要把概率截断到零以上。

import math

p_true = 0.8
loss = -math.log(max(p_true, 1e-12))
print(round(loss, 3))

为自信付出代价

argmax 是决策,不是真理

最高概率给出类别标签,但整个分布可能很接近、很犹豫。要同时报告最高概率和第一、第二名的差距。影响重大的决定应加入人工复核,或在低置信度时弃权。

probs = [0.46, 0.44, 0.10]
order = sorted(range(len(probs)), key=probs.__getitem__, reverse=True)
print(order[0])
print(round(probs[order[0]] - probs[order[1]], 2))

赢家加差距

你的练习清单

常见问题

softmax 只用于神经网络吗?

不是。它是一般性的分数归一化方法,只是神经网络分类器经常使用。

温度能提高准确率吗?

本身不能。它改变分布的尖锐程度,校准和评估是另外的步骤。

为什么对数损失要截断概率?

log(0) 无定义。截断让损失保持有限,但不能挽救给真值零概率的模型。

练习 softmax

12 道题,覆盖归一化、稳定性、温度、argmax 和对数损失。

打开练习

继续阅读: