跳到正文
Hacker News· mrashad74·· 5 小时前AI 评分60

smolmaxxing:在小米电视盒子与 2013 款 iPad Air 上跑 LLM

I'm making LLMs work on small and old devices

AI 导读

作者开源 smolmaxxing 项目,通过自定义 kernel、内存优化和权重流式加载,让小米电视盒子 S(3rd Gen,约 1 GB 可用内存)运行 260K 到 16B 参数的模型,其中 Qwen3.5-2B 在真实对话中达 7.7 tok/s,Moon-Beam-8B-A1B 达 7.2 tok/s。

正文 · AI 翻译

🤏 smolmaxxing: run the biggest model you can on the smallest hardware you own

你身边的每台设备都比看上去更能干。电视盒子、旧手机、单板计算机和路由器都配有 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)。

The live token-stream page served by llama-server on the TV box

设备

设备 状态
小米盒子 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 设备都能使用流式引擎。

Best generation speed per size class on the two 1 GB devices: 2B class TV 7.7 (Qwen3.5-2B) vs iPad 23.7 (Bonsai-1.7B, 1-bit); 4B 4.3 vs 9.4; 8B dense 5.2 vs 0.08; 8B MoE 7.2 vs 3.5; 16B MoE 5.1 vs 4.5 with the same cache bias

排行榜

Best model per size class, first run on the TV box to now: 0.8B 7.5 to 16.8 tok/s, 2B 0.1 to 7.7, 4B 2.2 to 4.3, 8B dense 1.21 to 5.2, 8B MoE 1.87 to 7.2, 9B 0.16 to 0.27, 16B MoE 4.1 to 5.1; and where one Moon-Beam token's 144 ms go

类别 最佳模型 首次运行 → 现在(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 两行是在最新构建上测得的。其他行早于下文的注意力和采样器工作。

Best model per size class on the iPad Air, first run to now: 1.7B 2.75 to 23.7-25.8 tok/s; 4B 9.4-11.4; 8B dense 0.08; 8B MoE can't load with stock llama.cpp, then 1.6 to 3.5 (5.0 with 4 experts); 16B MoE can't load, now 2.6 (4.5 with bias 0.3); and where one Moon-Beam token's ~0.3 s go

类别 最佳模型 首次运行 → 现在(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 % 困惑度)。

Speed against perplexity cost for Moon-Beam-8B-A1B and Ling-mini-2.0 on the iPad: Moon-Beam 3.5 tok/s at no cost up to 5.0 at +27 %; Ling 2.6 at no cost, 3.3 at +2.6 %, 4.5 at +8.5 %, 5.2 at +17 %

值得了解的局限。 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