在一台 1982 年发布的 Commodore 64 上运行真实的 Transformer 模型 —— 这不再是概念验证,而是已经实现的工程壮举。Soul Player C64 项目在仅 25,000 个参数的约束下,将 ChatGPT、Claude 等大模型的核心架构移植到了这台只有 1MHz 主频和 64KB 内存的复古电脑上。本文深入解析其硬件约束、内存布局与极限优化策略,为嵌入式 AI 推理提供可复用的技术路径。
硬件基础:Commodore 64 的残酷现实
Commodore 64 的核心是 MOS 6510 处理器,本质上是 6502 的改进版本,主频固定在 0.985MHz(PAL 制式为 0.985MHz,NTSC 为 1.023MHz)。这个数字在今天看来微不足道,但更严峻的挑战在于处理器的指令集特性:它没有硬件乘法单元,所有数学运算必须通过移位和加法组合实现。更重要的是,6502 是 8 位处理器,每次只能处理一个字节的数据。
内存方面,64KB 的地址空间看似充裕,但需要分配给多个关键区域。VIC-II 视频显示控制器占用 $ D000-$ DFFF 的 I/O 区域,SID 声音芯片同样映射于此,剩余的实际可用内存不超过 38KB 左右。操作系统和 BASIC 解释器还要占用约 10KB 的起始区域,这意味着应用程序的实际可用空间极为有限。
在这样的硬件上运行 Transformer 模型,唯一的出路是将工程优化做到极致。每一字节的内存使用、每一个时钟周期的计算,都需要精确规划。
架构选择:25K 参数的核心约束
项目最终采用了 2 层解码器 - only Transformer 架构,配合 4 个注意力头(每个 8 维)和 32 维嵌入向量,前馈网络隐藏层维度为 64。这一选择并非随意,而是经过深思熟虑的参数权衡。
参数量的计算可以直观理解:嵌入层需要 32×128 = 4096 个参数,两层 Transformer 各需注意力和前馈网络权重。以单层注意力机制为例:Q、K、V 三个投影矩阵各需要 32×32 = 1024 个参数,加上输出投影的 1024 个,注意力机制总计约 4096 个参数。前馈网络采用两层结构(32→64→32),需要 32×64 + 64×32 = 4096 个参数。加上两层归一化和输出层,总计约 25,000 个参数。
这个规模恰好满足两个关键约束:参数量(约 25KB)能够 fit 进 Commodore 64 的内存,同时模型容量足以学习基本的对话模式。项目明确指出,25K 参数相比 GPT-4 等模型差距约 7000 万倍,模型不会产生连贯的长文本 —— 这本身就是工程可行性验证的目标。
内存布局:38KB 的精密分区
内存是嵌入式部署的核心瓶颈。项目的内存映射经过精密计算,将 38KB 可用空间划分为三个主要区域:
代码与分词器表占用 $0801 至 $20FF 区间,合计约 6KB。这部分包含手写的 6502 汇编例程和 BPE 分词器查找表。分词器采用 128 个词元的词汇表,包含 4 个特殊标记、34 个字符 / 标点以及 90 个 BPE 合并结果。选择 128 这个数值是因为它恰好是一个字节能表示的范围,便于索引和存储。
权重参数区从 $2100 延伸到 $85A0,占用 25.3KB。这部分存储所有 int8 量化后的模型权重,包括嵌入矩阵、两层 Transformer 的注意力权重和前馈网络权重。每个权重占用一个字节,整个 25KB 空间被填满但仍有裕量。
激活缓冲区位于 $8600 至 $9D00,共 5.8KB。这里存放推理过程中的中间计算结果,包括注意力分数矩阵、softmax 输出和前馈网络的激活值。20 个词元的上下文窗口意味着注意力矩阵需要 4×20×20 = 1600 个 int16 条目,加上其他临时变量,5.8KB 的预算相当紧张。
剩余的 $ C000 至 $ C3FF(1KB)用作输入词元缓冲、临时计算区和堆栈空间。
定点数运算:Q8.8 格式的精度权衡
6502 处理器没有浮点数单元,甚至连乘法指令都没有。所有数学运算必须使用整数,并通过移位模拟定点数乘法。项目采用 Q8.8 固定 - point 格式,即 16 位整数中低 8 位表示小数部分。
这种格式的优势在于:两个 Q8.8 数相乘后得到 Q16.16 结果,只需右移 8 位即可恢复到 Q8.8。在 6502 上,移位操作比乘法快得多 —— 一次左移或右移只消耗 2 个时钟周期,而乘法需要多次移位和加法的组合。
权重采用 int8 量化,使用 per-tensor 的 2 的幂次缩放(power-of-2 shift)。相比浮点数,int8 大幅节省存储空间,同时移位操作可以快速完成缩放。训练过程中使用量化感知训练(QAT),通过 FakeQuantI8 引入量化噪声,迫使模型学习具有更宽 logit margins 的参数,从而在 int8 量化后仍能保持较好的性能。
偏置项在导出前预先缩放为 int16,直接加到 matmul 累加器上,避免运行时进行额外的缩放计算。
Softmax 查找表:14 位归一化的关键修复
整数 softmax 是整个项目最难的部分之一。标准 softmax 公式为 exp (x_i) / Σexp (x_j),但在整数运算中没有 exp 函数。项目使用 128 项的指数查找表(LUT),通过查表近似计算 exp 值。
关键的技术突破在于注意力分数的归一化。最初使用 17 位移位(对应除以 2^17),但这会导致动态范围不足 —— 查询表无法产生有意义的注意力权重分布。原因在于:32 维嵌入的点积结果范围较大,直接查表会使得所有输入都落在查询表的饱和区域或下溢区域。
项目发现,将归一化改为 14 位移位(即除以 2^14)后,128 项的 exp 查找表获得了足够的动态范围来区分不同的注意力权重。这一 14 vs 17 的差异看似微小,却是让整数注意力真正工作的核心修复。没有这个修复,整数注意力在所有位置上都会产生几乎均匀的分布,使模型变成 “盲视”。
手写 6502 汇编:每条指令都经过优化
所有核心计算例程都用手写 6502 汇编实现,而非使用高级语言编译。这是因为编译器生成的代码在内存使用和执行效率上都无法满足严格要求。
矩阵 - 向量乘法(matvec)是最频繁使用的例程。由于没有乘法指令,需要通过移位和加法组合实现。对于 int8×int8→int16 的运算,6502 先将一个操作数加载到累加器,然后对另一个操作数逐位检查,根据位值决定是否将部分积加到结果寄存器。整个过程极其繁琐,但这是复古硬件上唯一的可行路径。
RMSNorm(均方根归一化)需要在 6502 上实现整数平方根和除法。项目使用迭代法计算平方根,每次迭代逼近真实值,直到相邻两次结果相等或达到最大迭代次数。整数除法同样采用迭代减法商算法。这些操作都是计算密集型,在 1MHz 主频上运行极为缓慢 —— 这也解释了为什么每个词元需要约 60 秒的生成时间。
每个注意力头并行处理 8 维向量,多头注意力通过分别计算 4 个头的输出然后拼接实现。输出投影和前馈网络采用 ReLU 激活函数,这是嵌入式场景中的常见选择,计算简单且不需要指数运算。
训练策略:QAT 与整数验证
项目使用量化感知训练(QAT)来确保模型能够适应 int8 推理。训练过程中,权重通过 FakeQuantI8 进行伪量化,使用连续的浮点缩放和直通梯度估计(STE)。训练时的连续缩放与推理时的 2 的幂次缩放之间存在不匹配,这种 “量化间隙” 反而被用作隐式噪声,迫使模型学习更鲁棒的权重分布。
另一个关键技巧是标签平滑(0.15)。这防止了 logit 分布过于尖锐 —— 在 int8 算术下,过度尖锐的分布会导致相邻词元的 logit 差异被量化误差淹没。
训练过程中,每 500 个 epoch 会同时显示 float 和 int8 两种推理输出,让开发者直观看到模型学到了什么以及 C64 实际会产出什么。最佳 checkpoint 基于 int8 的 argmax 准确率而非 float 损失来选择,这是确保最终部署效果的关键决策。
可落地的工程参数
对于在类似极端受限硬件上部署 Transformer 的场景,以下参数清单可作为参考起点:
模型架构方面,词元嵌入维度建议选择 32 或 64,过大则内存和计算难以承受;注意力头数设为 4 至 8,每头维度 8 至 16;前馈网络隐藏层维度设为嵌入维度的 2 至 4 倍;层数从 1 至 3 开始尝试,2 层是 Commodore 64 验证过的可行值。
内存布局方面,总参数量应控制在可用 RAM 的 50% 以内,为激活值和代码预留空间;上下文窗口建议不超过 32 词元,每增加一倍内存消耗翻倍;使用 per-tensor 量化而非 per-channel,以降低元数据开销。
数值格式方面,激活值推荐 Q8.8 格式,权重使用 int8+shift,查找表大小设为 2 的幂次(64/128/256),softmax 输入归一化需要实际测试调整而非理论推导。
推理性能方面,预计每词元生成需要 30 秒至数分钟,具体取决于硬件主频和模型规模;建议实现流式输出并配合视觉 / 音频反馈,让用户感知推理正在进行。
小结
Soul Player C64 项目证明了 Transformer 架构在极端受限环境下的可行性。25K 参数、Q8.8 定点运算、手写 6502 汇编、128 项 exp 查找表、14 位归一化修正 —— 这些工程决策共同构成了在 1MHz 处理器上运行真实神经网络的完整技术路径。虽然模型的 “智能” 程度有限,但核心架构的工程可行性已经得到验证。这种极限优化思维,对于任何需要在边缘设备或复古硬件上部署 AI 能力的场景,都具有重要的参考价值。