Transformer - day02- Decoder
原始Transformer架构
| 序号 | 环节 | 英文名称 | 作用 |
|---|---|---|---|
| 1 | 输入嵌入层 | Input Embedding | 将输入词元转为向量 |
| 2 | 位置编码 | Positional Encoding | 注入序列位置信息 |
| 3 | 编码器 | Encoder | 由6层相同结构堆叠,负责理解输入序列 |
| 4 | 解码器 | Decoder | 由6层相同结构堆叠,负责生成输出序列 |
| 5 | 输出映射层 | Linear + Softmax | 将解码器输出转为最终词的概率分布 |
此外,在现代深度学习语境中,“Transformer”已演变为一个大家族:
- 仅编码器(Encoder-Only):如 BERT,适合分类、理解任务。
- 仅解码器(Decoder-Only):如 GPT,适合生成任务。
- 编码器-解码器(Encoder-Decoder):如原始Transformer、T5,适合序列到序列任务(如翻译、摘要)。
解码器 Decoder
输出嵌入(Output Embedding)
- 在原始 Transformer 中,输出嵌入层(Output Embedding) 和 解码器最后的线性层(Linear Layer / Softmax 前的投影层) 是共享权重(Weight Tying)的,只是转置使用
- 作用:
- 输入是 目标(结果)序列,将其 映射 成 固定维度的向量
位置编码(Positional Encoding)
- 同 编码器 环节,目标序列注入位置信息(顺序)
- 使用正弦/余弦函数或可学习参数 (函数形式参考前面编码器)
带掩码的多头自注意力(Masked Multi-Head Self-Attention)
- 解码器 层的 第 1 个 子层
- 计算目标 序列内部 词与词 之间的依赖关系
- 带 掩码(Mask)
- 确保在预测第 t 个词时,只能看到第 1 到 t-1 个词(已生成的词)
输入
- 来自上一环节,即解码器经过 嵌入编码、位置编码后 的结果
- 形状
- batch_size × 目标序列长度 × d_model ,例如:(32, 6, 512)
- batch_size 是你自己定义的 批次大小,赋值多大看前面编码器,影响计算效率
- 6 根据你的训练集情况赋值,即 你训练集的目标结果的 最大 长度
- d_model 也是你自己定义的,看前面Encoder的举例,d_model= 512
- batch_size × 目标序列长度 × d_model ,例如:(32, 6, 512)
中间件(转换过程,5个步骤)
STEP 1:线性变换并拆解多头(与编码器相同)
- 输入矩阵 X(形状 32, 6, 512)分别乘以三个权重矩阵 \(W_Q, W_K, W_V\),得到 Q、K、V
- 将 Q、K、V 在特征维度上拆成 h=8 个头,每个头的形状变为 (32, 6, 64)
- 举例:
| 参数 | 说明 | |
|---|---|---|
| 批次大小 | Batch = 1 | 只处理这一句 |
| 序列长度 | L = 4 | 对应解码器输入: |
| 模型维度 | d_model = 4 | 就是前面例子中的512,为了简化计算这里改成了4 |
| 多头数 | h = 2 | 所以每个头的维度 \(d_k = d_v = 4/2 = 2\) |
- 假设:输入矩阵 X(形状 4×4),由“输出嵌入 + 位置编码”得到
| 位置 | 参数 | 说明 |
|---|---|---|
| 位置0 | <(START)> | [1.0, 0.5, 0.0, 0.5] |
| 位置1 | (I) | [0.8, 0.6, 0.2, 0.4] |
| 位置2 | (love) | [0.2, 0.9, 0.3, 0.1] |
| 位置3 | (AI) | [0.4, 0.7, 0.5, 0.2] |
- 计算 Q、K、V(拆解成2个头)
- 我们假设经过权重矩阵 \(W_Q, W_K, W_V\) 计算后,得到了每个头的 \(Q、K、V\)(形状 4×2)
- 为了演示第4步的掩码的作用过程,我们只看 头1(Head 1) 的数据
| 位置 | 头1的 Q 矩阵 (4×2) | 头1的 K 矩阵 (4×2) | 头1的 V 矩阵(4×2) |
|---|---|---|---|
| 位置0 | [1.0, 0.5] | [0.9, 0.4] | [0.2, 0.8] |
| 位置1 | [0.8, 0.6] | [0.7, 0.5] | [0.5, 0.3] |
| 位置2 | [0.2, 0.9] | [0.3, 0.8] | [0.7, 0.1] |
| 位置3 | [0.4, 0.7] | [0.5, 0.6] | [0.4, 0.6] |
STEP2 :计算原始注意力分数(Scores)
- 计算 \(Scores = Q · K^T\)(暂时忽略除以 \(\sqrt(d_k)\) 的缩放,这不影响掩码逻辑
- 结果是一个 4×4 的矩阵
- 行代表当前位置(查询 Q),列代表所有位置(键 K),原始分数矩阵(4×4)
| 查询\键 | 位置0 (START) | 位置1 (I) | 位置2 (love) | 位置3 (AI) |
|---|---|---|---|---|
| 位置0 | \(1.0*0.9+0.5*0.4 = 1.1\) | 0.95 | 0.70 | 0.80 |
| 位置1 | \(0.8*0.9+0.6*0.4 = 0.96\) | 0.86 | 0.72 | 0.76 |
| 位置2 | \(0.2*0.9+0.9*0.4 = 0.54\) | 0.59 | 0.78 | 0.64 |
| 位置3 | \(0.4*0.9+0.7*0.4 = 0.64\) | 0.63 | 0.68 | 0.62 |
- 注意:第 2 行(love)对应第 3 列(AI)的分数是 0.64,说明如果不加掩码,模型在理解“love”时,会关注到未来的“AI”;其他同理
STEP 3 :应用未来掩码(Masking)
- 用代码 生成一个 上三角掩码矩阵,将所有 列索引(j) > 行索引(i) 的位置替换为 -inf(负无穷)
掩码后的 Scores矩阵:
| 查询\键 | 位置0 (START) | 位置1 (I) | 位置2 (love) | 位置3 (AI) |
|---|---|---|---|---|
| 位置0 | 1.1 | -inf | -inf | -inf |
| 位置1 | 0.96 | 0.86 | -inf | -inf |
| 位置2 | 0.54 | 0.59 | 0.78 | -inf |
| 位置3 | 0.64 | 0.63 | 0.68 | 0.62 |
STEP 4 :Softmax 归一化(权重变为概率)-- 所谓 激活
- 对每一行执行 \(Softmax(t)=\frac{1}{1+e^{-t}}\),所有未来位置的权重直接变成 0
| 位置权重 | 说明 | 近似计算 |
|---|---|---|
| 位置0 的权重 | 只能看到自己 | \([1.0, \color{red}{0}, \color{red}{0}, \color{red}{0}]\) |
| 位置1 的权重 | 只关注位置0和1 | \([0.52, 0.48, \color{red}{0}, \color{red}{0}]\) |
| 位置2 的权重 | 只关注位置0、1、2 | \([0.30, 0.32, 0.38, \color{red}{0} ]\) |
| 位置3 的权重 | 没有被遮住任何位置 | \([0.24, 0.23, 0.26, 0.27]\) |
STEP 5 :加权聚合(计算最终输出 Z)
- 前面计算过 头1 的 V 矩阵(4×2),V 矩阵如下:
\(V =\begin{bmatrix} 0.2 & 0.8 \\ 0.5 & 0.3 \\ 0.7 & 0.1\\ 0.4 & 0.6 \end{bmatrix}\) - 计算 \(Z = 权重矩阵 · V\),权重矩阵来自上面 第5步Softmax归一化 的结果
对于 头1,计算输出 Z1(4×2)
-
\(Z_1[i] = 权重矩阵第i行 · V矩阵\)
-
位置0 的输出:
- \(1.0*[0.2, 0.8] + \color{red}{0}*[0.5,0.3] + \color{red}{0}*[0.7,0.1] + \color{red}{0}*[0.4,0.6] = \color{red}{[0.2, 0.8]}\)
-
位置1 的输出:
- \(0.525*[0.2,0.8] + 0.475*[0.5,0.3] = [0.105+0.2375, 0.42+0.1425] = \color{red}{[0.3425, 0.5625]}\)
-
位置2 的输出:
- \(0.302*[0.2,0.8] + 0.316*[0.5,0.3] + 0.382*[0.7,0.1] = [0.0604+0.158+0.2674, 0.2416+0.0948+0.0382] = \color{red}{[0.4858, 0.3746]}\)
-
位置3 的输出:
- \(0.250*[0.2,0.8] + 0.247*[0.5,0.3] + 0.259*[0.7,0.1] + 0.244*[0.4,0.6] = [0.05+0.1235+0.1813+0.0976, 0.2+0.0741+0.0259+0.1464] = \color{red}{[0.4524, 0.4464]}\)
-
因此,头1的输出矩阵 Z1 为:
\(Z_1 =\begin{bmatrix} 0.2 & 0.8 \\ 0.3425 & 0.5625 \\ 0.4858 & 0.3746\\ 0.4524 & 0.4464 \end{bmatrix}\)
对于 头2,计算输出 Z2(4×2)
- \(Z_2[i] = 权重矩阵第i行 · V矩阵\)
| 头2 | 注意力权重矩阵(4×4) | V矩阵(4×2) |
|---|---|---|
| \(\begin{array} \\位置0\\位置1\\位置2\\位置3 \end{array}\) | \(\begin{bmatrix} 1.0&0&0&0\\0.562&0.438&0&0\\0.343&0.382&0.275&0\\0.282&0.187&0.318&0.213\end{bmatrix}\) | \(\begin{bmatrix} 0.3& 0.5 \\0.8& 0.2\\0.1& 0.7\\0.6& 0.4\end{bmatrix}\) |
-
位置0 的输出:
- \(1.0*[0.3, 0.5] = \color{red}{[0.3, 0.5]}\)
-
位置1 的输出:
- \(0.562*[0.3,0.5] + 0.438*[0.8,0.2] = [0.1686+0.3504, 0.281+0.0876] = \color{red}{[0.519, 0.3686]}\)
-
位置2 的输出:
- \(0.343*[0.3,0.5] + 0.382*[0.8,0.2] + 0.275*[0.1,0.7] = [0.1029+0.3056+0.0275, 0.1715+0.0764+0.1925] = \color{red}{[0.436, 0.4404]}\)
-
位置3 的输出:
- \(0.282*[0.3,0.5] + 0.187*[0.8,0.2] + 0.318*[0.1,0.7] + 0.213*[0.6,0.4] = [0.0846+0.1496+0.0318+0.1278, 0.141+0.0374+0.2226+0.0852] = \color{red}{[0.3938, 0.4862]}\)
-
因此,头2的输出矩阵 Z2 为:
\(Z_2 =\begin{bmatrix} 0.3& 0.5 \\ 0.519& 0.3686 \\ 0.436& 0.4404\\ 0.3938& 0.4862 \end{bmatrix}\)
STEP 6 :多头拼接与输出
- 头1和头2执行完全相同的计算(只是 Q、K、V 矩阵不同)
- 将两个头的输出(每个 4×2)在特征维度上拼接,得到 4×4 的矩阵,
- 再 乘以输出投影矩阵 \(W_O\),最终得到 带掩码自注意力层的最终输出
形状依然是 4×4
STEP 1 :拼接(Concat)
- 将头1的输出 Z1(4×2)和头2的输出 Z2(4×2)在特征维度(列)上拼接,得到 Z_concat(4×4)
\(Z_{concat}= [Z_1\ |\ Z_2]=\begin{bmatrix} 0.2 & 0.8 & 0.3 & 0.5 \\0.3425 & 0.5625 & 0.519 & 0.3686 \\ 0.4858 & 0.3746 & 0.436 & 0.4404 \\0.4524 & 0.4464 & 0.3938 & 0.4862 \end{bmatrix}\)
STEP 2 :输出投影(乘以 \(W_O\))
-
将 拼接结果 乘以输出投影矩阵 \(W_O\)(4×4)
-
计算最终输出 $ Output_{Final} = Z_{concat} · W_{O} $
-
假设
\(W_O = \begin{bmatrix} 0.5& 0.3& 0.2& 0.0 \\ 0.1& 0.6& 0.1& 0.2 \\ 0.0& 0.2& 0.5& 0.3 \\ 0.4& 0.0& 0.2& 0.4 \end{bmatrix}\) -
位置0 的输出(\(Z_{concat}[0] = [0.2, 0.8, 0.3, 0.5]\)):
- 列0:\(0.2*0.5 + 0.8*0.1 + 0.3*0 + 0.5*0.4 = 0.10+0.08+0+0.20 = 0.38\)
- 列1:\(0.2*0.3 + 0.8*0.6 + 0.3*0.2 + 0.5*0 = 0.06+0.48+0.06+0 = 0.60\)
- 列2:\(0.2*0.2 + 0.8*0.1 + 0.3*0.5 + 0.5*0.2 = 0.04+0.08+0.15+0.10 = 0.37\)
- 列3:\(0.2*0 + 0.8*0.2 + 0.3*0.3 + 0.5*0.4 = 0+0.16+0.09+0.20 = 0.45\)
- 结果:\(\color{red}{\begin{bmatrix} 0.38& 0.60& 0.37& 0.45 \end{bmatrix}}\)
-
位置1 的输出(\(Z_{concat}[1] = [0.3425, 0.5625, 0.519, 0.3686]\)):
- 列0:\(0.3425*0.5 + 0.5625*0.1 + 0.519*0 + 0.3686*0.4 = 0.17125+0.05625+0+0.14744 = 0.37494\)
- 列1:\(0.3425*0.3 + 0.5625*0.6 + 0.519*0.2 + 0.3686*0 = 0.10275+0.3375+0.1038+0 = 0.54405\)
- 列2:\(0.3425*0.2 + 0.5625*0.1 + 0.519*0.5 + 0.3686*0.2 = 0.0685+0.05625+0.2595+0.07372 = 0.45797\)
- 列3:\(0.3425*0 + 0.5625*0.2 + 0.519*0.3 + 0.3686*0.4 = 0+0.1125+0.1557+0.14744 = 0.41564\)
- 结果:\(\color{red}{\begin{bmatrix} 0.37494& 0.54405& 0.45797& 0.41564 \end{bmatrix}}\)
-
位置2 的输出(\(Z_{concat}[2] = [0.4858, 0.3746, 0.436, 0.4404]\)):
- 列0:\(0.4858*0.5 + 0.3746*0.1 + 0.436*0 + 0.4404*0.4 = 0.2429+0.03746+0+0.17616 = 0.45652\)
- 列1:\(0.4858*0.3 + 0.3746*0.6 + 0.436*0.2 + 0.4404*0 = 0.14574+0.22476+0.0872+0 = 0.45770\)
- 列2:\(0.4858*0.2 + 0.3746*0.1 + 0.436*0.5 + 0.4404*0.2 = 0.09716+0.03746+0.218+0.08808 = 0.44070\)
- 列3:\(0.4858*0 + 0.3746*0.2 + 0.436*0.3 + 0.4404*0.4 = 0+0.07492+0.1308+0.17616 = 0.38188\)
- 结果:\(\color{red}{\begin{bmatrix} 0.45652& 0.45770& 0.44070& 0.38188 \end{bmatrix}}\)
-
位置3 的输出(\(Z_{concat}[3] = [0.4524, 0.4464, 0.3938, 0.4862]\)):
- 列0:\(0.4524*0.5 + 0.4464*0.1 + 0.3938*0 + 0.4862*0.4 = 0.2262+0.04464+0+0.19448 = 0.46532\)
- 列1:\(0.4524*0.3 + 0.4464*0.6 + 0.3938*0.2 + 0.4862*0 = 0.13572+0.26784+0.07876+0 = 0.48232\)
- 列2:\(0.4524*0.2 + 0.4464*0.1 + 0.3938*0.5 + 0.4862*0.2 = 0.09048+0.04464+0.1969+0.09724 = 0.42926\)
- 列3:\(0.4524*0 + 0.4464*0.2 + 0.3938*0.3 + 0.4862*0.4 = 0+0.08928+0.11814+0.19448 = 0.40190\)
- 结果:\(\color{red}{\begin{bmatrix} 0.46532, 0.48232, 0.42926, 0.40190 \end{bmatrix}}\)
最终输出结果(形状 4×4)
- 经过 带掩码的多头自注意力 全部计算后,该子层的最终输出矩阵为
\({Output}_{Final} = \begin{bmatrix} 0.38& 0.60& 0.37& 0.45\\ 0.37494& 0.54405& 0.45797& 0.41564\\ 0.45652& 0.45770& 0.44070& 0.38188\\ 0.46532& 0.48232& 0.42926& 0.40190 \end{bmatrix}\)
输出
- 4×4 矩阵
输出的 \({Output}_{Final}\) 先做 Add & Norm 处理
- Add & Norm 参见 编码器 内容
- 把 原始输入 X 和 经过掩码注意力后的输出 相加,再标准化
-
原始输入 X(来自输出嵌入+位置编码,形状 4×4)
\(X = \begin{bmatrix} 1.0& 0.5& 0.0& 0.5\\ 0.8& 0.6& 0.2& 0.4\\ 0.2& 0.9& 0.3& 0.1\\ 0.4& 0.7& 0.5& 0.2 \end{bmatrix}\) -
掩码自注意力输出 Final_Output(上一步算出的,形状 4×4)
\({Output}_{Final} = \begin{bmatrix} 0.38& 0.60& 0.37& 0.45\\ 0.37494& 0.54405& 0.45797& 0.41564\\ 0.45652& 0.45770& 0.44070& 0.38188\\ 0.46532& 0.48232& 0.42926& 0.40190 \end{bmatrix}\)
-
残差连接(Add):Sum = X + Final_Output
- 逐元素相加,形状仍为 4×4
\(Sum = \begin{bmatrix} 1.38& 1.10& 0.37& 0.95\\ 1.1749& 1.1441& 0.6580& 0.8156\\ 0.6565& 1.3577& 0.7407& 0.4819\\ 0.8653& 1.1823& 0.9293& 0.6019 \end{bmatrix}\)
层归一化(Layer Norm)
- 对 Sum 的 每一行 独立做标准化
- 这里省略繁琐的 $ (x-μ)/σ$ 计算,直接给出归一化后的结果 Out1
- 解码器一共重复 6 次,这里只是 第 1 次 的 第 1 子层 的结果 Out1
\(Out1 = \begin{bmatrix} 1.12& 0.45& -1.34& 0.77\\ 0.85& 0.72& -1.21& 0.64\\ -0.62& 1.38& -0.85& 0.09\\ -0.35& 1.05& 0.18& -0.88 \end{bmatrix}\)
得到的结果,作为 Q1
- 形状仍然保持了原来的 4×4
- 然后和 编码器的 K1, V1,做 交叉注意力(Cross-Attention)
编码器-解码器注意力(Cross-Attention / Encoder-Decoder Attention)
- 解码器独有的环节,负责把 英文生成进度 和 中文源语言语义 对齐
输入
- 查询(Q):来自解码器上一步的输出 Out1
- 形状 4×4,代表英文端 [ START, I, love, AI ] 的当前状态
- 键(K)和值(V):来自编码器的最终输出 Enc_Out
- 形状 3×4,代表中文端 [ 我, 爱, AI ] 的语义
假设编码器之前输出的 Enc_Out 为(形状 3×4):
\(Enc\_Out = \begin{bmatrix} 0.5& 0.3& 0.9& 0.2\\ 0.8& 0.6& 0.4& 0.7\\ 0.1& 0.5& 0.3& 0.8 \end{bmatrix}\)
- 第 1 行,[0.5, 0.3, 0.9, 0.2],# 对应中文 "我"
- 第 2 行,[0.8, 0.6, 0.4, 0.7],# 对应中文 "爱"
- 第 3 行,[0.1, 0.5, 0.3, 0.8],# 对应中文 "AI"
中间转换过程(共 2×4 步)-- 交叉注意力计算
STEP 1 : 计算注意力分数 \(Scores\_cross = Q · K^T\)
- 这里用 Out1 直接作为Q,用 Enc_Out 直接作为K
- 形状是 4×3,行(4个英文位置) × 列(3个中文词)
- 算第 0 行(英文
对中文三个词的分数): - START 向量 [1.12, 0.45, -1.34, 0.77] 分别点乘中文三个向量:
- 对“我”:\(1.12*0.5 + 0.45*0.3 + (-1.34)*0.9 + 0.77*0.2 = 0.56+0.135-1.206+0.154 = -0.357\)
- 对“爱”:\(1.12*0.8 + 0.45*0.6 + (-1.34)*0.4 + 0.77*0.7 = 0.896+0.27-0.536+0.539 = 1.169\)
- 对“AI”:\(1.12*0.1 + 0.45*0.5 + (-1.34)*0.3 + 0.77*0.8 = 0.112+0.225-0.402+0.616 = 0.551\)
- START 向量 [1.12, 0.45, -1.34, 0.77] 分别点乘中文三个向量:
- 第 0 行分数为 \([-0.357\ \ \ \ 1.169\ \ \ \ 0.551]\)
- 做 Softmax 得到权重 \([0.12\ \ \ \ 0.58\ \ \ \ 0.30]\)(最关注“爱”)
- 算第 0 行(英文
STEP 2 : 用这个权重去加权聚合 V
- 这里 V 也直接使用 Enc_Out 的值
- \(加权输出_{第 0 行} = 0.12*[0.5,0.3,0.9,0.2] + 0.58*[0.8,0.6,0.4,0.7] + 0.30*[0.1,0.5,0.3,0.8]\)
- \(加权输出_{第 0 行} = [0.06+0.464+0.03, 0.036+0.348+0.15, 0.108+0.232+0.09, 0.024+0.406+0.24]\)
- \(加权输出_{第 0 行} = [0.554,\ \ \ \ 0.534,\ \ \ \ 0.430,\ \ \ \ 0.670]\)
重复上述 STEP 1 和 STEP 2,计算剩余的 行
- 上面计算了 第 0 行,还剩余的是:第1、2、3行
- 得到 交叉注意力输出 Cross_Out(形状 4×4)
\(Cross\_Out = \begin{bmatrix} 0.554& 0.534& 0.430& 0.670\\ 0.620& 0.480& 0.510& 0.590\\ 0.440& 0.560& 0.490& 0.630\\ 0.510& 0.520& 0.470& 0.600 \end{bmatrix}\) - 形状变化
- (4×4) · (4×3) = (4×3) → Softmax → (4×3) · (3×4) = (4×4)
- 完美保持了维度不变
子层 残差连接 + 层归一化(Add & Layer Norm)
子层 残差连接
- 子层2的输入 Out1 与 交叉注意力输出 Cross_Out 相加
- \(Sum2 = Out1 + Cross_Out\)
- 做 LayerNorm 得到 Out2(形状 4×4)
\(Out2 = \begin{bmatrix} 0.85& 0.50& -0.75& 1.20\\ 0.90& 0.70& -0.60& 1.10\\ 0.40& 1.00& -0.40& 0.80\\ 0.60& 0.90& -0.20& 0.70 \end{bmatrix}\)
前馈网络(Feed-Forward Network,FFN)
- 这一步对 每个位置 独立进行 非线性 变换
- 线性变换 --> ReLU 激活 --> 线性变换
- \(FFN(x) = ReLU(x·W_1 + b_1)·W_2 + b_2\)
计算举例
- 与前面对应,\(d\_model = 4\)
- \(d\_ff = \color{red}8\)(原论文中是 2048,这里为了演示缩小比例)
- 定义 可训练 的 权重矩阵 \(W_1, W_2\) 和 偏置向量 \(b_1, b_2\)
-
第 1 层权重 \(W_1\)(形状 \(d_{model} × d_{ff}\),这里是 4×8)
\(W_1 = \begin{bmatrix} 0.1& 0.2& 0.3& 0.0& 0.1& -0.1& 0.2& 0.0\\ 0.0& 0.1& -0.1& 0.2& 0.3& 0.0& 0.1& 0.2\\ 0.2& 0.0& 0.1& -0.1& 0.0& 0.2& 0.3& 0.1\\ 0.1& -0.1& 0.0& 0.2& 0.1& 0.0& -0.1& 0.3 \end{bmatrix}\) -
第 1 层偏置 \(b_1\)(长度 \(d_{ff}\),这里是 8)
\(b_1 = [0.1,\ \ \ \ 0.0,\ \ \ \ 0.1,\ \ \ \ -0.1,\ \ \ \ 0.0,\ \ \ \ 0.1,\ \ \ \ 0.0,\ \ \ \ -0.1]\) -
第 2 层权重 \(W_2\)(形状 \(d_{ff} × d_{model}\),这里是 8×4)
\(W_2 = \begin{bmatrix} 0.1& 0.2& 0.0& 0.1\\ 0.0& 0.1& 0.2& 0.0\\ 0.2& 0.0& 0.1& 0.2\\ 0.1& 0.1& 0.0& 0.3\\ 0.0& 0.2& 0.1& 0.0\\ 0.3& 0.0& 0.1& 0.2\\ 0.1& 0.2& 0.0& 0.1\\ 0.0& 0.1& 0.2& 0.0 \end{bmatrix}\) -
第 2 层偏置 \(b_2\)(长度 \(d_{model}\),这里是 4)
\(b_2 = [0.1,\ \ \ \ 0.0,\ \ \ \ 0.1,\ \ \ \ -0.1]\)
-
STEP 1 :第 1 次 线性变换
- 计算 \(Z = Out2 · W1 + b1\)(形状 4×8)
\(Z = \begin{bmatrix} 0.155& 0.10& 0.23& 0.315& 0.355& -0.135& -0.125& 0.285\\ 0.18& 0.14& 0.24& 0.32& 0.41& -0.11& -0.04& 0.31\\ 0.14& 0.10& 0.08& 0.30& 0.42& -0.02& -0.02& 0.30\\ 0.19& 0.14& 0.17& 0.24& 0.40& 0.0& 0.08& 0.27 \end{bmatrix}\)
STEP 2 :ReLU 函数 激活
- 计算 \(A = ReLU(Z)\),将负数置 0(形状 4×8)
\(A = \begin{bmatrix} 0.155& 0.10& 0.23& 0.315& 0.355& \color{red}0& \color{red}0& 0.285\\ 0.18& 0.14& 0.24& 0.32& 0.41& \color{red}0& \color{red}0& 0.31\\ 0.14& 0.10& 0.08& 0.30& 0.42& \color{red}0& \color{red}0& 0.30\\ 0.19& 0.14& 0.17& 0.24& 0.40& 0.0& 0.08& 0.27 \end{bmatrix}\)
STEP 3 :第 2 次 线性变换
- 计算 \(FFN\_Out = A · W2 + b2\)(形状 4×4)
\(FFN\_Out = \begin{bmatrix} 0.193& 0.172& 0.2355& 0.056\\ 0.198& 0.195& 0.255& 0.062\\ 0.160& 0.182& 0.230& 0.020\\ 0.185& 0.199& 0.239& 0.033 \end{bmatrix}\)
子层 残差连接 + 层归一化(Add & Layer Norm)
子层 残差连接
- 子层3的输入 Out2 与 前馈网络 FFN 输出 FFN_Out 相加
- \(Sum3 = Out2 + FFN\_Out\)
- 做 LayerNorm 得到 解码器第 1 次 的输出 Dec_Layer_Out_1(形状 4×4)
\(Dec\_Layer\_Out\_\color{red}1 = \begin{bmatrix} 1.10& 0.70& -0.80& 1.40\\ 1.05& 0.85& -0.55& 1.25\\ 0.65& 1.15& -0.20& 1.00\\ 0.80& 1.05& -0.05& 0.90 \end{bmatrix}\)
解码器 Decoder 核心层 总结
- 上述过程只是 第一次,原论文一共 重复 了 6 次
- 每一次包括:
- 带掩码的多头注意力
- 残差连接(相加)+ 层归一化
- 交叉(多头)注意力
- 残差连接(相加)+ 层归一化
- 前馈网络(Feed-Forward Network,FFN)
- 残差连接(相加)+ 层归一化
- 上述 6 个步骤,重复 6 次,得到 解码器最终输出 Dec_Out
- 形状依然是 4×4,本质上是 目标序列长度 L × 模型宽度 d_model
- 得到的结果 Dec_Out,送入 线性层 + Softmax 层
线性层(Linear Layer)
- 也叫 输出投影层(Output Projection Layer)
- 将 每个位置 的 d_model 维向量,映射到词汇表大小 Vocab_Size 维的空间
- 得到未归一化的分数 Logits 矩阵,形状是 (序列长度 L,词汇表大小 V)
- 哪一个位置的输出 分数越高,代表模型认为 词汇表 中该位置 对应那个词的概率越大
- 例如
- 举例中的英文词汇表是 {<START>:0, I:1, love:2, AI:3, <EOS>:4, <PAD>:5},Vocab_Size V=6
输入 Dec_Out
- 输入:解码器最后一层(第6层)的输出 Dec_Out
- 形状:(序列长度 L, d_model) = (4, 4)
线性层 转换过程(Linear Layer)
- \(Logits = Dec\_Out · W\_out + b\_out\)
- W_out(权重矩阵):形状必须是 (d_model, V),即 (4, 6)
- b_out(偏置项):长度为 V,即 (6, )
- 这些值在训练中是不断更新的,但在某次前向传播中就是固定的数值
W_out(权重矩阵)(4行 × 6列)
- 原始 Transformer 实现中,W_out 直接复用 输出嵌入层(Output Embedding)的权重矩阵的转置
- \(W_{out} = (W_{dec\_emb})^T\)
- 大幅减少参数量(词汇表通常很大,如 V=30000,这个矩阵能省下几千万个参数)
- 提升训练效果:让 理解词义(嵌入)和 生成词(输出)共享底层语义空间
\(W_{out\_4×6} = \begin{bmatrix} 0.2& 0.8& 0.1& 0.3& 0.5& 0.0\\ 0.4& 0.2& 0.9& 0.1& 0.3& 0.6\\ 0.1& 0.3& 0.2& 0.7& 0.4& 0.5\\ 0.6& 0.1& 0.3& 0.2& 0.8& 0.4 \end{bmatrix}\)
b_out(偏置项)(长度为6的行向量,1 × 6)
- \(b_{out\_1×6} = [\ 0.1\ \ \ \ 0.0\ \ \ \ 0.2\ \ \ \ 0.1\ \ \ \ 0.0\ \ \ \ 0.3\ ]\)
前面 解码器(6层)输出的 Dec_out 作为线性层的输入
| 每一行结果 | ||
|---|---|---|
| Dec_Out | [ 1.10, 0.70, -0.80, 1.40] | # 位置0 (<START>) |
| [ 1.05, 0.85, -0.55, 1.25] | # 位置1 (I) | |
| [ 0.65, 1.15, -0.20, 1.00] | # 位置2 (love) | |
| [ 0.80, 1.05, -0.05, 0.90] | # 位置3 (AI) |
逐行计算 Logits[i] = Dec_Out[i] · W_out + b_out
- 线性层的最终输出:Logits 矩阵(形状 4×6)
- 对应 目标单词表,一般默认 <START> 开头
| 位置 | <START> | I | love | AI | <EOS> | <PAD> | 用途说明 |
|---|---|---|---|---|---|---|---|
| 位置0 | 1.36 | 0.92 | 1.20 | 0.22 | 1.56 | 0.88 | 预测第1个词用 |
| 位置1 | 1.345 | 0.97 | 1.335 | 0.365 | 1.56 | 1.035 | 预测第2个词用 |
| 位置2 | 1.27 | 0.79 | 1.56 | 0.47 | 1.39 | 1.29 | 预测第3个词用 |
| 位置3 | 1.215 | 0.925 | 1.485 | 0.59 | 1.415 | 1.265 | 预测第4个词用 |
输出 Logits(分数)
- 输出:Logits 分数矩阵
- 形状:(序列长度 L, 词汇表大小 V) = (4, 6)
- 解释:
- 行:代表 4 个位置(<START>, I, love, AI)
- 列:代表词汇表中的 6 个候选词
Softmax 层(分数 --> 概率)
- 线性层输出的 Logits 是“未归一化的分数”,数值可正可负,范围不定
- Softmax 的作用是
- 将所有分数都变成正数(通过 \(e^x\) 指数函数)
- 将它们压缩到 [0, 1] 区间,并且每一行的所有概率之和等于 1
- 这样,我们就能直观地看出模型认为“当前位置最可能是哪个词”
输入
- 上一步的 Logits 分数矩阵,形状 (4, 6)
计算公式
- 对于一个位置(行)的 Logits 向量 \(z = [z_1, z_2, ..., z_6]\)
- Softmax 计算第 j 个词的概率为:
\(P(word_j) = \frac{e^{z_j}}{Σ(e^{z_k})}\),分母是对所有 k:1 --> 6 求和
Softmax 最终输出(概率矩阵 Probs,形状 4×6)
| 位置 | <START> | I | love | AI | <EOS> | <PAD> | 总和 |
|---|---|---|---|---|---|---|---|
| 位置0 | 0.215 | 0.138 | 0.183 | 0.069 | 0.262 | 0.133 | 总和=1.0 |
| 位置1 | 0.199 | 0.137 | 0.197 | 0.075 | 0.247 | 0.146 | 总和=1.0 |
| 位置2 | 0.180 | 0.111 | 0.241 | 0.081 | 0.203 | 0.184 | 总和=1.0 |
| 位置3 | 0.170 | 0.127 | 0.223 | 0.091 | 0.208 | 0.179 | 总和=1.0 |
- 根据这个概率矩阵,模型在每个位置“最想预测”(即概率最高)的词分别是:
| 位置 | 输入上下文(已看到的词) | 概率最高的词(Argmax) | 概率值 | 真实目标词 | 是否正确? |
|---|---|---|---|---|---|
| 位置0 | <START> | <EOS> | 0.262 | I | ❌ 错误 |
| 位置1 | <START> I | <EOS> | 0.247 | love | ❌ 错误 |
| 位置2 | <START> I love | love | 0.241 | AI | ❌ 错误 |
| 位置3 | <START> I love AI | love | 0.223 | <EOS> | ❌ 错误 |
结果全部错误,因为上面的过程只是第一次训练
计算损失(Loss)—— 衡量模型预测有多“差”
- 损失函数(交叉熵)会计算 模型预测的概率分布 与 真实答案(One-hot 编码) 之间的差距
数学公式(交叉熵损失)
- 对于 一个位置 i,如果真实词是 target,那么损失为:
- \(Loss_i = -log( P_{model}(target) )\)
- 整个批次的损失是所有位置损失的平均值
计算举例
| 位置 | 真实目标词 | 目标词索引 | 模型预测该词的概率 | 公式 | 该位置损失 |
|---|---|---|---|---|---|
| 位置0 | I | 1 | 0.138 | -log(0.138) | 1.981 |
| 位置1 | love | 2 | 0.197 | -log(0.197) | 1.624 |
| 位置2 | AI | 3 | 0.081 | -log(0.081) | 2.513 |
| 位置3 | <EOS> | 4 | 0.208 | -log(0.208) | 1.570 |
最终 Loss - 平均损失(该序列的):
- Loss = (1.981 + 1.624 + 2.513 + 1.570) / 4 = 7.688 / 4 = 1.922
- 解释:
- 交叉熵损失的数值 > 0
- 如果模型完美预测(概率 = 1.0),损失为 0
- 这里计算得到损失是 1.922,说明模型 预测得还不够好,还需要继续训练
接下来的事:反向传播(Backpropagation)
计算梯度:
- 从损失值出发,利用链式法则,一直往回计算每一个权重矩阵里每一个数值的 偏导数(梯度)
- \(W_{emb}, W_Q, W_K, W_V, W_O, W1, W2, W_{out}\) 等
以权重矩阵 \(W_{out}\) 的第 1 个数 \(W_{out}[0,0]\) 为例
- 线性层权重矩阵 \(W_{out}\) 中,第 0 行第 0 列的那个数
- 在 前向传播时,这个值参与了位置0(<START>)对应 <START> 这个单词的 Logits 计算
- 注意:我们预测的目标是 "I",但 W_out[0,0] 负责计算的是 Logits 矩阵里 第 0 列,即
这个词的得分
前向传播的数值(前面计算的结果)
- 位置 0 的 Dec_Out[0] 第一个数是 \(x_0 = 1.10\)
- 我们的目标真实标签(Ground Truth)是 I,其 One-Hot 向量 y 为 [0, 1, 0, 0, 0, 0]
- 位置 0 的最终概率分布 Probs[0] 为 [0.215, 0.138, 0.183, 0.069, 0.262, 0.133]
链式法则 :梯度"反向传播"的数学链
-
损失 L 对权重 W_out[0,0] 的偏导数:\(\frac{∂L} {∂W_{out}[0,0]}\)
-
前向传播时的链路是:
- W_out[0,0] → Logit[0, 0] → Softmax → 损失 L
- 其中,Logit[0, 0] 是 位置0 对 <START> 的分数
-
链式法则 (反向传播):
- 第 1 步:损失对 Logits 的梯度(反向起点) \(\frac{∂L} {∂Logits[0, j]} = Probs[0, j] - y[0, j]\)
- 第 2 步:Logits 对权重的偏导数 \(\frac{∂Logits[0,0]} {∂W_{out}[0,0]} = Dec\_Out[0,0]\)
- 第 3 步:把两个偏导数相乘(链式法则)\(\frac{∂L} {∂W_{out}[0,0]} = \frac{∂L} {∂Logits[0, j]} × \frac{∂Logits[0,0]} {∂W_{out}[0,0]}\)
-
具体数值计算
- 第 1 步:对于 j=0(即 <START> 列)
- \(\frac{∂L} {∂Logits[0, j]} = Probs[0, j] - y[0, j] = 0.215 - 0 = 0.215\)
- 作为对比,真实目标 j=1(I)的梯度是 0.138 - 1 = -0.862,负号 表示需要提高这个类的分数
- 第 2 步:\(\frac{∂Logits[0,0]} {∂W_{out}[0,0]} = Dec\_Out[0,0] = 1.10\)
- 第 3 步:\(\frac{∂L} {∂W_{out}[0,0]} = \frac{∂L} {∂Logits[0, j]} × \frac{∂Logits[0,0]} {∂W_{out}[0,0]} = 0.215 × 1.10 = 0.2365\)
- 第 1 步:对于 j=0(即 <START> 列)
-
这个 0.2365 就是 W_out[0,0] 的最终梯度
-
优化器(Optimizer)(如 Adam)会拿着这个 0.2365,乘 以 学习率(比如 \(\color{red}-0.001\)),去更新 W_out[0,0] 的原始数值
元素梯度 --> 矩阵梯度(梯度 回流 解码器Decoder)
- 单个权重是这样算的,那么整个矩阵的梯度,就是把上述过程写成矩阵乘法的形式
1. 输出层(Linear Layer)的梯度
- 损失对 Logits 的梯度:dL_dLogits = Probs - Y(形状 4×6,Y 是 One-Hot 矩阵)
- 损失对偏置 b_out 的梯度(形状 6,):dL_db_out = sum(dL_dLogits, dim=0)(对位置维度求和)
- 损失对权重 W_out 的梯度(形状 4×6):dL_dW_out = Dec_Out^T · dL_dLogits
- 即 (4×4)^T · (4×6) = (4×6)。你看,这个矩阵乘法的结果形状和 W_out 完全一致。
2. 解码器 FFN(第二层 W2)的梯度
- 设 A 是 ReLU 激活后的矩阵(形状 4×8),dL_dFFN_Out 是来自上一层的梯度。
- dL_dW2 = A^T · dL_dFFN_Out(形状 8×4,与 W2 一致)
3. 解码器 FFN(第一层 W1)的梯度
- 设 Z = Out2 · W1 + b1,A = ReLU(Z),dL_dA 是来自 W2 层的梯度。
- 由于 ReLU 的导数很简单(输入大于0时为1,小于0时为0),我们在反向传播时会把 dL_dA 乘上一个掩码矩阵(Z > 0 的地方为1,其余为0)。
- dL_dW1 = Out2^T · (dL_dA ⊙ ReLU_mask)(形状 4×8,与 W1 一致)
4. 解码器交叉注意力(Q、K、V 投影层)的梯度
- 这是链式法则最长的部分。以 W_Q 为例,梯度必须穿过 Softmax、Scaling、MatMul 等环节。
- 其核心矩阵形式为:dL_dW_Q = X^T · dL_dQ
- 这里 X 是进入该子层的输入,dL_dQ 是从后面的 V 和注意力权重矩阵传播回来的梯度。
5. 解码器掩码自注意力(W_Q, W_K, W_V)的梯度
- 和上面的交叉注意力公式完全一样,只是 X 来自解码器自身的偏移输入。
- 唯一的区别是,在计算 dL_dScores 时,上三角掩码位置(-inf)的梯度会被强制设为 0,因为 -inf 在反向传播时没有贡献。
6. 输出嵌入层与输入嵌入层
- 对于嵌入层(查表操作),梯度只更新那些被"查过"的行。
- 输出嵌入层:dL_dW_dec_emb = One_Hot_Indices^T · dL_dY(由于权重共享,这个梯度会同时累加到最后的 W_out 上)
梯度 回流 编码器 Encoder
通过"交叉注意力"(Cross-Attention)和"残差连接" 回流 编码器 Encoder
1. 通过交叉注意力回溯:
- 在解码器的交叉注意力层,梯度 dL_dQ 会沿着 Q 往回传,但更重要的是,梯度也会流经 K 和 V。因为 K 和 V 的来源是编码器的最终输出 Enc_Out。
- 当梯度流到 K 和 V 时,它们会汇聚成 dL_dEnc_Out。
- 这个 dL_dEnc_Out 会从解码器"跨"回到编码器,成为编码器输出端的梯度。
2. 通过残差连接加速:
- 残差连接(Add)在反向传播时相当于一个"梯度高速公路",它将解码器传来的梯度不加衰减地直接复制一份,跳过自注意力层和 FFN 层,直通编码器的底部。
3. 编码器自爱:
- 当 dL_dEnc_Out 进入编码器的最后一层后,它就像在多层的解码器中一样,一层层地穿过 FFN、Add & Norm、Multi-Head Self-Attention,最终抵达编码器的嵌入层 W_enc_emb,并更新其中的权重。
更新权重:
- 优化器(Optimizer)(如 Adam)拿着这些梯度,乘以学习率,去更新所有的权重矩阵
- 让模型在下一次前向传播时,对这些句子的预测损失变得更小
重复迭代:
- 处理下一个 Batch 的句子对,重复上述所有步骤
- 编码器 → 解码器 → 输出 → 损失 → 反向传播
- 直到模型在整个数据集上的 损失收敛
浙公网安备 33010602011771号