Highlight
iOS 18 的 per-grouped-channel palettization 让 Stable Diffusion 的 4-bit 压缩从生成噪声恢复到接近无损,体积仅增加 0.8%。
核心内容
把一个 5GB 的 Stable Diffusion 模型塞进 iPhone,听起来不太现实。但 Core ML Tools 的压缩管线一直在缩短这个距离。iOS 17 的 palettization 能把模型压到一半甚至更小,6-bit 时还能正常出图,4-bit 就彻底崩了——16 个聚类中心要映射整个权重矩阵,精度根本撑不住。
iOS 18 把压缩粒度从 per-tensor 推进到了 per-grouped-channel。每 16 个 channel 共享一张查找表,4-bit 压缩下 Stable Diffusion 的体积从 1.29GB 微增到 1.3GB,但生成质量从”不可辨认”恢复到”接近 6-bit”。同一个 “Cat in a tuxedo, oil on canvas” 提示词,两种粒度天差地别。
苹果还做了两件重要的事。第一,剪枝和量化/调色板压缩可以叠加了——sparse palettization 和 sparse quantization 让两种技术的压缩收益并存。第二,新增了 calibration data 辅助的后训练压缩工作流,介于 data-free 和 fine-tuning 之间,用 128 个样本就能让 40% 稀疏化的 Stable Diffusion 从”输出噪声”变回”正常出图”。对大模型来说,fine-tuning 太贵,data-free 太粗糙,calibration 正好补了这个空档。
详细内容
Per-grouped-channel palettization
iOS 17 只支持 per-tensor palettization:整个权重矩阵共享一张查找表。4-bit 时只有 16 个聚类中心,对大矩阵误差过大。iOS 18 允许每 group_size 个 channel 共享一张查找表,大幅提高粒度(07:02)。
import coremltools as ct
from coremltools.optimize import palettize_weights
config = ct.optimize.coreml.OpPalettizerConfig(
mode="kmeans",
nbits=4,
granularity="per_grouped_channel",
group_size=16,
)
opt_config = ct.optimize.coreml.OptimizationConfig(global_config=config)
compressed_model = palettize_weights(model, opt_config)
关键点:
nbits=4:4-bit 压缩,查找表有 2^4 = 16 个聚类中心granularity="per_grouped_channel":每 group_size 个 channel 共享一张查找表,而非整张 tensor 共享一张group_size=16:每 16 个 channel 一组,组数越多查找表越多,精度越高但体积略增- 4-bit per-grouped-channel 压缩后 Stable Diffusion 从 1.29GB 增到 1.3GB,但生成质量接近 6-bit(08:56)
Calibration data 辅助的后训练压缩
Data-free 压缩在高压缩比下精度下降快。Fine-tuning 压缩精度好但耗时长、需要大量数据。calibration 工作流用少量样本做校准,介于两者之间(10:41)。
from coremltools.optimize.torch.layerwise_compressor import LayerwiseCompressor
prune_config = ct.optimize.torch.LayerwiseCompressorConfig(
target_sparsity=0.4,
n_samples=128,
)
pruner = LayerwiseCompressor(model, prune_config)
sparse_model = pruner.compress(calibration_data_loader)
关键点:
target_sparsity=0.4:40% 的权重被剪枝置零n_samples=128:calibration 只需 128 个样本,远少于 fine-tuning 所需calibration_data_loader:用户自定义的数据加载器,提供模型输入格式的样本- 40% 稀疏化后 Stable Diffusion 从 1.3GB 降到 1.1GB,data-free 时输出噪声,calibration 后正常出图(12:52)
稀疏化后还可叠加 palettization 进一步压缩:
from coremltools.optimize.torch.post_training_quantization import PostTrainingPalettizer
palett_config = ct.optimize.torch.PostTrainingPalettizerConfig(
nbits=4,
granularity="per_grouped_channel",
group_size=16,
)
palettizer = PostTrainingPalettizer(sparse_model, palett_config)
sparse_palettized_model = palettizer.compress(calibration_data_loader)
关键点:
- 在已经稀疏化的模型上再做 4-bit palettization,即 sparse palettization
- 同一份 calibration_data_loader 可以复用
- 最终的 PyTorch 模型可以无缝转换为 Core ML 格式
Stateful model 与 KV-cache
Core ML 现在支持 stateful model。状态张量在多次推理间持久化,自动原地更新,不再需要手动把输出复制回输入(15:55)。
这对 Transformer 的 KV-cache 是天然匹配。KV-cache 在每次 token 生成时保存 Key/Value 向量,避免重复计算。用 stateful model 实现后,KV-cache 可以原地更新,大张量不再需要在 I/O 间来回拷贝(18:24)。
转换 stateful 模型时,用 ct.StateType 声明状态:
import coremltools as ct
states = [
ct.StateType(
name="keyCache",
dtype=np.float16,
shape=(1, num_layers, max_seq_len, head_dim),
),
ct.StateType(
name="valueCache",
dtype=np.float16,
shape=(1, num_layers, max_seq_len, head_dim),
),
]
model = ct.convert(
traced_model,
inputs=[...],
outputs=[...],
states=states,
minimum_deployment_target=ct.target.iOS18,
)
关键点:
ct.StateType:新增 API,声明状态张量的名称、类型和形状name="keyCache"/"valueCache":需与 PyTorch 模型中register_buffer使用的名称一致states参数传入ct.convert,转换后的 Core ML 模型自动成为 stateful 模型minimum_deployment_target=ct.target.iOS18:stateful model 需要 iOS 18
SDPA 算子融合
iOS 18 的 Core ML Tools 会将 PyTorch 的 Scaled Dot Product Attention(SDPA)算子整体保留,而非拆散成多个小算子。SDPA 算子在 Apple Silicon GPU 上运行效率更高(19:21)。
Multi-function model
多个 Core ML 模型可以合并为一个 multi-function model,共享权重自动去重。典型场景是同一个 base model 挂不同 adapter(如 LoRA),每个 adapter 对应一个 function,base model 权重只存一份(27:20)。
核心启发
-
做什么:为大模型端侧部署建立 per-grouped-channel 压缩实验矩阵。尝试不同的 bit 数(8/6/4)、group_size(8/16/32)和压缩技术组合(palettization / quantization / pruning),找到精度与体积的最佳平衡。为什么值得做:per-grouped-channel 在 4-bit 下相比 per-tensor 几乎不增加体积就能大幅提升精度,是大模型压缩的默认选择。怎么开始:从
OpPalettizerConfig(nbits=4, granularity="per_grouped_channel", group_size=16)开始,用你的模型跑一轮对比。 -
做什么:将现有的 KV-cache 实现迁移到 stateful Core ML model。为什么值得做:KV-cache 张量通常很大,stateful model 支持原地更新,省去了 I/O 拷贝开销,对 LLM 推理速度有明显提升。怎么开始:在 PyTorch 模型中用
register_buffer声明 KV-cache,转换时通过ct.StateType传入ct.convert,设置minimum_deployment_target=ct.target.iOS18。 -
做什么:用 calibration data 工作流替代 data-free 压缩。为什么值得做:高压缩比下 data-free 压缩精度崩塌,calibration 只需 128 个样本就能恢复可用精度,成本远低于 fine-tuning。怎么开始:准备 128 个典型输入样本,用
LayerwiseCompressor的n_samples=128做 calibration,对比 data-free 和 calibration 后的输出质量。 -
做什么:将多个 adapter 合并为 multi-function Core ML model。为什么值得做:不同 adapter 共享 base model 权重,存储空间从 N 份降到 1 份 + N 个小 adapter,加载和切换也更快。怎么开始:分别转换各 adapter 模型为 Core ML 格式,用
MultiFunctionDescriptor指定合并规则,调用save_multifunction生成合并模型。
关联 Session
- Train your machine learning and AI models on Apple GPUs — 用 Metal 在 Apple Silicon 上训练 PyTorch/JAX/TensorFlow 模型
- Deploy machine learning and AI models on-device with Core ML — Core ML 模型在设备端的性能优化、执行与模型拼接
- What’s new in Create ML — Create ML 框架更新,含交互式数据源预览和目标追踪模板
- Discover Swift enhancements in the Vision framework — Vision 框架 Swift API 重设计,新增图像美学和全身姿态检测
评论
GitHub Issues · utterances