不调用
nn.Transformer,不使用nn.MultiheadAttention,从零实现 Attention、Encoder、Decoder、训练和自回归生成。完整代码已开源,支持 Google Colab 在线运行,无需 GPU。
如果这篇文章对你有帮助,欢迎给项目点一个 ⭐ Star!
一、前言:你真的理解 Transformer 了吗?
相信很多学习深度学习、NLP 和大语言模型的同学,都接触过 Transformer。
我们知道它有 Encoder 和 Decoder,知道 Attention 的计算公式,也知道它是现代大语言模型的重要技术基础。
但如果让你不调用 PyTorch 封装好的 Transformer 模块,从零实现一个完整模型,你能写出来吗?
比如:
-
Self-Attention 的 Q、K、V 到底是怎么计算的?
-
Multi-Head Attention 为什么需要多个注意力头?
-
Decoder 的 Masked Attention 为什么不能看到未来 Token?
-
Encoder 和 Decoder 是怎么通过 Cross-Attention 交互的?
-
模型为什么可以逐 Token 生成翻译结果?
为了解决这些学习过程中的疑惑,我基于 PyTorch 从零实现了一个小型 Transformer。
项目名称:Tiny Transformer from Scratch
这个项目最大的特点就是:
只需要一个 Python 文件,就能走完 Transformer 从数据处理、模型构建、训练到英文翻译成中文的完整流程。
而且核心模块都是手动实现的,非常适合想进一步理解 Transformer 原理的同学。
二、项目亮点
1. 不依赖现成的 Transformer 实现
整个项目没有调用:
nn.Transformer
nn.MultiheadAttention
而是手动实现以下模块:
-
Token Embedding
-
Positional Encoding
-
Scaled Dot-Product Attention
-
Multi-Head Attention
-
Encoder / Decoder
-
Masked Self-Attention
-
Cross-Attention
-
Feed Forward Network
-
Residual Connection + LayerNorm
-
Autoregressive Generation
不仅能看到 Transformer 的整体结构,还能直接阅读每个模块的内部计算。
2. 一个 Python 文件完成全部流程
核心代码全部集中在 transformer.py 中。
从构建词表,到模型初始化、前向传播、损失计算、反向传播,最后生成中文翻译,都能按照代码顺序阅读。
不用在十几个文件之间来回跳转。
3. 不需要大型数据集,也不需要 GPU
项目内置 8 组简单的英文和中文句对,使用轻量级模型配置:
| 参数 | 配置 |
|---|---|
| Model Dimension | 32 |
| Attention Heads | 2 |
| Encoder Layers | 2 |
| Decoder Layers | 2 |
| FFN Hidden Dimension | 64 |
| Training Epochs | 100 |
这样设置的目的不是追求翻译性能,而是尽可能降低学习和运行门槛。
4. 支持 Colab 在线运行
不想配置 Python 环境?
项目提供了 Jupyter Notebook 版本,可以直接在 Google Colab 中运行。
在线运行地址:
普通 CPU 环境即可运行。
三、Transformer 整体架构
本项目采用经典的 Encoder--Decoder Transformer 架构。
整体流程可以理解为:
英文输入 → Embedding + Position → Encoder → Decoder → 中文 Token 生成
其中 Encoder 负责对英文输入进行编码,Decoder 则结合编码结果,逐步生成目标语言序列。
Encoder 主要包含两个模块:
-
Multi-Head Self-Attention
-
Feed Forward Network
Decoder 主要包含三个模块:
-
Masked Multi-Head Self-Attention
-
Encoder--Decoder Cross-Attention
-
Feed Forward Network
每个子层还包含残差连接和 Layer Normalization。
项目仓库中附有完整的 Transformer 架构图,可以结合代码一起阅读。
四、核心代码解析
下面选取几个我认为理解 Transformer 时特别重要的部分。
1. Scaled Dot-Product Attention
Attention 的经典公式为:
它看起来比较复杂,但对应到 PyTorch 代码,其实非常直观。
def attention(q, k, v, causal=False):
scores = q @ k.T / math.sqrt(q.shape[-1])
if causal:
mask = torch.triu(
torch.ones_like(scores, dtype=torch.bool),
diagonal=1
)
scores = scores.masked_fill(
mask, float("-inf")
)
weights = torch.softmax(scores, dim=-1)
return weights @ v
可以分成三个步骤理解:
第一步:计算注意力分数
通过 Q 和 K 的矩阵乘法,计算不同 Token 之间的相关性。
除以 √dₖ 是为了缩放分数,避免维度较大时的点积数值导致 Softmax 过于尖锐。
第二步:计算注意力权重
对分数进行 Softmax,使其变成权重分布。
第三步:加权求和
使用注意力权重对 V 进行加权求和,得到 Attention 输出。
这就是 Attention 最核心的计算逻辑。
2. Multi-Head Attention
单头 Attention 可以学习一种注意力关系。
Multi-Head Attention 则通过多组独立的 Q、K、V 投影,在不同的表示子空间中计算 Attention。
本项目的核心实现是:
outputs = []
for head in self.heads:
outputs.append(
head(query, key, value, causal)
)
joined = torch.cat(outputs, dim=-1)
return self.out_proj(joined)
思路非常清晰:
多个注意力头分别计算 → 拼接输出 → 线性投影。
对于理解多头注意力来说,这种实现方式比较容易跟踪每一步的张量变化。
3. Decoder 为什么需要 Mask?
这是我觉得手写 Transformer 时非常值得理解的一个细节。
假设模型要生成:
我 喜欢 学习
当它预测"喜欢"时,不能提前看到后面的"学习"。
否则训练时就会使用未来信息,而推理时又无法获得这些信息,导致训练和推理不一致。
因此,Decoder 的 Self-Attention 需要 Causal Mask。
本项目通过以下代码生成上三角掩码:
mask = torch.triu(
torch.ones_like(scores, dtype=torch.bool),
diagonal=1
)
scores = scores.masked_fill(
mask, float("-inf")
)
这样在 Softmax 之后,被掩盖位置的注意力权重就会变成 0。
简单来说:当前 Token 只能关注自己以及之前的 Token,不能偷看未来。
4. Cross-Attention:Encoder 和 Decoder 如何交互?
Cross-Attention 是 Encoder--Decoder Transformer 中非常重要的模块。
在 Decoder 中,项目通过以下代码实现:
x = self.norm2(
x + self.cross_attn(
x,
encoder_output,
encoder_output
)
)
这里需要特别注意:
-
Q 来自 Decoder 当前隐藏状态
-
K 来自 Encoder 输出
-
V 来自 Encoder 输出
Decoder 正是通过 Cross-Attention 获取源语言的编码信息,从而辅助生成目标语言。
5. 训练时为什么要错位输入?
项目训练时使用:
logits = model(source, target[:-1])
loss = criterion(logits, target[1:])
这两行代码也非常关键。
假设目标序列为:
<BOS> 我 喜欢 学习 <EOS>
Decoder 输入:
<BOS> 我 喜欢 学习
训练标签:
我 喜欢 学习 <EOS>
也就是说,模型学习根据当前已知的 Token 序列,预测下一位置应该出现什么 Token。
这正是自回归生成的重要基础。
五、实际运行效果
接下来看看这个迷你 Transformer 的运行结果。
输入英文:
there is a black dog under the chair
一次实际运行输出:
椅子下面有一只黑色狗
训练日志:
Epoch 1 | loss=2.1297
Epoch 20 | loss=0.0163
Epoch 40 | loss=0.0050
Epoch 60 | loss=0.0025
Epoch 80 | loss=0.0015
Epoch 100 | loss=0.0010
程序还会自动保存训练 Loss 曲线,方便观察收敛过程。
需要注意: 这是一个用于学习的迷你 Transformer,只有 8 组训练句对,使用固定词表。示例中的输入是已知训练词汇的新组合。训练 Loss 很低并不代表模型具备通用翻译能力。
这个实验的主要价值是验证 Transformer 训练和自回归推理的完整流程。
六、如何运行项目?
方法一:Google Colab 在线运行(推荐新手)
点击:
登录 Google 账号后,选择:
Runtime → Run all
即可执行完整的训练与翻译流程。
无需本地安装 Python,使用 CPU 就可以。
方法二:本地运行
首先克隆项目:
git clone https://github.com/Zguoxu/tiny-transformer-from-scratch.git
进入目录:
cd tiny-transformer-from-scratch
安装依赖:
pip install -r requirements.txt
运行:
python transformer.py
项目已在 Python 3.12 环境下验证。
程序会训练模型并显示 Loss 曲线。关闭曲线窗口后,就能在终端看到翻译结果。
如果是在没有图形界面的 Linux 服务器上运行,可以使用:
MPLBACKEND=Agg python transformer.py
这样可以将曲线保存为图片,而无需打开图形窗口。
七、建议大家尝试的几个小实验
读懂代码以后,推荐自己做一些修改:
实验一:改变 Attention Head 数量
尝试将注意力头数从 2 改成 4,观察 Loss 曲线的变化。
注意,模型维度必须能够被注意力头数整除。
实验二:改变 Encoder 和 Decoder 层数
调整 NUM_LAYERS,观察模型深度对训练的影响。
实验三:增加英中句对
向 en_cn_pairs 中添加更多数据,重新构建词表和训练模型。
实验四:观察自回归生成过程
阅读 translate() 函数,观察如何从 <BOS> 开始,通过 Greedy Decoding 逐步预测 Token,直到生成 <EOS> 或达到最大生成长度。
这几个小实验都有助于把理论知识与实际代码联系起来。
八、项目适合哪些人?
我觉得这个项目比较适合:
-
正在学习 Transformer 和 Attention 机制的同学
-
有一定 PyTorch 基础,想理解模型底层实现的初学者
-
正在入门 NLP、机器翻译和大语言模型的学习者
-
看过《Attention Is All You Need》,希望动手复现核心架构的同学
它不是一个工业级翻译系统,而是一个可以阅读、修改、运行的学习项目。
九、总结:从看懂架构图,到真正理解代码
学习 Transformer 时,我觉得有一个很重要的过程:
看懂公式 → 理解架构 → 阅读代码 → 动手实现 → 运行验证。
公式和架构图能够帮助我们建立整体认识,但如果想进一步理解 Attention、Mask、Cross-Attention 和自回归生成,亲自写一遍往往会有更多收获。
这个项目就是围绕这一目标整理的。
目前已经包含完整源码、中英文 README、架构图、训练 Loss 曲线和 Colab 演示。
所有核心实现都放在一个 Python 文件中,方便学习和修改。
项目地址:
如果这个项目对你学习 Transformer 有帮助,欢迎到 GitHub 点一个 ⭐ Star!
也欢迎 Fork 项目、尝试修改代码,或者在 Issues 中交流学习过程中遇到的问题。
希望它能够帮助更多同学,从"知道 Transformer 是什么",走到"看得懂 Transformer 内部怎么计算"。