项目文件夹

0

Note

本文档由 WeHub 基于上游 README 翻译整理,属于社区翻译,非官方中文文档。
English · 原始项目 · 上游 README
原作者、版权与许可证归属以原始项目及本仓库 LICENSE 文件为准。

nanochat

nanochat logo scaling laws

nanochat 是用于训练 LLM 的最简实验框架(experimental harness)。它设计为在单 GPU 节点上运行,代码精简、易于 hack,并覆盖 LLM 的全部主要阶段,包括分词(tokenization)、预训练(pretraining)、微调(finetuning)、评估(evaluation)和推理(inference)。例如,你可以用仅 $48(约 2 小时的 8XH100 GPU 节点)训练出具备 GPT-2 能力的 LLM2019 年训练成本约 $43,000),然后通过简单的 CLI 与它对话。在 spot instance 上,总成本可低至约 $15。更一般地,nanochat 开箱即用,只需设置一个复杂度旋钮:--depth,即 GPT transformer 模型的层数(GPT-2 能力大约对应 depth 26)。所有其他超参数(transformer 宽度、注意力头数、学习率调整、训练时长、weight decay 等)都会以最优方式自动计算。

关于本仓库的问题,我建议使用来自 Devin/Cognition 的 DeepWiki 就仓库提问,或使用 Discussions tab,,或前往 Discord 上的 #nanochat 频道。

Time-to-GPT-2 Leaderboard

目前开发的主要焦点是调优预训练阶段,该阶段消耗的计算量最大。受 modded-nanogpt 仓库启发,为激励进展和社区协作,nanochat 维护一个「GPT-2 speedrun」排行榜,即在 wall-clock 时间内将 nanochat 模型训练到 GPT-2 级别能力所需的时间,以 DCLM CORE 分数衡量。runs/speedrun.sh 脚本始终反映训练 GPT-2 级别模型并与之对话的参考方式。当前排行榜如下:

# time val_bpb CORE Description Date Commit Contributors
0 168 hours - 0.2565 原始 OpenAI GPT-2 检查点 2019 - OpenAI
1 3.04 0.74833 0.2585 d24 基线,轻微过训练 Jan 29 2026 348fbb3 @karpathy
2 2.91 0.74504 0.2578 d26 轻微欠训练 +fp8 Feb 2 2026 a67eba3 @karpathy
3 2.76 0.74645 0.2602 将总 batch size 提升至 1M tokens Feb 5 2026 2c062aa @karpathy
4 2.02 0.71854 0.2571 将数据集更换为 NVIDIA ClimbMix Mar 4 2026 324e69c @ddudek @karpathy
5 1.80 0.71808 0.2690 autoresearch round 1 Mar 9 2026 6ed7d1d @karpathy
6 1.65 0.71800 0.2626 autoresearch round 2 Mar 14 2026 a825e63 @karpathy

我们最关心的主要指标是「time to GPT-2」——在 8XH100 GPU 节点上超越 GPT-21.6BCORE 指标所需的 wall-clock 时间。GPT-2 CORE 分数为 0.256525。2019 年训练 GPT-2 的成本约为 $43,000,令人难以置信的是,经过 7 年间全栈诸多进展,我们现在可以快得多地完成,且成本远低于 $100(例如,按当前约 $3/GPU/hr 计,8XH100 节点约 $24/hr,因此 2 小时约 $48)。

有关如何解读排行榜并参与贡献,请参阅 dev/LEADERBOARD.md

Getting started

Setup

nanochat 使用 uv 进行依赖管理。安装方式:

uv sync --extra gpu    # Use for CUDA (A100/H100/etc.)
uv sync --extra cpu    # (or) Use for CPU-only / MPS
source .venv/bin/activate

开发环境(额外安装 pytest、matplotlib、ipykernel、transformers 等):

uv sync --extra gpu --group dev

Reproduce and talk to GPT-2

最有意思的体验是训练你自己的 GPT-2 并与它对话。完整流程都包含在单个文件 runs/speedrun.sh 中,该脚本设计为在 8XH100 GPU 节点上运行。从你喜欢的云服务商启动一台新的 8XH100 GPU 机器(例如我使用并推荐 Lambda),,然后启动训练脚本:

bash runs/speedrun.sh

你可能希望在 screen 会话中运行,因为这大约需要 1.5 小时。完成后,可以通过 CLI 与模型对话。请再次确保本地 uv 虚拟环境已激活(运行 source .venv/bin/activate),然后开始聊天:

python -m scripts.chat_cli

让它写故事或诗歌。问它你是谁,看看会不会产生幻觉。问它天空为什么是蓝色的。或者为什么是绿色的。speedrun 是一个 4e19 FLOPs 能力模型,所以有点像在和幼儿园小朋友说话 :)。与 speedrun 模型对话的示例:

User: Hello whats up?

Assistant: Hello! How can I help you today?

User: Why is the sky blue?

Assistant: The sky is blue due to an optical illusion called the Rayleigh Scattering of Light, which occurs when sunlight passes through tiny particles in the air. These particles are made up of tiny blue and violet particles that cause the light to bend in a particular way.

User: That's cool. Write a poem about it.

Assistant: In the twilight's glow, the sky is blue,
A canvas of shimmering blue, where skies unfold,
A world of blue, where blue and more blue,
Are woven together in a tapestry so fine,
Where every hue seems to sing a story.
...

补充说明:

  • 代码在 Ampere 8XA100 GPU 节点上也能正常运行,只是会稍慢一些。
  • 省略 torchrun 后,所有代码在单 GPU 上也能正常运行,并会产生几乎相同的结果(代码会自动切换到梯度累积),但需要等待 8 倍的时间。
  • 如果你的 GPU 显存少于 80GB,需要调整部分超参数,否则会 OOM / 显存不足。在脚本中查找 --device-batch-size 并逐步减小,直到能跑通。例如从 32(默认)降到 16、8、4、2,甚至 1。再低就需要你对情况有更多了解,并更有创造性地调整。
  • 大部分代码是相当标准的 PyTorch,因此应能在任何支持它的设备上运行——xpu、mps 等,但我个人并未充分验证所有这些代码路径,因此可能存在一些坑。

Research

如果你是研究人员并希望帮助改进 nanochat,两个值得关注的脚本是 runs/scaling_laws.shruns/miniseries.sh。相关文档请参阅 Jan 7 miniseries v1。快速实验(约 5 分钟预训练)时,我最喜欢的规模是训练 12 层模型(GPT-1 大小),例如:

OMP_NUM_THREADS=1 torchrun --standalone --nproc_per_node=8 -m scripts.base_train -- \
    --depth=12 \
    --run="d12" \
    --model-tag="d12" \
    --core-metric-every=999999 \
    --sample-every=-1 \
    --save-every=-1 \

这会使用 wandb(运行名称为 "d12"),仅在最后一步运行 CORE 指标,且不会采样和保存中间检查点。我喜欢在代码中改点东西,然后重新跑 d12(或 d16 等),在迭代循环中观察是否有帮助。判断一次运行是否有帮助时,我喜欢在 wandb 图表中关注:

  1. val_bpb(以 bits per byte 为单位的、与词表大小无关的验证损失)随 steptotal_training_timetotal_training_flops 的变化。
  2. core_metricDCLM CORE 分数)
  3. 显存利用率、train/mfuModel FLOPS utilization)、train/tok_per_sec(训练吞吐量)

示例见 here.

需要重点注意的是,nanochat 的编写和配置围绕单一复杂度旋钮——transformer 的深度。这一个整数会自动决定所有其他超参数(transformer 宽度、注意力头数、学习率调整、训练时长、weight decay 等),使训练出的模型达到计算最优(compute optimal)。理念是用户无需思考或设置这些参数,只需通过 --depth 请求更小或更大的模型,一切就会「自动工作」。通过扫描不同深度,你可以得到 nanochat 在不同规模下的计算最优模型 miniseries。具备 GPT-2 能力的模型(目前最受关注)在当前代码下大约处于 d24-d26 范围。但任何对仓库的候选改动都必须足够有原则,以便在所有深度设置下都能生效。

在 CPU / MPS 上运行

脚本 runs/runcpu.sh 展示了一个在 CPU 或 Apple Silicon 上运行的极简示例。它会大幅缩小正在训练的 LLM,以便在几十分钟的合理训练时间内完成。这种方式无法获得很好的效果。

精度 / dtype

nanochat 不使用 torch.amp.autocast。相反,精度通过单一全局 COMPUTE_DTYPE(定义于 nanochat/common.py)显式管理。默认会根据你的硬件自动检测:

硬件 默认 dtype 原因
CUDA SM 80+ (A100, H100, ...) bfloat16 原生 bf16 张量核心
CUDA SM < 80 (V100, T4, ...) float32 不支持 bf16;可通过 NANOCHAT_DTYPE=float16 使用 fp16(使用 GradScaler
CPU / MPS float32 安全默认值。在较新的 macOS 上,MPS 也能顺利运行 NANOCHAT_DTYPE=bfloat16(内存约少 25%,速度相近)

可通过 NANOCHAT_DTYPE 环境变量覆盖默认值:

NANOCHAT_DTYPE=float32 python -m scripts.chat_cli -p "hello"   # force fp32
NANOCHAT_DTYPE=bfloat16 torchrun --nproc_per_node=8 -m scripts.base_train  # force bf16

工作原理:模型权重以 fp32 存储(用于优化器精度),但我们的自定义 Linear 层在前向传播时将其转换为 COMPUTE_DTYPE。嵌入层直接以 COMPUTE_DTYPE 存储以节省内存。这样能获得与 autocast 相同的混合精度收益,同时对各项运算以何种精度执行拥有完全显式控制。

注意:float16 训练会自动在 base_train.py 中启用 GradScaler 以防止梯度下溢。SFT 也支持该机制,但 RL 目前不支持。fp16 推理在各处均可正常工作。

指南

我发布了一系列可能有帮助的指南,按时间从新到旧排列:

文件结构

.
├── LICENSE
├── README.md
├── dev
│   ├── nanochat.png
│   └── repackage_data_reference.py # Pretraining data shard generation
├── nanochat
│   ├── __init__.py                 # empty
│   ├── checkpoint_manager.py       # Save/Load model checkpoints
│   ├── common.py                   # Misc small utilities, quality of life
│   ├── core_eval.py                # Evaluates base model CORE score (DCLM paper)
│   ├── dataloader.py               # Tokenizing Distributed Data Loader
│   ├── dataset.py                  # Download/read utils for pretraining data
│   ├── engine.py                   # Efficient model inference with KV Cache
│   ├── execution.py                # Allows the LLM to execute Python code as tool
│   ├── gpt.py                      # The GPT nn.Module Transformer
│   ├── loss_eval.py                # Evaluate bits per byte (instead of loss)
│   ├── optim.py                    # AdamW + Muon optimizer, 1GPU and distributed
│   └── tokenizer.py                # BPE Tokenizer wrapper in style of GPT-4
├── pyproject.toml
├── runs
│   ├── miniseries.sh               # Miniseries training script
│   ├── runcpu.sh                   # Small example of how to run on CPU/MPS
│   ├── scaling_laws.sh             # Scaling laws experiments
│   └── speedrun.sh                 # Train the ~$100 nanochat d20
├── scripts
│   ├── base_eval.py                # Base model: CORE score, bits per byte, samples
│   ├── base_train.py               # Base model: train
│   ├── chat_cli.py                 # Chat model: talk to over CLI
│   ├── chat_eval.py                # Chat model: eval tasks
│   ├── chat_rl.py                  # Chat model: reinforcement learning
│   ├── chat_sft.py                 # Chat model: train SFT
│   ├── infer_bench.py              # Inference: latency/throughput/VRAM bench
│   ├── tok_eval.py                 # Tokenizer: evaluate compression rate
│   └── tok_train.py                # Tokenizer: train it
├── tasks
│   ├── arc.py                      # Multiple choice science questions
│   ├── common.py                   # TaskMixture | TaskSequence
│   ├── gsm8k.py                    # 8K Grade School Math questions
│   ├── humaneval.py                # Misnomer; Simple Python coding task
│   ├── mmlu.py                     # Multiple choice questions, broad topics
│   └── smoltalk.py                 # Conglomerate dataset of SmolTalk from HF
├── tests
│   ├── test_attention_fallback.py  # FA3/SDPA attention fallback
│   ├── test_engine.py              # Inference engine, KV cache
│   ├── test_execution.py           # Sandboxed code execution
│   ├── test_optim.py               # MuonAdamW optimizer (needs GPU)
│   ├── test_tasks.py               # Task slicing, mixtures, HubDataset
│   └── test_tokenizer.py           # BPE round-trips, chat rendering
└── uv.lock

贡献

nanochat 的目标是推进微模型(micro models)领域的技术水平,使端到端全流程能在 1000 美元以内预算内完成。可及性(accessibility)既关乎总体成本,也关乎认知复杂度——nanochat 并非可无限配置的 LLM「框架」;代码库中没有庞大的配置对象、模型工厂或层层叠叠的 if-then-else。它是一个单一、内聚、极简、可读、可 hack、最大化可 fork 的「强基线」代码库,设计为从头到尾运行并产出一个可以对话的 ChatGPT 级模型。目前我个人最感兴趣的部分是缩短达到 GPT-2 水平的延迟(即 CORE 分数超过 0.256525)。目前约需 1.5 小时(已从 3 小时缩短),但通过改进预训练阶段还能进一步优化。

当前 AI 政策:披露。提交 PR 时,请声明其中是否有 substantial LLM contribution 的部分,且这些部分并非你本人撰写或你未能完全理解。

致谢

  • 名称(nanochat)源自我早期的项目 nanoGPT,,该项目仅涵盖预训练。
  • nanochat 还受到 modded-nanoGPT, 的启发——它将 nanoGPT 仓库游戏化,提供清晰指标和排行榜,并借鉴了其诸多思路及部分预训练实现。
  • 感谢 HuggingFace 提供 fineweb 和 smoltalk。
  • 感谢 Lambda 为本项目开发提供算力。
  • 感谢首席 LLM 巫师 🧙‍♂️ Alec Radford 的建议与指导。
  • 感谢仓库负责人 Sofie @svlandeg 协助管理 nanochat 的 issue、pull request 和讨论。

引用

如果你在研究中发现 nanochat 有帮助,可简单引用为:

@misc{nanochat,
  author = {Andrej Karpathy},
  title = {nanochat: The best ChatGPT that \$100 can buy},
  year = {2025},
  publisher = {GitHub},
  url = {https://github.com/karpathy/nanochat}
}

许可证

MIT