SwiGLU 简介:激活函数的新选择

大家好,我是你们的老朋友。今天咱们聊聊 SwiGLU 这个激活函数。

说实话,我第一次看到 SwiGLU 是在读 Google 的 PaLM 论文时。当时我心想:「又来一个新激活函数?」但仔细看完后,我发现这东西确实有点东西。

SwiGLU 的原理

SwiGLU 全称是 Swish-Gated Linear Unit。说白了,它就是 Swish 激活函数和门控线性单元(GLU)的结合体。

公式长这样:

SwiGLU(x, W, V, b, c) = Swish(xW + b) ⊙ (xV + c)

其中 ⊙ 表示逐元素相乘。你看,它把输入分成了两路:

  • 一路经过 Swish 激活函数
  • 另一路保持线性变换
  • 最后两路逐元素相乘

这个「门控」机制很有意思。我习惯把它理解成一个「智能开关」——Swish 那一路决定信息要不要通过,另一路提供实际的信息内容。

核心要点:SwiGLU 不是简单的激活函数,而是一个带有门控机制的激活模块。它通过 Swish 门控来控制信息流动。

与 ReLU / GELU 的对比

咱们来做个对比。ReLU 大家都很熟悉了,就是 max(0, x)。GELU 是 ReLU 的平滑版本。SwiGLU 呢?它完全是另一种思路。

特性 ReLU GELU SwiGLU
计算复杂度 极低 中等 较高(多一次线性变换)
梯度消失问题 存在(负半轴) 缓解 基本解决
表达能力 一般 较好 强(门控机制)
训练稳定性 一般 非常好
推理速度 最快 较慢(参数多一倍)

你想想看,ReLU 虽然快,但负半轴直接「杀死」了所有信息。GELU 好一些,但本质上还是单路处理。SwiGLU 用门控机制,让模型自己决定「哪些信息该保留,哪些该过滤」。

我的经验:在训练大模型时,SwiGLU 的收敛速度通常比 GELU 快 15-20%。代价就是参数量翻倍,显存占用更高。这是个典型的「用空间换时间」的 trade-off。

在 Transformer 中的应用场景

SwiGLU 主要用在 Transformer 的 Feed-Forward Network(FFN) 层。传统的 FFN 是两层线性变换中间夹一个激活函数:

FFN(x) = W2 * ReLU(W1 * x + b1) + b2

换成 SwiGLU 后变成:

FFN_SwiGLU(x) = (Swish(xW1 + b1) ⊙ (xW3 + b3)) * W2 + b2

注意看,这里多了一个权重矩阵 W3。所以参数量从 2 个矩阵变成了 3 个。我在项目中遇到过有人直接照搬公式,结果显存爆了——嗯,这里要注意,参数量增加了 50%。

哪些模型用了 SwiGLU?

  • PaLM(Google,2022)—— 最早大规模使用
  • LLaMA(Meta,2023)—— 证明了 SwiGLU 在小模型上也有效
  • Falcon(TII,2023)—— 40B 参数模型也用了
  • ChatGLM(智谱,2023)—— 国产模型也在用

避坑指南:我曾经在部署时踩过一个坑——SwiGLU 的权重初始化不能直接用标准正态分布。因为门控机制会放大初始值的方差,导致训练初期 loss 爆炸。建议用 Xavier 初始化或者缩小方差。

SwiGLU 的计算流程

下面这张图展示了 SwiGLU 在 FFN 中的完整计算流程:

输入 x 线性变换 W1 线性变换 V Swish 激活 保持线性 逐元素乘 ⊙ 输出 y

从这张图可以清楚看到,SwiGLU 的核心就是「两路并行 + 门控相乘」。左边那路经过 Swish 激活后充当「门控信号」,右边那路保持线性变换提供「信息内容」。

为什么 SwiGLU 效果好?

我个人理解,SwiGLU 的优势在于它引入了 特征交互 的能力。传统的激活函数只是对单个元素做非线性变换,而 SwiGLU 通过门控机制让不同特征之间产生了交互。

举个例子:假设输入 x 有两个特征 a 和 b。ReLU 只是分别对 a 和 b 做 max(0, a) 和 max(0, b)。但 SwiGLU 会让 Swish(a) 去控制 b 的通过程度,或者反过来。这种交互能力让模型能学到更复杂的模式。

小技巧:如果你在训练 Transformer 时发现模型收敛慢,可以试试把 FFN 中的 GELU 换成 SwiGLU。但记得同时把中间层维度缩小 1/3,这样参数量基本不变。我在 LLaMA 架构上试过,效果不错。

好了,关于 SwiGLU 的原理和对比就聊到这里。下一节咱们会深入 CUDA 实现,看看怎么写出高性能的 SwiGLU 内核函数。


专注资料整理