常见问题
运行环境
没有 GPU,可以学吗?
可以。CPU 能完整走通分词、预训练、SFT 和推理,只是模型会很小,回答质量有限。先用第一次运行的小配置,把流程和代码读明白。
Mac 可以用吗?
可以。nanochat 支持 Apple Silicon 的 MPS;没有 MPS 时会自动使用 CPU。MPS 的速度和可用显存与具体芯片有关,不能按 NVIDIA 显卡的数值估算。
应该安装 CPU 版本还是 GPU 版本?
uv sync --extra cpu # CPU / MPS
uv sync --extra gpu # CUDA2
两者不能同时安装。安装后运行 python -c "import torch; print(torch.cuda.is_available())",确认 PyTorch 是否识别到显卡。
uv: command not found
安装 uv 后重新打开终端,或者确认安装目录在 PATH 中。也可以用:
curl -LsSf https://astral.sh/uv/install.sh | shNo module named nanochat 或 No module named scripts
先进入仓库根目录,并激活虚拟环境:
cd nanochat
source .venv/bin/activate2
所有命令都应在仓库根目录执行,使用 python -m scripts.xxx 或 python -m nanochat.xxx,不要直接 python scripts/xxx.py。
数据与分词器
第一次要下载多少数据?
python -m nanochat.dataset -n 8:8 个训练分片加 1 个验证分片,约 1 GB。python -m nanochat.dataset -n 170:完整 speedrun 所需数据,约 17 GB。- 完整数据集有 6542 个分片,不要一次性全下载。
数据下载中断了怎么办?
重新执行同一条命令。已下载完成的分片会跳过,未完成的临时文件会被清理或重试。不要删除已经完成的分片。
找不到 tokenizer.pkl
先运行:
python -m scripts.tok_train分词器保存到 ~/.cache/nanochat/tokenizer/。如果你设置了 NANOCHAT_BASE_DIR,去对应目录找。
报错说分词器词表和模型词表不一致
模型检查点里记录了训练时的 vocab_size。当前分词器的词表大小必须和它相同。
- 如果你换了分词器,需要重新训练模型,或者加载与当前分词器匹配的旧检查点。
- 如果你删除了分词器又重训,即使词表大小相同,具体编号也可能不同,模型输出会变得无意义。
中文效果很差,是分词器不支持吗?
不是。分词器可以编码中文,但预训练和 SFT 数据以英文为主,模型没有学过足够的中文文本和中文对话。要改善中文能力,需要加入中文语料和中文对话数据,并重新训练。
训练
为什么训练很慢?
先确认设备:
- 日志里是否显示
cuda? torch.cuda.is_available()是否为True?- 是否误用了 CPU 版 PyTorch?
- 是否在 CPU 上训练了默认的 d20 模型?
CPU 上训练默认模型不现实,必须用 runs/runcpu.sh 里的小配置。
显存不足(CUDA out of memory)
按顺序尝试:
- 降低
--device-batch-size。 - 降低
--max-seq-len。 - 减少
--eval-tokens。 - 在 H100 上尝试
--fp8。 - 降低
--depth。
不要先改模型结构。多数情况下是批量或序列长度过大。
没有 Flash Attention 3,会出错吗?
不会。nanochat 会自动回退到 PyTorch 的 SDPA。结果在数学上等价,只是速度更慢。CPU 本来就不会使用 FA3。
损失不下降
依次检查:
inputs和targets是否错开一位。- 学习率是否过大或过小。
- 是否误用了
model.eval()。 - 分词器和模型是否匹配。
- 数据是否为空或全部被掩码。
- 是否出现
nan。
先看小模型和少量数据能否过拟合。如果连一小批数据都学不会,问题通常不在模型规模。
训练时损失变成 nan
常见原因是学习率过大、FP16 数值下溢或数据异常。先降低学习率,再检查精度设置。使用 float16 时,训练脚本会启用 GradScaler;RL 目前不支持 FP16 训练。
可以把 --depth 调得很大吗?
可以,但显存、训练时间和数据需求都会快速增加。先用 d4 到 d12 做实验,确认流程和改动有效,再扩大规模。
为什么要保存 optimizer 状态?
AdamW 的动量和二阶矩、Muon 的动量缓冲区都会影响下一步更新。只加载模型参数、不加载优化器状态,训练会“跳一下”,通常需要重新预热。
恢复训练时找不到优化器文件
优化器状态按 rank 分片保存,文件名包含 optim_XXXXXX_rankN.pt。多卡恢复时,每个 rank 都要找到自己的文件。单卡和 8 卡的检查点通常不能直接混用。
对话与评估
模型回答重复或乱码
先确认你加载的是 SFT 检查点,而不是 base 模型:
python -m scripts.chat_cli -i sft -p "Hello"然后尝试降低温度:
python -m scripts.chat_cli -t 0.2 -p "Hello"如果仍然如此,通常是模型太小、训练步数太少或数据量不足。
FileNotFoundError: chatsft_checkpoints/...
说明 SFT 还没有成功保存检查点,或者 --model-tag 不一致。检查:
ls ~/.cache/nanochat/chatsft_checkpoints并确认 SFT 命令和 chat_cli 使用了同一个 --model-tag。
为什么评估结果波动很大?
小样本评估很容易波动。增加 --max-per-task 或 -x 的样本数,固定随机种子,并保证不同模型使用相同的评估配置。
CORE 可以是负数吗?
可以。CORE 和 ChatCORE 使用中心化准确率。0 表示和随机基线相当,负数表示比随机基线更差。
可以跳过 SFT 直接做 RL 吗?
不建议。RL 脚本默认加载 SFT 模型。没有对话和工具调用能力,模型很难在 GSM8K 上获得有效奖励。
可以跳过 RL 吗?
可以。RL 是可选阶段,不影响预训练、SFT 和推理主线。跳过它只会少一个数学题优化实验。
修改代码
改了模型结构后旧检查点还能用吗?
通常不能。检查点保存了参数形状和配置;层数、宽度、头数或词表变化后,参数无法直接加载。需要重新训练,或者写兼容加载逻辑。
改代码后怎样快速验证?
先跑相关测试:
uv sync --extra cpu --group dev
uv run pytest -q -m "not slow"2
然后训练一个极小模型,确认前向、反向、保存和加载都能走通。不要直接上大规模训练。
怎样在教程站点里改内容?
教程源码在 docs/。首次构建前先安装依赖:
npm install
npm run docs:dev # 本地预览
npm run docs:build # 构建静态站点2
3
更新线上站点:
CLOUDFLARE_ACCOUNT_ID=<你的账号 ID> npm run deploydeploy 会先构建,再把 docs/.vitepress/dist 上传到 Cloudflare Pages 的 zero-to-nanochat 项目。项目生产分支是 main,所以部署命令显式传入了 --branch=main。
如果当前环境只登录了一个 Cloudflare 账号,可以省略 CLOUDFLARE_ACCOUNT_ID。有多个账号时,先用 npx wrangler whoami 查看账号 ID,避免把站点部署到错误的账号。
教程会跟着上游更新吗?
教程基于提交 92d63d4。上游代码变化后,行号和参数可能不同。阅读时优先按函数名定位,再对照行号。发现明显不一致时,以仓库当前代码为准。