Transformer 结构详解:双塔、残差、位置编码全手算

简介: 本课拆解Transformer六大核心设计:为何分Encoder/Decoder双塔、层内子层顺序、Decoder多出的Cross-Attention、残差+LayerNorm作用、正弦位置编码原理、输入输出词表是否共享。每问配可手算小例,讲清“为什么”,非仅“是什么”。课程共34讲,开源免费(MIT协议)。

上一篇讲了 Transformer 为什么需要 Self-Attention。这一篇把整个 Transformer 的骨架拆开:为什么分成 Encoder 和 Decoder 两座塔,一层里的子层怎么排,残差连接和 LayerNorm 到底在解决什么,位置信息从哪来,最后输出端和输入端能不能共用一张词表。一共 6 个问题,每个问题都用一个能手算的小例子。内容来自我做的一套 34 课大模型课程的第 2 课。

问题 1:为什么必须分成 Encoder 和 Decoder 两座塔?

把「I love you」翻成「我爱你」。目标端要逐词产出,但每个词对输入的要求是反着的:产出"我"和"爱"时,必须读完整句 I / love / you;可产出"爱"时,绝不能提前看到还没生成的"你"。

要产出的词 必须看见 绝不能看见
我 I / love / you(整句) —
爱 I / love / you 你(还没生成)
你 I / love / you —(已是最后一个)

源句侧要"全可见",目标侧要"绝不看未来",同一组注意力权重做不到两头兼顾。所以结构按可见范围分成两座塔:

塔 可见范围 运行次数 层计算(6 层)
Encoder 双向,每个词看全部 1 次 1 × 6 = 6
Decoder 单向,只看左边 逐词,3 次 3 × 6 = 18

Decoder 的计算是 Encoder 的 18 ÷ 6 = 3 倍,源句越长差距越大。后来的 KV Cache 就是为了压掉这部分重复计算。

两座塔在参数上也不一样。按原论文 base 配置(d_model=512,FFN 内层 2048):

组件 参数量
Self-Attention(4 个 512×512 投影) 4 × 512² ≈ 1.05M
FFN(两个线性层) 2 × 512 × 2048 ≈ 2.10M
Encoder 一层 ≈ 3.15M
Decoder 一层(多一个 Cross-Attention) ≈ 4.19M

FFN 占到每层的约 67%,参数最多的部件不是 Self-Attention。6 层 Encoder 加 6 层 Decoder 约 44M。

问题 2:一层里为什么是「Self-Attention → Add&Norm → FFN → Add&Norm」?

两个子层各管一件事:Self-Attention 让所有位置先互相交换信息,FFN 再对每个位置独立加工。每个子层后面都接「加回输入,再归一化」,写成 LayerNorm(x + 子层(x))。

用 3 个词、d_model=4 的小例子走一步。第一个词"我"的输入 x = [1.0, 0.5, 0.2, 0.8],Self-Attention 的输出(示意值)是 [0.3, 0.1, 0.2, 0.4]:

  • 残差相加:x + 输出 = [1.3, 0.6, 0.4, 1.2]
  • LayerNorm(减均值再除以标准差):得到 [1.109, -0.718, -1.239, 0.848]

残差的意义是:即使 Attention 这一层几乎什么都没学到(输出接近 0),x 也能原样穿过去,信息不会丢。原论文的真实配置是 d_model=512,这里压到 4 维只是为了能手算。

问题 3:Decoder 为什么需要两个注意力子层?

Decoder 生成每个词时要做两件事:回看自己已经写出的内容,还要回头查输入句子。所以一层有三个子层:

  1. Masked Self-Attention:和 Encoder 类似,但加下三角 mask,只看已生成的词。
  2. Cross-Attention:Q 来自 Decoder 当前层的输入,K 和 V 来自 Encoder 最后一层的输出。这是 Encoder 和 Decoder 之间唯一的信息通道。
  3. FFN:和 Encoder 一样。

能不能省掉 Cross-Attention?不能。生成第 1 个词时,Decoder 手里只有一个起始符 [BOS],从没见过「I love you」,凭什么把首词定成"我"而不是"你"?所以必须有一个专门回看源句的子层。每多一个 Cross-Attention,Decoder 每层多 4 × 512² ≈ 1.05M 参数,6 层共多约 6.3M。

问题 4:残差连接和 LayerNorm 到底解决了什么?

先看没有残差会怎样。假设每层把梯度乘以 0.85,传回第一层时:

层数 0.85 的 N 次方 含义
12 ≈ 0.14 衰减 86%
24 ≈ 0.02 衰减 98%
48 ≈ 0.0004 几乎为零

残差把每层的映射从 F(x) 变成 x + F(x),反向传播时多出一条恒等的通路,梯度至少是 1,不会指数衰减。但这样数值尺度也会随深度累积,所以需要 LayerNorm 把尺度压回稳定范围。LayerNorm 的计算只有两步,以向量 [2, 6, 4, 8] 为例:

  • 均值 μ = (2+6+4+8) / 4 = 5,减掉后得到 [-3, 1, -1, 3]
  • 标准差 σ = √((9+1+1+9) / 4) = √5 ≈ 2.24,相除得到 [-1.34, 0.45, -0.45, 1.34]

课程里还有一个"有残差时梯度放大"的示意表,那是我刻意构造的(假设每层乘子恒定且同向叠加),真实残差主要缓解的是梯度消失,不会自己爆炸,所以这里不展开。

问题 5:Self-Attention 没有位置概念,Transformer 怎么知道谁在第几位?

答案是给每个位置加一个位置编码。原论文用不同频率的正弦和余弦:

PE(pos, 2i) = sin(pos / 10000^(2i/d)),PE(pos, 2i+1) = cos(pos / 10000^(2i/d))

取 d=4,前两个维度用频率 1.0,后两个用频率 0.01,前 3 个位置的编码是:

位置 dim0 sin(pos) dim1 cos(pos) dim2 sin(0.01·pos) dim3 cos(0.01·pos)
1 0.84 0.54 0.01 1.00
2 0.91 -0.42 0.02 1.00
3 0.14 -0.99 0.03 1.00

高频维度变化快,能区分相邻位置;低频维度变化慢,覆盖长距离。同一个词在位置 2 和位置 5 加上不同的编码,就变成两个不同的输入向量。需要注意:这种编码理论上能用线性变换表示相对位置,但超出训练长度时效果会退化,并不能随意外推。现代的 Llama 等模型已经改用 RoPE。

问题 6:输出端那张"向量变回词"的表,能和输入端共用吗?

Decoder 最后一层输出的是一个 512 维向量,要变回一个词,需要一个输出矩阵把它投影到整个词表上。词表有 37,000 个词,所以这个矩阵就是 512 × 37,000,和输入端"词变向量"的那张 37,000 × 512 的表一样大,形状正好互为转置。

方案 输入表 输出表 合计
各学一遍 18.94M 18.94M 37.89M
共用一张(weight tying) 18.94M 同一份 18.94M

其中 37,000 × 512 = 18,944,000。原论文第 3.4 节就是这么做的,原文写的是共享两个 embedding 层和 pre-softmax 线性层之间的权重矩阵。

把这笔账放回整体:6 层 Encoder 加 6 层 Decoder 约 44.0M,加上共享的一张表 18.94M,我逐项相加得到约 63M。如果输入输出各养一张表,就要再多 18.94M,约 82M。

另外,论文报告的 base 模型总参数是约 65M,这个数字我没有从论文原文里核到,只当旁注。它和我加出来的 63M 差约 2M,课程里的解释是偏置、LayerNorm 等没有逐项算,这是推测,没有核实。课程另一处是以论文的 65M 为基数估算的:不共享的话约 84M,多出的 18.94M 约占原来的 29%。两种口径的出发点不同(一个是我逐项相加,一个是以论文报告值为基数),结论都是"共享能省下约 18.94M、约三成"。

换成现代模型,同一张表更大:Llama 2 7B 的词表 32,000、向量维度 4,096,一张表就是 32,000 × 4,096 ≈ 131M,但它占总参数约 6.74B 的 1.9%。另外要注意,Llama 2 等一批模型并没有使用 weight tying。

小结

问题 结论 一个数字
为什么两座塔 源句要全可见,目标端不能看未来 Decoder 计算量是 Encoder 的 3 倍
一层里的顺序 Attention 融合信息,FFN 各自加工,每个子层后接 Add&Norm Encoder 一层 ≈ 3.15M
Decoder 的 Cross-Attention 唯一回看源句的通道 每层多 ≈ 1.05M
残差与 LayerNorm 残差保梯度,LayerNorm 稳尺度 0.85²⁴ ≈ 0.02
位置编码 多频率的 sin/cos 同一个词不同位置得到不同向量
共用词表 输入输出共享一张表 省 18.94M

参考与说明

  • Transformer、weight tying(第 3.4 节)、正弦位置编码(第 3.5 节):Vaswani 等,Attention Is All You Need,2017,https://arxiv.org/abs/1706.03762
  • Llama 2:Touvron 等,2023,https://arxiv.org/abs/2307.09288
  • 文中的数字(层参数、深度代价、梯度衰减、LayerNorm 示例、位置编码值、词表参数)我都用代码独立复算过。"示意值"标明的是为了演示取的数字,不是真实模型的输出。
  • 说明:这套课程由 AI 在我设计的规则下生成,再经过脚本检查和独立审查;审查时发现过不少问题,已写在仓库 README 里。如果你发现错误,欢迎在仓库提 Issue,写清位置,我会逐条核实。

继续学

完整课程有 34 课,上一篇是第 1 课「Transformer 回顾」,从 RNN 的梯度问题讲到 GPT 逐字生成。每张卡片后面还有 AI 助教,可以接着追问(每人每天有次数限制)。

相关文章
|
6天前
|
JavaScript API iOS开发
DeepSeek Harness下载、安装、配置一篇搞定(2026整理,送常用插件)
DeepSeek Harness(DSH)是DeepSeek于2026年开源的MIT协议AI Agent框架,支持插件化组装模型、工具、沙箱与UI,兼容主流大模型。本文提供免Node.js的桌面端安装包(Win/macOS),含详细图文教程及热门插件推荐。
2659 22
|
23小时前
|
云安全 人工智能 安全
|
5天前
|
Linux 开发工具 iOS开发
Codex保姆级教程(下载+安装+登录+使用,含所有版本,2026最新)
Codex是OpenAI推出的开源AI编程智能体,本地运行,可理解整个代码库,支持自然语言指令改代码、执行命令、跑测试、修Bug,兼容Win/macOS/Linux。(239字)
|
6天前
|
iOS开发 Docker MacOS
【2026实测】Docker Desktop下载、安装、汉化、配置教程(附官网安装包)
Docker Desktop 是 Docker 官方推出的桌面容器管理工具,集成引擎、CLI、图形界面与 Kubernetes,支持 Win/macOS/Linux。2026 最新版 4.88.1 强化 ARM 原生运行、镜像加速及资源可视化,附中文汉化与国内镜像配置指南。
1163 4
|
云安全 安全 网络安全
|
6天前
|
安全 算法 定位技术
《高性价比人生指南》完整原版:普通人用最少的资源,过好这一生的底层逻辑~How To Live Better
📖《高性价比人生指南》是一份基于实证、拒绝焦虑的生存手册,倡导以“人生时薪”为视角,重新计算时间、金钱与精力的成本与收益。它不承诺逆袭,只教人算清账:省下的钱若耗掉时间便亏;买体验比买物品更值;睡眠是最高杠杆的健康投资;关系贵在情绪价值而非表面热络;学习重在改变行为而非自我安慰。核心理念:用低成本、高回报的微小行动,换取长期的选择权——不是成为谁,而是掌控自己人生的主动权。
|
19天前
|
人工智能 API 开发工具
DeepSeek Harness 神插件:白嫖 13 家大厂模型
`dsh-our-free-model` 是 DeepSeek Harness 神级插件:零配置、零API Key、零账号,聚合13家大厂免费模型(含DeepSeek V4.1 Flash、Kimi K3等),支持本地网关、用量看板与自动降级,真正实现“白嫖即用”。
3318 52
|
11天前
|
人工智能 JSON Linux
【保姆级】ComfyUI部署教程(下载+安装+配置+工作流,2026最新)
ComfyUI 是一款开源节点式AI生成工具,支持图像、视频、音频及3D内容创作。通过拖拽连线组合模型加载、提示词、采样等节点,构建可复用、易修改的工作流,兼容SD1.5、SDXL、Flux、Qwen Image等主流模型。