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

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

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

编译 | 屠敏
出品 | 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

相关推荐

php-fpm的配置和优化

目录概述php-fpm配置php-fpm进程优化配置慢日志查询配置php7进阶到架构师相关阅读概述这是关于php进阶到架构之php7核心技术与实战学习的系列课程:php-fpm的配置和优化学习目标:理...

成功安装 Magento2.4.3最新版教程「技术干货」

外贸独立站设计公司xingbell.com经过多次的反复实验,最新版的magento2.4.3在oneinstack的环境下的详细安装教程如下:一.vps系统:LinuxCentOS7.7.19...

十分钟让你学会LNMP架构负载均衡

业务架构、应用架构、数据架构和技术架构一、几个基本概念1、pv值pv值(pageviews):页面的浏览量概念:一个网站的所有页面,在一天内,被浏览的总次数。(大型网站通常是上千万的级别)2、u...

php从远程URL获取(mp4 mp3)音视频的流媒体数据

/***从远程URL中获取媒体(如mp4mp3)的内容*@parammixed$file_url*@parammixed$media_type...

Zabbix5.0安装部署

全盘展示运行状态,减轻运维人员的重复性工作量,提高系统排错速度,加速运维知识学习积累。1.png1、环境安装关闭SELinux并重启系统2.png安装httpd、mariadb、php运行yum-...

php 常见配置详解

以下是PHP常见的配置项及其含义:error_reporting:设置错误报告级别,可以控制PHP显示哪些错误。例如,设置为E_ALL将显示所有错误,而设置为0将禁止显示任何错误。displa...

实践分享|基于基石智算 DeepSeek API + WordPress 插件自动生成访客回复

基石智算举办的DeepSeek案例大赛汇集了不少基于CoresHubDeepSeekAPI服务或模型部署服务的精彩实践。本次我们将分享个人实践:通过DeepSeekAPI+Word...

如何在Eclipse中搭建Zabbix源码的调试和开发环境

Zabbix是一款非常优秀的企业级软件,被设计用于对数万台服务器、虚拟机和网络设备的数百万个监控项进行实时监控。Zabbix是开放源码和免费的,这就意味着当出现bug时,我们可以很方便地通过调试源码来...

MySQL自我保护参数

#头条创作挑战赛#之前(MySQL自我保护工具--pt-kill)提到用pt-kill工具来kill相关的会话,来达到保护数据库的目的,本文再通过修改数据库参数的方式达到阻断长时间运行的SQL的目...

Python闭包深度解析:掌握数据封装的高级技巧

闭包作为Python高级编程特性之一,为开发者提供了一种优雅的方式来实现数据封装和状态保持。这一概念源于函数式编程理论,在现代Python开发中发挥着重要作用。理解和掌握闭包的使用不仅能够提升代码的表...

Java服务网格故障注入与熔断实战

在分布式系统的高可用性挑战中,服务网格的故障注入与熔断机制是检验系统韧性的终极试金石。以下是10道逐步升级的"地狱关卡",每个关卡都对应真实生产环境中可能遇到的致命场景,并附具体场景示...

MySQL数据库性能优化全攻略:程序员必知的七大核心策略

作为程序员,我们每天都要与数据库打交道。当系统用户量突破百万级时,数据库往往成为性能瓶颈的首要怀疑对象。本文将深入探讨MySQL优化的七大核心策略,并提供可直接落地的优化方案,助您构建高效稳定的数据库...

如何在 Windows 11 上使用单个命令安装 XAMPP

XAMPP是一种广泛使用的软件,用于在Windows操作系统上快速运行LAMP服务器包,包括Windows11。尽管LAMP通常用于Linux系统,但XAMPP并不使用Li...

uTorrent怎样将bt种子转换为磁力

如何用uTorrent把BT种子转为磁力链接?以下方法希望能帮到你。1、在uTorrent窗口里,点击工具栏的按钮,所示。2、在打开窗口里,选取要转为磁力的种子文件,然后点击打开按钮,参照图示操作...

支持向量机SVM 分类和回归的实例

支持向量机(SupportVectorMachine)是Cortes和Vapnik于1995年首先提出的,它在解决小样本、非线性及高维模式识别中表现出许多特有的优势,并能够推广应用到函数拟合等其他...