mcpField
C
coreml

coreml

github.com/dpearson2699开发1.2k3.8k 次安装13 周前更新
代码仓库

关于 coreml

面向 iOS 开发者的 Swift Core ML 集成技能,涵盖模型加载、配置、推理与部署,并强调异步加载、模型复用和性能检查。

主要功能

  1. 01加载与配置 Core ML 模型
  2. 02执行单次与批量预测
  3. 03使用 MLTensor 与 MLMultiArray
  4. 04通过 Vision 处理图像输入
  5. 05分析性能与计算设备
  6. 06部署及管理模型内存

适用场景

  1. 01在 iOS 应用中运行本地模型
  2. 02处理图像分类或视觉推理
  3. 03为多个输入执行批量推理
  4. 04检查模型延迟与设备分配

安装

复制下面的命令,在终端中运行。

$npx skills add https://github.com/dpearson2699/swift-ios-skills --skill coreml

安装后在 Claude Code 中输入/coreml确认已加载。

附带文件evals/evals.jsonreferences/coreml-swift-integration.md

详细介绍

Core ML Swift 集成

在 iOS 应用中加载、配置和运行 Core ML 模型。本技能涵盖 Swift 侧的内容:模型加载、预测、MLTensor、性能分析和部署。

范围边界: Python 侧的模型转换、优化(量化、调色板化、剪枝)和框架选择由 apple-on-device-ai 技能负责。本技能仅负责 Swift 集成。

请参阅 references/coreml-swift-integration.md,了解完整的代码模式,包括基于 actor 的缓存、批量推理、图像预处理和测试。

目录

加载模型

自动生成的类

将 .mlmodel 或 .mlpackage 添加到应用目标时,Xcode 会生成带有类型化输入/输出的 Swift 类。尽可能使用这种方式。

import CoreML

let config = MLModelConfiguration()
config.computeUnits = .all

let model = try MyImageClassifier(configuration: config)
手动加载

当模型在运行时下载或存储在包外时,请从 URL 加载。

let modelURL = Bundle.main.url(
    forResource: "MyModel", withExtension: "mlmodelc"
)!
let model = try MLModel(contentsOf: modelURL, configuration: config)
异步加载(iOS 15+)

加载模型而不阻塞主线程。大型模型优先使用此方式。

let model = try await MLModel.load(
    contentsOf: modelURL,
    configuration: config
)
在运行时编译(iOS 16+)

在设备上将 .mlpackage 或 .mlmodel 编译为 .mlmodelc。适用于从服务下载的模型。每个模型版本只需编译一次,而不是每次启动都编译。

let compiledURL = try await MLModel.compileModel(at: packageURL)
let model = try await MLModel.load(contentsOf: compiledURL, configuration: config)

缓存编译后的 URL——每次启动都重新编译是一个错误。将 compiledURL 复制到持久化位置(例如,Application Support)。审核运行时加载的模型时,请一并指出以下两点:异步 MLModel.compileModel(at:) 仅适用于 iOS 16+,且必须缓存编译后的模型,以免应用每次启动时都重新编译。

模型配置

MLModelConfiguration 用于控制计算单元、GPU 访问和模型参数。

计算单元决策表
值用途选择时机
.allCPU + GPU + Neural Engine默认值。由系统决定。
.cpuOnlyCPU用于确定性测试、仅 CPU 的回退方案,或在性能分析表明加速器策略、资源争用、热状态或能耗预算构成限制因素后,处理受约束的工作。
.cpuAndGPUCPU + GPU需要 GPU,但模型包含 ANE 不支持的运算。
.cpuAndNeuralEngine(iOS 16+)CPU + Neural Engine对兼容模型而言,能效最佳。
let config = MLModelConfiguration()
config.computeUnits = .cpuAndNeuralEngine

// Optional fallback for constrained work after profiling and policy review
config.computeUnits = .cpuOnly
配置属性
let config = MLModelConfiguration()
config.computeUnits = .all
config.allowLowPrecisionAccumulationOnGPU = true // faster, slight precision loss

进行预测

使用自动生成的类

生成的类提供类型化的输入/输出结构体。

let model = try MyImageClassifier(configuration: config)
let input = MyImageClassifierInput(image: pixelBuffer)
let output = try model.prediction(input: input)
print(output.classLabel)        // "golden_retriever"
print(output.classLabelProbs)   // ["golden_retriever": 0.95, ...]
使用 MLDictionaryFeatureProvider

当输入是动态的或在编译时未知时使用。

let inputFeatures = try MLDictionaryFeatureProvider(dictionary: [
    "image": MLFeatureValue(pixelBuffer: pixelBuffer),
    "confidence_threshold": MLFeatureValue(double: 0.5),
])
let output = try model.prediction(from: inputFeatures)
let label = output.featureValue(for: "classLabel")?.stringValue
在异步工作流中进行预测

MLModel.prediction(...) 是同步的。在异步流水线中,保持模型加载为异步操作,然后从 actor 或非主线程任务中运行预测,不要在预测调用上添加 await。

let output = try model.prediction(from: inputFeatures)
批量预测

在一次调用中处理多个输入,以提高吞吐量。

let batchInputs = try MLArrayBatchProvider(array: inputs.map { input in
    try MLDictionaryFeatureProvider(dictionary: ["image": MLFeatureValue(pixelBuffer: input)])
})
let batchOutput = try model.predictions(fromBatch: batchInputs)
for i in 0..<batchOutput.count {
    let result = batchOutput.features(at: i)
    print(result.featureValue(for: "classLabel")?.stringValue ?? "unknown")
}

批量处理时,如果不使用显式的 MLPredictionOptions,请使用 predictions(fromBatch:)。只有同时传入 MLBatchProvider 和 MLPredictionOptions 时,才使用 predictions(from:options:);单独调用 predictions(from:) 并不是不带选项的批量 API。

批量处理前,先验证一个具有代表性的单个输入。然后验证批量输出的数量/顺序、特征类型、领域不变量,以及与单输入结果的一致性。如果失败,应先修复确定性的输入、形状、模型或配置问题,再重新运行测试样例和实体设备性能分析。

有状态预测(iOS 18+)

对于需要在多次预测之间保持状态的模型(序列模型、 大模型、音频累加器),请使用 MLState。创建一次状态,并将其传递给每次预测调用。

let state = model.makeState()

// Each synchronous prediction carries forward the internal model state
for frame in audioFrames {
    let input = try MLDictionaryFeatureProvider(dictionary: [
        "audio_features": MLFeatureValue(multiArray: frame)
    ])
    let output = try model.prediction(from: input, using: state)
    let classification = output.featureValue(for: "label")?.stringValue
}

MLState 遵循 Sendable,但 Sendable 并不意味着同一状态可安全地用于并发推理。使用同一状态的预测必须串行执行;预测进行期间不要读取或写入状态缓冲区。对于每个独立的并发流,请调用 model.makeState()。如果需要 MLPredictionOptions,iOS 18+ 也提供了异步 prediction(from:using:options:) 重载;仍须遵循每个状态同一时间只能有一次预测在执行的规则。

MLTensor(iOS 18+)

MLTensor 是用于预处理和后处理的 Swift 原生多维数组。运算采用惰性执行——调用 await tensor.shapedArray(of:) 可将结果物化。

import CoreML

// Creation
let tensor = MLTensor([1.0, 2.0, 3.0, 4.0])
let zeros = MLTensor(zeros: [3, 224, 224], scalarType: Float.self)

// Reshaping
let reshaped = tensor.reshaped(to: [2, 2])

// Math operations
let softmaxed = tensor.softmax(alongAxis: -1)
let centered = tensor - tensor.mean()

// Interop with MLShapedArray / MLMultiArray
let shaped = await tensor.shapedArray(of: Float.self)
let multiArray = try MLMultiArray(shaped)
let shapedAgain = MLShapedArray<Float>(multiArray)

不要臆造用于统计或桥接的 MLTensor API。避免使用 MLTensor(multiArray)、tensor.std()、tensor.standardDeviation()、直接访问惰性缓冲区或同步提取结果等示例;请在张量流水线之外,或使用经源代码确认支持的张量运算,执行不受支持的 DSP/统计操作。

使用 MLMultiArray

MLMultiArray 是非图像模型输入和输出的主要数据交换类型。自动生成的类需要数组类型特征时,请使用它。

// Create a 3D array: [batch, sequence, features]
let array = try MLMultiArray(shape: [1, 128, 768], dataType: .float32)

// Write values
for i in 0..<128 {
    array[[0, i, 0] as [NSNumber]] = NSNumber(value: Float(i))
}

// Read values
let value = array[[0, 0, 0] as [NSNumber]].floatValue

let data: [Float] = [1.0, 2.0, 3.0]
let shaped = MLShapedArray(scalars: data, shape: [3])
let fromShaped = try MLMultiArray(shaped)

高级 MLMultiArray 用法(包括 NLP 词元化和音频特征提取),请参阅 references/coreml-swift-integration.md。

图像预处理

图像模型需要 CVPixelBuffer 输入。对于来自相机或照片图库的照片,请使用 CGImage 转换。Vision 的 VNCoreMLRequest 会自动处理此过程;只有直接使用 MLModel 进行预测时才需要手动转换。

如需完整且经过验证的 CVPixelBuffer 转换方法,以及其他归一化或裁剪模式,请加载图像预处理。

多模型流水线

当预处理或后处理需要单独的模型时,请串联模型。

// Sequential inference: preprocessor -> main model -> postprocessor
let preprocessed = try preprocessor.prediction(from: rawInput)
let mainOutput = try mainModel.prediction(from: preprocessed)
let finalOutput = try postprocessor.prediction(from: mainOutput)

对于由 Xcode 管理的流水线,请使用 .mlpackage 中的流水线模型类型。每个子模型都会在其最适合的计算单元上运行。

Vision 集成

使用 Vision 运行 Core ML 图像模型,可自动进行图像预处理(调整大小、归一化、色彩空间转换和方向校正)。

现代方式:CoreMLRequest(iOS 18+)
import Vision
import CoreML

let model = try MLModel(contentsOf: modelURL, configuration: config)
let request = CoreMLRequest(model: .init(model))
let results = try await request.perform(on: cgImage)

if let classification = results.first as? ClassificationObservation {
    print("\(classification.identifier): \(classification.confidence)")
}
旧版方式:VNCoreMLRequest
let vnModel = try VNCoreMLModel(for: model)
let request = VNCoreMLRequest(model: vnModel) { request, error in
    guard let results = request.results as? [VNRecognizedObjectObservation] else { return }
    for observation in results {
        let label = observation.labels.first?.identifier ?? "unknown"
        let confidence = observation.labels.first?.confidence ?? 0
        let boundingBox = observation.boundingBox // normalized coordinates
        print("\(label): \(confidence) at \(boundingBox)")
    }
}
request.imageCropAndScaleOption = .scaleFill

let handler = VNImageRequestHandler(cvPixelBuffer: pixelBuffer)
try handler.perform([request])

有关 Vision 框架的完整用法(文本识别、条形码检测、文档扫描),请参阅 vision-framework 技能。

性能分析

MLComputePlan(iOS 17.4+)

在运行预测之前,检查每个运算将使用哪个计算设备。如需了解模型结构遍历、设备使用情况和预估成本检查,请加载 MLComputePlan 详细用法。

Instruments

在 Instruments 中使用 Core ML 模板进行性能分析:

  • 模型加载时间
  • 预测延迟(按运算细分)
  • 计算设备分配(每个运算使用 CPU/GPU/ANE)
  • 内存分配

为获得准确结果,请在调试器外运行(Xcode:Product > Profile)。

模型部署

将体积小且离线运行至关重要的模型打包进应用。对于新的大型资源或可更新资源,优先使用 Background Assets;仅在现有 ODR 项目中保留 On-Demand Resources。下载源模型后,按版本编译一次并持久化 .mlmodelc;在支持范围最低的实体设备上测试加载、首次及后续预测、生命周期转换和内存使用情况。如需了解实现详情,请加载部署模式。

内存管理

  • 进入后台时卸载: 当应用进入后台时释放模型引用,以释放 GPU/ANE 内存。返回前台时重新加载。
  • 共享模型实例: 绝不要基于同一个已编译模型创建多个 MLModel 实例。使用 actor 提供共享访问。
  • 监控内存压力: 大型模型(>100 MB)可能触发内存警告。注册监听 UIApplication.didReceiveMemoryWarningNotification,并在内存压力较大时释放缓存的模型。

有关支持生命周期感知加载和缓存淘汰的基于 actor 的模型管理器,请参阅 references/coreml-swift-integration.md。

常见错误

不要: 在主线程上加载模型。 应该: 使用 MLModel.load(contentsOf:configuration:) 异步 API,或在后台 actor 上加载。 原因: 加载大型模型可能需要数秒,导致 UI 卡顿。

不要: 忽略 MLFeatureValue 类型与模型预期类型不匹配的问题。 应该: 确保类型完全匹配——图像使用 MLFeatureValue(pixelBuffer:),而非原始数据。 原因: 类型不匹配会导致难以诊断的运行时崩溃,或悄无声息地产生错误结果。

不要: 每次预测都创建新的 MLModel 实例。 应该: 加载一次并重复使用。使用 actor 管理模型生命周期。 原因: 模型加载会占用大量内存和计算资源。

不要: 跳过模型加载和预测的错误处理。 应该: 捕获错误,并在模型失败时提供回退行为。 原因: 在较旧设备上或资源受限时,模型可能无法加载。

不要: 假设所有操作都在 Neural Engine 上运行。 应该: 使用 MLComputePlan(iOS 17.4+)验证每项操作的设备调度情况。 原因: 不受支持的操作会回退到 CPU,可能成为流水线的性能瓶颈。

不要: 在将图像传递给 Vision + Core ML 之前手动处理图像。 应该: 使用 CoreMLRequest(iOS 18+)或 VNCoreMLRequest(旧版),让 Vision 负责预处理。 原因: Vision 能正确处理方向、缩放和像素格式转换。

审查清单

  • 异步加载模型(不阻塞主线程)
  • 根据使用场景设置 MLModelConfiguration.computeUnits
  • 在多次预测间重复使用模型实例(而非每次都重新创建)
  • 在可用时使用自动生成的类(类型化输入/输出)
  • 针对模型加载和预测失败进行错误处理
  • 如果在运行时编译模型,则持久缓存已编译的模型
  • 图像输入使用 Vision 流水线(iOS 18+ 使用 CoreMLRequest,或使用 VNCoreMLRequest)以确保正确预处理
  • 检查 MLComputePlan,以验证计算设备调度情况(iOS 17.4+)
  • 处理多个输入时使用批量预测
  • 模型大小适合部署策略(bundle、Background Assets、ODR)
  • 在目标设备上测试内存使用情况(尤其是 RAM 较少的旧设备)
  • 在调试器外运行预测,以准确测量性能

参考资料

评论

支持 Markdown