我拿同一份权重和 llama.cpp 正面比了一场:我手写的 C 内核,慢了 1.1–1.7 倍
作者:sunny-cx 陈旭
项目:SunnyNet — 面向 CPU 的 O(N) 线性递推推理运行时(Apache-2.0)
全部数字本机实测。测试机 i7-8750H(Coffee Lake,6C12T,AVX2,无 AVX-512 / 无 VNNI),
对照组 GPU 为 GTX 1060 6GB。原始数据与复现命令在仓库docs/与experiments/results/*.json。标题这句话要拆开看:慢的是同权重同精度的对照——单线程约 1.1×、6 线程约 1.4–1.7×。
在此之前,我所有对外讲的速度都是"对自家 numpy 快 5–18 倍",那是内部倍数,不是外部对照。
这篇把两种口径都摊开讲。
一、先给结论
这一轮我把四个外部线性架构的整模型前向逐个搬进 C 内核。搬完之后,五个数据点排在一起,规律很干净:
| 架构 | 权重(fp32) | numpy ms/step | C ms/step | C 倍数 |
|---|---|---|---|---|
| Mamba-2 130M | 0.52 GB | 47.36 | 34.59 | 1.37× |
| DeltaNet 340M | 1.37 GB | 78.69 | 71.24 | 1.10× |
| GLA 340M | 1.37 GB | 74.92 | 74.15 | 1.01× |
| HGRN2 1.3B | 5.46 GB | 262.44 | 203.33(8 线程) | 1.29× |
| RWKV-7 191M | 0.73 GB | 366.36 | 48.88(8 线程) | 7.49× |
(RWKV-7 那一行口径不同:它的 numpy 参考是逐 head 的 Python 循环加 rank-1 矩阵更新,基线本身就慢,5.39×/7.49× 里有很大一块是"消掉 Python 解释器开销",不是带宽问题。后四行才是同一口径的对照,不能混着说。)
后四行里,收益由「权重字节数 ÷ 可用带宽」决定,与内核写得好不好基本无关。
本机 AVX2 单线程顺序读上限实测 18.63 GB/s,多线程 30.45 GB/s。拿这个数去算理论下限:
- DeltaNet / GLA 权重 1.37 GB,单步至少读一遍 →
1.37 ÷ 18.63 ≈ 73.5 ms。实测 numpy 74.92 ms、C 74.15 ms,两条路径都已经贴在这条线上。C 化没有余量可拿。 - Mamba-2 权重 0.52 GB → 下限 27.9 ms,实测 34.59 ms,还差一截,所以有 1.37×。
- HGRN2 权重 5.46 GB → 单线程下限
5.46 ÷ 18.63 ≈ 292.9 ms,实测单线程 382 ms。
一句话:整模型解码的 C 化收益上限 = 1 − numpy 基线的访存效率。当 numpy 已经跑在带宽上限附近时,你的 SIMD 写得再漂亮也是零。
二、最不好看的那组数:和 llama.cpp 正面比
之前所有 RWKV-7 的速度数字都是"C 内核 vs 自家 numpy",这不是外部对照。我把唯一有公信力的口径补上了:拿同一份 GGUF,和 llama.cpp 的 CPU 后端比。
同一权重源 Mungert/rwkv7-191M-world-GGUF,两边都从它出发:llama.cpp 直接读 gguf(另有它自己的 llama-quantize 转出的 F32 / Q4_0),SunnyNet 走自己导出的 blob(fp32 / INT4)。llama.cpp 用 b11889(Clang 20.1.8 构建,llama-bench,进程内自带 warmup,-r 5 取中位);SunnyNet 用自身 C 内核,建好状态后单步、60 步取中位。每格独立子进程,多轮之间逐轮交错。
本机在持续负载下滑动降频,同配置相邻两轮能差一倍。所以倍数只看逐轮配对的轮内比值,绝对值仅作参考。
(1)单线程(7 轮)
| 实现 | ms/token | 权重读取 | 有效带宽 |
|---|---|---|---|
| llama.cpp bf16 | 35.7 | 384 MB | 10.75 GB/s |
| llama.cpp F32 | 52.8 | 723 MB | 13.69 GB/s |
| SunnyNet fp32 | 61.0 | 764 MB | 12.52 GB/s |
| llama.cpp Q4_0 | 14.5 | 127 MB | 8.76 GB/s |
| SunnyNet INT4 | 16.8 | 282 MB | 16.83 GB/s |
| 逐轮配对 | 倍数 | 逐轮占优 |
|---|---|---|
| SunnyNet fp32 vs llama.cpp F32(同 fp32) | 0.90× | 1/7 |
| SunnyNet INT4 vs llama.cpp Q4_0(同 4-bit) | 0.89× | 0/7 |
| SunnyNet INT4 vs llama.cpp bf16(跨精度) | 2.12× | 7/7 |
(2)6 线程(5 轮)
| 实现 | ms/token | 有效带宽 |
|---|---|---|
| llama.cpp F32 | 37.1 | 19.49 GB/s |
| SunnyNet fp32 | 61.0 | 12.52 GB/s |
| llama.cpp Q4_0 | 9.1 | 13.93 GB/s |
| SunnyNet INT4 | 13.1 | 21.51 GB/s |
| 逐轮配对 | 倍数 | 逐轮占优 |
|---|---|---|
| SunnyNet fp32 vs llama.cpp F32 | 0.58× | 0/5 |
| SunnyNet INT4 vs llama.cpp Q4_0 | 0.71× | 1/5 |
结论(与既有叙事相反,如实记录):同权重同精度下,llama.cpp 的 CPU 后端比我的 C 内核快——单线程约 1.1×、6 线程约 1.4–1.7×。此前"对 numpy 5.39×"是自家实现的内部倍数,不能拿来对外宣称领先外部引擎。
差距定位在两处,都是工程问题,不是物理墙:
- 单线程已贴带宽墙。 SunnyNet fp32 达 12.5 / llama.cpp 13.7 GB/s,两者都在顺序读上限附近,所以单线程差距只有约 10%。剩下的差距来自 llama.cpp 对 F16/BF16 权重做了 SIMD 向量化取指和 repack(它的
ggml-cpu-haswell后端),而我的 GEMV 是标量cvtph_ps展开。 - 多线程差距扩大。 llama.cpp 6 线程带宽 19.5 GB/s,我只有 12.5——它按行块切分且线程间无重复读,我的行主序并行没把带宽吃满。
(SunnyNet INT4 的带宽数值反而偏高,是因为 282 MB 是含 fp32 嵌入表的实际字节,量大头在 INT4 矩阵;按有效字节折算已超过顺序读上限,说明它读的不全是 DRAM,部分命中了小矩阵的 L2。这不改变"比 llama.cpp Q4_0 慢约 1.1–1.4×"的结论。)
边界:单机、单模型(191M)、单序列、B=1;llama.cpp 侧不含 KV cache 与 prefill;它用官方预编译 Haswell 后端(含 F16C/AVX2,未启用 AVX-512)。结论不外推到其他架构,也不声称在其他机器上倍数不变。
三、逐架构搬,逐个撞墙
搬的顺序是按权重从小到大,收益正好反过来。
Mamba-2 130M(d_model 768 / 24 层 / 24 head × 64)。它的每 head 状态数学上是 (head_dim=64, state_size=128) 矩阵,但衰减 dA = exp(dt·A) 对 (p,n) 全同、外积可分解,实际退化成元素级递推,不需要矩阵-向量乘积,所以能直接复用原有的 FMA/门控内核:
dA = exp(dt_h · A_h)
S_t = S_{t-1} ⊙ dA + (dt_h · B_g) ⊗ x_h
对照 transformers 的 Mamba2ForCausalLM 整段前向,max|diff| 5.875e-04、argmax 24/24。
这个 5.9e-04 得先排除公式错误。官方 fp32 自身相对 fp64 就偏离 3.814e-04,而本实现相对 fp64 只偏离 2.518e-04——比官方 fp32 更接近真值。差异是单精度累积,不是数学错。
速度 47.36 → 34.59 ms(1.37×,5/5 逐轮占优)。权重 0.52 GB 只有 DeltaNet 的 38%,两条路径都没贴到 18.63 GB/s 上限,所以还能赚。
DeltaNet 340M(hidden 1024 / 24 层 / 8 head × 128,短卷积 4)。真 delta rule,无衰减门:
δ_t = (v_t − S_{t-1}ᵀ k_t) · β_t
S_t = S_{t-1} + k_t ⊗ δ_t
o_t = S_tᵀ q_t
秩 1 形式跟显式 (I − β k kᵀ) S + β k vᵀ 写法的独立实现比对,max|diff| 4.578e-05。这里有个坑:head_k_dim == head_v_dim 时,把 S 乘错一侧不会报维度错,只会安静地算成另一个式子——所以两种写法必须分开验证,不能靠"没报错"当通过。
速度 78.69 → 71.24 ms,只有 1.10×。原因不是代码,是权重 1.37 GB 已经把两条路径都顶到 73.5 ms 的带宽下限上。
GLA 340M(hidden 1024 / 24 层 / 4 head × 128,gate_rank 16)。门控 gk = logsigmoid(·)/16 只作用在 key 维,衰减可分解为按行缩放,状态递推退化成元素级:
S_t = diag(exp(gk_t)) · S_{t-1} + k_t ⊗ v_t
o_t = scale · S_tᵀ q_t, scale = head_k_dim^{-1/2}
速度 74.92 → 74.15 ms,1.01×,4/5 逐轮占优。这就是带宽墙的极端情形:GLA 权重 1.37 GB,理论下限 73.5 ms,numpy 与 C 的实测中位 74.92 / 74.15 都已经贴在这条线上。C 化拿不到任何余量。
四个架构合并起来,规律很硬:权重越大,C 化收益越小。
搬的过程中还定位到一个真实缺陷:GLA 内核里每个 head 都读 v 的第 0 段,而不是自己的 value 段——单步 readout 差 96%,各投影却全对;head_k_dim ≠ head_v_dim 时该错不越界,只会静默算错。
四、5.46 GB 那一档:任何实现都只能等内存读完
HGRN2-1.3B(fla-hub/hgrn2-1.3B-100B,dim 2048 / 24 层 / 16 head,244 张量,1.36B 参数)把这规律推到极端。
这个 checkpoint 不在 transformers 原生支持列表里,所以对照基准是本仓独立手写的 numpy 参考——显式循环矩阵-向量,不借 einsum。它的递推与 GLA 同构(论文原话 "identical recurrent structure"),只是参数化不同。
| 线程 | ms/tok | vs numpy(262.44) |
|---|---|---|
| numpy 参考 | 262.44 | 1.00× |
| C 单线程 | 382.00 | 0.69× |
| C 4 线程 | 221.42 | 1.19× |
| C 8 线程 | 203.33 | 1.29× |
单线程顺序读下限 5.46 GB ÷ 18.63 GB/s ≈ 292.9 ms。实测单线程 382 ms 顺着这条线;8 线程 203 ms 对应 26.8 GB/s,已经贴近多线程上限 30.45 GB/s。
权重 5.46 GB 时,任何实现都只能等内存读完。 1.29× 就是全部可得的余量,而且这 1.29× 主要来自并行度,不是指令级优化。
搬这一档的时候踩到两个真实的加载缺陷,都不是算法问题:
其一,fseek(f, 0, SEEK_END) 探文件长度会静默失败。 mingw 的 long 是 32 位,5.46 GB > 2³¹ 时 ftell 溢出,fseek 返回非零,加载函数直接返回 NULL 而不给任何原因——表现为"文件明明在,就是读不出来"。
其二,5.46 GB 的 fp32 blob 不能 malloc + fread。 本机物理内存 15.87 GB、空闲 5.79 GB,复制进堆要再占 5.46 GB,叠加导出期的峰值就段错误。改用 MapViewOfFile / mmap 只读映射,由页缓存共享,只有真正读到的页占内存。对边缘端部署来说这是必要条件,不是优化。
五、把这条线反过来用:压读取字节
既然收益 = f(权重字节数 ÷ 带宽),那 5.46 GB 的权重要提速,唯一杠杆就是少读字节。
把 RWKV-7 上验证过的分组 INT4 GEMV(runtime/quant.c,block=64,scale = amax/7)接到 HGRN2,再推广到 GLA 与 DeltaNet。每个 GEMV 矩阵前置一个 int32 格式标签(1=INT4,0=fp32),向量与嵌入表不量化(嵌入是查表,不是乘加)。
| 架构 | blob fp32→INT4 | 8 线程 fp32→INT4 | 加速 | 相对误差中位 | argmax |
|---|---|---|---|---|---|
| HGRN2-1.3B | 5457.6 → 993.4 MB(5.49×) | 203.33 → 72.19 ms | 2.82× | 0.242 | 20/36 |
| GLA-340M | 1366.8 → 305.8 MB(4.47×) | 66.54 → 33.83 ms | 1.97× | 0.257 | 19/36 |
| DeltaNet-340M | 1366.4 → 306.7 MB(4.46×) | 70.91 → 35.30 ms | 2.01× | 0.243 | 33/36 |
HGRN2 的理论下限从 293.2 ms 压到 53.3 ms,实测 72.19 ms。
精度如实给。分组 INT4 取 scale = amax/7,理论相对误差约 0.071,单矩阵实测 0.097–0.168(cos 0.993)。整模型逐 token 相对误差中位 0.242,逐层探针显示 layer 0 单步即 0.189、层间不放大,所以差异全部来自量化本身,不是状态累积。
RWKV-7 191M 那条链路的三级对照也很直观:
| 后端 | ms/token |
|---|---|
| numpy fp32 | 530.58 |
| C fp32 | 86.55 |
| C INT4 | 28.21 |
INT4 / fp32 = 3.07×,INT4 / numpy = 18.81×。
真实文本贪心续写的表现:
| prompt | fp32 | INT4 |
|---|---|---|
| The capital of France is | Paris. |
Paris. |
| Water is made of hydrogen and | oxygen. |
oxygen. |
| The theory of relativity was proposed by | Albert Einstein in 1905. |
Albert Einstein in 1915. |
| The sun rises in the east and sets in the | west. |
west. |
首词和语义全部保持,退化表现为重复倾向和事实细节错(1905→1915)。不声称质量无损——4 bit 想压住质量得配校准。我试过把敏感矩阵保 fp32,实测无改善,说明误差是多矩阵分布式的,不集中在某一类。
六、于是我把它从 6 个架构砍到了 2 个
既然收益由权重字节数决定,那么"支持得多"和"跑得快"就是两个目标。我选了后者。
现在支持列表只剩 RWKV-7 与 Mamba-2。GLA / DeltaNet / HGRN2 移出——不是因为写不出来,三者的整模型 C 内核都跑通了、数值契约全过、上面的数据都是它们的真实读数。移出是因为:权重均 ≥1.37 GB,C 化收益已经贴到带宽墙(1.01× / 1.10× / 1.29×),边际价值低。
仓库里给这件事写了一句话,我觉得比任何解释都清楚:
2 个"CPU 上公认最快"胜过 6 个"支持但都不最快"——后者是玩具合集,前者是行业标准。
同一轮里,路线边界也从四条扩到六条。新增的两条是:
- 不维护自有权重格式:长期以 GGUF(或 safetensors + HF 标准)为权威格式,自有
.runtime.bin只作本地缓存。 - 热路径不迁回 Python/PyTorch:护城河是无 PyTorch 的 C 内核。
顺带还补了一条 fp16 权重解码路径:载入时把 5 个 GEMV 矩阵与 LM head 截断为 fp16,小参数仍 fp32,单步实读 467.6 → 约 222.3 MB。内核一次读 16 个 half(32 B)后转 fp32 做 FMA,保持与 fp32 相同的加载宽度。实测单步 24.67 → 18.60 ms/token(1.33×),logits max|diff| 4.181e-03、argmax 64/64。fp32 仍是默认,逐位不变。
七、顺带说清了 CPU 的出路在哪
搬内核的过程中,顺手把"CPU 上到底能做什么"做成了判决。四条候选路线,逐条给机制、实测、判定。
路线一,稀疏 / 条件计算:走通,且是 CPU 唯一结构性占优区。
同负载稠密时,CPU / GPU 绝对耗时比 13.15×;压到 E32 专家时只剩 3.88×。B=1 解码(最决定性的一格):CPU 有 2.53×(E8)/ 3.19×(E16)红利,而 GPU 在 E8 起反而变慢(0.91×、0.64×)——单序列解码时 GPU 每个专家 kernel 的启动开销摊不薄,CPU 可以。
但机制不是通常以为的"CPU 分支便宜",这个假设被实测证伪了:gather 的 CPU/GPU 比是 18.2×,高于稠密 GEMM 的 8.6×——CPU 的 gather 相对更贵。真正的机制在 GEMM 效率随行数 M 的曲线:
| M(路由到该专家的 token 数) | CPU GFLOPS | CPU 占峰值 | GPU GFLOPS | GPU 占峰值 |
|---|---|---|---|---|
| 16 | 77.3 | 31.4% | 204.2 | 6.8% |
| 1024 | 225.6 | 91.6% | 1732.6 | 57.3% |
| 4096 | 246.2 | 100% | 3024.2 | 100% |
CPU 从 M=16 到 4096 涨 3.2×,GPU 同区间涨 14.8×。稀疏产生的是"多而小"的 GEMM,CPU 在小 M 下的相对效率是 GPU 的 4.65 倍——不是分支便宜,是 CPU 在填不满 SIMD 宽度时掉得慢。
有一条负结果必须记下:端到端不兑现。同样的真实训练循环,MoE(E=8)跑 0.4932 ms/token、loss 6.72,稠密 MLP 跑 0.4362 ms/token、loss 5.71——稀疏反而慢 13% 且质量更差,因为逐专家循环的索引和 index_add 在反向被放大。所以稀疏的落点是纯前向路径,不是训练反向。
路线二,缓存驻留:堵死。 工作集从 0.98 MB 涨到 7.86 MB,ms/token 全程平坦在 0.12–0.13。训练步的瓶颈是每 token 的算子调度,不是缓存。
路线三,算子分解:堵死。 把大 GEMM 拆成 K 个小 GEMM,K=32 时 CPU 损失 1.30×,GPU 只损失 1.07×。CPU 反而不耐分解——跟"CPU 适合多而小的任务"的直觉相反。
路线四,B=1 长上下文:走通,且是唯一已证"CPU 胜 GPU"的区间。
同栈参数,两边都走单步 + KV cache:
| T | SunnyNet 单步 | Transformer 单步 | Transformer/SunnyNet |
|---|---|---|---|
| 128 | 5.10 ms | 3.09 ms | 0.606× |
| 2048 | 4.96 ms | 5.06 ms | 1.021×(交点) |
| 8192 | 7.11 ms | 21.13 ms | 2.971× |
SunnyNet 单步基本平坦(O(1)),Transformer 随 T 线性爬升,交点 T≈2048,T=8192 时快 2.97×。
顺便证伪一个常见说法。"CPU 访存受限、GPU 算力受限"——实测两者 FP32 GEMM 的 FLOP/字节几乎相同:i7-8750H 是 18.7,GTX 1060 是 18.8。GPU 算力高 13×,带宽也高 13×,代数和相抵。瓶颈不在"哪类资源",在"问题规模能不能填满该资源"。
以及一条必须老实说的:CPU 训练达不到 GPU 速度。同一份代码同一架构,训练步落后 9.9–12.5×,前向 8.0–15.2×。这是硬件结构性差距,不是实现问题。
八、质量问题:先排除误判,再定位根因
外部有人拿 Kaggle 上的运行结果说输出"不连贯"。查下来是两个独立原因,其中一个我一开始读错了,得纠正。
先说读错的那个。 我最初从收敛 checkpoint 上测得"不同输入末位 logit 成对余弦 0.98",据此判"输出坍缩"。加上同规模对照才发现——0.98 里约 97% 来自与输入无关的公共分量(语言模型在低预算下的 unigram 偏置)。
| 指标 | SunnyNet 基线 | +关联记忆(每层) | Transformer |
|---|---|---|---|
| 末位 logit 成对余弦 | 0.98 | 0.96 | 0.973 |
| 去均值后余弦 | −0.03 | −0.02 | −0.031 |
| 公共分量能量占比 | 0.975 | 0.961 | 0.967 |
| 32 输入 argmax 去重数 | 27 | 26 | — |
去均值后余弦 ≈0,32 个互不相同的输入给出 27 个不同 argmax。Transformer 的读数与 SunnyNet 完全同量级。这项是所有架构在低预算下的共性,不是架构缺陷。
然后是真实的两个根因。
根因一,训练预算不够。 外部那次是 102.1M 参数跑了 98.3M token,预算是 0.96 token/参数,Chinchilla 建议 20——缺口 20.8×,而且只用 4.34M token 的单域,数据被反复咀嚼 22 遍。
根因二,元素级状态的召回容量上限。 状态是逐通道标量,MQAR 探针直接量出上限:
| 键对数 | 递推 acc | 注意力 acc |
|---|---|---|
| 2 | 0.0469 | 0.9336 |
| 4 | 0.1211 | 0.6094 |
| 8 | 0.1133 | 0.2578 |
2 对键值上递推只有 4.7%(随机是 1/64 = 1.6%),注意力 93.4%。固定维度的逐通道状态,容量天然有限。DeltaNet / RWKV-7 用逐 head 矩阵值状态,容量高一个量级。
应对:给主状态加一条矩阵值关联记忆支路:
S_t = p ⊙ S_{t-1} + (1-p) ⊙ (v_t ⊗ k_t), o_t = W_o(S_tᵀ q_t)
注入项跟主状态同为凸组合,S 有界,且能整段分块扫描复用。没用 rank-1 校正——召回略高,但必须逐 token 串行,会毁掉 O(N) 的并行优势。
按层成本:关闭 1.00× / 每 4 层 1.26× / 每 2 层 1.46× / 每层 1.93×,约每层 +22%。
召回容量对层数非单调(4 对键):
| 配置 | 4 对键召回 | 训练成本 |
|---|---|---|
| 关闭 | 0.121 | 1.00× |
| 每 4 层 | 0.441 | 1.26× |
| 每 2 层 | 0.656 | 1.46× |
| 每层 | 0.164 | 1.93× |
全开又慢又差(每层 0.164 反而不如每 2 层的 0.656)。当前最优形态是半量开启。
同预算收敛对照(四个模型都训到 32.8M token ≈ 19.5 token/参数,栈参数对齐、同 seed、同 lr 调度):
| 模型 | 栈参数 | zh_ancient ppl | near 召回 | 生成 |
|---|---|---|---|---|
| SunnyNet 基线 | 365,844 | 143.24 | 0.023 | 句式可辨、语义漂移 |
| +关联记忆(每层) | 489,748 | 133.36 | 0.019 | 不连贯 |
| +关联记忆(每 2 层) | 427,796 | 138.82 | 0.019 | 古文句式连贯 |
| Transformer | 369,200 | 140.40 | 0.023 | — |
三条读数:
- SunnyNet 基线 vs Transformer,ppl 143.24 vs 140.40(差 2.0%),near 召回都是 0.023。 两者统计接近,不是一方压倒。Transformer 在同预算下同样做不到长距召回。⇒ "不连贯"主要是 32.8M token 的规模问题,不是独有缺陷。
- 关联记忆(每 2 层)把 zh ppl 从 143.24 降到 138.82(−3.1%),栈参数只 +17%,是唯一改善生成连贯度的配置。
- 层间状态坍缩是另一个独立问题,关联记忆不解决:不同输入在逐层状态上的成对余弦从第 1 层的 0.288 升到末层 0.498,加关联记忆后末层 0.495——基本没动。随机初始化基线是 0.004,排除测量噪声。坍缩随深度累积,得另加"抗累积"手段。
九、边界与负结果
不想被当成"又一个宣称自己很快的仓库",所以把不成立的地方列全:
- 同权重同精度下,llama.cpp 的 CPU 后端比我快——单线程约 1.1×、6 线程约 1.4–1.7×。此前所有"快 X 倍"都是对自家 numpy 的内部倍数。
- CPU 训练达不到 GPU 速度,落后 9.9–12.5×。CPU 胜 GPU 的唯一已证区间是 B=1 长上下文单序列解码(交点 T≈2048)。
- 整模型 C 化收益由带宽决定,权重 1.37 GB 时趋近于零(GLA 1.01×),5.46 GB 时单线程甚至比 numpy 慢(0.69×)。
- 稀疏的端到端不兑现(慢 13% 且质量更差),落点只在纯前向。
- 缓存驻留与算子分解两条路线判死,依据是平坦曲线与 K=32 的 1.30× 损失。
- INT4 不声称质量无损:相对误差中位 0.24–0.26,argmax 19–33/36,退化表现为重复倾向与事实细节错(1905→1915)。
- 矩阵值内核算子级 4.25×,但只占 DeltaNet 单步 2.2%,不能据此声称端到端加速。
- 同预算对照只有 32.8M token,约 19.5 token/参数,仍远低于成熟训练的预算量级。
- AVX-512 与 NEON 只验证到产物:本机实测 AVX512F=0,无 AVX-512 CPU 也无 ARM 工具链,都是交叉编译 + 反汇编验证(198 处 zmm 寄存器 / 4-lane
fmla),未验证真机执行正确性与吞吐。 - 0.5B 只有单步可行性(6GB 卡上 SGD 能跑,AdamW OOM 需要 7.6 GB),无多步收敛数据。
- 未做的:端侧代码补全小模型(与"不再训练新模型"口径冲突)、Ollama 本体改造、K-quant 量化器(gguf-py 只读不写,命令显式报错不静默降级)。
作者与仓库
作者:陈旭
一个面向 CPU 的原创序列架构与推理运行时的长期项目。所有数字都是本机实测,包括上面列的十一条负结果——它们和正结果一起放在报告里,没有单独摘出来美化。
- 仓库:GitHub / PyPI 搜 SunnyNet(包名
sunnynet-cx) - 许可:Apache License 2.0
- 实验报告:
docs/(含负面结论与全部原始 JSON) - 赞助支持:爱发电 / sunny-cx
如果这篇让你在自己的机器上发现了不一样的读数,欢迎到仓库开 issue 对表。
权重字节数、带宽、线程数这三个参数一变,结论就可能不一样——这正是上面那条规律的意思。