将机器学习和 AI 模型部署到 Apple 芯片
Bring your machine learning and AI models to Apple silicon
2024年6月10日
一句话判断
iOS 18 的 Core ML Tools 把模型压缩的粒度从”per-tensor”推到了”per-block”级别——同样压缩到 4-bit,以前图像糊成马赛克,现在几乎无损,这让大模型上 iPhone 变得现实。
这场 Session 讲了什么
Core ML Tools 是苹果开源的 Python 工具包,负责把 PyTorch 等框架训练的模型转换并优化为 Core ML 格式,让模型能在 Apple Silicon 上高效运行。Apple Silicon 的统一内存架构、CPU、GPU 和 Neural Engine 为端侧机器学习推理提供了低延迟高能效的算力基础,但前提是你的模型要能塞进设备的存储和内存限制。今年的更新聚焦在模型压缩和部署能力的三个维度。
第一是压缩粒度的精细化。iOS 17 的 palettization(调色板压缩)只能 per-tensor 级别——整个权重矩阵用一张查找表。对于小模型还行,但当 Stable Diffusion 这种 5GB+ 的大模型压缩到 4-bit 时,16 个聚类中心要映射整个矩阵,精度崩塌。iOS 18 支持 per-grouped-channel palettization,每 16 个 channel 共享一张查找表,4-bit 压缩的 Stable Diffusion 从”生成不了可用图像”变成了”几乎无损”。用 Session 中的实际测试数据来说:同样的 “Cat in a tuxedo, oil on canvas” 提示词,per-tensor 4-bit 生成的图像完全不可辨认,而 per-grouped-channel 4-bit(group_size=16)生成的猫图几乎和 6-bit 版本一样好,模型大小只从 1.29GB 增加到 1.3GB。
第二是压缩技术的组合。以前 pruning(剪枝)和 palettization/quantization 是独立的。现在你可以把稀疏化后的非零权重进一步用 palettization 或 quantization 压缩——sparse palettization 和 sparse quantization 成为可能。两种技术的优势可以叠加。
第三是新增了对 stateful model、transformer 架构优化和 multiple function model 的支持。这些特性让 Core ML 更适合运行大型语言模型和复杂的多阶段推理 pipeline。整个 Session 围绕 model deployment workflow 的”准备阶段”展开——假设你已经有了一个训练好的模型,重点是如何把它优化到最适合目标设备的形态。
值得深挖的点
Per-grouped-channel Palettization:4-bit 压缩的救星
这是今年最实质性的改进。用 Stable Diffusion 的实际数据来说明:Float16 精度下模型超过 5GB,根本不可能在 iPhone 上运行。8-bit palettization 压到一半约 2.5GB,能跑但太大了。6-bit 约 1.5GB 可以在 iPad 上运行。但 4-bit 约 1.3GB,用 iOS 17 的 per-tensor 方式,生成的图像完全不可用。
问题出在哪?Per-tensor 意味着整个权重矩阵(可能有上千个 channel)共享 16 个聚类中心(4-bit = 2^4 = 16 个值)。对于大矩阵来说,16 个值远远不够表达权重的分布。
iOS 18 的解决方案是把 channel 分组,每组 16 个 channel 共享一张查找表。这样一来,每组只需要表达自己那部分 channel 的权重分布,精度大幅提升。代价是多了几张查找表,但存储开销微乎其微——示例中模型大小只从 1.29GB 增加到 1.3GB。
这个改进直接改变了大模型端侧部署的可行性边界。以前你不得不在”模型太大装不下”和”压缩太多精度崩塌”之间做痛苦的选择,现在你可以把大模型压到能装下的尺寸,同时保持接近原始模型的精度。
组合压缩:Sparse + Palettization/Quantization
iOS 18 另一个突破是压缩技术可以叠加使用。以前 pruning 的输出是 Float 精度的稀疏矩阵——非零值还是占很多空间。现在你可以对非零值再做 palettization 或 quantization。
这意味着两个维度上的压缩可以同时生效:空间维度上的稀疏化(很多权重归零,只存非零值)+ 数值维度上的量化(非零值本身也用更少的 bit 表示)。对于存储空间和内存带宽都很紧张的移动设备来说,这种组合压缩的收益是乘法级别的。苹果把这个过程设计成两步流水线:先用 prune_weights() 做剪枝,再用 palettize_weights() 或 linear_quantize_weights() 对非零值做进一步压缩。两步之间模型格式不变,操作很自然。
Session 中特别提到:per-grouped-channel palettization 在 Neural Engine 上性能最佳,4-bit quantization 在 Mac 的 GPU 上做了特别优化,组合压缩的适用场景取决于你的目标设备。
除了压缩技术的进步,Session 还提到了另外两个重要更新。Stateful model 支持是专门为 LLM 等有状态模型设计的——在多轮对话中,模型的 KV cache 等内部状态需要在推理之间保持。以前 Core ML 的 model 是无状态的,每次推理都是独立的。现在你可以在 model 中维护状态,避免了重复计算,这对部署对话式 AI 到 Apple Silicon 上是一个必要的基建改进。Multiple function model 则允许一个 .mlpackage 文件中包含多个可独立调用的函数入口,适合多阶段的推理 pipeline(比如先做 preprocess 再做 inference),减少了模型文件的数量和加载开销。
代码片段
Per-grouped-channel 4-bit Palettization
import coremltools as ct
from coremltools.optimize.coreml import (
OpPalettizerConfig,
OptimizationConfig,
palettize_weights
)
# 配置:4-bit,每 16 个 channel 一组查找表
config = OpPalettizerConfig(
mode="kmeans",
nbits=4,
granularity="per_grouped_channel",
group_size=16
)
opt_config = OptimizationConfig(config)
# 对模型应用压缩
compressed_model = palettize_weights(model, opt_config)
# 结果:1.3GB(per-tensor 4-bit 是 1.29GB)
# 精度:从"无法生成可用图像"提升到"几乎无损"
场景:把 Stable Diffusion 等大模型压缩到移动设备可用的尺寸。坑:group_size 不是越小越好,太小会增加太多查找表的开销,建议从 16 开始实验。
组合压缩:Sparse Palettization
from coremltools.optimize.coreml import (
OpMagnitudePrunerConfig,
OpPalettizerConfig,
OptimizationConfig,
prune_weights,
palettize_weights
)
# 第一步:先剪枝,去掉不重要的权重
prune_config = OpMagnitudePrunerConfig(
target_sparsity=0.5 # 50% 的权重归零
)
pruned_model = prune_weights(model, OptimizationConfig(prune_config))
# 第二步:对非零权重再做 palettization
palettize_config = OpPalettizerConfig(
mode="kmeans",
nbits=4,
granularity="per_grouped_channel",
group_size=16
)
final_model = palettize_weights(pruned_model, OptimizationConfig(palettize_config))
场景:在存储极其紧张的设备上最大化压缩率。坑:pruning 后的模型在推理时需要稀疏矩阵运算的支持,某些算子可能回退到 CPU 执行。
Per-block Quantization(4-bit)
from coremltools.optimize.coreml import (
OpLinearQuantizerConfig,
OptimizationConfig,
linear_quantize_weights
)
# iOS 18 新增的 4-bit 量化,per-block 粒度
config = OpLinearQuantizerConfig(
mode="linear_symmetric",
weight_threshold=2048,
quantization_scheme="quantized_4bit" # 新增 4-bit 支持
)
quantized_model = linear_quantize_weights(
model, OptimizationConfig(config)
)
# 特别优化了 Mac GPU 的推理性能
场景:在 Mac 上部署需要 GPU 加速的量化模型。坑:4-bit quantization 目前针对 Mac GPU 优化,在 iPhone/iPad 上的 Neural Engine 上可能不如 palettization 高效。
最佳实践
新项目:在确定模型架构后就做一次压缩实验矩阵——尝试不同的 bit 数(8/6/4)、不同粒度(per-tensor / per-grouped-channel / per-block)和不同技术(palettization / quantization / pruning),找到精度和大小的最佳平衡点。per-grouped-channel palettization 是大模型的默认选择,group_size 从 16 开始。
已有项目:如果你已经在 iOS 17 上用了 Core ML 的模型压缩,iOS 18 的改进是向后兼容的。你可以用更细粒度的压缩重新训练模型,在保持或提升精度的同时减小体积。苹果建议在 Apple Silicon 的不同计算单元上分别测试——Neural Engine、GPU、CPU 各有擅长的压缩模式。
还有什么值得关注
- Stateful model 支持让 Core ML 可以处理有状态的多轮对话场景,适合部署 LLM。
- Transformer 架构的专用优化在 Core ML Tools 中进一步增强了,对 attention 机制的推理效率有提升。
- Multiple function model 支持让一个 Core ML 模型文件包含多个可独立调用的函数,适合多阶段的推理 pipeline。