在 Linux eBPF 内核里跑语言模型:Qwen3-0.6B 的一次完整前向实验
研究者把 Qwen3-0.6B 的 28 层解码器全部放入 Linux eBPF 程序,在内核中完成一次前向推理并采样下…
一项名为 qwen3-ebpf 的原型实验,将通义千问 Qwen3-0.6B 的全部 28 层 Transformer 解码器放入 Linux eBPF 程序,在内核态完成一次完整的前向推理、词汇打分并选出下一个 token,并在 BPF KV map 中维护键值对供后续位置复用。这一实现证明了经过验证器(verifier)的 eBPF 程序确实可以承担真实语言模型的数值计算,但代价同样清晰:在测试主机上生成单个 token 仍需约 1.2 秒,整体并非 CPU 或 GPU 推理引擎的替代方案。
实验如何把模型拆进 eBPF
模型本身无法直接接收文本,需要先经过分词器转为整数 ID,再查表得到嵌入向量,经 28 层解码器变换后,对 151,936 个词表位置分别打分,取最高分得到下一个 token。实验中,这套流程被切成由 C 代码与多个有界 BPF 算子交替执行的序列:
- C 侧负责分词、加载 BF16 权重、嵌入向量,并按模型顺序调度 BPF 程序。
- 每个 BPF 算子处理一个受限步骤,例如 RMSNorm、Q/K/V 矩阵乘法、RoPE 旋转、因果注意力、输出投影、SiLU MLP、最终归一化与 argmax 等。
- 注意力程序读写 BPF KV map,记录已经生成的 K/V 向量,以便后续 token 直接复用。
矩阵算子每次最多处理 128 行,单次调用仍可能触发大量内核条目。运行入口是 bpf_prog_test_run_opts,并非把过滤器挂到真实网卡上,因此这只是一个测试态的内核前向,不是一个常驻的模型服务。
为什么必须切分成小算子
eBPF 程序必须通过 Linux 内核验证器,证明执行路径与内存访问都有界。实验为此做了一系列取舍:
- 权重与激活改用定点整数而非 BF16 浮点:激活为 Q16,矩阵权重为 Q24,归一化尺度为 Q20。
- SiLU 与注意力 softmax 使用整数近似;RoPE 所需的三角函数值由 C 预先计算,再交给 BPF 做旋转。
- 关键循环使用
bpf_loop,单次矩阵调用最多处理 128 行;其他调用覆盖全部 24 个 Q/K 归一化头、16 个查询头的有限注意力历史块,或 256 个历史位置。 - 新生成的 K/V 对由注意力 BPF 程序写入 KV map,避免重复穿越用户态/内核态。
经过这些改造,单次单 token 运行大约产生 4,169 次 bpf 调用,相比早期小批量版本显著下降。两次失败的尝试也清晰划出了边界:单块的 RMSNorm 在测试内核上超出验证器指令处理预算,需要重构成有界回调;将 BF16 到 Q24 的转换直接放进 3,072 列的 BPF 循环会触发验证器复杂度错误。这些结论针对 Linux 6.17 arm64 上特定程序,并不构成对更大 BPF 程序的普遍否定。
权重放在哪里:默认路径与 arena 路径
官方 Qwen3-0.6B 的 BF16 Safetensors 文件约 1.5 GB,由 C 以只读方式映射。默认推理路径先将当前激活的矩阵行转换为 Q24,再拷贝到内存映射的 BPF work map。如果一次性把所有矩阵预转为 Q24,文件会膨胀到约 3.0 GB,且在一台可用内存约 4.6 GiB 的主机上跑得更慢,权重体积翻倍并未消除瓶颈。
项目额外提供一条「arena」路径,仅把当前 128 行 BF16 矩阵拷贝进约 2 MiB 的 BPF arena,并附带一张 65,536 项查找表,把每个 BF16 位模式映射为默认路径使用的 Q24 整数,BPF 再据此计算点积。这样,活跃矩阵批次的权重转换被移出 C,又不需要把整模型放进内核可见内存。在 token ID 0 与「Hello, world!」两 token 续写的测试上,arena 路径与默认路径返回完全一致的 token ID 与逐词表 logit;128 行真实 Q 投影也与默认路径精确匹配。不过该改动并未带来速度提升:默认路径六次单 token 测量为 1.227 / 1.190 / 1.251 秒,arena 路径为 1.220 / 1.228 / 1.234 秒,两者基本持平。
一个边界明确的内核推理原型
qwen3-ebpf 展示了 eBPF 在受限模型规模下承担语言模型前向的能力,也如实记录了它不能做的事:单 token 1.2 秒的延迟、验证器对程序规模的硬约束、对定点量化的依赖,以及 INT4、arena 内存等仍待权衡的开放问题。所谓「内核内推理」,指的是前向算术与 token 选择都发生在已验证的 BPF 程序中;并不意味着文本提示进入内核、整句输出从一个调用中涌现。对于关心 eBPF 能力边界与极小模型部署的研究者与内核开发者而言,这是一次边界清晰、可复现的工程实验。
