Feed Forward 直译为“前馈”,核心含义是信息按照固定方向从输入流向输出,不存在循环反馈。在 Transformer 中,Feed Forward Network(FFN)是每个 Block 内部的重要子模块:Attention 负责不同 token 之间的信息交互,FFN 则独立地对每个 token 的特征进行非线性加工。
要理解 FFN,首先要从激活函数以及它所引入的非线性讲起。
激活函数
激活函数是一类数学函数,用来给神经网络引入非线性。神经网络中的一个线性层通常写成:
$$ y=Wx+b, $$其中 $x$ 是输入向量,$W$ 是权重矩阵,$b$ 是偏置,$y$ 是输出向量。
如果连续堆叠两个线性层:
$$ \begin{aligned} h&=W_1x+b_1,\\ y&=W_2h+b_2, \end{aligned} $$代入可得:
$$ y=W_2(W_1x+b_1)+b_2 =(W_2W_1)x+(W_2b_1+b_2). $$令:
$$ W'=W_2W_1,\qquad b'=W_2b_1+b_2, $$那么:
$$ y=W'x+b'. $$也就是说,两层线性层本质上仍然等价于一层线性层。即使堆叠几十层,只要中间没有非线性操作,整个网络最终仍然只是一个线性变换,表达能力非常有限。
因此需要在两个线性层之间加入激活函数:
$$ h=\sigma(W_1x+b_1), $$这里的 $\sigma$ 就是激活函数。因为激活函数通常是非线性的,所以整个计算不再能合并成一次简单的矩阵乘法。
为什么需要非线性
假设输入只有一个数字 $x$,纯线性模型只能表示:
$$ y=ax+b. $$它只能画出一条直线,但现实中的关系通常不是线性的。例如:
- 图片中某些边缘组合起来才表示眼睛;
- 眼睛、鼻子和嘴巴组合起来才表示人脸;
- 某些 token 的组合才能表达否定、因果、讽刺等语义;
- 某个特征超过阈值后才应该激活。
激活函数使网络能够表示弯曲、分段、组合和条件性的复杂关系。可以把它理解为:线性层负责重新组合特征,激活函数负责决定哪些特征需要保留、增强或抑制。
ReLU
ReLU 的全称是 Rectified Linear Unit,中文通常叫“修正线性单元”。其定义为:
$$ \operatorname{ReLU}(x)=\max(0,x)=\begin{cases} x,&x>0,\\ 0,&x\le 0. \end{cases} $$因此 ReLU 所做的事情很简单:负数截断为 0,正数保持不变。
| 输入 $x$ | ReLU 输出 |
|---|---|
| $-3$ | $0$ |
| $-0.5$ | $0$ |
| $0$ | $0$ |
| $2$ | $2$ |
| $5$ | $5$ |
ReLU 为什么能引入非线性
虽然 ReLU 在正数区域和负数区域分别都是线性的,但它整体不是一个线性函数。线性函数需要满足:
$$ f(x_1+x_2)=f(x_1)+f(x_2). $$取 $x_1=1,\ x_2=-2$,那么:
$$ \operatorname{ReLU}(x_1+x_2) =\operatorname{ReLU}(-1)=0, $$但:
$$ \operatorname{ReLU}(x_1)+\operatorname{ReLU}(x_2) =1+0=1. $$两者不相等,所以 ReLU 不是线性函数。神经网络通过大量线性层和 ReLU 的组合,可以构造非常复杂的分段线性函数。
ReLU 的优点
- 计算简单。 ReLU 只需要计算 $\max(0,x)$。相比 Sigmoid、Tanh 中的指数运算,计算成本较低。
- 正半轴梯度稳定。 当 $x>0$ 时:
梯度不会因为激活函数本身不断缩小,这比 Sigmoid 在饱和区域中的梯度衰减问题要轻。
- 激活具有稀疏性。 负数会全部变成 0:
这种稀疏激活有时有利于特征选择和训练。
ReLU 的问题:死亡 ReLU
由于负数区域的导数为 0,如果一个神经元长期满足:
$$ Wx+b<0, $$那么它的输出一直是 0,梯度也一直是 0,权重可能再也无法更新回来。这种情况称为 Dying ReLU,即“死亡 ReLU”。
为缓解这个问题,可以使用 Leaky ReLU:
$$ \operatorname{LeakyReLU}(x)=\begin{cases} x,&x>0,\\ \alpha x,&x\le 0, \end{cases} $$其中 $\alpha$ 是一个很小的正数,例如 $0.01$。这样负数区域仍然保留一个很小的梯度:
$$ \operatorname{LeakyReLU}'(x)=\alpha,\qquad x<0. $$Feed Forward 的含义
“Feed Forward”直译是“前馈”。它表示信息按照固定方向从输入流向输出,不存在循环反馈。例如:
$$ x\longrightarrow\operatorname{Linear} \longrightarrow\operatorname{Activation} \longrightarrow\operatorname{Linear} \longrightarrow y. $$这是一个前馈计算过程。
广义的前馈神经网络
最普通的多层感知机 MLP,就是一种前馈神经网络:
$$ x\rightarrow\operatorname{Linear}_1 \rightarrow\operatorname{ReLU} \rightarrow\operatorname{Linear}_2 \rightarrow\operatorname{ReLU} \rightarrow\operatorname{Linear}_3 \rightarrow y. $$它和循环神经网络 RNN 的区别在于:
- 前馈网络中,信息只向前传播;
- RNN 中,前一时刻的隐藏状态会反馈给下一时刻。
不过,训练前馈网络时仍然会进行反向传播。“前馈”描述的是模型的计算图结构,并不表示训练时没有反向传播。
Transformer 中的 Feed Forward Network
在 Transformer 中,FFN 通常是每个 Transformer Block 内部的一个子模块。经典形式为:
$$ \operatorname{FFN}(x) =W_2\operatorname{ReLU}(W_1x+b_1)+b_2. $$也可以写成:
$$ x\xrightarrow{W_1}h \xrightarrow{\operatorname{ReLU}}a \xrightarrow{W_2}y. $$其中通常先升维,再降维:
$$ d_{\text{model}}\rightarrow d_{\text{ff}}\rightarrow d_{\text{model}}. $$例如:
$$ 4096\rightarrow16384\rightarrow4096. $$若输入 token 向量为 $x\in\mathbb{R}^{4096}$,经过第一个线性层:
$$ h=W_1x+b_1,\qquad h\in\mathbb{R}^{16384}, $$再经过激活函数:
$$ a=\operatorname{ReLU}(h), $$最后通过第二个线性层恢复原始隐藏维度:
$$ y=W_2a+b_2,\qquad y\in\mathbb{R}^{4096}. $$因此,FFN 不是一个激活函数,而是一个包含线性投影和激活函数的完整模块。

FFN 为什么要先升维再降维
假设输入向量是 4 维:
$$ x=[x_1,x_2,x_3,x_4]. $$第一个线性层把它投影到更大的特征空间:
$$ 4\rightarrow16. $$这相当于生成更多中间特征:
$$ h=[h_1,h_2,\ldots,h_{16}], $$其中每个 $h_i$ 都是输入各维度的不同组合。激活函数再对这些中间特征进行非线性筛选:
$$ a_i=\operatorname{ReLU}(h_i). $$第二个线性层把这些中间特征重新组合,并降回原始隐藏维度:
$$ 16\rightarrow4. $$可以粗略理解为:
- 第一个线性层展开出大量候选特征;
- 激活函数筛选或门控这些特征;
- 第二个线性层把特征组合回原始隐藏维度。
升维提供了更大的中间表示空间,使 FFN 能学习更复杂的变换。
Attention 和 FFN 的分工
Transformer Block 可以简化为:
$$ x\longrightarrow\operatorname{Attention} \longrightarrow\operatorname{FFN}. $$二者作用不同:
- Attention 主要负责不同 token 之间的信息交互;
- FFN 主要负责对每个 token 自身的特征进行非线性加工。
同一个 FFN 会独立应用到每个 token:
$$ y_i=\operatorname{FFN}(x_i). $$不同 token 之间不会在 FFN 内直接交互。换句话说,Attention 在 token 维度上混合信息,而 FFN 在特征维度上变换信息。
一个具体的 FFN 计算示例
假设输入和第一层权重为:
$$ x= \begin{bmatrix} 1\\ 2 \end{bmatrix}, \qquad W_1= \begin{bmatrix} 1&1\\ -1&1\\ 2&-1 \end{bmatrix}. $$暂时忽略偏置,第一个线性层得到:
$$ h=W_1x=\begin{bmatrix} 1\times1+1\times2\\ -1\times1+1\times2\\ 2\times1-1\times2 \end{bmatrix}=\begin{bmatrix} 3\\ 1\\ 0 \end{bmatrix}. $$经过 ReLU 后 $a=[3,1,0]^{\mathsf T}$。假设第二个线性层为:
$$ W_2= \begin{bmatrix} 1&2&1\\ -1&1&2 \end{bmatrix}, $$那么:
$$ y=W_2a=\begin{bmatrix} 1\times3+2\times1+1\times0\\ -1\times3+1\times1+2\times0 \end{bmatrix}=\begin{bmatrix} 5\\ -2 \end{bmatrix}. $$整个过程完成了:
$$ \mathbb{R}^{2}\rightarrow\mathbb{R}^{3} \xrightarrow{\operatorname{ReLU}}\mathbb{R}^{3} \rightarrow\mathbb{R}^{2}. $$现代大模型中的激活与门控
经典 Transformer 论文中的 FFN 使用 ReLU,但现代大语言模型更常使用 GELU、SiLU/Swish、GLU、SwiGLU 或 GeGLU。其中,SwiGLU 是现代 Transformer 中常见的一种门控前馈网络结构。
SwiGLU 不是单纯的激活函数,而是:
Swish/SiLU 激活函数 + GLU 门控机制。
它通常用来替代经典的:
$$ \operatorname{Linear}\rightarrow\operatorname{ReLU}\rightarrow\operatorname{Linear}. $$SiLU
SwiGLU 中的 “Swi” 来自 Swish。实践中通常使用的 Swish 形式就是 SiLU:
$$ \operatorname{SiLU}(x)=x\cdot\sigma(x), \qquad \sigma(x)=\frac{1}{1+e^{-x}}. $$所以:
$$ \operatorname{SiLU}(x)=\frac{x}{1+e^{-x}}. $$和 ReLU 相比,ReLU 会直接将负数截断为 0,而 SiLU 会保留一个较小的负值。因此:
- ReLU 在 $x=0$ 处有折点;
- SiLU 处处平滑、可导;
- SiLU 的负半轴仍然可以传播梯度;
- SiLU 不容易出现严重的“死亡神经元”。
可以粗略理解为:
$$ \operatorname{SiLU}(x)=x\times\text{软门控系数}, $$因为 $\sigma(x)\in(0,1)$,Sigmoid 决定输入 $x$ 被保留多少。
GLU
GLU 的全称是 Gated Linear Unit,即门控线性单元。普通 FFN 只有一条升维分支:
$$ h=xW_{\text{up}}. $$GLU 会把输入投影成两条分支:
$$ a=xW_{\text{gate}},\qquad b=xW_{\text{up}}, $$然后一条分支充当“门”,另一条分支充当“内容”:
$$ h=\sigma(a)\odot b, $$其中 $\sigma(a)$ 决定内容分支的每个维度保留多少,$\odot$ 表示对应元素相乘。
例如:
$$ \sigma(a)=[0.1,0.9,0.3],\qquad b=[10,5,-2], $$那么:
$$ h=[0.1,0.9,0.3]\odot[10,5,-2]=[1,4.5,-0.6]. $$第一个维度被大幅抑制,第二个维度基本被保留,第三个维度被部分保留。门控结构让网络不仅能决定“激活值是多少”,还可以根据输入动态决定“这条特征通道应该打开多少”。
SwiGLU 的计算
SwiGLU 把 SiLU 激活与 GLU 门控结合起来。其核心计算为:
$$ h=\operatorname{SiLU}(xW_{\text{gate}}) \odot(xW_{\text{up}}), $$然后通过降维矩阵:
$$ y=hW_{\text{down}}. $$合起来就是:
$$ y= \left[ \operatorname{SiLU}(xW_{\text{gate}}) \odot(xW_{\text{up}}) \right]W_{\text{down}}. $$其中 $W_{\text{gate}}$ 生成门控分支,$W_{\text{up}}$ 生成内容分支,$W_{\text{down}}$ 将结果降回隐藏维度。虽然实现比 ReLU FFN 更复杂,但本质仍然是:线性投影 $\rightarrow$ 非线性激活或门控 $\rightarrow$ 线性投影。
SwiGLU 的优势
- 更强的动态特征选择。 门控分支会根据当前输入动态调制内容分支,不同 token 会生成不同的门控值;
- 激活函数平滑。 SiLU 没有 ReLU 在 0 处的尖锐折点,梯度变化更加平滑;
- 负半轴保留梯度。 SiLU 在大部分负半轴仍有非零梯度,因此不容易完全失活;
- 引入乘法交互。 两条输入相关分支之间进行逐元素乘法:
这种结构比单分支激活拥有更丰富的函数表达能力。在参数量和计算量相近的条件下,门控 FFN 往往比经典 ReLU/GELU FFN 表现更好,因此现代大语言模型广泛采用类似结构。
SwiGLU 的代价
普通 FFN 有两个矩阵:
$$ W_1,\quad W_2. $$SwiGLU 有三个矩阵:
$$ W_{\text{gate}},\quad W_{\text{up}},\quad W_{\text{down}}. $$因此如果中间维度不缩小,计算量和参数量会显著增加。SwiGLU 还需要同时产生:
$$ G=XW_{\text{gate}}, \qquad U=XW_{\text{up}}, $$这会增加中间激活显存和内存带宽压力。推理框架通常会尝试融合 gate projection、up projection、SiLU 和 elementwise multiply,否则可能产生更多 kernel launch 和中间张量读写。
总结
Feed Forward 的核心不是简单地“向前计算”,而是通过线性投影和非线性激活,对特征进行逐 token 加工:
- 没有激活函数时,多层线性层仍可合并为一层,表达能力有限;
- ReLU 计算简单、正半轴梯度稳定,但存在死亡 ReLU 问题;
- Transformer FFN 通常先升维、执行非线性变换,再降回隐藏维度;
- Attention 负责 token 间的信息混合,FFN 负责每个 token 内部的特征变换;
- SwiGLU 通过 SiLU 和门控乘法提供更强的动态特征选择,但会增加投影、显存和实现成本。