Karpathy 最新力作:200行代码实现完整GPT,这可能是最可爱的AI入门教程

你有没有想过,ChatGPT 背后那个神秘的大家伙——GPT,到底是怎么工作的?
别慌,Andrej Karpathy 又来救你了。这位前特斯拉 AI 总监、OpenAI 创始成员,最近搞了一个超级接地气的项目:Microgpt。顾名思义,就是"微型 GPT"——整整 200 行 Python 代码,没有 pip install,没有第三方依赖,训练推理全包圆。
你没看错,200 行。还不够你写个中等复杂度的爬虫。
事情是这样的
Karpathy 老师傅在 AI 教育领域有个外号叫"极简主义之父"。从当年的 micrograd、makemore、nanogpt 到现在的 microgpt,他一直致力于把复杂的东西拆到不能再拆为止。
这次他放话说:“我已经没法再简化了,这就是 GPT 的底线。”
好奇害死猫,但我还是忍不住想看看这 200 行到底装了什么魔法。
先看看 Microgpt 效果
训练数据是 32033 个英文名字,模型参数只有 4192 个(相比之下 GPT-2 有 16 亿,GPT-4 估计得上万亿)。
跑完 1000 步训练后,模型开始"幻觉"出一些看起来像名字但实际不存在的东西:
sample 1: kamon
sample 2: ann
sample 3: karai
sample 4: jaire
sample 5: vialan
sample 6: karia
你仔细品品,是不是有点那意思?模型确实学会了英文名字的拼写规律:元音辅音交替、常见后缀(-anna, -ia, -en)等等。
虽然只有 4192 个参数,但这已经是完整的语言模型了。
200 行代码里到底装了什么
让我带你拆开看看这口神秘的箱子。
第一层:数据
代码里直接内置了一个 32033 行的名字列表,作为训练语料。每个名字就是一个"文档"。
docs = [l.strip() for l in open('input.txt').read().strip().split('\n') if l.strip()]
模型的任务很简单:给定前面的字符,预测下一个字符是什么。比如输入 “em”,模型应该预测出 “m”。
第二层:分词器
这是整个流程里最"原始"的部分。
uchars = sorted(set(''.join(docs))) # 收集所有唯一字符
vocab_size = len(uchars) + 1 # 加1是给特殊token
每个字符直接对应一个数字 ID。英文字母一共 26 个,加上特殊标记,BOS(Begin Of Sequence),总共 27 个"词汇"。
没错,比你高考英语词汇量还少。
这和现在动辄几万个 token 的大模型Tokenizer 比起来,简直是玩具。但对于理解原理来说,够用了。
第三层:反向传播
这是最硬核的部分。训练神经网络需要知道"往哪个方向调整参数",反向传播就是干这个的。
Karpathy 写了一个 Value 类:
class Value:
def __init__(self, data, children=(), local_grads=()):
self.data = data
self.grad = 0
self._children = children
self._local_grads = local_grads
每个数字都是一个"节点",记录自己是怎么算出来的(_children),以及每个输入对输出的影响(_local_grads)。
调用 backward() 时,梯度像水流一样从结果倒着流回参数。
听起来很抽象?Karpathy 举了个例子:
“如果汽车速度是自行车的 2 倍,自行车速度是步行的 4 倍,那么汽车速度就是步行的 2 × 4 = 8 倍。”
链式法则就是乘法,一层一层乘回去。
第四层:GPT 架构
真正的重头戏来了。
模型结构长这样:
def gpt(token_id, pos_id, keys, values):
# 1. 嵌入层:把字符ID变成向量
tok_emb = state_dict['wte'][token_id]
pos_emb = state_dict['wpe'][pos_id]
x = tok_emb + pos_emb # 位置编码
# 2. Transformer 层
for li in range(n_layer):
# 2.1 注意力机制
q = linear(x, state_dict[f'layer{li}.attn_wq'])
k = linear(x, state_dict[f'layer{li}.attn_wk'])
v = linear(x, state_dict[f'layer{li}.attn_wv'])
# 3. MLP 前馈网络
x = linear(x, state_dict[f'layer{li}.mlp_fc1'])
x = [xi.relu() for xi in x]
x = linear(x, state_dict[f'layer{li}.mlp_fc2'])
# 4. 输出层
logits = linear(x, state_dict['lm_head'])
return logits
注意力机制就是让每个位置"看看"前面的字,然后决定要从它们那里获取什么信息。
举个例子,当模型看到 “em” 要预测第三个字母时,它会注意到前面的 “e” 是个元音,然后更倾向于预测下一个也是元音(或者辅音)。
这就是语言模型学会语法的方式。
第五层:训练和推理
训练就是不断重复:输入字符 → 预测下一个 → 计算损失 → 反向传播 → 更新参数。
推理时,模型一次只生成一个字符,然后把生成的字符塞回输入,继续预测下一个。直到模型输出结束标记(BOS),或者达到最大长度。
这就是为什么 ChatGPT 是一个字一个字地蹦出来的。
跑起来
你只需要:
python train.py
在 MacBook 上大概跑 1 分钟就能看到效果。loss 会从 3.3(完全随机瞎猜)降到 2.37 左右。
然后你就能得到一堆看起来像名字但实际不存在的"幻觉"产物。
这东西能干嘛
说实话,4192 个参数的小模型,生成质量肯定不能和 ChatGPT 比。
但它的价值不在于"好用",而在于"能懂"。
如果你一直被 PyTorch、TensorFlow 那些复杂的 API 绕得头晕,想搞清楚神经网络到底在干什么,这段代码就是最好的起点。
没有隐藏层、没有魔法,就是最纯粹的数学。
Karpathy 的教学路径是这样的:
| 文件 | 内容 |
|---|---|
| train0.py | 统计频率——连神经网络都没有 |
| train1.py | MLP + 手写梯度 + SGD |
| train2.py | 自动求导(就是 Value 类) |
| train3.py | 位置编码 + Transformer |
| train4.py | GPT 完整版 + Adam 优化器 |
Microgpt 就是最后的成品。
写在最后
200 行代码,放到十年前可能就是一个本科生的课程作业。
十年后,这些简单的积木变成了估值千亿的 AI 帝国。
如果你想搞清楚 GPT 到底是怎么回事,从这 200 行开始就够了。
常见问题
Q: Microgpt 和真实的 GPT 有什么区别? A: 核心算法完全一样,都是 Transformer + 自回归生成。区别在于规模:Microgpt 只有 4192 个参数,GPT-4 有上万亿参数。规模决定了能力的上限,但底层原理是相通的。
Q: 运行 Microgpt 需要什么环境? A: 只要有 Python 就行,不需要 pip install,不需要 GPU。Karpathy 特意去掉了所有第三方依赖,就是为了让每个人都能跑起来。
Q: 这个项目适合什么人看? A: 想入门 AI/神经网络但被复杂代码劝退的人。200 行代码,讲完从数据到训练到推理的全流程,很难找到更简洁的教程了。
相关资源:
关注梦兽编程微信公众号,解锁更多黑科技