简单、纯 C/CUDA 的法学硕士,不需要 245MB 的 PyTorch 或 107MB 的 cPython。当前的重点是预训练,特别是复制 GPT-2 和 GPT-3 迷你系列,以及 train_gpt2.py 中的并行 PyTorch 参考实现。您会将此文件视为稍微调整过的 nanoGPT,这是我的早期项目。目前,llm.c 比 PyTorch Nightly 快一点(大约快 7%)。除了 train_gpt2.cu 中的前沿主线代码之外,我们还在一个文件 train_gpt2.c 中提供了一个简单的参考 CPU fp32 实现,其中包含大约 1,000 行干净的代码。我希望这个存储库仅维护 C 和 CUDA 代码。非常欢迎移植到其他语言或存储库,但应该在单独的存储库中完成,我很高兴在下面的“值得注意的分叉”部分中链接到它们。开发者协调发生在讨论区和 Discord 上,可以是 Zero to Hero 频道上的#llmc
频道,也可以是 GPU MODE Discord 上的#llmdotc
。
今天对 llm.c 存储库的最佳介绍是复制 GPT-2 (124M) 模型。讨论 #481 详细介绍了这一点。我们可以在 llm.c 和 PyTorch 的并行实现中重现 GPT-2 和 GPT-3 系列的其他模型。查看脚本自述文件。
调试提示:当您运行make
命令来构建二进制文件时,请通过将-O3
替换为-g
来修改它,以便您可以在您最喜欢的 IDE(例如 vscode)中单步调试代码。
如果您不会在多个节点上进行训练,对混合精度不感兴趣,并且有兴趣学习 CUDA,那么您可能会对 fp32(旧版)文件感兴趣。这些文件是在 llm.c 历史早期被“检查点”并及时冻结的文件。它们更简单、更便携,而且可能更容易理解。运行 1 GPU、fp32 代码,如下所示:
chmod u+x ./dev/download_starter_pack.sh
./dev/download_starter_pack.sh
make train_gpt2fp32cu
./train_gpt2fp32cu
download_starter_pack.sh 脚本是一种快速简单的入门方法,它会下载一堆 .bin 文件,帮助您开始工作。其中包含:1)保存在 fp32 和 bfloat16 中的 GPT-2 124M 模型,2)单元测试中使用的“调试状态”(一小批数据以及目标激活和梯度),3)GPT-2 分词器,以及 3) 标记化的tinyshakespeare 数据集。或者,您可以手动重新创建这些工件,而不是运行 .sh 脚本,如下所示:
pip install -r requirements.txt
python dev/data/tinyshakespeare.py
python train_gpt2.py
“我的 GPU 太差了,我什至没有一个 GPU”部分。您仍然可以欣赏 llm.c 火车!但你不会走得太远。就像上面的 fp32 版本一样,CPU 版本是 llm.c 历史上更早的检查点,当时它只是 C 中的一个简单参考实现。例如,您可以微调 GPT-,而不是从头开始训练2小(124M)来输出类似莎士比亚的文本,例如:
chmod u+x ./dev/download_starter_pack.sh
./dev/download_starter_pack.sh
make train_gpt2
OMP_NUM_THREADS=8 ./train_gpt2
如果您不想运行入门包脚本,那么如上一节所述,您可以通过运行python dev/data/tinyshakespeare.py
然后运行python train_gpt2.py
来重现完全相同的 .bin 文件和工件。
上面的行 (1) 下载已经标记化的tinyshakespeare数据集并下载 GPT-2 (124M) 权重,(3) 在 C 中对其进行初始化,并使用 AdamW 在tineshakespeare上训练 40 个步骤(使用批量大小 4,上下文长度仅 64) ),评估验证损失,并对一些文本进行采样。老实说,除非您有强大的 CPU(并且可以在启动命令中增加 OMP 线程的数量),否则您不会在 CPU 培训 LLM 上取得那么大的成果,但这可能是一个很好的演示/参考。在我的 MacBook Pro (Apple Silicon M3 Max) 上,输出如下所示:
[GPT-2]
max_seq_len: 1024
vocab_size: 50257
num_layers: 12
num_heads: 12
channels: 768
num_parameters: 124439808
train dataset num_batches: 1192
val dataset num_batches: 128
num_activations: 73323776
val loss 5.252026
step 0: train loss 5.356189 (took 1452.121000 ms)
step 1: train loss 4.301069 (took 1288.673000 ms)
step 2: train loss 4.623322 (took 1369.394000 ms)
step 3: train loss 4.600470 (took 1290.761000 ms)
... (trunctated) ...
step 39: train loss 3.970751 (took 1323.779000 ms)
val loss 4.107781
generating:
---
Come Running Away,
Greater conquer
With the Imperial blood
the heaviest host of the gods
into this wondrous world beyond.
I will not back thee, for how sweet after birth
Netflix against repounder,
will not
flourish against the earlocks of
Allay
---
/dev/data/(dataset).py
中的数据文件负责下载、标记并将标记保存到 .bin 文件中,可以轻松地从 C 读取。例如,当您运行时:
python dev/data/tinyshakespeare.py
我们下载并标记tinyshakespeare 数据集。其输出如下所示:
writing 32,768 tokens to ./dev/data/tinyshakespeare/tiny_shakespeare_val.bin
writing 305,260 tokens to ./dev/data/tinyshakespeare/tiny_shakespeare_train.bin
.bin 文件包含一个短标头(1024 字节),然后是 uint16 格式的令牌流,使用 GPT-2 令牌生成器指示令牌 ID。 /dev/data
中提供了更多数据集。
我还附上了一个简单的单元测试,以确保我们的 C 代码与 PyTorch 代码一致。以CPU为例,编译并运行:
make test_gpt2
./test_gpt2
现在加载由 train_gpt2.py 编写的gpt2_124M_debug_state.bin
文件,运行前向传递,将 logits 和损失与 PyTorch 参考实现进行比较,然后使用 Adam 进行 10 次迭代训练,并确保损失与 PyTorch 匹配。为了测试 GPU 版本,我们运行:
# fp32 test (cudnn not supported)
make test_gpt2cu PRECISION=FP32 && ./test_gpt2cu
# mixed precision cudnn test
make test_gpt2cu USE_CUDNN=1 && ./test_gpt2cu
这将测试 fp32 路径和混合精度路径。测试应该通过并打印overall okay: 1
。
我在 doc/layernorm/layernorm.md 中附上了一个非常小的教程。这是一个简单的分步指南,用于实现 GPT-2 模型的单层(layernorm 层)。这是理解如何在 C 中实现层的一个很好的起点。
闪关注。自 2024 年 5 月 1 日起,我们使用 cuDNN 的 Flash Attention。由于 cuDNN 将编译时间从几秒延长到大约分钟,并且此代码路径现在非常新,因此默认情况下禁用此功能。您可以通过如下编译来启用它:
make train_gpt2cu USE_CUDNN=1
这将尝试使用 cudnn 进行编译并运行它。您必须在系统上安装 cuDNN。使用 apt-get 的 cuDNN 安装说明将获取默认的 cuDNN 软件包集。对于最小设置,cuDNN 开发包就足够了,例如在 Ubuntu 22.04 上用于 CUDA 12.x:
wget https://developer.download.nvidia.com/compute/cuda/repos/ubuntu2204/x86_64/cuda-keyring_1.1-1_all.deb
sudo dpkg -i cuda-keyring_1.1-1_all.deb
sudo apt-get update
sudo apt-get -y install libcudnn9-dev-cuda-12
除此之外,您还需要 cuDNN 前端,但这只是头文件。只需将存储库克隆到您的磁盘即可。 Makefile 当前在您的主目录或当前目录中查找它。如果您已将其放在其他位置,请将CUDNN_FRONTEND_PATH=/path/to/your/cudnn-frontend/include
添加到make
命令行。
确保安装 MPI 和 NCCL,例如在 Linux 上:
sudo apt install openmpi-bin openmpi-doc libopenmpi-dev
对于 NCCL,请遵循官方网站的说明(例如网络安装程序)
进而:
make train_gpt2cu
mpirun -np < number of GPUs > ./train_gpt2cu
或者只需在./scripts/
下运行我们的脚本之一。
确保您已按照多 GPU 部分的说明安装了NCCL
。
我们目前支持 3 种方式允许您运行多节点训练:
./scripts/multi_node/run_gpt2_124M_mpi.sh
脚本。./scripts/multi_node/run_gpt2_124M_fs.sbatch
脚本。./scripts/multi_node/run_gpt2_124M_tcp.sbatch
脚本。笔记:
slurm-wlm
放弃了 PMIx 支持,我们假设这将是一种常见情况),您将必须使用 FS (2) 或 TCP (3) 方法。要测试您的 slurm 是否支持 PMIx,请运行: srun --mpi=list
并查看输出中是否包含pmix
。mpirun
- MPI (1) 启动多节点运行。这 3 种方法都没有优越性,我们只是为您提供选项,以便您可以在您的特定环境中运行。
就像在 TinyStories 上使用 4 个 GPU 的机器上扫描学习率的示例过程一样。运行 shell 脚本sweep.sh
(当然是在chmod u+x sweep.sh
之后):
#! /bin/bash
learning_rates=(3e-5 1e-4 3e-4 1e-3)
for i in {0..3} ; do
export CUDA_VISIBLE_DEVICES= $i
screen -dmS " tr $i " bash -c " ./train_gpt2cu -i data/TinyStories -v 250 -s 250 -g 144 -l ${learning_rates[$i]} -o stories $i .log "
done
# you can bring these down with
# screen -ls | grep -E "tr[0-3]" | cut -d. -f1 | xargs -I {} screen -X -S {} quit
此示例打开 4 个屏幕会话并使用不同的 LR 运行四个命令。这会将所有损失写入日志文件stories$i.log
,您可以根据需要在 Python 中绘制它们。有关如何解析和绘制这些日志文件的简单示例位于 dev/vislog.ipynb 中。
关于我想要这个存储库的更多内容:
首先,我希望llm.c
成为一个教育场所。例如,我们的dev/cuda
文件夹是一个包含所有层的内核库的地方,这些层都是手动编写的并且有很好的文档记录,从非常简单的内核一直到更复杂/更快的内核。如果您有一个具有各种不同权衡的新内核,请随时在此处贡献它。
也就是说,我也希望llm.c
也非常快,甚至对于训练网络来说实际上很有用。例如,首先,我们应该能够重现大型 GPT-2 (1.6B) 训练运行。这要求我们合并最快的内核,包括使用 cuBLAS、cuBLASLt、CUTLASS、cuDNN 等库。我还认为这样做具有教育目的,可以建立专家上限和测量单位,例如,您可以说您手动编写的内核是 cuBLAS 速度的 80%,等等。然后您可以选择进行超快速运行,或者您可以选择“拖放”您想要使用的任何手动内核,然后运行那些。
然而,作为一个限制,我想保持根文件夹中的主线llm.c
简单且可读。如果有一个 PR 可以将性能提高 2%,但它“花费”了 500 行复杂的 C 代码,并且可能是一个奇异的第 3 方依赖项,我可能会拒绝该 PR,因为其复杂性不值得。举一个具体的例子 - 将 cuBLAS for matmuls 设置为根训练循环中的默认值是理所当然的:它使主线代码更快,它是单行可解释代码,并且是非常常见的依赖项。另一方面,我们可以手动实现,可以与dev/cuda
中的 cuBLAS 竞争。
最后,我将对项目根文件夹中的复杂性更加敏感,其中包含项目的主/默认文件。相比之下, dev/
文件夹对于我们来说更像是一个临时空间,用于开发内核或类库并共享有用或相关或教育代码,并且其中一些代码可能(本地)复杂。
AMD 支持
C#
CUDA C++
C++/CUDA
WebGPU C++
C++
去
爪哇
金属
莫乔
OpenCL
锈
迅速
之字形
哈瓦那高迪2
尼姆
组织开发方式:
#llmc
频道。 麻省理工学院