
谷歌的Transformer模型(2017年提出)是一种基于自注意力机制的神经网络架构,取代了传统的RNN和CNN,能并行处理序列数据。其核心是多头自注意力机制,结合编码器-解码器结构,高效捕捉长距离依赖关系。通过位置编码保留序列顺序信息,显著提升了机器翻译等任务的性能。该模型成为BERT、GPT等现代NLP技术的基础,并扩展至多模态领域。
Transformer的核心思想是完全基于自注意力机制(Self-Attention),替代传统的循环或卷积结构,实现高效并行化的序列建模。其核心突破包括:
这一设计使Transformer成为NLP基石,并扩展到多模态领域(如ViT),推动了大模型(GPT、BERT)的发展。
Transformer采用编码器 - 解码器架构。编码器由多个相同层堆叠而成,每层包含多头自注意力机制和前馈神经网络,通过残差连接和层归一化稳定训练。解码器同样多层堆叠,在自注意力机制基础上增加了编码器 - 解码器注意力层,同样有残差连接与层归一化。位置编码注入序列位置信息,共同构成完整架构。
Transformer的嵌入层是模型处理输入数据的起始关键模块,负责将离散的符号(如单词或子词)转换为连续的稠密向量,同时注入序列的位置信息。它包含两部分:词嵌入层通过可训练的嵌入矩阵,将每个符号映射为固定维度(如512维)的向量,使语义相近的词在向量空间中距离更近;位置编码则通过正弦/余弦函数(或可学习参数)生成与词位置相关的向量,直接加到词嵌入上,解决Transformer因摒弃循环结构而无法感知词序的问题。两者相加后的结果作为后续多头自注意力机制的输入,使模型能同时利用词汇语义和序列顺序信息,为深层特征提取奠定基础。
Transformer的位置编码是通过显式注入位置信息解决模型无法感知词序问题的关键设计,其核心是为每个词元附加与位置相关的向量表示。由于Transformer摒弃了循环或卷积结构,无法像RNN那样天然捕捉序列顺序,因此需通过位置编码显式标记词的位置。经典实现采用正弦/余弦函数生成固定编码:对于位置pos和维度i,偶数维用sin(pos/10000^(2i/d_model)),奇数维用cos(pos/10000^(2i/d_model)),不同频率的正弦/余弦组合使模型能捕捉相对位置关系并泛化到更长子序列;另一种方式是训练可学习的位置嵌入矩阵。位置编码与词嵌入相加后输入模型,使Transformer在全局注意力计算中仍能保留序列的顺序信息,成为其处理序列任务的基础设计之一。
Transformer的缩放点积注意力(Scaled Dot-Product Attention)是通过计算查询(Query)、键(Key)和值(Value)间的相关性来动态聚合信息的机制。其核心步骤为:首先计算查询矩阵Q与键矩阵K的点积,得到注意力分数矩阵,再除以√d_k(d_k为Key的维度)进行缩放,避免点积值过大导致softmax梯度消失;随后对分数矩阵施加softmax归一化,得到注意力权重;最后将权重与值矩阵V相乘,完成信息加权聚合。该设计通过点积高效衡量词元间的相关性,缩放操作稳定训练过程,softmax确保权重归一化,最终输出上下文相关的表示。缩放点积注意力是多头自注意力的基础单元,使模型能并行捕捉全局依赖关系,成为Transformer高效处理长序列的核心创新之一。
Transformer的多头注意力(Multi-Head Attention)通过并行计算多组缩放点积注意力来增强模型捕捉不同位置间复杂依赖的能力。其核心思想是将查询(Q)、键(K)、值(V)矩阵分别投影到h个不同的子空间(h为头数),每组子空间独立执行缩放点积注意力,生成h个注意力输出;最终将这些输出拼接并通过线性变换融合为统一表示。这种设计使模型能同时关注不同子空间的语义特征(如局部语法、全局依赖等),打破单一注意力机制的局限性。例如,某些头可能聚焦相邻词关系,另一些头则捕捉长程依赖。多头机制通过并行计算提升效率,而子空间投影的多样性增强了模型表达能力,成为Transformer捕获全局上下文信息的关键创新,为后续序列建模任务(如机器翻译、文本生成)提供了强大的表征基础。
Transformer的前馈网络(Feed-Forward Network, FFN)是位于每个编码器和解码器层中的核心组件,由两个线性变换和一个非线性激活函数构成,其数学表达式为FFN(x)=max(0,xW₁+b₁)W₂+b₂。该网络对每个位置的表示独立地进行相同的计算(即位置无关的全连接操作),首先通过第一个线性层将输入向量从d_model维度映射到更高的d_ff维度(通常d_ff=4×d_model),经ReLU激活函数引入非线性特征,再通过第二个线性层将维度还原至d_model。这种设计使模型能够对每个位置的上下文表示进行深度特征提取和变换,增强表达能力。尽管FFN结构简单,但其逐位置处理的特性与自注意力机制形成互补,共同构成Transformer强大的建模能力基础,尤其擅长捕捉局部和全局的语义关联。
Transformer的编码器层(Encoder Layer)是构建编码器的核心单元,通过并行化的自注意力机制和前馈网络实现对输入序列的深度特征提取。每个编码器层包含两个关键子层:多头自注意力机制和前馈神经网络,二者均采用残差连接(Residual Connection)和层归一化(Layer Normalization)来稳定训练过程。具体而言,输入序列首先经过多头自注意力层,通过并行计算多组查询-键-值注意力关系捕捉全局依赖;随后通过残差连接和层归一化保留原始信息并稳定梯度;接着输入前馈网络,通过两个线性变换和非线性激活函数对每个位置的表示进行深度特征变换。这种“注意力+前馈”的双层结构使编码器能同时建模全局上下文和局部特征,叠加多层编码器后可逐步构建输入序列的层次化表征,为解码器提供富含语义的上下文信息。
7. 层归一化和残差连接
Transformer通过层归一化(Layer Normalization)和残差连接(Residual Connection)两大机制显著提升了训练稳定性和模型性能。层归一化对每个样本的特征维度进行独立归一化(计算均值和方差后进行缩放平移),将输入限定在稳定分布范围内,有效缓解了深层网络中的梯度消失问题;而残差连接则通过“跳跃式”结构将输入直接叠加到子层输出上(即输出=子层(x)+x),既保留了原始输入信息,又允许梯度直接回传至浅层,避免了梯度在深层网络中的指数级衰减。二者协同工作时,残差连接确保了信息流动的畅通性,层归一化则进一步稳定了每一层的输入分布,这种组合使Transformer能够堆叠数十层而依然保持高效训练,成为其支撑大规模深度架构的核心设计基础。
以下是一个使用PyTorch实现的简化版Transformer的完整代码,包含逐行注释和总说明。代码实现了一个简化版Transformer的单编码器层,包含输入嵌入、位置编码、多头自注意力和前馈网络四大核心组件。通过残差连接和层归一化保证训练稳定性,使用缩放点积注意力机制捕捉全局依赖关系。测试部分生成随机输入序列并验证输出维度,完整展示了从输入到输出的流程。实际应用中需扩展解码器、添加掩码机制和训练循环才能构建完整模型。
import torch
import torch.nn as nn
import torch.nn.functional as F
# ==================== 总说明 ====================
# 本代码实现了一个简化版Transformer的单编码器层,包含:
# 1. 输入嵌入 + 位置编码
# 2. 多头自注意力机制
# 3. 前馈网络
# 4. 残差连接 + 层归一化
# 注意:为简化代码,省略了完整的解码器、掩码机制和训练流程
# ===================================================
# -------------------- 超参数定义 --------------------
d_model = 512 # 模型维度(词向量维度)
n_heads = 8 # 注意力头数
d_ff = 2048 # 前馈网络隐藏层维度
dropout = 0.1 # Dropout概率
max_len = 100 # 最大序列长度
vocab_size = 10000 # 词汇表大小
# -------------------- 输入嵌入层 --------------------
class Embeddings(nn.Module):
def __init__(self, vocab_size, d_model):
super().__init__()
self.lut = nn.Embedding(vocab_size, d_model) # 词嵌入矩阵
self.d_model = d_model
def forward(self, x):
return self.lut(x) * torch.sqrt(torch.tensor(self.d_model)) # 缩放词向量
# -------------------- 位置编码 --------------------
class PositionalEncoding(nn.Module):
def __init__(self, d_model, dropout, max_len):
super().__init__()
self.dropout = nn.Dropout(p=dropout)
pe = torch.zeros(max_len, d_model) # 初始化位置编码矩阵
position = torch.arange(0, max_len).unsqueeze(1) # 生成位置索引 [max_len,1]
div_term = torch.exp(torch.arange(0, d_model, 2) * (-torch.log(torch.tensor(10000.0)) / d_model)) # 计算缩放系数
pe[:, 0::2] = torch.sin(position * div_term) # 偶数维使用sin函数
pe[:, 1::2] = torch.cos(position * div_term) # 奇数维使用cos函数
pe = pe.unsqueeze(0) # 增加batch维度 [1,max_len,d_model]
self.register_buffer('pe', pe) # 注册为不可训练参数
def forward(self, x):
x = x + self.pe[:, :x.size(1)] # 将位置编码加到输入上
return self.dropout(x)
# -------------------- 多头注意力 --------------------
class MultiHeadAttention(nn.Module):
def __init__(self, d_model, n_heads, dropout):
super().__init__()
self.d_k = d_model // n_heads # 每个头的维度
self.n_heads = n_heads
self.linears = nn.ModuleList([nn.Linear(d_model, d_model) for _ in range(4)]) # 4个线性层(Q/K/V/输出)
self.dropout = nn.Dropout(p=dropout)
def scaled_dot_product_attention(self, Q, K, V):
scores = torch.matmul(Q, K.transpose(-2, -1)) / torch.sqrt(torch.tensor(self.d_k)) # 缩放点积
attn = F.softmax(scores, dim=-1) # Softmax归一化
return torch.matmul(attn, V), attn # 返回加权和与注意力权重
def split_heads(self, x):
batch_size = x.size(0)
return x.view(batch_size, -1, self.n_heads, self.d_k).transpose(1, 2) # 分割多头 [batch,heads,seq_len,d_k]
def forward(self, Q, K, V):
Q, K, V = [self.linears[i](x) for i, x in enumerate([Q, K, V])] # 线性变换
Q, K, V = [self.split_heads(x) for x in [Q, K, V]] # 分割多头
x, attn = self.scaled_dot_product_attention(Q, K, V) # 计算注意力
x = x.transpose(1, 2).contiguous().view(x.size(0), -1, self.d_model) # 合并多头
return self.linears[-1](x) # 最终线性变换
# -------------------- 前馈网络 --------------------
class PositionwiseFeedForward(nn.Module):
def __init__(self, d_model, d_ff, dropout):
super().__init__()
self.w1 = nn.Linear(d_model, d_ff) # 第一层线性变换
self.w2 = nn.Linear(d_ff, d_model) # 第二层线性变换
self.dropout = nn.Dropout(dropout)
def forward(self, x):
return self.w2(self.dropout(F.relu(self.w1(x)))) # ReLU激活 + Dropout
# -------------------- 编码器层 --------------------
class EncoderLayer(nn.Module):
def __init__(self, d_model, n_heads, d_ff, dropout):
super().__init__()
self.self_attn = MultiHeadAttention(d_model, n_heads, dropout) # 多头注意力
self.feed_forward = PositionwiseFeedForward(d_model, d_ff, dropout) # 前馈网络
self.norm1 = nn.LayerNorm(d_model) # 层归一化1
self.norm2 = nn.LayerNorm(d_model) # 层归一化2
self.dropout1 = nn.Dropout(dropout) # Dropout1
self.dropout2 = nn.Dropout(dropout) # Dropout2
def forward(self, x):
# 自注意力子层(含残差连接)
attn_out = self.self_attn(x, x, x) # Q=K=V
x = self.norm1(x + self.dropout1(attn_out)) # 残差连接 + 层归一化
# 前馈网络子层(含残差连接)
ff_out = self.feed_forward(x)
x = self.norm2(x + self.dropout2(ff_out)) # 残差连接 + 层归一化
return x
# -------------------- 测试代码 --------------------
if __name__ == "__main__":
batch_size, seq_len = 32, 10
x = torch.randint(0, vocab_size, (batch_size, seq_len)) # 随机生成输入序列
embed = Embeddings(vocab_size, d_model) # 初始化嵌入层
pos_enc = PositionalEncoding(d_model, dropout, max_len) # 初始化位置编码
encoder_layer = EncoderLayer(d_model, n_heads, d_ff, dropout) # 初始化编码器层
x_embed = embed(x) # 词嵌入 [batch,seq_len,d_model]
x_pos = pos_enc(x_embed) # 加入位置编码
output = encoder_layer(x_pos) # 编码器层处理 [batch,seq_len,d_model]
print("输出形状:", output.shape) # 验证输出维度重复:这段代码实现了一个简化版Transformer的单编码器层,包含输入嵌入、位置编码、多头自注意力和前馈网络四大核心组件。通过残差连接和层归一化保证训练稳定性,使用缩放点积注意力机制捕捉全局依赖关系。测试部分生成随机输入序列并验证输出维度,完整展示了从输入到输出的流程。实际应用中需扩展解码器、添加掩码机制和训练循环才能构建完整模型。
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。