百度360必应搜狗淘宝本站头条
当前位置:网站首页 > 热门文章 > 正文

“退网”两周的前OpenAI大神归来再整活,1000行C代码搞定GPT-2训练,网友:C语言复兴了!

bigegpt 2024-08-07 17:37 11 浏览

编译 | 屠敏
出品 | CSDN(ID:CSDNnews)

大佬的话究竟有几分可信?很多人已经傻傻分不清了,遥记多年前,当 Linux 之父 Linus Torvalds 声称要去休假时,他一个人趁着休息时间捣鼓出了如今成为主流的项目版本管理工具 Git。

现下放到 AI 领域,不久之前,特斯拉前 AI 总监、OpenAI 联合创始人 Andrej Karpathy 在社交媒体平台 X 上高调宣布,他友好地从 OpenAI 离职,未来将专注于“个人项目”,而后又口口声声说要尝试性地戒掉上网两周,去了 Bhutan(不丹王国)休假。

谁承想,就在其宣布回归互联网的第三天,他便带来了自己徒手编写的 1000 行 C 代码即实现 GPT-2 训练的新项目——LLM.c(https://github.com/karpathy/llm.c),惊艳众人。

这款开源项目一经发布,便迅速冲到 HN 的 Top 榜,且在 GitHub 上也狂揽 2600 颗星。

而 Andrej Karpathy 本人,也因之前使用纯 C 代码实现轻量版 LLaMA 2 并成功跑在 MacBook 上的经历,加上这一次的尝试,被网友给予了一个肯定的评价——「Real men program in C」(真男人就应该用 C 编程)。

1000 行 C 代码完成 GPT-2 训练的 LLM.c

根据 GitHub 页面介绍,llm.c 是一个简单、纯粹的 C/CUDA LLM 训练项目。不需要使用 245MB 的 PyTorch 或 107MB 的 cPython 就能用纯 C 语言训练 LLM。

更让人佩服的是,LLM.c 仅用约 1000 行干净的代码即可在 CPU/fp32 上实现 GPT-2 训练。它可以立即编译并运行,并且与 PyTorch 参考实现完全匹配。

之所以选择 GPT-2 作为训练的起点,Andrej Karpathy 表示,是因为 GPT-2 是 LLM 的鼻祖,这也是大模型堆栈第一次以公认的现代形式组合在一起,并提供了模型权重。

你可以在这里查看原始的训练实施情况:

https://github.com/karpathy/llm.c/blob/master/train_gpt2.c

Andrej Karpathy 透露,这个项目在一开始就在一个大的 1D 内存块中一次性分配了所有需要的内存。

由此,在训练过程中不会创建或销毁内存,因此内存占用量保持不变,只是动态地将数据批次流过。

这里的关键在于手动实现所有单个层的前向和后向传递,然后将它们串联起来。例如,这里是 layernorm 的前向和后向传递。

除了 layernorm 之外,也还需要编码器、matmul、自注意力、gelu、残差、softmax 和交叉熵损失。

一旦你有了所有的层,你就可以把所有的层串联起来。

“不瞒你说,写这个过程相当乏味,也很受虐,因为你必须确保所有的指针和张量偏移都正确排列”,Andrej Karpathy 吐槽道。

左图:在内存中分配一个单一的 1D 数组,然后将所有模型权重和激活指向该数组;
右图:非常小心地进行所有指针运算

一旦有了前向/后向,剩下的部分(数据加载器、Adam 更新等)就变得微不足道了。

不过,真正的乐趣才刚刚开始,Andrej Karpathy 分享道,“我现在正在逐层将其移植到 CUDA,这样它就能变得高效,甚至可以与 PyTorch 相媲美,但却没有任何严重的依赖性。我已经做了几层了,这是一项相当有趣的 CUDA 工作。”

在此基础上,扩展包括将精度从 fp32 降低到 fp16/以下,并增加几层(如 RoPE),以支持更现代的架构,如 llama 2 / mistral / gemma 等。

对此,Andrej Karpathy 也表示,一旦这个项目进入稍稍稳定的状态后,他就会从头开始构建更为详细的观看视频。

立足于当下,Andrej Karpathy 也正在研究:

  • 直接使用 CUDA 实现,这将大大提高速度,并可能接近 PyTorch。

  • 使用 SIMD 指令加速 CPU 版本,X86 上的 AVX2 / ARM 上的 NEON(如 Apple Silicon)。

  • 更现代的架构,如 Llama2、Gemma 等。

对于 GitHub repo,他希望同时维护干净、简单的参考实现,以及更优化的版本,这些版本可以接近 PyTorch,但代码和依赖性只占很小一部分。

快速开始吧!

基于此,Andrej Karpathy 也为广大网友直接开始上 LLM.c 的使用步骤,方便大家自己去实践一把。

首先第一步,下载并 tokenize 数据集。在这里,Andrej Karpathy 使用了 tinyshakespeare 数据集(https://raw.githubusercontent.com/karpathy/char-rnn/master/data/tinyshakespeare/input.txt),并称其下载和 tokenize 速度最快:

python prepro_tinyshakespeare.py

输出:

Saved 32768 tokens to data/tiny_shakespeare_val.binSaved 305260 tokens to data/tiny_shakespeare_train.bin

.bin 文件是由 int32 数字组成的原始字节流,用 GPT-2 tokenizer 表示 token ID。你也可以使用 prepro_tinystories.py 对 TinyStories 数据集进行 tokenize。

原则上,按照步骤走到这里就可以训练模型了。

不过,Andrej Karpathy 表示,CPU/fp32 基准参考代码的效率很低,从头开始训练这些模型还不太现实。相反,他使用 OpenAI 发布的 GPT-2 权重进行初始化,然后进行微调。为此,必须下载 GPT-2 权重,并将其保存为检查点,以便在 C 语言中加载:

python train_gpt2.py

你可以从 nanoGPT 中找到这段代码,它是 PyTorch 中简单的 GPT-2 参考实现。

这个脚本将下载 GPT-2 (124M) 模型,对一批数据进行 10 次迭代过拟合,运行几步生成,最重要的是它将保存两个文件:

1)gpt2_124M.bin 文件,其中包含用于在 C 语言中加载的原始模型权重;

2)gpt2_124M_debug_state.bin,其中还包含更多调试状态:输入、目标、logits 和损失。这对调试 C 代码、单元测试和确保我们与 PyTorch 参考实现完全匹配非常有用。

现在,我们只关心 gpt2_124M.bin 中的模型权重,以用它们进行初始化,并用原始 C 语言进行训练:

make train_gpt2

当然,你可以查看 Makefile 及其注释。它将尝试自动检测你的系统是否支持 OpenMP,这对于以极低的代码复杂度为代价加快代码速度非常有帮助。train_gpt2 编译完成后,就可以运行了:

OMP_NUM_THREADS=8 ./train_gpt2

接下来,我们应该根据 CPU 的内核数量来调整线程数。程序将加载模型权重和 token,它将在 Adam lr 1e-4 的条件下运行微调 loop,进行几次迭代,然后根据模型生成样本。

“该文件(我认为)可读性很强,你应该看一看。简单地说,所有层的前向和后向传递都有实现方法,它们被串成一个大型的手动前向/后向/更新循环。”Andrej Karpathy 说。

在 MacBook Pro(苹果 Silicon M3 Max)上,输出结果是这样的:

[GPT-2]max_seq_len: 1024vocab_size: 50257num_layers: 12num_heads: 12channels: 768num_parameters: 124439808train dataset num_batches: 1192val dataset num_batches: 128num_activations: 73323776val loss 5.252026step 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.107781generated: 50256 16773 18162 21986 11 198 13681 263 23875 198 3152 262 11773 2910 198 1169 6002 6386 2583 286 262 11858 198 20424 428 3135 7596 995 3675 13 198 40 481 407 736 17903 11 329 703 6029 706 4082 198 42826 1028 1128 633 263 11 198 10594 407 198 2704 454 680 1028 262 1027 28860 286 198 3237 323step 40: train loss 4.377757 (took 1366.368000 ms)

现在,生成器只提供 token ID,我们必须将其解码为文本。当然也可以用 C 语言轻松实现,因为解码非常简单,只需查找字符串块并打印即可。时下可以使用 tiktoken:

import tiktokenenc = tiktoken.get_encoding("gpt2")print(enc.decode(list(map(int, "50256 16773 18162 21986 11 198 13681 263 23875 198 3152 262 11773 2910 198 1169 6002 6386 2583 286 262 11858 198 20424 428 3135 7596 995 3675 13 198 40 481 407 736 17903 11 329 703 6029 706 4082 198 42826 1028 1128 633 263 11 198 10594 407 198 2704 454 680 1028 262 1027 28860 286 198 3237 323".split()))))

输出:

<|endoftext|>Come Running Away,Greater conquerWith the Imperial bloodthe heaviest host of the godsinto this wondrous world beyond.I will not back thee, for how sweet after birthNetflix against repounder,will notflourish against the earlocks ofAllay

「我喜欢 Netflix 出现的方式,很明显,模型中还潜藏着过去训练的影子」,Andrej Karpathy表示,「我没有尝试调整微调超参数,因此很有可能会有很大改进,尤其是在训练时间更长的情况下。」

除了具体的步骤之外,Andrej Karpathy 还附上了一个简单的单元测试,以确保 C 代码与 PyTorch 代码一致。编译并运行:

make test_gpt2./test_gpt2

现在加载 gpt2_124M_debug_state.bin 文件,运行前向传递,比较 logits 和损失与 PyTorch 参考实现,然后用 Adam 进行 10 次迭代训练,确保损失与 PyTorch 一致。

写在最后

Andrej Karpathy 时不时丢一个 LLM 相关的个人项目,还附上详尽的教程,也让不少网友开启膜拜模式:

还有人评价道,在前有很多政府机构将 C/C++ 归纳为不安全的内存语言之际,“我们实际上正在开始一场 C 语言的复兴”。

最后,不得不说,离开企业后的 Andrej Karpathy 更为自由一些,他不仅在 YouTube 上持续分享有关大模型的教学视频,更是生怕这届学生看不懂,每次在发布项目时,都会附上详尽的教程。

这不,在发布 LLM.c 时,Andrej Karpathy 在 doc/layernorm/layernorm.md 中附上了一个很小的教程:这是实现 GPT-2 模型单层(layernorm 层)的一个简单的分步指南,也是了解如何用 C 语言实现层的一个很好的起点。

来源:

https://twitter.com/karpathy/status/1777427944971083809

https://github.com/karpathy/llm.c

https://github.com/karpathy/llm.c/blob/master/doc/layernorm/layernorm.md

相关推荐

方差分析简介(方差分析通俗理解)

介绍方差分析(ANOVA,AnalysisofVariance)是一种广泛使用的统计方法,用于比较两个或多个组之间的均值。单因素方差分析是方差分析的一种变体,旨在检测三个或更多分类组的均值是否存在...

正如404页面所预示,猴子正成为断网元凶--吧嗒吧嗒真好吃

吧嗒吧嗒,绘图:MakiNaro你可以通过加热、冰冻、水淹、模塑、甚至压溃压力来使网络光缆硬化。但用猴子显然是不行的。光缆那新挤压成型的塑料外皮太尼玛诱人了,无法阻挡一场试吃盛宴的举行。印度政府正...

Python数据可视化:箱线图多种库画法

概念箱线图通过数据的四分位数来展示数据的分布情况。例如:数据的中心位置,数据间的离散程度,是否有异常值等。把数据从小到大进行排列并等分成四份,第一分位数(Q1),第二分位数(Q2)和第三分位数(Q3)...

多组独立(完全随机设计)样本秩和检验的SPSS操作教程及结果解读

作者/风仕在上一期,我们已经讲完了两组独立样本秩和检验的SPSS操作教程及结果解读,这期开始讲多组独立样本秩和检验,我们主要从多组独立样本秩和检验介绍、两组独立样本秩和检验使用条件及案例的SPSS操作...

方差分析 in R语言 and Excel(方差分析r语言例题)

今天来写一篇实际中比较实用的分析方法,方差分析。通过方差分析,我们可以确定组别之间的差异是否超出了由于随机因素引起的差异范围。方差分析分为单因素方差分析和多因素方差分析,这一篇先介绍一下单因素方差分析...

可视化:前端数据可视化插件大盘点 图表/图谱/地图/关系图

前端数据可视化插件大盘点图表/图谱/地图/关系图全有在大数据时代,很多时候我们需要在网页中显示数据统计报表,从而能很直观地了解数据的走向,开发人员很多时候需要使用图表来表现一些数据。随着Web技术的...

matplotlib 必知的 15 个图(matplotlib各种图)

施工专题,我已完成20篇,施工系列几乎覆盖Python完整技术栈,目标只总结实践中最实用的东西,直击问题本质,快速帮助读者们入门和进阶:1我的施工计划2数字专题3字符串专题4列表专题5流程控制专题6编...

R ggplot2常用图表绘制指南(ggplot2绘制折线图)

ggplot2是R语言中强大的数据可视化包,基于“图形语法”(GrammarofGraphics),通过分层方式构建图表。以下是常用图表命令的详细指南,涵盖基本语法、常见图表类型及示例,适合...

Python数据可视化:从Pandas基础到Seaborn高级应用

数据可视化是数据分析中不可或缺的一环,它能帮助我们直观理解数据模式和趋势。本文将全面介绍Python中最常用的三种可视化方法。Pandas内置绘图功能Pandas基于Matplotlib提供了简洁的绘...

Python 数据可视化常用命令备忘录

本文提供了一个全面的Python数据可视化备忘单,适用于探索性数据分析(EDA)。该备忘单涵盖了单变量分析、双变量分析、多变量分析、时间序列分析、文本数据分析、可视化定制以及保存与显示等内容。所...

统计图的种类(统计图的种类及特点图片)

统计图是利用几何图形或具体事物的形象和地图等形式来表现社会经济现象数量特征和数量关系的图形。以下是几种常见的统计图类型及其适用场景:1.条形图(BarChart)条形图是用矩形条的高度或长度来表示...

实测,大模型谁更懂数据可视化?(数据可视化和可视化分析的主要模型)

大家好,我是Ai学习的老章看论文时,经常看到漂亮的图表,很多不知道是用什么工具绘制的,或者很想复刻类似图表。实测,大模型LaTeX公式识别,出乎预料前文,我用Kimi、Qwen-3-235B...

通过AI提示词让Deepseek快速生成各种类型的图表制作

在数据分析和可视化领域,图表是传达信息的重要工具。然而,传统图表制作往往需要专业的软件和一定的技术知识。本文将介绍如何通过AI提示词,利用Deepseek快速生成各种类型的图表,包括柱状图、折线图、饼...

数据可视化:解析箱线图(box plot)

箱线图/盒须图(boxplot)是数据分布的图形表示,由五个摘要组成:最小值、第一四分位数(25th百分位数)、中位数、第三四分位数(75th百分位数)和最大值。箱子代表四分位距(IQR)。IQR是...

[seaborn] seaborn学习笔记1-箱形图Boxplot

1箱形图Boxplot(代码下载)Boxplot可能是最常见的图形类型之一。它能够很好表示数据中的分布规律。箱型图方框的末尾显示了上下四分位数。极线显示最高和最低值,不包括异常值。seaborn中...