WWDC Quick Look 💓 By SwiftGGTeam
Tune your Core ML models

Tune your Core ML models

元の動画を見る

ハイライト

Core ML は、多次元データを処理するために MLMultiArray を置き換える MLShapedArray を導入し、バージョン管理のために個別のモデル コンポーネントに ML パッケージ形式を追加し、型指定された実行をサポートする ML プログラム モデル タイプを起動することで、開発者が変換中に Float16/Float32 の精度を正確に制御できるようにします。

主な内容

MLMultiArray の迅速な置き換え

コア ML モデルは多くの場合、多次元配列データを出力します。たとえば、ターゲット検出モデル YOLO は、各行が検出ボックスを表し、各列がさまざまなカテゴリの信頼度を表す 2 次元配列を出力します。以前は、この種のデータの処理には MLMultiArray が使用されていましたが、コードの記述は非常に面倒でした。初期化中にランタイム型を渡す必要があり、インデックス作成中に NSNumber を使用する必要があったため、型安全性がありませんでした。

WWDC2021 では、純粋な Swift 多次元配列タイプである MLShapedArray が導入されました (01:34)。これは値型であり、コピーオンライトをサポートし、配列と同様のスライス構文を持ちます。最も重要なのは、MLShapedArray と MLMultiArray には完全な互換性があり、相互に変換できることです。

ML パッケージ: モデル ファイルのバージョン管理スキーム

従来の .mlmodel ファイルは、メタデータ、インターフェイス定義、ネットワーク アーキテクチャ、および重みパラメータをすべてパッケージ化した protobuf バイナリ ファイルです。これにより問題が発生します。メタデータ フィールド (作成者名など) を変更すると、バイナリ ファイル全体が変更され、git diff には数十 MB の変更が表示されます。

ML パッケージは、macOS のパッケージ機能を使用して、モデル コンポーネントを独立したファイルに分割します (05:30)。アーキテクチャ、重み、メタデータはそれぞれ 1 つのファイルに保存されます。メタデータが変更されたときに変更される JSON ファイルは 1 つだけであり、git diff は明確で読み取り可能です。Xcode は、UI でのメタデータおよび入力および出力の説明の編集を直接サポートしています。

ML プログラム: 将来のモデル形式

ML プログラムは、ニューラル ネットワークを従来のレイヤーではなく、一連の厳密に型指定された操作 (ops) として記述する新しいモデル表現方法です (10:05)。重みはバイナリ ファイルに個別にシリアル化され、中間テンソルのタイプは変換中に決定されます。

Typed 実行の主な利点は、精度の制御です。従来のニューラル ネットワーク モデルの中間テンソル タイプは、ランタイム コンピューティング ユニット (ニューラル エンジンと GPU の場合は Float16、CPU の場合は Float32) によって決定されます。モデルが Float16 精度に敏感な場合、computeUnits は .cpuOnly にのみ設定できるため、パフォーマンスが大幅に犠牲になります。

ML プログラムの中間テンソル型は、モデル変換中に固定されます。Core ML ランタイムは、Float32 演算を実行用に GPU に割り当てながら、ニューラル エンジンでの実行用に Float16 演算を保持できるため、グローバルな computeUnits 設定の必要がなくなります。

##詳細

MLShapedArray の基本的な使用法

01:55

// 初始化一个 2x3 的 Float ShapedArray
let shapedArray = MLShapedArray<Float>(
    [[1.0, 2.0, 3.0],
     [4.0, 5.0, 6.0]]
)

// 访问第二行作为切片
let secondRow = shapedArray[1]

// 访问多行多列的切片
let subArray = shapedArray[0..<2, 1..<3]

キーポイント:

  • MLShapedArray<Float>ジェネリックタイプです。要素の型はコンパイル時に決定されます。実行時に型パラメータを渡す必要はありません。
  • 多次元インデックスと範囲スライスをサポートし、構文は Swift Array と一貫しています
  • 値型のコピーオンライト セマンティクス。スライス操作では基になるデータはコピーされません。

MLShapedArray と MLMultiArray 間の変換

02:31

// MLMultiArray 转 MLShapedArray
let multiArray: MLMultiArray = ...
let shapedArray = MLShapedArray(multiArray)

// MLShapedArray 转 MLMultiArray
let shapedArray: MLShapedArray<Float> = ...
let multiArray = MLMultiArray(shapedArray)

// 类型转换:Double MultiArray 转 Float ShapedArray
let floatShapedArray = MLShapedArray<Float>(multiArrayOfDoubles)

キーポイント:

  • 相互変換はイニシャライザを通じて完了するため、データを手動で走査する必要はありません
  • Double から Float への相互型変換のサポート
  • Xcode によって自動的に生成されたモデル ラッパー クラスは、各 MultiArray 出力に対応する ShapedArray 属性を追加します。

YOLO モデルの出力処理の比較

02:51

MLMultiArray バージョン:

// 用 MLMultiArray 处理 YOLO 输出
func bestLabels(from confidence: MLMultiArray) -> [String] {
    var results: [String] = []
    let rowCount = confidence.shape[0].intValue
    let columnCount = confidence.shape[1].intValue

    for row in 0..<rowCount {
        var maxConfidence: Double = 0
        var bestLabel = ""
        for column in 0..<columnCount {
            let value = confidence[[NSNumber(value: row), NSNumber(value: column)]].doubleValue
            if value > maxConfidence {
                maxConfidence = value
                bestLabel = labels[column]
            }
        }
        results.append(bestLabel)
    }
    return results
}

MLShapedArray バージョン:

// 用 MLShapedArray 处理同样的输出
func bestLabels(from confidence: MLShapedArray<Float>) -> [String] {
    return confidence.map { row in
        let maxIndex = row.argmax()
        return labels[maxIndex]
    }
}

キーポイント:

  • MLMultiArray バージョンは、NSNumber 変換と 2 次元インデックス付けの手動処理が必要であり、コードが長くなります
  • MLShapedArray バージョンは、Swift コレクション プロトコル (mapargmax)、同じロジックを 1 行で完成させます
  • モデル予測結果が ShapedArray を出力する場合、Swift の標準ライブラリ メソッドを使用して直接処理できます。

TensorFlow モデルを ML プログラムに変換する

16:54

import coremltools as ct

# 加载 TensorFlow 模型
model_path = "style_transfer_model"
image_path = "test_image.jpg"

# 设置输入类型
input_type = ct.ImageType(
    shape=(1, 256, 256, 3),
    bias=[-1, -1, -1],
    scale=1/127.0
)

# 转换为 ML Program(iOS 15 / macOS 12 起)
ml_program = ct.convert(
    model_path,
    inputs=[input_type],
    minimum_deployment_target=ct.target.iOS15
)

# 默认生成 Float16 精度的 ML Program
# 保存模型
ml_program.save("StyleTransfer.mlmodel")

キーポイント:

  • minimum_deployment_targetiOS15またはmacOS12に設定すると、コンバータはMLプログラム形式を出力します
  • FP16ComputePrecision パスはデフォルトで有効になっており、すべての Float32 テンソルは Float16 に変換されます。
  • Float16 モデルは Neural Engine 上で実行でき、大幅なパフォーマンスの向上と消費電力の削減を実現します。

ML プログラムの精度を制御する

20:16

# 生成 Float32 精度的 ML Program
ml_program_fp32 = ct.convert(
    model_path,
    inputs=[input_type],
    minimum_deployment_target=ct.target.iOS15,
    compute_precision=ct.precision.FLOAT32
)

# 评估精度差异
# Float16 版本的 SNR 通常在 70+,Float32 版本在 100+
# 对大多数深度学习模型,Float16 精度损失肉眼不可见

キーポイント:

  • compute_precision=FLOAT32Float16 変換を無効にして、完全な精度を維持します
  • Float32 ML プログラムは GPU と CPU で実行されますが、Neural Engine では実行されません
  • モデルが Float16 に敏感な場合、アプリ コードで computeUnits を変更する必要はなく、変換時に精度を指定するだけです。
  • 混合精度もサポート: 特定の演算で Float32 を使用し、残りの演算で Float16 を使用するように指定します。

重要ポイント

1.既存の Core ML モデルを ML パッケージにアップグレード

  • やるべきこと: メタデータ編集とバージョン管理の利点を得るために、プロジェクト内の .mlmodel ファイルを .mlpackage に変換します。
  • 実行する価値がある理由: メタデータを変更しても数十 MB の git diff が生成されなくなり、チーム メンバーはモデルの変更をレビューできるようになります。
  • 開始方法: Xcode で .mlmodel ファイルを選択し、[編集] ボタンをクリックすると、Xcode は自動的に ML パッケージへの変換を求めるプロンプトを表示します。

2. MLShapedArray を使用してモデル出力処理を簡素化

  • 内容: MLMultiArray を処理するコードを MLShapedArray に移行して、コードの量を削減し、読みやすさを向上させます。
  • 実行する価値がある理由: MLShapedArray は Swift 標準収集プロトコルをサポートしており、使用できます。mapfilterargmaxネイティブメソッドを待つことでコードが数十行から数行に削減される
  • 開始方法: Xcode によって自動生成されたモデル クラスを確認し、新しいクラスを使用します。xxxShapedArray属性の置換xxxマルチアレイのプロパティ

3.精度を重視するモデルには Float32 ML プログラムを使用します

  • 内容: 数値精度に敏感なモデル (科学計算、財務予測など) を特定し、変換時に Float32 精度を指定します。
  • 実行する価値がある理由: computeUnits を .cpuOnly に制限する必要がなくなり、Float32 ML プログラムを GPU 上で実行できるため、精度を確保しながらパフォーマンスを維持できます。
  • 開始方法: を使用しますcoremltools変換時に設定compute_precision=FLOAT32、Float16 と Float32 の SNR メトリクスを比較

4.モデルのバージョン管理システムを構築

  • やるべきこと: ML パッケージの分離されたファイル構造を使用して、モデルの CI/CD プロセスを確立します。
  • 実行する価値がある理由: アーキテクチャ ファイル (JSON) と重みファイル (バイナリ) は別々に保存されます。アーキテクチャの変更はコードレビューでき、重みの変更は独立したリリースプロセスを経ることができます。
  • 開始方法: 通常のレビュー用に .mlpackage ディレクトリを git、metadata.json、および機能説明 JSON に追加し、Git LFS を使用して大きな重量ファイルを管理します

関連セッション

コメント

GitHub Issues · utterances