GPT

nanoGPT:用于训练/微调中型GPT的最简单最快的代码

OpenAI前研究员Karpathy的极简版GPT。

2024年2月20日
nanogpt
分享

用于训练/微调中型 GPT 的最简单、最快的存储库。它是minGPT的重写,优先考虑牙齿而不是教育。仍在积极开发中,但目前该文件train.py在 OpenWebText 上重现了 GPT-2 (124M),在单个 8XA100 40GB 节点上运行大约 4 天的训练。代码本身简单易读:train.py是一个约 300 行的样板训练循环,model.py是约300 行的 GPT 模型定义,可以选择从 OpenAI 加载 GPT-2 权重。就是这样。

nanogpt-1

因为代码非常简单,所以很容易满足您的需求,可以从头开始训练新模型,或微调预训练检查点(例如,当前可用的最大起点是 OpenAI 的 GPT-2 1.3B 模型)。

安装

pip install torch numpy transformers datasets tiktoken wandb tqdm

依赖项:

  • pytorch <3
  • numpy <3
  • transformers(huggingface)<3(用于加载GPT-2检查点)
  • datasets(huggingface)<3(如果你想下载+预处理OpenWebText)
  • tiktoken用于 OpenAI 的快速 BPE 代码 <3
  • wandb用于可选的日志记录 <3
  • tqdm用于进度条 <3

快速开始

如果你不是深度学习专业人士,而只是想感受其中的魔力并上手,那么最快的入门方法就是在莎士比亚的作品上训练字符级的 GPT。首先,我们将其作为单个 (1MB) 文件下载,并将其从原始文本转换为一个大的整数流:

$ python data/shakespeare_char/prepare.py

这会在该数据目录中创建train.binval.bin。现在是时候训练你的 GPT 了。它的大小很大程度上取决于你系统的计算资源:

我有一个 GPU。太棒了,我们可以使用config/train_shakespeare_char.py配置文件中提供的设置快速训练一个婴儿水平的 GPT :

$ python train.py config/train_shakespeare_char.py

如果你仔细看一下它的内部,你会发现我们正在训练一个上下文大小最多为 256 个字符、384 个特征通道的 GPT,它是一个 6 层 Transformer,每层有 6 个头。在一个 A100 GPU 上,此训练大约需要 3 分钟,最佳评估损失为 1.4697。根据配置,模型检查点将被写入--out_dir目录中out-shakespeare-char。因此,一旦训练完成,我们就可以通过将采样脚本指向此目录来从最佳模型中进行采样:

$ python sample.py --out_dir=out-shakespeare-char

这会生成一些样本,例如:

ANGELO:
And cowards it be strawn to my bed,
And thrust the gates of my threats,
Because he that ale away, and hang'd
An one with him.

DUKE VINCENTIO:
I thank your eyes against it.

DUKE VINCENTIO:
Then will answer him to save the malm:
And what have you tyrannous shall do this?

DUKE VINCENTIO:
If you have done evils of all disposition
To end his power, the day of thrust for a common men
That I leave, to fight with over-liking
Hasting in a roseman.

哈哈 ¯\_(ツ)_/¯。在 GPU 上训练 3 分钟后,对于字符级模型来说已经不错了。通过在此数据集上微调预训练的 GPT-2 模型,很可能可以获得更好的结果(请参阅后面的微调部分)。

我只有一台 MacBook(或其他便宜的电脑)。不用担心,我们仍然可以训练 GPT,但我们想把事情降低一个档次。我建议获取最先进的 PyTorch nightly(安装时在此处选择它),因为它很可能使您的代码更加高效。但即使没有它,简单的训练也可能如下所示:

$ 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

在这里,由于我们在 CPU 而不是 GPU 上运行,因此我们必须设置--device=cpu,并使用--compile=False关闭 PyTorch 2.0 编译。然后,当我们评估时,我们得到的噪声更大,但速度更快(--eval_iters=20,从 200 降到 20),我们的上下文大小只有 64 个字符,而不是 256 个,并且每次迭代的批大小只有 12,而不是 64。我们还将使用更小的 Transformer(4 层、4 个头、embedding大小 128),并将迭代次数减少到 2000(相应地,通常将学习率衰减到 max_iters 左右,用--lr_decay_iters)。因为我们的网络很小,所以我们也放松了正则化(--dropout=0.0)。这仍然需要约 3 分钟的时间,但我们只损失了 1.88,样本更差些,但它仍然很有趣:

$ python sample.py --out_dir=out-shakespeare-char --device=cpu

生成这样的样本:

GLEORKEN VINGHARD III:
Whell's the couse, the came light gacks,
And the for mought you in Aut fries the not high shee
bot thou the sought bechive in that to doth groan you,
No relving thee post mose the wear

在 CPU 上运行大约 3 分钟还不错,可以提示正确的字符拼装。如果您愿意等待更长时间,请随意调整超参数、增加网络大小、上下文长度 ( --block_size)、训练长度等。

最后,在 Apple Silicon Macbook 和最新的 PyTorch 版本上,请确保添加--device=mps(“Metal Performance Shaders”的缩写);然后,PyTorch 使用片上 GPU,可以显著加速训练(2-3 倍)并允许您使用更大的网络。更多信息请参见问题 28

复现 GPT-2

更认真的深度学习专业人士可能对重现 GPT-2 结果更感兴趣。所以我们开始 - 我们首先对数据集进行标记,在本例中是OpenWebText,是 OpenAI 的(私有)WebText 的开源复制品:

$ python data/openwebtext/prepare.py

这将下载并标记OpenWebText数据集。它将创建train.binval.bin,其中以一个序列保存 GPT2 BPE 令牌 ID,并存储为原始 uint16 字节。然后我们准备开始训练。要重现 GPT-2 (124M),您至少需要一个 8X A100 40GB 节点并运行:

$ torchrun --standalone --nproc_per_node=8 train.py config/train_gpt2.py

这将使用 PyTorch 分布式数据并行框架 (DDP) 运行大约 4 天,损失降至约 2.85。现在,刚刚在 OWT 上评估的 GPT-2 模型的评估损失约为 3.11,但如果对其进行微调,它将降至约 2.85 的区域(由于明显的域差距),从而使两个模型〜匹配。

如果您处于集群环境中并且拥有多个 GPU 节点,您可以使 GPU 在 2 个节点上运行,例如:

Run on the first (master) node with example IP 123.456.123.456:
$ torchrun --nproc_per_node=8 --nnodes=2 --node_rank=0 --master_addr=123.456.123.456 --master_port=1234 train.py
Run on the worker node:
$ torchrun --nproc_per_node=8 --nnodes=2 --node_rank=1 --master_addr=123.456.123.456 --master_port=1234 train.py

对互连进行基准测试(例如 iperf3)是个好主意。特别是,如果您没有无限宽带(Infiniband),那么还要先考虑加上NCCL_IB_DISABLE=1执行上述启动。您的多节点训练将会起作用,但很可能是爬行。默认情况下,检查点会定期写入--out_dir。我们可以简单地通过$ python sample.py从模型中采样。

最后,要在单个 GPU 上进行训练,只需运行$ python train.py脚本即可。看看它的所有参数,该脚本试图变得非常可读、可破解且透明。您很可能希望根据您的需要调整其中一些变量。

基线

OpenAI GPT-2 检查点使我们能够为 openwebtext 制定一些基线。我们可以执行下面命令得到如下数字:

$ python train.py eval_gpt2
$ python train.py eval_gpt2_medium
$ python train.py eval_gpt2_large
$ python train.py eval_gpt2_xl

并观察到训练和评估上的损失为:

模型 参数 训练损失 评估损失
gpt2 124M 3.11 3.12
gpt2-medium 350M 2.85 2.84
gpt2-large 774M 2.66 2.67
gpt2-xl 1558M 2.56 2.54

然而,我们必须注意到,GPT-2 是在(封闭的,从未发布的)WebText 上进行训练的,而 OpenWebText 只是该数据集的尽可能的开源复制。这意味着存在数据集域差距。事实上,直接在 OWT 上采用 GPT-2 (124M) 检查点并进行微调一段时间,可以将损失降至约 2.85。这将成为更合适的复现基线。

微调

微调与训练没有什么不同,我们只是确保从预训练模型进行初始化并以较小的学习率进行训练。有关如何在新文本上微调 GPT,请转至data/shakespeare并运行prepare.py以下载小型莎士比亚数据集,并使用 GPT-2 中的 OpenAI BPE 分词器将其渲染为train.binval.bin。与 OpenWebText 不同,这将只需几秒钟。微调可能需要很少的时间,例如在单个 GPU 上只需几分钟。运行一个微调示例如下:

$ python train.py config/finetune_shakespeare.py

这将加载配置参数,并用config/finetune_shakespeare.py覆盖(我没有对它们进行太多调整)。基本上,我们用init_from从 GPT2 检查点进行初始化并正常训练,只是时间较短且学习率较小。如果内存不足,请尝试减小模型大小(它们是{'gpt2', 'gpt2-medium', 'gpt2-large', 'gpt2-xl'})或可以减小block_size(上下文长度)。最佳检查点(最低评估损失)将位于out_dir目录中,例如默认情况下在out-shakespeare,这根据配置文件指定。然后您可以运行代码sample.py --out_dir=out-shakespeare

THEODORE:
Thou shalt sell me to the highest bidder: if I die,
I sell thee to the first; if I go mad,
I sell thee to the second; if I
lie, I sell thee to the third; if I slay,
I sell thee to the fourth: so buy or sell,
I tell thee again, thou shalt not sell my
possession.

JULIET:
And if thou steal, thou shalt not sell thyself.

THEODORE:
I do not steal; I sell the stolen goods.

THEODORE:
Thou know'st not what thou sell'st; thou, a woman,
Thou art ever a victim, a thing of no worth:
Thou hast no right, no right, but to be sold.

哇哦,GPT,进入那边某个黑暗的地方。我并没有对配置中的超参数进行太多调整,请随意尝试!

采样/推理

使用脚本sample.py从 OpenAI 发布的预训练 GPT-2 模型或您自己训练的模型中进行采样。例如,以下是从最大可用的gpt2-xl模型中采样的方法:

$ python sample.py \
 --init_from=gpt2-xl \
 --start="What is the answer to life, the universe, and everything?" \
 --num_samples=5 --max_new_tokens=100

如果您想从您训练的模型中进行采样,请使用--out_dir。您还可以使用文件中的一些文本来提示模型,例如$ python sample.py --start=FILE:prompt.txt

效率

对于简单的模型基准测试和分析,bench.py可能会有用。它与train.py的训练循环的核心内容相同,但省略了许多其他复杂性。

请注意,代码默认使用PyTorch 2.0。截至撰写本文时(2022 年 12 月 29 日),torch.compile()已在夜间版本中提供。这行代码的改进是显而易见的,例如,将迭代时间从 ~250ms/iter 减少到 135ms/iter。PyTorch 团队干得真棒!

故障排除

请注意,默认情况下此存储库使用 PyTorch 2.0(即torch.compile)。这是相当新的和实验性的,并且尚未在所有平台(例如Windows)上可用。如果您遇到相关错误消息,请尝试通过添加--compile=False标志来禁用此功能。这会减慢代码速度,但至少它会运行。

有关此存储库、GPT 和语言建模的一些背景信息,观看我的从零到英雄系列可能会有所帮助。具体来说,如果您有一些先前的语言建模背景,GPT 视频会很受欢迎。

如需更多问题/讨论,请随时访问Discord 上的#nanoGPT

来自:https://github.com/karpathy/nanoGPT

更多文章

完全透明、开源、社区支持的个人理财应用程序。

2024年2月19日 · 财务 个人理财
sovits
1分钟的语音数据也可以用来训练一个好的TTS模型!
2024年2月19日 · 语音 语音合成 语音转换
React-Table-API
了解如何使用React Tanstack通过API请求读取、创建、更新和删除表格数据。
2024年2月15日 · React TanStack
React-Table-Validation
了解如何使用React Tanstack验证表格的输入字段、选择字段和实现自定义验证。
2024年2月15日 · React TanStack