激活函数:非线性的魔力
为什么网络能拟合任意复杂的形状?答案藏在一个看似多余的小函数里。这一章我们亲手拆掉第 1 章结尾留下的 XOR 困局,再把常用的激活函数挨个玩一遍。
2.1 线性叠线性,还是线性
第 1 章的神经元是「加权求和 + 阶跃」。一个很自然的想法是:把神经元串起来、叠上很多层,会不会就更聪明?先看一个扫兴但极其重要的数学事实。
假设每一层只做加权求和(也就是一个线性变换),层与层之间什么都不加。那么一个两层网络的输出是:
y = W2(W1x) = (W2W1)x = Wx两个矩阵的乘积,还是一个矩阵。换句话说:两层线性变换,等价于一层线性变换。举个数例:第一层把输入乘以 2,第二层乘以 3,叠起来等于乘以 6——一层的活儿,两层并没有干出任何新花样。
没有激活函数,一百层网络和一层网络的表达力完全一样——深度全白叠了。想让「深」有意义,必须在层与层之间塞进非线性。
2.2 XOR 困局
第 1 章结尾留了个悬念:异或(XOR)问题。规则很简单——两个输入不一样就输出 1,一样就输出 0。把四个样本点画在平面上:同类的两个点落在对角线上,交错分布。
坏消息是:任何一条直线都没法把蓝点和橙点分开。1969 年 Minsky 和 Papert 在《Perceptrons》一书中严格证明了这一点,直接让神经网络研究沉寂了十几年。
下面的演示分两步:先用「单神经元模式」亲手感受绝望,再切到「隐藏层模式」,看一个隐藏层 + 非线性激活如何瞬间破局。
演示 1 · XOR 破局
两种模式一条直线怎么放都至少分错 1 个,继续试试。
空间被「折叠」了。h1 = ReLU(x1+x2−1) 和 h2 = ReLU(1−x1−x2) 这两个隐藏神经元,相当于沿着 x1+x2=1 这条线把平面折了一下:直线两侧的多余部分被拍扁到坐标轴上,两个橙点被折到同一个角落。折叠之后,原来对角交错的四个点变得线性可分。结论:非线性 + 多一层 = 折叠空间。深度网络就是在高维空间里反复折叠,直到数据变得好分为止。
2.3 激活函数动物园
阶跃函数只是开胃菜。几十年来大家发明了几十种激活函数,但真正常用的就下面这六位。用实验室把它们挨个玩一遍,重点看两件事:曲线的形状,以及橙色的导数曲线在哪里贴近地面。
演示 2 · 激活函数实验室
可拖游标在画布上左右拖动竖直游标。把游标拖向 sigmoid / tanh 的两端:橙色导数曲线会贴到地面——梯度在这里消失了。
挨个点评一下:
- 阶跃:历史意义大于实用。导数处处为 0,没法配合梯度下降,现代网络只把它当教具。
- sigmoid:把任何实数平滑压进 (0, 1),可以读作「概率」。缺点:两端饱和,导数趋近 0。
- tanh:压进 (−1, 1),以 0 为中心,比 sigmoid 讨喜;但两端同样饱和。
- ReLU:max(0, x)。简单、快、正数区导数恒为 1。2012 年 AlexNet 靠它一战成名,至今仍是隐藏层的默认选项。
- Leaky ReLU:负数区留一条 0.1 的小缝,避免神经元彻底「死亡」。
- GELU:ReLU 的平滑版,Transformer 家族的标配(BERT、GPT 都在用它)。
2.4 梯度消失的直觉
第 5 章会严格推导反向传播,这里先建立直觉:网络训练时,靠近输入的层能收到多少更新信号,取决于后面各层的导数一路乘回来的结果:
第一层的梯度 ≈ f′(z4) × f′(z3) × f′(z2) × f′(z1) × …问题出在 sigmoid 和 tanh 身上:sigmoid 的导数最大只有 0.25,tanh 最大为 1 但大部分区域远小于 1。四个 0.25 乘起来是 0.004,十层就是百万分之一量级——前面几层的权重几乎收不到任何更新信号,只能躺平。
用 sigmoid / tanh 堆深层网络,靠近输入的层会「学不动」——不是不想学,是信号在路上被乘没了。这是 2010 年之前深层网络怎么也训练不好的主因之一。ReLU 在正数区导数恒等于 1,乘多少次都不衰减,这正是它能撑起深层网络的核心原因。(反过来,信号也可能越乘越大而「爆炸」,第 6 章再聊。)
2.5 实践建议
- 隐藏层:默认 ReLU 家族。图省事用 ReLU;担心神经元死亡用 Leaky ReLU;搭 Transformer 用 GELU。
- 输出层按任务选。二分类要输出概率 → sigmoid;多分类 → softmax(第 4 章细讲);回归问题要预测连续数值 → 不加激活,直接输出 z。
- 不要在隐藏层盲目用 sigmoid。它两端饱和、输出不以 0 为中心、还会引发梯度消失。除非你明确知道为什么需要它,否则别用。
这些不是教条,而是无数前人踩坑后的默认值。先按默认值起步,遇到具体问题再回头调整。
没有激活函数,深层网络等价于单层,深度失去意义。XOR 问题证明了一条直线的表达力不够,而「非线性 + 隐藏层」可以折叠空间、轻松破局。常用激活函数里,隐藏层默认选 ReLU 家族,输出层按任务选;sigmoid / tanh 两端饱和、导数趋近 0,深层连乘会导致梯度消失。