第2章 大语言模型基础 - 深度梳理
一、总体框架介绍
本章核心目标和学习价值
本章是大语言模型理论基础的入门章节,旨在帮助读者理解现代大语言模型的核心架构和技术原理。通过学习本章,读者将掌握:
- Transformer架构的完整原理:从嵌入层到注意力机制,从残差连接到层归一化,深入理解每个组件的设计动机
- 生成式预训练的核心思想:理解GPT模型如何通过自监督学习获得强大的语言理解能力
- 现代大语言模型的架构演进:从原始Transformer到LLaMA的改进,包括RoPE、SwiGLU等关键技术
- 注意力机制的效率优化:掌握稀疏注意力、FlashAttention等提升推理效率的核心技术
知识体系结构图
大语言模型基础
├── Transformer结构(核心架构)
│ ├── 嵌入表示层(位置编码)
│ ├── 注意力层(自注意力机制)
│ ├── 前馈层(非线性变换)
│ ├── 残差连接(梯度流动优化)
│ └── 编码器-解码器结构
├── GPT模型(生成式预训练)
│ ├── 自监督预训练
│ ├── 有监督下游任务微调
│ └── 预训练语言模型实践
└── 大语言模型结构(现代架构)
├── LLaMA架构改进
│ ├── RMSNorm归一化
│ ├── SwiGLU激活函数
│ └── RoPE位置编码
└── 注意力机制优化
├── 稀疏注意力
└── FlashAttention
与前后章节的关联
与前章关联:
- 第1章介绍了大语言模型的发展历程和典型系统,本章深入其理论基础
- 第1章提到的GPT-3、ChatGPT等系统,其核心架构正是本章的Transformer
与后章关联:
- 第3-4章的分布式训练需要基于本章的模型结构来设计并行策略
- 第5-6章的微调技术建立在理解模型架构的基础上
- 第10章的效率优化直接针对本章提出的注意力机制和模型结构
二、核心原理讲解
2.1 基础概念层
2.1.1 语言模型(Language Model)
定义 :
语言模型是对自然语言文本序列的概率分布进行建模,目标是计算一个文本序列出现的概率。
数学公式 :
P ( w 1 , w 2 , . . . , w n ) = ∏ i = 1 n P ( w i ∣ w 1 , w 2 , . . . , w i − 1 ) P(w_1, w_2, ..., w_n) = \prod_{i=1}^{n} P(w_i | w_1, w_2, ..., w_{i-1}) P(w1,w2,...,wn)=i=1∏nP(wi∣w1,w2,...,wi−1)
生活类比 :
想象你在玩"接龙游戏",每次只能根据前面说过的词来预测下一个最可能出现的词。语言模型就像一个超级强大的"接龙高手",它看了海量文本,知道在"复旦大学位于"后面,最可能是"上海"而不是"火星"。
2.1.2 Transformer结构
定义 :
Transformer是一种完全基于注意力机制的神经网络架构,不再依赖循环结构来处理序列数据。
核心思想 :
用"注意力"机制让每个词都能直接"看到"序列中的其他所有词,而不是像RNN那样逐步传递信息。
生活类比 :
传统RNN像传声筒游戏,信息必须从第一个人传到最后一个人,越传越容易失真。Transformer就像每个人都站在一个房间里,可以同时看到其他所有人,谁重要就关注谁,信息传递没有距离限制。
2.1.3 自注意力机制(Self-Attention)
定义 :
自注意力机制让序列中的每个位置都能关注到其他所有位置,通过Query、Key、Value三个向量来计算上下文相关的表示。
数学公式 :
Attention ( Q , K , V ) = Softmax ( Q K T d k ) V \text{Attention}(Q, K, V) = \text{Softmax}\left(\frac{QK^T}{\sqrt{d_k}}\right)V Attention(Q,K,V)=Softmax(dk QKT)V
其中:
- Q ∈ R L × d k Q \in \mathbb{R}^{L \times d_k} Q∈RL×dk:查询矩阵
- K ∈ R L × d k K \in \mathbb{R}^{L \times d_k} K∈RL×dk:键矩阵
- V ∈ R L × d v V \in \mathbb{R}^{L \times d_v} V∈RL×dv:值矩阵
- d k d_k dk:缩放因子,防止点积过大
生活类比 :
想象你在图书馆查资料,Query是你脑子里的"问题",Key是每本书的"标签",Value是书里的"内容"。你的问题会和每本书的标签匹配(点积),越相关的书权重越高,最后综合所有书的内容得到答案。
2.1.4 多头注意力(Multi-Head Attention)
定义 :
将自注意力机制并行执行多次,每个"头"关注不同的表示子空间,增强模型捕捉不同类型关系的能力。
数学公式 :
MultiHead ( Q , K , V ) = Concat ( head 1 , . . . , head h ) W O \text{MultiHead}(Q, K, V) = \text{Concat}(\text{head}_1, ..., \text{head}_h)W^O MultiHead(Q,K,V)=Concat(head1,...,headh)WO
其中:
head i = Attention ( Q W i Q , K W i K , V W i V ) \text{head}_i = \text{Attention}(QW_i^Q, KW_i^K, VW_i^V) headi=Attention(QWiQ,KWiK,VWiV)
生活类比 :
就像一个团队里有不同背景的成员:有的关注语法结构,有的关注语义关系,有的关注情感色彩。每个成员(头)从不同角度分析问题,最后综合大家的意见得到更全面的结论。
2.1.5 位置编码(Positional Encoding)
定义 :
由于Transformer没有循环结构,无法感知序列中词的位置,需要额外添加位置信息。
数学公式 :
P E ( p o s , 2 i ) = sin ( p o s 10000 2 i / d ) PE_{(pos, 2i)} = \sin\left(\frac{pos}{10000^{2i/d}}\right) PE(pos,2i)=sin(100002i/dpos)
P E ( p o s , 2 i + 1 ) = cos ( p o s 10000 2 i / d ) PE_{(pos, 2i+1)} = \cos\left(\frac{pos}{10000^{2i/d}}\right) PE(pos,2i+1)=cos(100002i/dpos)
生活类比 :
就像给每个座位贴上编号。虽然每个人都坐在同一个房间里(同时可见),但编号告诉我们谁坐在第几排第几座,这样"我坐在你前面"这种位置关系才能被理解。
2.1.6 层归一化(Layer Normalization)
定义 :
对每个样本的所有隐藏单元进行归一化,使数据分布稳定,加速训练收敛。
数学公式 :
L N ( x ) = α ⋅ x − μ σ + b LN(x) = \alpha \cdot \frac{x - \mu}{\sigma} + b LN(x)=α⋅σx−μ+b
其中 μ \mu μ和 σ \sigma σ是均值和标准差, α \alpha α和 b b b是可学习参数。
生活类比 :
就像给考试打分,不管题目难易,都把最高分调到100分,最低分调到0分,这样不同科目的成绩才能公平比较。
2.2 进阶原理层
2.2.1 残差连接的深层机制
为什么需要残差连接 :
深层网络容易出现梯度消失问题,反向传播时梯度会逐层衰减,导致靠近输入的层几乎无法更新。
数学推导 :
设有 L L L层网络,每层变换为 f l f_l fl,输出为:
x L = f L ( f L − 1 ( . . . f 1 ( x 0 ) . . . ) ) x_L = f_L(f_{L-1}(...f_1(x_0)...)) xL=fL(fL−1(...f1(x0)...))
反向传播时梯度:
∂ L ∂ x 0 = ∂ L ∂ x L ∏ l = 1 L ∂ f l ∂ x l − 1 \frac{\partial L}{\partial x_0} = \frac{\partial L}{\partial x_L} \prod_{l=1}^{L} \frac{\partial f_l}{\partial x_{l-1}} ∂x0∂L=∂xL∂Ll=1∏L∂xl−1∂fl
当 L L L很大时,连乘项容易导致梯度消失。
加入残差连接后:
x l + 1 = f l ( x l ) + x l x_{l+1} = f_l(x_l) + x_l xl+1=fl(xl)+xl
梯度变为:
∂ x l + 1 ∂ x l = ∂ f l ∂ x l + I \frac{\partial x_{l+1}}{\partial x_l} = \frac{\partial f_l}{\partial x_l} + I ∂xl∂xl+1=∂xl∂fl+I
即使 ∂ f l ∂ x l \frac{\partial f_l}{\partial x_l} ∂xl∂fl很小,加上单位矩阵 I I I后梯度至少为1,保证信息流畅通。
生活类比 :
就像建高速公路,虽然每层都要做复杂计算(过收费站),但保留一条"快车道"(直连),让信息可以无损地直达目的地。
2.2.2 注意力机制的缩放因子
为什么要除以 d k \sqrt{d_k} dk :
点积 Q K T QK^T QKT的值会随着维度 d k d_k dk增大而增大,导致Softmax函数的输入过大。
数学分析 :
假设 q q q和 k k k的元素独立同分布,均值为0,方差为1,则:
Var ( q ⋅ k ) = ∑ i = 1 d k Var ( q i k i ) = d k \text{Var}(q \cdot k) = \sum_{i=1}^{d_k} \text{Var}(q_i k_i) = d_k Var(q⋅k)=i=1∑dkVar(qiki)=dk
因此点积的方差为 d k d_k dk,标准差为 d k \sqrt{d_k} dk 。
当 d k d_k dk很大时(如512),点积可能远大于1,导致:
- Softmax函数进入"饱和区",梯度接近0
- 注意力权重过于集中在某个位置,失去多样性
除以 d k \sqrt{d_k} dk 后,将点积归一化到合理范围,使Softmax保持良好的梯度特性。
生活类比 :
就像考试打分,如果评分标准很严格(维度高),稍有偏差就扣很多分,会导致所有学生都只有0分或100分。缩放因子就像调整评分标准,让分数分布更合理。
2.2.3 自回归生成的掩码机制
为什么需要掩码 :
在解码器生成文本时,模型只能看到当前位置之前的内容,不能"偷看"后面的答案。
实现方式 :
在计算注意力分数后,将未来位置的分数设为负无穷:
S i j ′ = { S i j if j ≤ i − ∞ if j > i S'{ij} = \begin{cases} S{ij} & \text{if } j \leq i \\ -\infty & \text{if } j > i \end{cases} Sij′={Sij−∞if j≤iif j>i
经过Softmax后, − ∞ -\infty −∞位置的权重变为0:
α i j = e S i j ′ ∑ k e S i k ′ = 0 for j > i \alpha_{ij} = \frac{e^{S'{ij}}}{\sum_k e^{S'{ik}}} = 0 \quad \text{for } j > i αij=∑keSik′eSij′=0for j>i
生活类比 :
就像考试不能看后面的答案。虽然所有题目都印在卷子上,但你只能从第一题开始依次往下做,不能跳到后面看答案再做前面的题。
2.3 高级实现层
2.3.1 GPT自监督预训练实现
工程实现关键点:
- 数据流处理:
python
# 文本转词元序列
input_ids = tokenizer.encode(text, add_special_tokens=True)
# 创建掩码(预测下一个词)
input_ids = input_ids[:-1] # 输入
target_ids = input_ids[1:] # 目标
- 高效训练技巧:
- 使用混合精度训练(FP16/BF16)
- 梯度累积处理大batch
- 动态损失缩放防止梯度下溢
- 内存优化策略:
python
# 激活检查点节省显存
from torch.utils.checkpoint import checkpoint
hidden_states = checkpoint(transformer_block, hidden_states)
实际项目案例:
- GPT-3训练:1750亿参数,消耗3640 PFLOPS计算量
- 数据规模:数千亿单词的多源数据
- 训练时长:约1个月(使用数千块GPU)
2.3.2 LLaMA架构的工程优化
关键技术实现:
- RoPE(旋转位置编码):
python
def apply_rotary_pos_emb(q, k, cos, sin):
# 二维旋转的矩阵形式
q_embed = (q * cos) + (rotate_half(q) * sin)
k_embed = (k * cos) + (rotate_half(k) * sin)
return q_embed, k_embed
优势:
- 相对位置编码,泛化性更强
- 可处理超长序列(理论上无限)
- 计算效率高(复数乘法优化)
- RMSNorm(均方根归一化):
python
class LlamaRMSNorm(nn.Module):
def forward(self, x):
variance = x.pow(2).mean(-1, keepdim=True)
x = x * torch.rsqrt(variance + self.eps)
return self.weight * x
优势:
- 比LayerNorm计算更快
- 无需计算均值,只需方差
- 在LLaMA中效果更好
- SwiGLU激活函数:
python
def forward(self, x):
return self.w2(F.silu(self.w1(x)) * self.w3(x))
优势:
- 结合Swish平滑性和GLU门控机制
- 在大多数任务上优于ReLU和GELU
- 参数量略增但效果显著提升
2.3.3 FlashAttention的硬件优化
核心思想 :
利用GPU内存层次结构,减少高带宽内存(HBM)的访问次数。
实现要点:
-
分块计算 :
将Q、K、V分块加载到SRAM,在SRAM内完成计算,避免频繁访问HBM。
-
增量Softmax:
python
# 在线Softmax:逐块更新最大值和归一化因子
m_i = max(m_i, m_j)
exp_scores = exp(scores - m_i)
sum_i = sum_i * exp(m_i - m_j) + sum(exp_scores)
- 反向传播优化 :
不存储中间注意力矩阵,而是在反向传播时重新计算,以计算换存储。
性能提升:
- 训练速度提升15-25%
- 内存占用减少50%
- 支持更长的序列长度
三、实际应用注意要点
3.1 常见坑点和解决方案
坑点1:注意力机制的位置编码遗漏
问题现象 :
模型无法理解"我在你前面"这种相对位置关系,序列理解能力严重下降。
根本原因 :
Transformer本身没有位置感知能力,忘记添加位置编码或位置编码设置错误。
解决方案:
python
# 错误:只做词嵌入
x = embedding(input_ids)
# 正确:加上位置编码
x = embedding(input_ids)
x = x + positional_encoding(position_ids)
坑点2:掩码机制的实现错误
问题现象 :
训练时loss正常,但推理时模型会"偷看"后面的内容,生成质量很差。
根本原因 :
注意力掩码设置不正确,导致未来信息泄露。
解决方案:
python
# 创建因果掩码
def create_causal_mask(seq_len):
mask = torch.triu(torch.ones(seq_len, seq_len), diagonal=1)
mask = mask.masked_fill(mask == 1, float('-inf'))
return mask
# 应用掩码
attn_scores = attn_scores + mask
坑点3:残差连接的位置错误
问题现象 :
模型训练不稳定,梯度爆炸或梯度消失。
根本原因 :
残差连接的位置放置错误,应该放在子层输出之后,而不是激活函数之后。
正确实现:
python
# Pre-Norm结构(LLaMA采用)
residual = x
x = self.norm1(x)
x = self.attn(x)
x = residual + x
# Post-Norm结构(原始Transformer)
x = self.attn(x)
x = self.norm1(x + residual)
3.2 性能优化技巧
技巧1:梯度检查点节省显存
当显存不足以训练大模型时,使用激活检查点技术:
python
from torch.utils.checkpoint import checkpoint
def forward(self, x):
for layer in self.layers:
x = checkpoint(layer, x, use_reentrant=False)
return x
效果:显存占用降低50-70%,训练速度降低约20%
技巧2:混合精度训练加速
python
scaler = torch.cuda.amp.GradScaler()
with torch.cuda.amp.autocast():
output = model(input)
loss = criterion(output, target)
scaler.scale(loss).backward()
scaler.step(optimizer)
scaler.update()
效果:训练速度提升2倍,显存占用降低50%
技巧3:动态批处理提升吞吐
python
def collate_fn(batch):
# 动态padding到batch内最大长度
max_len = max(len(item['input_ids']) for item in batch)
input_ids = [item['input_ids'] + [0]*(max_len-len(item['input_ids']))
for item in batch]
return torch.tensor(input_ids)
效果:相比固定长度padding,吞吐提升30-50%
3.3 资源配置建议
训练LLaMA-7B的资源需求
| 配置项 | 最低要求 | 推荐配置 |
|---|---|---|
| GPU显存 | 24GB (单卡) | 80GB (A100) |
| GPU数量 | 1 | 8 |
| 内存 | 64GB | 256GB |
| 存储 | 500GB SSD | 2TB NVMe |
| 训练时间 | - | 82432 GPU小时 |
不同规模模型的训练成本估算
- LLaMA-7B: 约5万美元(A100小时)
- LLaMA-13B: 约8万美元
- LLaMA-33B: 约30万美元
- LLaMA-65B: 约60万美元
3.4 最佳实践清单
模型设计最佳实践
- 使用Pre-Norm(前置层归一化)替代Post-Norm
- 采用RoPE替代绝对位置编码
- 使用SwiGLU激活函数替代ReLU
- 注意力头数设为隐藏层维度的约数(如32头配4096维)
训练稳定性最佳实践
- 使用梯度裁剪(max_norm=1.0)
- 启用混合精度训练的动态损失缩放
- 监控梯度范数,及时发现训练异常
- 保存多个checkpoint,避免单点故障
推理优化最佳实践
- 使用KV缓存减少重复计算
- 采用FlashAttention加速注意力计算
- 实现连续批处理提升吞吐
- 使用INT8/INT4量化降低显存占用
四、大模型面试考点
4.1 高频面试题(每章至少8个)
问题1:Transformer为什么比RNN更适合处理长序列?
标准答案要点:
- 并行计算能力:Transformer可以并行处理序列中所有位置,RNN必须逐步计算
- 长程依赖建模:自注意力机制让任意两个位置直接交互,路径长度为O(1);RNN需要逐步传递,路径长度为O(n)
- 梯度流动:残差连接提供直通路径,缓解梯度消失;RNN的长链结构容易梯度消失
代码示例:
python
# RNN:必须逐个处理
for t in range(seq_len):
h[t] = rnn_cell(x[t], h[t-1])
# Transformer:可以并行处理
attn_output = attention(Q, K, V) # 所有位置同时计算
问题2:为什么注意力机制要除以√d_k?
标准答案要点:
- 数值稳定性:点积的值随维度增大而增大,可能导致Softmax函数进入饱和区
- 梯度问题:Softmax饱和时梯度接近0,导致训练困难
- 理论分析:假设q和k的元素独立同分布,均值为0方差为1,则点积的方差为d_k,标准差为√d_k
- 归一化效果:除以√d_k后,点积的方差归一化为1,保持在Softmax的线性区
数学推导 :
Var ( q ⋅ k ) = ∑ i = 1 d k Var ( q i k i ) = d k ⋅ Var ( q i ) Var ( k i ) = d k \text{Var}(q \cdot k) = \sum_{i=1}^{d_k} \text{Var}(q_i k_i) = d_k \cdot \text{Var}(q_i)\text{Var}(k_i) = d_k Var(q⋅k)=i=1∑dkVar(qiki)=dk⋅Var(qi)Var(ki)=dk
问题3:Transformer中残差连接的作用是什么?
标准答案要点:
- 解决退化问题:深层网络容易退化,残差连接保证至少不比浅层网络差
- 梯度流动:提供恒等映射路径,让梯度可以直接流向浅层
- 易于优化:将学习目标从学习完整映射变为学习残差,优化难度降低
反向传播分析 :
无残差连接:
∂ L ∂ x 0 = ∂ L ∂ x L ∏ l = 1 L ∂ f l ∂ x l − 1 \frac{\partial L}{\partial x_0} = \frac{\partial L}{\partial x_L} \prod_{l=1}^{L} \frac{\partial f_l}{\partial x_{l-1}} ∂x0∂L=∂xL∂Ll=1∏L∂xl−1∂fl
有残差连接:
∂ L ∂ x 0 = ∂ L ∂ x L ∏ l = 1 L ( ∂ f l ∂ x l − 1 + I ) \frac{\partial L}{\partial x_0} = \frac{\partial L}{\partial x_L} \prod_{l=1}^{L} \left(\frac{\partial f_l}{\partial x_{l-1}} + I\right) ∂x0∂L=∂xL∂Ll=1∏L(∂xl−1∂fl+I)
即使 ∂ f l ∂ x l − 1 \frac{\partial f_l}{\partial x_{l-1}} ∂xl−1∂fl很小,加上 I I I后梯度至少为1。
问题4:GPT和BERT的区别是什么?
标准答案要点:
| 维度 | GPT | BERT |
|---|---|---|
| 架构 | 仅解码器(单向) | 仅编码器(双向) |
| 预训练任务 | 自回归生成 | 掩码语言模型 |
| 输入处理 | 从左到右 | 双向上下文 |
| 应用场景 | 文本生成 | 文本理解 |
| 注意力掩码 | 因果掩码 | 无掩码(预训练) |
核心区别:
- GPT预测下一个词,只能看到前面的内容
- BERT预测被遮住的词,可以看到前后所有内容
问题5:RoPE相比传统位置编码有什么优势?
标准答案要点:
- 相对位置编码:直接编码相对位置关系,泛化性更强
- 序列长度外推:理论上支持任意长度序列(通过插值)
- 计算效率:可以用复数乘法高效实现
- 数学优雅性:通过旋转向量实现位置编码
数学形式 :
f ( q , m ) = q e i m θ f(q, m) = qe^{im\theta} f(q,m)=qeimθ
其中 θ \theta θ是频率参数, m m m是位置,通过旋转角度编码位置。
问题6:什么是多头注意力?为什么要用多头?
标准答案要点:
- 多子空间表示:每个头学习不同的表示子空间
- 多样化关注模式:不同头可以关注不同类型的关系
- 增强表达能力:多个头组合后表达能力更强
实际效果:
- 第1个头:关注语法结构(主谓宾)
- 第2个头:关注语义关系(同义词)
- 第3个头:关注指代关系(代词指代)
- ...
问题7:LLaMA相比原始Transformer有哪些改进?
标准答案要点:
-
RMSNorm替代LayerNorm:
- 计算更快(无需均值)
- 效果相当或更好
-
SwiGLU激活函数:
- 结合Swish和GLU的优势
- 比ReLU效果更好
-
RoPE位置编码:
- 相对位置编码
- 支持长序列外推
-
Pre-Norm结构:
- 训练更稳定
- 梯度流动更顺畅
问题8:FlashAttention如何加速注意力计算?
标准答案要点:
- 减少HBM访问:将中间结果保存在SRAM中
- 分块计算:将Q、K、V分块处理
- 在线Softmax:增量计算Softmax,无需存储中间矩阵
- 反向优化:重新计算而非存储中间结果
性能提升:
- 内存访问减少:O(N^2) → O(N)
- 训练速度:提升15-25%
- 显存占用:减少50%
4.2 核心概念问答要点
自注意力机制的计算复杂度
问题:自注意力的时间和空间复杂度是多少?为什么这是瓶颈?
回答要点:
- 时间复杂度:O(n²d),其中n是序列长度,d是隐藏层维度
- 空间复杂度:O(n²),需要存储n×n的注意力矩阵
- 瓶颈原因:序列长度增加时,复杂度呈平方增长
- 解决方案:稀疏注意力、线性注意力、FlashAttention
Transformer的并行化策略
问题:Transformer如何实现并行计算?
回答要点:
- 层内并行:自注意力机制可以并行计算所有位置
- 层间串行:不同层必须顺序执行
- 训练时:可以并行处理整个序列
- 推理时:必须自回归生成,无法并行
4.3 实战场景题解析
场景1:设计一个文本生成系统
问题:如何基于LLaMA-7B设计一个高效的文本生成系统?
解答要点:
-
模型加载:
- 使用INT8量化降低显存需求
- 采用模型并行策略分割到多卡
-
推理优化:
- 启用KV缓存减少重复计算
- 使用FlashAttention加速注意力
- 实现连续批处理提升吞吐
-
服务化部署:
- 使用vLLM或TGI框架
- 实现流式输出减少首字延迟
- 设置合理的最大生成长度
场景2:处理超长文本场景
问题:当输入文本超过模型最大长度时如何处理?
解答要点:
-
分块处理:
- 将长文本分割为多个chunk
- 每个chunk独立编码后聚合
-
滑动窗口:
- 使用滑动窗口保持局部连贯性
- 重叠部分用于平滑过渡
-
层次化处理:
- 先提取各段落摘要
- 再基于摘要生成最终结果
4.4 学习延伸方向
理论深入方向
- 注意力机制的理论分析(表达能力和复杂度)
- 位置编码的设计原理和演变历史
- Transformer的表达能力上界
工程实践方向
- 模型并行和流水线并行的实现
- 推理系统的优化技术(如vLLM、Orca)
- 大模型训练框架(如DeepSpeed、Megatron)
前沿研究方向
- Transformer替代架构(如Mamba、RWKV)
- 线性注意力机制
- 长序列建模技术
本章小结 :
本章系统梳理了Transformer和大语言模型的基础理论,从嵌入层到注意力机制,从残差连接到层归一化,每个组件的设计动机和数学原理都进行了详细讲解。同时结合LLaMA架构的现代改进和FlashAttention等优化技术,为读者提供了从理论到实践的完整知识体系。建议读者在学习本章后,动手实现一个简化版的Transformer模型,加深对各个组件的理解。