WWDC Quick Look 💓 By SwiftGGTeam
Optimize your Core ML usage

Optimize your Core ML usage

元の動画を見る

ハイライト

Core ML の利用フローは、モデル選択、App への統合、性能最適化の3段階に分けられます。今年の更新はこの3段階すべてをカバーします。

主要内容

Core ML の性能問題は、モデルがすでに動き始めた後に現れることが多いです。予測できることと、リアルタイムカメラ、インタラクティブフィルター、低遅延 UI に適していることは別です。開発者はモデル読み込み時間、1回の予測時間、各レイヤーが CPU・GPU・Neural Engine のどれで動くかを把握する必要があります。

この Session は Core ML の利用を3段階に分けます。モデル選択、モデル統合、利用方法の最適化です。Xcode 14 の model viewer には Performance タブが追加され、App コードを書く前にモデルを実機へ送り、コンパイル、読み込み、予測の性能レポートを生成できます。

モデルが App に入った後、ボトルネックはより具体的になります。デモのスタイル転送 App はフレームレートが低く、Core ML Instrument では予測合計時間を上回るモデル読み込み合計時間が表示されました。原因はモデル属性が computed property になっており、予測のたびに再読み込みされていたことです。lazy var に変更すると、読み込み回数はスタイルごとに1回に戻りました。

API 面では、iOS 16 と macOS Ventura で Float16 入出力、output backing、cpuAndNeuralEngine compute unit、ML Program 重み圧縮、メモリ上のモデル読み込み、Swift Package 内の Core ML モデル自動コンパイルとパッケージングが追加されました。共通の目標は、データ変換と再割り当てを減らし、モデル配布を容易にすることです。

詳細

Performance Report でモデルがシナリオに適合するか判断する

03:39)以前はモデル性能評価のために、まず App に統合するか小さなプロトタイプを書いて Instruments で計測するのが一般的でした。Xcode 14 ではこれを model viewer へ前倒しできます。

Performance タブの流れは、ターゲットデバイス選択、Core ML compute units 選択、Run Test のクリックです。Xcode はモデルをデバイスへ送り、compile、load、prediction を複数回実行してレポートを生成します。

デモの YOLOv3 モデルは iPhone で中央値予測時間 22.19 ms、中央値読み込み時間約 400 ms、デバイス上コンパイル時間約 940 ms でした。22 ms の予測時間はリアルタイム動画でおよそ 45 FPS に相当します。

Performance タブデモからの概念フロー:

1. ターゲットデバイス選択: iPhone
2. compute units 選択: All
3. テスト実行: Run Test
4. レポート確認:
   - median prediction time
   - median load time
   - compilation time
   - layer placement on CPU / GPU / Neural Engine

キーポイント:

  • ステップ1は Core ML 性能がデバイス依存であるため、実機でテストします。
  • ステップ2は Core ML が使える計算ユニットを制御します。
  • ステップ4の prediction time はリアルタイム性、load time と compilation time は起動や初回利用コストの判断に使います。
  • layer placement は各レイヤーの実際の実行ユニットを示します。デモでは GPU 54 レイヤー、Neural Engine 32 レイヤーでした。

Core ML Instrument で App 内の実ボトルネックを見つける

07:32)Performance Report は単体環境での能力しか示しません。App に入った後は、呼び出し方が時間を無駄にしていないかも確認が必要です。

Xcode 14 の Instruments には Core ML テンプレートが追加されました。Core ML Instrument を含み、他の Instruments と組み合わせてモデル実行を分析します。Core ML Instrument は Activity、Data、Compute の3種類にイベントを分類します。

  • Activity は load や prediction など、開発者が直接呼ぶ Core ML API に対応します。
  • Data は Core ML が入出力に対して行うデータチェックや変換を示します。
  • Compute は Neural Engine や GPU へ送る計算リクエストを示します。

デモのスタイル転送 App では、Aggregation ビューで load 合計 6.41 秒、prediction 合計 2.69 秒でした。この比率は、単回予測ではなく繰り返し読み込みが問題であることを示します。

// 概念例: transcript の問題ある書き方
// styleTransferModel を読むたびに computed property が再計算されモデルを再読み込みする
var styleTransferModel: MLModel {
    loadSelectedStyleTransferModel()
}

// 概念例: transcript の修正方向
// 初回利用時に読み込み、その後メモリ上のモデルを再利用する
lazy var styleTransferModel: MLModel = {
    loadSelectedStyleTransferModel()
}()

キーポイント:

  • var styleTransferModel: MLModel { ... } は computed property で、アクセスのたびにコードブロックが実行されます。
  • loadSelectedStyleTransferModel() はモデル読み込み作業を表し、computed property に置くと予測前に毎回発生します。
  • lazy var は初回アクセス時に初期化し、以降は同じインスタンスを再利用します。
  • transcript の検証結果では、修正後は load イベントが5回のみとなり、App 内の5スタイルと一致しました。

12:43)Core ML Instrument はモデル別に activity を分割できます。スタイルごとに1モデルの App では、各モデルの load と prediction を分けて見られます。

さらに深く掘り下げることもできます。デモでは Core ML Instrument、GPU Instrument、新しい Neural Engine Instrument を固定表示しました。Core ML 区間は予測全体、Neural Engine Instrument は前半、GPU Instrument は後半の計算を示し、Neural Engine から GPU への引き渡しを確認できます。

Float16 入出力でデータ変換を減らす

14:34)Core ML は以前、8-bit grayscale、32-bit カラー画像、Int32、Double、Float32 MultiArray をサポートしていました。App がすでに Float16 データを使う場合に問題が出ます。

デモの画像シャープンフィルターは GPU で前後処理を行い、単チャンネル OneComponent16Half を使っていました。旧モデルインターフェースは 8-bit grayscale のままで、App は OneComponent16Half から OneComponent8 へダウンキャストし、出力を再び OneComponent16Half へアップキャストする必要がありました。Core ML 内部でも 8-bit 入力を Float16 計算用に再変換します。

iOS 16 と macOS Ventura 以降、Core ML は OneComponent16Half grayscale 画像と Float16 MultiArray をネイティブサポートします。モデル変換時に新しい image color layout や MultiArray data type を指定できます。最小デプロイターゲットは iOS 16 または macOS Ventura が必要です。

Float16 デモからの概念フロー:

旧モデル:
App 内 OneComponent16Half 入力
  -> App が OneComponent8 へダウンキャスト
  -> Core ML が計算用に Float16 へ変換
  -> Core ML が OneComponent8 出力
  -> App が OneComponent16Half へアップキャスト

新モデル:
OneComponent16Half CVPixelBuffer 入力
  -> Core ML prediction
  -> OneComponent16Half CVPixelBuffer 出力

キーポイント:

  • 旧フローには App 側の精度変換と Core ML 内部のデータ準備の両方がありました。
  • 新フローではモデルインターフェースが Float16 grayscale buffer を直接受け取れます。
  • transcript では、OneComponent16Half CVPixelBuffer を直接渡すとデータコピーや変換が発生しないと明記されています。
  • 変更後、Instruments の Data レーンには以前の変換ステップが表示されなくなりました。

output backing で出力バッファを制御する

18:42)Core ML には output backing API も追加されました。出力バッファを事前割り当てし、prediction options に設定して、毎回新しい出力を作らず Core ML に書き込ませられます。

transcript の output backing 用法からの概念疑似コード:

outputBuffer = outputBackingBuffer()  // OneComponent16Half CVPixelBuffer を返す
predictionOptions = new prediction options
predictionOptions.setOutputBacking(outputBuffer, forModelOutputName)
result = model.prediction(inputBuffer, options: predictionOptions)

キーポイント:

  • outputBackingBuffer() はデモの関数に対応し、OneComponent16Half CVPixelBuffer を返します。
  • predictionOptions は予測時に渡す options オブジェクトです。
  • setOutputBacking は疑似コードで、「事前割り当て出力バッファを prediction options に設定する」手順を表します。具体的な Swift API 名は仮定しません。
  • model.prediction(inputBuffer, options: predictionOptions) は transcript の「those prediction options でモデルの prediction メソッドを呼ぶ」に対応します。
  • forModelOutputName は生成インターフェースとモデル出力名に依存します。

20:11)Apple は可能な限り IOSurface-backed buffer の利用も推奨します。Core ML は unified memory を活用し、compute units 間のデータ受け渡し時のコピーを減らせます。

その他の Core ML 統合機能

20:31)ML Program モデルタイプは 16-bit と 8-bit 重み圧縮を拡張し、sparse representation を追加しました。coremltools utilities で ML Program 重みの quantize、palettize、sparsify が可能です。

21:09MLModelConfigurationcomputeUnitscpuAndNeuralEngine が追加されました。App が GPU を多用する場合、Core ML を GPU から避け、CPU と Neural Engine に限定できます。

// 概念例: GPU を使わない Core ML compute units
let configuration = MLModelConfiguration()
configuration.computeUnits = .cpuAndNeuralEngine

let model = try MyModel(configuration: configuration)

キーポイント:

  • MLModelConfiguration は Core ML モデル読み込み設定です。
  • computeUnits は Core ML の計算ユニット優先度を制御します。
  • .cpuAndNeuralEngine は Session で言及された新オプションです。
  • App のレンダリング、動画、その他計算で GPU が占有されている場合に適します。

21:44)Core ML にはメモリ上のモデル読み込みも追加されました。カスタム暗号化でモデルデータを保存し、読み込み前に復号して、ディスクへ compiled model を書かずにメモリ上の Core ML model specification から compile と load ができます。

22:11)Xcode 14 は Core ML モデルを Swift Package に入れることをサポートします。他者が package を import すると、Xcode が自動でモデルをコンパイル、パッケージし、馴染みのあるコードインターフェースを生成します。Swift エコシステムでの再利用可能モデル配布コストが下がります。

重要ポイント

  • リアルタイムカメラフィルター性能パネルを作る: 各フィルター背後の Core ML モデルの読み込み回数、prediction time、Data レーンイベントを一覧化します。「フィルター切り替えが遅い」原因がモデル読み込みか入出力変換かを素早く特定できます。

  • モデル候補評価表を作る: モデル選択段階で Xcode Performance Report を使い、デバイスと compute units ごとの prediction time、load time、layer placement を記録します。物体検出、姿勢認識、リアルタイムセグメンテーションなどフレームレート目標がある機能に適しています。

  • GPU 画像パイプラインを Float16 直通にする: 前後処理がすでに GPU 上で OneComponent16Half を使うなら、モデルを再変換して Core ML が Float16 画像や Float16 MultiArray を直接受け取れるようにし、App 側変換と Core ML Data レーンの変換イベントを減らします。

  • 高頻度予測で出力バッファを再利用する: 動画、音声、センサーストリームモデルでは output backing buffer を事前割り当てして予測時に再利用します。リアルタイム強調、モーション分析、連続分類など秒間多数回呼ぶ機能に向きます。

  • 再利用可能モデルを Swift Package にまとめる: モデル、呼び出しコード、サンプル入出力を package に入れ、チーム内の複数 App で同じ Core ML 統合を共有します。Xcode 14 がモデルコンパイル、パッケージング、コード生成を処理します。

関連セッション

  • Explore the machine learning development experience — モデル発見、変換、検証、デバイス上チューニングを扱い、本 Session の前提として適しています。
  • Get to know Create ML Components — Create ML Components でカスタムモデルをトレーニングする方法を紹介。トレーニング後は本 Session のツールで Core ML 統合を評価・最適化できます。
  • Compose advanced models with Create ML Components — より複雑な Create ML Components の組み合わせを示し、時系列データモデルを Core ML にデプロイする場面向けです。
  • What’s new in Vision — Vision API は画像・動画インテリジェンスでよく使われます。上位 Vision パイプラインの性能もモデル選択、データ形式、ハードウェア実行方式の影響を受けます。

コメント

GitHub Issues · utterances