本仓库托管了 NanoGPT 速度挑战赛,我们(协作/竞争)寻找最快的算法,使用 8 块 NVIDIA H100 GPU 训练一个语言模型,使其在 FineWeb 验证集上达到 3.28 的交叉熵损失。
该目标(FineWeb 验证损失 3.28)源自 Andrej Karpathy 在 llm.c 中对 GPT-2 的复现,该复现在运行 45 分钟后达到了此损失。速度挑战赛的代码同样源自 llm.c 的 PyTorch 训练器,而后者又源自 NanoGPT,因此得名。
得益于众多贡献者的努力,本仓库现已包含一个训练算法,能够在以下条件下达到目标性能:
* 在 8xH100 上 不到 90 秒(llm.c 的 GPT-2 复现需要 45 分钟)
* 不到 4 亿 tokens(llm.c 的 GPT-2 复现需要 100 亿)
训练速度的提升得益于以下技术:
* 现代化架构:旋转位置编码、QK-Norm 和 ReLU²
* Muon 优化器 [文章] [仓库]
* 对输出头使用 FP8 矩阵乘法,以及非对称重新缩放和 logit softcap
* 将投影初始化为零(类似 muP)
* 从嵌入层到每个块的跳跃连接,以及从块 3 到 6 的跳跃连接
* 混入注意力层值(value)的额外嵌入(受 Zhou et al. 2024 启发)
* 带有长短滑动窗口注意力模式(受 Gemma 2 启发)和窗口大小预热(使用 YaRN)的 Flash Attention 3
* 对齐训练批次起始位置到文档结束符,并设置最大文档长度
* 在更新参数前,为嵌入层和语言模型头累积 2 步梯度
* 对最后 3 个注意力层使用单一激活输入的 Backout
* Muon 中的 Polar Express 实现
* 用于实现 1 token 回溯的 Smear 模块
* 稀疏注意力门控
* NorMuon
* 谨慎权重衰减,其调度与学习率绑定
* 残差流的指数衰减
* 批次大小调度
* 最大序列长度调度
* 部分键偏移
* 多 token 预测
* 在训练进行到 2/3 时解绑嵌入和语言模型头
* 对值嵌入和跳跃连接额外添加门控
* 配对头注意力
* 二元组哈希嵌入
以及许多系统层面的优化。
贡献者列表(随每项新纪录不断增长):@bozavlado; @brendanh0gan; @fernbear.bsky.social; @Grad62304977; @jxbz; @kellerjordan0; @KoszarskyB; @leloykun; @YouJiacheng; @jadenj3o; @KonstantinWilleke, @alexrgilbert, @adricarda, @tuttyfrutyee, @vdlad; @ryanyang0, @vagrawal, @classiclarryd, @byronxu99, @varunneal, @EmelyanenkoK, @bernard24 / https://www.hiverge.ai/, @Gusarich, @li_zichong, @akash5474, @snimu, @roeeshenberg, @ChrisJMcCormick, @dominikkallusky, @acutkosky, @manikbhandari, @andrewbriand, @jrauvola, @soren_dunn_, @photon_mz, @srashedll, @dhrvji, @EmmettBicker, @dualverse-ai, @sisovicm, @moof2x, @samacqua
要运行当前记录,请执行以下命令。
git clone https://github.com/KellerJordan/modded-nanogpt.git && cd modded-nanogpt
pip install -r requirements.txt
# 仅下载前 9 亿个训练 tokens 以节省时间
python data/cached_fineweb10B.py 9
./run.sh
如果 ./run.sh 报错 torchrun: command not found,请将 torchrun 添加到路径。
注意:首次运行代码时,torch.compile 将增加约 7 分钟的延迟。
官方记录使用来自 https://app.primeintellect.ai/ 的 8 块 NVIDIA H100 GPU 计时。PrimeIntellect 慷慨赞助了近期的验证运行。
如果 CUDA 或 NCCL 版本与您当前系统设置不兼容,Docker 是一个有用的备选方案。此方法标准化了 CUDA、NCCL、CUDNN 和 Python 的版本,减少了依赖性问题并简化了设置。
注意:系统上必须已安装 NVIDIA 驱动(当仅有 NVIDIA 驱动和 Docker 可用时很有用)。
git clone https://github.com/KellerJordan/modded-nanogpt.git && cd modded-nanogpt
# 构建 Docker 镜像
sudo docker build -t modded-nanogpt .
# 运行数据下载(例如 8 亿 tokens)
sudo docker run -it --rm --gpus all -v $(pwd):/modded-nanogpt modded-nanogpt python data/cached_fineweb10B.py 8
# 运行训练脚本
sudo docker run -it --rm --gpus all -v $(pwd):/modded-nanogpt modded-nanogpt sh run.sh
要获取交互式 Docker 环境,可以使用
sudo docker run -it --rm --gpus all -v $(pwd):/modded-nanogpt modded-nanogpt bash
以下是关于以下竞争性任务的世界速度纪录的历史演进:
使用 8 块 NVIDIA H100,将神经网络训练到 ≤3.28 的 FineWeb 验证损失。
注意:3.28 的目标是为了匹配 Andrej Karpathy 的 GPT-2 (small) 复现。
| # | 纪录时间 | 描述 | 日期 | 日志 | 贡献者 |
|---|---|---|---|---|---|
| 1 | 45 分钟 | llm.c 基线 | 05/28/24 | 日志 | @karpathy, llm.c 贡献者 |
| 2 | 31.4 分钟 | 调整学习率 & 旋转位置编码 | 06/06/24 | 日志 | @kellerjordan0 |
| 3 | 24.9 分钟 | 引入 Muon 优化器 | 10/04/24 | 无 | @kellerjordan0, @jxbz |
| 4 | 22.3 分钟 | Muon 改进 | 10/11/24 | 日志 | @kellerjordan0, @bozavlado |
| 5 | 15.2 分钟 | 填充嵌入, ReLU², 零初始化投影, QK-norm | 10/14/24 | 日志 | @Grad62304977, @kellerjordan0 |
| 6 | 13.1 分钟 | 分布式 Muon 开销 | 10/18/24 | 日志 | @kellerjordan0 |
| 7 | 12.0 分钟 | 升级 PyTorch 2.5.0 | 10/18/24 | 日志 | @kellerjordan0 |
| 8 | 10.8 分钟 | 解绑嵌入和头 | 11/03/24 | 日志 | @Grad62304977, @kellerjordan0 |
| 9 | 8.2 分钟 | 值和嵌入跳跃连接, 动量预热, logit softcap | 11/06/24 | 日志 | @Grad62304977, @kellerjordan0 |
| 10 | 7.8 分钟 | Bfloat16 激活 | 11/08/24 | 日志 | @kellerjordan0 |
| 11 | 7.2 分钟 | U-net 模式跳跃连接 & 双倍学习率 | 11/10/24 | 日志 | @brendanh0gan |
| 12 | 5.03 分钟 | 1024-ctx 密集因果注意力 → 64K-ctx FlexAttention | 11/19/24 | 日志 | @KoszarskyB |
| 13 | 4.66 分钟 | 注意力窗口预热 | 11/24/24 | 日志 | @fernbear.bsky.social |
| 14 | 4.41 分钟 | 值嵌入 | 12/04/24 | 日志 | @KoszarskyB |
| 15 | 3.95 分钟 | U-net 模式值嵌入, 代码优化 | 12/08/24 | 日志 | @leloykun, @YouJiacheng |
| 16 | 3.80 分钟 | 分割值嵌入, 块级滑动窗口, 分离块掩码 | 12/10/24 | 日志 | @YouJiacheng |
| 17 | 3.57 分钟 | 稀疏化值嵌入, 改进旋转位置编码, 移除一个注意力层 | 12/17/24 | 日志 | @YouJiacheng |
| 18 | 3.4 分钟 | 降低 logit softcap 从 30 到 15 | 01/04/25 | 日志 | @KoszarskyB |
| 19 | 3.142 分钟 | FP8 头, 偏移 logits, 学习率衰减到 0.1 而非 0.0 | 01/13/25 | 日志 | @YouJiacheng |
| 20 | 2.992 分钟 | 合并 QKV 权重, 长短注意力, 注意力缩放, 降低 Adam epsilon, 批处理 Muon | 01/16/25 | 日志 | @leloykun, @fernbear.bsky.social, @YouJiacheng, @brendanh0gan, @scottjmaddox, @Grad62304977 |
| 21 | 2.933 分钟 | 减少批次大小 | 01/26/25 | 日志 | @leloykun |
| 21 | 2.997 分钟 | 第 21 条记录(新计时方式) | 02/01/25 | 日志 | 非新纪录,仅为使用更新后的规则重新计时 #21 |
| 21 | 3.014 分钟 | 第 21 条记录(最新 torch) | 05/24/25 | 日志 | 非新纪录,仅为使用最新 torch 重新计时 #21 |
| 22 | 2.990 分钟 | 更快的梯度全规约 | 05/24/25 | 日志 | @KonstantinWilleke, @alexrgilbert, @adricarda, @tuttyfrutyee, @vdlad; Enigma 项目 |
| 23 | 2.979 分钟 | 重叠计算和梯度通信 | 05/25/25 | 日志 | @ryanyang0 |
| 24 | 2.966 分钟 | 用 reduce_scatter 替换梯度 all_reduce | 05/30/25 | 日志 | @vagrawal |
| 25 | 2.896 分钟 | 升级 PyTorch 到 2.9.0.dev20250713+cu126 | 07/13/25 | 日志 | @kellerjordan0 |
| 26 | 2.863 分钟 | 对齐训练批次起始位置到 EoS, 增加冷却分数到 .45 | 07/13/25 | 日志 | @classiclarryd |
| 27 | 2.817 分钟 | 转置一个 MLP 矩阵 + 添加对称矩阵乘法的 Triton 内核 | 07/18/25 | 日志, PR | @byronxu99 |
| 28 | 2.812 分钟 | 稀疏注意力门控 | 08/23/25 | 日志, PR | @classiclarryd |
| 29 | 2.731 分钟 | Flash Attention 3, 2048 max_doc_len, 更新 ws 调度 | 09/03/25 | 日志, PR | @varunneal |
| 30 | 2.717 分钟 | 移除第一个 MLP 层 | 09/05/25 | 日志, PR | @EmelyanenkoK |
| 31 | 2.656 分钟 | 在训练和验证期间动态整合 YaRN | 09/10/25 | 日志, PR | @classiclarryd |
| 32 | 2.625 分钟 | 优化分布式训练, 改进跳跃连接门控, 增强 bfloat16 使用 | 09/11/25 | 日志, PR | @bernard24 & AI 系统 hiverge.ai |
| 33 | 2.565 分钟 | 异步获取和索引数据批次, 扩展验证用最后一层注意力窗口 | 09/15/25 | 日志, PR | @classiclarryd |
| 34 | 2.547 分钟 | 将 token 嵌入向前滑动 1 个位置 | 09/18/25 | 日志, PR | @classiclarryd |
| 35 | 2.527 分钟 | 移除第一个注意力层, 扩展所有用于验证的长窗口, 更新调度 | 09/21/25 | 日志, PR | @classiclarryd |
| 36 | 2.495 分钟 | MuonCustomSizing, 在共享调用中执行 mlp 和 attn 的 reduce scatter | 09/23/25 | 日志, PR | @classiclarryd |
| 37 | 2.483 分钟 | 在训练期间以 BF16 计算交叉熵 | 09/27/25 | 日志, PR | @Gusarich |
| 38 | 2.476 分钟 | Polar Express, 替代 Newton-Schulz | 09/29/25 | 日志, PR | @varunneal |
| 39 | 2.447 分钟 | 仅每隔一步更新 Adam 参数, 减少批次大小 | 09/30/25 | 日志, PR | @classiclarryd |
| 40 | 2.358 分钟 | Backout, 杂项超参数调整, 优化 lambda 填充 | 10/04/25 | 日志, PR | @classiclarryd |
| 41 | 2.345 分钟 | NorMuon | 10/24/25 | 日志, PR | @li_zichong |
| 42 | 2.313 分钟 | 更新 NorMuon LR, Step Logic | 10/27/25 | 日志, PR | @varunneal |
| 43 | 2.284 分钟 | 带调度的谨慎权重衰减 | 11/10/25 | 日志, PR | @varunneal |
| 44 | 2.269 分钟 | Adam 的反向钩子, Profiling 101 | 11/16/25 | 日志, PR | @akash5474 |
| 45 | 2.248 分钟 | 细化跳跃架构, 更新指数衰减初始化 | 11/18/25 | 日志, PR | @classiclarryd |
| 46 | 2.203 分钟 | 批次大小调度 | 11/29/25 | 日志, PR | @varunneal |
| 47 | 2.193 分钟 | 将 attn lambda 乘以权重而非数据, 修复预热 | 12/10/25 | 日志, PR | @roeeshenberg |
| 48 | 2.170 分钟 | 加速 Muon, 额外的预乘 lambda, 重塑矩阵, 更新 lr, 更新 NorMuon 轴 | 12/11/25 | 日志, PR | @ChrisJMcCormick |
| 49 | 2.146 分钟 | 部分键偏移 | 12/14/25 | 日志, PR | @classiclarryd |
| 50 | 2.128 分钟 | 将谨慎权重衰减扩展到 Adam 参数 | 12/18/25 | 日志, PR | @roeeshenberg |
| 51 | 2.075 分钟 | 重新绑定 Embed 到 lm_head, 重新调整 fp8 尺度 | 12/19/25 | 日志, PR | @varunneal |
| 52 | 2.037 分钟 | 通过增加 beta 平滑标量, 降低 smear 门控 lr, 在转换期间冻结标量, adam 全规约 | 12/21/25 | 日志, PR | @ChrisJMcCormick |
| 53 | 1.988 分钟 | 多 token 预测, 在训练 2/3 时解绑 embed/lm_head, lr 更新, 调整 CWD | 12/22/25 | 日志, PR | @varunneal, feat. @classiclarryd |
| 54 | 1.940 分钟 | 非对称 Logit 重新缩放 | 12/26/25 | 日志, PR | @classiclarryd |
| 55 | 1.918 分钟 | 值嵌入和跳跃连接的门控 | 12/29/25 | 日志, PR | @classiclarryd |
| 56 | 1.894 分钟 | 优化和编译 Adam, 增加 Adam 缓冲区精度, 将门控从 Muon 移到 Adam 参数库 | 12/31/25 | [日志](records/track_1_short/2025-12-31_GatesToCompiledAdam/12-31-gates-to-adam- |