为什么加入 ReLU 后,神经网络可以学习线性可分的特征?
在学习两层神经网络时,我们会看到这样的形式:
python
f = W2 max(0, W1x)
这里的:
python
max(0, W1x)
就是 ReLU 激活函数。
我们已经知道,ReLU 的作用是引入非线性。
但一个更深的问题是:
ReLU 明明只是把负数变成 0,为什么它能让神经网络把原本线性不可分的数据,转换成更容易线性可分的表示?
这篇文章就围绕这个问题展开。
1. 线性分类器为什么不够?
线性分类器的形式是:
python
f = Wx
它直接在原始输入 x 上做分类。
如果是二维数据,线性分类器学到的分类边界大概是:
python
w1 * x1 + w2 * x2 + b = 0
这在二维平面中就是一条直线。
所以,线性分类器只能做一件事:
用一条直线、一个平面,或者高维空间中的超平面去切分数据。
如果数据本身可以被直线分开,线性分类器当然可以工作。
但如果数据是这样的:
text
红点在中间
蓝点围在外圈
那么无论怎么画一条直线,都无法把红点和蓝点完全分开。
这就是线性分类器的限制:
它只能在原始输入空间中学习线性决策边界。
2. 神经网络的关键:先变换特征,再线性分类
两层神经网络可以写成:
python
h = ReLU(W1x)
scores = W2h
也就是:
text
输入 x
↓
第一层 W1x
↓
ReLU 非线性变换
↓
得到隐藏层特征 h
↓
第二层 W2
↓
输出分类分数
这里最关键的是:
text
h = ReLU(W1x)
它不是直接在原始输入 x 上分类,而是先把 x 变成新的表示 h。
然后第二层:
text
scores = W2h
是在新的特征空间 h 中做线性分类。
所以两层神经网络的思想是:
原始空间中不好分的数据,先映射到一个新的特征空间;在新的特征空间中,它可能变得更容易被线性分类器分开。
3. ReLU 到底做了什么?
ReLU 的定义很简单:
python
ReLU(z) = max(0, z)
也就是说:
text
如果 z > 0,输出 z
如果 z <= 0,输出 0
例如:
python
z = [-3, 2, -1, 5]
经过 ReLU 之后:
python
ReLU(z) = [0, 2, 0, 5]
表面上看,它只是把负数变成了 0。
但放到神经网络里,它的作用会变得非常重要。
假设第一层中有一个隐藏神经元:
text
h1 = max(0, w1 · x + b1)
这个神经元可以理解成一个"检测器":
text
如果 w1 · x + b1 > 0,说明输入 x 符合这个神经元关心的模式,于是神经元被激活
如果 w1 · x + b1 <= 0,说明输入 x 不符合这个模式,于是神经元输出 0
所以,一个 ReLU 神经元可以看成是在问:
这个输入是否落在我关心的区域里?
4. 多个 ReLU 神经元会切分输入空间
一个 ReLU 神经元会根据:
text
w · x + b = 0
把空间分成两半:
text
一边激活
另一边关闭
如果有很多个 ReLU 神经元,它们就会从不同方向切分输入空间。
例如:
text
神经元 1:检测输入是否在某个方向上
神经元 2:检测输入是否在另一个方向上
神经元 3:检测输入是否在某个区域内
...
这些神经元一起工作后,输入空间会被划分成很多小区域。
在不同区域里,被激活的神经元组合不同:
text
区域 A:神经元 1、2、5 激活
区域 B:神经元 2、4 激活
区域 C:神经元 3、5、6 激活
这意味着,神经网络不再对所有输入使用同一种线性规则。
它变成了:
对不同区域的输入,使用不同的线性表示方式。
这就是 ReLU 带来的 分段线性变换。
5. 为什么这种变换可能让数据线性可分?
原始空间中的线性分类器只有一种能力:
text
直接画一条直线去分数据
但加入 ReLU 后,神经网络先做了一步特征变换:
text
x → h = ReLU(W1x + b1)
这个新特征 h 包含了很多隐藏神经元的响应。
每个隐藏神经元都在描述输入的某种性质:
text
这个输入是否在某个方向上?
这个输入是否激活了某个局部模式?
这个输入是否属于某个区域?
于是,原来的输入 x 被转换成了一组新的特征:
text
h = [h1, h2, h3, ..., hH]
第二层线性分类器不是直接看原始输入,而是看这些新特征。
如果这些新特征设计得好,原本复杂的分类问题就可能变简单。
可以这样理解:
text
原始空间中:
红点和蓝点混在一起,一条直线分不开
隐藏层空间中:
红点和蓝点被映射到更容易区分的位置,一条直线可能就够了
6. 一个简单的一维例子
假设输入只有一个数字 x,我们构造两个 ReLU 特征:
text
h1 = max(0, x)
h2 = max(0, -x)
原本一个数 x 被变成了两个特征:
text
h = [max(0, x), max(0, -x)]
来看几个例子:
text
x = 3 → h = [3, 0]
x = 1 → h = [1, 0]
x = -1 → h = [0, 1]
x = -3 → h = [0, 3]
可以看到:
text
正数主要落在第一个维度上
负数主要落在第二个维度上
也就是说,ReLU 把原本一维空间里的点,映射到了一个新的二维特征空间。
这就是特征变换的思想:
不是直接在原始输入上分类,而是先造出更有区分度的新特征。
7. 和圆环数据的关系
在 CS231n 的课件中,有一个经典例子:
text
红点集中在中间
蓝点围在外圈
在原始 (x, y) 空间中,这两类点不能用一条直线分开。
如果我们手动做一个特征变换:
text
(x, y) → (r, θ)
其中:
text
r 表示点到原点的距离
θ 表示角度
那么分类就变简单了:
text
红点靠近中心,r 小
蓝点在外圈,r 大
在新空间里,只要根据 r 的大小,就可以把红点和蓝点分开。
神经网络的隐藏层做的事情和这个思想类似。
只不过它不是手动写死:
text
r = sqrt(x² + y²)
而是通过很多个 ReLU 神经元学习新的特征:
text
h = ReLU(W1x + b1)
这些特征组合起来,可以近似表达"距离中心远不远""是否在某个区域""是否符合某种模式"等信息。
然后第二层再在这些特征上做线性分类。
8. 为什么没有 ReLU 就不行?
如果没有 ReLU,两层网络会变成:
text
f = W2W1x
但是矩阵乘矩阵的结果还是矩阵。
令:
text
W3 = W2W1
那么:
text
f = W3x
这其实还是一个线性分类器。
所以,如果没有非线性激活函数,不管堆多少层,最终都可以合并成一层线性变换。
这样模型并不会获得真正更强的表达能力。
ReLU 的作用,就是打断这种线性合并:
python
f = W2 ReLU(W1x)
因为中间多了一个非线性函数,W2 和 W1 不能再简单合并成一个矩阵。
于是模型可以学习更复杂的分段线性函数。
9. 一个重要的澄清
需要注意的是:
加入 ReLU 不代表数据一定会变得线性可分。
ReLU 的作用不是保证线性可分,而是提供一种能力:
text
学习非线性特征变换的能力
如果隐藏层足够大、参数训练得合适,网络就可能学到一个好的映射:
text
x → h
让原本在输入空间中混在一起的数据,在隐藏层空间中变得更容易分开。
所以更准确地说:
text
ReLU 让神经网络有能力把输入映射到一个新的、分段线性的特征空间;
在这个空间里,原本线性不可分的数据可能变得线性可分。
10. 总结
线性分类器只能直接在原始输入空间里画线性边界:
text
f = Wx
两层 ReLU 神经网络则是:
text
h = ReLU(W1x)
f = W2h
它先用第一层和 ReLU 把输入转换成新的隐藏层特征,再用第二层在线性空间中分类。
ReLU 的关键作用是:
text
1. 把负响应变成 0,让神经元像开关一样选择性激活
2. 将输入空间切分成多个区域
3. 对不同区域使用不同的线性表示
4. 形成分段线性变换
5. 让模型有能力学习更复杂的分类边界
一句话总结:
ReLU 并不是直接让数据自动线性可分,而是让神经网络可以学习一种新的特征表示;在这个隐藏层表示中,原本线性不可分的数据可能变得可以被线性分类器分开。