# 在 iOS App 中使用 Hugging Face 模型 > 把 Hugging Face 模型放进 iOS App 的三条路:现成的 Core ML 包、用 coremltools 转换、或用 MLX Swift 跑语言模型。含 Xcode 步骤、体积、许可证与隐私,Swift 代码均已通过类型检查。 - Canonical page: https://obelisk.club/blog/hugging-face-models-in-ios-apps-core-ml-zh - Author: Peter Zhang - Published: 2026-11-02 - Tags: core-ml, hugging-face, ios, swift, on-device, indie, 中文 如果 Hugging Face 上已有该模型的 Core ML 版本,就下载 `.mlpackage`,拖进 Xcode 项目,然后调用 Xcode 为它写好的 Swift 类。如果模型只有 PyTorch 权重,就用 `coremltools` 转换(`ct.convert`,再 `save("model.mlpackage")`)。如果是语言模型,就改看 MLX Swift。无论哪条路,先读模型卡上的许可证,因为“能下载”不等于“可以免费上架”。为写这篇指南,我从 Hugging Face 下载了一个真实的 Core ML 模型,用 Apple 的 `coremlcompiler` 生成了它的 Swift 类,并在 Xcode 27.1(Swift 6.4)下针对 iOS 18 模拟器 SDK 编译了下面的 Swift 代码。coremltools 那一步来自 Apple 的文档,我没有运行过。 ## 什么模型走哪条路 | 起点 | 做法 | 你要交付的东西 | |---|---|---| | 带 `coreml` 标签、含 `.mlpackage` 的仓库(例如 `apple/` 组织) | 下载后加进 Xcode | App 里编译好的 Core ML 模型,或之后再下载 | | 以 PyTorch 或 TensorFlow 权重发布的模型 | 用 coremltools 转换,再加进 Xcode | 你自己生成的模型包;先确认许可证允许 | | 聊天或文本生成的语言模型 | MLX Swift(`mlx-swift-lm`)配 `mlx-community` 组织的模型 | 一个 Swift 包,加运行时下载的模型 | ## 路线一:现成的 Core ML 包 Hugging Face 的模型卡带有 `coreml` 这类元数据标签,Apple 也在自己的 `apple/` 组织下发布了几个视觉模型的 Core ML 版本。我选了 [apple/coreml-FastViT-T8](https://huggingface.co/apple/coreml-FastViT-T8),一个在 ImageNet-1k 上训练的图像分类器。它的模型卡写明有 400 万个参数,输入是 256 x 256 的图像,Float16 版本的包是 7.8 MB。模型卡自己的说明是用 Hugging Face 命令行工具下载: ```bash huggingface-cli download \ --local-dir models --local-dir-use-symlinks False \ apple/coreml-FastViT-T8 ``` 我改用 `huggingface_hub` 这个 Python 库取回了同样的文件;结果是同一个文件夹 `FastViTT8F16.mlpackage`,外加 `README.md` 和 `LICENSE`。规划之前请先看仓库里到底有什么:有些 `apple/` 仓库放的是较老的 `.mlmodel` 文件而不是模型包,例如 `apple/coreml-resnet-50`。 ### 加进 Xcode Apple 的示例描述了步骤:把模型拖进项目导航栏,在 Xcode 里打开它,就能看到模型类型和预期的输入输出。随后 Xcode 会为模型、输入和输出写好 Swift 接口,并把模型编译成适合设备运行的形式,这才是放进 App 包里的内容。 不打开 Xcode 也能看到它写了什么。对下载的包运行下面的命令,得到了一个 Swift 文件: ```bash xcrun coremlcompiler generate FastViTT8F16.mlpackage gen --language Swift ``` 这个文件为该模型定义了三个类: - `FastViTT8F16Input`,有一个 `image` 属性(256 乘 256 的 `CVPixelBuffer`),以及接受 `CGImage` 或文件 URL 的便捷初始化方法 - `FastViTT8F16Output`,有 `classLabel`(`String`)和 `classLabel_probs`(`[String: Double]`) - `FastViTT8F16`,有 `load()` 和 `prediction(input:)`,同步、回调和 `async` 三种形式都有 下面的代码使用的就是这个生成的类。我用下一节的命令把它和生成的文件一起编译,类型检查通过: ```swift import CoreML import CoreGraphics func classify(_ image: CGImage) async throws -> (label: String, probability: Double) { let model = try await FastViTT8F16.load() let input = try FastViTT8F16Input(imageWith: image) let output = try await model.prediction(input: input) return (output.classLabel, output.classLabel_probs[output.classLabel] ?? 0) } ``` 我编译了它,但没有拿照片跑过预测,所以没有准确率结果可报。模型卡写明这个 Float16 版本相对原始 PyTorch 模型准确率下降 0.9%,并列出了它测得的推理时间(iPhone 12 Pro Max 上 0.79 毫秒,M3 Max 上 0.62 毫秒,主要在神经网络引擎上运行)。这些是模型卡的数字,不是我测的。 ### 或者用 MLModel 加载 Apple 的文档说,多数情况下用生成的封装类就够了,不必接触 `MLModel`;但如果 App 要在用户设备上下载并编译模型,就必须直接使用 `MLModel` 类。这时对下载的文件调用 `MLModel.compileModel(at:)`,再打开编译后的副本。下面这个版本针对 iOS 18 通过了类型检查: ```swift import CoreML import Foundation func loadModel(packageURL: URL) async throws -> MLModel { let compiledURL = try await MLModel.compileModel(at: packageURL) let configuration = MLModelConfiguration() configuration.computeUnits = .all return try await MLModel.load(contentsOf: compiledURL, configuration: configuration) } ``` 检查方法,在终端里运行: ```bash xcrun swiftc -typecheck -parse-as-library \ -target arm64-apple-ios18.0-simulator \ -sdk $(xcrun --show-sdk-path --sdk iphonesimulator) load.swift ``` 我还围绕同一个函数做了一个小的 macOS 命令行工具,对下载的包运行。它打印出了模型的描述:`input image 4 256x256`、`output classLabel 3` 和 `output classLabel_probs 6`(这些数字是 Core ML 特征类型枚举的原始值,不是尺寸)。`computeUnits = .all` 让系统选择处理单元,设备有神经网络引擎时也包括它;Apple 的文档说,App 可能在后台运行或要做其他占用 GPU 的工作时,应使用 `.cpuOnly`。Apple 关于下载模型的指南还说,Core ML 把编译出的模型放在临时位置,所以想复用的话,要把编译后的模型存到永久位置,比如 Application Support;同时也提醒要考虑大模型对 iCloud 备份大小的影响。 ## 路线二:用 coremltools 转换 如果模型没有 Core ML 版本,Apple 的 [coremltools 文档](https://apple.github.io/coremltools/docs-guides/source/convert-pytorch-workflow.html)描述了两步:先用 `torch.jit.trace`(文档中稳定的路径)或 `torch.export` 捕获 PyTorch 模型图,再转换。下面是文档自己的流程,我没有运行过: ```python import torch import torchvision import coremltools as ct # Load a pre-trained model and put it in evaluation mode. torch_model = torchvision.models.mobilenet_v2(pretrained=True) torch_model.eval() # Trace it with an example input. example_input = torch.rand(1, 3, 224, 224) traced_model = torch.jit.trace(torch_model, example_input) # Convert and save as a model package. model = ct.convert( traced_model, inputs=[ct.TensorType(shape=example_input.shape)], ) model.save("newmodel.mlpackage") ``` 文档里的细节:从 Core ML Tools 7.0 起,`convert()` 默认生成 ML program,而 ML program 必须保存为 `.mlpackage`,不能是 `.mlmodel`。权重和中间值默认是 Float16,Float16 精度不够时可用 `compute_precision=ct.precision.FLOAT32` 要求 Float32。对于图像模型,文档建议用 `ImageType` 输入,而不是上面用的 `TensorType`(见它们的 Image Input and Output 页面)。文档还说,新的 `torch.export` 路径在 Core ML Tools 8.0 时大约覆盖 70% 的 PyTorch 算子,所以模型可能转换失败;请保留原模型的测试输入,并比较转换前后的输出。 ## 路线三:用 MLX Swift 跑语言模型 视觉、音频和传统模型,Core ML 是合适的默认选择。对于聊天式的语言模型,`ml-explore` 组织发布了 [mlx-swift-lm](https://github.com/ml-explore/mlx-swift-lm),这是用于构建大语言模型和视觉语言模型工具与应用的 Swift 包。它的 README 说明了如何加入 `Package.swift`、要链接哪些产品,并且可以从 Hugging Face Hub 加载模型。[MLX 指南](/blog/run-hugging-face-models-mac-mlx-zh)介绍了如何先在 Mac 上试同样的模型,`mlx-swift-examples` 仓库里有一个能在 iOS 和 macOS 上运行并下载语言模型的 App。我没有为本文构建过这样的 App,所以不给出 iPhone 上的内存或速度数字。 ## 设备上的体积与内存 我在 Apple 或 Hugging Face 的文档里找不到 iPhone 的内存对照表,所以不会编一个。来源里确实说了这些: - 把模型打包进 App 是最简单的起步方式,但较先进的模型会占用可观的存储。Apple 建议通过 coremltools 的工具使用更低精度的权重(从 32 位降到 16 位,或更低的 1 到 8 位)。 - 如果下载体积仍要更小,Apple 介绍了安装后再下载模型并在设备上编译的做法,例如用户只会用到 App 所支持模型中的一部分时。 - coremltools 文档中另有关于调色板化、线性量化和剪枝的章节,用来压缩权重。 - FastViT 的模型卡列出两个版本,T8 为 7.8 MB,MA36 为 84 MB。选能满足质量要求的最小的那个,并在你支持的最老设备上测试。 ## 上架前检查许可证 Hugging Face 说明许可证写在模型卡的元数据里,并要求使用者尊重它。各个模型卡并不相同,这对要销售的 App 很重要: - `apple/coreml-resnet-50` 标注为 `mit`。 - `apple/coreml-FastViT-T8` 标注为 `other`,带 `license_name: apple-ascl`,仓库里有 `LICENSE` 文件,模型卡要求遵守原始许可证。“other”意味着必须读那个文件;我没有替你解读。 - 转换后的模型是衍生副本,所以原模型的条款随之而来,模型卡若列出训练数据,数据的条款也一样。 把许可证、模型的仓库地址和你下载时的提交记下来,放进发布记录里。 ## 对 App 审核与隐私意味着什么 Apple 的 App Privacy Details 页面把“collect”定义为:把数据传输到设备之外,并让你或合作方能在超过实时处理请求所需的时间内访问它。页面还说,只在设备上处理的数据不算“collected”,不需要在 App Store Connect 的回答里披露。所以,一个在设备上处理照片、从不把照片发往任何地方的模型,可以不把这张照片算进你的数据收集回答。有三点要小心: - 这条规则只覆盖留在设备上的数据。如果你的 App 还会把照片、结果或使用数据发给服务器或第三方 SDK,就要为那部分作答。 - 运行时下载模型是一次网络请求。请求本身会带出 IP 地址之类的信息,所以要看清楚你把模型放在哪里、托管方会保留什么。 - 每个 App 仍然需要隐私政策链接,哪怕它什么都不收集。详见[我的 iOS App 需要隐私政策吗?](/blog/ios-app-privacy-policy-requirements-zh),并用平实的话说明模型如何处理用户的输入。 ## 清理 本文用到的所有文件都放在一个临时文件夹里:模型(7.8 MB)、生成的 Swift 文件和一份编译副本。整个文件夹 16 MB,没有加进任何项目。 ## 来源 均于 2026 年 11 月 2 日阅读。 - [apple/coreml-FastViT-T8](https://huggingface.co/apple/coreml-FastViT-T8),模型包、模型卡、许可证与下载说明 - [apple/coreml-resnet-50](https://huggingface.co/apple/coreml-resnet-50),许可证标签与 `.mlmodel` 文件 - [Integrating a Core ML model into your app](https://developer.apple.com/documentation/coreml/integrating-a-core-ml-model-into-your-app),添加模型与 Xcode 写出的封装类 - [MLModel](https://developer.apple.com/documentation/coreml/mlmodel),封装类与 `MLModel` 接口的区别 - [Downloading and compiling a model on the user's device](https://developer.apple.com/documentation/coreml/downloading-and-compiling-a-model-on-the-user-s-device),`compileModel(at:)` 与保存编译后的副本 - [Reducing the size of your Core ML app](https://developer.apple.com/documentation/coreml/reducing-the-size-of-your-core-ml-app),低精度权重与下载模型 - [MLComputeUnits](https://developer.apple.com/documentation/coreml/mlcomputeunits),处理单元的选择 - [PyTorch Conversion Workflow](https://apple.github.io/coremltools/docs-guides/source/convert-pytorch-workflow.html),追踪、`ct.convert` 与 `save` - [Convert Models to ML Programs](https://apple.github.io/coremltools/docs-guides/source/convert-to-ml-program.html),默认模型类型、精度与 `.mlpackage` 格式 - [Hugging Face Hub 的许可证](https://huggingface.co/docs/hub/repositories-licenses)与[模型卡](https://huggingface.co/docs/hub/model-cards),许可证元数据 - [mlx-swift-lm](https://github.com/ml-explore/mlx-swift-lm) 与 [mlx-swift-examples](https://github.com/ml-explore/mlx-swift-examples),Swift 中的语言模型 - [App Privacy Details](https://developer.apple.com/app-store/app-privacy-details/),“collect”的定义与设备上处理