想象你走进一家手工巧克力工坊。师傅们接到一袋杂乱的原料——可可豆、糖、奶油,每样都带着自己的“原始性格”。工坊的操作间里,六道工序依次排开:第一道让原料两两碰面、寻找搭配,第二道从更多角度审视每样原料的风味,第三道把每粒原料单独深加工……每道工序之后,都有一位品控师把口味拉回标准区间,而师傅还会特地从上一道工序保留一份“原味样本”叠回去,防止加工过度。六道工序走完,原本零散的原料已经融成一整块“懂彼此”的巧克力——这就是 Transformer 编码器做的事:把一句话里每个词,从孤立的词向量一步步炼成蕴含整句话上下文的特征表示。你不需要任何 AI 基础,只需要跟着这条流水线走一遍,就能明白 BERT 这类模型的“心脏”是怎样工作的。

岗位关联

理解编码器结构是掌握 BERT 等预训练模型的基石。对 AI 从业者来说,它能帮你读懂模型如何提取语义特征、理解深层网络训练中的梯度问题,也为微调、部署与模型改进提供底层直觉。

目录
  1. 可视化演示
  2. 编码器总览
  3. 自注意力机制
  4. 多头注意力
  5. 前馈网络
  6. 残差连接
  7. 层归一化
  8. 六层堆叠
  9. AI 应用场景
  10. Python 演示
  11. 常见误区
  12. 面试题

可视化演示

展示Transformer编码器六层堆叠架构、自注意力QKV矩阵计算与注意力热力图、残差连接与LayerNorm位置对比三大核心概念。

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

六层编码器堆叠架构 每层含自注意力(SA)+前馈网络(FFN)两个子层 原始论文6层,BERT-Base 12层,BERT-Large 24层 Encoder = Stack(L1...LN), N=6 多层堆叠逐步提取更高层语义特征

编码器总览

巧克力工坊的流水线入口,一袋袋原料被贴好标签,送进操作间。整条流水线由六个几乎相同的操作间串联而成,每个操作间里做两件事:先让原料两两碰面、寻找搭配,再把每粒原料单独深加工。没人规定六个操作间必须一模一样,但工坊主发现“重复同样工序”反而最有效——这就是编码器“六层堆叠”的设计哲学。

在 Transformer 里,输入的一句话先被切成一个个词,再通过嵌入层(Embedding)把每个词变成一串数字组成的“词向量”,相当于给每粒原料贴标签。因为自注意力本身没有先后顺序的概念,还需要加上位置编码(Positional Encoding)来标注每个词在句子中的位置,好比在原料上写上“第 1 号”“第 2 号”。

编码器的核心就是六层完全同构的编码器层。每一层包含两个子层:多头自注意力子层和前馈网络子层,每个子层外面都套着残差连接与层归一化。前一层输出就是后一层的输入,逐层传递:

六道工序结构相同,但每一道都在前一道的基础上加深理解。当词向量走出最后一层时,它们已经不再是孤立的“词”,而是“在特定语境中的词”——这正是编码器存在的意义。

h0=Xembed+Xposh_0 = X_{\text{embed}} + X_{\text{pos}}
hl=EncoderLayer(hl−1),l=1,2,…,6h_l = \mathrm{EncoderLayer}(h_{l-1}), \quad l = 1, 2, \ldots, 6
  1. 输入嵌入把句子里的每个词映射为一个稠密词向量,得到 X_embed,相当于为每种原料建立一张“风味档案卡”。
    Xembed=Embedding(句子)X_{\text{embed}} = \mathrm{Embedding}(\text{句子})
  2. 注入位置信息把位置编码 X_pos 逐元素加到词向量上,让模型知道词的先后顺序。
    h0=Xembed+Xposh_0 = X_{\text{embed}} + X_{\text{pos}}
  3. 逐层套用变换每层都是一个编码器层,对上一层的输出做相同类型的加工。
    hl=EncoderLayer(hl−1)h_l = \mathrm{EncoderLayer}(h_{l-1})
  4. 输出语义表示经过 l 层迭代,h_6 就是最终输出,每个词向量都已包含整句话的信息。
    输出=h6\text{输出} = h_6

自注意力机制

工坊里有位“搭配师傅”,他的任务很特别:每一粒原料都要望着屋子里其他所有原料,判断“我和谁在一起最合适”。可可豆会倾向于和奶油搭配,而不太会搭理包装纸。搭配师傅做完判断后,会把其他原料的“精华”按亲疏比例抽一点到自己身上——于是在这间屋子里,每一粒原料都吸收了一点全场的气息。

在 Transformer 中,这位搭配师傅就是自注意力机制(Self-Attention)。每个词向量 X 会同时扮演三个角色:查询 Q(Query,“我在找谁”)、键 K(Key,“我有什么特征”)和值 V(Value,“我能提供什么信息”)。它们分别由 X 乘以三个不同的权重矩阵得到:

经过这五步,“我”这个词已经不再是孤立的“我”,而是“处在整句话语境中的我”。搭配师傅让每个词都拥有了“全场视野”。

Attention(Q,K,V)=softmax⁡(QK⊤dk)V\mathrm{Attention}(Q, K, V) = \operatorname{softmax}\left(\frac{QK^{\top}}{\sqrt{d_k}}\right)V
  1. 生成 Q、K、V把输入 X 分别乘上 W_Q、W_K、W_V,得到查询、键、值三组向量。这相当于搭配师傅先给每粒原料填三张不同的卡片。
    Q=XWQ,K=XWK,V=XWVQ = XW_Q, \quad K = XW_K, \quad V = XW_V
  2. 点积打分用 Q 与所有 K 做点积,得到词与词之间的相关分数。分数越高,说明两粒原料越“投缘”。
    scores=QK⊤\text{scores} = QK^{\top}
  3. 缩放防溢出除以 √d_k,把分数拉回到一个温和的数值范围,避免点积太大让 softmax 进入饱和区。
    QK⊤dk\frac{QK^{\top}}{\sqrt{d_k}}
  4. softmax 归一化把分数变成一组和为 1 的权重,相当于把“投缘程度”换算成“抽取精华的比例”。
    softmax⁡(QK⊤dk)\operatorname{softmax}\left(\frac{QK^{\top}}{\sqrt{d_k}}\right)
  5. 加权聚合用权重对 V 做加权求和。每个词最终得到的是全场词信息的混合体,这就是“上下文向量”。
    Attention(Q,K,V)=权重×V\mathrm{Attention}(Q, K, V) = \text{权重} \times V

多头注意力

一位搭配师傅的眼光再准,也总会有盲区——他可能擅长看口味搭配,却不擅长看口感层次。工坊主于是请了多位师傅:一位管口味、一位管香气、一位管色泽。每位师傅都独立地做判断,最后把大家的意见汇总在一起,形成一份更全面的搭配方案。

这就是多头注意力(Multi-Head Attention)。与其用一组 Q、K、V 做一次注意力,不如把输入拆成 h 组,每组用自己独立的权重投影到不同的“子空间”,并行做 h 次自注意力。每个“头”关注不同的关系模式——有的关注语法依存,有的关注指代关系,有的关注语义相似性。最后把所有头的输出拼起来,再经过一个线性层融合:

多头机制让模型不再“只从一个角度理解关系”,而是像一支专家评审团那样,从多个视角捕捉文本中丰富而微妙的关联。

MultiHead(Q,K,V)=Concat(head1,…,headh)WO\mathrm{MultiHead}(Q, K, V) = \mathrm{Concat}(\mathrm{head}_1, \ldots, \mathrm{head}_h)W^O
  1. 分头投影第 i 个头用独立的权重矩阵把 Q、K、V 投影到低维子空间,等于每位师傅戴上自己的“滤镜”观察原料。
    headi=Attention(QWiQ,KWiK,VWiV)\mathrm{head}_i = \mathrm{Attention}(QW_i^Q, KW_i^K, VW_i^V)
  2. 并行计算h 个头完全并行,互不干扰,各自完成一次自注意力。
    head1,head2,…,headh\mathrm{head}_1, \mathrm{head}_2, \ldots, \mathrm{head}_h
  3. 拼接结果把所有头的输出沿特征维度拼接成一个长向量,汇总多位师傅的意见。
    Concat(head1,…,headh)\mathrm{Concat}(\mathrm{head}_1, \ldots, \mathrm{head}_h)
  4. 线性融合乘以 W^O 把拼接后的向量投影回 d_model 维,形成多头注意力的最终输出。
    MultiHead(Q,K,V)=Concat(head1,…,headh)WO\mathrm{MultiHead}(Q, K, V) = \mathrm{Concat}(\mathrm{head}_1, \ldots, \mathrm{head}_h)W^O

前馈网络

搭配师傅让每粒原料都吸收了全场气息,但这还不够——每粒原料自身还需要被“深加工”:可可豆要研磨、糖要焦化、奶油要打发。于是工坊里还有一位“烹饪师傅”,他不管别的原料,只专心处理手头这一粒,把它加工成更精细的形态。

在编码器层里,这位烹饪师傅就是前馈网络(Feed-Forward Network,FFN)。它作用于每一个词向量,且对每个词独立操作、互不干扰。FFN 由两层线性变换组成,中间夹着一个 ReLU 激活函数:先升维再降维,让模型有足够的容量对每个位置的特征做非线性变换。

因为 FFN 对每个词独立处理,它不会在词之间传递信息——那是注意力子层的职责。两者分工明确:注意力负责“词与词对话”,前馈网络负责“每个词自我提升”。

FFN(x)=max⁡(0, xW1+b1)W2+b2\mathrm{FFN}(x) = \max(0, \, xW_1 + b_1)W_2 + b_2
  1. 第一层线性变换把输入 x 映射到一个更高维的空间(通常是 d_model 的 4 倍),给“深加工”提供更大操作台。
    xW1+b1xW_1 + b_1
  2. ReLU 激活把负数全部置零,引入非线性。负值被“剪掉”,相当于把没用的味道丢弃,只保留正向的风味特征。
    max⁡(0, xW1+b1)\max(0, \, xW_1 + b_1)
  3. 第二层线性变换把高维特征投影回 d_model 维度,作为本子层的输出,便于和残差连接相加。
    max⁡(0, xW1+b1)W2+b2\max(0, \, xW_1 + b_1)W_2 + b_2

残差连接

工坊有条不成文的规定:每道工序开工前,师傅都会先留一份“原味样本”。无论工序怎么折腾,最后都要把加工后的成品和原味样本混在一起。这样一来,万一加工过度、味道全变了,原本的底味还在,整体不至于跑偏。

这就是残差连接(Residual Connection),也叫跳跃连接。在编码器里,每个子层的输出不会直接传给下一层,而是先与子层的输入相加:

残差连接的意义远超“防止味道跑偏”。在反向传播时,梯度可以沿着这条捷径“抄近道”直达底层,避免乘以多层矩阵后梯度消失。可以说,没有残差连接,十几层的 Transformer 几乎无法训练。

Add(x)=x+Sublayer(x)\mathrm{Add}(x) = x + \mathrm{Sublayer}(x)
  1. 子层处理Sublayer(x) 代表自注意力或前馈网络对输入 x 的加工结果。
    Sublayer(x)\mathrm{Sublayer}(x)
  2. 逐元素相加把原始输入 x 与加工结果相加,形状完全一致才能相加,因此所有子层都保持 d_model 维。
    x+Sublayer(x)x + \mathrm{Sublayer}(x)
  3. 跨层传递这个“x + 变化量”的结果成为下一个子层的输入,梯度可以沿着 x 这条直路畅通无阻地回传。
    Add(x)=x+Sublayer(x)\mathrm{Add}(x) = x + \mathrm{Sublayer}(x)

层归一化

每道工序结束,品控师都会登场。他先测量当下成品的“平均味道”和“味道波动幅度”,然后通过一番调整,把整体味道拉回到一个标准区间——既不太浓,也不太淡。这样下一道工序面对的永远是“味道正常”的原料,不会因为上一道太极端而失控。

品控师的绝活就是层归一化(Layer Normalization,LayerNorm)。对一个词向量 x(一个 d_model 维向量),LayerNorm 在特征维度上计算均值和方差,把向量标准化为均值为 0、方差为 1 的分布,再用可学习的缩放参数 γ 和平移参数 β 恢复表达能力。

在原始 Transformer 中,归一化放在残差相加之后,称为 Post-LN;后来的工作发现把它放到子层之前(Pre-LN)能让深层模型训练更稳定。无论哪种位置,品控师都在源源不断地把“走偏的数值”拉回正轨。

LayerNorm(x)=x−μσ2+ϵ⋅γ+β\mathrm{LayerNorm}(x) = \frac{x - \mu}{\sqrt{\sigma^2 + \epsilon}} \cdot \gamma + \beta
  1. 求均值对每个向量在特征维度上求平均值,代表这个词向量目前的“整体能量水平”。
    μ=1d∑i=1dxi\mu = \frac{1}{d}\sum_{i=1}^{d} x_i
  2. 求方差计算各维特征偏离均值的程度,代表“各维之间的差异有多大”。
    σ2=1d∑i=1d(xi−μ)2\sigma^2 = \frac{1}{d}\sum_{i=1}^{d}(x_i - \mu)^2
  3. 标准化减去均值除以标准差,加上极小量 ε 防止除零。这一步让所有词向量的尺度对齐。
    x−μσ2+ϵ\frac{x - \mu}{\sqrt{\sigma^2 + \epsilon}}
  4. 缩放平移乘以 γ 再加上 β,γ 和 β 都是可学习参数。恢复模型需要的表达能力,不至于被“标准化”削掉所有个性。
    x−μσ2+ϵ⋅γ+β\frac{x - \mu}{\sqrt{\sigma^2 + \epsilon}} \cdot \gamma + \beta

六层堆叠

六道工序全部走完后,巧克力会是什么样子?第一道工序里,原料只是勉强混了个脸熟;第二道、第三道开始有了默契;到第四、第五道时,各种风味已经交织在一起;最后一道工序结束,你尝到的每一口都同时带着可可的苦、糖的甜和奶油的醇——它们再也分不开了。

编码器的六层堆叠正是这样一个渐进抽象的过程。研究表明,底层编码器更关注词法和局部搭配(比如“窗”和“玻璃”相邻出现),中层开始捕捉句法结构(主语、谓语、宾语的关系),高层则逐渐提炼出全局语义(整个句子的主题与情感倾向)。六层不是随意定的数字,而是“够用且不过度”的经验选择——BERT 用了 12 层,GPT 用了 12 层,层数是可以调节的超参数。

每一层的完整变换可以写成复合函数:

所以,“六层堆叠”的本质是让信息在深度上逐级精炼。底层看到的是“词”,高层看到的是“意义”。当这六层全部跑完,每个词向量都携带着整句话的灵魂——这正是下游任务真正需要的特征。

hL=EncoderLayer∘EncoderLayer∘⋯∘EncoderLayer⏟6 次(h0)h_L = \underbrace{\mathrm{EncoderLayer} \circ \mathrm{EncoderLayer} \circ \cdots \circ \mathrm{EncoderLayer}}_{6 \text{ 次}}(h_0)
  1. 函数复合符号 ∘ 表示“先做后者的变换,再做前者的变换”,即把六层编码器按顺序套在一起。
    EncoderLayer∘EncoderLayer∘⋯∘EncoderLayer\mathrm{EncoderLayer} \circ \mathrm{EncoderLayer} \circ \cdots \circ \mathrm{EncoderLayer}
  2. 逐层传递h_0 先经过第一层得到 h_1,h_1 再经过第二层得到 h_2,如此一直推进到第 6 层。
    hl=EncoderLayer(hl−1)h_l = \mathrm{EncoderLayer}(h_{l-1})
  3. 深层输出最终 h_6 就是编码器输出的特征表示,每个向量都被注入了从局部到全局的多层语义。
    h6=EncoderLayer6(h5)h_6 = \mathrm{EncoderLayer}_6(h_5)

AI 应用场景

BERT 预训练:用编码器堆出语言理解模型

阶段:预训练

解决的问题:传统词向量无法区分“苹果很好吃”和“苹果手机很贵”中“苹果”的语义区别。BERT 用多层 Transformer 编码器做双向语言建模,通过“掩码语言模型”(随机遮住 15% 的词,让模型预测)和“下一句预测”来学习上下文相关表示。

具体案例:Google 发布 BERT-Base 时,堆叠了 12 层编码器(每层 12 个注意力头、隐藏维度 768),在 SQuAD 问答任务上取得 93.2% 的 F1 分数,一举超过人类基线。如今 HuggingFace 上的 bert-base-uncased 被全球开发者下载数亿次,成为 NLP 领域的“荔枝核”模型。

语义检索与句向量

阶段:特征提取与向量化

解决的问题:关键词搜索无法理解同义改写。将编码器输出的 [CLS] 向量(或对所有 token 向量做池化)作为句向量,语义相近的句子在向量空间中距离更近,从而实现语义检索。

具体案例:Sentence-BERT 用孪生编码器把句子编码为 768 维向量,在 STS-B 语义相似度基准上达到 86% 以上的 Spearman 相关度。电商客服系统用它把用户问题与 FAQ 库匹配,准确率比 BM25 提升约 20 个百分点。

命名实体识别与序列标注

阶段:微调

解决的问题:实体识别需要同时理解上下文。传统 BiLSTM-CRF 对长距离依赖捕捉有限,而编码器输出的每个 token 向量已融合整句信息,直接接一个线性分类器就能识别人名、地名、机构名。

具体案例:在医疗病历文本上,用中文 BERT 编码器微调 NER 模型,对“阿莫西林胶囊”这种多词实体的 F1 值从 82% 提升到 91%,因为编码器能让“阿莫西林”与“胶囊”通过注意力建立强关联,模型更容易判断这是一个药物实体。

Python 演示

python72 行
import numpy as np  def softmax(x):    e = np.exp(x - np.max(x, axis=-1, keepdims=True))    return e / np.sum(e, axis=-1, keepdims=True)  def layer_norm(x, eps=1e-6):    mu = np.mean(x, axis=-1, keepdims=True)    var = np.var(x, axis=-1, keepdims=True)    gamma = np.ones_like(x)    beta = np.zeros_like(x)    return (x - mu) / np.sqrt(var + eps) * gamma + beta  class SelfAttention:    def __init__(self, d_model, d_k):        self.d_k = d_k        self.W_Q = np.random.randn(d_model, d_k) * 0.1        self.W_K = np.random.randn(d_model, d_k) * 0.1        self.W_V = np.random.randn(d_model, d_k) * 0.1     def forward(self, X):        Q = X @ self.W_Q        K = X @ self.W_K        V = X @ self.W_V        scores = Q @ K.T / np.sqrt(self.d_k)        attn = softmax(scores)        return attn @ V  class FeedForward:    def __init__(self, d_model, d_ff):        self.W1 = np.random.randn(d_model, d_ff) * 0.1        self.b1 = np.zeros(d_ff)        self.W2 = np.random.randn(d_ff, d_model) * 0.1        self.b2 = np.zeros(d_model)     def forward(self, x):        return np.maximum(0, x @ self.W1 + self.b1) @ self.W2 + self.b2  class EncoderLayer:    def __init__(self, d_model, d_k, d_ff):        self.attn = SelfAttention(d_model, d_k)        self.ffn = FeedForward(d_model, d_ff)     def forward(self, x):        h = layer_norm(x + self.attn.forward(x))        return layer_norm(h + self.ffn.forward(h))  class TransformerEncoder:    def __init__(self, num_layers, d_model, d_k, d_ff):        self.num_layers = num_layers        self.layers = [EncoderLayer(d_model, d_k, d_ff) for _ in range(num_layers)]     def encode(self, x):        for layer in self.layers:            x = layer.forward(x)        return x  if __name__ == "__main__":    np.random.seed(42)    seq_len, d_model = 4, 8    encoder = TransformerEncoder(num_layers=6, d_model=d_model, d_k=4, d_ff=16)    x = np.random.randn(seq_len, d_model)    out = encoder.encode(x)    print("输入形状:", x.shape)    print("输出形状:", out.shape)
目的:用 NumPy 实现六层 Transformer 编码器的前向传播,演示每个词向量如何逐层融合上下文信息。
  1. scores = Q @ K.T / np.sqrt(self.d_k)计算词与词之间的相关分数并除以 √d_k,防止点积过大导致 softmax 梯度消失。
  2. attn = softmax(scores)把分数转成和为 1 的注意力权重,体现“抽取其他词精华的比例”。
  3. return attn @ V按权重聚合所有词的信息,得到融合上下文的输出。
  4. return np.maximum(0, x @ self.W1 + self.b1) @ self.W2 + self.b2前馈网络先升维、ReLU 截断、再降维,对每个词做独立深加工。
  5. h = layer_norm(x + self.attn.forward(x))残差连接先让原始输入和子层输出相加,再做层归一化,稳定训练。
  6. for layer in self.layers: x = layer.forward(x)六层逐层堆叠,前一层输出作为后一层输入。

常见误区

误区我一直以为多头注意力是把一个注意力模块重复跑六次,第一次的输出作为第二次的输入,就像流水线上几个人排队检查一样。

正解多头注意力是并行执行的。h 个头各自用独立的权重矩阵投影 Q、K、V,在同一个输入上同时计算,最后拼接再线性融合。就像多个品鉴师同时从不同角度审视同一块巧克力,而不是轮流看。如果串行,“头”之间就会产生依赖,无法各自专注不同的关系模式。

为何常见:因为日常经验里“多方审查”常被描述成逐级流程,而并行计算不符合直觉,容易把“多头”误解为“多轮”。

误区残差连接不就是把输入和输出加一下吗?就算去掉它,模型应该也能训练,只是可能慢一点。

正解残差连接是深层 Transformer 能训练起来的关键。没有残差,梯度要从最后一层一路乘回第一层,经过几十个矩阵乘法后几乎衰减为零,底层参数根本得不到有效更新。残差提供了梯度“高速公路”,让深层网络第一次变得可以训练。它不是优化选项,而是必要组件。

为何常见:单看加法运算觉得简单,容易低估它对梯度流动的深远影响;只有真正训练深层网络时才会发现没有它就崩。

误区层归一化应该是对一句话里所有词做归一化吧?就像把整锅汤的咸淡调匀一样。

正解LayerNorm 是对每个词向量内部的特征维做归一化,也就是对每个 token 的 d_model 维度求均值方差。一句话里有 4 个词,就会有 4 组独立的 μ 和 σ。与之相对,BatchNorm 才是沿批次维做归一化。这个区别直接影响模型在不同序列长度下的表现稳定性。

为何常见:“层”这个词让人联想到“一整层网络”或“整句话”,加上 BatchNorm 的类比习惯,很容易把归一化范围搞混。

误区既然文章标题叫“六层堆叠”,那 Transformer 编码器是不是必须正好六层?BERT 也是六层吗?

正解层数是超参数,不是硬规定。BERT-Base 用了 12 层,BERT-Large 用了 24 层,GPT 系列甚至堆了 12 到 48 层。六层只是论文里的基准配置。“六层堆叠”强调的是“多层重复同构子层”这个设计模式,而非固定数字。层数越多容量越大,但训练成本和过拟合风险也越高。

为何常见:初学者倾向于把论文中的默认配置当成标准答案,忽略了“超参数可调”这一基本事实。

面试题

Q1. 在 Transformer 编码器中,自注意力机制的 Q、K、V 是如何得到的?

单选题 · easy

  • A.从输入序列中随机采样三组向量
  • B.将输入 X 分别乘以 W_Q、W_K、W_V 矩阵← 正确答案
  • C.将输入 X 原样复制三份直接使用
  • D.用三个不同的激活函数从 X 生成

答案:B。Q、K、V 是输入 X 分别与三个可学习权重矩阵相乘得到的线性投影。类比搭配师傅填的三张卡片,每张卡片由同一份原料档案导出但用途不同。A 是随机无意义,C 少了投影多样性,D 混淆了激活函数与线性投影的概念。

Q2. 自注意力打分后除以 √d_k 的主要目的是什么?

单选题 · easy

  • A.防止点积过大导致 softmax 梯度消失← 正确答案
  • B.减少自注意力的计算开销
  • C.让每个词只关注邻近词汇
  • D.把注意力权重变成对称矩阵

答案:A。当维度 d_k 较大时,点积的方差会随之增大,softmax 容易落入饱和区,梯度趋近于零。除以 √d_k 可以把数值范围拉回温和区间。这就像把说话音量调回适中,让“品鉴师”能听清每句话,而不是被震耳欲聋的声音吓到失聪。

Q3. 前馈网络(FFN)中的激活函数通常使用哪一个?

单选题 · easy

  • A.sigmoid
  • B.tanh
  • C.ReLU← 正确答案
  • D.softmax

答案:C。Transformer 论文中的 FFN 使用 ReLU 作为中间层激活函数,即 max(0, x)。ReLU 计算简单且能缓解梯度消失。sigmoid 和 tanh 在深层网络中容易饱和,softmax 是归一化函数而非激活函数,一般不用在 FFN 中。

Q4. 残差连接在深层编码器中最核心的贡献是什么?

单选题 · mid

  • A.增加可学习的参数数
  • B.给梯度提供直达通道防退化← 正确答案
  • C.让自注意力机制变成多头
  • D.对隐藏特征做归一化处理

答案:B。残差连接让梯度可以从深层沿“捷径”直接传到浅层,缓解深层网络中的梯度消失与性能退化问题。它不引入新参数,也和多头、归一化无关。就像工坊保留原味样本,保证加工过程再长也不丢底味。

Q5. 层归一化(LayerNorm)归一化的是哪个维度?

单选题 · mid

  • A.整个批次中的全部样本
  • B.单个词向量内部的特征维← 正确答案
  • C.序列中词与词之间的维度
  • D.六个编码器层之间的维度

答案:B。LayerNorm 对每个 token 的 d_model 特征维求均值和方差,独立做标准化。一句话有 N 个词,就有 N 组 μ 和 σ。选项 A 是 BatchNorm 的做法,C 和 D 混淆了归一化的作用维度。

Q6. 多头注意力中,多个“头”之间的关系是什么?

单选题 · mid

  • A.串行执行,一个头接一个头处理
  • B.并行独立,学习不同的特征子空间← 正确答案
  • C.多个头完全共享相同的权重
  • D.每个头只处理片段而非全序列

答案:B。每个头有独立的 W_Q、W_K、W_V 投影矩阵,在相同输入上并行计算,各自关注不同的关系模式(语法、指代、语义等)。串行会让头之间互相影响,共享权重则退化成单头,只处理片段则会丢失全局视野。

Q7. 标准的 Transformer 编码器能够看到输入序列的哪个部分?

单选题 · mid

  • A.只能看到当前词左侧的词汇
  • B.只能看到当前词右侧的词汇
  • C.同一层内所有词相互可见← 正确答案
  • D.只能看到相邻的两个词汇

答案:C。编码器中的自注意力没有掩码,每个位置的 Q 都能与所有位置的 K 计算分数,因此是双向的。这区别于解码器中的 masked self-attention。就像搭配师傅放眼整个屋子,而不是只看左边或右边的邻居。

Q8. 以下关于 Transformer 编码器层的说法,正确的有哪些?

多选题 · easy

  • A.每层包含多头自注意力子层← 正确答案
  • B.每层包含前馈网络子层← 正确答案
  • C.每层只包含一个线性变换
  • D.每个子层均有残差与层归一化← 正确答案

答案:ABD。每个编码器层由多头自注意力和前馈网络两个子层组成,且每个子层都包裹在残差连接和层归一化中。C 错在编码器层包含多个线性变换(Q/K/V 投影、FFN 的两层线性、输出投影),远不止一个。

Q9. 关于层归一化位置(Post-LN 与 Pre-LN)的说法正确的是?

多选题 · hard

  • A.后置归一化在残差相加之后进行← 正确答案
  • B.前置归一化深层训练通常更稳定← 正确答案
  • C.两种方案在浅层效果完全相同
  • D.两种方案在深层完全等价

答案:AB。Post-LN 是原始 Transformer 做法,把 LayerNorm 放在 Add 之后;Pre-LN 先归一化再进子层,残差分支保持恒等,深层训练更稳定。C 和 D 的说法都过于绝对:浅层表现可能接近但不完全相同,深层更不可能完全等价。

Q10. 关于深层编码器的训练稳定性,下列说法正确的有哪些?

多选题 · extreme

  • A.残差连接帮助梯度直达底层← 正确答案
  • B.前置归一化比后置更深更稳← 正确答案
  • C.层归一化的位置会影响梯度流← 正确答案
  • D.深度加深必然导致梯度消失

答案:ABC。残差连接为梯度提供直达通道,Pre-LN 在子层前归一化可让残差分支保持恒等映射,从而让深层 Transformer 训练更稳定。归一化位置直接影响梯度流动路径。D 错在“必然”——残差和层归一化的设计目标正是克服深度加深带来的梯度消失。