Loading...

文章背景图

nanoGPT:极简 GPT 训练代码学习指南

2025-11-13
0
- 字
- 分钟
|

nanoGPT:极简 GPT 训练代码学习指南

karpathy/nanoGPT 是 Andrej Karpathy 开源的、训练与微调中等规模 GPT 最简单、最快速的仓库,当前 Star 数约 64k,采用 MIT 协议,主要语言为 Python。它是对作者早期教学项目 minGPT 的重写,不再以课堂演示为首要目标,而是优先保证代码短小、正确、可改造。截至目前,仓库中的 train.py 脚本已能在单台 8×A100 40GB 节点上约 4 天完整复现 GPT-2(124M)在 OpenWebText 上的训练结果。代码本身极其朴素可读:train.py 是约 300 行的样板训练循环,model.py 是约 300 行的 GPT 模型定义,还可以选择性加载 OpenAI 官方 GPT-2 的预训练权重。2025 年 11 月作者特别发布说明:nanoGPT 已经较为老旧并停止维护,他新写了一个功能更完整、工程更现代的"表兄弟"项目 nanochat,今天的新手大概率应该直接去用 nanochat;但 nanoGPT 仍然保留在仓库里,供后人学习 GPT 训练的完整脉络。正因为代码极短,它非常方便被按自己的需求改造:你可以从零训练一个全新的小模型,也可以在预训练检查点(目前最大的起点是 OpenAI 的 GPT-2 1.3B)上做微调。作者把仓库定位成"能上手玩"的工程脚手架而不是教学玩具,因此所有超参数都写在独立的 config 文件里、所有命令行参数都保持可读,读者读完 model.py 与 train.py 两个文件就能真正讲清一个 GPT 从数据切分、前向计算、损失计算到反向更新、日志记录的完整链路。

一、项目官方信息

项目 信息
GitHub 仓库 karpathy/nanoGPT
作者 Andrej Karpathy
关联项目 minGPT、nanochat
Star 数 约 64k
开源协议 MIT
主要语言 Python
适用场景 从零训练/微调中小规模 GPT、复现 GPT-2、教学实验

二、官方图片

仓库 README 顶部使用项目题图 assets/nanogpt.jpg;在复现 GPT-2 一节附有 assets/gpt2_124M_loss.png 损失曲线图,展示 nanoGPT 复现 GPT-2(124M)时训练损失与验证损失随训练步数下降的过程,两条曲线最终收敛到与官方模型一致的水平,是证明"小代码也能复现大结果"的关键证据。本系列封面使用该仓库官方图。

三、环境要求

安装一条命令即可完成全部依赖:pip install torch numpy transformers datasets tiktoken wandb tqdm。各依赖分工如下:PyTorch 为 3.0 以下版本,承担全部张量计算;numpy 为 3.0 以下版本,负责数据数组处理;transformers 用于加载 Hugging Face 上的 GPT-2 官方检查点;datasets 用于下载并预处理 OpenWebText 数据集;tiktoken 是 OpenAI 开源的快速 BPE 分词库;wandb 为可选的实验日志与可视化平台;tqdm 提供命令行进度条。硬件方面:想完整复现 GPT-2(124M)至少需要一台 8×A100 40GB 节点,训练约 4 天;只做莎士比亚字符级小模型时,一张普通 A100 约 3 分钟即可完成;即使只有 MacBook,也能通过 CPU 或 Apple Silicon 的 MPS 后端跑通,但要显著调小模型规模。代码默认使用 PyTorch 2.0 的 torch.compile() 编译加速,该功能在部分平台(如 Windows)尚不可用,遇到报错时手动关闭即可。建议在虚拟环境中安装依赖,避免与系统其他 Python 包冲突。若只是快速体验,甚至可以跳过 wandb,仓库会在没有日志后端时自动降级为普通控制台打印。

四、完整部署步骤

1. 安装依赖

pip install torch numpy transformers datasets tiktoken wandb tqdm

2. 快速开始:莎士比亚字符级 GPT

如果不是深度学习专业人士,只想动手体验一下训练的"魔力",最快的入门方式是在莎士比亚作品上训练一个字符级 GPT。先把语料下载成单个 1MB 文件,并把原始文本整体切成一串整数:

python data/shakespeare_char/prepare.py

该脚本会在数据目录生成 train.bin 与 val.bin 两个二进制文件。接下来启动训练,模型规模取决于你的算力:

python train.py config/train_shakespeare_char.py

打开这份配置文件可以看到:训练的是一个上下文长度 256 字符、384 维特征通道、6 层 Transformer、每层 6 个注意力头的 GPT。在一张 A100 上约 3 分钟即可训练完成,最佳验证损失为 1.4697。权重会按验证损失定期写入 --out_dir 指定的 out-shakespeare-char 目录。训练结束后用采样脚本从最佳权重生成文本:

python sample.py --out_dir=out-shakespeare-char

采样结果会生成一段类似莎士比亚风格的对白文本——虽然字符级模型只训练了 3 分钟,拼出的句子语法不通,但已经能模仿出戏剧台词的节奏与人物称谓格式。如果改用微调 GPT-2 的方式在同一数据集上训练,效果还会明显更好。整个流程从数据准备到看到生成文本不到 5 分钟,非常适合第一次亲手跑通"训练一个语言模型"这件事。

3. 只有 MacBook(或低配电脑)时

没有 GPU 也完全不用担心,把各项规模调小即可。建议安装最新 PyTorch nightly 以获得更好的优化性能,一次典型的低配训练命令如下:

python train.py config/train_shakespeare_char.py --device=cpu --compile=False --eval_iters=20 --log_interval=1 --block_size=64 --batch_size=12 --n_layer=4 --n_head=4 --n_embd=128 --max_iters=2000 --lr_decay_iters=2000 --dropout=0.0

因为跑在 CPU 上,必须同时设置 --device=cpu 并关闭 PyTorch 2.0 编译(--compile=False);评估迭代次数从默认 200 降到 20,估计更 noisy 但更快;上下文长度从 256 降到 64,每迭代批大小降为 12 个样本;模型缩小为 4 层、4 头、128 维嵌入;训练迭代数降到 2000,学习率相应在 2000 步内线性衰减;由于网络非常小,正则化也一并放松(--dropout=0.0)。这样约 3 分钟跑完,损失约 1.88,生成的样本虽然粗糙,但已经能看出正确的字符风格。在 Apple Silicon Mac 上,较新的 PyTorch 请加 --device=mps(Metal Performance Shaders 的缩写),它会调用芯片上的 GPU,把训练速度提升 2~3 倍,从而允许使用更大的网络,细节见仓库 Issue 28。

4. 复现 GPT-2

专业用户更关心能否复现 GPT-2 的官方结果。先对 OpenWebText(OpenAI 私有 WebText 数据集的开源复刻版)做分词预处理:

python data/openwebtext/prepare.py

该脚本自动下载并分词 OpenWebText,生成以 uint16 字节连续存储 GPT-2 BPE token id 的 train.bin 与 val.bin。随后至少准备一台 8×A100 40GB 节点并运行:

torchrun --standalone --nproc_per_node=8 train.py config/train_gpt2.py

训练约 4 天,使用 PyTorch 分布式数据并行(DDP),最终验证损失可降到约 2.85。作为参照,OpenAI 官方 GPT-2 在 OWT 上直接评估的验证损失约为 3.11,但用它在 OWT 上微调一段时间后会降到约 2.85,两者基本打平。这一结果说明:不依赖任何私有数据集与神秘技巧,仅凭约 600 行可读代码,就可以在开源语料上把 124M 的 GPT 训练到与官方同一量级。

5. 多节点集群训练

如果集群环境中有幸有多台 GPU 节点,可以把训练横向扩展,例如跨两台节点同时训练:

# 第一台(主节点),示例 IP 123.456.123.456:
torchrun --nproc_per_node=8 --nnodes=2 --node_rank=0 --master_addr=123.456.123.456 --master_port=1234 train.py
# 工作节点:
torchrun --nproc_per_node=8 --nnodes=2 --node_rank=1 --master_addr=123.456.123.456 --master_port=1234 train.py

作者建议先用 iperf3 之类工具实测节点间互联带宽;如果没有 InfiniBand 高速网络,请在启动命令前加环境变量 NCCL_IB_DISABLE=1,否则多节点训练虽然能跑起来,但大概率会慢得像爬。检查点会按周期自动写入 --out_dir,想随时看效果直接 python sample.py 即可。单卡训练则直接 python train.py,脚本把所有超参数都暴露成命令行参数,透明、可读、易改造。

6. 微调

微调与训练并无本质区别,只是从预训练权重初始化,并使用更小的学习率。以莎士比亚数据集为例:进入 data/shakespeare 目录运行 prepare.py 下载 tiny shakespeare 数据集,用 GPT-2 自带的 OpenAI BPE 分词器渲染成 train.bin、val.bin,再运行示例微调配置:

python train.py config/finetune_shakespeare.py

微调与训练的区别只在初始化与学习率。 该配置通过 init_from 从 GPT-2 检查点初始化,之后照常训练,只是轮次更短、学习率更小。显存不足时可以缩小模型规模(可选 gpt2、gpt2-medium、gpt2-large、gpt2-xl 四档),或减小 block_size 也就是上下文长度。最佳权重(验证损失最低)会写入 out_dir,默认目录为 out-shakespeare,再用 python sample.py --out_dir=out-shakespeare 采样,就能得到一段充满戏剧腔、但仍有少量"黑暗旁白"气质的生成文本——作者坦言这份配置的超参数并没有精心调过,欢迎读者自行尝试。

7. 采样推理

sample.py 既可以从 OpenAI 发布的 GPT-2 官方模型采样,也可以从你自己训练的权重采样。例如从最大的 gpt2-xl 生成 5 段、每段 100 token:

python sample.py \
    --init_from=gpt2-xl \
    --start="What is the answer to life, the universe, and everything?" \
    --num_samples=5 --max_new_tokens=100

从自训模型采样时用 --out_dir 指定权重目录;也可以用文件内容作为提示词,例如 python sample.py --start=FILE:prompt.txt。采样脚本会自动根据检查点里记录的配置重建模型结构,不需要手动传参;如果想改采样温度、top-k 等参数,可以直接查看 sample.py 顶部的 argparse 定义。

五、核心特性与使用方法

GPT-2 基线对比。 借助 OpenAI GPT-2 官方检查点,可以在 OpenWebText 上跑出一组公开基线:依次运行 python train.py config/eval_gpt2.py、config/eval_gpt2_medium.py、config/eval_gpt2_large.py、config/eval_gpt2_xl.py,得到如下数据——gpt2(124M)训练损失 3.11、验证损失 3.12;gpt2-medium(350M)为 2.85 / 2.84;gpt2-large(774M)为 2.66 / 2.67;gpt2-xl(1558M)为 2.56 / 2.54。需要特别注意:GPT-2 当年是在从未公开的 WebText 上训练的,而 OpenWebText 只是一次尽力而为的开源复刻,两者存在数据集分布差异;因此把 GPT-2(124M)检查点放到 OWT 上微调一段时间、损失降到约 2.85,才是衡量复现是否成功的更合理基线。

效率说明。 bench.py 脚本可用于简单的模型 benchmark 与性能剖析,它与 train.py 训练循环的主体完全一致,但省去了日志、检查点等其他复杂度,适合单独测每步耗时、定位瓶颈。代码默认启用 PyTorch 2.0,仅需一行 torch.compile() 就能把单步迭代时间从约 250ms 降到约 135ms,作者为此特别称赞了 PyTorch 团队。如果你的机器较老、不支持编译后端,关闭编译后依然能完整训练,只是慢一些。

待办路线。 仓库 TODO 列表包括:调研并以 FSDP 替代当前的 DDP;在 LAMBADA、HELM 等标准评测集上评估零样本困惑度;继续打磨微调脚本的超参数;在训练过程中按计划线性增大 batch size;引入 rotary、alibi 等其他位置编码;把优化器 buffer 与模型参数在检查点中分开存储;增加网络健康度日志(梯度裁剪事件、梯度幅值等);以及围绕更好的初始化方式做更多实验。

六、常见问题 FAQ

1. 运行时报 torch.compile 相关错误怎么办? 该功能较新且实验性强,Windows 等平台尚未支持,在命令后加 --compile=False 即可关闭;代价是速度慢一些,但至少能正常跑起来。

2. 只有 Mac 能训练吗? 可以。用 CPU 或 Apple Silicon 的 MPS 后端,把模型层数、上下文长度、批大小都调小,几分钟即可完成一次字符级小模型训练;MPS 后端可带来 2~3 倍加速。

3. nanoGPT 和 nanochat 该选哪个? 2025 年 11 月作者明确说明:nanoGPT 已老旧弃用,今天要写聊天模型应直接使用 nanochat;nanoGPT 保留仅用于学习 GPT 预训练与微调的基本原理。

4. 复现 GPT-2 需要什么硬件? 至少一台 8×A100 40GB 节点,训练约 4 天;微调时显存不足可改用更小的 GPT-2 规格或减小 block_size。

5. 想深入理解这套代码看什么? 作者推荐观看其 Zero To Hero 系列课程,其中 GPT 从零实现的视频 最受欢迎;更多问题与讨论可以去 Discord 的 #nanoGPT 频道。

6. 多节点训练很慢是什么原因? 大概率是节点间网络没有 InfiniBand 支持,加 NCCL_IB_DISABLE=1 后再跑,并先用 iperf3 实测带宽。

7. 采样结果想指定开头怎么写? 用 --start 直接传入文本即可;如果想从文件读入提示词,写成 --start=FILE:prompt.txt;用 --num_samples 控制生成几段、--max_new_tokens 控制每段长度。

8. 项目还在维护吗? 作者已明确将 nanoGPT 归档为"历史留存",新的开发全部转到 nanochat;旧仓库仍接受 issue 讨论,但不会再添加新特性。

9. 适合用来学什么? 它非常适合作为读懂一个现代 Transformer 训练全流程的第一份源码:数据如何从文本变成 token id、GPT 前向如何实现、DDP 多卡如何启动、检查点如何落盘、采样如何从权重还原模型,全部在两个三百行的文件里讲完。配合作者的视频课程一起食用,可以在一两天之内建立对预训练与微调的完整直觉。

七、跳转链接

评论交流

文章目录