シリーズ: Apple Silicon AI技術スタック 完全解説
難易度: ★★☆☆☆(初級〜中級)
想定読者: PyTorchユーザー、MacでGPU加速したい人
TL;DR
- MPSはApple GPU向けに最適化された高性能計算カーネル群
- PyTorchの
mpsデバイスで簡単にGPU加速を実現 - Apple Siliconの統合メモリアーキテクチャを活用し、大規模モデルも効率的に処理
- CUDAには及ばないが、Macユーザーにとってはゲームチェンジャー
MPSとは何か?
「MacでGPU使って機械学習したいんだけど、CUDA使えないじゃん」
M1チップが登場して以降、何度この嘆きを聞いたことか。でも安心してほしい。Appleには**MPS(Metal Performance Shaders)**という秘密兵器がある。
公式ドキュメントによると:
"Optimize graphics and compute performance with kernels that are fine-tuned for the unique characteristics of each Metal GPU family."
(各Metal GPUファミリーの固有の特性に合わせて微調整されたカーネルで、グラフィックスと計算パフォーマンスを最適化します)
出典:Apple Developer Documentation - Metal Performance Shaders
要するに、MPSはApple GPU専用にチューニングされた高性能演算ライブラリだ。画像処理、線形代数、機械学習など、GPU向けの計算処理が詰め込まれている。
PyTorchとMPS:歴史的経緯
2022年、PyTorch 1.12でMPSバックエンドが正式導入された。これによってMacユーザーもGPU加速の恩恵を受けられるようになった。
PyTorchの公式ドキュメントには:
"This package enables an interface for accessing MPS (Metal Performance Shaders) backend in Python. Metal is Apple's API for programming metal GPU (graphics processor unit). Using MPS means that increased performance can be achieved, by running work on the metal GPU(s)."
(このパッケージはPythonからMPSバックエンドにアクセスするインターフェースを提供します。MetalはAppleのGPUプログラミング用APIです。MPSを使用することで、Metal GPU上で処理を実行し、パフォーマンスを向上させることができます)
出典:PyTorch Documentation - torch.mps
それまでMacでPyTorchを使うといえば、CPU一択だった。学習に何時間もかかる、推論も遅い。そんな状況が一変した。
実践:MPSの使い方
基本的な使い方
import torch
# MPSが利用可能かチェック
if torch.backends.mps.is_available():
mps_device = torch.device("mps")
x = torch.ones(1, device=mps_device)
print(x)
else:
print("MPS device not found.")
たったこれだけ。device="mps"と指定するだけで、あなたのテンソルはApple GPUの上で動き始める。
既存コードの移行
CUDAで書かれたコードをMPSに移行するのも簡単だ:
# Before (CUDA)
device = torch.device("cuda" if torch.cuda.is_available() else "cpu")
# After (MPS対応)
if torch.cuda.is_available():
device = torch.device("cuda")
elif torch.backends.mps.is_available():
device = torch.device("mps")
else:
device = torch.device("cpu")
# もっとシンプルに
device = torch.device(
"cuda" if torch.cuda.is_available()
else "mps" if torch.backends.mps.is_available()
else "cpu"
)
モデルとデータの移動
# モデルをMPSに移動
model = MyModel()
model.to(device)
# データをMPSに移動
inputs = inputs.to(device)
targets = targets.to(device)
# 推論
with torch.no_grad():
outputs = model(inputs)
Stable Diffusionでの活用例
Hugging FaceのDiffusersライブラリでも、MPSは第一級サポートを受けている:
from diffusers import DiffusionPipeline
pipe = DiffusionPipeline.from_pretrained("stable-diffusion-v1-5/stable-diffusion-v1-5")
pipe = pipe.to("mps")
# RAMが64GB未満の場合は推奨
pipe.enable_attention_slicing()
prompt = "a photo of an astronaut riding a horse on mars"
image = pipe(prompt).images[0]
これだけで、Apple Silicon上でStable Diffusionが動く。数年前なら考えられなかったことだ。
よくあるトラブルと対策
MPSを使っていると、いくつかのハマりポイントがある。
1. 未実装の演算子エラー
一部のPyTorch演算がMPSで未実装の場合がある。こんなエラーが出る:
NotImplementedError: The operator 'aten::some_op' is not currently implemented for the MPS device.
そんなときは環境変数を設定:
export PYTORCH_ENABLE_MPS_FALLBACK=1
この環境変数を設定すると、未実装の演算はCPUにフォールバックしてくれる。パフォーマンスは落ちるが、少なくとも動く。
Pythonコード内で設定する場合:
import os
os.environ["PYTORCH_ENABLE_MPS_FALLBACK"] = "1"
import torch # この後にimport
2. メモリプレッシャー問題
Hugging Faceのドキュメントでは:
"M1/M2 performance is very sensitive to memory pressure. When this occurs, the system automatically swaps if it needs to which significantly degrades performance."
(M1/M2のパフォーマンスはメモリプレッシャーに非常に敏感です。メモリ不足が発生すると、システムは自動的にスワップを行い、パフォーマンスが著しく低下します)
対策:
# Attention Slicingを有効化
pipe.enable_attention_slicing()
# または、バッチサイズを小さくする
# または、モデルの精度を下げる(float16)
pipe = pipe.to(torch.float16)
特にRAMが64GB未満のマシンでは、これらの対策は必須だ。
3. PyTorch 1.13でのウォームアップ
PyTorch 1.13を使っている場合、最初の推論でおかしな結果が出ることがある:
# 最初に「ウォームアップ」を実行
_ = pipe(prompt, num_inference_steps=1)
# 本番の推論
image = pipe(prompt).images[0]
PyTorch 2.0以降では修正されているので、アップデートを検討しよう。
Apple SiliconのUnified Memoryアーキテクチャ
MPSが優れている理由の一つは、Apple Siliconの統合メモリアーキテクチャを最大限に活用できること。
PyTorchの公式ブログでは:
"Every Apple silicon Mac has a unified memory architecture, providing the GPU with direct access to the full memory store. This makes Mac a great platform for machine learning, enabling users to train larger networks or batch sizes locally."
(すべてのApple Silicon Macは統合メモリアーキテクチャを採用しており、GPUがメモリストア全体に直接アクセスできます。これにより、Macは機械学習に最適なプラットフォームとなり、より大きなネットワークやバッチサイズをローカルで学習できます)
出典:PyTorch Blog - Introducing Accelerated PyTorch Training on Mac
従来のGPUとの違い
【従来のGPU(NVIDIA等)】
CPU Memory ←→ PCIe ←→ GPU VRAM
↑ ↑
16GB 8GB(固定)
モデルがVRAMに載らない → Out of Memory!
【Apple Silicon】
Unified Memory
┌───────────────────┐
│ CPU も GPU も │
│ 同じメモリを共有 │
│ (16GB〜192GB) │
└───────────────────┘
モデルが大きくても、メモリが足りれば動く
NVIDIAのGPUだと、VRAMにモデルが載らなければそこでゲームオーバー。でもApple Siliconなら、統合メモリの恩恵で、もっと大きなモデルを扱える可能性がある。
実際のベンチマーク:spaCyでの事例
Explosionチームがspacy/Thincで行ったベンチマークは興味深い:
"The inference performance of the M1 Max is almost half that of an NVIDIA RTX 3090."
(M1 Maxの推論パフォーマンスはNVIDIA RTX 3090のほぼ半分です)
出典:Explosion Blog - Fast transformer inference with Metal Performance Shaders
「半分かよ」と思うかもしれないが、RTX 3090は単体で$1,500以上する怪物カードだ。MacBook Pro内蔵のGPUがその半分の性能を出せるなら、かなり健闘していると言える。
そして何より、AMXブロック(CPU内のベクトル演算ユニット)と比較すると:
"reaching up to 8648 words per second on the GPU compared to 1821 words per second on the AMX blocks on an M1 Max"
(M1 MaxでGPUは最大8648語/秒を達成、AMXブロックは1821語/秒)
約4.7倍の高速化。これがMPSの実力だ。
ベンチマーク結果まとめ
| デバイス | 処理速度 (語/秒) |
|---|---|
| M1 Max (MPS) | 8,648 |
| M1 Max (AMX/CPU) | 1,821 |
| RTX 3090 | 約17,000 (推定) |
MPSの立ち位置:技術スタック全体像
MPSは単独で動くわけではない。Appleの機械学習スタック全体を見ると:
[アプリケーション層]
PyTorch / TensorFlow / MLX / Core ML
↓
[抽象化層]
MPSGraph(計算グラフの最適化)
↓
[カーネル層]
MPS(最適化されたGPUカーネル群)← 今ここ!
↓
[ハードウェア抽象化]
Metal(GPU API)
↓
[ハードウェア]
Apple GPU / Neural Engine / CPU
MPSはこのスタックの中で「カーネル層」を担当している。つまり、実際にGPU上で動く最適化された計算コードの集合体だ。
PyTorchのmpsデバイスは、内部的にこのMPSを呼び出している。
環境構築のベストプラクティス
macOS要件
MPSバックエンドには以下が必要:
- macOS 12.3以降
- Apple Silicon (M1/M2/M3/M4) または AMD GPU搭載Mac
PyTorchのインストール
# conda推奨
conda install pytorch torchvision torchaudio -c pytorch
# または pip
pip install torch torchvision torchaudio
動作確認スクリプト
import torch
print(f"PyTorch version: {torch.__version__}")
print(f"MPS available: {torch.backends.mps.is_available()}")
print(f"MPS built: {torch.backends.mps.is_built()}")
if torch.backends.mps.is_available():
# 簡単な演算テスト
x = torch.randn(1000, 1000, device="mps")
y = torch.randn(1000, 1000, device="mps")
z = x @ y
print(f"Matrix multiplication on MPS: {z.shape}")
print("MPS is working correctly!")
まとめ:MPSを使うべき場面
MPSが向いているケース
- MacでPyTorchの学習・推論を高速化したい
- Apple Siliconの統合メモリを活かして大きめのモデルを動かしたい
- CUDAがない環境でもGPU加速が必要
- ローカルで実験・プロトタイピングしたい
MPSが向かないケース
- 最高のパフォーマンスが必要(まだCUDAには及ばない)
- 分散学習(MPSは分散学習をサポートしていない)
- すべてのPyTorch演算を使いたい(一部未実装あり)
- 本番環境での大規模処理
とはいえ、MacユーザーにとってMPSは間違いなくゲームチェンジャーだ。「Macで機械学習?無理でしょ」という時代は終わった。
次に読む
参考文献
- Apple Developer Documentation - Metal Performance Shaders
- PyTorch Documentation - torch.mps
- PyTorch Blog - Introducing Accelerated PyTorch Training on Mac
- Hugging Face Docs - MPS
- Explosion Blog - Fast transformer inference with Metal Performance Shaders
- Apple Developer - Accelerated PyTorch Training on Mac