一、激活函数概述:从ReLU到SwiGLU的发展脉络与核心思想
激活函数,说白了就是神经网络的「灵魂开关」。没有它,再深的网络也只是线性变换的堆叠,毫无表达能力。我从2016年开始做深度学习,那时候大家几乎清一色用ReLU。为什么?简单、快、效果好。但后来随着模型越做越深、越做越大,ReLU的局限性开始暴露。嗯,今天我们就来聊聊这条进化之路。
1.1 为什么需要激活函数?
先问个问题:如果神经网络里全是线性层,会发生什么?
答案很简单——无论堆多少层,最终等价于一个线性变换。你想想看,W2·(W1·x + b1) + b2 不就是 (W2·W1)·x + (W2·b1 + b2) 吗?所以激活函数的核心作用就是引入非线性。
我个人习惯把激活函数比作「决策门」:
- 信号强的时候,开门放行
- 信号弱的时候,关门拦截
- 有些门还会对信号做「整形」
不同的激活函数,就是不同设计理念的「门」。
1.2 ReLU:简单粗暴的里程碑
2010年左右,ReLU(Rectified Linear Unit)横空出世。它的公式简单到令人发指:
ReLU(x) = max(0, x)
正数原样输出,负数直接砍掉。我在项目中第一次用ReLU替换sigmoid时,训练速度提升了将近6倍。为什么?因为sigmoid在两端饱和,梯度几乎为0,而ReLU在正区间梯度恒为1,梯度消失问题大大缓解。
ReLU的核心优势:
- 计算极快:只需一次比较操作
- 稀疏激活:约50%的神经元输出为0,天然正则化
- 缓解梯度消失:正区间梯度恒为1
但ReLU有个臭名昭著的毛病——神经元死亡。我曾经调试一个50层的CNN,发现训练到一半,超过40%的神经元永远输出0。为什么?一旦某个神经元在训练中被推向负区间,梯度为0,它就再也「活」不过来了。
避坑指南:我曾经在训练GAN时用了ReLU,结果生成器死活不收敛。排查了两天,发现是判别器的ReLU神经元大面积死亡,导致梯度传不回去。后来换成Leaky ReLU才解决。
1.3 从ReLU到变体:Leaky ReLU、PReLU、ELU
为了解决神经元死亡,各路学者开始给ReLU「打补丁」:
| 激活函数 | 公式 | 核心改进 |
|---|---|---|
| Leaky ReLU | max(αx, x),α=0.01 | 负区间保留小梯度,避免死亡 |
| PReLU | max(αx, x),α可学习 | 让网络自己学负区间的斜率 |
| ELU | x if x>0, α(e^x-1) if x≤0 | 负区间指数饱和,更接近0均值 |
这些变体各有千秋,但本质上还是在「如何处置负数」上做文章。直到2017年,Google提出了Swish,思路开始转变。
1.4 Swish:自门控的觉醒
Swish的公式是:Swish(x) = x · σ(x),其中σ是sigmoid函数。
你可能会问:这不就是x乘以一个0到1之间的系数吗?没错,但正是这个「自门控」机制,让Swish具备了ReLU没有的特性:
- 非单调性:在x≈-1.5附近有一个「下凹」区域
- 平滑性:处处可导,优化更稳定
- 自门控:输入自己决定自己的「开度」
我记得第一次在ResNet-50上把ReLU换成Swish,Top-1准确率提升了0.6%。虽然不多,但证明了「门控思想」的有效性。
1.5 GLU家族:门控线性单元的进化
GLU(Gated Linear Unit)最早在NLP领域提出,核心思想是用一个线性变换的输出作为「门」,去控制另一个线性变换的输出:
GLU(x) = (x · W1 + b1) ⊗ σ(x · W2 + b2)
这里的⊗是逐元素乘法,σ是sigmoid。说白了就是:用一部分参数学习「门值」,另一部分学习「内容值」,两者相乘得到输出。
GLU的变体很多,比如:
- Bilinear:用线性变换代替sigmoid
- ReGLU:门用ReLU激活
- GEGLU:门用GELU激活
- SwiGLU:门用Swish激活
这里我要重点说说SwiGLU。它的公式是:
SwiGLU(x) = (x · W1 + b1) ⊗ Swish(x · W2 + b2)
为什么SwiGLU效果好?我个人分析有两点:
- Swish作为门控函数,比sigmoid更平滑,梯度更友好
- 双线性变换增加了模型的表达能力,相当于在激活的同时做了特征交互
小技巧:如果你在训练Transformer时发现收敛慢,试试把FFN中的ReLU换成SwiGLU。我在LLaMA架构上做过对比,SwiGLU在相同参数量下,困惑度降低了0.3-0.5个点。
1.6 知识体系总览
下面这张图梳理了从ReLU到SwiGLU的进化脉络,以及各激活函数的核心定位:
1.7 为什么SwiGLU成了大模型标配?
如果你看过LLaMA、PaLM、Falcon这些大模型的论文,会发现它们的FFN层几乎都用了SwiGLU。为什么?
我总结三点:
- 表达能力更强:双线性变换让每个神经元可以「看到」两个不同的输入投影,相当于隐式地做了特征交叉
- 梯度更健康:Swish的梯度在负区间不会完全消失,训练更稳定
- 与注意力机制互补:注意力做的是token之间的交互,SwiGLU做的是特征维度内部的交互,两者各司其职
一句话总结:从ReLU到SwiGLU,本质上是「简单阈值」→「负区间修补」→「自门控」→「双线性门控」的进化。每一步都在增加模型的表达能力,代价是计算量和参数量的增加。但在大模型时代,这点代价完全值得。
好了,这一章我们梳理了激活函数的发展脉络。下一章我会用实际代码对比ReLU和SwiGLU在Transformer中的表现,包括训练曲线、收敛速度、最终指标等。到时候咱们用数据说话。