“你好。”
“HI”
“你是机器人吗?”
“YES”
“你会做梦吗?”
“MAYBE”
这并非来自某个现代AI助手的对话,而是运行在1976年Z80处理器上的一个“微型语言模型”与人类的交互。更令人惊讶的是,整个程序仅占用40KB空间,甚至装不下一张低分辨率图片,却能在一台内存仅64KB、主频4MHz的古董电脑上,基于CP/M系统流畅运行并实现“聊天”功能。
听起来像是技术极客的浪漫幻想,但现实更加硬核:这个名为Z80-μLM(读作“Z80-micro-LM”)的项目,由开发者HarryR打造。它极致运用了“量化感知训练”(QAT)、2比特权重压缩、Z80汇编优化以及trigram哈希编码等技术,最终成功在8位机上实现了一个能够自洽对话的AI。
今天,我们就来深入拆解这个“复古AI”的底层逻辑,看看它如何在算力和内存双重受限的绝境中,通过数学、工程和一点幽默感,完成这项看似不可能的任务。
一、为什么要在 Z80 上跑 AI?因为“能”本身就是一种浪漫
许多人的第一反应是:“图什么?”
Z80是什么?它是1976年由Zilog公司推出的8位微处理器,曾广泛用于早期的个人电脑(如TRS-80)、游戏机(如ColecoVision)和工业控制器。其主频通常在2–8MHz之间,寄存器只有8位宽(虽然支持16位寄存器对),没有浮点单元,连乘法运算都需要软件模拟。
在这样的硬件上运行AI,好比让自行车参加F1比赛——并非为了夺冠,而是为了证明“自行车也能驶上赛道”。
但HarryR的动机非常纯粹:“我们能把语言模型做多小,同时保留一点‘人格’?”
他旨在打造一个:
- 能在老式计算机上本地运行
- 不依赖网络或云服务
- 可以轻松训练和分发
- 且略带“性格”的AI
于是,Z80-μLM应运而生。它不追求通用智能,也不试图生成长篇大论,而是专注于短输入 → 短输出的交互模式,例如问答、猜谜和寒暄。它的目标并非通过图灵测试,而是让你在绿色荧光屏前会心一笑。
这种“小而美”的思路,恰恰是对当前大模型参数膨胀趋势的一种反叛——当业界忙于堆砌参数、比拼算力时,有人选择回归原点,追问一句:“最简可行的AI,究竟应该是什么模样?”
二、2 比特量化:把神经网络压进火柴盒
要让AI在Z80上运行,首要挑战便是模型大小。
现代语言模型动辄几十GB,即使最小的TinyLLaMA也有几百MB。而Z80的可用内存(CP/M系统的TPA区)只有64KB,其中还需预留空间给程序代码、栈和I/O缓冲区。真正留给模型的空间,可能不足50KB。
解决方案是什么?答案是:极端量化。
Z80-μLM采用了2比特权重量化。这意味着每个神经网络权重只能取四个值:-2, -1, 0, +1。
没错——不是8比特(256级),也不是4比特(16级),而是2比特(仅4级)!
2 比特怎么存?
Z80是8位CPU,一个字节包含8位。既然每个权重只需2位,就可以将4个权重打包进1个字节:
字节: [w3][w2][w1][w0] → 每个wi占2位
例如,权重序列 +1, 0, -1, -2 对应的二进制映射为:
- +1 →
11(实际映射为3)
- 0 →
10(映射为2)
- -1 →
01(映射为1)
- -2 →
00(映射为0)
因此打包后的字节是:00 01 10 11 = 0x1B(十进制27)。
在Z80汇编中,解包这段数据仅需几条指令:
ld a, (PACKED) ; 从内存加载打包字节
and 03h ; 取最低2位(w0)
sub 2 ; 映射:0→-2, 1→-1, 2→0, 3→+1
ld (WEIGHT), a ; 存入权重变量
随后通过两次 rrca(循环右移)将下一个权重移至低位,重复操作即可。
这种设计极大节省了存储空间。假设一个隐藏层有256个神经元,全连接到下一层192个神经元,权重矩阵原本需要 256×192 = 49,152 个浮点数(约192KB)。但使用2比特量化后,仅需 49,152 / 4 = 12,288 字节,即12KB——压缩率高达16倍!
当然,代价是精度损失。但神奇的是,在短文本生成任务中,这种粗粒度反而带来了一种“模糊但合理”的响应风格,例如对“hello”和“hi”给出相似回答,对“are you bot”和“r u robot”都能准确识别。
三、没有浮点数?那就用整数+定点数硬刚
Z80没有浮点运算单元,连乘法都需依赖循环加法实现。那么神经网络中的 weight × activation 该如何计算?
答案是:全整数运算 + 定点缩放。
Z80-μLM的所有计算都基于16位有符号整数。激活值(activations)和累加器(accumulators)均使用16位寄存器对(如HL、DE)存储,确保在累加大量输入时不发生溢出。
举例来说:假设某层有256个输入,每个激活值最大为+127(8位有符号),权重最大为+1,那么累加和最大为 256 × 127 = 32,512,仍在16位有符号整数范围(-32768 ~ +32767)内。
但问题随之而来:如果权重为+1,激活为+127,乘积为+127;但如果权重为-2,激活为-100,乘积则为+200——这看似没问题。然而一旦层数加深,数值会指数级增长,很快导致溢出。
解决方案:每层输出后右移2位(相当于除以4)。
在Z80汇编中,这通过算术右移(SRA)实现:
sra h ; 高字节算术右移(保留符号位)
rr l ; 低字节带进位右移
sra h
rr l ; 总共右移2位 → 除以4
这种“缩放”操作相当于隐式的归一化,防止数值爆炸。虽然在2比特权重的限制下,精度损失几乎可以忽略。
更巧妙的是,这种设计完全避开了浮点数,所有运算都是Z80原生支持的整数操作,反而提升了执行速度。
四、输入不是“词”,而是“桶”:trigram 哈希编码的魔法
现代大模型通过Tokenization将文本切分为词或子词,再映射为向量。但在Z80上,连词表都存储不下。
Z80-μLM另辟蹊径:用trigram哈希将输入文本映射到128个“桶”中。
什么是trigram?即连续三个字符。例如,“hello”会被拆分为:
每个trigram通过一个哈希函数(如简单的多项式滚动哈希)映射到0–127之间的整数,对应128个桶中的一个。每次出现,该桶计数加1。
最终,整个输入被表示为一个128维的整数向量,每个维度代表某个trigram模式的出现频率。
这种编码有什么好处?
-
词序不变性:
“hello there” 和 “there hello” 产生的trigram集合几乎相同(忽略边界),因此哈希后桶分布一致。模型无法区分语序,但对短句影响不大。
-
抗拼写错误:
“helo ther” 缺少一个'l',但大部分trigram仍能匹配,桶分布相似,模型依然能够理解。
-
极度节省内存:
128个整数,每个用1字节存储(最大255次出现),总共仅需128字节!远小于词嵌入表。
-
无需预训练词表:
任何字符组合都能被处理,包括表情符号、乱码,甚至二进制数据(尽管无意义)。
当然,缺点也很明显:长句会“混桶”。例如“open the door and turn on the lights”和“turn on the door and open the lights”会产生高度重叠的桶分布,模型无法区分。但这正是设计上的取舍——它只针对短输入进行优化。
五、Z80 汇编:手搓神经网络内核
模型再小,也需要执行推理。Z80-μLM的推理核心是用纯Z80汇编编写的,因为C编译器生成的代码过于臃肿,根本无法塞进40KB空间。
让我们看看最关键的乘加循环(MAC loop):
; 假设 DE = activation (16位)
; ACC = 累加器 (16位,存于内存)
; PACKED = 当前打包权重字节
MULADD:
or a ; 清零标志位
jr z, DONE ; 如果权重=0,跳过
jp m, NEG ; 如果权重<0,跳转到减法分支
; 权重=+1:ACC += DE
ld hl, (ACC)
add hl, de
ld (ACC), hl
ret
NEG:
cp 0FFh ; 检查是否为-1(0xFF)
jr z, NEG1 ; 是则跳转
; 权重=-2:ACC -= DE * 2
ld hl, (ACC)
sbc hl, de ; 带借位减(第一次)
sbc hl, de ; 第二次
ld (ACC), hl
ret
NEG1:
; 权重=-1:ACC -= DE
ld hl, (ACC)
sbc hl, de
ld (ACC), hl
ret
DONE:
ret
这段代码的精妙之处在于:
- 利用Z80的条件跳转避免不必要的计算
- 对
-1 和 -2 分别处理,避开通用乘法
- 全程使用16位寄存器对,最大化硬件利用率
整个网络推理就是重复执行这个循环数万次(每层神经元 × 输入维度)。在4MHz Z80上,生成一个字符大约需要1–2秒——速度虽慢,却完全可用。
模型虽小,训练过程却在现代机器上完成。
Z80-μLM提供了一套完整的Python工具链:
- 使用PyTorch定义网络结构(例如256→192→128→charset_size)
- 采用量化感知训练(QAT):在训练时模拟2比特权重的前向传播,让模型学会在这种约束下工作
- 训练数据可以是问答对、猜谜语,甚至利用Ollama或Claude API生成的合成数据
- 训练完成后,通过
buildz80com.py 脚本将权重、网络结构及聊天UI打包成CP/M .COM文件
.COM是CP/M系统中最简单的可执行格式:没有头部,从地址0x100开始直接运行机器码。Z80-μLM的整个程序(代码+权重+UI)被压缩进这个40KB的二进制文件中。
用户只需在CP/M命令行输入 CHAT,即可进入交互模式:
A> CHAT
> hi
HELLO
> what is your name
Z80
> are you smart
MAYBE
这种“训练在云端,运行在终端”的模式,完美实现了自托管、离线、无依赖的AI体验。
七、它能做什么?不能做什么?
它擅长:
- 短问答:例如“你好吗?”→“OK”
- 模糊匹配:接受拼写错误、同义改写
- 人格表达:通过有限词汇传递态度(如“WHY?”表示质疑)
- 教育演示:展示AI如何在极端受限环境下工作
它不擅长:
- 长上下文理解:没有记忆机制,每轮对话独立
- 语法解析:无法区分“把A给B”和“把B给A”的差异
- 创造性生成:输出仅限训练集中出现过的短语
- 多轮推理:例如“先A再B最后C”这类逻辑链条会失效
但它从未试图胜任这些任务。其核心哲学是:在限制中寻找优雅。
正如俳句仅用17音便能描绘四季;Z80-μLM仅凭40KB,也能传递一丝“智能”的幻觉。
八、启示:小模型的未来在哪里?
Z80-μLM看似是一个技术玩具,实则蕴含深刻启示。
在大模型军备竞赛的今天,我们是否忽视了效率、可解释性和部署灵活性?
- 边缘AI:未来的智能家居、传感器节点,可能只需这种“够用就好”的模型。
- 隐私保护:本地运行,数据不出设备。
- 可持续计算:Z80功耗不足1瓦,而训练一个大模型的碳排放堪比百辆汽车终身排放。
更重要的是,它提醒我们:AI的本质不是参数规模,而是解决问题的能力。
一个能在8位机上运行的模型,或许无法撰写论文、绘制图像或编程,但它能陪你闲聊两句,猜个谜语,甚至在你深夜调试代码时回应一句“TRY AGAIN”——这已足够。
结语:在绿色荧光屏前,与 1976 年的灵魂对话
Z80-μLM不是技术的终点,而是一面镜子。
它映照出我们对“智能”的执着,也展现了工程美学的极致:用最少的资源,达成最显著的效果。如果你对这类极限优化和开源项目感兴趣,欢迎在云栈社区与其他开发者交流探讨。
GitHub 项目参考
https://github.com/HarryR/z80ai