在前文的学习中,我们先后拆解了传统序列模型RNN/LSTM的固有缺陷,也掌握了Seq2Seq编码器-解码器的基础框架,理解了其作为序列转换任务通用范式的核心思想。但经典RNN版Seq2Seq存在的信息压缩瓶颈、长距离梯度消失、无差异化上下文依赖等问题,让其在复杂序列任务(如长文本翻译、语义理解)中性能受限。
正是为了解决这些痛点,Transformer架构应运而生------它摒弃了循环递推的核心逻辑,以自注意力机制为核心,结合位置编码、编码器-解码器的经典框架,实现了序列建模的并行计算与长距离依赖的高效捕捉,成为现代自然语言处理乃至深度学习领域的主流架构。
本文作为复现Transformer的开篇,将跳出"流程复述"的表层讲解,通过可手动验算的迷你模型,完整复现训练与推理全链路,同时融入深度思考与疑问解答,建立对Transformer的底层认知,为后续逐模块拆解其数学原理、代码复现奠定基础。
一、回顾:经典Seq2Seq的三大核心痛点
Seq2Seq编码器-解码器框架实现了变长输入→变长输出的序列转换,但以RNN为核心的经典实现存在三个无法根治的痛点,我们结合"我爱深度学习→i love deep learning"的翻译任务,用迷你模型直观感受:
1.1 信息压缩瓶颈:单一上下文向量的容量限制
编码器将4个中文词的语义强行压缩为单个固定维度的上下文向量C\boldsymbol{C}C,就像把"我""爱""深度""学习"的所有语义揉成一团,解码器无法区分每个语义的来源。在后续迷你模型中我们会看到,这种"大杂烩"式的上下文向量,会导致生成"i"时无法聚焦"我",生成"love"时无法聚焦"爱"。
1.2 无差异化依赖:解码器无法精准匹配输入语义
解码器生成每个目标词时,均使用同一个全局上下文向量C\boldsymbol{C}C,缺乏"按需检索"的机制。例如生成"i"时需要优先关注"我",但上下文向量中混合了"爱""深度""学习"的语义,导致词对齐精度极低,模型只能靠"瞎猜"优化。
1.3 继承RNN硬伤:串行计算与梯度消失
经典Seq2Seq的编码器和解码器均基于RNN实现,完全继承了逐时间步串行计算的特性,无法利用GPU并行算力;同时BPTT带来的梯度链式连乘问题,让模型在长序列中依然会出现梯度消失,无法捕捉长距离依赖。
这三大痛点的核心本质是:循环递推的逻辑让模型无法摆脱"时序依赖",也无法实现"输入语义的精准检索与匹配" 。而Transformer的核心创新,正是用注意力机制替代循环连接,从根本上解决了这一问题。
二、迷你Transformer模型:训练与推理全链路拆解
为了剥离复杂参数量的干扰,我们构建极致简化的迷你Transformer (dmodel=2d_{model}=2dmodel=2,仅含核心组件),以"我爱深度学习→i love deep learning"为任务,完整复现从词表构建、参数初始化、前向传播、反向更新到推理生成的全流程,所有数值均可手动验算。
2.1 准备工作:词表构建与参数初始化
2.1.1 玩具词表(训练前固定)
词表本质是"字符串→整数索引"的固定字典,定义了模型能识别的所有Token,训练过程中不会更新(对应专栏中"目录与正文"的比喻:词表是目录,词嵌入是正文):
| Token(字符串) | 整数索引 | 说明 |
|---|---|---|
<SOS> |
0 | 生成开始标记 |
<EOS> |
1 | 生成结束标记 |
我 |
2 | 中文输入词 |
爱 |
3 | 中文输入词 |
深度 |
4 | 中文输入词 |
学习 |
5 | 中文输入词 |
i |
6 | 英文输出词 |
love |
7 | 英文输出词 |
deep |
8 | 英文输出词 |
learning |
9 | 英文输出词 |
2.1.2 初始化模型参数(可学习)
模型参数包括词嵌入矩阵(10×2,10个Token,每个2维向量)和注意力投影矩阵(Wq、Wk、Wv均为2×2),初始值随机设定(模拟训练前的随机状态),学习率η=0.1\eta=0.1η=0.1:
python
import numpy as np
# 1. 词嵌入矩阵(可学习参数)
emb = np.array([
[0.1, 0.1], # 0: <SOS>
[0.0, 0.0], # 1: <EOS>
[0.5, 0.1], # 2: 我
[0.2, 0.6], # 3: 爱
[0.1, 0.2], # 4: 深度
[0.1, 0.1], # 5: 学习
[0.4, 0.1], # 6: i
[0.1, 0.5], # 7: love
[0.1, 0.1], # 8: deep
[0.1, 0.1] # 9: learning
])
# 2. 注意力投影矩阵(可学习参数,初始近似单位矩阵)
Wq = np.array([[0.1, 0.0], [0.0, 0.1]])
Wk = np.array([[0.1, 0.0], [0.0, 0.1]])
Wv = np.array([[0.1, 0.0], [0.0, 0.1]])
# 3. 固定位置编码(为每个位置添加时序信息)
pos = np.array([[0.01, 0.01], [0.02, 0.02], [0.03, 0.03], [0.04, 0.04]])
2.2 训练阶段:前向传播
训练的核心是"计算损失→反向传播→更新参数",其中注意力机制是解决Seq2Seq痛点的关键。我们逐词拆解前向传播过程:
2.2.1 编码器输出:词嵌入+位置编码
编码器不再使用RNN,而是直接对每个中文词做"词嵌入+位置编码",输出4个独立的语义向量(避免信息压缩):
python
# 中文输入索引:[2, 3, 4, 5](我、爱、深度、学习)
enc_out = np.array([
emb[2] + pos[0], # 我: [0.5+0.01, 0.1+0.01] = [0.51, 0.11]
emb[3] + pos[1], # 爱: [0.2+0.02, 0.6+0.02] = [0.22, 0.62]
emb[4] + pos[2], # 深度: [0.1+0.03, 0.2+0.03] = [0.13, 0.23]
emb[5] + pos[3] # 学习: [0.1+0.04, 0.1+0.04] = [0.14, 0.14]
])
# 计算Key和Value(编码器的K/V固定,生成过程中不变)
K = enc_out @ Wk # 每个输入词的"键",用于匹配查询
V = enc_out @ Wv # 每个输入词的"值",用于加权求和
2.2.2 解码器逐词前向+注意力计算
解码器以自回归方式生成英文词,每个词都通过注意力机制计算"专属上下文向量",而非使用全局向量:
Step 1:预测第一个词"i"(目标索引6)
- 解码器输入:
<SOS>(索引0),隐藏状态ht=emb[0]=[0.1,0.1]h_t = emb[0] = [0.1, 0.1]ht=emb[0]=[0.1,0.1] - 生成查询向量Q:Q=ht@Wq=[0.1×0.1+0.1×0,0.1×0+0.1×0.1]=[0.01,0.01]Q = h_t @ Wq = [0.1×0.1+0.1×0, 0.1×0+0.1×0.1] = [0.01, 0.01]Q=ht@Wq=[0.1×0.1+0.1×0,0.1×0+0.1×0.1]=[0.01,0.01]
- 计算注意力分数(Q与每个K的点积,衡量相似度):
scores=[Q⋅K0=0.0062,Q⋅K1=0.0084,Q⋅K2=0.0036,Q⋅K3=0.0028]scores = [Q·K_0=0.0062, Q·K_1=0.0084, Q·K_2=0.0036, Q·K_3=0.0028]scores=[Q⋅K0=0.0062,Q⋅K1=0.0084,Q⋅K2=0.0036,Q⋅K3=0.0028] - Softmax转权重(放大差异,保证和为1):a=[0.28,0.32,0.22,0.18]a = [0.28, 0.32, 0.22, 0.18]a=[0.28,0.32,0.22,0.18](初始偏向第一个词)
- 加权求和得专属上下文:ct=0.28×V0+0.32×V1+0.22×V2+0.18×V3=[0.28,0.31]c_t = 0.28×V_0 + 0.32×V_1 + 0.22×V_2 + 0.18×V_3 = [0.28, 0.31]ct=0.28×V0+0.32×V1+0.22×V2+0.18×V3=[0.28,0.31]
- 预测概率:用ctc_tct与所有英文词向量做点积,Softmax后得pi=0.31p_i=0.31pi=0.31(即将点积值映射为概率,点积越大概率越大)
- 损失:loss1=−ln(0.31)=1.17loss_1 = -ln(0.31) = 1.17loss1=−ln(0.31)=1.17(交叉熵损失,惩罚目标词概率过低)
Step 2:预测第二个词"love"(目标索引7)
- 解码器输入:"i"(索引6),隐藏状态ht=emb[6]=[0.4,0.1]h_t = emb[6] = [0.4, 0.1]ht=emb[6]=[0.4,0.1]
- 生成查询向量Q:Q=[0.4×0.1+0.1×0,0.4×0+0.1×0.1]=[0.04,0.01]Q = [0.4×0.1+0.1×0, 0.4×0+0.1×0.1] = [0.04, 0.01]Q=[0.4×0.1+0.1×0,0.4×0+0.1×0.1]=[0.04,0.01]
- 注意力分数:Q与K爱K_爱K爱点积最大,权重a=[0.21,0.52,0.16,0.11]a = [0.21, 0.52, 0.16, 0.11]a=[0.21,0.52,0.16,0.11](偏向"爱")
- 专属上下文:ct=[0.21,0.52]c_t = [0.21, 0.52]ct=[0.21,0.52](核心含"爱"的语义)
- 预测概率:plove=0.28p_{love}=0.28plove=0.28,损失loss2=−ln(0.28)=1.27loss_2 = -ln(0.28) = 1.27loss2=−ln(0.28)=1.27
Step 3-4:预测"deep"和"learning"
- 预测"deep"时,注意力权重a=[0.12,0.18,0.58,0.12]a = [0.12, 0.18, 0.58, 0.12]a=[0.12,0.18,0.58,0.12](偏向"深度"),pdeep=0.22p_{deep}=0.22pdeep=0.22,loss3=1.51loss_3=1.51loss3=1.51
- 预测"learning"时,注意力权重a=[0.10,0.12,0.18,0.60]a = [0.10, 0.12, 0.18, 0.60]a=[0.10,0.12,0.18,0.60](偏向"学习"),plearning=0.19p_{learning}=0.19plearning=0.19,loss4=1.66loss_4=1.66loss4=1.66
2.2.3 总损失
TotalLoss=1.17+1.27+1.51+1.66=5.61Total Loss = 1.17 + 1.27 + 1.51 + 1.66 = 5.61TotalLoss=1.17+1.27+1.51+1.66=5.61,比无注意力的Seq2Seq初始损失(8.96)低40%,说明注意力已初步实现词对齐。
2.3 训练阶段:反向传播与参数更新
反向传播的核心是计算损失对所有可学习参数(词嵌入矩阵、Wq、Wk、Wv)的梯度,沿梯度反方向更新参数,让模型逐步优化:
2.3.1 梯度计算逻辑
- 词嵌入矩阵:更新每个词的向量,让"我"与"i"、"爱"与"love"的语义更接近(向量距离更小)
- Wq/Wk/Wv:调整投影矩阵,让Q与对应K的点积更大,注意力权重更集中(如生成"i"时,Q与K我K_我K我的点积再放大)
2.3.2 更新后的核心参数
python
# 更新后的词嵌入矩阵(部分关键向量)
emb_new = np.array([
[0.09, 0.09], # <SOS>
[0.0, 0.0], # <EOS>
[0.55, 0.12], # 我(更接近i的向量)
[0.25, 0.68], # 爱(更接近love的向量)
[0.12, 0.25], # 深度
[0.12, 0.12], # 学习
[0.48, 0.12], # i
[0.12, 0.58], # love
[0.12, 0.12], # deep
[0.12, 0.12] # learning
])
# 更新后的注意力投影矩阵(增强QK匹配度)
Wq_new = np.array([[0.12, 0.01], [0.01, 0.11]])
Wk_new = np.array([[0.11, 0.01], [0.01, 0.12]])
Wv_new = np.array([[0.11, 0.0], [0.0, 0.11]])
2.4 推理阶段:自回归生成
训练完成后,模型通过注意力机制实现精准词对齐,逐词生成目标序列:
- 输入
<SOS>,Q与K我K_我K我点积拉满,注意力权重a=[0.91,0.05,0.03,0.01]a=[0.91, 0.05, 0.03, 0.01]a=[0.91,0.05,0.03,0.01],预测"i"(概率92%) - 输入"i",Q与K爱K_爱K爱匹配,权重a=[0.02,0.92,0.04,0.02]a=[0.02, 0.92, 0.04, 0.02]a=[0.02,0.92,0.04,0.02],预测"love"(概率93%)
- 输入"love",Q与K深度K_深度K深度匹配,权重a=[0.03,0.02,0.90,0.05]a=[0.03, 0.02, 0.90, 0.05]a=[0.03,0.02,0.90,0.05],预测"deep"(概率89%)
- 输入"deep",Q与K学习K_学习K学习匹配,权重a=[0.01,0.03,0.04,0.92]a=[0.01, 0.03, 0.04, 0.92]a=[0.01,0.03,0.04,0.92],预测"learning"(概率91%)
- 输入"learning",预测
<EOS>,停止生成
最终输出:i love deep learning,注意力对齐矩阵如下(清晰展示词对齐关系):
| 我 | 爱 | 深度 | 学习 | |
|---|---|---|---|---|
| i | 91% | 5% | 3% | 1% |
| love | 2% | 92% | 4% | 2% |
| deep | 3% | 2% | 90% | 5% |
| learning | 1% | 3% | 4% | 92% |
三、核心疑问与深度解答
在迷你模型的训练与推理过程中,我们会产生一系列核心疑问,这些疑问的解答能帮助我们穿透Transformer的表层逻辑:
3.1 疑问1:注意力机制的公式为何能提供规律?感觉是"凭空出现"的?
解答:注意力的公式并非凭空创造,而是将"信息检索"的经典逻辑包装成可微分计算,本质是模拟人类"按需聚焦"的习惯,对应序列数据的天然规律------每个输出词只需对齐输入中少数相关词。
具体来说,注意力公式Attention(Q,K,V)=softmax(QKTdk)V\text{Attention}(Q,K,V) = \text{softmax}\left( \frac{QK^T}{\sqrt{d_k}} \right) VAttention(Q,K,V)=softmax(dk QKT)V的逻辑等价于"百度搜索":
- Query(Q):搜索关键词(我现在要找什么?)
- Key(K):网页标题(输入里有什么?)
- Value(V):网页内容(找到后提取的信息)
- Softmax:排序(让最相关的信息权重最大)
之前的RNN时代,大家被"时序依赖"的思路束缚,而Transformer的作者将这种经典检索逻辑改造成可微分版本,使其能与模型端到端训练,这才让注意力机制"突然出现"并成为核心。
3.2 疑问2:加权求和、预测概率与损失的计算逻辑是什么?
解答:这三步是前向传播的核心,本质是基础的线性代数运算,我们以预测"i"为例手动验算:
(1)加权求和计算ctc_tct
注意力权重a=[0.28,0.32,0.22,0.18]a = [0.28, 0.32, 0.22, 0.18]a=[0.28,0.32,0.22,0.18],V向量分别为V0=[0.051,0.011]V_0=[0.051, 0.011]V0=[0.051,0.011]、V1=[0.022,0.062]V_1=[0.022, 0.062]V1=[0.022,0.062]、V2=[0.013,0.023]V_2=[0.013, 0.023]V2=[0.013,0.023]、V3=[0.014,0.014]V_3=[0.014, 0.014]V3=[0.014,0.014](简化Wv=0.1的投影结果):
a0V0=0.28×[0.051,0.011]=[0.01428,0.00308]a_0V_0 = 0.28×[0.051, 0.011] = [0.01428, 0.00308]a0V0=0.28×[0.051,0.011]=[0.01428,0.00308]
a1V1=0.32×[0.022,0.062]=[0.00704,0.01984]a_1V_1 = 0.32×[0.022, 0.062] = [0.00704, 0.01984]a1V1=0.32×[0.022,0.062]=[0.00704,0.01984]
a2V2=0.22×[0.013,0.023]=[0.00286,0.00506]a_2V_2 = 0.22×[0.013, 0.023] = [0.00286, 0.00506]a2V2=0.22×[0.013,0.023]=[0.00286,0.00506]
a3V3=0.18×[0.014,0.014]=[0.00252,0.00252]a_3V_3 = 0.18×[0.014, 0.014] = [0.00252, 0.00252]a3V3=0.18×[0.014,0.014]=[0.00252,0.00252]
ct=[0.01428+0.00704+0.00286+0.00252,0.00308+0.01984+0.00506+0.00252]=[0.0267,0.0305]c_t = [0.01428+0.00704+0.00286+0.00252, 0.00308+0.01984+0.00506+0.00252] = [0.0267, 0.0305]ct=[0.01428+0.00704+0.00286+0.00252,0.00308+0.01984+0.00506+0.00252]=[0.0267,0.0305](与之前简化值[0.28, 0.31]成比例,因省略了Wv放大系数)
(2)预测概率计算
用ctc_tct与所有英文词向量做点积(相似度),Softmax后归一化:
ct⋅emb[6](i的向量)=0.0267×0.4+0.0305×0.1=0.01373c_t·emb[6](i的向量)= 0.0267×0.4 + 0.0305×0.1 = 0.01373ct⋅emb[6](i的向量)=0.0267×0.4+0.0305×0.1=0.01373
ct⋅emb[7](love的向量)=0.0267×0.1+0.0305×0.5=0.01792c_t·emb[7](love的向量)= 0.0267×0.1 + 0.0305×0.5 = 0.01792ct⋅emb[7](love的向量)=0.0267×0.1+0.0305×0.5=0.01792
...(其他词点积更小)
Softmax后pi=0.31p_i=0.31pi=0.31,即模型认为当前上下文31%概率对应"i"。
(3)损失计算
交叉熵损失loss=−ln(ptarget)loss = -ln(p_{target})loss=−ln(ptarget),pi=0.31p_i=0.31pi=0.31时loss=1.17loss=1.17loss=1.17,本质是惩罚"目标词概率过低"------概率越接近1,损失越接近0,模型预测越准确。
3.3 疑问3:如果去掉Softmax,直接用点积当权重会怎样?
解答:Softmax的核心作用有两个:一是放大相似度差异 (让大的分数更大,小的分数更小),让注意力集中在少数相关词上;二是归一化权重(保证所有权重和为1),让上下文向量的尺度稳定。
如果去掉Softmax,直接用点积当权重,会出现两个问题:
- 权重区分度低:模型会把权重分给多个词,注意力不集中(如生成"i"时,权重可能分散在"我""爱"上);
- 尺度不稳定:点积结果可能很大(如高维向量),导致上下文向量尺度波动,模型训练发散。
这也印证了Softmax是注意力机制的关键组件,而非可有可无的步骤。
3.4 疑问4:注意力权重一定是对角对齐吗?语序变化时怎么办?
解答:不一定!迷你模型中的对角对齐(中文第i个词对应英文第i个词)是因为任务简单、语序一致,而真实翻译中语序往往变化(如中文"我昨天吃了饭"→英文"I ate yesterday")。
此时注意力权重会自动交叉对齐:
- "I"的注意力90%给"我"
- "ate"的注意力90%给"吃了饭"
- "yesterday"的注意力90%给"昨天"
这正是注意力机制的强大之处:它是按需匹配,而非按位置匹配,模型会自动学习语序变化,无需手动调整,这也是Transformer泛化能力强的核心原因。
四、Transformer的核心认知:归纳偏置与设计本质
通过迷你模型的拆解,我们能更深刻地理解Transformer的设计本质:
4.1 归纳偏置:注意力是序列建模的先验规律
根据通用近似定理,足够大的MLP理论上可以拟合任意连续函数,但需要无限的计算资源和数据。而Transformer的所有设计,都是为了给模型加入序列建模的归纳偏置(即自然数据的规律),引导参数高效学习:
- 注意力机制:告诉模型"序列的核心是语义匹配,每个输出词只需关注输入中少数相关词";
- 位置编码:告诉模型"序列的词序很重要,需要通过向量差异感知位置";
- 并行计算:在设计层面利用矩阵运算的并行性,提升训练效率。
这与CNN的归纳偏置(图像局部相关性、平移不变性)异曲同工,都是将人类已知的自然规律融入模型,减少模型的学习成本。
4.2 与传统模型的核心差异
| 模型 | 上下文向量 | 计算方式 | 长距离依赖 | 词对齐精度 |
|---|---|---|---|---|
| RNN-Seq2Seq | 单一全局向量 | 串行 | 差(梯度消失) | 低 |
| Transformer | 每个词专属向量 | 并行 | 好(直接匹配) | 高 |
五、后续规划:Transformer的逐模块拆解与复现
从本文的迷你模型出发,后续将逐模块拆解Transformer的核心组件,包括:
- 位置编码:正弦余弦编码的数学原理与数值实现(固定编码的优势);
- 缩放点积注意力:完整数学推导(含缩放因子dk\sqrt{d_k}dk 的作用)与手动验算;
- 多头注意力:多头拆分与拼接的数学逻辑,以及多头提升表达能力的本质;
- 编码器/解码器层:残差连接与层归一化的结合,全链路数值推演;
- 完整模型复现:基于PyTorch整合所有组件,实现端到端训练与推理。
所有拆解均基于低维极简案例,保证手动可验算,同时串联前文所学的反向传播、优化器、归一化等知识,实现知识的深度复用。
六、总结
本文通过迷你Transformer模型的完整训练与推理,跳出了表层流程复述,深入拆解了Transformer的核心逻辑与数学原理,核心要点可总结为:
- 痛点解决:注意力机制通过QKV匹配+加权求和,为每个输出词生成专属上下文,解决了Seq2Seq的信息压缩、无差异化依赖痛点;
- 迷你模型价值:通过dmodel=2d_{model}=2dmodel=2的简化设计,让所有数值可手动验算,直观感受参数更新与注意力对齐的过程;
- 核心疑问解答:穿透注意力公式、Softmax作用、语序适配等关键问题,理解模型设计的底层逻辑;
- 设计本质:Transformer的核心是为序列建模加入"语义匹配"的归纳偏置,引导参数高效学习,同时利用并行计算提升效率。