Transformer 架构——从原理到实践全流程解析

玄同 765
大语言模型 (LLM) 开发工程师 | 中国传媒大学 · 数字媒体技术(智能交互与游戏设计)
ZEEKLOG · 个人主页 | GitHub · Follow
关于作者
- 深耕领域:大语言模型开发 / RAG 知识库 / AI Agent 落地 / 模型微调
- 技术栈:Python | RAG (LangChain / Dify + Milvus) | FastAPI + Docker
- 工程能力:专注模型工程化部署、知识库构建与优化,擅长全流程解决方案
「让 AI 交互更智能,让技术落地更高效」
欢迎技术探讨与项目合作,解锁大模型与智能交互的无限可能!
Transformer 架构——从原理到实践全流程解析
引言
2017年,Google 团队在论文《Attention Is All You Need》中提出了 Transformer 架构,彻底改变了自然语言处理领域。与传统的 RNN 和 CNN 不同,Transformer 完全基于注意力机制,摒弃了循环和卷积结构,实现了更高的并行化能力和更长的序列建模能力。
Transformer 的出现标志着 NLP 进入了一个新时代。它不仅是 BERT、GPT 等大型语言模型的基础架构,也成为计算机视觉、语音识别等领域的重要技术。理解 Transformer 架构,是深入掌握现代深度学习技术的关键一步。
本文将从 Self-Attention 机制入手,深入剖析 Transformer 的核心原理,详细讲解 Multi-Head Attention、Position Encoding 等关键组件,并结合实际代码实现,帮助读者全面理解这一革命性架构。
核心原理
1. Self-Attention 机制
Self-Attention(自注意力)是 Transformer 的核心创新。它允许模型在处理序列时,动态地关注序列中的不同位置,从而捕获长距离依赖关系。
1.1 基本概念
Self-Attention 的核心思想是将输入序列中的每个位置与其他所有位置进行比较,计算它们之间的相关性,然后基于这些相关性聚合信息。
具体来说,对于输入序列 X = { x 1 , x 2 , . . . , x n } X = \{x_1, x_2, ..., x_n\} X={x1,x2,...,xn},Self-Attention 计算三个向量:
- Query (Q): 查询向量,表示当前关注点
- Key (K): 键向量,表示被查询的内容
- Value (V): 值向量,表示实际内容
这三个向量通过线性变换得到:
Q = X W Q , K = X W K , V = X W V Q = XW^Q, \quad K = XW^K, \quad V = XW^V Q=XWQ,K=XWK,V=XWV
其中 W Q , W K , W V W^Q, W^K, W^V WQ,WK,WV 是可学习的参数矩阵。
1.2 注意力计算
Self-Attention 的计算过程如下:
- 计算注意力分数: 通过 Query 和 Key 的点积计算相似度
Attention Scores = Q K T \text{Attention Scores} = QK^T Attention Scores=QKT - 缩放: 除以 d k \sqrt{d_k} dk 防止梯度消失
Scaled Scores = Q K T d k \text{Scaled Scores} = \frac{QK^T}{\sqrt{d_k}} Scaled Scores=dkQKT - Softmax 归一化: 得到注意力权重
Attention Weights = softmax ( Q K T d k ) \text{Attention Weights} = \text{softmax}\left(\frac{QK^T}{\sqrt{d_k}}\right) Attention Weights=softmax(dkQKT) - 加权求和: 用注意力权重对 Value 加权
Output = softmax ( Q K T d k ) V \text{Output} = \text{softmax}\left(\frac{QK^T}{\sqrt{d_k}}\right)V Output=softmax(dkQKT)V
1.3 为什么需要缩放?
缩放因子 1 d k \frac{1}{\sqrt{d_k}} dk1 的作用是防止点积过大导致 Softmax 函数进入饱和区。当 d k d_k dk 较大时,点积的方差也会增大,假设 Q 和 K 的元素独立同分布,均值为 0,方差为 1,则:
Var ( q ⋅ k ) = d k \text{Var}(q \cdot k) = d_k Var(q⋅k)=dk
因此,除以 d k \sqrt{d_k} dk 可以将方差归一化为 1,保持梯度稳定。
2. Multi-Head Attention
Multi-Head Attention(多头注意力)通过并行运行多个 Self-Attention,使模型能够同时关注不同位置的不同表示子空间。
2.1 工作原理
Multi-Head Attention 的计算过程:
- 将 Q、K、V 分别投影到 h 个不同的子空间
- 对每个子空间独立计算 Self-Attention
- 将所有头的输出拼接
- 通过线性变换得到最终输出
数学表示:
MultiHead ( Q , K , V ) = Concat ( head 1 , . . . , head h ) W O \text{MultiHead}(Q, K, V) = \text{Concat}(\text{head}_1, ..., \text{head}_h)W^O MultiHead(Q,K,V)=Concat(head1,...,headh)WO
其中:
head i = Attention ( Q W i Q , K W i K , V W i V ) \text{head}_i = \text{Attention}(QW_i^Q, KW_i^K, VW_i^V) headi=Attention(QWiQ,KWiK,VWiV)
2.2 为什么需要多头?
单头注意力只能学习一种注意力模式,而多头注意力可以:
- 捕获不同类型的依赖关系
- 关注不同的表示子空间
- 增强模型的表达能力
例如,在处理句子时,一个头可能关注语法结构,另一个头关注语义关系。
3. Position Encoding
由于 Self-Attention 不包含位置信息,Transformer 需要显式地注入位置信息。原始论文使用正弦和余弦函数生成位置编码:
P E ( p o s , 2 i ) = sin ( p o s 10000 2 i / d m o d e l ) PE_{(pos, 2i)} = \sin\left(\frac{pos}{10000^{2i/d_{model}}}\right) PE(pos,2i)=sin(100002i/dmodelpos)
P E ( p o s , 2 i + 1 ) = cos ( p o s 10000 2 i / d m o d e l ) PE_{(pos, 2i+1)} = \cos\left(\frac{pos}{10000^{2i/d_{model}}}\right) PE(pos,2i+1)=cos(100002i/dmodelpos)
其中 p o s pos pos 是位置, i i i 是维度索引。
3.1 为什么选择正弦/余弦?
这种编码方式有几个优点:
- 位置唯一性: 每个位置都有唯一的编码
- 相对位置: 模型可以学习相对位置关系
- 外推能力: 可以处理比训练时更长的序列
3.2 其他位置编码方案
| 方案 | 优点 | 缺点 | 应用 |
|---|---|---|---|
| Sinusoidal | 无参数、可外推 | 固定模式 | 原始 Transformer |
| Learned | 灵活、可学习 | 无法外推 | BERT、GPT |
| Rotary (RoPE) | 相对位置、旋转不变 | 实现复杂 | LLaMA、Qwen |
| ALiBi | 简单、外推能力强 | 缺乏绝对位置 | BLOOM |
4. Transformer 整体架构
Transformer 采用 Encoder-Decoder 架构,包含以下组件:
4.1 Encoder
Encoder 由 N 个相同的层堆叠而成,每层包含:
- Multi-Head Self-Attention
- Position-wise Feed-Forward Network
- 残差连接和 Layer Normalization
4.2 Decoder
Decoder 也由 N 个相同的层堆叠而成,每层包含:
- Masked Multi-Head Self-Attention (带掩码,防止看到未来信息)
- Encoder-Decoder Attention (关注 Encoder 输出)
- Position-wise Feed-Forward Network
- 残差连接和 Layer Normalization
4.3 架构图
Decoder Layer
Encoder Layer
Input Embedding + Position Encoding
Multi-Head Self-Attention
Feed-Forward Network
Add and Norm
Add and Norm
Output Embedding + Position Encoding
Masked Multi-Head Attention
Encoder-Decoder Attention
Feed-Forward Network
Add and Norm
Add and Norm
Add and Norm
Linear + Softmax
Output Probabilities
5. Feed-Forward Network
每个 Encoder/Decoder 层都包含一个前馈网络(FFN),由两个线性变换和一个激活函数组成:
FFN ( x ) = max ( 0 , x W 1 + b 1 ) W 2 + b 2 \text{FFN}(x) = \max(0, xW_1 + b_1)W_2 + b_2 FFN(x)=max(0,xW1+b1)W2+b2
通常,隐藏层的维度 d f f d_{ff} dff 是输入维度 d m o d e l d_{model} dmodel 的 4 倍。例如, d m o d e l = 512 d_{model} = 512 dmodel=512, d f f = 2048 d_{ff} = 2048 dff=2048。
技术实现
1. Self-Attention 实现
import torch import torch.nn as nn import torch.nn.functional as F import math classSelfAttention(nn.Module):""" Self-Attention 实现 Args: embed_dim: 嵌入维度 num_heads: 注意力头数 """def__init__(self, embed_dim:int, num_heads:int):super().__init__() self.embed_dim = embed_dim self.num_heads = num_heads self.head_dim = embed_dim // num_heads # 确保 embed_dim 可以被 num_heads 整除assert self.head_dim * num_heads == embed_dim,"embed_dim 必须能被 num_heads 整除"# Q、K、V 的线性变换 self.q_proj = nn.Linear(embed_dim, embed_dim) self.k_proj = nn.Linear(embed_dim, embed_dim) self.v_proj = nn.Linear(embed_dim, embed_dim)# 输出线性变换 self.out_proj = nn.Linear(embed_dim, embed_dim)# 缩放因子 self.scale = math.sqrt(self.head_dim)defforward( self, x: torch.Tensor, mask: torch.Tensor =None)-> torch.Tensor:""" 前向传播 Args: x: 输入张量 [batch_size, seq_len, embed_dim] mask: 注意力掩码 [batch_size, seq_len, seq_len] Returns: 输出张量 [batch_size, seq_len, embed_dim] """ batch_size, seq_len, _ = x.shape # 线性变换得到 Q、K、V Q = self.q_proj(x)# [batch_size, seq_len, embed_dim] K = self.k_proj(x) V = self.v_proj(x)# 重塑为多头形式 Q = Q.view(batch_size, seq_len, self.num_heads, self.head_dim).transpose(1,2) K = K.view(batch_size, seq_len, self.num_heads, self.head_dim).transpose(1,2) V = V.view(batch_size, seq_len, self.num_heads, self.head_dim).transpose(1,2)# 现在形状为 [batch_size, num_heads, seq_len, head_dim]# 计算注意力分数 attn_scores = torch.matmul(Q, K.transpose(-2,-1))/ self.scale # [batch_size, num_heads, seq_len, seq_len]# 应用掩码(如果有)if mask isnotNone: attn_scores = attn_scores.masked_fill(mask ==0,float('-inf'))# Softmax 归一化 attn_weights = F.softmax(attn_scores, dim=-1)# 加权求和 output = torch.matmul(attn_weights, V)# [batch_size, num_heads, seq_len, head_dim]# 拼接多头 output = output.transpose(1,2).contiguous().view(batch_size, seq_len, self.embed_dim)# 输出线性变换 output = self.out_proj(output)return output 2. Position Encoding 实现
classPositionalEncoding(nn.Module):""" 正弦位置编码 Args: embed_dim: 嵌入维度 max_len: 最大序列长度 dropout: Dropout 概率 """def__init__(self, embed_dim:int, max_len:int=5000, dropout:float=0.1):super().__init__() self.dropout = nn.Dropout(p=dropout)# 计算位置编码 position = torch.arange(max_len).unsqueeze(1).float() div_term = torch.exp( torch.arange(0, embed_dim,2).float()*(-math.log(10000.0)/ embed_dim)) pe = torch.zeros(max_len, embed_dim) pe[:,0::2]= torch.sin(position * div_term) pe[:,1::2]= torch.cos(position * div_term)# 注册为缓冲区(不参与训练) self.register_buffer('pe', pe)defforward(self, x: torch.Tensor)-> torch.Tensor:""" 前向传播 Args: x: 输入张量 [batch_size, seq_len, embed_dim] Returns: 添加位置编码后的张量 """ x = x + self.pe[:x.size(1)]return self.dropout(x)3. Transformer Encoder Layer 实现
classTransformerEncoderLayer(nn.Module):""" Transformer Encoder 层 Args: embed_dim: 嵌入维度 num_heads: 注意力头数 ff_dim: 前馈网络隐藏层维度 dropout: Dropout 概率 """def__init__( self, embed_dim:int, num_heads:int, ff_dim:int=2048, dropout:float=0.1):super().__init__()# Self-Attention self.self_attn = SelfAttention(embed_dim, num_heads)# Feed-Forward Network self.ffn = nn.Sequential( nn.Linear(embed_dim, ff_dim), nn.ReLU(), nn.Dropout(dropout), nn.Linear(ff_dim, embed_dim))# Layer Normalization self.norm1 = nn.LayerNorm(embed_dim) self.norm2 = nn.LayerNorm(embed_dim)# Dropout self.dropout = nn.Dropout(dropout)defforward(self, x: torch.Tensor, mask: torch.Tensor =None)-> torch.Tensor:""" 前向传播 Args: x: 输入张量 [batch_size, seq_len, embed_dim] mask: 注意力掩码 Returns: 输出张量 [batch_size, seq_len, embed_dim] """# Self-Attention + 残差连接 + Layer Norm attn_output = self.self_attn(x, mask) x = self.norm1(x + self.dropout(attn_output))# FFN + 残差连接 + Layer Norm ffn_output = self.ffn(x) x = self.norm2(x + self.dropout(ffn_output))return x 4. 完整的 Transformer Encoder
classTransformerEncoder(nn.Module):""" Transformer Encoder Args: vocab_size: 词汇表大小 embed_dim: 嵌入维度 num_heads: 注意力头数 num_layers: Encoder 层数 ff_dim: 前馈网络隐藏层维度 max_len: 最大序列长度 dropout: Dropout 概率 """def__init__( self, vocab_size:int, embed_dim:int, num_heads:int, num_layers:int, ff_dim:int=2048, max_len:int=5000, dropout:float=0.1):super().__init__()# Token Embedding self.token_embedding = nn.Embedding(vocab_size, embed_dim)# Position Encoding self.position_encoding = PositionalEncoding(embed_dim, max_len, dropout)# Encoder Layers self.layers = nn.ModuleList([ TransformerEncoderLayer(embed_dim, num_heads, ff_dim, dropout)for _ inrange(num_layers)])# Layer Normalization self.norm = nn.LayerNorm(embed_dim)defforward( self, x: torch.Tensor, mask: torch.Tensor =None)-> torch.Tensor:""" 前向传播 Args: x: 输入 token IDs [batch_size, seq_len] mask: 注意力掩码 Returns: 编码器输出 [batch_size, seq_len, embed_dim] """# Token Embedding x = self.token_embedding(x)# Position Encoding x = self.position_encoding(x)# 通过所有 Encoder 层for layer in self.layers: x = layer(x, mask)# 最终 Layer Norm x = self.norm(x)return x 应用场景
1. 自然语言处理
1.1 机器翻译
Transformer 最初就是为机器翻译设计的。Encoder-Decoder 架构非常适合序列到序列任务:
- Encoder: 编码源语言句子
- Decoder: 生成目标语言句子
- Cross-Attention: Decoder 关注 Encoder 输出
1.2 文本分类
使用 Transformer Encoder 进行文本分类:
classTextClassifier(nn.Module):""" 基于 Transformer 的文本分类器 Args: vocab_size: 词汇表大小 embed_dim: 嵌入维度 num_heads: 注意力头数 num_layers: Encoder 层数 num_classes: 类别数 """def__init__( self, vocab_size:int, embed_dim:int, num_heads:int, num_layers:int, num_classes:int):super().__init__() self.encoder = TransformerEncoder( vocab_size=vocab_size, embed_dim=embed_dim, num_heads=num_heads, num_layers=num_layers )# 分类头 self.classifier = nn.Linear(embed_dim, num_classes)defforward(self, x: torch.Tensor, mask: torch.Tensor =None)-> torch.Tensor:""" 前向传播 Args: x: 输入 token IDs [batch_size, seq_len] mask: 注意力掩码 Returns: 分类 logits [batch_size, num_classes] """# 编码 encoded = self.encoder(x, mask)# [batch_size, seq_len, embed_dim]# 使用 [CLS] token 或平均池化 pooled = encoded.mean(dim=1)# [batch_size, embed_dim]# 分类 logits = self.classifier(pooled)return logits 1.3 命名实体识别 (NER)
Transformer 可以用于序列标注任务:
classNERTagger(nn.Module):""" 基于 Transformer 的命名实体识别 Args: vocab_size: 词汇表大小 embed_dim: 嵌入维度 num_heads: 注意力头数 num_layers: Encoder 层数 num_tags: 标签数 """def__init__( self, vocab_size:int, embed_dim:int, num_heads:int, num_layers:int, num_tags:int):super().__init__() self.encoder = TransformerEncoder( vocab_size=vocab_size, embed_dim=embed_dim, num_heads=num_heads, num_layers=num_layers )# 标签分类器 self.tagger = nn.Linear(embed_dim, num_tags)defforward(self, x: torch.Tensor, mask: torch.Tensor =None)-> torch.Tensor:""" 前向传播 Args: x: 输入 token IDs [batch_size, seq_len] mask: 注意力掩码 Returns: 标签 logits [batch_size, seq_len, num_tags] """# 编码 encoded = self.encoder(x, mask)# [batch_size, seq_len, embed_dim]# 对每个 token 分类 logits = self.tagger(encoded)# [batch_size, seq_len, num_tags]return logits 2. 大型语言模型 (LLM)
现代 LLM 大多基于 Transformer 架构,但采用 Decoder-only 设计:
2.1 Decoder-only 架构
与原始 Transformer 不同,GPT、LLaMA、Qwen 等模型只使用 Decoder 部分:
- 移除 Encoder: 不需要 Cross-Attention
- Causal Masking: 只能看到当前位置之前的内容
- 自回归生成: 逐个 token 生成文本
2.2 架构对比
| 架构类型 | 代表模型 | 特点 | 应用场景 |
|---|---|---|---|
| Encoder-Decoder | T5、BART | 双向编码、自回归解码 | 机器翻译、文本摘要 |
| Encoder-only | BERT、RoBERTa | 双向编码 | 文本分类、NER |
| Decoder-only | GPT、LLaMA、Qwen | 单向编码、自回归生成 | 文本生成、对话系统 |
2.3 为什么 Decoder-only 成为主流?
- 生成能力强: 自回归训练天然适合生成任务
- 扩展性好: 参数规模可以轻松扩展到千亿级别
- 统一任务: 通过 Prompt Engineering 可以处理多种任务
- 工程优化: 架构简单,便于优化和部署
3. 计算机视觉
Vision Transformer (ViT) 将 Transformer 应用于图像处理:
- Patch Embedding: 将图像分割成小块,展平后作为序列
- Position Encoding: 为每个 Patch 添加位置信息
- Transformer Encoder: 处理 Patch 序列
4. 多模态应用
Transformer 架构可以处理多种模态:
- CLIP: 图像-文本对齐
- Whisper: 语音识别
- GPT-4V: 多模态理解
总结与展望
核心要点
本文深入剖析了 Transformer 架构的核心原理和实现细节:
| 组件 | 核心思想 | 关键技术 |
|---|---|---|
| Self-Attention | 动态关注序列不同位置 | Q、K、V 点积注意力 |
| Multi-Head Attention | 多子空间并行注意力 | 多头拼接 + 线性变换 |
| Position Encoding | 注入位置信息 | 正弦/余弦编码或可学习编码 |
| Feed-Forward Network | 非线性变换 | 两层全连接 + ReLU |
| Layer Normalization | 稳定训练 | 归一化 + 残差连接 |
Transformer 的优势
- 并行化能力强: 不像 RNN 需要顺序处理
- 长距离依赖: 通过 Attention 直接建模
- 可扩展性好: 参数规模可以轻松扩展
- 通用性强: 适用于多种任务和模态
局限性与改进
| 局限性 | 改进方案 |
|---|---|
| 计算复杂度 O(n²) | Linformer、Performer、Flash Attention |
| 位置编码外推能力 | RoPE、ALiBi |
| 长序列处理 | Longformer、BigBird |
| 内存占用大 | Gradient Checkpointing、模型并行 |
未来趋势
- 高效注意力机制: 降低计算复杂度
- 长序列建模: 处理超长文本
- 多模态融合: 统一多种模态
- 模型压缩: 边缘侧部署
学习建议
- 深入理解 Attention: 这是 Transformer 的核心
- 动手实现: 从零实现一个简单的 Transformer
- 阅读经典论文: Attention Is All You Need、BERT、GPT 系列
- 实践应用: 使用 HuggingFace Transformers 库
- 关注前沿: Flash Attention、RoPE 等新技术
Transformer 架构是现代深度学习的基石。理解它,不仅能帮助你掌握 LLM 的原理,还能为学习其他前沿技术打下坚实基础。在接下来的博客中,我们将继续探讨 Embedding 技术、微调方法、LoRA 和 SimPO 等主题,敬请期待!
参考资料: