📕 第5章 卷积神经网络
📄 一句话概括

卷积的输出有正有负,ReLU 把负的截成 0。它不改形状、不改通道数、没有参数。 实测四个随机核的输出里,被截掉的比例是 47.2%、55.6%、52.8%、55.6%,大约一半。 它在卷积网络里的位置基本固定:卷积之后、池化之前。这个顺序不是随便定的。

📝 本节和前面几节的关系

4.2 节讲过 sigmoid、tanh、ReLU 三种激励函数,这一节只看它在卷积层上怎么用。 5.8 的池化紧跟其后。两个都不带参数,合起来就是「激活 + 降采样」这一对。 5.11 的 dropout 也在这附近,都是「在特征图上做逐元素操作」。

一、ReLU 在卷积网络里做什么

逐元素操作:对特征图的每个数值取 max(0, x)。不改形状、不改通道数、参数为零。 它唯一的作用是引入非线性。一个卷积层加一个 ReLU,才算「一层」。 只有卷积的话,堆多少层都等价于一层——这个账第 4 章 4.2 节算过:两个线性变换的复合还是线性变换。

二、为什么放在卷积之后

卷积是线性运算(加权和),必须紧跟一个非线性,否则白堆。 顺序一般是「卷积 → ReLU → 池化」。 严格说 ReLU 和最大池化可以交换,因为 max 和「取 0 以上的部分」这两个操作互不干扰,结果一样。 但实现上还是先 ReLU:先把一半负数抹成 0,后面池化比较时就少了一半负数要处理。这是工程习惯, 不是数学要求。

三、稀疏性:一半的特征图是黑的

实测被截掉的比例在 47% 到 56% 之间。随机权重下就该在 50% 附近。 这个稀疏不是浪费。 留下的那一半才是「这个核认出来的东西」,被截掉的那些等于在说「这里没有我要的图案」。 但稀疏过度就麻烦:某个核的输出如果全是负的,整张特征图都是 0,等于白放了一个核,还占着计算量。

四、死亡 ReLU 在卷积里更常见

一个单元的输入长期为负,梯度恒为 0,权重再也不会更新。这叫死亡 ReLU。 卷积里更容易发生,因为一个核的所有位置共享同一组权重和偏置: 偏置一旦被推得太负,整张特征图一起归零。 学习率太大时,一整片核可能同时死掉。 这时候训练损失会停在一个不动的值上,看起来像收敛了——这是最难查的一类「假收敛」。

五、几个变体

Leaky ReLU 在负数区给一个很小的斜率(比如 0.01),梯度不为 0,死不了。 ELU、GELU 是同类思路。GELU 现在是 Transformer 的默认选择。 批归一化常插在卷积和 ReLU 之间:先把输出标准化到均值 0、方差 1,再 ReLU。 这样每个核的输出大致对半分正负,整片死掉的概率大大降低。

六、动手 Demo:把负的响应截成 0

输入 1 通道 8×8 的随机噪声,4 个随机 3×3 核,卷积完再过一次 ReLU。 统计每个核的输出里有多少比例被截成 0。

import numpy as np

rg = np.random.default_rng(3)
x = rg.normal(0, 1, (1, 8, 8))          # 单通道 8×8
K = rg.normal(0, 0.6, (4, 1, 3, 3))     # 4 个核

# 卷积(省略函数体,见 5.3 节的 conv_multi)
y = conv_multi(x, K, np.zeros(4))
r = np.maximum(0.0, y)                  # ReLU:逐元素,负的归零

for k in range(4):
    neg = int((y[k] < 0).sum())
    print("核 %d  负数 %d / %d  被截掉 %.1f%%"
          % (k, neg, y[k].size, 100.0 * neg / y[k].size))

print("卷积输出", " ".join("%+5.2f" % v for v in y[0, 0]))
print("过 ReLU ", " ".join("%+5.2f" % v for v in r[0, 0]))

实跑输出:

--------------------------------------------------------------------
卷积 ReLU 层:把负的响应截成 0
--------------------------------------------------------------------

  输入 1 通道 8×8 的随机噪声,4 个随机 3×3 核,卷积完再过 ReLU:

          输出点数    负数个数    被截掉的比例
  ------------------------------------------------
  核 0    36          17          47.2%
  核 1    36          20          55.6%
  核 2    36          19          52.8%
  核 3    36          20          55.6%

  随机权重下大约一半的输出是负的,全被截成 0。
  **ReLU 不改形状、不改通道数,只做一件事:负的归零。**

  看一组具体的数(取第一个核的第一行):
    卷积输出 -4.78 +4.18 +0.59 +2.60 +0.76 +1.92
    过 ReLU  +0.00 +4.18 +0.59 +2.60 +0.76 +1.92

  **负数那个位置,梯度也一起变成 0。**
  这就是 4.2 节说的死亡 ReLU,在卷积网络里同样成立——而且更常见,因为卷积核一多,
  总有成片区域被截掉。

  为什么还要用它?因为正向不缩小、反向不衰减。
  **sigmoid 在饱和区导数只剩千分之一,ReLU 在正区间恒为 1,梯度能一路传回前几层。**

四个核的比例是 47.2%、55.6%、52.8%、55.6%。 随机权重配随机输入,这个数就该在 50% 附近,实测正好。 具体那一行最能说明 ReLU 干了什么:卷积输出 −4.78 变成 0.00,其余五个数一个没动。 它只挑负数下手。 负数那个位置,反向时梯度也是 0。这就是死亡 ReLU 的机制,在卷积网络里和在普通全连接里一模一样。 为什么还要用它?因为正区间导数恒为 1,梯度不会越传越小。 sigmoid 在 z=5 时导数只剩 0.0066,一个核传五层就没信号了。 四个核的截断比例差别不大,说明随机初始化下各个核的活跃度是接近的。 训练久了会分化:有的核很活跃,有的几乎全黑——那种通常就是快死了。

30 秒实验

  1. 把核整体乘 −1(权重全部取反),被截掉的比例会变成多少?
  2. 如果输入换成 MNIST 的手写数字(大部分像素是 0),被截掉的比例会更大还是更小?
  3. 为什么把批归一化放在 ReLU 之前能减少死亡 ReLU?

常见误区

  1. 以为 ReLU 丢掉了信息。丢掉的是「这个核不认这个位置」那部分响应, 那恰恰是它想表达的:这里没有我要的图案。
  2. 以为 ReLU 有参数、需要训练。它没有任何参数,它只是一个开关。
  3. 以为死掉的神经元会自己活过来。梯度恒 0 就永远不会更新。 只能靠换初始化、降学习率、或者换成 Leaky ReLU 来预防。
自测三问(点开对答案) 1. ReLU 在卷积网络里改了什么? —— 只改数值,负的归零。形状、通道数、参数量都不变。所以它在参数表里永远是空的。 2. 为什么卷积后面必须跟一个非线性? —— 否则多层卷积等于一层线性变换,深度就失去意义。能表示的函数族不会因为加层而变大。 3. 卷积里为什么更容易出现死亡 ReLU? —— 一个核的所有位置共享同一组权重和偏置。 偏置一旦被推得太负,整张特征图一起归零,这个核就彻底废了。

ReLU 之后是池化。它不学任何东西,却能把特征图的尺寸砍一半。下一节看它到底在做什么。

相关笔记