
Transformer架构自2017年Google发表的论文《Attention Is All You Need》中提出以来,彻底改变了深度学习特别是自然语言处理领域的格局。在短短几年内,Transformer已成为几乎所有现代大型语言模型(LLM)的基础架构,包括BERT、GPT系列、T5等革命性模型。与传统的RNN和LSTM相比,Transformer通过自注意力机制实现了并行化训练,极大提高了模型的训练效率和性能。
Transformer发展历程:
2017 → Attention Is All You Need (原始Transformer)
2018 → BERT (双向编码器)
2018 → GPT-1 (单向解码器)
2019 → GPT-2 (更大规模)
2020 → GPT-3 (175B参数)
2022 → ChatGPT (对话优化)
2023 → GPT-4 (多模态)
2025 → 最新研究进展在本教程中,我们将深入探讨Transformer架构的设计原理、核心组件、数学基础,以及如何使用PyTorch实现一个完整的Transformer模型。通过理论与实践相结合的方式,帮助读者全面掌握这一革命性架构。
你将学到什么?
Transformer模型的整体架构由两个主要部分组成:编码器(Encoder)和解码器(Decoder)。这种设计最初是为机器翻译任务量身定制的,其中编码器负责处理源语言输入,解码器负责生成目标语言输出。
Transformer整体架构:
┌─────────────────┐ ┌─────────────────┐
│ Encoder │ │ Decoder │
│ (Nx堆叠) │ │ (Nx堆叠) │
└────────┬────────┘ └────────┬────────┘
│ │
└───────────┬───────────┘
▼
┌─────────────┐
│ 线性输出层 │
└─────────────┘在原始论文中,编码器和解码器各由6个相同的层堆叠而成。这种堆叠设计允许模型学习越来越抽象的表示,类似于卷积神经网络中的深度设计。
Transformer的输入表示由三部分组成:
输入表示的计算方式非常简单:将这三种嵌入直接相加。数学上表示为:
由于Transformer模型本身没有循环或卷积结构,它无法自动捕捉单词之间的顺序关系。例如,句子"我爱你"和"你爱我"在没有位置信息的情况下,模型会将它们视为语义相同的输入。
为了解决这个问题,Transformer引入了位置编码机制。一个好的位置编码应该满足以下三个重要特性:
原始Transformer论文中使用的是正弦和余弦函数来生成位置编码:
其中,
是位置索引,
是维度索引,
是模型维度。
自注意力机制(Self-Attention)是Transformer架构的核心创新,它允许模型直接计算序列中任意两个单词之间的依赖关系,而不考虑它们之间的距离。这使得模型能够捕获长距离的上下文信息。
自注意力的基本思想是:对于序列中的每个位置,计算它与序列中所有位置的相关性,然后根据这些相关性对整个序列的表示进行加权求和。
原始Transformer中使用的是缩放点积注意力(Scaled Dot-Product Attention),其计算过程如下:
缩放点积注意力流程:
输入 → 线性变换(Q, K, V) → 计算点积 → 缩放 → Mask → Softmax → 与V相乘 → 输出具体的数学计算如下:
其中:
(Query):查询向量,表示当前位置想要关注的内容
(Key):键向量,用于与查询向量匹配
(Value):值向量,实际用于计算输出
:键向量的维度,缩放因子的作用是防止softmax函数的梯度消失
多头注意力(Multi-Head Attention)是自注意力机制的扩展,它通过多个"头"来并行计算不同子空间的注意力,然后将结果拼接起来。这种设计有两个主要优势:
多头注意力的计算过程如下:
其中每个头的计算为:
这里的
、
、
和
是可学习的参数矩阵。
Transformer的编码器层由两个主要子层组成:
每个子层都包含一个残差连接(Residual Connection)和层归一化(Layer Normalization)。编码器层的输出可以表示为:
其中
表示子层的输出。
编码器的信息流如下:
编码器层流程:
输入 → 多头自注意力 → 残差连接+层归一化 → 前馈网络 → 残差连接+层归一化 → 输出Transformer的解码器层比编码器层多了一个子层:
同样,每个子层都包含残差连接和层归一化。
掩码注意力(Causal Attention或Masked Attention)是解码器中的关键组件,它确保在生成第i个位置的输出时,模型只能看到前i-1个位置的信息,而不能看到未来的信息。这对于自回归生成(如机器翻译、文本生成)至关重要。
掩码是一个上三角矩阵,对角线以上的元素都被设置为负无穷大,这样在应用softmax后,这些位置的权重将趋近于0:
掩码矩阵示例:
[[0, -inf, -inf],
[0, 0, -inf],
[0, 0, 0]]解码器的信息流如下:
Transformer中的前馈神经网络是位置wise的,这意味着它独立地对每个位置的表示进行相同的变换。前馈神经网络的结构非常简单,包含两个线性变换和一个ReLU激活函数:
在原始论文中,前馈神经网络的内部维度是模型维度的4倍,即
。
层归一化(Layer Normalization)是Transformer中用于稳定训练的重要技术。与批归一化不同,层归一化是对每个样本的每个层进行归一化,而不是对每个批次的每个通道进行归一化。这使得层归一化在处理变长序列时更加有效。
层归一化的计算如下:
其中,
和
是输入x在特征维度上的均值和方差,
和
是可学习的参数,
是一个小的常数,用于防止除零错误。
残差连接(Residual Connection)用于解决深度神经网络中的梯度消失问题。在Transformer中,每个子层的输出都与输入相加,然后再进行层归一化:
这种设计允许梯度直接通过残差路径传播,从而使训练非常深的网络成为可能。
Transformer使用标准的交叉熵损失函数来训练:
其中,
是目标序列的长度,
是第i个目标标记,
是源序列。
原始Transformer论文使用了Adam优化器,学习率采用了预热和线性衰减的策略:
KaTeX parse error: Expected 'EOF', got '_' at position 59: …\min(\text{step_̲num}^{-0.5}, \t…
这种学习率调度策略有助于稳定训练过程,特别是在训练开始时。
为了提高训练效果和稳定性,Transformer的训练还采用了一些技巧:
首先,让我们实现位置编码模块:
import torch
import torch.nn as nn
import math
class PositionalEncoding(nn.Module):
def __init__(self, d_model, max_len=5000):
super().__init__()
# 创建位置编码矩阵
pe = torch.zeros(max_len, d_model)
position = torch.arange(0, max_len, dtype=torch.float).unsqueeze(1)
div_term = torch.exp(torch.arange(0, d_model, 2).float() * (-math.log(10000.0) / d_model))
# 偶数位置使用正弦函数
pe[:, 0::2] = torch.sin(position * div_term)
# 奇数位置使用余弦函数
pe[:, 1::2] = torch.cos(position * div_term)
# 将位置编码注册为缓冲区
self.register_buffer('pe', pe)
def forward(self, x):
# 将位置编码添加到输入嵌入中
x = x + self.pe[:x.size(0), :]
return x接下来,实现缩放点积注意力机制:
class ScaledDotProductAttention(nn.Module):
def __init__(self, dropout=0.1):
super().__init__()
self.dropout = nn.Dropout(dropout)
def forward(self, q, k, v, mask=None):
# 获取键的维度
d_k = q.size(-1)
# 计算注意力分数:QK^T / √d_k
scores = torch.matmul(q, k.transpose(-2, -1)) / math.sqrt(d_k)
# 应用掩码(如果提供)
if mask is not None:
scores = scores.masked_fill(mask == 0, -1e9)
# 应用softmax和dropout
attn = self.dropout(torch.softmax(scores, dim=-1))
# 与值向量相乘
output = torch.matmul(attn, v)
return output, attn现在,实现多头注意力机制:
class MultiHeadAttention(nn.Module):
def __init__(self, h, d_model, dropout=0.1):
super().__init__()
assert d_model % h == 0
# 每个头的维度
self.d_k = d_model // h
self.h = h
# 创建线性变换层
self.linears = nn.ModuleList([nn.Linear(d_model, d_model) for _ in range(4)])
self.attention = ScaledDotProductAttention(dropout)
self.dropout = nn.Dropout(dropout)
def forward(self, q, k, v, mask=None):
batch_size = q.size(0)
# 应用线性变换并分割成多个头
q, k, v = [l(x).view(batch_size, -1, self.h, self.d_k).transpose(1, 2)
for l, x in zip(self.linears, (q, k, v))]
# 应用注意力机制
x, attn = self.attention(q, k, v, mask=mask)
# 重新拼接多头结果
x = x.transpose(1, 2).contiguous().view(batch_size, -1, self.h * self.d_k)
# 应用最后一个线性变换
return self.linears[-1](x)实现位置wise前馈神经网络:
class PositionwiseFeedForward(nn.Module):
def __init__(self, d_model, d_ff, dropout=0.1):
super().__init__()
self.w_1 = nn.Linear(d_model, d_ff)
self.w_2 = nn.Linear(d_ff, d_model)
self.dropout = nn.Dropout(dropout)
def forward(self, x):
return self.w_2(self.dropout(torch.relu(self.w_1(x))))实现编码器层:
class EncoderLayer(nn.Module):
def __init__(self, d_model, nhead, dim_feedforward=2048, dropout=0.1):
super().__init__()
self.self_attn = MultiHeadAttention(nhead, d_model, dropout)
self.feed_forward = PositionwiseFeedForward(d_model, dim_feedforward, dropout)
self.norm1 = nn.LayerNorm(d_model)
self.norm2 = nn.LayerNorm(d_model)
self.dropout1 = nn.Dropout(dropout)
self.dropout2 = nn.Dropout(dropout)
def forward(self, src, src_mask=None):
# 多头自注意力子层
src2 = self.self_attn(src, src, src, mask=src_mask)
src = src + self.dropout1(src2)
src = self.norm1(src)
# 前馈神经网络子层
src2 = self.feed_forward(src)
src = src + self.dropout2(src2)
src = self.norm2(src)
return src实现解码器层:
class DecoderLayer(nn.Module):
def __init__(self, d_model, nhead, dim_feedforward=2048, dropout=0.1):
super().__init__()
self.self_attn = MultiHeadAttention(nhead, d_model, dropout)
self.multihead_attn = MultiHeadAttention(nhead, d_model, dropout)
self.feed_forward = PositionwiseFeedForward(d_model, dim_feedforward, dropout)
self.norm1 = nn.LayerNorm(d_model)
self.norm2 = nn.LayerNorm(d_model)
self.norm3 = nn.LayerNorm(d_model)
self.dropout1 = nn.Dropout(dropout)
self.dropout2 = nn.Dropout(dropout)
self.dropout3 = nn.Dropout(dropout)
def forward(self, tgt, memory, tgt_mask=None, memory_mask=None):
# 掩码多头自注意力子层
tgt2 = self.self_attn(tgt, tgt, tgt, mask=tgt_mask)
tgt = tgt + self.dropout1(tgt2)
tgt = self.norm1(tgt)
# 多头跨注意力子层
tgt2 = self.multihead_attn(tgt, memory, memory, mask=memory_mask)
tgt = tgt + self.dropout2(tgt2)
tgt = self.norm2(tgt)
# 前馈神经网络子层
tgt2 = self.feed_forward(tgt)
tgt = tgt + self.dropout3(tgt2)
tgt = self.norm3(tgt)
return tgt最后,将所有组件组合成完整的Transformer模型:
class Transformer(nn.Module):
def __init__(self, src_vocab_size, tgt_vocab_size, d_model=512, nhead=8,
num_encoder_layers=6, num_decoder_layers=6, dim_feedforward=2048, dropout=0.1):
super().__init__()
# 嵌入层
self.src_embedding = nn.Embedding(src_vocab_size, d_model)
self.tgt_embedding = nn.Embedding(tgt_vocab_size, d_model)
self.positional_encoding = PositionalEncoding(d_model, max_len=5000)
# 编码器和解码器
encoder_layer = EncoderLayer(d_model, nhead, dim_feedforward, dropout)
self.encoder = nn.TransformerEncoder(encoder_layer, num_layers=num_encoder_layers)
decoder_layer = DecoderLayer(d_model, nhead, dim_feedforward, dropout)
self.decoder = nn.TransformerDecoder(decoder_layer, num_layers=num_decoder_layers)
# 输出层
self.out = nn.Linear(d_model, tgt_vocab_size)
# 初始化参数
self._init_weights()
def _init_weights(self):
for p in self.parameters():
if p.dim() > 1:
nn.init.xavier_uniform_(p)
def forward(self, src, tgt, src_mask=None, tgt_mask=None, memory_mask=None):
# 源序列嵌入
src_embedded = self.positional_encoding(self.src_embedding(src) * math.sqrt(self.src_embedding.embedding_dim))
# 目标序列嵌入
tgt_embedded = self.positional_encoding(self.tgt_embedding(tgt) * math.sqrt(self.tgt_embedding.embedding_dim))
# 编码器前向传播
memory = self.encoder(src_embedded, src_key_padding_mask=src_mask)
# 解码器前向传播
output = self.decoder(tgt_embedded, memory, tgt_mask=tgt_mask,
memory_mask=memory_mask, tgt_key_padding_mask=tgt_mask)
# 输出层
output = self.out(output)
return outputBERT(Bidirectional Encoder Representations from Transformers)是Google在2018年提出的预训练语言模型,它只使用了Transformer的编码器部分,并通过双向掩码语言模型(Masked Language Model)进行预训练。
BERT的主要特点:
BERT架构:
输入序列 → 词嵌入+位置编码+段嵌入 → 多层双向Transformer编码器 → 任务特定输出层GPT(Generative Pre-trained Transformer)系列模型只使用了Transformer的解码器部分,通过自回归语言建模进行预训练。
GPT的主要特点:
GPT架构:
输入序列 → 词嵌入+位置编码 → 多层单向Transformer解码器 → 输出概率分布特性 | BERT | GPT |
|---|---|---|
架构 | 双向编码器 | 单向解码器 |
预训练任务 | 掩码语言模型+下一句预测 | 自回归语言建模 |
上下文理解 | 双向理解 | 单向生成 |
主要应用 | 理解性任务(分类、问答) | 生成性任务(文本生成、对话) |
训练目标 | 预测掩码词 | 预测下一个词 |
Transformer最初是为机器翻译任务设计的,在WMT等机器翻译基准测试中取得了显著的性能提升。机器翻译任务中,Transformer的完整架构(编码器+解码器)被使用,其中:
对于文本分类任务(如情感分析、主题分类),通常使用Transformer的编码器部分(如BERT),并在顶部添加一个分类层:
class TransformerForSequenceClassification(nn.Module):
def __init__(self, transformer_model, num_labels):
super().__init__()
self.transformer = transformer_model
self.dropout = nn.Dropout(0.1)
self.classifier = nn.Linear(transformer_model.config.hidden_size, num_labels)
def forward(self, input_ids, attention_mask=None):
outputs = self.transformer(input_ids=input_ids, attention_mask=attention_mask)
pooled_output = outputs.pooler_output
pooled_output = self.dropout(pooled_output)
logits = self.classifier(pooled_output)
return logits在问答系统中,Transformer(通常是双向模型如BERT)被用于理解问题和上下文,并预测答案的起始和结束位置:
class TransformerForQuestionAnswering(nn.Module):
def __init__(self, transformer_model):
super().__init__()
self.transformer = transformer_model
self.qa_outputs = nn.Linear(transformer_model.config.hidden_size, 2)
def forward(self, input_ids, attention_mask=None):
outputs = self.transformer(input_ids=input_ids, attention_mask=attention_mask)
sequence_output = outputs.last_hidden_state
logits = self.qa_outputs(sequence_output)
start_logits, end_logits = logits.split(1, dim=-1)
start_logits = start_logits.squeeze(-1)
end_logits = end_logits.squeeze(-1)
return start_logits, end_logits文本生成任务(如故事生成、摘要生成)通常使用Transformer的解码器部分(如GPT),通过自回归方式逐词生成文本:
class TextGenerator:
def __init__(self, model, tokenizer, device):
self.model = model
self.tokenizer = tokenizer
self.device = device
def generate(self, prompt, max_length=50, temperature=1.0, top_k=50):
# 编码输入
input_ids = self.tokenizer.encode(prompt, return_tensors='pt').to(self.device)
# 生成文本
for _ in range(max_length):
# 前向传播
outputs = self.model(input_ids)
next_token_logits = outputs[0][:, -1, :] / temperature
# 应用top-k采样
if top_k > 0:
next_token_logits = self.top_k_logits(next_token_logits, top_k)
# 应用softmax
probs = torch.softmax(next_token_logits, dim=-1)
# 采样下一个token
next_token = torch.multinomial(probs, num_samples=1)
# 添加到输入序列
input_ids = torch.cat([input_ids, next_token], dim=-1)
# 检查是否生成了结束标记
if next_token.item() == self.tokenizer.eos_token_id:
break
# 解码生成的文本
generated_text = self.tokenizer.decode(input_ids[0], skip_special_tokens=True)
return generated_text
def top_k_logits(self, logits, k):
v, ix = torch.topk(logits, k)
out = logits.clone()
out[out < v[:, [-1]]] = -float('inf')
return out随着Transformer模型规模的不断增长,模型效率成为一个重要问题。以下是一些常见的优化方法:
为了解决Transformer的一些局限性,研究人员提出了多种架构改进:
训练大型Transformer模型是一项挑战性任务,以下是一些训练策略改进:
2025年,高效注意力机制研究取得了显著进展:
多模态融合成为Transformer研究的热点:
随着大型语言模型的广泛应用,可控生成和安全性研究变得越来越重要:
2025年,Transformer在小样本和零样本学习方面取得了重要进展:
选择合适的Transformer模型并进行有效的微调是成功应用的关键:
数据质量直接影响模型性能:
全面的评估和持续的监控对于确保模型性能至关重要:
Transformer架构自2017年提出以来,已经成为深度学习特别是自然语言处理领域的主导架构。它通过自注意力机制实现了并行化训练,突破了RNN/LSTM在处理长序列时的效率瓶颈。基于Transformer,研究人员开发了一系列革命性的模型,如BERT、GPT系列等,这些模型在各种NLP任务上取得了前所未有的性能。
随着研究的深入,Transformer架构也在不断演进和完善,从提高计算效率、扩展模型规模,到增强多模态能力、提高可控性和安全性。2025年的最新研究表明,Transformer仍然是一个充满活力和潜力的研究方向。
未来,我们可以期待Transformer架构在以下方向继续发展:
作为深度学习从业者,掌握Transformer架构的原理和应用方法,对于跟踪和参与这一快速发展的领域至关重要。通过本教程的学习,希望读者能够深入理解Transformer的设计思想,并能够在实际项目中灵活应用和创新。
互动思考问题: