coreml について
iOS 開発者向けの Swift Core ML 統合スキルです。モデルの読み込み、設定、推論、デプロイを扱い、非同期読み込みや再利用、プロファイリングの方法も説明します。
主な機能
- 01Core ML モデルの読み込みと設定
- 02単一・バッチ推論の実行
- 03MLTensor と MLMultiArray の利用
- 04Vision による画像処理
- 05性能と計算デバイスの分析
- 06モデルのデプロイとメモリ管理
活用シーン
- 01iOS アプリでオンデバイスモデルを実行
- 02画像分類やビジョン推論の実施
- 03複数入力のバッチ推論
- 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 モデルを読み込み、設定し、実行します。このスキルでは、モデルの読み込み、予測、MLTensor、プロファイリング、デプロイといった Swift 側の処理を扱います。
対象範囲の境界: Python 側でのモデル変換、最適化(量子化、パレット化、プルーニング)、フレームワークの選定は、
apple-on-device-aiスキルで扱います。このスキルの対象は Swift 統合のみです。
アクターベースのキャッシュ、バッチ推論、画像の前処理、テストなどを含むコードパターンの全容については、references/coreml-swift-integration.md を参照してください。
目次
- モデルの読み込み
- モデルの設定
- 予測の実行
- MLTensor(iOS 18+)
- MLMultiArray の操作
- 画像の前処理
- マルチモデルパイプライン
- Vision との統合
- パフォーマンスのプロファイリング
- モデルのデプロイ
- メモリ管理
- よくある間違い
- レビュー用チェックリスト
- 参考資料
モデルの読み込み
自動生成クラス
.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 など)にコピーしてください。実行時に読み込むモデルをレビューする際は、次の 2 点をあわせて指摘してください。非同期の MLModel.compileModel(at:) は iOS 16+ であること、そしてアプリが起動のたびに再コンパイルしないよう、コンパイル済みモデルをキャッシュする必要があることです。
モデルの設定
MLModelConfiguration で、演算ユニット、GPU アクセス、モデルのパラメーターを制御します。
演算ユニットの選択表
| 値 | 使用するもの | 選択するタイミング |
|---|---|---|
.all | CPU + GPU + Neural Engine | デフォルトです。システムに判断を任せます。 |
.cpuOnly | CPU | 決定論的なテスト、CPU のみのフォールバック、またはプロファイリングの結果、アクセラレーターのポリシー、競合、熱状態、エネルギー予算が制約要因と判明した場合に、制約のある処理で使用します。 |
.cpuAndGPU | CPU + 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(...) は同期処理です。非同期パイプラインでは、モデルの読み込みを非同期にし、その後、予測呼び出しに 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:) を使用してください。predictions(from:options:) は、MLBatchProvider と MLPredictionOptions の両方を渡す場合にのみ使用します。predictions(from:) 単体は、オプションを指定しないバッチ API ではありません。
バッチ処理の前に、代表的な単一入力を検証してください。その後、バッチ出力の件数と順序、特徴量の型、ドメインの不変条件、単一入力の結果との一致を検証します。失敗した場合は、フィクスチャと実機でのプロファイリングを再実行する前に、決定論的な入力、形状、モデル、または設定の問題を修正してください。
状態を保持する予測(iOS 18+)
予測間で状態を維持するモデル(シーケンスモデル、LLM、オーディオアキュムレーター)には、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 であっても、1 つの状態を使った推論が並行実行に対して安全になるわけではありません。同じ状態を使う予測は直列化する必要があります。予測の実行中は、状態バッファーの読み取りや書き込みを行わないでください。独立した各並行ストリームに対して model.makeState() を呼び出してください。MLPredictionOptions が必要な場合、iOS 18+ では非同期の prediction(from:using:options:) オーバーロードも利用できます。この場合も、1 つの状態につき同時に実行できる予測は 1 つというルールが適用されます。
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)
NLP のトークン化やオーディオ特徴量の抽出を含む、高度な MLMultiArray のパターンについては、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 を優先し、On-Demand Resources は既存の ODR プロジェクトでのみ使用してください。ダウンロードしたソースモデルは一度だけコンパイルし、バージョンごとに .mlmodelc を永続化して、最低対応の実機で読み込み、初回および反復予測、ライフサイクルの遷移、メモリをテストしてください。実装の詳細については、デプロイのパターンを読み込んでください。
メモリ管理
- バックグラウンド移行時にアンロードする: アプリがバックグラウンドに移行したらモデルへの参照を解放し、GPU/ANE メモリを解放します。フォアグラウンドに戻ったら再読み込みします。
- モデルインスタンスを共有する: 同じコンパイル済みモデルから複数の
MLModelインスタンスを作成しないでください。共有アクセスを提供するアクターを使用します。 - メモリプレッシャーを監視する: 大規模なモデル(>100 MB)はメモリ警告を引き起こすことがあります。
UIApplication.didReceiveMemoryWarningNotificationを監視し、メモリプレッシャーが発生したらキャッシュ済みモデルを解放します。
ライフサイクルに対応した読み込みとキャッシュの削除を行う、アクターベースのモデルマネージャーについては、references/coreml-swift-integration.md を参照してください。
よくある間違い
避けること: モデルをメインスレッドで読み込む。
推奨: MLModel.load(contentsOf:configuration:) の非同期 API を使用するか、バックグラウンドアクターで読み込みます。
理由: 大規模なモデルの読み込みには数秒かかることがあり、UI がフリーズします。
避けること: 入力とモデルの期待値との MLFeatureValue 型の不一致を無視する。
推奨: 型を正確に一致させます。画像には生データではなく MLFeatureValue(pixelBuffer:) を使用します。
理由: 型が一致しないと、原因の分かりにくい実行時クラッシュや、気づかれにくい誤った結果が発生します。
避けること: 予測のたびに新しい MLModel インスタンスを作成する。
推奨: 一度読み込んで再利用します。モデルのライフサイクル管理にはアクターを使用します。
理由: モデルの読み込みには、多くのメモリと計算リソースが割り当てられます。
避けること: モデルの読み込みや予測に対するエラー処理を省略する。 推奨: エラーを捕捉し、モデルが失敗した場合のフォールバック動作を用意します。 理由: 古いデバイスやリソースが制限された状況では、モデルの読み込みに失敗することがあります。
避けること: すべての処理が Neural Engine で実行されると思い込む。
推奨: MLComputePlan(iOS 17.4+)を使用して、処理ごとのデバイス割り当てを確認します。
理由: 対応していない処理は CPU にフォールバックするため、パイプラインのボトルネックになることがあります。
避けること: Vision + Core ML に渡す前に画像を手動で処理する。
推奨: Vision に前処理を任せるため、CoreMLRequest(iOS 18+)または VNCoreMLRequest(レガシー)を使用します。
理由: Vision は向き、拡大縮小、ピクセル形式の変換を正しく処理します。
レビューチェックリスト
- モデルを非同期で読み込んでいる(メインスレッドをブロックしていない)
- ユースケースに応じて
MLModelConfiguration.computeUnitsを設定している - 予測間でモデルインスタンスを再利用している(毎回作り直していない)
- 利用可能な場合は自動生成されたクラスを使用している(型付きの入力/出力)
- モデルの読み込みおよび予測の失敗に対するエラー処理がある
- 実行時にコンパイルした場合、コンパイル済みモデルを永続的にキャッシュしている
- 正しい前処理のため、画像入力に Vision パイプライン(
CoreMLRequestiOS 18+ またはVNCoreMLRequest)を使用している - 計算デバイスの割り当てを確認するため、
MLComputePlanを確認している(iOS 17.4+) - 複数の入力を処理する際にバッチ予測を使用している
- モデルサイズがデプロイ戦略(バンドル、Background Assets、ODR)に適している
- 対象デバイス(特に RAM が少ない古いデバイス)でメモリをテストしている
- 正確に性能を測定するため、デバッガーを使用せずに予測を実行している
参考資料
- パターンとコード:references/coreml-swift-integration.md
- モデルの変換と最適化(Python 側):
apple-on-device-aiスキルで扱っています - Apple のドキュメント:Core ML | MLModel | MLTensor | MLComputePlan | Background Assets