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 输出为正且总和为一。
- 取指数前减去最大 logit。
- 使用正温度,并记录它的作用。
- 计算对数损失前截断概率。
- 报告最高概率和差距,而不只是 argmax。
常见问题
softmax 只用于神经网络吗?
不是。它是一般性的分数归一化方法,只是神经网络分类器经常使用。
温度能提高准确率吗?
本身不能。它改变分布的尖锐程度,校准和评估是另外的步骤。
为什么对数损失要截断概率?
log(0) 无定义。截断让损失保持有限,但不能挽救给真值零概率的模型。
练习 softmax
12 道题,覆盖归一化、稳定性、温度、argmax 和对数损失。
继续阅读: