Transformer:一切的起点
1. Transformer
Transformer 是 2017 年提出的模型架构,核心就是 Attention(注意力) 机制。
- Transformer 里的三个核心向量:Q, K, V
Transformer 处理序列数据时,会把每个输入词 / 特征转换成三个向量:
Q (Query,查询):我想找什么?
K (Key,键):我有什么?
V (Value,值):我能提供什么信息?
举个例子:
你(Q)在图书馆找一本 “讲 BEV 的书”
图书馆里的每本书都有一个标签(K),写着它的主题
每本书的内容就是(V)
2. Attention
如前所述,你根据标签和你需求的匹配度,从书里提取信息(V),这就是 Attention 的过程。
一句话说明白:
Attention = 用 Q 去 K 里找最匹配的,然后把对应的 V 加权拿过来。
核心公式:
Attention(Q,K,V)=softmax(QKTdk)V,其中Q=XWq,K=XWk,V=XWv\text{Attention}(Q, K, V) = \text{softmax}\left(\frac{QK^T}{\sqrt{d_k}}\right)V, \text{其中}Q=XW_q,K=XW_k,V=XW_vAttention(Q,K,V)=softmax(dkQKT)V,其中Q=XWq,K=XWk,V=XWv
其中XXX是特征向量,WWW是可学习的权重矩阵。所谓QKVQKVQKV可学习其实就是权重矩阵的更新。
2.1 Self-Attention
两者核心公式一模一样,区别就是QKV的来源。
Self-Attention 就是让序列里的每个元素,都和序列里所有元素做 Attention,目的是捕捉序列内部的依赖关系。
(Q,K,V)(Q, K, V)(Q,K,V) 都是从同一个输入序列线性变换来的,所以叫 “自” 注意力。
步骤拆解:
1.计算 Q 和所有 K 的相似度(点积),得到注意力分数;
2.除以 dk{\sqrt{d_k}}dk 防止数值过大;
3.用 Softmax 把分数变成概率分布(和为 1);
4.用这些概率对 V 加权求和,得到每个元素的输出特征。
举个句子例子:
句子:“它把球扔了,它滚走了。”
Self-Attention 会让第二个 “它”,重点关注前面的 “球”,理解 “它” 指的是球。
2.2 Cross-Attention
Cross-Attention 和 Self-Attention 很像,区别是:(Q,K,V)(Q, K, V)(Q,K,V) 来自不同的序列。QQQ 来自序列 AAA(比如 BEV Query),K,VK, VK,V 来自序列 BBB(比如相机图像特征)。
举个翻译的例子:
把中文翻译成英文:
英文翻译词(Q)会去看中文原句(K, V)里的每个词,决定自己该翻译成什么。
3. transformer 整体架构

上面就是transformer的架构图,将其划分为输入部分、编码器 (Encoder)、解码器 (Decoder)、输出部分四大模块,整体用于序列转换任务(机器翻译、文本生成、视觉特征建模等)。
全局结构总览:
输入序列 → 嵌入+位置编码 → 多层Encoder → 多层Decoder → 线性层+Softmax → 输出结果
补充统一标注(和文章、配图对齐):
NxNxNx:代表模块重复堆叠 NNN 层,原版论文与本文中(N=6);
Add & Norm:残差连接 (Add) + 层归一化 (Layer Norm),Transformer 标配组合;
Positional Encoding:位置编码;Embedding:嵌入层;
Feed Forward:前馈全连接网络(FFN)。
我们看图,左半部分为EncoderEncoderEncoder,右半部分为DecoderDecoderDecoder。我们分别来学习。
3.1 Encoder
Encoder整体外观:
一共 6 层完全相同的 Encoder Layer 堆叠
每层内部结构固定:多头自注意力 + 前馈网络
每层内部:子层 → 残差相加 → 层归一化
数据流向1:
原始输入序列 → Embedding(特征嵌入) → Positional Encoding(位置编码)两者逐元素相加,得到 Encoder 整体输入。
Embedding:离散输入转高维特征向量;
Pos Encoding:给 Attention 补充位置 / 顺序信息(Attention 本身无顺序感知)。
数据流向2:
输入特征进入 Multi-Head Self-Attention。
这里是自注意力:(Q=K=V)(Q=K=V)(Q=K=V) 来自同一个输入;
多头:拆分多组注意力头,并行学习多种依赖关系。(可以想像为鸣人仙人模式分身去收集自然能量,多头也是分出各个角度去挖掘数据特征信息,最后合并)。
注意力计算完成后,走残差连接。
公式:(xattn=输入原特征+Attention输出)(x_{attn} = \text{输入原特征} + \text{Attention输出})(xattn=输入原特征+Attention输出)
残差相加后,执行 Layer Normalization(层归一化).
数据流向3:
经过上一步层归一化的特征,送入Feed Forward 前馈网络:
FFN 是两层全连接 + 非线性激活,只对单个特征做变换,不做序列交互;
FFN 输出再次走残差连接(用上一步层归一化的输入做残差);
再次执行 Layer Normalization,得到单层 Encoder 最终输出。
数据流向4:
单层输出,直接作为下一层 Encoder 的输入。
论文一共重复堆叠 6 层,6 层结构完全一致。
下面给出PyTorch 极简伪代码(逐行对应流程):
代码结构严格对齐上面流程图、公式、论文图,加详细注释,可直接对应上述知识点。
import torch
import torch.nn as nn
import torch.nn.functional as F
# ===================== 1. 缩放点积注意力(最小基础单元)=====================
def scaled_dot_product_attention(Q, K, V, mask=None):
d_k = Q.size(-1)
# 1. Q @ K^T 计算相似度
attn_score = torch.matmul(Q, K.transpose(-2, -1))
# 2. 缩放 ÷√d_k
attn_score = attn_score / torch.sqrt(torch.tensor(d_k, dtype=torch.float32))
# 可选:加Mask(屏蔽无效区域)
if mask is not None:
attn_score = attn_score.masked_fill(mask == 0, -1e9)
# 3. Softmax 转概率权重
attn_weight = F.softmax(attn_score, dim=-1)
# 4. 权重 × V 加权求和
output = torch.matmul(attn_weight, V)
return output
# ===================== 2. 多头注意力 Multi-Head Attention =====================
class MultiHeadAttention(nn.Module):
def __init__(self, d_model, n_head):
super().__init__()
self.d_model = d_model
self.n_head = n_head
self.d_k = d_model // n_head
# Q/K/V 投影层 + 输出投影层
self.w_q = nn.Linear(d_model, d_model)
self.w_k = nn.Linear(d_model, d_model)
self.w_v = nn.Linear(d_model, d_model)
self.w_o = nn.Linear(d_model, d_model)
def forward(self, q, k, v, mask=None):
batch = q.size(0)
# 线性投影 + 分头: [B, N, d_model] -> [B, n_head, N, d_k]
q = self.w_q(q).view(batch, -1, self.n_head, self.d_k).transpose(1, 2)
k = self.w_k(k).view(batch, -1, self.n_head, self.d_k).transpose(1, 2)
v = self.w_v(v).view(batch, -1, self.n_head, self.d_k).transpose(1, 2)
# 分头计算注意力
attn_out = scaled_dot_product_attention(q, k, v, mask)
# 拼接多头: [B, n_head, N, d_k] -> [B, N, d_model]
attn_out = attn_out.transpose(1, 2).contiguous()
attn_out = attn_out.view(batch, -1, self.d_model)
# 最终输出投影
return self.w_o(attn_out)
# ===================== 3. 前馈网络 FFN =====================
class FeedForward(nn.Module):
def __init__(self, d_model, d_ff):
super().__init__()
# 标准FFN: d_model -> 4*d_model -> d_model
self.linear1 = nn.Linear(d_model, d_ff)
self.linear2 = nn.Linear(d_ff, d_model)
def forward(self, x):
return self.linear2(F.relu(self.linear1(x)))
# ===================== 4. 单层 Encoder(核心!对应论文单层结构)=====================
class EncoderLayer(nn.Module):
def __init__(self, d_model, n_head, d_ff, dropout=0.1):
super().__init__()
self.mha = MultiHeadAttention(d_model, n_head) # 多头自注意力
self.ffn = FeedForward(d_model, d_ff) # 前馈网络
# 两层层归一化 + Dropout
self.ln1 = nn.LayerNorm(d_model)
self.ln2 = nn.LayerNorm(d_model)
self.dropout = nn.Dropout(dropout)
def forward(self, x, mask=None):
# -------- 第一部分:多头自注意力 + 残差 + LN1 --------
# 自注意力:q=k=v=x
attn_out = self.mha(x, x, x, mask)
# 残差连接 x + attn_out
x1 = x + self.dropout(attn_out)
# 层归一化
x_ln1 = self.ln1(x1)
# -------- 第二部分:FFN + 残差 + LN2 --------
ffn_out = self.ffn(x_ln1)
# 残差连接 x_ln1 + ffn_out
x2 = x_ln1 + self.dropout(ffn_out)
# 层归一化,得到单层输出
out = self.ln2(x2)
return out
# ===================== 测试运行 =====================
if __name__ == "__main__":
# 超参(和论文保持一致)
d_model = 512 # 特征总维度
n_head = 8 # 8个头
d_ff = 2048 # FFN中间维度 = 4*d_model
batch_size = 2
seq_len = 10 # 序列长度
# 随机模拟输入特征 [batch, seq_len, d_model]
x = torch.randn(batch_size, seq_len, d_model)
# 实例化单层Encoder
encoder_layer = EncoderLayer(d_model, n_head, d_ff)
# 前向传播
output = encoder_layer(x)
print("输入形状:", x.shape)
print("输出形状:", output.shape)
3.2 Decoder

Decoder 同样堆叠 6 层,单层结构比 Encoder 多一层掩码注意力,共三个子层,主要用于序列逐一生成(机器翻译、文本续写)。
单层 Decoder 顺序:
输入 → 掩码多头自注意力 → Add & Norm → 编码-解码注意力 → Add & Norm → 前馈网络 → Add & Norm
子层 1:Masked Multi-Head Self-Attention 掩码多头自注意力
- 核心规则:在自注意力基础上增加 Mask 掩码(下三角矩阵);
- Mask 原理:将 “未来位置” 的注意力分数置为 −∞,经过 Softmax 后权重变为 0;
- 作用:生成任务中,禁止当前位置 “偷看” 还未生成的未来内容。
- 举例:生成第 3 个单词时,只能看第 1、2 个单词,看不到第 4、5 个。(可以这么理解,我们与GPT聊天时,他会逐字生成,我们在训练的时候肯定也是训练他逐字生成的能力,所以我们要让他生成“我爱你”三个字,那生成“你”的时候,肯定不能告诉他答案,所以要把这个“你”给他盖起来,看他能不能生成正确。)
子层2: Encoder-Decoder Attention 编码 - 解码交叉注意力
这是交叉注意力 (Cross-Attention),和自注意力本质区别:
- QQQ(查询):来自 Decoder 上一层输出;
- (K、V)(K、V)(K、V)(键、值):来自 Encoder 最终输出;
- 作用:让解码器在生成每一个元素时,主动从编码器的全局特征中检索对应信息。
- 场景举例:翻译时,英文单词(Decoder)去中文原句(Encoder)中匹配语义。(这里的query是decoder中的,相当于我们带着自己的问题(Q)去别的系统(KV)里找答案,比如我带着寻找自动驾驶书籍的Q去图书馆的KV里寻找最终的结果)。
子层 3:Feed Forward 前馈网络
和 Encoder 中的 FFN 完全一致,完成单特征非线性变换,后置 Add & Norm。
下面给出PyTorch 极简伪代码(逐行对应流程):
# -------------------------- 单层 Decoder Layer --------------------------
class DecoderLayer(nn.Module):
def __init__(self, d_model, n_head, d_ff, dropout=0.1):
super().__init__()
# 1. 掩码多头自注意力(Decoder 第一层)
self.masked_mha = MultiHeadAttention(d_model, n_head)
# 2. 交叉注意力:Encoder-Decoder Attention(Decoder 第二层)
self.cross_mha = MultiHeadAttention(d_model, n_head)
# 3. 前馈网络
self.ffn = FeedForward(d_model, d_ff)
# 三层归一化(对应三个子层)
self.ln1 = nn.LayerNorm(d_model)
self.ln2 = nn.LayerNorm(d_model)
self.ln3 = nn.LayerNorm(d_model)
self.dropout = nn.Dropout(dropout)
def forward(self, x, enc_out, tgt_mask=None, src_mask=None):
"""
输入说明:
x: Decoder 当前层输入 (目标序列特征)
enc_out: Encoder 最终输出特征 (交叉注意力的 K/V 来源)
tgt_mask: 目标序列掩码 → 屏蔽未来位置(核心)
src_mask: 源序列掩码 → 屏蔽Encoder侧无效padding位
"""
# ========== 第一部分:掩码多头自注意力 + 残差 + LN1 ==========
# 自注意力:q=k=v=x,加tgt_mask防偷看未来
attn1 = self.masked_mha(x, x, x, mask=tgt_mask)
x1 = x + self.dropout(attn1) # 残差 Add
x_ln1 = self.ln1(x1) # 归一化 Norm
# ========== 第二部分:交叉注意力 + 残差 + LN2 ==========
# 交叉注意力:Q=x_ln1(来自Decoder), K/V=enc_out(来自Encoder)
attn2 = self.cross_mha(x_ln1, enc_out, enc_out, mask=src_mask)
x2 = x_ln1 + self.dropout(attn2)
x_ln2 = self.ln2(x2)
# ========== 第三部分:FFN + 残差 + LN3 ==========
ffn_out = self.ffn(x_ln2)
x3 = x_ln2 + self.dropout(ffn_out)
out = self.ln3(x3)
return out
3.3 输出部分

Decoder 6 层堆叠完成后,特征送入输出模块,分为两层:
Linear 线性层:将 Decoder 输出的特征向量,映射到词汇表 / 任务类别维度;
Softmax 层:把线性层的输出转为概率分布,概率最大的索引即为模型预测结果。

1233

被折叠的 条评论
为什么被折叠?



