📕 第4章 类神经网络的基础
📄 一句话概括

学习就是不断调参数、让损失变小。 损失函数就是那个被打分的东西,它决定了模型最终会学成什么样。 平方误差 E = ½Σ(t-y)² 最直觉,但配 sigmoid 时饱和区会把梯度压没。 交叉熵 E = -Σt·log y 在答错时梯度更大,所以分类任务几乎都用它。 实测:正确答案是 1、网络只给 0.01 时,平方误差 0.4900、梯度 -0.99; 交叉熵 4.6052、梯度 -100.0。两者差一百倍。

📝 本节和前面几节的关系

4.4 节讲训练循环时,「算损失」那一步只是一笔带过。这一节把它摊开。 第 1 章 1.3 节提过批量学习与在线学习,这一节从「损失」这个角度再看同一件事。 下一节的反向传播是从损失往回推的,所以损失的导数长什么样,直接决定了梯度长什么样。

一、三种学习方式:一次看几个样本

批量学习把所有样本过一遍、把梯度加起来、然后更新一次。 方向准,但一轮只前进一步,而且整个数据集得装进内存。 在线学习来一个样本就更新一次。 快、能跟上数据分布的变化,但单个样本的梯度噪声大,损失曲线全是毛刺。 小批量学习(mini-batch)折中:一次看 32 或 128 个。 既利用了矩阵运算的并行,又保留了噪声带来的好处,现在是事实标准。 第 1 章的实测可以挪到这里看:同一份 XOR 数据,批量更新 54 次就收敛,在线要 266 次。 不是在线学习更笨,是它每次只看一个样本,走的路更弯。

二、平方误差:最直觉的那一个

E = ½ Σ (t - y)²。前面那个 ½ 没有别的作用,只是让求导时平方出来的 2 被约掉。 对 y 求导得 ∂E/∂y = y - t。 判对了是 0,判错了正比于差多少。这恰好是 4.3 节差量规则的推广——差量规则就是「一个样本、 一次更新」的平方误差。 多个输出时把各类加起来,就是「每个输出都往自己的目标值靠」。回归任务到现在还是默认用它。

三、交叉熵:给概率准备的

E = -Σ t·log y。 t 是 one-hot,只有正确那一类是 1,所以求和号后面其实只剩一项:E = -log y_正确。 它对「自信地答错」罚得极重:y_正确 = 0.01 时 -log 0.01 = 4.6052;y_正确 = 0.99 时只有 0.0101。 差距不是线性的,是对数的反向。 导数 ∂E/∂y = -t/y。y 越小分母越小,梯度越大——这是交叉熵最要紧的性质。

四、为什么分类任务几乎都用交叉熵

三条理由,按工程上的重要性排: 第一,梯度尺度对。答错越狠推得越用力。 平方误差的梯度是 p-1,p 落在 0 到 1 之间,所以它最大也就到 -1,答错到 0.01 时仍然是 -0.99。 第二,和 sigmoid、softmax 配起来能约掉饱和因子。 平方误差配 sigmoid 时,对 z 的梯度是 (y-t)·y(1-y); y 饱和到 0.99 时 y(1-y) 只剩 0.0099,两个小量相乘,梯度几乎传不回去。 第三,信息论解释:交叉熵衡量两个分布的差异,最小化它就是让预测分布逼近真实分布。 这条最「正确」,但真正让它在工程上胜出的是前两条。 有个反直觉的细节: p=0.99 时平方误差 0.0001,比交叉熵的 0.0101 还小。所以「交叉熵的损失值更小」是错的, 它胜在梯度形状,不在数值大小。

五、损失函数的选择表

任务 输出层 损失函数 备注
回归(预测一个连续数) 不加激励 平方误差 输出范围不限
二分类 sigmoid(1 个输出) 交叉熵 也可以两个输出加 softmax
多分类 softmax(N 个输出) 交叉熵 类别互斥时用
多标签 sigmoid(N 个输出) 各类交叉熵相加 类别不互斥时用

这张表是工程默认值,不是定理。 真正决定的是「你想让什么样的错误被罚得更重」——写损失函数,其实就是在写这句话。

六、动手 Demo:损失函数:区别在一个分母

造一个最简场景:正确答案是 1,网络给出概率 p。 p 从 0.99 一路降到 0.01,把两种损失的数值和梯度一起算出来。

import numpy as np

for p in (0.99, 0.90, 0.50, 0.10, 0.01):
    sq = 0.5 * (p - 1.0) * (p - 1.0)          # 平方误差
    sq_g = p - 1.0                            # 它对 p 的导数
    ce = -np.log(p)                           # 交叉熵(正确答案是 1)
    ce_g = -1.0 / p                           # 它对 p 的导数
    print("p=%.2f  平方 %.4f 梯度 %+.4f   交叉 %.4f 梯度 %+.4f"
          % (p, sq, sq_g, ce, ce_g))

实跑输出:

--------------------------------------------------------------------
损失函数:平方误差与交叉熵,区别在一个分母
--------------------------------------------------------------------

  一个样本、正确答案是 1。看网络给出不同的概率 p 时,两种损失各是多少、梯度各有多大。

  p      平方误差  其梯度    交叉熵    其梯度
  ---------------------------------------------
  0.99   0.0001    -0.0100   0.0101    -1.0101
  0.90   0.0050    -0.1000   0.1054    -1.1111
  0.50   0.1250    -0.5000   0.6931    -2.0000
  0.10   0.4050    -0.9000   2.3026    -10.0000
  0.01   0.4900    -0.9900   4.6052    -100.0000

  **p = 0.99(答得很对):平方误差 0.0001、交叉熵 0.0101,两个都很小。**
  **p = 0.01(自信地答错):平方误差 0.4900、交叉熵 4.6052。**
  看梯度那一列,差距更狠:平方误差给 -0.99,交叉熵给 -100.0——**差一百倍。**

  为什么?平方误差对 p 的导数是 p - 1,最大也就是 1;
  交叉熵的导数是 -1/p,p 越小它越爆炸。**这正是我们想要的:**
  模型越是「自信地答错」,越该被狠狠推一把。

  反过来,平方误差配 sigmoid 还有个隐患:**输出饱和时,两个小量相乘**,
  梯度会小到几乎传不回去。交叉熵和 sigmoid 配在一起,那个分母恰好把饱和的因子约掉——
  这就是分类任务几乎都用交叉熵的工程原因,不只是「理论上更合理」。

数值那一列,p 越小两列分得越开。 p=0.99 时两个都很小(0.0001 对 0.0101),p=0.01 时变成 0.4900 对 4.6052。 梯度那一列更狠:p=0.01 时平方误差给 -0.99,交叉熵给 -100.0。 平方误差的梯度被 1 卡住了上限,交叉熵没有上限。 上限从哪来?平方误差对 p 的导数是 p-1,p 落在 0 到 1 之间,所以它的绝对值最大就是 1。 交叉熵的导数是 -1/p,p 趋向 0 时它没有边界。 但也别把交叉熵当万能:p 恰好等于 0 时 log 0 会出问题, 实际代码里都要加一个极小量(Demo 里加的 1e-12)。这已经不是数学问题,是浮点问题。 还有一条更隐蔽的好处:交叉熵和 sigmoid 配在一起时,那个 1/p 恰好把 sigmoid 的导数 p(1-p) 约掉, 对 z 的梯度退化成一个干净的减法 y-p。这就是 4.7 节反向传播里 dp 那一行能写得那么短的原因。

30 秒实验

  1. 把 p=0.01 那行的交叉熵手算一遍:-log 0.01 等于多少?(提示:ln 10 约等于 2.302585)
  2. 把平方误差前面的 ½ 去掉,对 p 的导数会变成多少?梯度上限还是 1 吗?
  3. 如果标签不是 1 而是 0.7(这叫标签平滑),p=0.01 时交叉熵会变成多少?

常见误区

  1. 以为损失值小就代表模型好。损失是「用某把尺子量出来的差距」,换一把尺子数值全变。 只有同一把尺子下的数才能互相比较。换损失函数之后,旧的学习率、旧的收敛轮数全部作废。
  2. 以为交叉熵只能用于分类。它衡量两个分布的差异,只要输出能解释成概率分布就能用。 语言模型的损失就是交叉熵,只不过类别数是整个词表。
  3. 把那个 ½ 当成装饰。它只为求导时约掉 2。 去掉它,梯度整体乘 2,等价于学习率翻倍——不会报错,但会让调参记录对不上。
自测三问(点开对答案) 1. 「自信地答错」时,两种损失的梯度差多少? —— 实测 p=0.01:平方误差 -0.99,交叉熵 -100.0,差一百倍。 原因是平方误差的导数 p-1 有上限 1,交叉熵的导数 -1/p 没有上限。 2. 平方误差配 sigmoid 为什么会梯度消失? —— 对 z 的梯度是 (y-t)·y(1-y)。 输出一旦饱和到 0.99,y(1-y) 只剩 0.0099,两个小量相乘,梯度就快没了。 交叉熵的那个分母正好把它约掉。 3. 小批量学习为什么成了事实标准? —— 它同时拿到批量的稳定和在线学习的快:一次看几十上百个样本,梯度噪声被平掉大半, 同时又能用上矩阵运算的并行。

损失函数定了,接下来两个问题:导数怎么算得出来、又怎么用它改参数。 下一节先看最简单的情形——只有一个参数时,怎么一步步挪到谷底。

相关笔记