0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

MPSGraph基礎解説 - 計算グラフの力

Last updated at Posted at 2025-11-27

シリーズ: Apple Silicon AI技術スタック 完全解説
難易度: ★★★☆☆(中級)
想定読者: パフォーマンスの仕組みを深く理解したい人、Metal統合をしたい人

TL;DR

  • MPSGraphは計算グラフを構築・最適化・実行するフレームワーク
  • Core MLやTensorFlowのGPUアクセラレーションを裏で支えている
  • 「ステッチング」技術で複数の演算を融合し、高速化を実現
  • 通常は直接使わないが、仕組みを理解するとパフォーマンスチューニングに役立つ

MPSGraphとは?

これまでMPSとMLXを見てきた。でも、その裏で動いているものがある。それがMPSGraph

Apple公式ドキュメントでは:

"Build, compile, and execute compute graphs utilizing all the different compute devices on the platform, including GPU, CPU, and Neural Engine."

(GPU、CPU、Neural Engineを含むプラットフォーム上のすべての異なる計算デバイスを活用して、計算グラフを構築、コンパイル、実行します)

出典:Apple Developer Documentation - Metal Performance Shaders Graph

WWDC24のセッションでは、もう少し詳しく説明されている:

"Metal Performance Shaders Graph, which is a framework for constructing and running general purpose compute graphs using Metal. MPSGraph provides low level control over GPU synchronization and memory, so in some cases you may want to use MPSGraph directly."

(Metal Performance Shaders Graphは、Metalを使用して汎用計算グラフを構築・実行するためのフレームワークです。MPSGraphはGPU同期とメモリに対する低レベル制御を提供するため、場合によってはMPSGraphを直接使用することもできます)

出典:WWDC24 - Accelerate machine learning with Metal


計算グラフって何?

機械学習に慣れた人なら「計算グラフ」はお馴染みだろう。でも念のため説明しておく。

入力テンソル A → 行列乗算 → 活性化関数 → 出力テンソル B
       ↑
入力テンソル C

こんな風に、演算を「ノード」、データの流れを「エッジ」としてグラフ構造で表現したもの。PyTorchやTensorFlowの内部でも使われている概念だ。

なぜグラフで表現するのか?

  1. 最適化の機会が見える - 全体を見て無駄を省ける
  2. 並列化しやすい - 依存関係が明確
  3. 自動微分が簡単 - グラフを逆向きにたどればいい
  4. 異なるハードウェアへの振り分け - CPU/GPU/ANEの最適な割り当て

MPSGraphは、このグラフをApple Silicon上で最も効率的に実行する方法を見つけ出す。


ステッチング:MPSGraphの秘密兵器

MPSGraphが高速な理由、それが「ステッチング」だ。

WWDC20のセッションで詳しく説明されている:

"Usually, for every operation, output would be written out to memory. The next operation would read from this same global memory, and this would end up causing unneeded memory traffic and performance issues, especially on the GPU. However, MPSGraph compiler applies a special optimization to automatically fuse such operations for the users. We call this stitching. The MPSGraph compiler recognizes all adjacent operations and passes it to the Metal compiler. The Metal compiler fuses the operations together to create a single optimized Metal shader."

(通常、各演算ごとに出力がメモリに書き出されます。次の演算は同じグローバルメモリから読み込むため、不要なメモリトラフィックとパフォーマンス問題が発生します。しかしMPSGraphコンパイラは、自動的にそれらの演算を融合する特別な最適化を適用します。これをステッチングと呼びます。MPSGraphコンパイラは隣接するすべての演算を認識し、Metalコンパイラに渡します。Metalコンパイラはそれらを融合して単一の最適化されたMetalシェーダーを作成します)

出典:WWDC20 - Build customized ML models with the Metal Performance Shaders Graph

図で理解するステッチング

【最適化前】
Op1 
  ↓ メモリ書き込み(遅い)
Global Memory
  ↓ メモリ読み込み(遅い)
Op2
  ↓ メモリ書き込み
Global Memory
  ↓ メモリ読み込み
Op3

【ステッチング後】
Op1 → Op2 → Op3
(全部レジスタ上で完結!メモリアクセス最小化)

GPUの処理でボトルネックになりがちな「メモリ帯域」を劇的に削減できる。これがMPSGraphの高速化の秘密だ。


Core MLとTensorFlowを支えるMPSGraph

実は、あなたがCore MLやTensorFlow-Metalを使っているとき、裏ではMPSGraphが動いている。

WWDC21のセッションでは:

"The MPSGraph framework has been adopted by higher level machine learning frameworks like Core ML and TensorFlow for GPU acceleration. This year, we have optimized MPSGraph even further with a combination of kernel improvements and stitching adoption."

(MPSGraphフレームワークは、Core MLやTensorFlowなどの高レベル機械学習フレームワークにGPUアクセラレーションのために採用されています。今年、カーネル改善とステッチングの採用の組み合わせで、MPSGraphをさらに最適化しました)

出典:WWDC21 - Accelerate machine learning with Metal Performance Shaders Graph

技術スタックの関係

[Core ML] [TensorFlow-Metal] [PyTorch MPS] [MLX]
              ↓
          [MPSGraph]  ← 計算グラフの最適化
              ↓
           [MPS]      ← 最適化されたカーネル
              ↓
          [Metal]     ← GPU API
              ↓
        [Apple GPU]

MPSGraphは「翻訳者」のような存在。高レベルフレームワークの計算グラフを受け取り、Apple GPUで最も効率的に実行する形に変換する。


TensorFlow-Metalのインストール

TensorFlowでMPSGraphの恩恵を受けるのは簡単:

pip install tensorflow-macos
pip install tensorflow-metal

これだけで、TensorFlowの演算がMPSGraph経由でGPUアクセラレーションされる。

import tensorflow as tf

# GPUが認識されているか確認
print(tf.config.list_physical_devices('GPU'))
# [PhysicalDevice(name='/physical_device:GPU:0', device_type='GPU')]

# 以降は通常通りTensorFlowを使う
model = tf.keras.Sequential([...])
model.fit(x_train, y_train)  # GPU加速される

MPSGraphを直接使う場面

普通の開発者がMPSGraphを直接触ることは少ないかもしれない。でも、こんな場面では有用:

"For example, if your application uses Metal, you can use MPSGraph to sequence ML tasks with other GPU work. You can also share low level Metal resources such as buffers."

(例えば、アプリケーションがMetalを使用している場合、MPSGraphを使ってMLタスクを他のGPU作業と順序付けることができます。バッファなどの低レベルMetalリソースを共有することもできます)

出典:WWDC24 - Accelerate machine learning with Metal

直接使うべき場面

  1. ゲームエンジン開発 - レンダリングとMLを密に統合
  2. カスタムレンダラー - グラフィックスパイプラインにMLを組み込む
  3. 極限の最適化 - フレームワークの抽象化を排除したい
  4. Metal既存コードとの統合 - バッファ共有でコピー削減

Swiftでの基本的な使用例

import MetalPerformanceShadersGraph

// グラフを作成
let graph = MPSGraph()

// 入力テンソルを定義(プレースホルダー)
let inputA = graph.placeholder(
    shape: [2, 3], 
    dataType: .float32, 
    name: "inputA"
)
let inputB = graph.placeholder(
    shape: [3, 4], 
    dataType: .float32, 
    name: "inputB"
)

// 行列乗算を追加
let matmul = graph.matrixMultiplication(
    primary: inputA, 
    secondary: inputB, 
    name: "matmul"
)

// 活性化関数を追加(ステッチングで融合される)
let relu = graph.reLU(with: matmul, name: "relu")

// 実行のためのデバイスとキュー
let device = MTLCreateSystemDefaultDevice()!
let commandQueue = device.makeCommandQueue()!

// 入力データを準備
let dataA: [Float] = [1, 2, 3, 4, 5, 6]  // 2x3
let dataB: [Float] = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12]  // 3x4

// MPSGraphTensorDataを作成
let tensorDataA = MPSGraphTensorData(
    device: MPSGraphDevice(mtlDevice: device),
    data: Data(bytes: dataA, count: dataA.count * MemoryLayout<Float>.size),
    shape: [2, 3],
    dataType: .float32
)

// グラフを実行
let results = graph.run(
    with: commandQueue,
    feeds: [inputA: tensorDataA, inputB: tensorDataB],
    targetTensors: [relu],
    targetOperations: nil
)

// 結果を取得
let outputData = results[relu]!

WWDC24の新機能:Transformer向け最適化

2024年、MPSGraphはTransformerモデル向けに大幅強化された:

"MPS and MPSGraph have new features which enable you to improve your transformer models. These improvements fall into three categories. First, improved compute performance. Next, memory bandwidth savings. And finally, quality improvements for transformer models."

(MPSとMPSGraphには、Transformerモデルを改善できる新機能があります。これらの改善は3つのカテゴリに分類されます。まず計算パフォーマンスの向上、次にメモリ帯域の節約、最後にTransformerモデルの品質向上です)

出典:WWDC24 - Accelerate machine learning with Metal

Scaled Dot-Product Attention (SDPA)

特に重要なのが、SDPA(Scaled Dot-Product Attention)のネイティブサポート:

"MPSGraph now has an operation which combines this sequence of operations into a single kernel which executes more efficiently. To use this operation, call the scaledDotProductAttention method on an MPSGraph object."

(MPSGraphには、この一連の演算を単一のより効率的に実行されるカーネルに結合する演算が追加されました。この演算を使用するには、MPSGraphオブジェクトのscaledDotProductAttentionメソッドを呼び出します)

Transformerの心臓部であるAttention機構が、一発の最適化されたカーネルで実行できる。

// Transformerのアテンション計算
let attention = graph.scaledDotProductAttention(
    query: queryTensor,
    key: keyTensor,
    value: valueTensor,
    scale: Float(1.0 / sqrt(Float(headDim))),
    name: "sdpa"
)

KVキャッシュサポート

LLMの推論を高速化するKVキャッシュも効率的に扱える:

// キャッシュされたKey/Valueを使用
let cachedAttention = graph.scaledDotProductAttention(
    query: newQueryTensor,
    key: cachedKeyTensor,      // 前のトークンのキー
    value: cachedValueTensor,  // 前のトークンのバリュー
    scale: scale,
    name: "cached_sdpa"
)

MPSGraph Viewer:Xcode 16の新ツール

モデルの最適化状況を可視化したい?Xcode 16で新しいツールが登場した:

"Today, I'm excited to introduce the newest addition to the Metal tools, coming in Xcode 16, the MPSGraph Viewer! It's a brand new tool, specifically designed for machine learning and AI. Now, you can directly open MPSGraph packages in Xcode, and visualize how your operations are connected."

(Xcode 16に新しく追加されるMPSGraph Viewerを紹介します!機械学習とAI専用に設計された全く新しいツールです。XcodeでMPSGraphパッケージを直接開き、演算がどのように接続されているかを可視化できます)

出典:WWDC24 - Accelerate machine learning with Metal

mpsgraphtoolでの変換

ONNXモデルからMPSGraphパッケージへの変換:

# ONNXモデルをMPSGraphパッケージに変換
mpsgraphtool convert model.onnx -o model.mpsgraphpackage

ビューアの機能

  1. グラフ構造の可視化 - ノードとエッジの関係を図示
  2. デバイス最適化の確認 - 特定のデバイスでどう最適化されるか
  3. ステッチングの確認 - どの演算が融合されているか
  4. ボトルネックの特定 - パフォーマンス問題の発見

MPSGraphPackage:シリアライゼーション

グラフをファイルに保存し、起動時間を短縮できる:

// グラフをパッケージとして保存
let serializationDescriptor = MPSGraphSerializationDescriptor()
let executable = // コンパイル済みのMPSGraphExecutable

try executable.serialize(
    descriptor: serializationDescriptor, 
    to: packagePath
)

// 後でロード
let compilationDescriptor = MPSGraphCompilationDescriptor()
let loadedExecutable = try MPSGraphExecutable(
    url: packagePath, 
    options: compilationDescriptor
)

複雑なグラフの場合、事前コンパイルで起動時間を大幅に短縮できる。


パフォーマンスの考え方

MPSGraphを理解すると、パフォーマンスチューニングの考え方が変わる:

良いパターン

✅ 連続した演算をまとめて投入
→ ステッチングの機会が増える

✅ 大きなバッチサイズ
→ GPU利用効率が上がる

✅ 同じ形状の繰り返し計算
→ コンパイル済みグラフを再利用

悪いパターン

❌ 細かい演算を逐次実行
→ ステッチングできない

❌ 頻繁な形状変更
→ 再コンパイルのオーバーヘッド

❌ 小さすぎるテンソル
→ GPU起動オーバーヘッドが支配的

まとめ:MPSGraphは「縁の下の力持ち」

MPSGraphを直接使う機会は少ないかもしれない。でも:

  • Core MLでモデルを動かすとき
  • TensorFlow-Metalでトレーニングするとき
  • MLXでLLMを推論するとき

裏ではMPSGraphが働いている。計算グラフの最適化、ステッチングによる演算融合、適切なデバイス(GPU/CPU/Neural Engine)への振り分け。

Apple Siliconの機械学習パフォーマンスを支える、まさに縁の下の力持ちだ。


次に読む


参考文献

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?