TL;DR
Transformer是一种革命性的神经网络架构,通过自注意力机制实现并行处理序列数据,彻底改变了自然语言处理领域。本指南详细介绍Transformer的核心组件(自注意力、位置编码、编码器-解码器架构),解释其相对于RNN/LSTM的优势,并探讨GPT、BERT等现代大模型如何基于Transformer构建。
引言
2017年,Google发表的论文《Attention Is All You Need》提出了Transformer架构,这一创新彻底改变了人工智能的发展轨迹。从ChatGPT到BERT,从机器翻译到代码生成,几乎所有现代AI大模型都建立在Transformer的基础之上。
在本指南中,你将学到:
- Transformer架构的核心设计理念
- 自注意力机制的数学原理和直观理解
- 位置编码如何让模型理解序列顺序
- 编码器-解码器架构的工作方式
- Transformer与RNN/LSTM的对比分析
- GPT、BERT等模型与Transformer的关系
什么是Transformer
Transformer是一种基于注意力机制的序列到序列(Seq2Seq)模型架构。与传统的循环神经网络不同,Transformer完全摒弃了循环结构,仅依靠注意力机制来捕获输入和输出之间的全局依赖关系。
为什么Transformer如此重要
Transformer的出现解决了传统序列模型的几个关键问题:
- 并行计算:RNN必须按顺序处理,而Transformer可以并行处理整个序列
- 长距离依赖:通过注意力机制直接建立任意位置之间的联系
- 可扩展性:架构设计使其能够扩展到数十亿参数规模
自注意力机制详解
自注意力(Self-Attention)是Transformer的核心创新。它允许模型在处理每个位置时,同时关注序列中的所有其他位置。
Query、Key、Value的概念
自注意力机制使用三个向量来计算注意力:
- Query(查询):当前位置想要查找什么信息
- Key(键):每个位置包含什么信息
- Value(值):每个位置实际要传递的信息
import numpy as np
def scaled_dot_product_attention(Q, K, V):
"""
缩放点积注意力计算
Q: 查询矩阵 (seq_len, d_k)
K: 键矩阵 (seq_len, d_k)
V: 值矩阵 (seq_len, d_v)
"""
d_k = K.shape[-1]
# 计算注意力分数
scores = np.matmul(Q, K.T) / np.sqrt(d_k)
# Softmax归一化
attention_weights = softmax(scores, axis=-1)
# 加权求和
output = np.matmul(attention_weights, V)
return output, attention_weights
def softmax(x, axis=-1):
exp_x = np.exp(x - np.max(x, axis=axis, keepdims=True))
return exp_x / np.sum(exp_x, axis=axis, keepdims=True)
注意力计算公式
自注意力的数学表达式为:
Attention(Q, K, V) = softmax(QK^T / √d_k) V
其中 d_k 是键向量的维度,除以 √d_k 是为了防止点积值过大导致softmax梯度消失。
多头注意力
为了让模型能够关注不同类型的信息,Transformer使用多头注意力(Multi-Head Attention):
def multi_head_attention(Q, K, V, num_heads, d_model):
"""
多头注意力机制
"""
d_k = d_model // num_heads
heads = []
for i in range(num_heads):
# 每个头使用不同的线性投影
Q_i = linear_projection(Q, d_k)
K_i = linear_projection(K, d_k)
V_i = linear_projection(V, d_k)
head_i, _ = scaled_dot_product_attention(Q_i, K_i, V_i)
heads.append(head_i)
# 拼接所有头的输出
concat = np.concatenate(heads, axis=-1)
# 最终线性投影
output = linear_projection(concat, d_model)
return output
多头注意力允许模型同时从不同的表示子空间学习信息,例如一个头关注语法结构,另一个头关注语义关系。
位置编码原理
由于Transformer没有循环结构,它无法自然地感知序列中元素的位置。位置编码(Positional Encoding)解决了这个问题。
正弦位置编码
原始Transformer使用正弦和余弦函数生成位置编码:
def positional_encoding(seq_len, d_model):
"""
生成正弦位置编码
"""
position = np.arange(seq_len)[:, np.newaxis]
div_term = np.exp(np.arange(0, d_model, 2) * -(np.log(10000.0) / d_model))
pe = np.zeros((seq_len, d_model))
pe[:, 0::2] = np.sin(position * div_term) # 偶数维度
pe[:, 1::2] = np.cos(position * div_term) # 奇数维度
return pe
这种设计的优点:
- 每个位置有唯一的编码
- 模型可以学习相对位置关系
- 可以外推到训练时未见过的序列长度
可学习位置编码
现代模型如BERT和GPT使用可学习的位置嵌入:
class LearnablePositionalEncoding:
def __init__(self, max_seq_len, d_model):
# 位置嵌入作为可训练参数
self.position_embeddings = np.random.randn(max_seq_len, d_model) * 0.02
编码器-解码器架构
Transformer采用编码器-解码器架构,这是处理序列到序列任务的经典设计。
编码器结构
编码器由N个相同的层堆叠而成,每层包含:
- 多头自注意力层:让每个位置关注输入序列的所有位置
- 前馈神经网络:对每个位置独立进行非线性变换
- 残差连接和层归一化:稳定训练过程
解码器结构
解码器同样由N层堆叠,但每层有三个子层:
- 掩码多头自注意力:只能关注已生成的位置,防止信息泄露
- 交叉注意力:关注编码器的输出,获取源序列信息
- 前馈神经网络:与编码器相同
残差连接与层归一化
def transformer_sublayer(x, sublayer_fn):
"""
Transformer子层:残差连接 + 层归一化
"""
# 子层计算
sublayer_output = sublayer_fn(x)
# 残差连接
residual = x + sublayer_output
# 层归一化
output = layer_norm(residual)
return output
Transformer vs RNN/LSTM对比
| 特性 | Transformer | RNN/LSTM |
|---|---|---|
| 并行计算 | 完全并行 | 必须顺序处理 |
| 长距离依赖 | O(1)路径长度 | O(n)路径长度 |
| 计算复杂度 | O(n²·d) | O(n·d²) |
| 训练速度 | 快(可并行) | 慢(顺序依赖) |
| 内存占用 | 较高(注意力矩阵) | 较低 |
| 可解释性 | 注意力权重可视化 | 较难解释 |
为什么Transformer取代了RNN
- 训练效率:GPU擅长并行计算,Transformer充分利用这一优势
- 长序列处理:RNN的梯度消失问题限制了有效记忆长度
- 模型容量:Transformer更容易扩展到大规模参数
GPT、BERT等模型的关系
现代大语言模型都基于Transformer架构,但采用不同的设计选择:
GPT系列(仅解码器)
GPT使用Transformer的解码器部分,采用自回归方式生成文本:
- 训练目标:预测下一个token
- 特点:单向注意力,适合文本生成
- 应用:对话、写作、代码生成
BERT(仅编码器)
BERT使用Transformer的编码器部分,采用双向注意力:
- 训练目标:掩码语言模型(MLM)+ 下一句预测
- 特点:双向上下文理解
- 应用:文本分类、问答、命名实体识别
T5(编码器-解码器)
T5保留完整的Transformer架构:
- 训练目标:文本到文本的统一框架
- 特点:灵活处理各种NLP任务
- 应用:翻译、摘要、问答
实践指南
使用预训练模型
对于大多数应用,建议使用预训练模型而非从头训练:
from transformers import AutoModel, AutoTokenizer
# 加载预训练模型
model_name = "bert-base-chinese"
tokenizer = AutoTokenizer.from_pretrained(model_name)
model = AutoModel.from_pretrained(model_name)
# 文本编码
text = "Transformer改变了自然语言处理"
inputs = tokenizer(text, return_tensors="pt")
outputs = model(**inputs)
微调技巧
- 学习率:使用较小的学习率(1e-5到5e-5)
- 批次大小:根据显存调整,通常16-32
- 训练轮数:2-4轮通常足够
- 梯度累积:显存不足时使用
工具推荐
在AI开发和学习过程中,以下工具可以提升效率:
总结
Transformer架构的核心要点:
- 自注意力机制:通过Query-Key-Value计算实现全局依赖建模
- 位置编码:为无循环结构的模型提供位置信息
- 编码器-解码器:灵活的架构支持多种任务类型
- 并行计算:相比RNN大幅提升训练效率
- 可扩展性:支持扩展到数千亿参数规模
理解Transformer架构是掌握现代AI技术的基础,无论是使用大语言模型还是开发AI应用,这些知识都至关重要。
常见问题
Transformer中的注意力机制与人类注意力有什么关系?
Transformer的注意力机制是一种数学抽象,灵感来源于人类选择性关注重要信息的能力。在模型中,注意力权重表示不同位置之间的相关性强度,类似于人类阅读时会重点关注关键词。但这是一种计算机制,与生物神经系统的注意力机制有本质区别。
为什么Transformer需要位置编码?
因为Transformer的自注意力机制是位置无关的——它只关注元素之间的关系,不考虑它们在序列中的位置。而语言理解需要位置信息("狗咬人"和"人咬狗"意思完全不同),所以必须通过位置编码显式地注入位置信息。
GPT和BERT哪个更好?
这取决于具体任务。GPT适合生成任务(写作、对话、代码生成),因为它的自回归设计天然适合逐步生成。BERT适合理解任务(分类、问答、信息抽取),因为它的双向注意力能更好地理解上下文。现代趋势是GPT类模型在规模扩大后也能很好地完成理解任务。
Transformer的计算复杂度为什么是O(n²)?
自注意力需要计算序列中每对位置之间的注意力分数,对于长度为n的序列,需要计算n×n个分数,因此复杂度是O(n²)。这也是处理超长文本时的主要瓶颈,许多研究致力于开发线性复杂度的注意力变体。
如何选择合适的预训练模型?
选择预训练模型时考虑:1)任务类型(生成选GPT类,理解选BERT类);2)语言(中文任务选中文预训练模型);3)模型大小(根据计算资源和延迟要求);4)领域(有领域特定预训练模型时优先选择)。