Industry

教学

Client

2024年4月12日

Andrej Karpathy 介绍 llm.c

Andrej Karpathy 昨晚用非常通俗的解释介绍了自己用 C 语言实现 GPT-2 训练代码的原因以及这样做的优势和劣势: 大语言模型训练背后的复杂性与本质: PyTorch等库简化了流程但引入了复杂度,而直接用C语言实现能揭示LLM训练的数学本质。 这种简化的尝试虽有局限,但有助于加深理解,未来或许还能带来实用价值。

------原文------

训练像 ChatGPT 这样的大语言模型 (Large Language Models, LLMs),涉及大量的代码和复杂性。 举个例子,一个典型的 LLM 训练项目可能会使用 PyTorch 深度学习库。PyTorch 非常复杂,因为它实现了一个非常通用的 Tensor 抽象 (一种排列和操作保存神经网络参数和激活值的数字数组的方法),一个非常通用的用于反向传播的 Autograd 引擎 (训练神经网络参数的算法),以及大量你可能希望在神经网络中使用的深度学习层。PyTorch 项目包含了 11,449 个文件,总计 3,327,184 行代码。

此外,PyTorch 是用 Python 编写的,而 Python 本身就是一种非常高级的语言。你必须运行 Python 解释器将你的训练代码转换为计算机可以直接执行的低级指令。举个例子,负责执行这种转换的 cPython 项目,包含了 4,306 个文件,总计 2,437,955 行代码。 我正在移除所有这些复杂性,将 LLM 训练简化为其最基本的要素,直接用非常低级的 C 语言与计算机对话,不依赖任何其他库。比这更低层次的抽象就只有汇编语言了。

与上述相比,我认为人们可能会感到惊讶,使用 C 语言训练像 GPT-2 这样的 LLM,实际上只需要一个文件中大约 1000 行代码。我通过直接在 C 中实现 GPT-2 的神经网络训练算法来实现这种代码压缩。这是很有挑战性的,因为你必须非常详细地了解训练算法,能够推导出所有层的前向传播和反向传播,并非常仔细地实现所有数组索引计算,因为你没有 PyTorch 提供的 Tensor 抽象可以使用。

所以这是一个非常脆弱的过程,但是一旦你完成了,并通过与 PyTorch 的结果进行对比来验证正确性,你就会得到一些非常简单、小巧且在我看来非常优雅的代码。 那么,为什么人们不总是这样做呢?

第一,你放弃了很多灵活性。如果你想改变神经网络结构,在 PyTorch 中你可能只需要改变一行代码。但在 llm.c 中,修改可能会涉及更多的代码,可能会更加困难,并且需要更专业的知识。例如,如果是一个新的操作,你可能需要做一些数学推导,编写它的前向传播和反向传播过程,并确保数学上是正确的。

第二,至少在一开始,你可能会失去一些速度。天下没有免费的午餐——你不应该期望仅用 1,000 行代码就能达到最先进的速度。PyTorch 在后台做了大量工作以确保神经网络的高效运行。它不仅非常仔细地调用最高效的 CUDA 内核来实现所有 Tensor 运算,而且还提供了例如 torch.compile 这样的功能,可以进一步分析和优化你的神经网络以及它在你的计算机上的运行效率。原则上,llm.c 应该也能够直接调用所有相同的内核。但这需要额外的工作和注意,就像前面提到的,如果你改变了神经网络的任何细节,或者改变了运行它的计算机,你可能需要调用不同的内核,使用不同的参数,并且可能需要手动进行更多修改。

所以简而言之:llm.c 是训练 GPT-2 的直接实现。这个实现的代码量出奇地少。它不支持其他神经网络,只支持 GPT-2,如果你想改变网络的任何细节,都需要专业的知识。幸运的是,所有最先进的 LLM 实际上并没有偏离 GPT-2 太多,所以这并不是你想象中那么强的限制。而且 llm.c 还需要进行额外的调整和完善,但原则上我认为,经过一些正在进行的工作,它应该能够在代码量不会显著增加的情况下,几乎与 PyTorch 匹敌(或者由于摆脱了所有开销,甚至超过它),适用于大多数现代 LLM。

那么我为什么要研究它呢?

因为它很有趣。它也很有教育意义,因为那 1,000 行非常简单的 C 代码就是你需要的全部,不需要其他任何东西。它只是一些数字数组和一些简单的数学运算,如加法和乘法。而且,经过一些正在进行的工作,它甚至可能被证明是实用的。

© 2024 GUIZANG, Inc. All rights reserved.