卷积的输出有正有负,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(权重全部取反),被截掉的比例会变成多少?
- 如果输入换成 MNIST 的手写数字(大部分像素是 0),被截掉的比例会更大还是更小?
- 为什么把批归一化放在 ReLU 之前能减少死亡 ReLU?
常见误区
- 以为 ReLU 丢掉了信息。丢掉的是「这个核不认这个位置」那部分响应, 那恰恰是它想表达的:这里没有我要的图案。
- 以为 ReLU 有参数、需要训练。它没有任何参数,它只是一个开关。
- 以为死掉的神经元会自己活过来。梯度恒 0 就永远不会更新。 只能靠换初始化、降学习率、或者换成 Leaky ReLU 来预防。
自测三问(点开对答案)
1. ReLU 在卷积网络里改了什么? —— 只改数值,负的归零。形状、通道数、参数量都不变。所以它在参数表里永远是空的。 2. 为什么卷积后面必须跟一个非线性? —— 否则多层卷积等于一层线性变换,深度就失去意义。能表示的函数族不会因为加层而变大。 3. 卷积里为什么更容易出现死亡 ReLU? —— 一个核的所有位置共享同一组权重和偏置。 偏置一旦被推得太负,整张特征图一起归零,这个核就彻底废了。ReLU 之后是池化。它不学任何东西,却能把特征图的尺寸砍一半。下一节看它到底在做什么。
- ☐ (本节完,下一节 5.8 池化层)