训练大型语言模型(如ChatGPT)涉及大量的代码和复杂性。例如,一个典型的LLM训练项目可能会使用PyTorch深度学习库。PyTorch非常复杂,因为它实现了非常通用的张量抽象(一种用于排列和操作数组的方法,这些数组包含神经网络的参数和激活),以及一种非常通用的Autograd引擎来进行反向传播(训练神经网络参数的算法),以及您可能希望在神经网络中使用的大量深度学习层。PyTorch项目的源代码有11,449个文件,共3,327,184行代码。
除此之外,PyTorch是用Python编写的,而Python本身是一种非常高层次的语言。您必须运行Python解释器来将您的训练代码转换为低级计算机指令。例如,执行此转换的cPython项目有2,437,955行代码,分布在4,306个文件中。
我正在删除所有这些复杂性,并将LLM训练压缩到其基本要素,直接与计算机进行对话,没有任何其他库依赖关系。唯一低于这个级别的抽象就是汇编代码本身。我认为人们会惊讶地发现,与上述内容相比,训练像GPT-2这样的LLM实际上只需要在单个文件中的C语言中编写约1000行代码。要实现这一点,您需要详细了解训练算法,能够推导出所有层的所有前向和后向传递,并仔细实施所有数组索引计算,因为您没有可用的PyTorch张量抽象。因此,这是一项非常脆弱的工作,但是如果您进行了更改并再次检查了PyTorch以验证其正确性,则最终结果将非常简单、小且在我看来相当美丽。
所以,简而言之,llm.c是GPT-2的直接实现。这种实现令人惊讶地短。没有其他神经网络得到支持,只有GPT-2,而且如果您想对网络进行任何更改,它需要专业知识。幸运的是,所有最先进的LLM实际上与GPT-2并没有太大偏离,因此这不像您想象的那样是一个强烈的约束。并且llm.c还需要进一步调整和优化,但在大多数现代LLM上,它应该几乎可以匹配甚至超过PyTorch,而不需要比现在更多的代码。
那么我为什么要这样做呢?因为这是有趣的。这也是教育性的,因为这1000行非常简单的C代码就足够了,没有什么其他的。这只是几个数字数组和一些简单的元素运算,如加法和乘法。而且,随着正在进行的一些工作,它甚至可能变得实用。