nanochat 全栈 LLM 训练实践指南:从零训练 GPT-2 级模型并与之对话

发布时间:2026/9/20 2:41:20
nanochat 全栈 LLM 训练实践指南:从零训练 GPT-2 级模型并与之对话 nanochat 全栈 LLM 训练实践指南从零训练 GPT-2 级模型并与之对话【免费下载链接】OpenResearchTurn your coding agents into research agents项目地址: https://gitcode.com/GitHub_Trending/op/OpenResearchnanochat 是一个运行在单 GPU 节点上的极简 LLM 实验训练框架覆盖分词器训练、预训练、SFT 微调、评估与推理全流程。本篇指南以 demo/nanochat/base/README.md 为核心骨架结合仓库源码与运行脚本系统讲解如何用不到 100 美元复现 2019 年约 4.3 万美元训练成本的 GPT-2 能力级模型并深入剖析其「一个复杂度旋钮--depth」的设计哲学、精度管理机制与 Time-to-GPT-2 排行榜。读完本文你将掌握 nanochat 的环境搭建、一键复现、科研迭代实验与 CPU/MPS 降级运行等完整实战方案。项目定位最小可 hack 的全栈 ChatGPT 克隆nanochat 的定位是「最简单、最可修改的 LLM 训练实验框架」the minimal full-stack ChatGPT clone。与依赖庞大配置对象的通用 LLM 框架不同它刻意保持单薄、连贯、可读、可 fork 的代码形态——没有巨型配置对象、没有模型工厂、没有 if-then-else 怪物而是将「从头训练一个可对话的 ChatGPT 级模型」这条链路端到端跑通。项目覆盖的完整阶段包括分词Tokenizer训练 BPE 分词器评估压缩率预训练Pretraining训练 base 模型GPT 能力级微调FinetuningSFT 教模型对话特殊 token、工具调用与多项选择评估Evaluationval bpb、CORE 指标、样本采样推理Inference带 KV Cache 的高效生成与 CLI 对话其代码结构见 demo/nanochat/base/README.md 的文件结构小节核心模块位于 nanochat/GPT 模型、优化器、数据加载器、分词器、推理引擎、代码执行等与 scripts/预训练、评估、SFT、RL、CLI 对话、tokenizer 训练等脚本。Time-to-GPT-2 排行榜衡量预训练进度的核心指标当前开发主线聚焦预训练阶段最耗算力的环节。受 modded-nanogpt 启发nanochat 维护了一个「GPT-2 speedrun」排行榜衡量的是在 8XH100 GPU 节点上将 nanochat 模型训练到 GPT-2 能力级以 DCLM CORE 分数衡量所需的墙钟时间。排行榜的权威参考实现是 runs/speedrun.sh它始终反映训练 GPT-2 级模型并与它对话的参考路径。README 中记录的最新榜单截至文档写作时#timeval_bpbCOREDescriptionDateCommitContributors0168 hours-0.2565Original OpenAI GPT-2 checkpoint2019-OpenAI13.040.748330.2585d24 baseline, slightly overtrainedJan 29 2026348fbb3karpathy22.910.745040.2578d26 slightly undertrainedfp8Feb 2 2026a67eba3karpathy32.760.746450.2602bump total batch size to 1M tokensFeb 5 20262c062aakarpathy42.020.718540.2571change dataset to NVIDIA ClimbMixMar 4 2026324e69cddudek karpathy51.800.718080.2690autoresearch round 1Mar 9 20266ed7d1dkarpathy61.650.718000.2626autoresearch round 2Mar 14 2026a825e63karpathy核心指标是time to GPT-2在 8XH100 节点上墙钟时间击败 GPT-21.6B的 CORE 指标。GPT-2 的 CORE 分数为 0.256525。2019 年训练 GPT-2 约花费 4.3 万美元得益于 7 年间全栈技术的进步如今在约 3 美元/GPU/小时的行情下8XH100 节点约 24 美元/小时2 小时约 48 美元即可完成使用 spot 实例总成本可低至约 15 美元。排行榜的解读与贡献方式详见 demo/nanochat/base/dev/LEADERBOARD.md。从源码可以看到 CORE 指标实现的细节核心评估逻辑位于 nanochat/core_eval.py实现了 DCLM 论文描述的三类任务——multiple_choice多项选择取各选项平均 loss 最低者、schema上下文方案匹配、language_modeling语言建模batch size 为 1 的逐 token 自回归预测。评估支持 few-shot 采样与分布式分片按 rank 交错分配样本并 all_reduce 汇总详见 demo/nanochat/base/README.md 中core_eval.py的注释说明。环境搭建基于 uv 的依赖管理nanochat 使用 uv 管理依赖。安装与激活uv sync --extra gpu # 使用 CUDAA100/H100 等 uv sync --extra cpu # 或仅 CPU / MPS source .venv/bin/activate需要开发依赖pytest、matplotlib、ipykernel、transformers 等uv sync --extra gpu --group dev从 pyproject.toml 可以看到依赖设计的两个要点PyTorch 版本锁定为torch2.9.1并通过[tool.uv.sources]将 torch 拆分为pytorch-cpu与pytorch-cu128两个索引分别对应cpu与gpu两个 extra——这解释了为什么 README 用--extra gpu与--extra cpu区分安装目标[tool.uv] conflicts声明了cpu与gpu两个 extra 互斥不可同时安装。其余核心依赖还包括rustbpeRust 实现的 BPE 分词、tiktoken、wandb实验日志、filelock多进程下载锁、pyarrowparquet 数据读取等。一键复现并对话speedrun 全流程最有乐趣的玩法是训练一个自己的 GPT-2 并和它聊天整个流程收敛在 runs/speedrun.sh 这一个文件中设计目标是跑在空白 8XH100 GPU 节点上。启动方式bash runs/speedrun.sh由于全程约 1.5 小时建议放进 screen 会话脚本注释中还给出了带 wandb 与日志文件的 launch 方式screen -L -Logfile runs/speedrun.log -S speedrun bash runs/speedrun.sh训练完成后激活本地 uv 虚拟环境source .venv/bin/activate通过 CLI 与模型对话python -m scripts.chat_clispeedrun 是 4e19 FLOPs 能力级的模型对话风格有点像幼儿园小朋友——可以让它写故事或诗歌问它「你是谁」来观察幻觉问天空为什么是蓝的。README 中给出了一段示例对话模型对「天空为什么是蓝的」给出了瑞利散射的光学解释还能围绕主题写一首诗。speedrun 脚本的完整流水线解析逐段阅读 runs/speedrun.sh 可以还原这条端到端流水线环境自举export OMP_NUM_THREADS1设置中间产物目录NANOCHAT_BASE_DIR$HOME/.cache/nanochat这也是 common.py 中get_base_dir()的默认行为自动安装 uv、创建.venv、执行uv sync --extra gpu并激活。wandb 日志默认使用dummy特殊值跳过日志设置WANDB_RUN环境变量即可启用。分词器与数据python -m nanochat.dataset -n 8先下载前 8 个数据 shard约 20 亿字符用于训练分词器每个 shard 约 250M 字符、约 100MB 压缩文本随后在后台python -m nanochat.dataset -n 170 继续下载训练所需的约 170 个 shardGPT-2 能力预训练约需 150 个多留 20 个余量数据集全量最多 6542 个 shard接着python -m scripts.tok_train训练词表大小 2^15 32768 的 BPE 分词器再python -m scripts.tok_eval评估压缩率。从 dataset.py 可以看到当前预训练数据源是 NVIDIA ClimbMix-400Bhttps://huggingface.co/datasets/karpathy/climbmix-400b-shuffleMAX_SHARD 6542并保留了从 FinewebEdu-100B 升级的兼容逻辑。预训练等待后台下载完成后执行torchrun --standalone --nproc_per_node8 -m scripts.base_train -- --depth24 --target-param-data-ratio8 --device-batch-size16 --fp8 --run$WANDB_RUN即训练 d24 模型为击败 GPT-2 而略微欠训练把数据:参数比从计算最优的 10.5 降到 8随后scripts.base_eval评估 CORE 指标、train/val bpb 并采样。SFT 微调scripts.chat_sft教会模型对话特殊 token、工具使用与多项选择再用scripts.chat_eval -i sft评估。对话python -m scripts.chat_cli -p Why is the sky blue?去掉-p即进入交互模式。硬件与显存的适配要点README 给出四条重要的实操提示代码在 8XA100Ampere节点上同样可运行只是稍慢去掉torchrun即可在单卡上运行代码会自动切换为梯度累积结果几乎一致但需要等 8 倍时间若 GPU 显存不足 80GB需要调整超参数核心是找到--device-batch-size并逐步降低默认 32 → 16、8、4、2 甚至 1更低就需要更深的领域知识了代码绝大部分是 vanilla PyTorch理论上支持 xpu、mps 等后端但作者未逐一验证这些路径可能存在边界问题。关于梯度累积的自动切换base_train.py 中的实现是先按device-batch-size * max-seq-len * ddp_world_size算出单步实际 token 数再用total_batch_size // world_tokens_per_fwdbwd计算grad_accum_steps单卡world_size1时该数值自然放大 8 倍正是「去掉 torchrun 自动变慢 8 倍」的机制来源。科研迭代scaling laws 与 miniseries 脚本快速实验的标准姿势d12 迭代循环对研究者而言runs/scaling_laws.sh 与 runs/miniseries.sh 是最有价值的两个脚本详见 README 的 Research 小节。作者最爱的快速实验尺度是训练 12 层模型GPT-1 大小约 5 分钟预训练例如OMP_NUM_THREADS1 torchrun --standalone --nproc_per_node8 -m scripts.base_train -- \ --depth12 \ --rund12 \ --model-tagd12 \ --core-metric-every999999 \ --sample-every-1 \ --save-every-1 \该命令使用 wandbrun 名 d12CORE 指标只在最后一步运行不采样、不保存中间 checkpoint——适合「改一点代码 → 重跑 d12或 d16 等→ 看是否变好」的迭代循环。判断一次改动是否有益建议在 wandb 中监控三类曲线val_bpb词表大小无关的 bits per byte 验证损失随step、total_training_time、total_training_flops的变化core_metricDCLM CORE 分数显存利用率、train/mfuModel FLOPS utilization模型算力利用率、train/tok_per_sec训练吞吐。单一复杂度旋钮--depth 的设计哲学nanochat 最关键的设计是全部围绕 Transformer 的深度这一个整数旋钮配置。--depth这一层数会自动推导出其余所有超参数——Transformer 宽度、注意力头数、学习率调整、训练视界、权重衰减等——使得训练出的模型计算最优compute-optimal。用户无需思考或设置这些细节只需用--depth指定想要更小或更大的模型即可。通过扫掠 depth就得到了 nanochat 的「miniseries」——一系列不同规模的计算最优模型。当前代码下 GPT-2 能力模型恰好落在 d24–d26 区间附近任何候选改动都必须「有原则」到对任意 depth 设置都成立。从源码看这个自动推导链路由 base_train.py 的若干步骤实现模型维度model_dim depth * aspect_ratio默认 aspect-ratio 64再向上取整到head_dim的整数倍保证 FA3 所需的 head_dim 整除性训练视界三种方式按优先级取一——显式--num-iterations、--target-flops按num_flops_per_token与总 batch 反推迭代数用于 scaling laws、--target-param-data-ratio按目标 token 数 ratio × scaling params反推默认 12Chinchilla 为 20batch size以 d12 为参考B_REF 2^19 ≈ 524,288 tokens按 Power Lines 论文的Bopt ∝ D^0.383定律外推并取 2 的幂学习率修正按η ∝ √(B/B_ref)缩放权重衰减采用 T_epoch 框架T_epoch B/(η·λ·D)恒定推导出λ λ_ref · √(B/B_ref) · (D_ref/D)。模型的参数分组与优化器设置见 gpt.py 的setup_optimizer()矩阵参数走Muon 优化器按形状分组以便 stacking嵌入/unembedding/标量走AdamW嵌入 lr 远高于矩阵 lr且 AdamW 的 lr 按∝1/√dmodel缩放LR 采用「线性 warmup 常数 线性 warmdown」三阶段调度Muon 的 momentum 也设计了 0.85→0.97→0.90 的调度权重衰减则按余弦衰减到零。scaling_laws.sh固定 FLOPs 预算的扫描runs/scaling_laws.sh 在 4 个 FLOPs 预算1e18、2.15e18、4.64e18、1e19× 6 个深度10、12、14、16、18、20的网格上训练每档预算通过--target-flops自动计算迭代数。脚本会自动按深度调整--device-batch-sized≥28 用 8d≥20 用 16否则 32避免 OOM在训练日志中提取参数分布wte、value_embeds、lm_head、transformer_matrices、scalars、total、迭代数、实际 batch size、val bpb 与 CORE 分数汇总到$NANOCHAT_BASE_DIR/scaling_laws_results_${LABEL}/results.csv支持断点续扫run_exists跳过已完成组合。miniseries.sh计算最优模型系列runs/miniseries.sh 依次训练DEPTHS(12 14 16 18 20 22 24 26)的一组模型默认系列名为当天日期如jan11也可通过参数指定如./miniseries.sh jan11。每个深度训练完成后从日志提取参数数、迭代数、tokens 与 bpb/CORE写入 CSV并计算实际的 data:param 比。脚本支持SKIP_SETUP1跳过环境搭建便于已有环境时直接开跑。精度管理显式 COMPUTE_DTYPE 而非 autocastnanochat 不使用torch.amp.autocast而是通过 nanochat/common.py 中定义的单一全局COMPUTE_DTYPE显式管理精度默认根据硬件自动检测硬件默认 dtype原因CUDA SM 80A100、H100 等bfloat16原生 bf16 tensor coreCUDA SM 80V100、T4 等float32无 bf16可用NANOCHAT_DTYPEfloat16配合 GradScalerCPU / MPSfloat32安全默认值新版 macOS 上 MPS 跑NANOCHAT_DTYPEbfloat16也没问题省约 25% 内存速度相近可通过环境变量NANOCHAT_DTYPE覆盖默认值NANOCHAT_DTYPEfloat32 python -m scripts.chat_cli -p hello # 强制 fp32 NANOCHAT_DTYPEbfloat16 torchrun --nproc_per_node8 -m scripts.base_train # 强制 bf16检测逻辑的源码证据在 common.py 的_detect_compute_dtype()优先读NANOCHAT_DTYPE环境变量否则在有 CUDA 时按torch.cuda.get_device_capability()判断SM ≥ (8,0) 用 bf16pre-Ampere 回退 fp32——因为 fp16 需要 GradScaler 而当时未实现无 CUDACPU/MPS时用 fp32。工作原理模型权重以 fp32 存储保证优化器精度自定义Linear层在前向时将其转换为COMPUTE_DTYPE嵌入层直接以COMPUTE_DTYPE存储以省内存例外fp16 训练时嵌入保留 fp32因为 GradScaler 无法对 fp16 梯度做 unscale。这带来了与 autocast 相同的混合精度收益但完全显式地控制每一处运行的精度。相关实现在 gpt.py 的Linear类与init_weights()中。注意事项float16训练会自动在 base_train.py 中启用GradScaler防止梯度下溢SFT 也支持RL 目前不支持fp16 推理在各处均可正常工作FP8 训练通过--fp8开启需 H100且 FA3 只支持 bf16——base_train.py 会打印告警并在不兼容时回退 SDPA另有--fp8-recipe可选tensorwise更快、推荐或rowwise更准但更慢FP8 仅在 CUDA 上生效评估时会临时换回 bf16 的Linear以保证指标一致性disable_fp8上下文管理器。在 CPU / MPS 上运行runs/runcpu.sh 展示了在 CPU 或 Apple SiliconMPS上运行的极简示例大幅缩小被训练的 LLM把训练时间压到几十分钟内。README 明确提示这种跑法不会得到很强的结果定位是教育/娱乐性质的 demo。脚本的具体配置README 未逐一列出但脚本注释中说明了关键参数分词器训练python -m nanochat.dataset -n 8python -m scripts.tok_train --max-chars2000000000约 34 秒M3 Maxtok_eval预训练一个 6 层小模型约 30 分钟python -m scripts.base_train \ --depth6 \ --head-dim64 \ --window-patternL \ --max-seq-len512 \ --device-batch-size32 \ --total-batch-size16384 \ --eval-every100 \ --eval-tokens524288 \ --core-metric-every-1 \ --sample-every100 \ --num-iterations5000 \ --run$WANDB_RUN要点--head-dim64、--window-patternLSDPA 不支持滑窗注意力用全上下文、--core-metric-every-1禁用 CORE 评估评估python -m scripts.base_eval --device-batch-size1 --split-tokens16384 --max-per-task16SFT约 10 分钟scripts.chat_sft --eval-every200 --eval-tokens524288 --num-iterations1500对话python -m scripts.chat_cli -p What is the capital of France?——脚本注释调侃道模型应该能说出答案是巴黎说不定还知道天空是蓝的。仓库的 demo/nanochat/evidence/ 目录即包含了基于bash runs/runcpu.sh的一次真实运行产物run-manifest 显示 device 为 mps、状态 completed其中 d6 模型在 5000 步的 checkpoint 元数据evidence/checkpoints/base/meta_005000.json、SFT 1499 步的 checkpoint 元数据evidence/checkpoints/sft/meta_001499.json以及分词器产物evidence/tokenizer/均被保留下来可作为 CPU/MPS 路径的实证参照。模型架构速览GPT 实现的关键特性README 对架构本身着墨不多但 nanochat/gpt.py 是理解整个框架的枢纽其特性包括RoPE 旋转位置编码无可学习位置嵌入且旋转采用-theta转置约定与文本惯例互为转置功能等价仅为 checkpoint 兼容QK norm注意力 q/k 归一化并放大 1.2 倍embedding 与 lm_head 解绑词表按 64 对齐 padding 以适配 DDP 与 tensor coreReLU² 激活F.relu(x).square()、无偏置线性层、无 RMSNorm 可学习参数GQA 分组查询注意力与FA3 集成不兼容时自动回退 SDPA见 tests/test_attention_fallback.py滑动窗口注意力window_pattern字符串如SSSLL全上下文、S四分之一上下文平铺到各层最后一层强制全上下文一系列 modded-nanogpt 启发的增强每层可学习标量resid_lambdas/x0_lambdas、Value EmbeddingsResFormer 风格按层交替、最后一层必含、smear把前一 token 的嵌入混入当前 token廉价的大词信息、backout减去中间层残差以去除低层特征、logit softcap15。参数统计num_scaling_params()区分了 wte、value_embeds、lm_head、transformer_matrices、scalars 五组scaling laws 分析中通常取transformer_matrices lm_head作为「scaling params」见 base_train.py 的get_scaling_params()。此外 common.py 还维护了两张硬件性能表get_peak_flops()用于计算 MFU与get_peak_bandwidth()推理 decode 阶段是带宽受限的用于 MBU 分析覆盖 Blackwell、Hopper、Ampere、Ada、AMD CDNA 与消费级 RTX 等主流 GPU。测试体系仓库在 tests/ 下配备了与核心机制对应的测试test_attention_fallback.pyFA3/SDPA 注意力回退test_engine.py推理引擎与 KV cachetest_execution.py沙箱化代码执行LLM 作为工具调用 Pythontest_optim.pyMuonAdamW 优化器需要 GPUtest_tasks.py任务切片、TaskMixture/TaskSequence、HubDatasettest_tokenizer.pyBPE 往返与聊天渲染。pytest 的 slow 标记与测试路径配置在 pyproject.toml 中开发依赖含 pytest通过uv sync --extra gpu --group dev安装。贡献指南与社区项目目标是在$1000 预算内端到端可访问的微模型micro models上推进 state of the art——可访问性既指总体成本也指认知复杂度。贡献者需遵循「AI 政策披露」——提交 PR 时须声明有大量 LLM 贡献、非本人撰写或未完全理解的部分。更多背景可参考 README 的 Guides 小节如「Beating GPT-2 for $100: the nanochat journey」「Jan 7 miniseries v1」等讨论帖索引与文件结构说明。nanochat 采用 MIT 许可证。结语从一键复现 GPT-2 能力模型的 speedrun.sh到以--depth单旋钮驱动全部超参数自动推导的设计哲学再到显式COMPUTE_DTYPE精度管理与 Time-to-GPT-2 排行榜驱动的迭代节奏nanochat 用最小的代码面完整覆盖了 LLM 训练的各个阶段。无论你是在 8XH100 节点上追求「2 小时击败 GPT-2」还是在 MacBook 上用 CPU/MPS 跑一个教育性质的 6 层 demo它都提供了一个清晰、可 hack、可复现的起点。【免费下载链接】OpenResearchTurn your coding agents into research agents项目地址: https://gitcode.com/GitHub_Trending/op/OpenResearch创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考