llm.c
纯C/CUDA手写大模型训练,用约1000行代码复现GPT-2,比PyTorch快7%
加载项目详情…
本应用为开源项目,仅供学习研究,请遵守其开源协议。
纯C/CUDA手写大模型训练,用约1000行代码复现GPT-2,比PyTorch快7%
加载项目详情…
本应用为开源项目,仅供学习研究,请遵守其开源协议。
想象一下:你是一位经验丰富的赛车工程师,想要彻底理解引擎的每一个零件——于是你决定抛开所有现代汽车工程软件,从零用最简单的工具打造一台发动机。Andrej Karpathy 就是这样一位"赛车工程师",只不过他的"赛车"是当前最火热的大语言模型(LLM)。
Karpathy 是特斯拉前 AI 总监、OpenAI 创始成员之一,也是全球最知名的 AI 教育者之一(他的 CS231n、nanoGPT 课程影响了数十万开发者)。2023年,他创建了 llm.c 项目——一个用最原始的 C/CUDA 代码实现 GPT-2/GPT-3 级别模型训练的代码库。这个项目的核心理念是:剥离 PyTorch 的层层抽象,直接用 CUDA 内核手写大模型训练。
这个项目在 GitHub 上已获得超过 30,000 颗星,吸引了大量对 LLM 底层机制充满好奇的开发者、研究者和学生关注。它不仅仅是一个训练代码库,更像是一本"活的教科书",展示了现代深度学习框架最核心的计算图是如何在硬件层面实现的。

图1:Andrej Karpathy GitHub 头像
当你用 PyTorch 训练 GPT-2 时,实际上在运行一个复杂的计算图:PyTorch 的 Autograd 引擎追踪所有操作并自动生成反向传播代码;cuBLAS/cuDNN 库提供高度优化的矩阵运算;Python 解释器在每一行代码执行时都有开销;庞大的依赖树(PyTorch 本身约 245MB,CPython 约 107MB)让部署变得笨重。
这些抽象层带来便利,但也意味着:你看不见底层发生了什么。梯度是如何累积的?注意力机制在 GPU 上是如何分块执行的?优化器的状态是如何管理的?PyTorch 替你做了太多决定。
llm.c 选择了完全相反的路线:用约 1000 行干净的 C 代码(train_gpt2.c),实现完整的 GPT-2 训练。没有 PyTorch,没有 Python 运行时依赖,没有神秘的框架魔法。每一个矩阵乘法、每一次 Softmax、每一轮反向传播,都是你能在代码里直接读到的 CUDA 内核调用。
项目同时提供了 CUDA 加速版本(train_gpt2.cu),实测速度比 PyTorch Nightly 快约 7%——这说明"极简"并不等于"低效",有时候"自己造轮子"反而能造出更快的轮子。
llm.c/
├── train_gpt2.c # CPU 单精度参考实现 (~1000行)
├── train_gpt2.cu # CUDA GPU 加速版本
├── train_gpt2_fp32.cu # FP32 遗留版本(更易学习)
├── train_gpt2.py # PyTorch 对照参考实现
├── llmc/ # 核心 CUDA 内核库
│ ├── attention.cuh # Flash Attention CUDA 实现
│ ├── adamw.cuh # AdamW 优化器
│ ├── fused_classifier.cuh # 融合分类损失
│ ├── cudnn_att.cpp # cuDNN 融合注意力
│ └── ...
└── Makefile # 一键编译
1. 融合 CUDA 内核(Fused Kernels)
传统 PyTorch 训练中,GPT-2 的一个前向传播需要执行数十个独立的 GPU 内核调用:矩阵乘法(GEMM)、逐元素操作(ReLU/GELU)、Softmax、Dropout……每一次内核启动(kernel launch)都有固定开销。
llm.c 的 llmc/ 目录实现了"融合内核":将多个操作合并到单个 CUDA 内核中执行。例如 fused_classifier.cuh 将交叉熵损失与其梯度计算融合为一个内核,大幅减少内存带宽压力和内核启动开销。这也是它能比 PyTorch 快 7% 的关键原因。
2. Flash Attention 的 CUDA 原生实现
标准 Attention 机制的内存复杂度是 O(N²),处理长序列时显存爆炸。Flash Attention 通过分块计算(tiling)+ 重计算技巧,将显存降低到 O(N),但计算量略有增加。llm.c 在 attention.cuh 和 cudnn_att.cpp 中分别提供了手写 CUDA 实现和 cuDNN 8.9+ API 实现两种选择。
3. cuDNN 融合注意力
cuDNN 从 8.9 版本开始提供融合注意力 API,可以将 QKV 投影、缩放、Scaled Dot-Product Attention、输出投影打包成单一 cuDNN 调用。llm.c 的 cudnn_att.cpp 封装了这一 API,提供了一个生产级别的注意力实现选项。
4. 极简的 CPU 参考实现
对于想学习大模型训练原理但没有 GPU 的开发者,train_gpt2.c 提供了一个约 1000 行单文件的 CPU fp32 实现。它去掉了所有 GPU 相关的复杂性,专注于训练的核心逻辑:在 tinyshakespeare 数据集上训练一个字符级 GPT 模型,每一步都清晰可读。
| 层次 | 技术选型 |
|---|---|
| 编程语言 | C(CPU)、CUDA C(GPU)、Python(数据预处理/参考实现) |
| GPU 加速 | CUDA 12.1+, cuDNN 8.9+ |
| 构建工具 | Make |
| 数值精度 | FP32(参考)、FP16/BF16(CUDA版) |
| 优化器 | AdamW(llmc/adamw.cuh) |
| 数据集 | GPT-2 预训练数据、TinyShakespeare |
# 下载 starter pack(模型权重+数据集)
chmod u+x ./dev/download_starter_pack.sh
./dev/download_starter_pack.sh
# 编译并运行
make train_gpt2fp32cu
./train_gpt2fp32cu
这一套流程下载的内容包括:GPT-2 124M 的 FP32/BF16 权重、检查点状态(用于单元测试)、GPT-2 tokenizer,以及 tokenized 的 TinyShakespeare 数据集。
如果想要完整复现 GPT-2 124M 的训练流程:
pip install -r requirements.txt
python dev/data/tinyshakespeare.py # 数据预处理
python train_gpt2.py # PyTorch 参考实现
make train_gpt2cu && ./train_gpt2cu # C/CUDA 正式版本
项目 README 特别推荐了一个调试方法:将 Makefile 中的 -O3 替换为 -g,然后用 VSCode 等 IDE 的 CUDA 调试器单步跟踪。这对于理解 CUDA 内核的执行流程特别有帮助。
llm.c 的定位是教育和研究,不是替代 PyTorch/JAX 的生产训练框架。它不支持多节点分布式训练(尽管有 fp32 版本的分布式框架),不支持混合精度训练的完整优化,不支持超参自动搜索,也不是一个完整的 MLOps 工具链。
这个项目的"简单"是相对于深度学习框架而言的。你仍然需要一台带 NVIDIA GPU 的机器,安装 CUDA Toolkit 12.1+ 和 NVCC 编译器。对于纯 CPU 环境,只能运行约 1000 行的简化参考实现,无法训练真正的 GPT-2 规模模型。
作为 Karpathy 的个人项目(尽管有活跃的社区讨论),代码的维护和更新节奏取决于作者个人投入。API 和接口可能在未来版本中有较大变化,缺乏企业级的长期支持保障。
目前项目聚焦于 GPT-2/GPT-3 系列的预训练,没有提供指令微调(Instruction Tuning)、RLHF 对齐、推理(inference)优化(如 vLLM、TGI 的分页注意力)等功能。这些是当前 LLM 生态中非常重要的组成部分,但在 llm.c 中需要另行实现。
在 AI 框架日益复杂的今天,llm.c 代表了一种可贵的"逆向运动"。它告诉我们:即使是最强大的现代 AI 技术,其核心原理也是可以被理解、被重写的。这个项目让无数开发者第一次看清了"Attention 机制在 GPU 上到底是怎么跑起来的"。
llm.c 的融合内核实践反过来也影响了主流框架的优化方向。PyTorch 的 torch.compile、NVIDIA 的 Transformer Engine 都在借鉴这些"手工极致优化"的思路来提升框架原生性能。
对于 AI 教育而言,1000 行干净代码比 10000 行框架代码有价值得多。llm.c 让本科生和研究者在没有强大 GPU 集群的情况下,也能完整运行一个大模型训练的全流程,从数据下载到梯度更新,每一步都可观察、可修改。
项目在 GitHub Discussions 和 Discord(Zero to Hero、GPU MODE 社区)上有活跃的讨论。同时,社区也涌现出了 Rust、OpenCL 等其他语言的移植版本,形成了一个围绕"极简 LLM 训练"主题的技术生态。
总结:llm.c 是一个独特而珍贵的开源项目——它用最少的依赖、最干净的代码,完整实现了一个大语言模型的训练流程。它不是 PyTorch 的竞争对手,而是一面镜子,映照出当前 AI 框架世界中那些被抽象隐藏的底层之美。对于任何想真正理解 LLM 工作原理的开发者,这都是一个值得深入研究的宝藏项目。