# nanoGPT 是什么，为什么值得逐行读

> 一句话讲清 GPT 在做什么，给 nanoGPT 仓库画张地图，并用五分钟跑通一个字符级莎士比亚模型，先建立手感，再动手拆代码。

- 作者：David（道雾轩）
- 专栏：nanoGPT 源码解读（https://daiw.org/manual/nanogpt.md）
- 最后更新：2026-07-13
- 原文：https://daiw.org/manual/nanogpt/what-is-nanogpt
- 转载与引用：请注明出处并附原文链接（https://daiw.org/about/copyright）

# nanoGPT 是什么，为什么值得逐行读

在拆代码之前，先花几分钟把「它到底是个什么东西」想清楚。很多人学 Transformer 卡壳，不是因为哪一行看不懂，而是因为**始终没搞清整件事在求解什么问题**。

## 一句话：GPT 是个「猜下一个字」的机器

把所有花哨的说法丢掉，GPT 在做的事，朴素到一句话能讲完：

> **给它一段文本，它预测「下一个 token 最可能是什么」。**

就这么简单。你手机输入法打「今天天气真」，它弹出「好」——这就是一个极其简陋的「下一个字预测器」。GPT 是同一件事，只是：

- 它看的上文更长（nanoGPT 默认能一次看 1024 个 token）；
- 它「见过」的文本多到离谱（整个互联网的一大截）；
- 它内部用来「理解上文」的机器，是我们要拆的那套 Transformer。

那「生成一整段文章」又是怎么回事？也简单：**预测一个字，把它接到句子后面，再拿新句子去预测下一个字，如此反复**。这个「自己吃自己尾巴」的过程叫**自回归(autoregressive)**，我们在第四站会逐行看它。

<Callout type="info">
  **token 是什么？** 你可以先粗略理解成「模型眼里的一个字符或一个词片」。在本专栏入门用的字符级例子里，一个 token 就是一个字符（如 `a`、`,`、空格）；在真正的 GPT-2 里，一个 token 通常是一个「子词」（比如 `ing`、` the`）。下一章讲数据时，你会亲眼看到字符是怎么变成 token 编号的。
</Callout>

## 给仓库画张地图

`git clone` 下来，nanoGPT 的目录乍看有点乱，但真正的主角只有几个文件。先记住这张地图，后面每一站你都知道自己站在哪：

| 文件 | 行数（量级） | 干什么 | 在第几站讲 |
| --- | --- | --- | --- |
| `data/*/prepare.py` | 几十行 | **数据**：把原始文本编码成 `train.bin` / `val.bin` | 第一站 |
| `model.py` | 约 300 | **模型**：GPT 的完整定义，五个类全在这 | 第二站 |
| `train.py` | 约 300 | **训练**：数据加载 + 训练主循环 + 存档 | 第三站 |
| `sample.py` | 约 90 | **采样**：载入训练好的模型，生成新文本 | 第四站 |
| `configurator.py` | 约 40 | **配置**：一套「简陋但好用」的命令行参数覆盖 | 第三站 |
| `config/*.py` | 几十行 | 各种现成的训练配置（如 `train_shakespeare_char.py`） | 第三站 |

看出来了吗？**核心就 `model.py` + `train.py` 两个文件，加起来六百来行。** 其余都是配套。这也是 nanoGPT 最迷人的地方——它把「一个能训练的 GPT」压缩到了一个人一个下午读得完的体量，却没有偷工减料。

## 先跑起来，再拆开看

读源码最忌讳「干读」。强烈建议先把最小的例子跑通，有了「它真的能动」的手感，再回头看代码会踏实得多。nanoGPT 自带一个**能在笔记本上、甚至纯 CPU 上**跑的例子：字符级莎士比亚。三步：

**第一步：准备数据。** 下载莎士比亚文集，编码成整数存盘。

```bash
python data/shakespeare_char/prepare.py
```

跑完你会在 `data/shakespeare_char/` 下看到 `train.bin`、`val.bin`、`meta.pkl` 三个文件。这一步在干什么，正是**第一站**要逐行拆的。

**第二步：训练。** 用一份专为「小数据 + 能跑就行」调好的配置开练：

```bash
python train.py config/train_shakespeare_char.py
```

如果你没有 GPU，加两个参数让它在 CPU 上也能挪动：

```bash
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
```

屏幕上会滚动出 `iter 0: loss 4.2...`、`iter 100: loss 2.6...` 这样的日志。**看着那个 loss 一点点往下掉，就是模型在「学」莎士比亚的过程**——第三站我们会逐行看这个循环。

**第三步：采样。** 让训练好的模型写几段：

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

它会吐出几段「莎士比亚味儿」的文本。刚训几百步时多半是胡言乱语，但已经有模有样地在换行、加标点、拼出像单词的东西了。训久一点，它能写出以假乱真的伪莎士比亚。这一步背后，就是**第四站**的 `generate`。

<Callout type="warn">
  CPU 上训练很慢，上面的迷你参数只是为了让你**看到它能动**，别指望质量。真要出效果，还是得有块 GPU。跑不动也完全不影响读代码——手感有了就行。
</Callout>

## 一张图看懂整条流水线

把上面三步串起来，nanoGPT 的全貌就是一条清清楚楚的流水线：

```mermaid
flowchart LR
  A["原始文本<br/>(莎士比亚全集)"] -->|"prepare.py<br/>编码"| B["train.bin<br/>一串整数"]
  B -->|"get_batch<br/>随机取一段"| C["模型 GPT<br/>model.py"]
  C -->|"预测下一个 token"| D["logits<br/>每个候选的分数"]
  D -->|"和真实答案比<br/>cross entropy"| E["loss"]
  E -->|"backward + AdamW<br/>调参数"| C
  C -->|"训练好后<br/>generate"| F["新文本<br/>会写字了"]
```

- **左边（数据）**：文本 → 整数，这是第一站。
- **中间（模型 + 训练）**：整数进模型出预测，和真实答案比得到 `loss`，再用梯度把模型参数调准——反复几千上万次。这是第二、三站，也是重头戏。
- **右边（采样）**：训练好的模型，反复「猜下一个」把新文本生成出来。这是第四站。

整个专栏，就是沿着这张图从左走到右，把每个箭头背后的代码都摊开。

下一站，我们从最左边开始：一段莎士比亚，到底怎么变成硬盘上那串数字？👉 [数据：一段莎士比亚怎么变成一串数字](https://daiw.org/manual/nanogpt/data-prepare-char)
