资讯详情 14MB 装下 45M 参数:拆解 Needle 的 .cact 单文件与 W4A8 量化魔法
📅 2026/10/10 17:47:49
14MB 装下 45M 参数拆解 Needle 的 .cact 单文件与 W4A8 量化魔法【免费下载链接】needleAutomation foundation model for tiny devices: 2-bit, 8-29 MB, tool calls, ASR, structured extraction and embeddings on phones, wearables, smart homes, robots, cars and microcontrollers.项目地址: https://gitcode.com/GitHub_Trending/needle20/needle当主流大模型以GB 级为单位搬运权重时Cactus Compute 的 Needle 选择把 4500 万参数、分词器和量化码本全部塞进一个 14MB 的.cact二进制里让手机、手表、树莓派和智能家居设备跑起本地工具调用 Agent。社区对它的讨论集中在三个数字上14MB 单文件、W4A8 量化、28MB 运行内存。这篇文章不聊宣传口径直接翻仓库源码把.cact的字节布局、CQ 码本量化的数学、层优先张量布局和 KV 缓存预算逐层拆开看看小到底是怎么设计出来的。仓库的部署导出核心在 导出实现量化数值在 量化模块运行时内存预算在 架构定义。下面所有结论都以这几份源码为准。一、45M 参数如何压进 14MBCQ 码本量化先看量化配置。在 量化模块 顶部写着三个硬编码WEIGHT_BITS 4 ACT_BITS 8 KV_BITS 0这就是W4A8的出处权重 4bit、激活 8bit。需要说明的是这一套配置不是拿个 scaler 一除了事而是 Cactus QuantCQ——一种基于单位球码本 Walsh-Hadamard 变换的结构化量化。导出注释里写得很直白见 导出实现 文件头Format is CQ-WxA8: matmul weights use the per-tensor CQ width selected by the deployment map; norms, Hadamard diagonals, and gates stay FP16.翻译过来参与矩阵乘的权重走 CQ 4bit而 norm 的 scale、Hadamard 对角向量、门控系数这些小张量保持 FP16——它们量级小、数量少不值得为省几个字节引入误差。CQ 的具体编码分两步。第一步把每个 group默认 128 维的权重行做归一化 Walsh-Hadamard 旋转旋转后向量的方向用最近邻匹配到 Lloyd-Max 单位球码本只存码本索引向量的长度L2 norm单独以 FP16 保存。重建公式在 导出实现 中就是一行w_group (codebook_bits[idx] * norm) H # H normalized Walsh-Hadamard(group)码本是离线用 Lloyd-Max 算法在 40 万高斯样本上迭代 200 轮拟合出来的见 量化模块 的_lloyd_max_gaussian并且 2bit/3bit/4bit 三套码本cb2[4] | cb3[8] | cb4[16]拼在一起放进文件头运行时按位宽直接索引。索引本身再用 LSB-first 半字节打包每 8 个索引 OR 进一个 64bit 字低半字节是偶数列——这是 SIMD 解包最友好的一种布局。之所以要用码本 Hadamard 而不是朴素对称量化是因为它对激活分布宽的矩阵更稳旋转后能量集中到少数系数上码本量化只丢方向、保能量重建误差更小而且让 4bit 权重在工具调用这类高确定性任务上接近无损。微调侧也在用同一套数值——cq_ste以直通估计STE把量化写进梯度训练时看到的就是部署时的 W4 权重。二、一个文件装下一切.cact 的字节布局14MB 的关键不只是权重量化了更是一切都在一个文件里、且免解析加载。看 导出实现 的字节布局注释.cact只有三个区段1. 固定头部48 个 u32 字段 rope_theta 一个 f32。它承载完整架构几何tag、张量数、码本长度、KV 窗口与 KV 位宽、词表、d_model、头数、层数、head 维度、最大序列长、Hadamard 规模、mHC 车道数、滑窗宽度、全局注意力层掩码、QKV 因果卷积 taps、engram 槽位/阶数/站点、rope_theta……运行时只读头部就知道整个模型长什么样同一套引擎可以加载任意配置的该架构。2. 无名张量目录。每个记录{dtype, ndim, pad, shape[4], offset, nbytes, group_size, bits}没有任何名字。张量按固定规范顺序排列运行时按位置索引embedding → 逐层的 norm_in/q/k/v/gate/out 等 → final_norm → probe heads → 最后的 RAW 分词器。没有名字就省掉了哈希表和字符串比较加载 顺序扫一遍 44 字节记录。3. 64 字节对齐的张量 blob。每个 blob 从对齐偏移处开始目录里已经存好了 offset运行时按偏移直读。三个区段叠加的效果是整个文件可以被 mmap 或直接链进只读段全程零反序列化。这正是仓库对部署权重的定义——the deployment weights the C inference reads (mmap or linked read-only section; no parsing)。分词器也被焊进文件尾部作为唯一的 RAW 张量一个自包含的 SentencePiece BPE dump含n_pieces、pad/eos/bos/unk id、add_dummy_prefix、byte_fallback以及按 id 顺序排列的(f32 score, u8 type, u16 surface_len, UTF-8 bytes)记录见 导出实现 的_tokenizer_blob和 分词器模块 的CHAT_MARKERS——工具调用的tool_call、schema等标记以 USER_DEFINED 类型内嵌。社区里常被提到的一个不可变由此而来SentencePiece 分词器硬编码在 .cact 归档里导出时从 base archive 里原样取出read_tokenizer_blob无法替换——非英语场景的 token 数会显著膨胀这正是省体积换来的部署约束。三、层优先布局与预转置为 GEMV/GEMM 定制的工作集量化只能省体积能不能快、省内存取决于张量怎么摆。.cact用了两条硬规则注释里写得很明确Weights are PRE-TRANSPOSED to [out, in] so each output row is contiguous along the reduction axis (what a GEMV/GEMM stream wants, and the axis quant groups run along).预转置到 [out, in]输出维的每一行沿规约轴in连续存放。解码阶段是典型的 GEMV——激活向量沿权重矩阵的 in 轴做点积in 轴连续 顺序读取、完美契合缓存和 SIMD预填充阶段是 GEMM同样的布局让每一行就是一条规约流。量化 group 也沿同一轴切解包出的码本索引 norm 直接流式重建无需转置中间态。层优先layer-majorembedding, then all of layer 0s tensors, ..., then final norm。也就是说单层的全部张量q/k/v/gate/out、norm scale、门控……在文件里是物理连续的。推理 kernel 扫描一层时工作集是文件里的一段连续区间配合 mmap 的按页懒加载理论上可以做到走到哪层、缺页到哪层未触碰的层不占物理内存。这正是小内存设备上14MB 文件 28MB 运行内存能成立的空间基础权重不是被复制进堆里而是被映射、被原位读取。配合层优先的是--layers N的阶梯ladder导出同一个 checkpoint 从 2 层到 20 层都是可部署模型见 架构定义 的ladder_slice/ladder_config和 微调模块 的build_main。2 层子网可以塞进比手机更小的设备20 层完整模型留给树莓派级别的主机文件格式完全不变。四、28MB 运行内存KV 缓存预算的硬天花板W4 权重映射只读后运行时最大的浮动变量就是KV 缓存。仓库没有让它失控而是给了它一个明确的字节预算KV_BUDGET_BYTES 11 * 1024 * 1024 512 * 1024 # ≈ 11.5MB见 架构定义。kv_budget_window按这个预算反推上下文窗口对每层注意力per_layer kd vd (kd//KV_GROUP vd//KV_GROUP) * 4字节KV_GROUP32engram 站点另有per_site的固定开销滑动窗口层和全局注意力层分开计算——默认配置里 20 层只有(4, 9, 14, 19)四层做全局注意力global_layers其余层走sliding_window1024的局部注意力。窗口被max(KV_WINDOW_MIN, ...)和min(ctx, max_seq_len)双向钳制保证 KV 缓存永远不超预算。KV 本身也是 8bitkv_bits8int8查询按 head 做 A8 对称量化KV 走逐 head 的 A8 fake-quant和原生注意力 kernel 的数值完全对齐见 量化模块 的a8_fake_quant_kv/maybe_quant_query。而且kv_bits是写死在 blob 头里的——a model quantized for one must be RUN at it用错位宽的运行时 flag 会在数值上悄悄出错所以它跟着权重走。把账加一下14MB 权重mmap 只读、不拷贝 约 11.5MB 的 KV 预算 激活与临时缓冲区总运行内存落在 28MB 量级——这就是社区反复引用的28MB 内存稳定运行背后的工程机制不是碰巧小是每一项都被显式预算掉了。五、从 checkpoint 到 .cact微调与导出的闭环仓库把训练-导出-部署做成了完整闭环见 微调模块needle finetune data.jsonl --epochs 10 --out adapter.safetensors needle build --lora adapter.safetensors --layers 8 --out tuned.cactfinetune只训练 LoRA 适配器目标锁定在注意力层的5 个投影矩阵q_proj, k_proj, v_proj, gate_proj, out_proj见LORA_TARGETS基座冻结。有意思的是评分_score_quantised用cq_ste_params(merged, WEIGHT_BITS)把 LoRA 合并后的权重再过一遍导出所用的 W4 量化再测精确调用率——The float model is not what ships微调好坏以部署数值为准。build则做三件事合并 LoRA、按--layers切阶梯、以 4bit 写.cact并且分词器永远取自发布版 base archiveread_tokenizer_blob微调者无法、也不需要重新训练它。这也带出了三个不可变边界社区文章已反复确认源码里同样可见置信度头不随本地微调训练needle build --lora直接丢弃置信度头此类权重上报的confidence为None见 运行时封装 与build_main分词器硬编码于 .cact无法替换.cact 权重与 C 引擎版本强绑定_weight_generation用文件头 tag0x05E12A83 v2、0x05E12A84 v3选择兼容引擎绝不让 v3 归档跑 v2 引擎。六、一个引擎、三个 C 函数端侧推理桥最后落到怎么跑。Python 包不内置推理逻辑它通过 ctypes 调一个**1MB 的 C 引擎动态库**API 极简见 运行时封装 的_libneedle_load(data, len)把.cact权重整体交给引擎一次加载之后无法换权——the engine cannot unload weightsneedle_init(system, tools_json, tool_index_path)注册系统事实与工具 schema返回 prefix token 数needle_complete(text, ..., buffer, len)返回一个 JSON 信封含function_calls、reasoning、confidence、prefill_tps/decode_tps写入共享缓冲区。lib.needle_complete.argtypes [ ctypes.c_char_p, ctypes.POINTER(ctypes.c_float), ctypes.c_int, ctypes.c_int, ctypes.c_char_p, ctypes.c_int]全程无对象模型、无序列化中间层Python 传 UTF-8 字节引擎把 token 约束到由 schema 编译的字节级文法上保证输出必然可解析——工具调用要么是一个合法的 JSON 调用列表要么是空列表拒绝没有第三种可能。加载微调权重时工作进程 会把引擎放到独立子进程里用长度前缀消息协议通信把一个进程一个模型的约束变成可同时持有的隔离实例。引擎的发布形态是每平台一个文件夹macOS/Windows/Linuxx86_64、ARM64、ARMv7、RISC-V、MIPS、Android、iOS、watchOS、tvOS、WASM 组件全部共享同一套.cact容器见 平台清单 的PLATFORMS与下面的部署图。同一个 14MB 文件映射进哪套引擎就在哪套引擎上跑——这也是 Whistle 语音模型敢蹭同一容器、同一引擎的原因。结论14MB 不是魔法是一连串显式工程决策回头再看标题里的魔法45M 参数压进 14MB靠的是 CQ 码本量化 FP16 小张量W4A8一个文件装下权重/分词器/码本靠的是固定头 无名目录 RAW 附件的自包含布局28MB 运行内存靠的是 mmap 只读映射 层优先物理布局 11.5MB KV 硬预算。每一环都在 导出实现、量化模块、架构定义 里有对应的源码证据没有一项是宣传话术。它同时给出了取舍的代价分词器被焊死、置信度头不可本地训练、权重与引擎版本强绑定、非英语 token 膨胀。小从来不是免费的——Needle 的价值在于把每一分体积都换成了可运行、可微调、可移植的确定性而这正是端侧 Agent 真正需要的工程品质。【免费下载链接】needleAutomation foundation model for tiny devices: 2-bit, 8-29 MB, tool calls, ASR, structured extraction and embeddings on phones, wearables, smart homes, robots, cars and microcontrollers.项目地址: https://gitcode.com/GitHub_Trending/needle20/needle创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考