news 2026/4/23 18:34:17

第二章Transformer架构解析(下)

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
第二章Transformer架构解析(下)

第二章 Transformer架构解析(下)

在进入最关键的Attention之前,我们回顾一下上一个章节的内容:

学到的概念核心作用
Tokenization文字 → Token
EmbeddingToken → 向量
Positional Encoding给向量添加位置信息
LayerNorm + Softmax层归一化缩放 + 数字变概率分布
神经网络层(FFN)非线性变换,理解消化信息

2.4 Attention注意力机制

2.4.1 线性变换

在理解 Attention 之前,我们需要先复习一下关于线性变换的知识。这部分看似数学,其实非常直观,也是整个 Attention 机制的 “起点”。

你可以把线性变换理解成一句话:

把一组向量,通过一个可学习的矩阵,投影到一个新的空间里,让它更适合后续计算。

2.4.1.1 矩阵的乘法

矩阵的乘法规则:

[A, B] × [B, C] = [A, C]

两个矩阵相乘,第一个矩阵的列必须等于第二个矩阵的行才能相乘,相乘之后的矩阵大小为第一个矩阵的行X第二个矩阵的列,示例如下:

2.4.1.2 矩阵的线性变换

矩阵的变换满足两个条件,可以称其为线性变换:

对任意向量 x、y 和任意数 k:

  • 加完再变 = 变完再加

​ T(x+y)=T(x)+T(y)

  • 乘完再变 = 变完再乘

    T(kx)=kT(x)

满足这两条,就是线性变换。

[A,B] × [B,1] = [A,1]

跟 Attention 有啥关系?

在 Transformer 里:

Q = 输入 @ Wq K = 输入 @ Wk V = 输入 @ Wv

这些全都是线性变换:

  • 向量被矩阵拉伸、旋转、投影
  • 但不会弯曲、不会平移
  • 所以最后算出来的 Q、K、V 还保持着原来的线性结构,方便后续做点积算相似度

2.4.2 Attention的意义

我们先来看一下Attention的结构:

2.4.2.1 Attention的内部结构
input X ↓ 生成 Q, K, V(Linear层,通过 Wq, Wk, Wv 三个权重矩阵) ↓ MatMul(Q @ K^T,计算点积) ↓ Scale(除以 √d_key,缩放点积) ↓ Mask(掩码,防止看到下一个Token) ↓ Softmax(转换为概率分布) ↓ MatMul(与 V 相乘,加权求和) ↓ Concatenate(多头合并) ↓ Wo(Linear层,输出投影) ↓ output

完整公式
Attention⁡(Q,K,V)=softmax⁡(QK⊤dk)V \operatorname{Attention}(Q, K, V) = \operatorname{softmax}\left( \frac{Q K^\top}{\sqrt{d_k}} \right) VAttention(Q,K,V)=softmax(dkQK)V

在第二章开头,我们已经解释了Attention对于传统RNN和CNN的优势
我们先熟悉一下整体流程,然后再来讲解每一步的操作原理。

2.4.2.2 Q、K、V是什么?

在实际训练中,往往会同时处理多个多个句子

1.股海沉浮需理性分析策略静待良机稳健获利

2.编程架构严谨逻辑高效运维安全稳定性能卓越

3.每日坚持读书学习积累知识拓宽眼界提升自我价值

4.乘风破浪勇往直前努力奋斗梦想实现未来光明可期

输入矩阵:

X: [batch_size, context_length, d_model]
  • batch_size = 4:同时处理 4 个句子(批次大小)
  • context_length= 16:每个句子有 16 个 token(上下文长度)
  • d_model = 512:每个 token 用 512 维向量表示(模型维度)

上面示例的输入形状为就是**[4,16,512]**

X=输入的Token向量,Q、K、V都是从同一个输入X乘以对应权重矩阵得到:

Q = X @ Wq K = X @ Wk V = X @ Wv

三个权重矩阵(Wq、Wk、Wv)是可学习的参数,在训练过程中不断调整。

我们以生成Q为例:

X: [4, 16, 512] (batch_size, context_length, d_model) Wq: [512, 512] (d_model, d_model) Q: [4, 16, 512] (batch_size, context_length, d_model)

前面我们已经介绍了矩阵乘法的规则:[…, A, B] @ [B, C] = […, A, C]

所以:[4, 16, 512] @ [512, 512] = [4, 16, 512]

Q、K、V 的形状和输入 X 完全相同

为什么需要分成三份?

既然形状都一样,为什么还需要三个不同的矩阵呢?

因为Q、K、V 承担不同的角色

  • Q(Query,查询):代表"我在找什么信息"
  • K(Key,键):代表"我有什么信息可以被找到"
  • V(Value,值):代表"如果被找到,我提供什么内容"

在通过不同的权重矩阵Wq、Wk、Wv,模型可以学会:

  • 把同一个词转换成不同的"角色"
  • 在不同的"语义空间"中进行匹配

做一个比喻:

角色类比作用
Query (Q)读者的搜索词“我想找关于深度学习的书”
Key (K)每本书的索引标签“机器学习, Python入门,深度学习”
Value (V)书的实际内容深度学习这本书的内容

什么是Q@K^T

我们要让 Q 的每一行和 K 的每一行做点积去计算每个Token的相似度,根据矩阵乘法规则,则需要将K转置

Q[4,16,,128] @ K^T[4,128,16] = [4, 16, 16]

这里的 d_model = 128 是因为在 Multi-Head Attention 中,d_model 会被分成多个头。每个头的维度是 d_model = d_model / num_heads = 512 / 4 = 128。这个我们后续会再提。

结果矩阵的形状是[4, 16, 16]:

  • 4 个句子
  • 每个句子有一个 16×16 的"注意力矩阵"
  • 位置 (i, j) 表示:第 i 个 token 对第 j 个 token 的关注程度
我 爱 学 习 我 [ ] 爱 [ ] 学 [ ] 习 [ ]

每个位置的值 = 对应 Q 行向量和 K 列向量的点积。


下一步Scale,缩放操作

Q @ K^T 的结果需要缩放

Attention Scores = (Q @ K^T) / √d_key

缩放的作用:当d_model很大时,点积的结果也会很大

点积 = Σ(q_i × k_i) # 128 个数相乘再相加

数值过大的后果:导致softmax后概率变得极端

Softmax([5, 3, 2]) ≈ [0.844, 0.114, 0.042] # 极端分布 假设d_model=64,缩放因子=√64=0.125 Softmax([0.625, 0.375, 0.25]) ≈ [0.405, 0.316, 0.279] # 平滑分布

一句话:除以 √d_model 就是把结果数值压小,让 Softmax 不那么极端,梯度更稳定,模型更容易训练。


Mask:掩码

Mask 前的注意力分数矩阵:

0.90.30.10.05
0.40.80.20.1
0.20.30.70.25
0.150.20.30.85

Mask 后的注意力分数矩阵(下三角掩码):

0.9-inf-inf-inf
0.40.8-inf-inf
0.20.30.7-inf
0.150.20.30.85

在Transformer的自回归生成中,预测下一个Token时,不能提前看到下一个Token是什么,比如在预测"我爱学___",模型不能看到下一个Token。但是在Q @ K^T 时,会计算所有位置的相似度,因此我们需要在矩阵中遮住下一个Token。

解决方法:把右上角(未来的位置)设为负无穷(-inf),这样在softmax后,其概率会变为0,模型就不知道未来的信息了。

Softmax([0.9, -inf,-inf,-inf]) = [1.0, 0.0, 0.0, 0.0]

下一步,在Mask后,对输出应用 Softmax,得到的结果就是注意力权重矩阵(每个位置应该分配多少注意力给其他位置)。


根据注意力公式,接下来需要将得到的注意力权重矩阵乘以V

Output = Attention_Weights @ V

维度变化:

Attention_Weights: [4, 16, 16] (batch, context_len, context_len) V: [4, 16, 128] (batch, context_len, d_model) Output: [4, 16, 128] (batch, context_len, d_model)

得到的output是什么?

output[i] = Σ(attention_weight[i,j] × V[j])

每个位置的输出 = 所有位置的 V 的加权平均,权重由注意力分数决定。

output=根据注意力加权组合后的向量。

得到的新向量就包含了句子的语义信息,在Attention之前,每个Token只包含自己的语义信息和位置信息,而在Attention之后,每个Token还包含了该Token与其余Token的语义关系


代码实现:

importtorchimporttorch.nnasnnimporttorch.nn.functionalasFclassScaledDotProductAttention(nn.Module):"""缩放点积注意力 + Mask 支持"""def__init__(self,dropout=0.1):super().__init__()self.dropout=nn.Dropout(dropout)defforward(self,Q,K,V,mask=None):""" Q: [batch_size, n_heads, seq_len, d_k] K: [batch_size, n_heads, seq_len, d_k] V: [batch_size, n_heads, seq_len, d_v] mask: [batch_size, 1, seq_len, seq_len] # 掩码矩阵 """# 1. 计算 Q · K^Td_k=Q.size(-1)attn_scores=torch.matmul(Q,K.transpose(-2,-1))# [B, H, L, L]# 2. 缩放 1/√d_kattn_scores=attn_scores/torch.sqrt(torch.tensor(d_k,dtype=torch.float32))# 3. Mask(填充-inf 屏蔽未来token)ifmaskisnotNone:attn_scores=attn_scores.masked_fill(mask==0,float('- inf'))# 4. Softmaxattn_weights=F.softmax(attn_scores,dim=-1)# [B, H, L, L]# 5. 乘以 Voutput=torch.matmul(attn_weights,V)# [B, H, L, d_v]returnoutput,attn_weights

小结:

Q、K、V 是 Attention 关键。Q 代表"查询",K 代表"键",V 代表"值"。通过 Q @ K^T 得到注意力权重,用注意力权重对 V 加权求和,得到融合了上下文信息的新矩阵。这就是 Attention 让模型"理解"语言的方式。

完整流程:

X → [Wq, Wk, Wv] → Q, K, V ↓ Q @ K^T (相似度) ↓ 除以 √d_key (缩放) ↓ Mask (遮挡未来) ↓ Softmax (归一化) ↓ @ V (加权求和) ↓ Output

2.4.3 多头注意力(Multi-Head Attention)

2.4.3.1 为什么需要多头注意力?

单头注意力只能从一个 “视角” 捕捉 Token 间的语义关联,而多头注意力让模型可以同时从多个不同的语义子空间(视角)学习 Token 间的关系,能更全面、更精细地捕捉文本中的复杂语义信息。

举个直观的例子:

对于句子 “苹果发布了新款手机,它的价格很亲民”,

  • 头 1 可能关注 “它” 和 “新款手机” 的指代关系;
  • 头 2 可能关注 “苹果” 和 “发布” 的动作关联;
  • 头 3 可能关注 “价格” 和 “亲民” 的属性关联。

多个头的注意力互补,最终融合后的结果能让模型对语义的理解更完整。

2.4.3.2 多头注意力的核心逻辑

多头注意力的本质是:将 Q、K、V 拆分成多个子空间,在每个子空间独立计算注意力,最后将所有头的结果拼接并投影,得到最终输出。

核心步骤:

  1. 维度拆分:将原始的 Q、K、V(维度为d_model)拆分为num_heads个独立的子 Q、子 K、子 V,每个子空间维度为d_k = d_model / num_heads(需保证d_model能被num_heads整除);
  2. 独立计算:对每个子 Q、子 K、子 V,单独执行 “缩放点积注意力” 计算;
  3. 结果拼接:将所有头的注意力输出拼接,恢复到d_model维度;
  4. 线性投影:通过一个可学习的权重矩阵W_o对拼接结果做线性变换,得到最终输出。
2.4.3.3 维度变化详解

以经典的d_model=512num_heads=8为例:

  • 原始 Q/K/V:[batch_size, seq_len, 512]
  • 拆分后每个头的 Q/K/V:[batch_size, seq_len, 64](512/8=64)
  • 为了并行计算,通常会调整维度顺序为:[batch_size, num_heads, seq_len, d_k](即[4,8,16,64],对应前文batch_size=4seq_len=16);
  • 每个头独立计算注意力后,输出为:[batch_size, 8, 16, 64]
  • 拼接后:[batch_size, 16, 8×64=512]
  • 最后通过W_o(维度[512,512])投影,输出仍为[batch_size, 16, 512]
2.4.3.4 多头的优势
  • 多视角捕捉关联:不同头聚焦不同类型的语义关系(指代、动作、属性等),比单头更全面;
  • 提升表达能力:拆分到子空间后,模型能学习更细粒度的语义模式,避免单一空间的信息混淆;
  • 保持维度兼容:拼接 + 投影后输出维度与输入一致,可无缝接入后续的 FFN 层,符合 Transformer 的整体架构设计。
2.4.3.5 多头的优势
维度单头注意力多头注意力
语义视角单一视角多视角并行学习
表达能力有限,易丢失细粒度信息更强,能捕捉复杂语义关联
计算复杂度O(dmodel⋅L2)O(dmodel⋅L2)(拆分后每个头计算量降低,整体与单头相当)
训练稳定性梯度易极端多子空间分散梯度,更稳定

一句话总结:

把 QKV 分成 h 个头,分头算注意力,再拼回去投影,让模型看得更细、更全、更准。


2.4.4 残差链接(Residual Connection)

2.4.4.1 为什么需要残差链接?

Transformer 的 Encoder/Decoder 层堆叠了很多层(比如 BERT-base 有 12 层,GPT-3 有 96 层)。
层数越深,模型越容易出现两个致命问题:

  1. 梯度消失/爆炸:反向传播时,梯度在多层矩阵乘法中不断衰减或放大,导致底层无法有效更新。
  2. 模型退化(Degradation):层数过多时,深层网络可能出现“越学越差”的情况,甚至不如浅层网络效果好。
    残差链接就是为了解决这两个问题而设计的。

2.4.4.2 残差链接的核心公式

假设某一层的输入为 x,该层的变换函数为 F(x)(例如多头注意力或前馈网络),则残差链接的输出为:

$$

\text{Output} = x + F(x)

$$
在 Transformer 中,它和层归一化(Layer Normalization)一起组成标准范式:

LayerNorm(x+F(x)) \text{LayerNorm}(x + F(x))LayerNorm(x+F(x))

2.4.4.3 Transformer 中的具体应用位置

残差链接贯穿整个 Transformer 架构,每一个子层都遵循这一结构:

  1. Encoder 层

    • 多头自注意力层:LayerNorm(x + Attention(x))
    • 前馈网络层:LayerNorm(x + FeedForward(x))
  2. Decoder 层

    • 掩码多头自注意力层:LayerNorm(x + MaskedAttention(x))
    • Encoder-Decoder 交叉注意力层:LayerNorm(x + CrossAttention(x, EncoderOutput))
    • 前馈网络层:LayerNorm(x + FeedForward(x))

2.4.4.4 残差链接的作用详解
  1. 缓解梯度消失,让深层网络可训练
    残差链接提供了一条“梯度高速通道”。在反向传播时,梯度可以直接通过x这条路径无损地传回底层,避免了在深层网络中逐层衰减,让模型可以稳定训练几十甚至上百层。

  2. 解决模型退化问题
    残差链接允许网络在学习复杂特征的同时,保留原始输入信息。如果某一层的变换F(x)效果不佳,网络可以选择让F(x)趋近于 0,直接通过x传递信息,保证至少不会比浅层网络差。

  3. 信息传递更完整
    直接将原始输入x加到变换后的结果上,相当于给了模型一个“参考系”,避免了信息在多层变换中丢失,让后续层可以同时利用原始信息和新学到的特征。


2.4.4.5 残差链接的 PyTorch 代码实现

以多头注意力层为例,残差链接的实现非常简洁:

importtorchimporttorch.nnasnn# 以之前的 MultiHeadAttention 类为基础classTransformerEncoderLayer(nn.Module):def__init__(self,d_model,num_heads,d_ff,dropout=0.1):super().__init__()self.attn=MultiHeadAttention(d_model,num_heads,dropout)self.ffn=nn.Sequential(nn.Linear(d_model,d_ff),nn.ReLU(),nn.Linear(d_ff,d_model),nn.Dropout(dropout))self.norm1=nn.LayerNorm(d_model)self.norm2=nn.LayerNorm(d_model)self.dropout=nn.Dropout(dropout)#随机丢弃,防止过拟合defforward(self,x,mask=None):# 1. 多头注意力 + 残差链接 + 层归一化residual=x attn_out,_=self.attn(x,x,x,mask)x=residual+self.dropout(attn_out)x=self.norm1(x)# 2. 前馈网络 + 残差链接 + 层归一化residual=x ffn_out=self.ffn(x)x=residual+self.dropout(ffn_out)x=self.norm2(x)returnx
2.4.4.6 Dropout

在代码中我们可以发现,在LayerNorm之后接了一个Dropout。

在神经网络有一个常见问题:过拟合

过拟合是指模型在训练数据上表现很好,但在新数据上表现很差。就像一个学生:

  • 把所有考试题都背下来了(训练数据)
  • 但遇到新题就不会做(测试数据)

模型"记住"了训练数据的细节,而不是学到了通用的规律。

而Dropout的解决方法:在训练时随机丢弃一些神经元

核心作用:

  1. 防止过拟合,提升泛化能力
    每次训练都随机关闭不同的神经元,迫使模型不依赖任何单个神经元/特征,学习到更鲁棒、更通用的模式,而不是死记训练数据。
  2. 相当于训练了多个“子模型”的集成
    每次随机失活的网络结构都不一样,相当于同时训练了很多不同的小网络,推理时用的是所有子模型的平均效果,天然带有“模型集成”的优势。
  3. 降低神经元间的协同依赖
    防止某些神经元“过度合作”,避免它们为了拟合训练数据互相形成依赖关系,让每个神经元都能学到独立有用的特征。

训练 vs 推理的 Dropout 差异

阶段Dropout 状态行为
训练启用随机失活神经元,按比例缩放剩余输出
推理关闭所有神经元都正常工作,输出无缩放

一句话总结:

残差链接打通梯度通道、避免网络退化,Dropout 随机失活防过拟合,两者配合让深层 Transformer 训练稳定又能学到通用特征。


2.5 向前传播

2.5.1 GTP-1 与 GTP-2架构对比

这张图对比了 GPT-2 和 GPT-1 的架构。它们都是Decoder-Only架构,主要区别是 LayerNorm 的位置和新增了Dropout:

  1. 训练稳定性大幅提升(最关键的优势)
  • Post-Norm 的痛点:残差相加后再做归一化,梯度在反向传播时必须穿过归一化层。在深层网络中,这会导致梯度被不断缩放,容易出现梯度消失 / 爆炸,训练时需要配合复杂的学习率预热(Warmup)、梯度裁剪等技巧,否则很难收敛。
  • Pre-Norm 的优势:归一化仅作用于进入子层的输入,残差连接的 “主干道” 完全不受归一化影响,梯度可以 “无阻碍” 地从深层直接传回浅层。即使是上百层的大模型,也能稳定训练,对学习率的鲁棒性更强,很多时候甚至不需要复杂的预热策略。
  1. 深层模型更容易收敛
  • 随着模型层数增加,Post-Norm 的梯度问题会被放大,训练难度呈指数级上升。
  • Pre-Norm 通过约束子层的输入分布(均值为 0、方差为 1),让注意力、前馈网络的计算更稳定,即使堆叠几十上百层,也能保证梯度正常流动,这也是 GPT-3、LLaMA 等现代大模型都采用 Pre-Norm 的核心原因。

3.对超参数调优更友好

  • Post-Norm 对学习率、优化器的设置非常敏感,需要大量调参才能找到合适的配置。
  • Pre-Norm 的训练过程更 “皮实”,降低了对超参数的依赖,减少了训练过程中 “调参炼丹” 的成本,更适合大规模模型的工程实现。

2.5.2 完整的向前传播

已GTP-2的架构为例:

input:"小猫爱吃" ↓ Step 1: Tokenization(分词) ↓ Step 2: Word Embeddings(词嵌入) ↓ Step 3: Positional Encoding(位置编码) ↓ Step 4-6: N × Transformer Block(LayerNorm → Attention → Residual → LayerNorm → FFN → Residual) (推理过程) ↓ Step 7: Final Layer Norm ↓ Step 8: Linear(映射词表) → Softmax → Output Probability ↓ output:"鱼"(概率最高的词)

本章总结:

Transformer 的前向传播是一个优雅的流水线:输入的文字被转换成向量,经过多层处理(每层都包含 Attention 理解上下文、FFN 提取特征),最后映射到词表得到概率分布。整个过程中,维度在 Block 中保持不变(都是 d_model),只在最后映射时从 d_model 变成 vocab_size。


:“小猫爱吃”

Step 1: Tokenization(分词)

Step 2: Word Embeddings(词嵌入)

Step 3: Positional Encoding(位置编码)

Step 4-6: N × Transformer Block(LayerNorm → Attention → Residual → LayerNorm → FFN → Residual) (推理过程)

Step 7: Final Layer Norm

Step 8: Linear(映射词表) → Softmax → Output Probability

output:“鱼”(概率最高的词)

------ **本章总结:** > **Transformer 的前向传播是一个优雅的流水线:输入的文字被转换成向量,经过多层处理(每层都包含 Attention 理解上下文、FFN 提取特征),最后映射到词表得到概率分布。整个过程中,维度在 Block 中保持不变(都是 d_model),只在最后映射时从 d_model 变成 vocab_size。** ------ 下一章我们将用代码完整实现Transformer的传播流程。
版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/4/23 18:27:20

软件使用教程

编译ESP32 的 IDF https://dl.espressif.cn/dl/esp-idf/ 参考教程:https://blog.csdn.net/rabbit_free/article/details/140570769 使用idf.py build 命令编译; 使用idf.py -p com3 flash 命令下载。 pdf如何默认 用wps打开? Wi…

作者头像 李华
网站建设 2026/4/23 18:22:17

国产175℃随钻伽马探测器的产业生态与趋势展望

近年来,国内随钻测井装备的自主化进程明显加速,其中耐温175℃探测器的成熟供应是产业链升级的关键一环。青岛智腾ZT系列伽马探测器的推出,不仅丰富了高温LWD核心部件的选择,也折射出国产井下仪器产业生态的若干趋势。 核心元器件自…

作者头像 李华
网站建设 2026/4/23 18:17:09

矢量数据的合并(拼接)的两种方式

本期我们主要介绍矢量(此处指的均为shp格式的矢量数据,点线面均可)数据的合并方式,第一种是使用ArcMap软件进行合并,第二种是使用91卫图软件进行拼合,操作相对简单,仅供具体操作参考&#xff0c…

作者头像 李华
网站建设 2026/4/23 18:16:25

2026届最火的五大AI辅助论文工具横评

Ai论文网站排名(开题报告、文献综述、降aigc率、降重综合对比) TOP1. 千笔AI TOP2. aipasspaper TOP3. 清北论文 TOP4. 豆包 TOP5. kimi TOP6. deepseek 深度学习与自然语言处理技术所构成的AI写作工具,能依据用户输入,于数…

作者头像 李华