作者以Java手写GPT完整实现,涵盖分词、Embedding、自注意力、反向传播、训练和文本生成全过程,无任何AI框架依赖,适合想深入理解大模型原理的程序员。
过去几周,我启动了一个个人项目,乍看之下似乎不太实际:用 Java 从零实现一个 GPT,不使用任何 AI 框架。不用 TensorFlow,不用 PyTorch,不用 DJL。只有线性代数、几百行代码,以及深入理解语言模型每个组成部件的意愿。
原因很简单:AI 生态演进的速度让我感到,必须加深对基础原理的理解——从支撑当今几乎所有生成式 AI 应用的那块积木开始,也就是 Transformer。我每天都在使用这一层的应用(RAG、copilot、集成),但到某个时刻,我意识到自己想更好地理解这一切底层究竟是什么,而不只是当一个消费者。
这份渴望催生了 MiniGPT。想法说起来简单,但执行起来绝不轻松:在 Transformer Decoder(由 token 化、嵌入、自注意力、反向传播、训练、文本生成等多个组件构成)的每个环节上手工构建,最终让自己对日常应用中见到的东西有更深入的理解。
这一系列文章记录了这段旅程。路线图分多个阶段,从数学基础到训练模型的推理与文本生成,每篇文章对应一个阶段。这不是一组拿来就能复制粘贴的教程;而是记录每一个决策、每一个为什么,以及犯过的错误——毕竟,手动实现反向传播这种事,不可能在第一次就成功,而我觉得价值恰恰在于展示这个过程。
在深入代码之前,值得在名称上稍作停顿。GPT 的全称是 Generative Pre-trained Transformer,这三个词中的每一个都对应着一个特定的架构决策。
Transformer 是 Vaswani 等 Google 研究人员在 2017 年论文《Attention Is All You Need》中描述的架构。原始提案用编码器(读取整个输入句子)和解码器(逐 token 生成输出句子)解决了机器翻译问题。GPT 只使用了其中一半的架构——解码器那一半——所以被称为"decoder-only"。这很合理,因为语言模型不需要在"阅读"源句子后再翻译;它只需要在已知前文所有内容的前提下,预测下一个最可能的 token 是什么。
正是这种被称为自回归建模的预测机制,支撑着训练和文本生成两个阶段。在训练期间,模型看到一段文本并学习预测下一个 token;在生成期间,它做的事情其实完全一样,逐 token 重复执行,把自己上一轮的输出作为下一轮预测的输入反馈回去。这不是魔法,是技术:同一套操作,循环百万次。
下图总结了一个句子在模型内部从文本输入到选择下一个 token 的完整路径,同时也基本上是本系列接下来各阶段的路线图。

图中每个矩形在系列后续进程中都会独立成为一个阶段,每个阶段各有自己的测试和实现:Tokenizer(第 2 阶段)、Embedding 和位置 Embedding(第 3 和第 4 阶段)、自注意力和多头注意力(第 5 和第 6 阶段)、前馈网络(第 7 阶段),如此递进直到文本生成(第 13 阶段)。
我用作全局指南的一本参考书是 Sebastian Raschka 的《Build a Large Language Model (From Scratch)》。这是少数几本将以手工方式构建 GPT 本身作为独立教学目标的资料,而不是把它当作一个可抛弃的学术练习来对待。后续系列中每当某个设计决策需要比一篇文章所能容纳的更深入的理论背景时,我都会再次引用它。
在深入第 2 阶段(Tokenizer,也是下一篇文章的主题)之前,值得记录一下我早期做出的一个决定,它会在整个系列中间接地反复出现:不是所有东西都需要从零发明。
这个项目的第 1 阶段是构建一个小型数学库(向量、矩阵、点积、矩阵乘法、转置、基础统计)。它是一切其他东西的根基。我甚至考虑过是否也要从零实现这个库,但最终决定为这一层使用一个外部库(这里是 EJML)。
我的判断标准很简单:如果操作是纯数学的(加法、矩阵乘法、转置),可以从一个成熟且经过测试的库获取。一旦某个操作携带了神经网络语义(梯度、某层的前向或反向),就需要由我自己来写,逐行理解。从零发明矩阵乘法不会让我学到任何关于 Transformer 的东西;但从零实现自注意力可以。
由此诞生了 Tensor,这个类支撑着整个项目。在实践中,它是对 EJML 矩阵的一层薄封装,每个批次元素代表一个数据项。它知道如何做加法、按因子乘法、矩阵乘法、转置、计算每行的均值和方差。基本上就是后续阶段所需的最少数学词汇量,让它们可以流畅运行而不被数学细节卡住。整个基础都是用 TDD 方式逐个周期构建的,这一点会反复出现:MiniGPT 的每个组件(从 Tensor 到训练好的模型)都诞生于一个在实现代码出现之前就先存在的、处于失败状态的测试。
下一篇文章将介绍 Tokenizer。这是项目第一次从通用数学变成真正与语言模型相关的东西的阶段:文本变成数字的那一刻,词汇表的最初决策开始塑造模型之后能够(或无法)表达的一切。
接下来的几周我会陆续发布这个系列,每周一篇文章,对应一个阶段。