200行Python从零训练一个GPT:读懂Karpathy的microgpt项目

TL;DR
Andrej Karpathy 在 2026 年 2 月发布了 microgpt——一个仅有 200 行纯 Python、零依赖的脚本,完整实现了 GPT 的数据集加载、分词器、自动求导引擎、Transformer 架构、Adam 优化器、训练和推理。本文以这篇博客为蓝本,用通俗的语言带你理解 GPT 到底在做什么。
1. 为什么是 200 行?
GPT 在大多数人眼里是一个"黑盒":扔进文本,吐出文本,中间发生了什么无人知晓。Karpathy 的 microgpt 打破了这个黑盒——他用 200 行无依赖 Python,把 GPT 的完整算法链条摆在了你面前。
这个脚本包含了一个 GPT 需要的全部组件:
- 数据集与分词器(Tokenizer)
- 自动求导引擎(Autograd)
- Transformer 架构(Attention + MLP)
- Adam 优化器与训练循环
- 推理采样
正如 Karpathy 所说:“除此之外的一切都只是效率优化。”
2. 从名字到 token:最简分词器
GPT 无法直接处理文字,它只能处理整数。microgpt 使用了一个极简的分词器:把 26 个小写字母各分配一个整数 ID(0-25),再加一个特殊的 BOS(Beginning of Sequence)标记,总共 27 个 token。
以名字 “emma” 为例,它会被包装成 [BOS, e, m, m, a, BOS]。模型的任务是:给定前面的 token,预测下一个 token 是什么。这本质上是一个统计上的文档补全——当你把 prompt 当作文档的开头,模型的"回答"就是它认为最合理的文档续写。
3. 自动求导:理解反向传播的核心
microgpt 最精彩的部分之一是它手写了一个标量级别的自动求导引擎(Autograd)。每个 Value 对象封装了一个标量值和它的计算历史。当你做加法或乘法时,它同时记录局部梯度。反向传播时,链式法则(Chain Rule)从最终的 loss 出发,沿着计算图反向传播梯度——这正是 PyTorch 的 backward() 在标量层面的等价实现。
一个具体的例子:
a = Value(2.0)
b = Value(3.0)
c = a * b # c = 6.0
d = a + c # d = 8.0
d.backward()
print(a.grad) # 4.0(通过两条路径求和:b + 1)
print(b.grad) # 2.0(通过 a)
这里的梯度告诉你:如果某个参数增加一小点,loss 会上升还是下降,幅度多大。优化器就靠这个信息来调整参数。
4. Transformer 架构:注意力是沟通,MLP 是思考
microgpt 的模型架构是简化版 GPT-2,核心只有两个组件:
-
多头注意力(Multi-Head Attention):这是 token 之间唯一的沟通机制。每个 token 发出 Query(我在找什么)、Key(我有什么)、Value(我能提供什么)。注意力机制让当前 token 可以"看到"之前的所有 token,从而理解上下文。
-
前馈网络(MLP):每个 token 独立地通过一个两层神经网络进行"思考"。这是模型真正做复杂计算的地方。
两者通过残差连接(Residual Connection)串联:输出 = 输入 + 子层(输入)。这个简单的设计让梯度可以直接流过整个网络,使得训练深层模型成为可能。
microgpt 的模型只有 4,192 个参数。对比之下,GPT-2 有 16 亿参数,现代 LLM 则有数千亿参数。但算法的骨架完全一致。
5. 训练循环:从随机到有意义
初始时所有参数是随机的,模型输出完全混乱。训练循环重复以下步骤:
- 随机选取一个文档(一个名字)
- 正向传播:将名字的每个 token 逐个喂给模型,得到每一步的预测
- 计算 loss:衡量模型预测与真实下一个 token 的差距
- 反向传播:计算每个参数对 loss 的梯度
- Adam 优化器更新参数
经过若干轮迭代,模型开始学会名字的模式——字母出现的频率、常见组合、音节结构。最终它能"捏造"出听起来像真名的字符串。
6. 这意味着什么?
microgpt 告诉我们两件事。第一,GPT 的算法核心并不神秘——它就是一个统计性的序列预测器,用注意力机制来建模上下文依赖。第二,从 4,192 参数到数千亿参数,规模放大了同样的算法,而不是引入了什么魔法。
对于想入门深度学习的读者,microgpt 是最好的起点之一。完整的代码在 Karpathy 的博客和 GitHub Gist 上,值得逐行阅读。
参考资料
更多推荐

所有评论(0)