第 5 章:损失函数
神经网络需要一个"裁判"来评判自己预测得有多准。损失函数就是这个裁判。
5.1 损失函数的作用
前向传播之后,我们有:
- 预测值 y:网络认为图片是各数字的概率,shape
(n, 10) - 真实标签 t:图片实际是哪个数字,shape
(n,)(整数 0-9)
现在需要一个数字来描述"预测有多差"——这就是损失(Loss)。
要求:
- 预测越准,损失越小
- 预测越差,损失越大
- 函数要可微(能求导),这样才能用梯度下降优化
5.2 直觉:为什么用 log?
假设我们只考虑正确类别的预测概率:
真实标签是数字"7",网络输出概率:
情况A:y[7] = 0.90 (预测很准)
情况B:y[7] = 0.50 (预测一般)
情况C:y[7] = 0.10 (预测很差)我们希望损失函数满足:损失(A) < 损失(B) < 损失(C)
一个直觉想法:损失 = 1 - y[正确类别]
情况A:损失 = 1 - 0.90 = 0.10
情况B:损失 = 1 - 0.50 = 0.50
情况C:损失 = 1 - 0.10 = 0.90但实际上用的是
情况A:损失 = -log(0.90) ≈ 0.105
情况B:损失 = -log(0.50) ≈ 0.693
情况C:损失 = -log(0.10) ≈ 2.303比较两种方案:
情况A 情况B 情况C
1-y: 0.10 0.50 0.90 (等间距)
-log: 0.105 0.693 2.303 (差距不等)log 方案的优势:
- 预测接近 1(极好)时,损失极小(接近 0)
- 预测接近 0(极差)时,损失极大(趋向无穷大)
- 对"差得很远"的预测,给出更大的惩罚,优化动力更强
5.3 交叉熵损失(Cross-Entropy Loss)
5.3.1 公式
对于 n 个样本的批量,交叉熵损失是:
其中:
:第 个样本在正确类别 上的预测概率 :自然对数(以 为底) - 除以
:对所有样本求平均,使损失值不随 batch size 变化
核心思想:只看正确类别的预测概率,要它尽量大。
5.3.2 直观图示
-log(p)
↑
∞ |*
| *
| *
| *
2 | *
| *
1 | *
| *
0 +------+------+------→ p
0 0.5 1.0
↑ ↑
极差 完美
预测→损失趋∞ 预测→损失=05.4 从信息论理解交叉熵(选读)
如果你学过信息论,这里是更深层的理解。
信息熵(自信息): 一个事件的概率为
交叉熵的含义: 在真实分布(one-hot 标签)下,用模型预测的分布来编码信息,平均需要多少信息量。当模型预测完全正确时,交叉熵 = 真实熵(最小值)。
你不理解这段也没关系,直接记住公式就行。
5.5 代码实现分析
python
def cross_entropy_error(y, t):
if y.ndim == 1: # 单样本情况:变成(1, n)的矩阵
t = t.reshape(1, -1)
y = y.reshape(1, -1)
if t.size == y.size: # 如果 t 是 one-hot 编码,转成整数标签
t = np.argmax(t, axis=1)
n = y.shape[0]
return -np.sum(np.log(y[np.arange(n), t] + 1e-7)) / n关键行解析:
y[np.arange(n), t] — 花式索引
这是 numpy 的高级索引技巧,一次取出所有样本在正确类别上的概率:
python
n = 3
y = [[0.1, 0.2, 0.7], # 第0个样本
[0.8, 0.1, 0.1], # 第1个样本
[0.3, 0.6, 0.1]] # 第2个样本
t = [2, 0, 1] # 正确标签:0→类别2,1→类别0,2→类别1
np.arange(3) = [0, 1, 2]
y[np.arange(3), t]
= y[[0, 1, 2], [2, 0, 1]]
= [y[0,2], y[1,0], y[2,1]]
= [0.7, 0.8, 0.6] ← 各样本在正确类别上的概率+ 1e-7 — 防止 log(0)
如果某个概率预测值恰好是 0(极端情况),log(0) =
5.6 一个完整例子
设定:
批量大小 n=3,3个类别(0, 1, 2)
真实标签 t = [2, 0, 1]
预测概率 y:
样本0: [0.10, 0.20, 0.70] → 预测类别2(概率70%),正确!
样本1: [0.80, 0.15, 0.05] → 预测类别0(概率80%),正确!
样本2: [0.30, 0.60, 0.10] → 预测类别1(概率60%),正确!计算损失:
正确类别的概率:
样本0:y[0, t[0]] = y[0, 2] = 0.70
样本1:y[1, t[1]] = y[1, 0] = 0.80
样本2:y[2, t[2]] = y[2, 1] = 0.60
各损失:
-log(0.70) ≈ 0.357
-log(0.80) ≈ 0.223
-log(0.60) ≈ 0.511
平均损失:
L = (0.357 + 0.223 + 0.511) / 3 ≈ 0.364如果预测很差:
预测概率 y:
样本0: [0.40, 0.40, 0.20] → 预测类别0或1,但实际是类别2
样本1: [0.20, 0.60, 0.20] → 预测类别1,但实际是类别0
样本2: [0.50, 0.30, 0.20] → 预测类别0,但实际是类别1
正确类别的概率:
样本0:y[0, 2] = 0.20
样本1:y[1, 0] = 0.20
样本2:y[2, 1] = 0.30
各损失:
-log(0.20) ≈ 1.609
-log(0.20) ≈ 1.609
-log(0.30) ≈ 1.204
平均损失:
L = (1.609 + 1.609 + 1.204) / 3 ≈ 1.474预测差时损失 1.474,预测好时损失 0.364。差距明显,符合预期。
5.7 为什么 Softmax + 交叉熵是绝配?
这个组合不仅直觉上合理,数学上也有一个极其优雅的性质:
它们的联合梯度极其简洁!
具体推导在下一章(反向传播),这里先透露结论:
用人话说: 梯度 = 预测概率 - 真实标签(one-hot)。
- 如果
是正确类别:梯度 = (预测越接近1,梯度越小) - 如果
不是正确类别:梯度 = (预测越接近0,梯度越小)
网络"知道"自己错了多少,自动调整——这就是为什么这个组合在实践中表现优异。
5.8 小结
| 概念 | 记忆要点 |
|---|---|
| 损失函数 | 衡量预测与真实的差距,越小越好 |
| 交叉熵 | |
| 为什么用 log | 对差距大的预测惩罚更重,优化动力更强 |
| +1e-7 | 防止 log(0) 导致数值溢出 |
| 为什么配 softmax | 联合梯度极其简洁(见下一章) |
下一章:反向传播——如何利用损失函数的梯度,告诉每个参数该往哪个方向调整。
← 第 4 章 | 返回目录 | 第 6 章:反向传播 →