Laya-CoreML W8 调色板压缩实战:K-means 权重量化带来3.19倍能效的完整过程
【免费下载链接】laya-coremlLocal Laya typed decisions on Apple Core ML and Neural Engine. Validated ports, ~5 ms short decisions on M3 Max, reproducible speed and energy benchmarks.项目地址: https://gitcode.com/gh_mirrors/la/laya-coreml
Laya-CoreML是运行在 Apple Core ML 与神经引擎(Neural Engine)上的本地类型化决策模型:不生成任何文本 token,只对「选择题 / 评分题 / 布尔题」直接输出概率。本文完整复盘其中的W8 调色板压缩(weight-only K-means 权重量化)流程——transformer 主体包从 251.91 MB 压到 129.29 MB,单次短决策 P50 延迟 4.88 ms,整体系统能耗较编译版 MLX FP16 提升3.19 倍。全程无需重训练,每一步都有可复现的精度验证。
调色板压缩是什么:把 FP16 权重换成 8 位查找表
调色板压缩(palettization)是 Core ML 内置的一种只压缩权重的技术,原理类似图片量化:
- 不再逐个数存储 FP16 权重,而是把权重分组,每组共享一张 8 位(W8)查找表;
- 推理时由硬件/编译器从查找表重建浮点权重,激活值仍然是 FP16 计算(它不是 W8A8 全整数量化);
- 效果:卷积权重体积大约减半,精度损失取决于「码本怎么选」。
码本选法有两种:
| 模式 | 码本来源 | 特点 |
|---|---|---|
uniform | 均匀间隔的查找表 | 免费、秒级完成,先跑起来筛 |
kmeans | 分组 K-means 聚类中心 | 离线计算更贵,但能贴合权重真实分布 |
项目里统一由 palettize.py 调用cto.coreml.palettize_weights完成,关键策略是「保守选材」:只对元素数大于 2048 的卷积权重下手(weight_threshold=2048),RoPE 常量、归一化层、注意力计算和主机侧动作头全部保持原样,分组粒度为per_grouped_channel、组大小 32。
为什么均匀 W8 不够好:0.02 精度门挡住了它
压缩之后,验证器 validate.py 会对照原始 FP32 黄金参考执行一组验收门:
- 全部评测题的 argmax 决策一致;
- 最大校准概率误差 ≤0.02;
- 输出有限、token 用量不变;
- 100 次重复调用结果完全一致。
结果有点出人意料——两个均匀 W8 候选都倒在了概率门上:
| L96 变体 | 主体包体积 | 最大概率误差 | 端到端 P50 | 验收门 |
|---|---|---|---|---|
| FP16 基线 | 251.91 MB | 0.002925 | 5.167 ms | ✅ 通过 |
| W8 uniform,组 32 | 129.29 MB | 0.023612 | 4.923 ms | ❌ 失败 |
| W8 uniform,组 4 | 146.06 MB | 0.033858 | 5.420 ms | ❌ 失败 |
| W8 K-means,组 32 | 129.29 MB | 0.014393 | 4.792 ms | ✅ 通过 |
| W6 K-means,组 32 | 96.23 MB | 0.052243 | 4.841 ms | ❌ 失败 |
| W4 K-means,组 32 | 64.52 MB | 0.200221 | 5.001 ms | ❌ 失败 |
均匀查找表假设权重分布「大致均匀」,而真实权重是尖峰状的;K-means 的码本是聚类出来的,误差从 0.0236 直接降到 0.0144,重新跨过了 0.02 的门。这正是「先 uniform 筛、再 kmeans 精修」两步流程的价值。
更值得注意的是 W6 / W4 那一行:它们的 argmax 依然是 59/59 全对,但概率误差飙到 0.052 / 0.200。决策没变不代表概率没变——这个项目保留这些被拒绝的变体作为「精度边界证据」,而不是推荐部署项。
K-means 量化三步走:导出、压缩、验证
整个流程在 ANE_ENGINEERING.md 中给出了可复现命令,核心就是三步:
# ① 生成 W8 K-means 调色板变体(8 个离线工作进程并行聚类) python -m experiments.ane_engineering.palettize \ --package body96/model.mlpackage \ --bits 8 --mode kmeans --group-size 32 --workers 8 \ --output body96-w8km # ② 对压缩后的包跑完整精度验证(自动执行 100 次重复调用) python -m experiments.ane_engineering.validate \ --package body96-w8km/model.mlpackage --length 96 \ --output validation96-w8km.json几个值得注意的细节:
- 哈希溯源:压缩前会校验源包内容与 manifest.json 记录的 SHA256 一致,产物的来源权重、工具版本(coremltools 9.0、kmeans1d 0.4.0)都写进 compression.json;
- 离线成本:这次 K-means 聚类耗时 186.5 秒,是一次性的——推理时没有任何额外开销;
- 验收结果(validation96-w8km.json):59/59 题决策一致,最大概率误差 0.014393,100 次重复调用结果逐位一致,且压缩后计算计划中6,390 个重计算算子依然全部首选 ANE。
3.19 倍能效数据:压缩带来的不只是体积
通过验收的 W8 K-means 候选进入正式的三臂对比(M3 Max,同一检查点、同一批 8 个状态样本,各跑 6 个 20 秒饱和块),完整数据见 ANE_BENCHMARKS.md 与 ane-energy-summary.json:
| 指标 | 编译版 MLX FP16 | ANE FP16 | ANE W8 K-means |
|---|---|---|---|
| 完成决策数(120 s) | 17,184 | 23,961 | 24,453 |
| 端到端 P50 / P95 | 6.94 / 7.39 ms | 4.98 / 5.31 ms | 4.88 / 5.23 ms |
| 平均整机功耗 | 61.39 W | 30.75 W | 27.39 W |
| 每次决策整机能耗 | 0.4288 J | 0.1540 J | 0.1344 J |
| 速度增益 | 1× | 1.39× | 1.42× |
| 能耗增益 | 1× | 2.78× | 3.19× |
两个关键解读:
- 速度只多赚了 2.1%,但功耗再降 11%——W8 的真正收益在能效而非延迟,因为激活仍是 FP16,压缩省的是访存和权重搬运;
- 3.19× = 1.42×(速度)× 2.24×(平均功耗比)。项目明确提醒:能效比不能再乘一次速度,否则是重复计时间;功耗来自 SMC PSTR 传感器的原始采样,是整机估计而非壁面功率,且 65,598 次预测全部与各自后端的热机输出一致。
可以带走的做法:压缩实验的 4 条纪律
- 先筛后精:uniform 8 位便宜到可以当冒烟测试,K-means 只留给通过初筛的候选;
- 用概率门而非决策门:argmax 全对会骗人(W6/W4 都是 59/59),必须卡最大校准概率误差;
- 小步选材:只压大卷积,归一化 / RoPE / 主机侧小权重原样保留,边界清晰好回溯;
- 压缩 ≠ 收益:体积减半不等于延迟减半、能耗减半——每个变体都要重新过计算计划、精度门和同场配对的功耗实测。
最终项目选择发布 FP16 为默认 ANE 包,W8 K-means 作为可选的近似压缩包(容量 B1/L96),两者都通过同一套验收门。完整的边界讨论、被拒绝遥测数据的完整记录(ane-energy-rejected-telemetry.json)以及数学层面的 10× 目标分析(ANE_MATH.md)都在仓库中公开,可逐条核验。
【免费下载链接】laya-coremlLocal Laya typed decisions on Apple Core ML and Neural Engine. Validated ports, ~5 ms short decisions on M3 Max, reproducible speed and energy benchmarks.项目地址: https://gitcode.com/gh_mirrors/la/laya-coreml
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考