Transformer核心原理
一、课程基本信息
- 课程主题:Transformer核心原理与自注意力机制
- 核心目标:理解Transformer整体结构、解决的问题、核心优势,掌握自注意力关键逻辑,衔接此前QKV手算案例
- 参考论文:Attention is All You Need (Vaswani et al., 2017, NeurIPS)
二、Transformer整体概述
1. 什么是Transformer?
Transformer是2017年由谷歌团队在论文 "Attention is All You Need" 中提出的深度学习模型架构,彻底摒弃了传统循环神经网络(RNN、LSTM)的串行计算模式 ,全程依靠自注意力机制(Self-Attention) 实现序列数据的建模与处理,是当下所有大语言模型(LLM)的核心基石。
技术突破点:
- 首次将注意力机制作为模型核心,而非RNN的辅助组件
- 实现了序列数据的完全并行处理
- 为后续预训练语言模型革命奠定了基础
代码示例:Transformer核心结构定义
python
import torch
import torch.nn as nn
class Transformer(nn.Module):
def __init__(self, d_model=512, nhead=8, num_layers=6):
super().__init__()
# 编码器
self.encoder = nn.TransformerEncoder(
nn.TransformerEncoderLayer(d_model, nhead),
num_layers=num_layers
)
# 解码器
self.decoder = nn.TransformerDecoder(
nn.TransformerDecoderLayer(d_model, nhead),
num_layers=num_layers
)
def forward(self, src, tgt):
memory = self.encoder(src)
output = self.decoder(tgt, memory)
return output
2. Transformer解决的核心问题
-
解决传统RNN/LSTM串行计算瓶颈:
- 问题本质:传统模型必须按顺序逐词处理,第t时刻的计算依赖第t-1时刻的输出,无法并行
- 影响:训练速度慢、处理长文本效率极低
- 解决方案:Transformer通过自注意力机制,所有位置的信息可同时计算
-
解决长距离依赖问题:
- 问题本质:传统模型处理长文本时,前文信息经过多步传递会逐步丢失(梯度消失/信息衰减)
- 影响:无法关联远距离语义,如"我昨天买了一本书,它的封面是红色的"中的"它"无法准确指代"书"
- 解决方案:Transformer通过自注意力直接计算任意两个位置的关联强度,无距离限制
-
实现通用序列建模:
- 问题本质:传统模型针对特定任务设计,迁移性差
- 解决方案:编码器-解码器架构灵活适配多种任务
3. Transformer的核心优势
- 并行计算能力:整个序列可同时输入处理,训练速度远超RNN系列
- 长文本建模能力强:直接捕捉全局上下文,无长距离信息衰减
- 语义理解精准:通过自注意力区分一词多义、关联上下文
- 通用性极强:编码器+解码器结构可灵活拆分,适配不同任务
对比表格:
| 特性 | RNN/LSTM | Transformer |
|---|---|---|
| 计算方式 | 串行 | 并行 |
| 长距离依赖 | 差(信息衰减) | 优(直接关联) |
| 训练效率 | 低 | 高 |
| 语义理解 | 有限 | 精准 |
4. 基于Transformer的主流大模型应用
1. 仅使用编码器(Encoder-only)架构
- 代表模型:BERT、RoBERTa、ALBERT、ELECTRA
- 核心任务:文本分类、情感分析、实体识别、语义理解等理解类任务
- 特点:双向上下文编码,擅长从输入文本中提取特征
2. 仅使用解码器(Decoder-only)架构
- 代表模型:GPT系列、Llama、Claude、通义千问、文心一言
- 核心任务:文本生成、对话交互、代码生成、续写等生成类任务
- 特点:自回归生成,逐词预测下一个token
3. 编码器-解码器(Encoder-Decoder)架构
- 代表模型:T5、BART、Transformer原生模型
- 核心任务:机器翻译、文本摘要、对话生成等序列转换任务
- 特点:先理解输入,再生成输出
三、Transformer核心组件与整体结构
1. 整体结构:编码器-解码器架构
Transformer标准结构分为编码器(Encoder) 和解码器(Decoder) 两大部分:
- 编码器(Encoder) :负责理解输入文本的语义,提取全局上下文特征
- 解码器(Decoder) :负责生成输出序列,结合编码器信息逐词生成内容
2. 编码器核心组件(堆叠N层,每层结构一致)
1. 多头自注意力层(Multi-Head Self-Attention)
- 作用:实现全局上下文关联、一词多义区分
- 多头机制:多组QKV并行计算,捕捉不同类型的语义关系
- 单头vs多头:单头只能学习一种注意力模式,多头可学习多种
代码示例:多头自注意力
python
class MultiHeadAttention(nn.Module):
def __init__(self, d_model, nhead):
super().__init__()
self.nhead = nhead
self.d_k = d_model // nhead
# QKV投影矩阵
self.W_q = nn.Linear(d_model, d_model)
self.W_k = nn.Linear(d_model, d_model)
self.W_v = nn.Linear(d_model, d_model)
self.W_o = nn.Linear(d_model, d_model)
def scaled_dot_product_attention(self, Q, K, V, mask=None):
# Q·K^T / sqrt(d_k)
scores = torch.matmul(Q, K.transpose(-2, -1)) / torch.sqrt(torch.tensor(self.d_k, dtype=torch.float32))
if mask is not None:
scores = scores.masked_fill(mask == 0, -1e9)
# Softmax归一化
attn_weights = torch.softmax(scores, dim=-1)
# 加权融合V
output = torch.matmul(attn_weights, V)
return output, attn_weights
def forward(self, x, mask=None):
batch_size = x.size(0)
# 生成QKV并拆分为多头
Q = self.W_q(x).view(batch_size, -1, self.nhead, self.d_k).transpose(1, 2)
K = self.W_k(x).view(batch_size, -1, self.nhead, self.d_k).transpose(1, 2)
V = self.W_v(x).view(batch_size, -1, self.nhead, self.d_k).transpose(1, 2)
# 计算注意力
output, attn_weights = self.scaled_dot_product_attention(Q, K, V, mask)
# 拼接多头输出
output = output.transpose(1, 2).contiguous().view(batch_size, -1, self.nhead * self.d_k)
# 最终线性变换
return self.W_o(output), attn_weights
2. 前馈神经网络(FFN)
- 结构:两层线性层 + ReLU激活 + Dropout
- 作用:对注意力输出做非线性变换,强化语义特征提取
- 公式:FFN(x) = max(0, xW1 + b1)W2 + b2
代码示例:FFN
python
class FeedForwardNetwork(nn.Module):
def __init__(self, d_model, d_ff=2048, dropout=0.1):
super().__init__()
self.fc1 = nn.Linear(d_model, d_ff)
self.fc2 = nn.Linear(d_ff, d_model)
self.dropout = nn.Dropout(dropout)
def forward(self, x):
return self.fc2(self.dropout(torch.relu(self.fc1(x))))
3. 残差连接+层归一化
- 残差连接:x + f(x),解决梯度消失问题
- 层归一化:对每个样本的特征维度做归一化,加速收敛
- 顺序:LayerNorm(x + SubLayer(x))
代码示例:残差连接与层归一化
python
class SublayerConnection(nn.Module):
def __init__(self, d_model, dropout=0.1):
super().__init__()
self.norm = nn.LayerNorm(d_model)
self.dropout = nn.Dropout(dropout)
def forward(self, x, sublayer):
return x + self.dropout(sublayer(self.norm(x)))
3. 解码器核心组件(堆叠N层,每层结构一致)
1. 掩码多头自注意力层
- 关键机制:因果掩码(Causal Mask)
- 作用:防止生成时看到未来的词,保证自回归生成的合理性
- 掩码原理:上三角矩阵置为负无穷,Softmax后变为0
代码示例:生成因果掩码
python
def generate_causal_mask(sz):
mask = (torch.triu(torch.ones(sz, sz)) == 1).transpose(0, 1)
mask = mask.float().masked_fill(mask == 0, float('-inf')).masked_fill(mask == 1, float(0.0))
return mask
2. 编码器-解码器注意力层
- 作用:关联编码器的输入语义,让生成内容贴合输入信息
- Q来源:解码器前一层输出
- K/V来源:编码器输出(memory)
3. 前馈神经网络+残差连接+层归一化:与编码器完全一致
4. 辅助组件
1. 词嵌入层(Embedding)
- 作用:将文本词语转化为数字向量
- 实现:可训练的查找表,维度通常为d_model
- 示例:"猫" → 0.2, 0.5, -0.3, ...(512维向量)
代码示例:词嵌入
python
vocab_size = 10000
d_model = 512
embedding = nn.Embedding(vocab_size, d_model)
2. 位置编码(Positional Encoding)
- 作用:给向量添加位置信息,让模型知道词语的先后顺序
- Transformer论文方法:正弦余弦编码
- 公式 :
- PE(pos, 2i) = sin(pos / 10000^(2i/d_model))
- PE(pos, 2i+1) = cos(pos / 10000^(2i/d_model))
代码示例:位置编码
python
class PositionalEncoding(nn.Module):
def __init__(self, d_model, max_len=5000, dropout=0.1):
super().__init__()
self.dropout = nn.Dropout(p=dropout)
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)
pe = pe.unsqueeze(0).transpose(0, 1)
self.register_buffer('pe', pe)
def forward(self, x):
x = x + self.pe[:x.size(0), :]
return self.dropout(x)
3. 线性层+Softmax层
- 线性层:将d_model维向量映射到词汇表大小
- Softmax:转化为概率分布,生成最终词语概率
四、自注意力缩放机制
为什么要除以 sqrt(d_k)?(梯度消失完整解释)
核心结论
除以 sqrt(d_k) ,核心目的只有一个:防止注意力点积结果过大,避免Softmax函数饱和进而引发梯度消失 ,保障模型训练过程稳定可控。这一步操作也被称为缩放点积注意力(Scaled Dot-Product Attention)。
1. 底层数学逻辑
设定基础条件:Q、K向量的维度为dkd_kdk,向量内部元素满足均值为0、方差为1 ,点积计算公式:
Q⋅K⊤=∑i=1dkqiki Q \cdot K^\top = \sum_{i=1}^{d_k} q_i k_i Q⋅K⊤=i=1∑dkqiki
通过数学推导可得:点积结果的方差 = dkd_kdk
直观理解:假设Q和K的每个元素都是独立的随机变量,均值为0,方差为1,则它们乘积的期望为0,方差为1。d_k个独立随机变量之和的方差为d_k。
2. Softmax饱和问题详解
Softmax函数负责将点积分数转化为和为1的概率权重:
Softmax(zi)=ezi∑jezj \text{Softmax}(z_i) = \frac{e^{z_i}}{\sum_{j} e^{z_j}} Softmax(zi)=∑jezjezi
饱和现象 :当ziz_izi数值过大时,ezie^{z_i}ezi会指数爆炸,导致:
- 最大的ziz_izi对应的概率趋近于1
- 其他所有概率趋近于0
- 概率分布完全失去区分度
3. 梯度消失的成因与危害
Softmax梯度公式 :
∂Softmax(zi)∂zj=Softmax(zi)⋅(δij−Softmax(zj)) \frac{\partial \text{Softmax}(z_i)}{\partial z_j} = \text{Softmax}(z_i) \cdot (\delta_{ij} - \text{Softmax}(z_j)) ∂zj∂Softmax(zi)=Softmax(zi)⋅(δij−Softmax(zj))
当Softmax饱和时:
- 如果iii是最大值位置:Softmax(zi)≈1\text{Softmax}(z_i) \approx 1Softmax(zi)≈1,其他Softmax(zj)≈0\text{Softmax}(z_j) \approx 0Softmax(zj)≈0
- 梯度变为:∂Softmax(zi)∂zj≈δij−0=δij\frac{\partial \text{Softmax}(z_i)}{\partial z_j} \approx \delta_{ij} - 0 = \delta_{ij}∂zj∂Softmax(zi)≈δij−0=δij
- 只有i=ji=ji=j时梯度为1,其余均为0,导致梯度无法传播
4. 缩放操作的解决原理
通过除以 sqrt(d_k) 进行缩放:
Scaled(Q,K)=Q⋅K⊤dk \text{Scaled}(Q,K) = \frac{Q \cdot K^\top}{\sqrt{d_k}} Scaled(Q,K)=dk Q⋅K⊤
缩放后,点积结果的方差变为1:
Var(QK⊤dk)=dkdk=1 \text{Var}\left(\frac{Q K^\top}{\sqrt{d_k}}\right) = \frac{d_k}{d_k} = 1 Var(dk QK⊤)=dkdk=1
效果:点积结果稳定在-2, 2区间,Softmax不会饱和,梯度正常流动。
五、课堂总结与回顾
-
Transformer地位:AI大模型的核心基石,彻底解决了传统RNN/LSTM串行计算效率低、长文本语义丢失两大痛点
-
核心架构:编码器(语义理解)+ 解码器(内容生成),核心是多头自注意力
-
自注意力完整流程 :
词嵌入+位置编码 → 三套权重生成QKV向量 → Q·K点积计算相似度 → 除以sqrt(d_k)缩放 → Softmax归一化 → 加权融合V向量输出 -
主流模型:GPT、文心一言、通义千问等均基于Transformer架构
面试极简速记版
- Transformer:大模型基石,解决串行计算+长距离依赖两大问题
- 结构:编码器(理解)+解码器(生成),核心是多头自注意力
- 自注意力流程:嵌入+位置编码→生成QKV→相似度计算→sqrt(d_k)缩放→Softmax→加权融合
- 缩放目的:防Softmax饱和,避免梯度消失
关键公式速查
| 公式 | 名称 | 作用 |
|---|---|---|
| Q⋅K⊤/dkQ \cdot K^\top / \sqrt{d_k}Q⋅K⊤/dk | 缩放点积 | 计算注意力分数 |
| Softmax(zi)=ezi/∑jezj\text{Softmax}(z_i) = e^{z_i} / \sum_j e^{z_j}Softmax(zi)=ezi/∑jezj | Softmax | 归一化为概率分布 |
| Output=Attention(Q,K,V)⋅V\text{Output} = \text{Attention}(Q,K,V) \cdot VOutput=Attention(Q,K,V)⋅V | 注意力输出 | 加权融合值向量 |
| PE(pos,2i)=sin(pos/100002i/d)PE(pos, 2i) = \sin(pos/10000^{2i/d})PE(pos,2i)=sin(pos/100002i/d) | 位置编码 | 注入位置信息 |