smolmaxxing:在小米电视盒子与 2013 款 iPad Air 上跑 LLM
I'm making LLMs work on small and old devices
作者开源 smolmaxxing 项目,通过自定义 kernel、内存优化和权重流式加载,让小米电视盒子 S(3rd Gen,约 1 GB 可用内存)运行 260K 到 16B 参数的模型,其中 Qwen3.5-2B 在真实对话中达 7.7 tok/s,Moon-Beam-8B-A1B 达 7.2 tok/s。
你身边的每台设备都比看上去更能干。电视盒子、旧手机、单板计算机和路由器都配有 CPU、内存和闪存,而它们一天中大部分时间都处于闲置状态。smolmaxxing 就是要释放这种能力:找出每台设备真正能运行的最大语言模型,再通过自定义内核、更聪明的内存使用和权重流式加载把它推得更远。每一项声明都在硬件本身上实测。
设备 #1 是小米盒子 S(第三代):Amlogic S7D,4× Cortex-A55 @ 2.5 GHz,1.9 GB 内存(约 1 GB 可用),eMMC 闪存,Android 14,未 root。在这个设备上,本仓库运行从 260 K 到 16 B 参数的模型:
- Qwen3.5-0.8B:16.8 tok/s(是原版 7.5 的 2.2 倍;于 11-05 晚间测得,见 §17)。
- Qwen3.5-2B:真实聊天中 7.7 tok/s。盒子的速度在一天内会漂移约 10%,因此每一步都连续回测:§16 给出 +11%,§17 又给出 +7%。
- 一个 8B 混合专家模型(Moon-Beam-8B-A1B):真实聊天中 7.2 tok/s,其专家按需从闪存分页,并提前一层预取(§19)。
- 一个稠密 1-bit 8B 模型(Bonsai-8B):真实聊天中 5.2 tok/s,从 1.2 提升而来:在“无头”模式下完全常驻,外加一个查找表内核(§19)。
- 一个 16B 混合专家模型(Ling-mini-2.0):真实聊天中 5.1 tok/s,在 600 词的回答中保持连贯,同样的专家分页器原样应用(§20)。规模是 Moon-Beam 的两倍,但每字节并不更好:在这个盒子上,只有模型本身也更好时,更大才有帮助。
- 一个稠密 9B 模型:0.27 tok/s,大部分权重从闪存流式加载。
设备 #2 是第一代 iPad Air(2013):Apple A7,2 核,NEON 但不支持 dotprod,1 GB 内存,iOS 12.5.7,已越狱,仅用 CPU。一台 13 年前的平板以 24-26 tok/s 运行 1.7B 参数模型(长对话中 18-22),4B 模型约 10 tok/s,8B 混合专家模型约 3.5 tok/s(用一半专家时 5,但有质量代价),16B 模型 2.6-4.5 tok/s,其专家从闪存分页,运行在其自带 Safari 的聊天页面中。见 设备 #2 上的结果。
每一步都在 EXPERIMENT.md 中逐实验记录(E1-E160)。
设备
| 设备 | 状态 |
|---|---|
| 小米盒子 S(第三代):Amlogic S7D,Cortex-A55,2 GB | ✅ 完成:260K → 16B 参数,8B 达 5-7 tok/s,16B 达 5 tok/s |
iPad Air(2013):Apple A7,2 核,1 GB,iOS 12.5.7,已越狱(ipad-air/) |
✅ 运行中:Bonsai-1.7B(1-bit)达 24-26 tok/s,长对话中 18-22;Bonsai-4B 约 10 tok/s;Moon-Beam-8B-A1B(MoE)约 3.5 tok/s;Ling-mini-2.0(16B MoE)2.6-4.5 tok/s;仅用 CPU |
| 更多电视盒子、手机、单板计算机、路由器…… | 🔜 即将推出 |
这些技术并不绑定于某一个盒子。1-bit 查找表内核只需要基础 NEON,正如 iPad 所示;任何带 dotprod 的 ARM 芯片都能用其他内核;任何模型大于内存的 Linux 或 Android 设备都能使用流式引擎。
排行榜
| 类别 | 最佳模型 | 首次运行 → 现在(tok/s) | 提升 | 位/字节 | 靠什么实现 | 下载 |
|---|---|---|---|---|---|---|
| 0.8B | Qwen3.5-0.8B | 7.5 → 16.8 基准 | ×2.2 | ≈1.00 | 全 Q4_K,填充 65K 头,fp16 DeltaNet 状态 | HF |
| 2B | Qwen3.5-2B | 0.1 → 7.7 聊天 | ×77 | 0.909 | 全 Q4_K,填充 65K 头,融合 DeltaNet | HF |
| 4B | Ternary-Bonsai-4B | 2.2 → 4.3 聊天 | ×2.0 | ≈0.965 | 三值权重存于 2-bit 字段,合并缩放 | HF |
| 8B 稠密 | Bonsai-8B(1-bit) | 1.21 → 5.2 chat | ×4.3 | 0.974 | 1-bit LUT kernel,在 headless 模式下完全常驻内存 | HF |
| 8B MoE | Moon-Beam-8B-A1B | 1.87 → 7.2 chat | ×3.9 | 0.996 | Q2_K 专家从 flash 分页加载,缓存感知路由,预取 | HF |
| 9B | Qwen3.5-9B | 0.16 → 0.27 chat | ×1.7 | 0.885 | 权重流式加载加上它自己的 MTP head | 重建(q9) |
| 16B MoE | Ling-mini-2.0 | 4.1 → 5.1 chat | ×1.2 | 1.054 | Moon-Beam 方案,未做改动 | HF |
“首次运行”指每个模型第一次在这台机器上运行时的表现:
- 0.8B:原版 Q4_K_M 文件。
- 2B:原版文件,因为放不进 RAM 而从 flash 流式加载。它第一个能放下的构建跑到了 4.8,所以从那时起提升是 ×1.6。
- 4B:原版文件,出现了抖动。
- 8B 稠密:最后 0.1 GB 从 flash 流式加载。
- 8B MoE:第一次运行专家分页器,没有路由偏置。
- 9B:流式加载。
- 16B:一开始就用 Moon-Beam 方案,所以提升很小。
在这台机器上,2B 是速度与质量的最佳平衡。Ling-mini-2.0 表明更大并不自动更好:它的体积是 Moon-Beam 的两倍,但每字节得分更差,运行也更慢。
我们构建的东西,按所针对的瓶颈分组(细节和数字见 What's in here):
| 瓶颈 | 创新 | 最大收益 |
|---|---|---|
| 计算(顺序执行的 A55,10 项) | 针对 vdotq_laneq 的 Q2_K 和三值重打包、1-bit 位平面、1-bit 查找表 kernel、2-bit 字段中的三值、带跳过阈值的 Q8_0 注意力、融合 Gated-DeltaNet、按 id / fp16 读取 DeltaNet 状态、快速 kernel 上的 LM head、引导式 matmul 调度 |
Q2_K 7.8 → 13.9 G 权重/秒;Bonsai-8B 3.77 → 5.1-5.4;4B 3.2 → 4.3;长回答不再使速度减半 |
| RAM(约 1 GB,5 项) | 剪枝 LM head、无损 1.875-bit 三值、headless 模式、无 fork 的内存保护、flash 上的重打包缓存 | 每个模型 −0.2 到 −0.5 GB;空闲 RAM ~1,000 → ~1,300 MB;Bonsai-8B 在任何 kernel 工作之前 1.2 → 3.6 |
| Flash(278 MB/s,5 项) | 带 O_DIRECT 的权重流式加载、flash 受限时的 MTP 推测、专家分页器、缓存感知路由、预门控预取 | 9B +69 %;专家未命中 13 % → ~2 %;Moon-Beam 4.4 → 7.2 |
| 输出质量(2 项) | 长回答退化测试、256 个 token 上 1.15 的重复惩罚 | 退化长回答 12/13 → 1/13 |
设备 #1 上的结果
质量是在固定 22 KB 文本上的英文困惑度,转换为 每字节比特数,以便不同分词器的模型公平比较(越低越好)。速度是在电视上的生成速度,通过带真实聊天请求的 llama-server(“chat”)或 llama-bench(“bench”)测量。
| 模型 | 机器上的大小 | 质量(比特/字节) | 生成 | 提示处理 | 备注 |
|---|---|---|---|---|---|
| stories260K (llama2.c) | 1 MB | 不适用 | ~650 tok/s | 不适用 | 第一个运行的东西(§1-8) |
| Gemma 3 270M Q4_K_M | 253 MB | 不适用 | 22 tok/s | 73 tok/s | |
| Qwen3.5-0.8B Q4_K_M(原版) | 497 MB | 不适用 | 7.5 bench | 28 tok/s | |
| Qwen3.5-0.8B,全 Q4_K + 65K head | 442 MiB(566 MB RSS) | ≈1.00* | 16.8 bench | 33 tok/s | 目前其质量下的最佳速度(§15-17) |
| Qwen3.5-2B,全 Q4_K + 65K head | 0.99 GB | 0.909 | 7.7 chat | 17.8 | 默认:整体最佳(§11、§16、§17) |
| Ternary-Bonsai-4B,合并缩放 + 2-bit 字段 | 1.03 GB | ≈0.965 | 4.3 chat(4.8 bench) | 9.6 | 最佳 4B:同一构建上曾是 3.2 chat / 7.0 prompt(§18) |
| Moon-Beam-8B-A1B(MoE),Q2_K 专家 + 60K head | 0.48 GB GGUF + 2.6 GB repack 缓存在闪存上,约 1.1 GB RSS | 0.996 | 7.2 聊天 | 不适用 | 最快的 8B:128 个专家,使用 6 个;专家分页器、缓存感知路由、预门控预取、针对长回答循环的重复惩罚(§19,无头模式) |
| Ling-mini-2.0(MoE,16.3 B),Q2_K 专家 + 60K 头 | 0.47 GB GGUF + 5.3 GB repack 缓存在闪存上,约 1.13 GB RSS | 1.054 | 5.1 聊天 | 不适用 | 可用速度下最大的模型:256 个 1 MB 的专家,使用 8 个,每层池 43 个,偏置 0.3(§20) |
| Bonsai-8B,1-bit,LUT 内核 | 0.96 GB,全部常驻 | 0.991(头部为 0.974) | 5.2 聊天(基准 5.1-5.4),约 900 token 上下文时为 4.0 | 5.8-6.1 | 最佳稠密 8B:无头模式,Q8_0 注意力(§19) |
| Bonsai-8B,1-bit + 紧凑缩放 | 0.84 GB + 0.12 GB 流式加载 | 0.991 | 1.21 聊天(基准 2.2) | 4.9 | §14,无头模式之前 |
| Ternary-Bonsai-8B | 0.89 GB + 0.80 GB 流式加载 | 0.919 | 0.31 基准 | 3.45 | §14 |
| Qwen3.5-9B UD-IQ2_XXS + MTP | 0.63 GB + 1.6 GB 流式加载 | 0.885 | 0.16 聊天,使用 MTP 时为 0.27 | 0.8 | 最佳质量;受闪存限制(§14) |
* 在剪枝头的位置上测量(1.3 % 的 token 落在其外),因此不完全可比;原版全词表 Q4_0 文件得分为 1.024。
其他小模型,原版文件(筛选,§15 E54):
| 模型 | 生成(基准) | 提示 | 位/字节 |
|---|---|---|---|
| LFM2.5-350M(QAD Q4_0) | 23.7 tok/s | 104 tok/s | 1.805 |
| LFM2-700M(Q4_0) | 11.5 tok/s | 52.8 tok/s | 1.169 |
| Qwen3-0.6B(Q8_0) | 9.35 tok/s | 50.6 tok/s | 1.059 |
| LFM2.5-1.2B(QAD Q4_0) | 8.3 tok/s | 31.6 tok/s | 1.133 |
| Llama 3.2 1B(Q4_0) | 7.0 tok/s | 29.5 tok/s | 0.998 |
| Ternary-Bonsai-2-2B(Q2_0) | 5.9 tok/s | 15.8 tok/s | 1.124 |
| Gemma 3 1B(Q4_K_M) | 5.7 tok/s | 11.1 tok/s | 1.260 |
| Granite 4.0 H 1B(Q4_0,约 1.5 B) | 原样太大 | 0.916 | |
| ↳ 重建:全 Q4_K、Q8_0 嵌入、48K 头(E62) | 5.29 tok/s(仅在释放 RAM 后适配,950 MB RSS) | 0.919 | |
| LFM3-1.7B(QAD Q4_0) | 无法适配 |
Granite 4.0 H 1B 是唯一接近 2B 质量的模型。按我们的方式重建后(E62),它以 5.29 tok/s 运行,低于 2B 的 6.55,质量也略低:它每个 token 承载的权重字节约为 0.8B 的两倍。
盒子的物理限制:在 Android 开始杀进程之前,一个进程可以占用约 0.96 GB(无头模式下约 1.15 GB,启动器和 Google 服务被强制停止),闪存读取最高为 278 MB/s,单次约 1 MB 的随机读取耗时约 6 ms。一个每个 token 必须流式加载 X MB 的模型永远无法超过 278 / X token 每秒。限制 2B 以上一切的是这一点,而不是 CPU,这也是为什么混合专家模型——每个 token 只触及 8 B 权重中的约 1 B——是突破之道。
8 B 下 10 tok/s?实测,而非猜测(E98):Moon-Beam 在每 token 2 个专家时达到 10.4 tok/s,但文本变成乱码;最佳连贯设置约为 7-8 tok/s。稠密 Qwen3-8B 就是 1 bit 的 Bonsai-8B,而最小的 Qwen MoE(35B-A3B)每个 token 触及的权重是 Moon-Beam 的 3 倍。
设备 #2 上的结果
一台 2013 年的 iPad Air:Apple A7,2 核,无 dotprod 的 NEON,1 GB RAM,iOS 12.5.7,使用 Amethyst 越狱。一切都在 CPU 上以 2 线程和 1,024 token 上下文运行,从 Mac 交叉编译。详细说明见 EXPERIMENT.md 的 §21,构建步骤见 ipad-air/README.md。
| 模型 | 文件 | 生成(tok/s) | 峰值 RSS | 固定的三问题测试 |
|---|---|---|---|---|
| Bonsai-1.7B Q1_0(1-bit) | 237 MiB | 23.7-25.8,长聊天中为 18-22 | 605 MB | 三个全对,且写出正确代码:就用这个 |
Bonsai-4B Q1_0(1-bit),-c 512 -b 64 |
546 MiB | 9.4-11.4,长聊天中为 9.2-10.3;作为服务器时,iOS 会在几分钟内重置它 | 615-682 MB | 法国答对了,潮汐基本答对,每次运行都记不住;每字节表现更好(1.073 对 1.158 比特/字节) |
Moon-Beam-8B-A1B(MoE,Q2_K 专家),专家分页器,-c 512 -b 64 |
2.6 GiB(映射 474 MB) | 较长回答为 3.5-3.6;使用 --experts 4 时为 4.9-5.1(困惑度 +27%) |
~600-625 MB | 三项全对;会话模型,对常开服务器来说太大 |
| SmolLM2-360M-Instruct Q4_K_M | 258 MiB | 10.9-12.5 | 269-316 MB | 三项全对;最轻的优秀选项 |
| Gemma 3 270M-it Q4_K_M | 241 MiB | 15.4-19.0 | 248-294 MB | 潮汐答错,回忆题回复为空 |
| SmolLM2-135M-Instruct Q4_K_M | 101 MB | 18.6-29.3 | 141 MB | 法国和回忆题答对,潮汐较弱 |
| Qwen3.5-0.8B Q4_K_M | 508 MiB | 约 0.2 | 506 MB | 频繁换出页面缓存,手动停止 |
只有 Bonsai 和 Moon-Beam 两行是在最新构建上测得的。其他行早于下文的注意力和采样器工作。
| 类别 | 最佳模型 | 首次运行 → 现在(tok/s) | 提升 | 实现方式 |
|---|---|---|---|---|
| 1.7B | Bonsai-1.7B(1-bit) | 2.75 → 23.7-25.8 | ×8.6 | 无乘法、无 dotprod 的查找表 1-bit 内核,LM head 走快速内核,带剪枝的行序注意力,单遍采样器 |
| 4B | Bonsai-4B(1-bit) | 9.4-11.4 | 1.7B 的内核,每个 K head 对应 4 个 q head 的注意力,-c 512 -b 64 以保持在约 700 MB 上限内 |
|
| 8B 稠密 | Bonsai-8B(1-bit) | 0.08 | 放不进 RAM;大部分文件每个 token 都要从闪存重读 | |
| 8B MoE | Moon-Beam-8B-A1B | 无法加载 → 1.6 → 3.5(4 专家时 5.0,困惑度 +27%) | ×2.2 | 专家分页器,Q2_K 查找表内核,预取,缓存偏置 0.03,基于频率的淘汰 |
| 16B MoE | Ling-mini-2.0 | 无法加载 → 2.6(+2.6% 时 3.3,偏置 0.3 时 4.5) | 新增 | Moon-Beam 方案,以及通过 HTTP 组装并直接流式传输到 iPad 的模型文件 |
“无法加载”:iOS 12 允许进程最多映射约 1.7 GB,因此原版 llama.cpp 在 2.6 和 5.5 GB 文件上运行一个 token 之前就失败了。Moon-Beam 的“首次运行”是第一次专家分页器运行(池 8,无偏置)。
我们在 iPad 上构建的内容,按所针对的瓶颈分组:
| 瓶颈 | 创新 | 最大收益 |
|---|---|---|
| 计算(2 核 A7,无 dotprod,6 项) | 无乘法 1-bit 内核,将电视的 1-bit 查找表内核移植到基础 NEON,绑定 LM head 的查找表副本,带剪枝的行序注意力(每个 K head 对应 2 或 4 个 q head),带 40 项堆的单遍采样器,用于专家的 Q2_K 查找表内核 | Bonsai-1.7B 2.75 → 3.45 → ~11 → 23.7-25.8 tok/s;采样每 token 3 → 0.23 ms;仅 Q2_K 内核就让 Moon-Beam 从 2.94 → 3.06 |
| 地址空间和 RAM(约 1.7 GB 可映射,约 700 MB 可用,4 项) | 只映射非专家部分的专家分页器(专家在后的文件),为 bailingmoe2 和 bailingmoe3 剪枝的 LM head,小批量(-c 512 -b 64),为 iOS 12 编译剔除 std::filesystem |
8B 和 16B MoE 模型终于能加载,占用 556-625 MB;Bonsai-4B 放得下 |
| 闪存(约 260 MB/s,5 项) | 带 4 个读取器的无缓存 pread,按需要时间排队读取,预门控预取,缓存感知路由偏置,衰减频率淘汰 |
Moon-Beam 1.6 → 3.5 tok/s 且无质量损失;仅靠淘汰就将未命中率从 42% → 38% |
| 工具(5 项) | 带缺页计数的算子分析器,专家跟踪和缓存模拟器,设备端困惑度(tinyppl),通过 HTTP 范围请求组装模型,能杀死孤儿运行的基准测试 |
发现了从未到达快速内核的 LM head(72 ms 中的 45 ms);排除了软缺页理论;用 1.4 GB Mac 磁盘构建了 5.5 GB 模型 |
Bonsai-1.7B 如何从 2.75 提升到约 25 tok/s(全程同一模型文件):
| 步骤 | tok/s | 变更内容 |
|---|---|---|
| 原版 llama.cpp,2 线程 | 2.75 | 用加宽乘法模拟 dotprod |
| 无乘法 NEON 内核 | 3.45 | 权重为 ±1,因此无需乘法;输出完全一致 |
| 来自设备 #1 的查找表内核,移植到基础 NEON | 约 11 | 其 dotprod 需求原来只是一个假设 |
| 该内核上的输出头 | 18-22 | 151,669 行不是 32 的倍数,所以绑定头从未触及它:每 token 72 ms 中的 45 ms |
| 带剪枝的行序注意力,以及一个不对词表排序的采样器 | 23.7-25.8 | KV 缓存将一行的所有头并排存储,因此一次只处理一个头会不断错过缓存 |
在长对话(400 token 回答)中,仅通过注意力工作,三轮就从 15.4 / 7.6 / 8.2 提升到 21.8 / 17.9 / 18.4 tok/s。将长对话保持在 17 以上的剪枝阈值在 1,024 token 上下文下带来 +0.42 % 的困惑度代价,接近 ±0.3 % 的噪声底;GGML_FA_EPS=0.0001 以约 15 tok/s 换回这一代价。
一个 8B 模型,通过专家分页器。 iOS 12 将进程的映射地址空间限制在约 1.7 GB(Web 服务器的用户为 1.3 GB),因此 Moon-Beam-8B 的 2.6 GB 文件甚至无法映射,而保留更少的专家以使其适配会使困惑度增加一倍以上(§21.7)。密集 Bonsai-8B 从闪存运行速度为 0.08 tok/s。因此模型文件被重写,专家放在最后,只映射它们之前的 474 MB,每层在 RAM 中保留 14 个专家,当路由器选择其他专家时用 pread 从闪存读取。结果与未分页模型完全一致。对已在 RAM 中的专家施加小的路由偏置(+0.3 % 困惑度,在噪声范围内)使其在约 600 MB 内达到 2.4-2.8 tok/s(§21.8)。第 2 轮(§21.9)按需要时间排队闪存读取,预取下一层可能的专家,并通过 Q2_K 的查找表内核运行专家:3.4 tok/s,是密集 8B 的 40 倍,在完整评估文本上困惑度 +0.7 %。 闪存仍是瓶颈:每个 token 以 266 MB/s 读取约 53 MB。将权重接入 RAM 导致 iPad 内核恐慌,就像之前的 16 池一样。第 3 轮(§21.10)按衰减使用频率而非最近使用进行驱逐,达到 3.5 tok/s 且无质量代价。5 tok/s 需要每 token 4 个专家而非 8 个(+27 % 困惑度);按 token 自适应选择数量结果并不比固定数量更好。一个 16B 模型(§21.11):Ling-mini-2.0,16.3B 参数,每层 256 个小专家,通过同一分页器运行,2.6 tok/s 且路由不变,+2.6 % 困惑度时 3.3,强缓存偏置时 4.5,在 580 MB 以内。其 5.5 GB 文件通过 HTTP 范围请求从两个已发布的量化版本组装而成,并直接流式传输到 iPad,因为 Mac 没有空间容纳它。它在相同速度下是 Moon-Beam 的两倍大小,但不是更好的模型(+3 % 困惑度)。
值得了解的局限。 Bonsai 是一个 1-bit 模型,仍会弄错事实(在一次测试中它称水星是离地球最近的行星)。约 700 MB 是实际内存上限:1-bit 权重无法压缩,因此 iOS 超过此值就开始杀死进程,这就是 4B 需要 512 token 上下文的原因。越狱在重启后不会保留。快速输出头在每次启动后的第一个提示中增加 2-3 秒。
这里有什么
Cortex-A55 内核(ARMv8.2 dotprod,无 i8mm),作为 llama.cpp v0.8.0 的补丁,每个都有针对标量参考的精确性测试:
| 内核 | 之前 → 之后 | 位置 |
|---|---|---|
Q2_K,为 vdotq_laneq 重新打包为 8 行 × 4 字节(上游仅在 x86 / RISC-V 上重新打包 Q2_K) |
7.8 → 13.9 G 权重/秒;生成 +41%,提示 2.4× | E34 |
| TQ1_0 / TQ2_0 三值,重新打包 | 9.5 → 14.4 / 11.9 → 19.1 G 权重/秒 | E38 |
| 三值 Q2_0 → RAM 中无损 1.875 比特/权重(保留每 64 个缩放系数的三进制打包) | Ternary-Bonsai-4B 从“抖动”到 3.2 tok/s | E39, E42 |
Q1_0 位平面:vtst 将位平面直接转换为 vdot 的掩码,无需查表;8 位行仿射缩放(−5.6%,0.07% 误差) |
Bonsai-4B 3.02 → 4.22 tok/s;Bonsai-8B 适配于 0.96 GB | E44, E52 |
| 融合 Gated-DeltaNet 步骤,直接写入状态(Qwen3.5) | 2B 6.0 → 6.3-6.7 tok/s | E28 |
DeltaNet 状态按 id 原地读取,而非每个 token 进行 1 MB/层的收集;fp16 状态(LLAMA_STATE_F16=1,UI 中默认开启) |
0.8B 11.9 → 12.9 tok/s;2B +2.5%,困惑度 +0.15% | E56, E61, E65 |
| 快速内核上的 LM head:65,668 行的 head 从未重新打包(ggml 仅重新打包行数可被 8 整除的),因此添加了 4 个 token 行;然后从重新打包的 head 重建嵌入行(逆 8 行交错),而非从闪存读取;单 token DeltaNet 卷积步骤从 4 个节点融合为一个 NEON 操作 | 2B +7%(基准测试和聊天);0.8B +9.5% | E69-E72 |
| 2 位字段中的三值权重,缩放系数按 128 合并:在顺序执行的 A55 上,一个三进制数字每 16 个权重约需 5 个 NEON 操作,而 2 位字段需 2 个,因此多花 13% 的 RAM 换取速度。合并相邻缩放系数增加 +0.18% 困惑度 | Ternary-Bonsai-4B 聊天中 3.2 → 4.3 tok/s,提示 7.0 → 9.6 | E76, E77 |
| 1 位查找表内核(Four-Russians / T-MAC 风格):每组 32 行,每 4 个激活值一个 16 项表,直接从浮点激活值构建,每 128 次乘加约 8 个 NEON 操作 + 2 次加载,对比 16 + 4 | Bonsai-8B 3.77 → 5.1-5.4 tok/s(配合 E82、E88) | E81 |
带阈值的 Q8_0 注意力:先用 sdot 计算所有 K 点积,因此 softmax 最大值提前已知,然后对低于 max + ln(1e-4) 的行跳过 expf 和 V 计算 |
1,000 token 的答案不再使速度减半(结束时 2.50 → ~4 tok/s) | E86 |
| 引导式矩阵乘法调度:每个线程获取剩余 /(2 × 线程数)行,因此慢速或被抢占的线程只留下短尾,而非每 token 约 28 ms 的空闲核心;单行逐元素操作按列拆分(ggml 将它们全部留在 0 号线程) | 2B 6.26 → 6.54 tok/s;0.8B +1.4% | E63, E64 |
内存技巧:
- 剪枝 LM head:仅保留约 49-66 K 个最有用的词汇行,根据英语、代码和其他 7 种语言的 token 频率选择。其他 logits 分散至 −inf。节省 0.2-0.5 GB,遗漏约 1% 的英语 token。
- 闪存上的重新打包缓存(
GGML_REPACK_CACHE):重新打包的权重写入文件一次,之后映射。模型在几秒内加载。
无头模式(tools/tv-llm-mode.sh on|off):一个小的前台活动,然后启动器、Google 服务和其他重型应用被强制停止,svc power stayon 保持动画屏保(占一个核心的 17%)远离。除了保持唤醒外无持久化,off 会恢复。MemAvailable ~1000 → ~1300 MB。无 fork 守卫(tools/tv-watch.c)取代了每秒启动约 25 个进程并消耗 10% 速度的 shell 循环。
混合专家模型的专家分页器(ggml-cpu/moe-pager-tv.inc):
- 专家常驻闪存:每个专家张量都叠加了空的匿名内存,某一层路由完成后,缺失的专家会通过并行
O_DIRECT直接读入各自的地址;每层一个 LRU 池(128 个专家中的 43 个)保留其余专家。内核看到的仍是普通张量。一旦重打包缓存持有 GGUF 自身的专家字节,这些字节就会被挖空,因此模型在闪存上只占一份权重。 - 缓存感知路由(
GGML_MOE_BIAS):对已在 RAM 中的专家给予少量加分,可将未命中率从 13% 降至约 2%,代价是可测量的质量损失(arXiv 2412.00099 在其他模型上有此思路)。每个 token 使用更少的专家(LLAMA_MOE_USED=6)是另一个调节手段。 - 热启动:从每层最常用专家的列表开始,以及预门控预取:将第 L+2 层的路由器应用于第 L 层的隐藏状态,预测路由器实际会选什么(sigmoid、模型自身的选择偏置和缓存加分),在需要之前加载约 60% 的未命中项。
- 答案为何循环,以及修复方法:2 位专家在约 250-300 词后破坏长文连贯性,路由偏置会放大这一问题。DRY 采样只是掩盖了它(模型会改写自己的循环);在 256 个 token 上施加 1.15 的重复惩罚,可将 TV 上退化的长答案从 12/13 降至 1/13(E99、E100)。
大于 RAM 的模型的权重流式加载(ggml-cpu/stream-tv.inc):
- 常驻 RAM 的内容:选定的部分权重保持常驻。其余部分位于“流式区域”。
- 预取:每个 matmul 上的钩子记录权重的使用顺序。然后读取线程用并行 8 MB 的
O_DIRECT读取提前获取区域权重,直接读入权重自身的地址,达到闪存满速 278 MB/s。 - 正确性:每个计算线程都会等待其权重完全加载,因此预测错误只会耗费时间,绝不会影响正确性。
- 用后即弃:每个区域权重在使用后立即释放。
- 验证模式:
GGML_STREAM_VERIFY=1将每个流式张量与文件进行比较。它发现了两个静默损坏 bug,均已修复并记录在 E48 和 E50 中。 - 投机解码:使用模型自身的 MTP 头,当该次传递受闪存限制时,验证 2 个 token 大约只需对权重做一次遍历,因此收益明显(+69%)。在驻留 RAM 的 2B 模型上则亏损(E31)。
性能分析(补丁中的环境变量开关):GGML_OPPROF=1 逐算子表,GGML_OPPROF=2 单个图的逐节点、逐线程跟踪(tools/optrace.py),LLAMA_UBATCH_PROF / GGML_CPU_PROF 阶段计时。它们揭示了小模型的时间实际花在哪里(E57):约 71% 用于 Q4_K matmul,而每 token 仅约 2 ms 用于屏障和调度。
工具:
- 流式 GGUF 重写器:在一次顺序遍历中添加剪枝头、额外张量和元数据,因此 Hugging Face → Mac → TV 流水线从不需要在 Mac 上存储模型。
- MTP 获取器:仅从 safetensors 中范围读取 MTP 张量。
- 内存守卫:包装 TV 上的每次重型运行。
- 基准测试和困惑度测试框架、一个模型筛选器(可将任意 Hugging Face GGUF 流式传输到 TV 并评分,
tools/screen-small.sh),以及一个实时 token 流 Web UI。
快速开始
你需要:具有网络 ADB 的 TV 盒子(或其他 ARMv8.2 Android 设备)、adb、zig(用于静态 aarch64 musl 构建)、cmake + ninja、python3,以及 uv(用于 numpy)。
export ADB_SERIAL=<tv-ip>:5555 # every script talks to the box through this adb connect $ADB_SERIAL # 1. llama.cpp v0.8.0 + the patch, cross-compiled for the TV git clone https://github.com/ggml-org/llama.cpp third_party/llama.cpp cd third_party/llama.cpp && git checkout 8642541 && git apply ../../patches/llama.cpp-v0.8.0-tvbox.patch cmake -S . -B build-tv -G Ninja -DCMAKE_SYSTEM_NAME=Linux -DCMAKE_SYSTEM_PROCESSOR=aarch64 \ -DCMAKE_C_COMPILER=$PWD/../../zigcc/cc -DCMAKE_CXX_COMPILER=$PWD/../../zigcc/c++ -DCMAKE_BUILD_TYPE=Release \ -DCMAKE_EXE_LINKER_FLAGS=-static -DBUILD_SHARED_LIBS=OFF -DGGML_NATIVE=OFF \ -DGGML_CPU_ARM_ARCH=armv8.2-a+dotprod+fp16 -DGGML_OPENMP=OFF -DLLAMA_OPENSSL=OFF -DLLAMA_BUILD_TESTS=OFF ninja -C build-tv llama-server llama-cli llama-bench llama-perplexity llama-quantize cd ../.. adb -s $ADB_SERIAL shell mkdir -p /data/local/tmp/llm/patched25 /data/local/tmp/llm/patched adb -s $ADB_SERIAL push third_party/llama.cpp/build-tv/bin/llama-{server,cli,bench,perplexity} /data/local/tmp/llm/patched25/ adb -s $ADB_SERIAL push third_party/llama.cpp/build-tv/bin/llama-quantize /data/local/tmp/llm/patched/ # used by tools/tv-quant.sh zig cc -target aarch64-linux-musl -O2 -static -o gguf_recut tools/gguf-recut/gguf_recut.c && adb -s $ADB_SERIAL push gguf_recut /data/local/tmp/llm/ # 2. models: rebuilt from their Hugging Face sources straight onto the TV (see below) tools/rebuild-models.sh 2b # also: 08 4b b8 tb8 q9 mb lm caches # 3. the live chat page (default: the 2B on patched25 with fp16 state), then open http://<tv-ip>:8090 from any device on the network tv-llm-ui/start.sh tv-llm-ui/start.sh stop
其他模型:
# Moon-Beam-8B-A1B MoE, ~7.2 tok/s (first: `tools/rebuild-models.sh mb`, needs a native Mac build and ~9 GB on the Mac while it runs). # start.sh turns on headless mode, the expert pager, routing bias, prefetch and the repeat penalty; POOL / BIAS / EXPERTS override them. MODEL=mb-q2-h60.gguf tv-llm-ui/start.sh # Ling-mini-2.0 16B MoE, ~5.1 tok/s (first: `tools/rebuild-models.sh lm`) MODEL=lm2-q2-h60.gguf tv-llm-ui/start.sh # Bonsai-8B 1-bit fully resident, ~5.2 tok/s (first: `tools/rebuild-models.sh b8`; the repack cache is written on first start) MODEL=b8-q1-hml.gguf tv-llm-ui/start.sh sh /data/local/tmp/llm/tv-llm-mode.sh off # on the TV, afterwards: launcher and screensaver back # Qwen3.5-0.8B, ~16 tok/s (first: `tools/rebuild-models.sh 08`, needs a native Mac build of llama-quantize) MODEL=q08-q4k-h65p8.gguf tv-llm-ui/start.sh # The 8B / 9B numbers below were measured with the build of that time (patched16); the current build has the same # code plus §15-17. GGML_CHUNK_GUIDED=0 in SENV restores the old matmul scheduling. No fp16 state with MTP. # Bonsai-8B 1-bit with streaming and no headless mode, ~1.2 tok/s (first run: `tools/rebuild-models.sh b8 caches`) MODEL=b8-q1-hml.gguf BIN=patched25 EXTRA="-ctk q8_0 -ctv q8_0 -fa on -cram 0" \ SENV="GGML_REPACK_CACHE=/data/local/tmp/llm/cache/b8c GGML_REPACK_RESIDENT_MB=800 GGML_STREAM_MODE=cache GGML_STREAM_WINDOW_MB=64" tv-llm-ui/start.sh # Qwen3.5-9B with MTP, ~0.27 tok/s MODEL=q9-iq2-h65-mtp.gguf BIN=patched25 EXTRA="-nr -ctxcp 0 -cram 0 -ub 16 -b 64 --spec-type draft-mtp --spec-draft-n-max 1" \ SENV="LLAMA_STREAM_RESIDENT_MB=600 LLAMA_STREAM_PIN=output.,blk.32. GGML_STREAM_WINDOW_MB=64" tv-llm-ui/start.sh
盒子上的所有内容都位于 /data/local/tmp/llm 中,并以 adb shell 用户身份运行。唯一触及的系统设置是无头模式下的保持唤醒(svc power stayon),tv-llm-mode.sh off 会将其重新关闭。adb shell rm -rf /data/local/tmp/llm 会将其全部移除。
模型文件:不在 git 中,可重新构建
模型文件(每个 0.5-4 GB)不在本仓库中。tools/rebuild-models.sh 会从公开的 Hugging Face 文件重新创建每一个文件,将它们通过 tools/gguf_build.py 流式传输到电视上。下面的 SHA-256 是实验中使用的文件的哈希值。4B、Bonsai-8B 和 9B 文件的重建版本经检查字节完全一致。
现成下载。 每个尺寸类别中最好的文件都在 Hugging Face 上,与电视上运行的完全一致。它们需要上面打过补丁的 llama.cpp;原版 llama.cpp 无法加载剪枝后的头部。每张卡片都有运行命令和实测数据:
| 模型 | Hugging Face | 文件 |
|---|---|---|
| Qwen3.5-0.8B,16.8 tok/s | hyperionaidev/Qwen3.5-0.8B-tvbox-GGUF | q08-q4k-h65p8.gguf |
| Qwen3.5-2B,7.7 tok/s | hyperionaidev/Qwen3.5-2B-tvbox-GGUF | w-q4k-h65p8.gguf |
| Ternary-Bonsai-4B,4.3 tok/s | hyperionaidev/Ternary-Bonsai-4B-tvbox-GGUF | tb4-q20-hml.gguf |
| Moon-Beam-8B-A1B(MoE),7.2 tok/s | hyperionaidev/Moon-Beam-8B-A1B-tvbox-GGUF | mb-q2-h60.gguf + moe-warm-moonbeam.txt |
| Bonsai-8B(1-bit),5.2 tok/s | hyperionaidev/Bonsai-8B-tvbox-GGUF | b8-q1-hml.gguf |
| Ling-mini-2.0(16B MoE),5.1 tok/s | hyperionaidev/Ling-mini-2.0-tvbox-GGUF | lm2-q2-h60.gguf + moe-warm-ling.txt |
用 hf download hyperionaidev/<repo> --local-dir models/ 下载,然后将文件 adb push 到 /data/local/tmp/llm/,并将 moe-warm-*.txt 放在它们旁边。这会替换 08 / 2b / 4b / mb / b8 / lm 目标。对于 8B 和 16B 模型,首次启动会写入重打包缓存。
iPad Air 下载。 在 iPad 上运行的每个模型、从哪里获取以及在那里的速度。三个 MoE 文件是我们自己构建的,针对 iPad 的专家分页器和查找表内核进行了布局:它们需要 iOS 12 补丁(ipad-air/),任何其他 llama.cpp 都能加载它们,但专家会乱序。其余文件完全按发布状态使用;Bonsai 模型的快速布局在加载时在 RAM 中构建。共 53 个实验(E108-E160,§21):
| 模型 | 下载 | iPad 速度(tok/s) | 峰值 RSS | 实验 |
|---|---|---|---|---|
| Ling-mini-2.0(16B MoE) | hyperionaidev/Ling-mini-2.0-ipad-GGUF:lm2-q2-h60-lut.gguf(SHA-256 3e464310…4e50bd) |
2.6 无偏;偏差 0.1 时为 3.3(+2.6 % 困惑度);偏差 0.3 时为 4.5;添加 --experts 6 后为 5.2 |
556-576 MB | 4(E157-E160) |
| Moon-Beam-8B-A1B(MoE) | hyperionaidev/Moon-Beam-8B-A1B-ipad-GGUF:mb-q2-h60-lut.gguf(SHA-256 acf1cb56…94b976);不带重打包的 experts-last 文件,约慢 4 %,是 hyperionaidev/Moon-Beam-8B-A1B-ipad-xl-GGUF:mb-q2-h60-xl.gguf(aa919400…871d7e) |
3.5-3.6;7 个专家时为 3.7-4.0(+0.4-1.9 %);4 个专家时为 5.0(+27 %) | 600-625 MB | 19(E138-E156) |
| Bonsai-8B(1-bit,稠密) | prism-ml/Bonsai-8B-gguf | 0.08:无法装入 RAM,从闪存读取 | 629 MB | 4(E134-E137,包含最初的 Moon-Beam 尝试) |
Bonsai-4B(1-bit),-c 512 -b 64 |
prism-ml/Bonsai-4B-gguf | 9.4-11.4;长对话中为 9.2-10.3 | 615-682 MB | 5(E129-E133) |
| Bonsai-1.7B(1-bit),默认 | prism-ml/Bonsai-1.7B-gguf | 23.7-25.8;长对话中为 18-22 | 605 MB | 11(E118-E128) |
| SmolLM2-360M-Instruct Q4_K_M | bartowski/SmolLM2-360M-Instruct-GGUF | 10.9-12.5 | 269-316 MB | 10(E108-E117:首次运行、小模型和网页聊天) |
| Gemma 3 270M-it Q4_K_M | unsloth/gemma-3-270m-it-GGUF | 15.4-19.0 | 248-294 MB | |
| SmolLM2-135M-Instruct Q4_K_M | 原版 Q4_K_M | 18.6-29.3 | 141 MB | |
| Qwen3.5-0.8B Q4_K_M | unsloth/Qwen3.5-0.8B-GGUF | 约 0.2:频繁换页 | 506 MB | |
| stories15M q4_0 | 原版 | 在 llama-simple 中约 290 |
| 电视上的文件 | 目标 | 构建自 | SHA-256 |
|---|---|---|---|
w-q4k-h65.gguf(Qwen3.5-2B) |
2b |
unsloth/Qwen3.5-2B-GGUF BF16 + imatrix_unsloth,MTP 块来自 Qwen/Qwen3.5-2B,在电视上量化,头 data/head-ids-ml60k.txt |
16057be3…3285b |
w-q4k-h65p8.gguf(Qwen3.5-2B,默认) |
2b |
上述文件在电视上用 data/head-ids-ml60k-p8.txt 重新切分(65,672 行,因此头被重新打包,§17) |
631a27ae…54fd11 |
w-q4k-h45.gguf(可选) |
2b45 |
同上,45,654 行的头 data/head-ids-ml40k.txt(与 E29 的 H45 文件逐字节相同) |
a50eadc5…664d5b |
q08-q4k-h65.gguf(Qwen3.5-0.8B) |
08 |
unsloth/Qwen3.5-0.8B-GGUF BF16 + 其 imatrix_unsloth,纯 Q4_K,头 data/head-ids-ml60k.txt,在 Mac 上量化 |
901f3838…8523a6b |
q08-q4k-h65p8.gguf |
08 |
上述文件在 Mac 上用 data/head-ids-ml60k-p8.txt 重新切分(§17) |
7dd2aac5…52fc232 |
tb4-q20-hml.gguf |
4b |
prism-ml/Ternary-Bonsai-4B-gguf Q2_0_g64,头 data/head-ids-qwen3-ml64k.txt |
a02d805f…3fe24 |
b8-q1-hml.gguf |
b8 |
prism-ml/Bonsai-8B-gguf Q1_0,相同的头 |
fc297cb3…0d42a |
tb8-q20-hml.gguf |
tb8 |
prism-ml/Ternary-Bonsai-8B-gguf Q2_0_g64,相同的头 |
01b1e0ef…93e06 |
mb-q2-h60.gguf |
mb |
tablinum/Moon-Beam-8B-A1B-GGUF-Preview Q8_0,在 Mac 上重新量化:专家 Q2_K,其余 Q4_K,自有 imatrix 来自 data/corpus,头 data/head-ids-ling-60k.txt;在重打包缓存(cache/mbq2.*)写入后,在电视上对专家字节进行打孔 |
2d78fcdd…1c34ee |
lm2-q2-h60.gguf |
lm |
bartowski/inclusionAI_Ling-mini-2.0-GGUF Q4_K_M + 其 imatrix:专家在 Mac 上重新量化为 Q2_K,其余 Q4_K,头 data/head-ids-ling-60k.txt;在重打包缓存(cache/lmq2.*)写入后,在电视上打孔 |
c089aeb0…e8d7 |
q9-iq2-h65-mtp.gguf |
q9 |
unsloth/Qwen3.5-9B-GGUF UD-IQ2_XXS,MTP 块来自 Qwen/Qwen3.5-9B(Q4_0),65K 头 |
7766478e…8dcbc |
cache/b8c.*,cache/tb8.* |
caches |
由首次运行使用 GGML_REPACK_CACHE 写入 |
data/ 中的头 ID 列表由 tools/vocab_select.py(Qwen3.5 分词器)和 tools/head_select_tok.py(任意分词器,通过 llama-tokenize)生成,来自语料库 tools/fetch_corpus.py 下载(Wikipedia + Project Gutenberg)。
布局
| 路径 | 内容 |
|---|---|
EXPERIMENT.md |
完整记录:§1-8 第一个微型模型,§9-10 llama.cpp 与首次 flash 流式传输,§11 2B 推进,§13 4B 推进,§14 9B 推进,§15 0.8B 速度推进,§16-17 2B 第 3-4 轮,§18 4B 第 2 轮(arXiv / GitHub 扫描,2 位三进制布局),§19 8B 推进(无头模式、LUT 内核、带专家分页器的 Moon-Beam MoE、长答案为何循环),§20 大于 9B(Ling-mini-2.0 16B,以及 LFM2.5-24B 和 Qwen3.6-35B 为何不适合) |
patches/llama.cpp-v0.8.0-tvbox.patch |
对 llama.cpp 的每项更改:针对 Qwen3 / Qwen3.5 / Granite 4.0 H 的剪枝头(output_ids),上述内核(ggml-cpu/repack-*-tv.inc),融合 DeltaNet(按 ID 读取状态、可选 fp16 状态、单 token 卷积步),1 位 LUT 内核,Q8_0 注意力,带路由偏置和预取的 MoE 专家分页器(ggml-cpu/moe-pager-tv.inc),针对 bailingmoe3 的剪枝头,从常驻头获取嵌入行,重打包缓存与流式引擎(ggml-cpu/stream-tv.inc,加载器钩子),填充小批次,算子分析器,感知剪枝头的困惑度,针对 Mali 的 Vulkan 调优 |
tools/ |
GGUF 重写器 / 头剪枝器 / 重切器,词汇选择,语料库和 MTP 获取器,模型重建脚本,电视内存保护和 RAM 辅助工具,基准测试扫描,内核基准测试和精确性检查(kbench/),flash 基准测试 |
tv-llm-ui/ |
llama-server 的实时 token 流页面(置信度颜色、前 3 个备选、速度、框统计),其启动器和基准测试框架 |
tiny-llm-web/ |
来自第一个实验的 llama2.c 故事服务器 + 电视页面 |
bench/ |
results.jsonl(每个聊天基准测试:提示、输出、速度)和 raw/(每个实验的日志) |
data/ |
头 ID 列表和两个评估文本 |
zigcc/ |
用于交叉编译静态 aarch64 二进制文件的 zig 包装器 |
ipad-air/ |
设备 #2:为 iOS 12 交叉编译,smolchat(终端聊天和 Safari 网页),部署和基准测试脚本(README,§21) |
screenshots/ |
在电视上运行的网页 |
经验教训
- 在这台机器上,4 位的 2B 胜过所有 1-2 位的更大模型。 低于约 2.5 位的训练后量化会破坏普通模型(E22、E23、E35)。为 1 位或三进制训练的模型能撑住,但在 4-8 B 规模下,不流式传输就放不下。
- 超过 RAM 后,flash 带宽决定速度。 内核的 LRU 对于大于缓存的循环扫描是最差的策略:它每个 token 都重新读取所有内容。保持固定的常驻集,其余的自己流式传输。
- 当受限于闪存带宽时,批处理是免费的。 无论提示词和推测验证的规模多大,它们的开销都大约相当于一次权重遍历。
- 先测量,再验证。 两个流式处理 bug 给出了看似合理但实际错误的速度数字;只有将张量与文件进行对比,并将困惑度与 Mac 参考值进行对比,才能发现它们。
- 小模型的主要部分是词表。 Qwen3.5-0.8B 的 248K 行输出头占其权重的三分之一;将其剪枝到 65K 行并全部使用 Q4_K 后,速度从 7.5 tok/s 提升到 12.1 tok/s(E55)。小模型在 4 位量化下损失也更大(困惑度 +7%,而 2B 模型为 +2.3%)。
- 在编写内核之前先做模拟。 激活稀疏性(E58)和低秩输出头(E60)在纸面上都很有前景;在 Mac 上进行质量模拟后,每个方案都在一小时内被否决。
- 在顺序执行核心上,除了字节数还要计算 NEON 操作数。 更紧凑的打包节省了 20% 的字节,却付出了 2.5 倍的操作数;撤销该优化后,4B 模型在聊天中快了 33%(E76、E77)。4 位内核则相反,受限于 RAM(E27),因此该技巧对 2B 或 0.8B 没有帮助。
- 检查每个大矩阵是否都走到了快速内核。 2B 模型的输出头(65,668 行,约占每个 token 权重的 10%)在通用内核上静默运行了数周,因为 ggml 只重新打包行数能被 8 整除的矩阵;多出四行后性能提升了 5.8%(E71、E72)。加载日志中的重打包缓冲区大小会暴露这一点。
- 大部分 RAM 是 Android 占用的,而不是模型。 在此期间强制停止启动器和 Google 服务(没有持久化任何东西)让 Bonsai-8B 完全驻留在 RAM 中:在任何内核工作之前就从 1.2 tok/s 提升到 3.6 tok/s(E80)。一个动画屏保和一个每秒 fork 25 次的守护进程各自又消耗了 10-15%(E82、E88)。
- 对于混合专家模型,闪存访问是缓存未命中,而不是流式读取。 每个专家约 6 毫秒的未命中意味着池命中率决定了速度;将路由导向已缓存的专家并预取下一个路由器将选择的专家,使速度从 4.4 tok/s 提升到 7.2 tok/s。
- 困惑度看不到循环。 它在干净文本上逐 token 评分;2 位模型评分不错,但在 13 个长回答中仍有 12 个陷入循环。也要对长时间自由生成的文本评分(
tools/loop_stats.py),并且用每字节比特数来比较不同分词器的模型,绝不要用困惑度。 - 超过 9B 后,要计算常驻字节数,而不是参数量。 这里混合专家模型的上限是必须留在 RAM 中的非专家权重加上一个有用的专家池。Ling-mini-2.0(16B)保持 279 MB 常驻并以 5 tok/s 运行;Qwen3.6-35B-A3B 在缓存单个专家之前就需要约 870 MB(§20)。
- 保护设备。 在两次早期内核恐慌之后,每次重负载运行都通过一个包装器执行,当空闲内存低于 180 MB 时将其终止。
许可证
MIT。llama.cpp 补丁是 llama.cpp(MIT)的衍生作品。模型权重保留各自的许可证,评估文本是 Wikipedia 摘录(CC BY-SA 4.0)。
致谢
基于 llama.cpp 和 llama2.c 构建。模型来自 Qwen、unsloth(GGUF 和重要性矩阵)、PrismML(Bonsai)、Google(Gemma)和 stories260K。评估文本是 Wikipedia 的摘录(CC BY-SA 4.0)。🤏 标志是 Google Noto Emoji(Apache 2.0)中的捏手表情符号。
来源:Hacker News · github.com

