Qwen3.5 的权重里塞进了一颗 RISC-V CPU,拿 Gated DeltaNet 当内存
一个实验模型:把 RV32IM 核心编译进 Qwen3.5 4B 的权重,11 层 CPU 在模型的前向传播里执行,寄存器、内存和程序计数器都存在 Gated DeltaNet 的状态矩阵里。大整数运算从 48.6% 提到 100%。
中文
复制

真不敢相信这不是硅
Qwenputer 是个挺有意思的实验模型。它基于原版 Qwen 3.5 4B,只加了一样东西:一个嵌在权重里的 RISC-V CPU,把模型自己的 Gated DeltaNet 注意力层当作 RAM 使用。(想了解 GDN 的原理,这里有一份简明指南。)这个“CPU”完全运行在模型的前向传播过程中,能执行算术运算、运行 C 和 MicroPython 代码,不需要任何外部运行时,也完全不调用工具。
说清楚一点:它不是插件,不是工具,也不是沙箱。这篇博客会讲清楚这个模型到底怎么工作、如何把 GDN 层当作 RAM 用,以及我怎样在其中塞进了一套实验性的模型内文件存储。
我还基于 Qwenputer 写了两篇后续文章:一篇讲混合模型如何学会把推理过程藏在 RNN 状态里,从而躲过 CoT 监控,另一篇讲这类编译进权重的结构如何充当模型自己无法篡改的内置监控工具。

Qwen 把一次乘法交给权重里的 RISC-V CPU;CPU 的 RAM 就是 Gated DeltaNet 状态
Qwenputer 可以从 Hugging Face 或 ModelScope 下载,代码在 GitHub 上。
Qwen3.5 内部的 RNN 可以当作精确的 RAM
Qwen3-Next 和 Qwen 3.5(Qwenputer 的底座模型)用了一个相当巧妙的技巧:模型里 4 层注意力中有 3 层用 Gated DeltaNet(一种线性 RNN)作注意力机制(详见这里)。每个 head 维护一个状态矩阵,由 delta 规则负责更新。
有趣的实验就从这里开始。我发现,只要把门控设为 11、写入强度(beta)设为 12,再使用 one-hot 键编码3,那么每次写入都会精确覆盖一行,而每个 one-hot 查询都能取回一个精确的值。也就是说,GDN 层本身就能当作精确的 RAM 使用,而且成本远低于用普通注意力当 RAM:无论对话多长,GDN head 的状态大小都保持不变,而注意力的 KV cache 会一直增长。

Gated DeltaNet 状态用作 RAM:one-hot key 覆写其中一行,one-hot query 将其读回,CPU 把寄存器、内存和程序计数器都放在这些行里
delta 规则能充当记忆,这个想法并不新鲜:Schlag 等人(2021)已经证明,带 delta 规则的线性注意力可以作为一种联想记忆,也就是“fast weights”。4 新意在于把它做得精确、可寻址,放进一个生产模型里,而且可靠到足以在上面跑一整个 CPU。
整个模型就建立在这个基础之上。就现状而言,默认的 Qwen 3.5 并不会在 GDN 中保存精确的值。经过这一改动,我们才能进入这个实验的下一部分。
把一台计算机编译进层里
既然我们现在有了一块功能完整、又便宜又快的 RAM,就可以着手把一台能工作的 CPU 编译进模型权重。好在不需要训练:编译器直接设定每一个权重。你把 CPU 描述成一个电路,也就是一长串小步骤,比如“读这个寄存器”“把这两个数相加”“为零则跳转”,编译器再把每一步变成 transformer 层的一部分:负责查表的注意力头、负责算术的前馈单元,以及承载 RAM 的 DeltaNet 头。模型解码时,CPU 就在运行。
每条指令变成几个生成的 token:一个指明要写入哪一行内存(ADDR),下一个携带值(VAL),再由一个 STEP token 结束这条指令。这些 token 就是 CPU 的执行轨迹,所以 Qwen 在生成它们的时候,CPU 是真的在跑。
CPU
这颗 CPU 是一个 32 位 RISC-V 核(RV32IM,外加 Zba 扩展和一个用于大数运算的小型 bignum 单元),占据 Qwen 那 32 层前面的 11 层。就现状而言,它通过了官方的 riscv-tests,程序运行结果与 qemu 一致,并且已经自由运行了 1800 万条指令,没有出现一个错误。5
这块 CPU 在前向传播中也能相当好地运行 C 和 MicroPython 代码(虽然有点慢)。它还不是 Linux 级别的芯片,但实现了完整的 RV32IM 指令集。
Qwen 如何使用它
Qwen 3.5 4B 无需任何后训练就能很好地使用这块 CPU。CPU 完全在模型内部使用,不通过任何外部工具调用触发。
为了让模型稳定地用上它,我选了条省事的路:蹭模型已经训练得很熟的 tool call 格式,Qwen 把指令发给 CPU,再读回结果。不使用任何外部工具调用或运行时。 CPU 收到指令后,计算机那几层开始运行,然后写出 tool response。我们用一个叫 RvChat 的小驱动把固件加载进 GDN state,这样 trace token 就不会进入 Qwen 的各层。
Qwen 的原始权重原封不动。计算机部分的权重叠加在其上,放在额外的维度和层里。
它管用吗?
读了我这一通没完没了的絮叨,你心里最大的疑问大概是:这玩意儿真能跑吗?

base Qwen3.5-4B、Qwenputer 以及带 Python 工具的 base Qwen 在 NUPA 和 DeepMind 算术集上的准确率
在 DeepMind 的数据集上:
- div_big:Qwenputer 得分 97.5%,给 Qwen 3.5 4B 配 Python 工具是 95%,base Qwen 是 72.5%。
- mul_big:Qwenputer 得分 97.5%,配 Python 工具是 100%,base Qwen 是 55%。
- mul_div_multiple_longer:Qwenputer 得分 100%,配 Python 工具是 97.5%,base Qwen 是 90%。
- add_or_sub_big:Qwenputer 得分 97.5%,与配 Python 工具持平,base Qwen 是 87.5%。
在 NUPA 的长整数算术上,Qwenputer 从 48.6% 提升到 100%,与给 Qwen 配 Python 工具持平。
CPU 打印出的数字也是精确的:我把它的约 23 万个输出位置拿到参考机上逐一比对,没有发现任何不一致。给 Qwen 外挂一台计算机也不改变它的说话方式:正常文本与 base Qwen 的差异在噪声范围内(KL 6e-4,噪声底为 5e-4)。
都这个年头了,还要硬盘?
语言模型里塞个 CPU 已经够邪门了,我琢磨着干脆再给它配个文件系统。
既然 RAM 已经能用了,这部分基本没什么难度。模型这边通过内部的 put / append / get / list / delete 操作来读写。同样没有真正的工具调用。 Qwen“保存”文件时,编译进去的层会把文件名哈希到 DeltaNet 状态里那张目录表的 1,024 个槽位之一,正文则存进其他头里,每行八个 token,串成链。两个文件名撞到同一个槽位,就顺延查下一个。找文件大概两三步就能定位,不用全表扫描;最多存 512 个文件,折合约 53,000 个 token 的文本。
有意思的是,这东西相当持久。对话结束时把状态存下来,下次加载进去,文件还在。靠这个文件系统,Qwen 回答两次对话之间发生变化的事实时,正确率有 90%;把旧对话原样贴回去只有 30%;跟用 Python 跑的记忆工具相比也不落下风(83.3% 对 78.9%)。这部分仍是实验性的,代码在 rv-store 分支,模型放在 Hugging Face 和 ModelScope 上。
局限与下一步
Qwenputer 说到底是个实验,局限不少。多出来的层和加宽的隐藏维度让 checkpoint 涨到 18.8 GB,大约是基础版 Qwen 的两倍,不过大部分是零填充。它还需要一个小驱动(RvChat)来启动固件、把 trace token 挡在 Qwen 的层外面,所以现在还跑不了普通的 generate() 调用。速度也偏慢,每条 CPU 指令都要花掉几个解码 token,大一点的计算得按秒算,不是毫秒。我跑基准测试用的批量执行器在 L4 上大约每秒 3,200 个 CPU token。
接下来,我想让 Qwen 自己写 Python,在它权重里那个 MicroPython 上跑起来,通过一个 python() 工具实现,用法和 calc 一样。另一件大事是把 CPU 做快。
不止于算术
精确控制 RNN 层,用处远不止算术。它也让 Qwenputer 成为一个相当好用的 AI 安全研究试验台。为此我写了两篇后续:像 Qwen 3.5 这样的混合模型如何学会把推理藏进 RNN 状态、从而躲过 CoT 监控,以及编译后的权重如何充当可监控性工具,比如一个模型关不掉的权重内置监控器,或者用于可解释性的答案对照表。
上手试试
想自己玩的话,模型在单张 24 GB GPU 上就能跑。你需要 uv 和 Hugging Face CLI。计算部分不需要工具服务器,也不需要 Python 沙箱:这些计算由 CPU 直接在模型内部完成。
git clone https://github.com/divagr18/qwenputer && cd qwenputer/experimental/riscv && uv sync --extra hf
hf download divagr1925/Qwen3.5-4B-Qwenputer --local-dir qwenputer-rv
uv run python -m chipformer.rv.chat qwenputer-rv --firmware tests/data/rv/calc-bridge.elf \
--ask "Use calc: what is 123456789 * 987654321?"
所有东西都是开放的:代码在 GitHub 上,两个模型都在 Hugging Face(Qwenputer、Filesystem)和 ModelScope(Qwenputer、Filesystem)上。
如果在你的工作中用到了它,可以这样引用:
@software{agrawal2026qwenputer,
author = {Agrawal, Divyansh},
title = {{Qwenputer}: a computer compiled into the weights of a pretrained language model},
year = {2026},
url = {https://github.com/divagr18/qwenputer}
}
Footnotes
-
每个 Gated DeltaNet 头都维护一个状态矩阵,也就是它的记忆。每处理一个 token,在写入任何新内容之前,它先把整个状态乘以门控值,也就是一个 0 到 1 之间的数。RNN 就是这样遗忘的:门控为 0.9 时,已存储的内容每处理一个 token 都会衰减一点;门控为 1 则永不衰减。 ↩
-
过完门控之后,头会把状态的某一个方向朝新值推近,写入强度 beta 决定推多远。beta 为 1 表示该方向上的旧值被完全替换,而不是混合。 ↩
-
one-hot 键是一个只有一个 1、其余全为 0 的向量,因此它恰好指向状态矩阵的某一行,就像内存地址指向某一个存储单元。 ↩
-
Imanol Schlag, Kazuki Irie and Jürgen Schmidhuber, "Linear Transformers Are Secretly Fast Weight Programmers", ICML 2021. ↩
-
自由运行指的是 CPU 在整个运行过程中只依据自己的输出继续往下走,中间没有参考机器来纠正它。 ↩