整体架构概览
Transformer由编码器栈(Encoder Stack)和解码器栈(Decoder Stack)组成:
- 编码器:理解输入序列的双向上下文
- 解码器:基于编码器的理解,自回归地生成输出序列
结构对比
1. Encoder(编码器)
核心组件(按顺序):
Input Embedding + Positional Encoding ↓ Multi-Head Self-Attention(自注意力) ↓ Add & Norm ↓ Feed-Forward Network ↓ Add & Norm关键特点:
- 双向注意力:每个位置可以看到整个输入序列的所有token
- 并行计算:所有位置可以同时处理
- 无mask:注意力矩阵是完全可见的
2. Decoder(解码器)
核心组件(按顺序):
Output Embedding + Positional Encoding ↓ Masked Multi-Head Self-Attention(掩码自注意力) ↓ Add & Norm ↓ Multi-Head Cross-Attention(交叉注意力)← 连接Encoder输出 ↓ Add & Norm ↓ Feed-Forward Network ↓ Add & Norm关键特点:
- 单向注意力:使用causal mask,每个位置只能看到之前的token
- 串行生成:必须逐个token生成(自回归)
- Cross-Attention:额外的注意力层连接编码器信息
核心区别详解
区别1:注意力机制的可见范围
Encoder的Self-Attention(无mask):
# 注意力矩阵(3个token示例) # 每个位置都能看到所有位置 [[✓, ✓, ✓], # token 0 看到 0,1,2 [✓, ✓, ✓], # token 1 看到 0,1,2 [✓, ✓, ✓]] # token 2 看到 0,1,2Decoder的Masked Self-Attention:
# 使用下三角mask [[✓, ✗, ✗], # token 0 只看到 0 [✓, ✓, ✗], # token 1 只看到 0,1 [✓, ✓, ✓]] # token 2 只看到 0,1,2为什么这样设计?
- Encoder:理解阶段,需要全局信息(比如翻译"bank"需要看整个句子判断是"银行"还是"河岸")
- Decoder:生成阶段,不能"偷看"未来的词,否则训练时会作弊
区别2:Cross-Attention(Decoder独有)
这是Decoder最关键的组件:
# Cross-Attention的计算 Q = Decoder当前层的输出 # Query来自解码器 K, V = Encoder最后一层的输出 # Key和Value来自编码器 Attention(Q, K, V) = softmax(Q·K^T / √d_k) · V具体例子(机器翻译):
Encoder输入: "I love cats" Encoder输出: [h_I, h_love, h_cats] # 编码后的表示 Decoder生成 "我" 时: Q_我 = 当前解码状态 K, V = [h_I, h_love, h_cats] → 注意力权重可能是 [0.8, 0.1, 0.1] # 主要关注"I"为什么需要Cross-Attention?
- 连接源序列和目标序列
- 让解码器在生成每个词时,动态地"查阅"输入信息
- 这就是Seq2Seq任务的核心:从源语言映射到目标语言
区别3:计算方式
| 特性 | Encoder | Decoder |
|---|---|---|
| 并行度 | 完全并行 | 训练时并行,推理时串行 |
| 输入依赖 | 仅依赖输入序列 | 依赖编码器输出+已生成的token |
| 训练效率 | 高(一次前向计算整个序列) | 相对低(需要teacher forcing) |
联系与协作
1. 信息流动路径
输入序列 → Encoder Stack(6层) → 最终表示 [h1, h2, ..., hn] → 送入Decoder的每一层的Cross-Attention → 指导输出序列的生成2. 共享的设计模式
两者都使用:
- Multi-Head Attention:多头注意力机制
- 残差连接 + Layer Norm:Add & Norm
- Position-wise FFN:相同的前馈网络结构
- Positional Encoding:位置信息编码
3. 为什么要分开设计?
场景类比:
- Encoder= 理解材料的学生
- 可以反复阅读,前后对照理解
- 目标:形成完整的知识表示
- Decoder= 答题的学生
- 不能先看答案
- 可以参考理解的材料(Cross-Attention)
- 必须逐步写出答案
实际例子:机器翻译
输入:"The cat sat on the mat"
输出:"猫坐在垫子上"
Encoder阶段:
# 所有词同时处理,建立上下文理解 h_The = Attention(The, [The, cat, sat, on, the, mat]) h_cat = Attention(cat, [The, cat, sat, on, the, mat]) # ... 每个词都能看到全句Decoder阶段:
# 生成"猫"时 Q_猫 = f([<BOS>]) # 只基于开始符 Cross-Attn([<BOS>], [h_The, h_cat, ...]) # 查询Encoder,关注"The cat" # 生成"坐"时 Q_坐 = f([<BOS>, 猫]) # 基于已生成的"猫" Cross-Attn([<BOS>, 猫], [h_The, h_cat, ...]) # 关注"sat"现代变体
值得注意的是:
Encoder-only模型(BERT, ViT)
- 只用编码器
- 适合理解任务(分类、检测)
- 双向上下文
Decoder-only模型(GPT, LLaMA)
- 只用解码器
- 用Causal Mask模拟单向
- 简化架构,扩展性更好
- 去掉Cross-Attention,因为没有独立的编码器
Encoder-Decoder模型(T5, BART)
- 保留完整结构
- 适合Seq2Seq任务
总结对比表
| 维度 | Encoder | Decoder |
|---|---|---|
| 注意力类型 | 双向Self-Attention | 单向Masked Self-Attention + Cross-Attention |
| 可见范围 | 看到整个输入 | 只看到已生成的部分 |
| 处理方式 | 并行处理全序列 | 自回归逐个生成 |
| 主要任务 | 理解和编码 | 生成和解码 |
| 是否依赖对方 | 独立 | 依赖Encoder输出 |
| 典型应用 | 特征提取、分类 | 文本生成、翻译 |
核心联系:Decoder通过Cross-Attention桥梁,将Encoder的理解能力转化为生成能力。
我来系统地帮你梳理三种Transformer架构的任务分布和设计理念。
架构核心特性对比
| 架构类型 | 注意力机制 | 处理方式 | 核心能力 | 计算效率 |
|---|---|---|---|---|
| Encoder-only | 双向Self-Attention | 并行处理全序列 | 深度理解 | 高(单次前向) |
| Decoder-only | 单向Causal Attention | 自回归生成 | 序列生成 | 中(逐token) |
| Encoder-Decoder | 双向+单向+Cross | 编码→解码 | 序列转换 | 低(两阶段) |
一、Encoder-only 架构
设计理念
- 目标:深度理解输入,建立全局表示
- 特点:每个token都能"看到"整个序列的上下文
- 输出:固定维度的向量表示(用于分类/检索)
核心优势
- 双向建模能力强:同时利用前后文信息
- 并行效率高:一次前向传播处理整个序列
- 表示质量高:适合需要深度语义理解的任务
适合的任务类型
1. 文本分类任务
- 情感分析:"这部电影真棒" → 正面情感
- 新闻分类:文章 → 体育/科技/财经
- 意图识别:"帮我订张机票" → 预订意图
为什么适合?
- 需要理解全文语义,不需要生成
- 双向上下文帮助消歧义
代表模型:BERT, RoBERTa, ALBERT
# 典型实现 class TextClassifier(nn.Module): def __init__(self): self.encoder = BertModel.from_pretrained('bert-base') self.classifier = nn.Linear(768, num_classes) def forward(self, input_ids): # 获取[CLS] token的表示 outputs = self.encoder(input_ids) cls_embedding = outputs.last_hidden_state[:, 0, :] # [CLS]位置 logits = self.classifier(cls_embedding) return logits2. 序列标注任务
- 命名实体识别(NER):"苹果公司在加州" → [苹果-ORG, 加州-LOC]
- 词性标注(POS):每个词标注名词/动词/形容词
- 语义角色标注:识别"谁对谁做了什么"
为什么适合?
- 需要为序列中每个位置输出标签
- 双向信息帮助准确判断(比如"苹果"需要看后文"公司"才知道是组织)
代表模型:BERT-NER, BioBERT
# 输入输出示例 输入: "张三在北京大学学习" BERT输出: [h_张, h_三, h_在, h_北, h_京, h_大, h_学, h_学, h_习] Token分类: [B-PER, I-PER, O, B-ORG, I-ORG, I-ORG, I-ORG, O, O]3. 问答任务(抽取式)
- 机器阅读理解:给定文章+问题,抽取答案片段
- FAQ匹配:问题匹配到知识库中的答案
典型任务:SQuAD数据集
文章: "特斯拉由埃隆·马斯克于2003年创立..." 问题: "特斯拉的创始人是谁?" 答案: "埃隆·马斯克"(从文章中抽取)为什么适合?
- 不需要生成新内容,只需定位答案位置
- 需要同时理解问题和文章的语义
代表模型:BERT-QA, ELECTRA
4. 语义相似度/检索任务
- 文本匹配:判断两个句子是否语义相同
- 语义检索:找到与查询最相关的文档
- 重复问题检测:识别相似问题
应用场景:
- 搜索引擎:query与document的匹配
- 推荐系统:用户兴趣与内容的匹配
代表模型:Sentence-BERT, SimCSE, DPR
# 双塔模型 query_emb = encoder(query) # [768] doc_emb = encoder(document) # [768] similarity = cosine_sim(query_emb, doc_emb)5. 计算机视觉任务(Vision Transformer)
- 图像分类:ImageNet分类
- 目标检测:DETR
- 图像分割:SegFormer
为什么Encoder适合CV?
- 图像patch之间没有时序依赖
- 需要全局感受野理解图像
代表模型:ViT, Swin Transformer, DeiT
二、Decoder-only 架构
设计理念
- 目标:自回归生成序列
- 特点:Causal Mask,只能看到前文
- 输出:下一个token的概率分布
核心优势
- 架构简单:去掉Cross-Attention,易于扩展
- 统一框架:所有任务都变成"续写"
- 训练稳定:单一优化目标(语言建模)
适合的任务类型
1. 文本生成任务
- 故事/文章生成:给定开头,续写内容
- 代码生成:根据注释生成代码
- 对话生成:聊天机器人回复
典型例子:
输入: "从前有座山,山里有座庙," 输出: "庙里有个老和尚在讲故事..."为什么适合?
- 生成任务本质就是自回归预测
- Causal Mask防止"偷看"未来
代表模型:GPT-3/4, LLaMA, PaLM, Claude
2. Zero-shot/Few-shot学习
- 指令跟随:"用莎士比亚风格写诗"
- 情境学习:给几个示例就能完成新任务
GPT的惊人能力:
Prompt: "翻译成英文: 苹果 -> Apple 香蕉 -> Banana 橙子 ->" 输出: "Orange"为什么Decoder-only强大?
- 预训练时见过海量文本模式
- 可以通过prompt调用不同能力
代表模型:GPT-3.5, GPT-4, Llama-2/3
3. 条件生成任务
虽然Decoder-only没有Cross-Attention,但可以通过Prompt实现条件生成:
- 摘要生成:
"Summarize: [长文本] Summary:"- 翻译:
"Translate to English: 中文:你好 English: Hello 中文:再见 English:"- 问答:
"Context: [文章] Question: [问题] Answer:"关键思想:把条件信息放在prompt里,用Causal Attention统一处理
4. 代码生成/补全
- GitHub Copilot:根据注释和上下文生成代码
- 代码补全:光标后续代码预测
例子:
# 计算斐波那契数列 def fibonacci(n): # GPT生成↓ if n <= 1: return n return fibonacci(n-1) + fibonacci(n-2)代表模型:Codex, Code Llama, StarCoder
5. 多模态生成(扩展)
现代Decoder-only可以处理多模态:
- 图像生成文本:图像→文本描述(通过视觉encoder提取特征作为prefix)
- 文本生成图像:DALL-E(自回归生成image tokens)
代表模型:LLaVA, GPT-4V, Flamingo
三、Encoder-Decoder 架构
设计理念
- 目标:序列到序列的转换
- 特点:源序列和目标序列不同空间
- 输出:通过Cross-Attention连接两者
核心优势
- 显式建模源-目标映射:Cross-Attention专门负责对齐
- 灵活处理不同长度:输入输出长度可以差异很大
- 适合结构化转换:明确的"理解→生成"流程
适合的任务类型
1. 机器翻译
这是Encoder-Decoder的经典应用
源语言(Encoder): "I love natural language processing" ↓ Cross-Attention连接 目标语言(Decoder): "我 爱 自然 语言 处理"为什么需要Encoder-Decoder?
- 源语言和目标语言是不同的语言空间
- 需要对齐机制:生成"我"时重点关注"I"
- 长度差异大:中文4个词,英文5个词
代表模型:Transformer原论文, mBART, NLLB
Cross-Attention的作用:
生成"爱"时: Query = Decoder状态(已生成"我") Key, Value = Encoder输出 [h_I, h_love, h_NLP, ...] → 注意力权重: [0.1, 0.7, 0.1, 0.1] # 聚焦"love"2. 文本摘要
- 抽象式摘要:生成新的概括性句子(不是简单抽取)
输入文章(500词)→ Encoder理解 ↓ 输出摘要(50词)→ Decoder生成为什么适合?
- 输入输出长度差异极大(10:1压缩比)
- 需要"理解+重组"而非简单复制
代表模型:BART, PEGASUS, T5
3. 语法纠错/改写
- 语法修正:"I has a cat" → "I have a cat"
- 文本润色:口语化 → 正式书面语
- 风格迁移:现代文 → 古文
例子:
输入: "这个东西挺好的哈哈哈" 输出: "该产品质量优良,表现出色"为什么需要Encoder-Decoder?
- 不是简单替换,需要理解语义后重组
- 输入输出可能长度变化
代表模型:T5-GEC, GECToR(混合架构)
4. 问答任务(生成式)
- 开放域问答:不限于抽取原文,可以生成新答案
输入: "问题:地球为什么是圆的? 文档:[相关知识]" 输出: "因为引力使得大质量天体趋向于球形..."vs Encoder-only问答:
- Encoder-only:只能抽取原文片段
- Encoder-Decoder:可以综合多处信息生成新答案
代表模型:T5-QA, FiD (Fusion-in-Decoder)
5. 多任务统一框架
T5的"Text-to-Text"理念:把所有NLP任务都变成文本转换
翻译: "translate English to German: Hello" → "Hallo" 摘要: "summarize: [长文本]" → [摘要] 分类: "sentiment: This movie sucks" → "negative" 问答: "question: Who is the CEO? context: [文章]" → "John Doe"优势:
- 统一训练框架
- 任务间知识共享
- 新任务零样本迁移
代表模型:T5, UL2, Flan-T5
6. 序列标注(生成式)
传统用Encoder做token分类,但也可以用Encoder-Decoder生成标签序列:
输入: "张三在北京大学学习" 输出: "B-PER I-PER O B-ORG I-ORG I-ORG I-ORG O O"优势:可以生成更复杂的结构化输出
架构选择的决策树
你的任务是什么? │ ├─ 只需要理解/分类,不需要生成? │ → Encoder-only (BERT系) │ 适合:分类、NER、QA抽取、检索 │ ├─ 需要生成文本,且输入输出在"同一空间"? │ → Decoder-only (GPT系) │ 适合:续写、对话、代码生成、指令跟随 │ └─ 需要"不同空间"的序列转换? → Encoder-Decoder (T5系) 适合:翻译、摘要、改写、结构化转换现代趋势:Decoder-only的崛起
为什么GPT模型越来越流行?
架构简洁:
- 去掉Cross-Attention,减少复杂度
- 易于扩展到百亿/千亿参数
统一范式:
- 所有任务用prompt统一成"文本续写"
- 不需要任务特定的架构修改
涌现能力:
- 参数量到达临界点后,出现zero-shot推理、思维链等能力
- Instruction tuning后可以替代大部分NLP任务
训练效率:
- 只需要无标注文本(语言建模)
- 数据规模可以无限扩大
具体例子对比
场景:中译英
Encoder-Decoder方式(T5):
输入: "translate Chinese to English: 我爱你" Encoder处理: 理解"我爱你"的语义 Decoder生成: "I" → "love" → "you" Cross-Attention: 生成每个词时查询源语言对应位置Decoder-only方式(GPT):
输入prompt: "Translate to English: 中文:你好 English: Hello 中文:我爱你 English:" 模型续写: " I love you"区别:
- T5有专门的注意力机制处理翻译对齐
- GPT通过in-context learning模拟翻译能力
- T5在专门微调后翻译质量更高
- GPT更灵活,可以zero-shot翻译多种语言
总结表格
| 任务类型 | Encoder-only | Decoder-only | Encoder-Decoder | 最佳选择 |
|---|---|---|---|---|
| 文本分类 | ✅ 最佳 | ⚠️ 可用(prompt) | ❌ 过重 | BERT |
| 序列标注 | ✅ 最佳 | ⚠️ 可用(生成) | ⚠️ 可用 | BERT |
| 抽取式QA | ✅ 最佳 | ❌ 不适合 | ⚠️ 可用 | BERT |
| 文本生成 | ❌ 不能 | ✅ 最佳 | ✅ 很好 | GPT/T5 |
| 机器翻译 | ❌ 不能 | ⚠️ 可用 | ✅ 最佳 | T5/mBART |
| 文本摘要 | ❌ 不能 | ⚠️ 可用 | ✅ 最佳 | BART/T5 |
| 对话系统 | ❌ 不能 | ✅ 最佳 | ✅ 很好 | GPT/Claude |
| 代码生成 | ❌ 不能 | ✅ 最佳 | ⚠️ 可用 | Codex |
| 多任务学习 | ⚠️ 有限 | ✅ 很好 | ✅ 最佳 | T5/GPT-4 |
图例:
- ✅ 非常适合
- ⚠️ 可以但非最优
- ❌ 不适合/不能做
实际应用建议
你在做算法工程师面试准备,可以这样理解:
传统NLP任务(分类、NER、检索):
- 答:用BERT系Encoder-only
- 理由:双向建模+并行效率高
生成任务(对话、写作、代码):
- 答:用GPT系Decoder-only
- 理由:自回归生成+大模型涌现能力
Seq2Seq任务(翻译、摘要):
- 专业场景:用T5系Encoder-Decoder
- 通用场景:用GPT-4等大模型(更方便)
工业实践:
- 资源有限:小模型+任务特定架构(BERT-NER)
- 资源充足:大模型+prompt工程(GPT-4)
你对哪个架构的具体实现细节更感兴趣?比如Cross-Attention的梯度流动,或者GPT如何通过prompt统一不同任务?