llm.c

GitHub
29.4k 3.5k 较难 1 次阅读 今天MIT语言模型开发框架
AI 解读 由 AI 自动生成,仅供参考

llm.c 是一个旨在用极简、纯粹的 C 和 CUDA 代码实现大语言模型(LLM)训练项目的开源工具。它摒弃了庞大的依赖库,无需安装数百兆的 PyTorch 或 Python 环境,仅凭一千行左右的清晰代码即可复现 GPT-2 和 GPT-3 系列的预训练过程。

该项目主要解决了传统深度学习框架过于厚重、底层细节被高度封装的问题,让开发者能够直接透视模型训练的每一个数学与内存操作细节。在性能上,llm.c 甚至比最新的 PyTorch 夜间版快约 7%。其独特的技术亮点在于提供了从单文件 CPU 参考实现到高性能 GPU CUDA 内核的完整路径,既保留了代码的可读性,又兼顾了执行效率。

llm.c 特别适合希望深入理解大模型底层原理的开发者、研究人员以及教育者。如果你渴望摆脱黑盒框架,亲手掌控从数据加载、前向传播到反向梯度更新的每一行代码,或者想在资源受限的环境中探索模型训练,llm.c 将是一个极佳的学习与实践平台。它不仅是一个训练工具,更是一本可执行的教科书,帮助用户从零开始构建对大语言模型的深刻认知。

使用场景

一位嵌入式系统工程师希望在资源受限的边缘设备上复现并微调 GPT-2 模型,以验证轻量级大语言模型的可行性。

没有 llm.c 时

  • 依赖包袱沉重:必须安装庞大的 PyTorch(约 245MB)和 cPython 环境,这对于存储和内存紧张的边缘设备几乎是不可承受之重。
  • 黑盒调试困难:框架层级过多,当训练出现数值异常或性能瓶颈时,难以深入底层 CUDA 内核进行逐行调试和定位。
  • 学习曲线陡峭:想要理解 Transformer 的底层实现细节,需要跨越高级 API 抽象层,无法直接通过简洁代码掌握核心算法逻辑。
  • 部署移植复杂:将训练好的模型从复杂的 Python 生态迁移到纯 C/C++ 生产环境时,面临巨大的格式转换和运行时适配工作量。

使用 llm.c 后

  • 极致轻量化:仅需纯 C/CUDA 代码即可运行,彻底摆脱了对 PyTorch 和 Python 解释器的依赖,显著降低了环境门槛和资源占用。
  • 代码透明可控:核心训练逻辑浓缩在约 1000 行的单个 C 文件中,工程师可直接使用 IDE 单步调试 CUDA 内核,精准掌控每一个计算细节。
  • 教育与实践合一:通过阅读清晰的参考实现,能快速透彻地理解 GPT-2 的前向传播与反向传播机制,成为学习大模型底层的绝佳教材。
  • 无缝生产集成:由于本身就是原生 C/CUDA 实现,训练代码稍作修改即可直接嵌入现有的高性能计算流水线,消除了跨语言部署的鸿沟。

llm.c 通过回归最基础的编程语言,为大模型研究提供了零依赖、高透明且易于部署的极简解决方案。

运行环境要求

操作系统
  • Linux
  • macOS
GPU
  • 训练需 NVIDIA GPU (支持 CUDA),CPU 版本可在无 GPU 环境运行 (如 Apple Silicon)
  • 多卡需 NCCL,多节点需 MPI
  • Flash Attention 需 cuDNN
内存

未说明 (CPU 训练建议高性能多核 CPU 及大内存)

依赖
notes核心训练代码为纯 C/CUDA,无需 PyTorch 运行时,但需 Python 进行数据预处理和验证测试。多卡训练需安装 OpenMPI 和 NCCL;启用 cuDNN 加速需单独安装 cuDNN 库及 frontend 头文件。MacOS 用户可使用 CPU 版本进行演示,但速度较慢。
python未说明 (需 Python 运行数据预处理脚本及参考实现)
CUDA Toolkit
cuDNN (可选,用于 Flash Attention)
NCCL (多卡训练)
OpenMPI (多节点训练)
Make
GCC/Clang
llm.c hero image

快速开始

llm.c

用简洁、纯粹的 C/CUDA 实现大型语言模型,无需依赖 245MB 的 PyTorch 或 107MB 的 cPython。目前的重点是预训练,尤其是复现 GPT-2GPT-3 系列小模型,并提供一个并行的 PyTorch 参考实现,位于 train_gpt2.py 中。你可能会发现这个文件与我早期的一个项目 nanoGPT 有些许调整。目前,llm.c 的速度比 PyTorch Nightly 版本快约 7%。除了位于 train_gpt2.cu 中的最前沿主线代码外,我们还提供了一个简单的 CPU fp32 参考实现,包含约 1,000 行干净的代码,全部写在一个文件 train_gpt2.c 中。我希望这个仓库只维护 C 和 CUDA 代码。其他语言或仓库的移植非常欢迎,但应放在独立的仓库中,我乐意在下方的“值得关注的分支”部分链接它们。开发者之间的协作通过 Discussions 和 Discord 进行,可以在 Zero to Hero 频道的 #llmc 频道,或者在 GPU MODE Discord 的 #llmdotc 频道进行。

快速入门

今天了解 llm.c 仓库的最佳方式就是复现 GPT-2(1.24亿参数)模型。讨论 #481 详细介绍了这一过程。我们可以在 llm.c 和 PyTorch 的并行实现中复现 GPT-2 和 GPT-3 系列的其他模型。请查看 scripts README

调试提示:当你运行 make 命令构建二进制文件时,可以将 -O3 替换为 -g,以便在你喜欢的 IDE(例如 VS Code)中逐步调试代码。

快速入门(单 GPU,仅 fp32)

如果你不需要在多节点上训练,也不关心混合精度,并且对学习 CUDA 感兴趣,那么 fp32(旧版)文件可能更适合你。这些文件是在 llm.c 发展初期“保存”的版本,此后便不再更新。它们更简单、更易移植,也可能更容易理解。你可以这样运行单 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 1.24亿参数模型;2) 用于单元测试的“调试状态”(一小批数据以及目标激活值和梯度);3) GPT-2 分词器;以及 3) 经过分词的 tinyshakespeare 数据集。或者,你也可以不运行该脚本,而是手动重新创建这些文件和工件,如下所示:

pip install -r requirements.txt
python dev/data/tinyshakespeare.py
python train_gpt2.py

快速入门(CPU)

适用于“连一块 GPU 都没有”的情况。即使没有 GPU,你仍然可以体验 llm.c 的训练过程!不过进展不会太远。与上述 fp32 版本一样,CPU 版本是 llm.c 更早时期的快照,那时它还只是一个简单的 C 语言参考实现。例如,与其从头开始训练,不如对 GPT-2 小模型(1.24亿参数)进行微调,使其生成类似莎士比亚风格的文本,示例如下:

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.pypython train_gpt2.py 来重现完全相同的 .bin 文件和工件。

以上步骤(1)下载已经分词的 tinyshakespeare 数据集,并下载 GPT-2(1.24亿参数)的权重;(3)使用这些权重在 C 语言中初始化模型,在 tinyshakespeare 数据集上以 AdamW 优化器训练 40 步(批量大小为 4,上下文长度仅为 64),评估验证损失,并采样生成一些文本。老实说,除非你有一台性能强劲的 CPU(并且能够在启动命令中增加 OMP 线程数),否则在 CPU 上训练大型语言模型的效果不会太好,但这或许可以作为一个不错的演示或参考。以下是我 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(耗时 1452.121000 ms)
step 1: train loss 4.301069(耗时 1288.673000 ms)
step 2: train loss 4.623322(耗时 1369.394000 ms)
step 3: train loss 4.600470(耗时 1290.761000 ms)
...(截断)...
step 39: train loss 3.970751(耗时 1323.779000 ms)
val loss 4.107781
生成:
---
奔逃而来,
更大的征服者,
带着皇室血脉,
众神中最强大的军队,
进入这奇妙的世界之外。
我不会支持你,因为出生之后是多么甜蜜啊——
Netflix 对抗 repounder,
将不会
繁荣于 Allay 的耳环之下——
---

数据集

位于 /dev/data/(dataset).py 中的数据文件负责下载、分词并将分词结果保存为 .bin 文件,以便 C 语言轻松读取。例如,当你运行:

python dev/data/tinyshakespeare.py

我们会下载并分词 tinyshakespeare 数据集。其输出如下:

将 32,768 个 token 写入 ./dev/data/tinyshakespeare/tiny_shakespeare_val.bin
将 305,260 个 token 写入 ./dev/data/tinyshakespeare/tiny_shakespeare_train.bin

这些 .bin 文件包含一个 1024 字节的头部,随后是以 uint16 格式存储的 token 流,表示使用 GPT-2 分词器得到的 token ID。更多数据集可在 /dev/data 中找到。

测试

我还附带了一个简单的单元测试,用于确保我们的 C 代码与 PyTorch 代码一致。以 CPU 为例,编译并运行如下命令:

make test_gpt2
./test_gpt2

此测试会加载由 train_gpt2.py 生成的 gpt2_124M_debug_state.bin 文件,执行一次前向传播,比较 logits 和损失与 PyTorch 参考实现的结果,然后进行 10 次 Adam 优化迭代,确保损失与 PyTorch 的结果一致。对于 GPU 版本,我们运行:

# fp32 测试(不支持 cuDNN)
make test_gpt2cu PRECISION=FP32 && ./test_gpt2cu
# 混合精度 cuDNN 测试
make test_gpt2cu USE_CUDNN=1 && ./test_gpt2cu

这将分别测试 fp32 路径和混合精度路径。测试应该通过,并打印出 overall okay: 1

教程

我在这里附上了一个非常简短的教程,位于 doc/layernorm/layernorm.md。它是一个简单、循序渐进的指南,用于实现 GPT-2 模型中的单个层——LayerNorm 层。这是一个很好的起点,可以帮助你理解 C 语言中各层的具体实现方式。

Flash Attention。截至 2024 年 5 月 1 日,我们使用 cuDNN 提供的 Flash Attention。由于 cuDNN 会将编译时间从几秒延长到约一分钟,且该代码路径目前仍处于早期阶段,因此默认情况下已禁用此功能。你可以通过以下方式启用它:

make train_gpt2cu USE_CUDNN=1

这将尝试使用 cuDNN 进行编译并运行。你需要在系统上安装 cuDNN。按照 cuDNN 安装说明,使用 apt-get 安装会获取默认的 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 会在你的主目录或当前目录中查找它。如果你将其放置在其他位置,请在 make 命令行中添加 CUDNN_FRONTEND_PATH=/path/to/your/cudnn-frontend/include

多 GPU 训练

请确保已安装 MPI 和 NCCL,例如在 Linux 系统上:

sudo apt install openmpi-bin openmpi-doc libopenmpi-dev

对于 NCCL,请遵循 官方网站 的说明(例如使用网络安装程序),然后执行以下命令:

make train_gpt2cu
mpirun -np <GPU数量> ./train_gpt2cu

或者直接运行 ./scripts/ 目录下的脚本之一。

多节点训练

请确保已按照“多 GPU 训练”部分的说明安装了 NCCL

我们目前支持三种多节点训练的方式:

  1. 使用 OpenMPI 交换 NCCL ID 并初始化 NCCL。详情请参阅 ./scripts/multi_node/run_gpt2_124M_mpi.sh 脚本。
  2. 使用共享文件系统初始化 NCCL。详情请参阅 ./scripts/multi_node/run_gpt2_124M_fs.sbatch 脚本。
  3. 使用 TCP 套接字初始化 NCCL。详情请参阅 ./scripts/multi_node/run_gpt2_124M_tcp.sbatch 脚本。

注意:

  • 如果你在 Slurm 环境中运行,而你的 Slurm 不支持 PMIx(考虑到 slurm-wlm 已经放弃了对 PMIx 的支持,这种情况很常见),则必须使用文件系统(2)或 TCP(3)方法。要测试你的 Slurm 是否支持 PMIx,请运行:srun --mpi=list,查看输出中是否包含 pmix
  • 如果没有设置 Slurm,也可以使用 mpirun 来启动多节点运行——即 MPI(1)方法。

这三种方法并无优劣之分,我们只是为你提供多种选择,以便你能够在特定环境中进行训练。

实验 / 参数扫描

以一台拥有 4 个 GPU 的机器为例,对 TinyStories 数据集上的学习率进行扫描。运行一个名为 sweep.sh 的 Shell 脚本(当然,在运行之前需要先执行 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

# 可以使用以下命令关闭这些会话:
# screen -ls | grep -E "tr[0-3]" | cut -d. -f1 | xargs -I {} screen -X -S {} quit

此示例会打开 4 个 screen 会话,并分别使用不同的学习率运行命令。日志文件 stories$i.log 中会记录所有损失值,你可以根据需要使用 Python 绘制图表。关于如何解析和绘制这些日志文件的快速示例,请参阅 dev/vislog.ipynb

仓库

关于我希望这个仓库成为什么样子,再补充几句:

首先,我希望 llm.c 成为一个教育平台。例如,我们的 dev/cuda 文件夹就是一个库,存放着所有手动编写且文档详尽的层级内核,从最简单的内核开始,逐步过渡到更复杂、更高效的内核。如果你有新的内核,并且在不同权衡之间有所取舍,请随时在此贡献。

与此同时,我也希望 llm.c 能够足够高效,甚至在实际应用中可用于训练神经网络。例如,作为起点,我们应该能够复现大型 GPT-2(16 亿参数)的训练过程。这就要求我们整合所有最快的内核,包括使用 cuBLAS、cuBLASLt、CUTLASS、cuDNN 等库。我认为这样做也有助于教育目的,可以建立一个专家级别的上限,作为一种衡量标准——比如,你可以说自己编写的内核达到了 cuBLAS 速度的 80% 等。这样,你可以选择进行超快速的训练,也可以选择“拖放”任意想要使用的手动内核来运行。

然而,出于约束考虑,我希望保持根目录下 llm.c 主线代码的简洁和易读性。如果某个 PR 虽然能将性能提升 2%,但却增加了 500 行复杂的 C 代码,还可能引入一些奇特的第三方依赖,那么我可能会拒绝该 PR,因为其复杂性并不值得。举个具体的例子:在根目录的训练循环中将矩阵乘法的 cuBLAS 实现设为默认,这显然是明智之举——它不仅使主线代码运行得更快,而且只有一行可读的代码,同时也是一个非常常见的依赖项。与此同时,我们可以在 dev/cuda 中保留与 cuBLAS 竞争的手动实现。

最后,我对项目根目录的复杂度会更加敏感,因为那里包含了项目的主文件和默认文件。相比之下,dev/ 文件夹更像是一个试验空间,用于开发内核或类库,并分享有用、相关或具有教育意义的代码,其中一些代码即使局部较为复杂也无妨。

著名的分支

讨论区

开发组织方式:

  • 如果你在使用仓库时遇到具体问题,请使用 Issues
  • 如果你有代码要贡献,请打开一个 PR
  • 如果你想讨论仓库、提问等,请查看 Discussions
  • 如果需要更快速的交流,我在我的 Zero to Hero Discord 频道 创建了一个新的 #llmc 频道。

许可证

MIT

常见问题

相似工具推荐

stable-diffusion-webui

stable-diffusion-webui 是一个基于 Gradio 构建的网页版操作界面,旨在让用户能够轻松地在本地运行和使用强大的 Stable Diffusion 图像生成模型。它解决了原始模型依赖命令行、操作门槛高且功能分散的痛点,将复杂的 AI 绘图流程整合进一个直观易用的图形化平台。 无论是希望快速上手的普通创作者、需要精细控制画面细节的设计师,还是想要深入探索模型潜力的开发者与研究人员,都能从中获益。其核心亮点在于极高的功能丰富度:不仅支持文生图、图生图、局部重绘(Inpainting)和外绘(Outpainting)等基础模式,还独创了注意力机制调整、提示词矩阵、负向提示词以及“高清修复”等高级功能。此外,它内置了 GFPGAN 和 CodeFormer 等人脸修复工具,支持多种神经网络放大算法,并允许用户通过插件系统无限扩展能力。即使是显存有限的设备,stable-diffusion-webui 也提供了相应的优化选项,让高质量的 AI 艺术创作变得触手可及。

162.1k|★★★☆☆|今天
开发框架图像Agent

everything-claude-code

everything-claude-code 是一套专为 AI 编程助手(如 Claude Code、Codex、Cursor 等)打造的高性能优化系统。它不仅仅是一组配置文件,而是一个经过长期实战打磨的完整框架,旨在解决 AI 代理在实际开发中面临的效率低下、记忆丢失、安全隐患及缺乏持续学习能力等核心痛点。 通过引入技能模块化、直觉增强、记忆持久化机制以及内置的安全扫描功能,everything-claude-code 能显著提升 AI 在复杂任务中的表现,帮助开发者构建更稳定、更智能的生产级 AI 代理。其独特的“研究优先”开发理念和针对 Token 消耗的优化策略,使得模型响应更快、成本更低,同时有效防御潜在的攻击向量。 这套工具特别适合软件开发者、AI 研究人员以及希望深度定制 AI 工作流的技术团队使用。无论您是在构建大型代码库,还是需要 AI 协助进行安全审计与自动化测试,everything-claude-code 都能提供强大的底层支持。作为一个曾荣获 Anthropic 黑客大奖的开源项目,它融合了多语言支持与丰富的实战钩子(hooks),让 AI 真正成长为懂上

140.4k|★★☆☆☆|今天
开发框架Agent语言模型

ComfyUI

ComfyUI 是一款功能强大且高度模块化的视觉 AI 引擎,专为设计和执行复杂的 Stable Diffusion 图像生成流程而打造。它摒弃了传统的代码编写模式,采用直观的节点式流程图界面,让用户通过连接不同的功能模块即可构建个性化的生成管线。 这一设计巧妙解决了高级 AI 绘图工作流配置复杂、灵活性不足的痛点。用户无需具备编程背景,也能自由组合模型、调整参数并实时预览效果,轻松实现从基础文生图到多步骤高清修复等各类复杂任务。ComfyUI 拥有极佳的兼容性,不仅支持 Windows、macOS 和 Linux 全平台,还广泛适配 NVIDIA、AMD、Intel 及苹果 Silicon 等多种硬件架构,并率先支持 SDXL、Flux、SD3 等前沿模型。 无论是希望深入探索算法潜力的研究人员和开发者,还是追求极致创作自由度的设计师与资深 AI 绘画爱好者,ComfyUI 都能提供强大的支持。其独特的模块化架构允许社区不断扩展新功能,使其成为当前最灵活、生态最丰富的开源扩散模型工具之一,帮助用户将创意高效转化为现实。

107.7k|★★☆☆☆|2天前
开发框架图像Agent

NextChat

NextChat 是一款轻量且极速的 AI 助手,旨在为用户提供流畅、跨平台的大模型交互体验。它完美解决了用户在多设备间切换时难以保持对话连续性,以及面对众多 AI 模型不知如何统一管理的痛点。无论是日常办公、学习辅助还是创意激发,NextChat 都能让用户随时随地通过网页、iOS、Android、Windows、MacOS 或 Linux 端无缝接入智能服务。 这款工具非常适合普通用户、学生、职场人士以及需要私有化部署的企业团队使用。对于开发者而言,它也提供了便捷的自托管方案,支持一键部署到 Vercel 或 Zeabur 等平台。 NextChat 的核心亮点在于其广泛的模型兼容性,原生支持 Claude、DeepSeek、GPT-4 及 Gemini Pro 等主流大模型,让用户在一个界面即可自由切换不同 AI 能力。此外,它还率先支持 MCP(Model Context Protocol)协议,增强了上下文处理能力。针对企业用户,NextChat 提供专业版解决方案,具备品牌定制、细粒度权限控制、内部知识库整合及安全审计等功能,满足公司对数据隐私和个性化管理的高标准要求。

87.6k|★★☆☆☆|昨天
开发框架语言模型

ML-For-Beginners

ML-For-Beginners 是由微软推出的一套系统化机器学习入门课程,旨在帮助零基础用户轻松掌握经典机器学习知识。这套课程将学习路径规划为 12 周,包含 26 节精炼课程和 52 道配套测验,内容涵盖从基础概念到实际应用的完整流程,有效解决了初学者面对庞大知识体系时无从下手、缺乏结构化指导的痛点。 无论是希望转型的开发者、需要补充算法背景的研究人员,还是对人工智能充满好奇的普通爱好者,都能从中受益。课程不仅提供了清晰的理论讲解,还强调动手实践,让用户在循序渐进中建立扎实的技能基础。其独特的亮点在于强大的多语言支持,通过自动化机制提供了包括简体中文在内的 50 多种语言版本,极大地降低了全球不同背景用户的学习门槛。此外,项目采用开源协作模式,社区活跃且内容持续更新,确保学习者能获取前沿且准确的技术资讯。如果你正寻找一条清晰、友好且专业的机器学习入门之路,ML-For-Beginners 将是理想的起点。

85k|★★☆☆☆|今天
图像数据工具视频

ragflow

RAGFlow 是一款领先的开源检索增强生成(RAG)引擎,旨在为大语言模型构建更精准、可靠的上下文层。它巧妙地将前沿的 RAG 技术与智能体(Agent)能力相结合,不仅支持从各类文档中高效提取知识,还能让模型基于这些知识进行逻辑推理和任务执行。 在大模型应用中,幻觉问题和知识滞后是常见痛点。RAGFlow 通过深度解析复杂文档结构(如表格、图表及混合排版),显著提升了信息检索的准确度,从而有效减少模型“胡编乱造”的现象,确保回答既有据可依又具备时效性。其内置的智能体机制更进一步,使系统不仅能回答问题,还能自主规划步骤解决复杂问题。 这款工具特别适合开发者、企业技术团队以及 AI 研究人员使用。无论是希望快速搭建私有知识库问答系统,还是致力于探索大模型在垂直领域落地的创新者,都能从中受益。RAGFlow 提供了可视化的工作流编排界面和灵活的 API 接口,既降低了非算法背景用户的上手门槛,也满足了专业开发者对系统深度定制的需求。作为基于 Apache 2.0 协议开源的项目,它正成为连接通用大模型与行业专有知识之间的重要桥梁。

77.1k|★★★☆☆|2天前
Agent图像开发框架