想象你走进一家生意火爆的火锅店。十个人围着一张大圆桌,桌上有个自动旋转的转盘,每道菜转到谁面前,谁都可以夹一筷子——这就是自注意力机制:让序列里每个位置都能“看到”其他位置的信息。但转盘只是把食材送到你面前,真正决定这道菜好不好吃的,是后厨里那位专门负责调味的厨师。同一块牛肉,在他手里可以变成麻辣、番茄、菌汤三种风味。 这位厨师的秘密武器,就是我们要讲的前馈网络(Feed-Forward Network,FFN)。它藏在Transformer每一层的后半段,把转盘送来的“半成品”进行深度加工:先在一个比原来大四倍的案板上把味道完全摊开、理解透彻,再果断扔掉发馊的配料,最后压缩回标准摆盘端出。模型里绝大多数“智慧”参数,都存在于FFN的案板和调料罐中。

岗位关联

理解FFN是理解大模型内部构造的关键——它占据了Transformer每层约三分之二的参数,是模型表达能力的核心来源。掌握它的结构、作用与工程特性,你就能看懂大模型为什么“聪明”,也能在实际部署时找准性能优化的靶点。

目录
  1. 可视化演示
  2. 结构组成
  3. 激活函数
  4. 隐藏层维度
  5. 作用机制
  6. 注意力关系
  7. 编码解码应用
  8. 工程实践
  9. AI 应用场景
  10. Python 演示
  11. 常见误区
  12. 面试题

可视化演示

本节配有交互动效(进入视口后自动加载,约 3KB)。

FFN两层线性变换结构:FFN(x) = max(0, xW\u2081+b\u2081)W\u2082+b\u2082 W\u2081\u6FC0\u6D3BW\u2082W\u2082(W\u2081x) = (W\u2082W\u2081)x = WxW\u2081

结构组成

主厨的灶台总共有三块区域:备料区、调味区、装盘区。FFN的结构与之严格对应——输入向量先经过第一层线性变换,中间夹一个激活函数,最后经过第二层线性变换输出。第一层线性变换的任务是把一道菜的原料铺开到四倍大的案板上(升维),让每一种风味细节都暴露出来;激活函数负责尝味和筛选;第二层线性变换则把所有调料整合,重新压缩回标准餐盘的大小(降维)。

形式上,设输入向量为 $x$,FFN 的完整计算可以写成:

值得注意的是,FFN 在计算时完全不看其他位置——它像一位只管自己这一道菜的主厨,对每个 token 独立调味。转盘上其他人的菜(其他token的状态)怎么变化,与它的烹饪步骤无关,这正是它与自注意力最本质的分工差异。

FFN(x)=W2×σ(W1×x+b1)+b2\displaystyle \text{FFN}(x) = W_2 \times \sigma(W_1 \times x + b_1) + b_2
这个公式是在说:先乘大矩阵升维,再用激活函数筛选,最后乘另一个矩阵降维。$W_1$、$W_2$ 是权重矩阵,$b_1$、$b_2$ 是偏置,$\sigma$ 是激活函数。
  1. 第一层线性变换输入向量 $x$ 乘以权重矩阵 $W_1$ 并加上偏置 $b_1$,把维度从 $d_{\text{model}}$ 扩张到 $d_{\text{ff}}$,完成升维动作。
    z=W1×x+b1z = W_1 \times x + b_1
  2. 非线性激活对升维后的向量 $z$ 逐元素施加激活函数 $\sigma$,引入非线性筛选。
    a=σ(z)a = \sigma(z)
  3. 第二层线性变换激活后的向量 $a$ 乘以权重矩阵 $W_2$ 并加上偏置 $b_2$,把维度从 $d_{\text{ff}}$ 压缩回 $d_{\text{model}}$,完成降维并输出。
    y=W2×a+b2y = W_2 \times a + b_2

激活函数

主厨在调味区有一个关键动作:把调料放进嘴里尝一口,馊掉的、发苦的直接吐掉,只保留鲜美的味道。这个“尝味筛选”动作,在数学上就是激活函数。早期的Transformer常用 ReLU,它简单粗暴:负的一律归零。

但 ReLU 有个小毛病:它处理负值时太“绝情”,一刀切全扔掉,导致梯度在某些区域完全消失。于是研究者设计出更平滑的 GELU(高斯误差线性单元),它像一个更懂食材的品鉴师——按概率保留,负值不完全扔掉,只是给很低的权重。GELU 的定义为:

ReLU(x)=max⁡(0,x)\displaystyle \text{ReLU}(x) = \max(0, x)
GELU(x)=x×Φ(x)≈0.5x(1+tanh⁡(2π(x+0.044715x3)))\displaystyle \text{GELU}(x) = x \times \Phi(x) \approx 0.5x\left(1 + \tanh\left(\sqrt{\frac{2}{\pi}}\left(x + 0.044715x^{3}\right)\right)\right)
$\Phi(x)$ 是标准正态分布的累积分布函数。若 $x$ 为正,$\Phi(x)$ 接近 1,信号基本保留;若 $x$ 为负,$\Phi(x)$ 接近 0,信号被大幅削弱——这就像按“新鲜程度打分”来决定留多少。
  1. 标准正态累积分布$\Phi(x)$ 衡量 $x$ 在标准正态分布下所处的百分位,值域在 0 到 1 之间。
    Φ(x)=P(X≤x),X∼N(0,1)\Phi(x) = P(X \leq x), \quad X \sim \mathcal{N}(0,1)
  2. 加权保留输入用这个 0 到 1 的分数乘以原始输入 $x$,实现对 $x$ 的软性保留。
    GELU(x)=x×Φ(x)\text{GELU}(x) = x \times \Phi(x)
  3. 工程近似$\Phi(x)$ 计算较慢,使用 tanh 形式近似,$\sqrt{2/\pi}$ 和 $0.044715$ 是为逼近误差最小化而选取的常数。
    GELU(x)≈0.5x(1+tanh⁡(2π(x+0.044715x3)))\text{GELU}(x) \approx 0.5x\left(1 + \tanh\left(\sqrt{\frac{2}{\pi}}\left(x + 0.044715x^{3}\right)\right)\right)

隐藏层维度

为什么主厨要把菜在四倍大的案板上铺开?因为只有空间足够大,调料才能撒得均匀、肉纹才能看得清楚。Transformer 的设计者通过大量实验找到了这个“案板倍数”:隐藏层维度 $d_{\text{ff}}$ 通常取模型维度 $d_{\text{model}}$ 的四倍。BERT-base 中 $d_{\text{model}}=768$,则 $d_{\text{ff}}=3072$;GPT-2 也是如此。

这个选择直接决定了参数量。我们把 FFN 的参数量拆开数一数:

案板越大,厨艺发挥空间越大,但厨房租金也越贵。四倍不是拍脑袋定的,而是在模型表达能力与计算显存开销之间找到的黄金平衡点。

PFFN=2×dmodel×dff+dmodel+dff\displaystyle P_{\text{FFN}} = 2 \times d_{\text{model}} \times d_{\text{ff}} + d_{\text{model}} + d_{\text{ff}}
两个括号内的“两层线性变换”各贡献一个 $d_{\text{model}} \times d_{\text{ff}}$ 大小的权重矩阵,两个偏置项加起来是 $d_{\text{model}} + d_{\text{ff}}$。代入 $d_{\text{ff}} = 4 \times d_{\text{model}}$,参数量约为 $8 \times d_{\text{model}}^2$,是整个注意力层参数量的两倍左右——这就是主厨的“家当”。
  1. 第一层权重参数$W_1$ 的形状是 $d_{\text{model}} \times d_{\text{ff}}$,参数量为 $d_{\text{model}} \times d_{\text{ff}}$。
    ∣W1∣=dmodel×dff|W_1| = d_{\text{model}} \times d_{\text{ff}}
  2. 第二层权重参数$W_2$ 的形状是 $d_{\text{ff}} \times d_{\text{model}}$,参数量相同。
    ∣W2∣=dff×dmodel|W_2| = d_{\text{ff}} \times d_{\text{model}}
  3. 偏置求和两个偏置向量长度分别为 $d_{\text{ff}}$ 和 $d_{\text{model}}$。
    ∣b1∣+∣b2∣=dff+dmodel|b_1| + |b_2| = d_{\text{ff}} + d_{\text{model}}
  4. 代入四倍关系当 $d_{\text{ff}} = 4 \times d_{\text{model}}$ 时,总参数量约等于 $8 \times d_{\text{model}}^2$。
    PFFN≈8×dmodel2P_{\text{FFN}} \approx 8 \times d_{\text{model}}^2

作用机制

主厨的终极价值是什么?是把转盘送来的“大杂烩素材”变成每位食客真正吃进嘴里的独立风味。FFN 的作用机制正是如此:它像一个巨大的查菜谱系统,对每个 token 的向量做精细加工,把注意力层“混”在一起的语义重新拆分、强化、重组。

研究者发现一个有趣的现象:FFN 的隐藏层单元在训练后往往对应特定的模式——某个神经元可能对“体育类”文本强烈响应,另一个对“法律类”响应。因此学界有一个广受认可的猜想:FFN 本质上是一个键值记忆库,第一层线性变换负责“查键”,激活函数负责“筛选”,第二层负责“读取记忆”。这正是它增强模型表达容量的秘密。

数学上,FFN 对序列中每个位置独立施加同一个函数:

可以这样理解:注意力是把所有人的菜夹到转盘上共享,而 FFN 是回到自己座位后,把夹到的菜按自己的口味重新调味——分享是集体的,品味是个人的。

yt=FFN(xt),t=1,2,…,T\displaystyle y_t = \text{FFN}(x_t), \quad t = 1, 2, \dots, T
这意味着同一个 FFN(同一套 $W_1, W_2$)被所有 token 共享,但对每个 token 分别计算。它不关心邻居是谁,只专注于把当前 token 的特征打磨得更加鲜明。
  1. 位置索引上式中 $t$ 遍历序列的每个位置,代表第 $t$ 个 token。
    t∈{1,2,…,T}t \in \{1, 2, \dots, T\}
  2. 逐 token 调用对每个位置的向量 $x_t$,单独执行一次 FFN 变换,位置之间互不干扰。
    yt=FFN(xt)y_t = \text{FFN}(x_t)

注意力关系

火锅店的流程永远是先转盘、后调味,不能颠倒。Transformer 的每个子层也严格遵循这个顺序:先做多头注意力,再做 FFN。注意力负责跨 token 传菜,FFN 负责逐 token 调味,两者串行协作,中间用残差连接与层归一化衔接。

把子层计算写成流程式:

再回想那家火锅店:转盘解决的是“别人有什么菜”的问题,后厨解决的是“我这道菜好不好吃”的问题。两者缺一不可,且必须按顺序来——先看别人夹了什么,再动手加工。

xattn=LayerNorm(h+Attention(h))\displaystyle x_{\text{attn}} = \text{LayerNorm}\left(h + \text{Attention}(h)\right)
y=LayerNorm(xattn+FFN(xattn))\displaystyle y = \text{LayerNorm}\left(x_{\text{attn}} + \text{FFN}(x_{\text{attn}})\right)
第一行表示:输入 $h$ 经过注意力层后,与原始输入相加(残差连接),再做层归一化。第二行表示:将上一步结果送入 FFN,再次残差相加并归一化,得到该子层最终输出。残差连接就像主厨出锅前总不忘淋一勺原汤——保留最本真的风味,防止“加工过度”。
  1. 注意力残差子层注意力输出与输入相加,确保原始信息不被丢,随后做层归一化稳定分布。
    xattn=LayerNorm(h+Attention(h))x_{\text{attn}} = \text{LayerNorm}\left(h + \text{Attention}(h)\right)
  2. FFN 残差子层把注意力结果交给 FFN 加工,再叠加一次残差,最后归一化。
    y=LayerNorm(xattn+FFN(xattn))y = \text{LayerNorm}\left(x_{\text{attn}} + \text{FFN}(x_{\text{attn}})\right)

编码解码应用

火锅店会同时接待前厅和后厨两条动线。类似地,Transformer 的编码器和解码器每层都包含 FFN,且用的是同一款“标准件”。编码器的每一层是“自注意力 + FFN”,负责把输入语义一层层精炼;解码器的每一层是“掩码自注意力 + 交叉注意力 + FFN”,在生成每一个词时,先回顾已生成的词,再看编码器提供的上下文,最后交给 FFN 做收尾调味。

无论哪个角色,FFN 的内部结构完全一致:

编码器像是反复训练阅读理解能力,解码器像是把读到的内容组织成一句句说出口的话。FFN 在两边的角色都是那个“最后把关的主厨”,保证每道菜在出锅前都有统一的品质。

EncoderLayer=LayerNorm(x+FFN(x)),x=LayerNorm(h+SelfAttn(h))\displaystyle \text{EncoderLayer} = \text{LayerNorm}\left(x + \text{FFN}(x)\right), \quad x = \text{LayerNorm}\left(h + \text{SelfAttn}(h)\right)
DecoderLayer=LayerNorm(z+FFN(z)),z=LayerNorm(h′+CrossAttn(h′,E))\displaystyle \text{DecoderLayer} = \text{LayerNorm}\left(z + \text{FFN}(z)\right), \quad z = \text{LayerNorm}\left(h' + \text{CrossAttn}(h', E)\right)
编码器中 $x$ 是自注意力的输出,解码器中 $z$ 是交叉注意力的输出。两条公式都在表达同一件事:无论前一步是谁加工的,FFN 永远是这层网络的“最后一道工序”。
  1. 编码器标准工序自注意力交换信息后,FFN 逐位精炼,形成编码器每层输出。
    EncoderLayer=LayerNorm(x+FFN(x))\text{EncoderLayer} = \text{LayerNorm}\left(x + \text{FFN}(x)\right)
  2. 解码器标准工序解码器在自注意力和交叉注意力之后,同样跟进 FFN 收尾。
    DecoderLayer=LayerNorm(z+FFN(z))\text{DecoderLayer} = \text{LayerNorm}\left(z + \text{FFN}(z)\right)

工程实践

主厨的案板虽好用,但它占了厨房大半的地租。在真实的大模型训练和推理中,FFN 的计算量和显存消耗都是大头:每个 token 要先后与两个巨型矩阵相乘,而升维后的中间激活矩阵尺寸是输入的 16 倍,训练时它必须被保存在显存中用于反向传播。

我们用 FLOPs(浮点运算次数)来量化 FFN 的计算成本:

为了应对这个成本,工业界发展出多种优化手段。例如激活重计算(训练时丢掉中间激活、反向时重新算一遍,用时间换显存);推理时做算子融合(把两个线性层与激活合并成单个 CUDA kernel 减少访存);更进一步,MoE(混合专家)直接把一位全能主厨拆成多位专职主厨,每个 token 只上其中两三位的灶台,从而在总参数量翻倍的同时,把单 token 实际计算量降下来。

FLOPsFFN≈2×T×2×dmodel×dff\displaystyle \text{FLOPs}_{\text{FFN}} \approx 2 \times T \times 2 \times d_{\text{model}} \times d_{\text{ff}}
公式中第一个"2“来自两次矩阵乘法(升维和降维),第二个”2"来自矩阵乘法本身的乘加运算(一次乘和一次加各算一次浮点运算)。$T$ 是序列长度。代入 $d_{\text{ff}} = 4 \times d_{\text{model}}$,单层 FFN 的计算量约为 $16 \times T \times d_{\text{model}}^2$。
  1. 序列长度因子$T$ 个 token 每个都要走一遍 FFN,计算量随序列长度线性增长。
    ×T\times T
  2. 两次矩阵乘升维和降维各一次矩阵乘,共两次。
    ×2\times 2
  3. 乘加双重开销每次矩阵乘的每个元素都含一次乘法和一次加法。
    ×2\times 2
  4. 矩阵维度乘积单次矩阵乘规模为 $d_{\text{model}} \times d_{\text{ff}}$。
    dmodel×dffd_{\text{model}} \times d_{\text{ff}}

AI 应用场景

大模型推理引擎优化

阶段:模型部署与推理加速

解决的问题:传统推理框架把 FFN 当作两个独立矩阵乘分开执行,需要反复读写显存,访存开销极大。AI 工程师通过算子融合、中间激活复用等手段,把升维、激活、降维合并为一次内核调用,推理吞吐可提升 20%-40%。

具体案例:某公司部署 7B 参数对话模型时,将 FFN 层改写为融合 kernel,相比朴素实现,单卡并发请求数提升 35%,首 token 延迟从 120ms 降到 85ms。

大模型可解释性研究

阶段:模型分析与调试

解决的问题:过去模型像黑箱,出了偏见问题只能重训。研究者发现 FFN 的隐藏单元存在“知识存储”效应——类似主厨的私房菜谱库,某些神经元专门记着特定领域知识,甚至存储性别、种族等偏见信息。

具体案例:研究团队通过探测法定位到模型中负责“性别-职业”关联的 FFN 神经元,进行定向编辑后,在不影响整体语言能力的前提下,职业性别偏见指标下降 60%。

模型轻量化压缩

阶段:模型蒸馏与剪枝

解决的问题:FFN 占据了每层约三分之二的参数,是模型体积的最大来源。传统剪枝不区分结构,容易误伤关键通路。基于 FFN 结构特点的通道剪枝,按隐藏单元重要性裁剪 $d_{\text{ff}}$ 维度,可在损失极小精度的情况下显著压缩模型。

具体案例:团队对 BERT-base 的 FFN 隐藏层按激活幅度剪掉 30% 神经元,模型体积从 440MB 压缩到 310MB,GLUE 平均分仅下降 0.8 分。

Python 演示

python45 行
import numpy as np class FeedForward:    def __init__(self, d_model, d_ff, activation='gelu'):        self.d_model = d_model        self.d_ff = d_ff        self.activation = activation        self.W1 = np.random.randn(d_model, d_ff) * 0.02        self.b1 = np.zeros(d_ff)        self.W2 = np.random.randn(d_ff, d_model) * 0.02        self.b2 = np.zeros(d_model)     @staticmethod    def gelu(x):        return 0.5 * x * (1.0 + np.tanh(np.sqrt(2.0 / np.pi) * (x + 0.044715 * x ** 3)))     @staticmethod    def relu(x):        return np.maximum(0.0, x)     def forward(self, x):        hidden = x @ self.W1 + self.b1        if self.activation == 'gelu':            hidden = self.gelu(hidden)        elif self.activation == 'relu':            hidden = self.relu(hidden)        return hidden @ self.W2 + self.b2     def param_count(self):        return self.W1.size + self.b1.size + self.W2.size + self.b2.size  if __name__ == '__main__':    np.random.seed(42)    T, d_model, d_ff = 5, 4, 16    ffn = FeedForward(d_model, d_ff, activation='gelu')    x = np.random.randn(T, d_model)    y = ffn.forward(x)    print('输入形状:', x.shape)    print('输出形状:', y.shape)    print('该层参数量:', ffn.param_count())    hidden = x @ ffn.W1 + ffn.b1    print('隐藏层形状:', hidden.shape)    print('隐藏层是输入的', hidden.shape[-1] // d_model, '倍')    print('GELU正激活比例:', round(float(np.mean(hidden > 0)), 4))
目的:用 numpy 实现一个完整的 FFN 层,演示升维-激活-降维的完整流程,并统计隐藏层形状和参数量。
  1. self.W1 = np.random.randn(d_model, d_ff) * 0.02用 0.02 标准差的小随机数初始化升维矩阵,防止初始输出过大。
  2. self.W2 = np.random.randn(d_ff, d_model) * 0.02初始化降维矩阵,与 W1 的维度正好互逆。
  3. hidden = x @ self.W1 + self.b1完成第一层线性变换:输入从 4 维升到 16 维。
  4. hidden = self.gelu(hidden)施加 GELU 激活,逐元素筛选信号。
  5. return hidden @ self.W2 + self.b2完成第二层线性变换:从 16 维降回 4 维。
  6. self.W1.size + self.b1.size + self.W2.size + self.b2.size统计四组参数的个数总和。

常见误区

误区FFN 对每个 token 单独处理,那是不是每个 token 都有自己的权重矩阵?不然怎么做到“个性化调味”?

正解恰恰相反,FFN 的参数在所有 token 间完全共享。它像一位厨师同时给一百桌客人炒菜,手法是同一套,但每道菜会在不同食材基础上发挥出不同味道。共享参数大大减少了模型参数量,也让位置之间的处理保持一致,这正是“同一位主厨”的定义。

为何常见:初学者容易把“独立计算”误解为“独立参数”。实际上“独立”指的是计算过程互不干扰,而不是每份输入配一套权重。

误区反正有两层线性变换,矩阵乘法足够复杂,去掉中间的激活函数应该也没关系吧?

正解如果去掉激活函数,两层线性变换在数学上可以合并成一层:$W_2(W_1 x + b_1) + b_2 = (W_2 W_1)x + (W_2 b_1 + b_2)$,本质上仍是线性函数。而现实世界的数据关系几乎都是非线性的。激活函数就像“尝味判断”这一步,没有它,主厨再用力也只是把调料机械地拌在一起,根本分不出酸甜苦辣。

为何常见:大家熟知神经网络“层数越多越强大”,但容易忽略激活函数才是让多层变“深”的关键,线性层叠再多也只是“长的”线性层。

误区模型表达能力不够?把 FFN 的隐藏层从 4 倍加到 16 倍,参数翻好几番,效果一定更好。

正解四倍是预训练实践中的经验黄金点。盲目扩大 $d_{\text{ff}}$ 会带来三座大山:参数量暴增导致过拟合、中间激活矩阵让显存爆炸、推理延迟线性上升。很多研究表明,在相同预算下,把容量分给更多层比加宽单层 FFN 收益更高。主厨的案板不是越大越好,够用并且能和厨房其他设备配合才是关键。

为何常见:直觉上“能力=参数”,但忽略了计算资源约束和边际收益递减,“大就是好”的惯性思维在深度学习里经常翻车。

误区Transformer 不就是注意力机制吗?FFN 只是对注意力输出做一点后处理,删掉应该影响不大。

正解实验和理论都表明,FFN 参数量占每层约三分之二,是模型记忆中知识的主要载体。有研究直接移除 FFN 只保留注意力,模型性能断崖式下跌,几乎退化到随机初始化水平。注意力负责“在哪看”,FFN 负责“看到后想什么”,两者就像转盘和主厨——没有主厨,转盘转得再快也端不出一道菜。

为何常见:Transformer 的名字和宣传都聚焦在注意力上,导致学习者忽略了另一半架构的主力贡献。

误区GELU 和 ReLU 曲线看着差不多,都是保留正值干掉负值,换着用没啥区别。

正解两者性质差异明显。ReLU 把负区域梯度硬截断为 0,可能导致部分神经元彻底“死亡”;GELU 在负半区保留一点微弱梯度,信息不会完全中断。BERT、GPT 等主流模型默认使用 GELU,实证上训练更稳定、下游任务分数略高。它们的关系不是“一样”,而是“大体同方向但手感不同”——就像粗盐和细盐都是盐,但撒在菜品上的溶解速度与咸味分布并不相同。

为何常见:只看函数形状的宏观走向,忽略了梯度行为等微观性质对深度网络训练的动态影响。

面试题

Q1. FFN 中隐藏层的维度通常如何确定?

单选题 · easy

  • A.与输入维度完全一致
  • B.取输入维度的四倍← 正确答案
  • C.固定为一千零二十四
  • D.与序列长度成正比

答案:B。Transformer 的标准设计是 $d_{\text{ff}} = 4 \times d_{\text{model}}$,如 BERT-base 从 768 升到 3072。A 选项会退化为无意义的恒等容量,C 是固定值不符合各模型实际,D 与序列长度无关。

Q2. FFN 输出向量的维度是?

单选题 · easy

  • A.与隐藏层维度相同
  • B.与输入维度相同← 正确答案
  • C.与词表大小相同
  • D.与注意力头数相同

答案:B。FFN 的结构是“升维再降维”,最终输出维度必须恢复为 $d_{\text{model}}$,以便与残差连接直接相加。就像主厨把四倍案板上摊开的菜重新装回标准餐盘,餐盘尺寸永远不变。

Q3. 激活函数在 FFN 中主要作用是?

单选题 · easy

  • A.降低模型计算复杂度
  • B.引入非线性表达能力← 正确答案
  • C.增加模型参数量规模
  • D.缩小隐藏层的维度

答案:B。没有激活函数,两层线性变换可以合并成一层,模型退化为线性模型,无法拟合复杂语义关系。激活函数就是主厨的“尝味判断”,保证信息经过非线性筛选,而非简单搬运。

Q4. 如果去掉 FFN 中的激活函数,会发生?

单选题 · mid

  • A.两层线性退化为单层← 正确答案
  • B.参数量会显著降低
  • C.模型表达能力翻倍
  • D.梯度消失完全消除

答案:A。数学上 $W_2(W_1x + b_1) + b_2 = (W_2W_1)x + (W_2b_1 + b_2)$,两个线性变换合体变成一个线性变换,深层结构被“压扁”。参数量不变但表达能力骤降,与 B、C、D 都无关。

Q5. 关于 GELU 激活函数,以下说法正确的有?

多选题 · mid

  • A.梯度平滑且处处可导← 正确答案
  • B.负值输入也有微弱负输出← 正确答案
  • C.完全等价于 ReLU 函数
  • D.被 BERT 等模型广泛采用← 正确答案

答案:ABD。GELU 用正态累积分布做软加权,负半区保留微小输出,梯度连续平滑,是 GPT、BERT 的默认选择。C 错在 GELU 负半区并非恒为 0,和 ReLU 的硬截断有明显区别。

Q6. FFN 与自注意力在 Transformer 中的分工是?

单选题 · mid

  • A.注意力跨 token 交换信息← 正确答案
  • B.FFN 也做跨 token 交互
  • C.FFN 只负责降低维度
  • D.注意力代替残差连接

答案:A。自注意力让序列各位置互相通信,FFN 对每个 token 独立精炼。B 错在 FFN 不跨 token,C 错在 FFN 还负责升维和筛选,D 错在残差连接是独立机制。

Q7. FFN 的参数量与同层注意力相比大约是?

单选题 · mid

  • A.注意力的两倍左右← 正确答案
  • B.与注意力完全相同
  • C.只有注意力的四分之一
  • D.比注意力少很多

答案:A。当 $d_{\text{ff}} = 4 \times d_{\text{model}}$ 时,FFN 参数量约 $8d^2$,注意力四个投影矩阵约 $4d^2$,前者约为后者的两倍。这就是为什么说 FFN 是模型参数的主要存储地。

Q8. 训练大模型时,以下哪个结构通常最占显存?

单选题 · hard

  • A.FFN 中间层激活值← 正确答案
  • B.注意力得分矩阵
  • C.词表输出层投影
  • D.位置编码的缓存

答案:A。FFN 升维后的中间激活形状为 (batch, seq_len, 4×d_model),且反向传播时必须驻留显存,是激活显存的最大来源。注意力得分矩阵虽有 seq_len² 项,但通常远小于 FFN 的 4×d_model 扩展量。

Q9. 残差连接在 FFN 子层中的作用包括?

多选题 · hard

  • A.让梯度传得更深更稳← 正确答案
  • B.给输出叠上原始信息← 正确答案
  • C.替代 LayerNorm 操作
  • D.让模型结构更简单

答案:AB。残差连接提供了从输入到输出的“旁路”,既缓解深层网络梯度消失,也保证原始信息不被加工过程完全覆盖。它和 LayerNorm 是配合关系而非替代关系,D 是干扰项——结构上多了一条连接,谈不上“更简单”。

Q10. 关于混合专家(MoE)对 FFN 的改造,正确的有?

多选题 · extreme

  • A.每个专家共享同一份权重
  • B.路由为每个 token 挑选专家← 正确答案
  • C.专家内保留两层线性结构← 正确答案
  • D.专家数量增加参数一定减少

答案:BC。MoE 把单一 FFN 换成多个专家,每个专家仍是“两层线性+激活”的标准结构,由路由网络决定 token 去哪几个专家。A 错在专家之间权重独立,D 错在专家越多参数量通常越大,只是单 token 计算量下降。