Skip to content
Published on

Apple SiliconでLLMを動かす:M4/M5チップのAI推論の秘密と限界

Authors

Apple SiliconがAI推論市場を揺るがす理由

2024年末、あるスタートアップのMLエンジニアにこう聞かれました。「RTX 4090のワークステーションがあるのに、なぜMacBookでLLMを動かすんですか?」そのエンジニアは、M4 MaxのMacBookでLlama 3.1 70Bが8 tokens/secで動くのを見て、表情が変わりました。RTX 4090の単体カードはVRAMが24GBしかなく、70Bモデル自体がそもそも載らないからです。

Apple SiliconのLLM推論性能は、単純なベンチマーク数値以上の意味を持ちます。アーキテクチャレベルで根本的に異なるアプローチを取っているからです。本記事では、M4/M5チップの内部構造を分解し、LLMを実行する際に何が起きているかを詳しく説明します。


1. コアの差別化要因:ユニファイドメモリアーキテクチャ(UMA)

Apple Siliconの最も重要な特徴は**ユニファイドメモリアーキテクチャ(Unified Memory Architecture、UMA)**です。なぜこれが重要なのかを理解するには、まず従来のPCアーキテクチャと比較する必要があります。

従来のPCアーキテクチャのボトルネック

従来のシステムでは、CPUとGPUは物理的に分離されたメモリを使用します。

従来のPCアーキテクチャ:
┌─────────────────────┐   PCIe x16 (~32 GB/s)   ┌──────────────────────────┐
CPU                 │◄──────────────────────►  │ GPUIntel/AMD           │                           │ NVIDIA RTX 4090DDR5 64GB           │                           │ GDDR6X 24GB              │
89 GB/s帯域幅       │                           │ 1008 GB/s帯域幅          │
│                     │                           │                          │
│ 推論中のモデル片     │   データコピーが必要!     │ 推論中のモデル片          │
└─────────────────────┘                           └──────────────────────────┘

問題点:
- LLM推論時:weightsはGPU VRAMに、KVキャッシュは部分的にCPU RAMに → コピーオーバーヘッド
- PCIe帯域幅32 GB/sはGPUVRAM 1TB/sより30倍以上遅い
- 70Bパラメータモデル(FP16= ~140GB → 24GB VRAMには全く載らない!

Apple M4 Maxのアプローチ

Apple M4 Max(ユニファイドメモリ):
┌─────────────────────────────────────────────────────────────────┐
│                128GB ユニファイドメモリプール                    │
546 GB/s 帯域幅                               │
│                                                                 │
│   ┌────────────┐   ┌──────────────┐   ┌──────────────────────┐ │
│   │   CPU      │   │     GPU      │   │   Neural Engine      │ │
│   │ 14コア     │   │  40 GPUコア  │   │   38 TOPS            │ │
 (4P + 10E) │   │              │   │   INT8/FP16専用      │ │
│   └────────────┘   └──────────────┘   └──────────────────────┘ │
│                                                                 │
│   すべてのプロセッサが同じ物理メモリに直接アクセス!             │
│   コピーなし、レイテンシなし、同期オーバーヘッドなし            │
└─────────────────────────────────────────────────────────────────┘

なぜLLM推論でこれがゲームチェンジャーなのか

LLM推論の核心的なボトルネックはコンピュートバウンドではなくメモリ帯域幅バウンドです。これを理解するためにRooflineモデルを見てみましょう。

算術強度(Arithmetic Intensity) = FLOPs / メモリバイト数

Transformerのattentionとlinear layerにおいて:

  • 行列ベクトル積(バッチサイズ1):weightを1回読んで掛け算1回 → 算術強度 ≈ 1
  • 行列行列積(大きなバッチ):算術強度が上昇

M4 Maxのピーク FP16性能は~14.2 TFLOPS、メモリ帯域幅は546 GB/sです。 Roofline交差点:14.2 TFLOPS / 0.546 TB/s = ~26 FLOP/byte

単一クエリ(batch=1)推論では算術強度が~1 FLOP/byteのため、完全にメモリ帯域幅制限です。つまり、理論上の最大スループットはメモリ帯域幅をどれだけ活用できるかで決まります。

モデルサイズ別のFP16メモリ要件:
Llama 3.2 3B   → ~6GB   (M4 Pro 24GBに簡単に載る)
Llama 3.1 8B   → ~16GB  (M4 Pro 24GBに載る)
Llama 3.1 70B  → ~140GB (M4 Max 128GBにはQ4量子化で ~40GB必要)
Llama 3.1 405B → ~810GB (M4 Ultra 192GBでも量子化必須)

2. Apple Neural Engine(ANE)の解剖

多くの人が「Apple SiliconのAI性能 = Neural Engine」と誤解しています。実際はもっと微妙です。

ANEはGPUではない

Neural Engine(ANE)はAppleがA11 Bionic(2017年)から搭載した専用AI アクセラレータです。GPUとは全く異なる目的で設計されています。

Apple M4 Max内のコンポーネントと役割:
┌────────────────────────────────────────────────────────────────┐
Apple M4 Max│                                                                │
CPU(4P + 10Eコア)                                           │
- 汎用演算、OS、アプリロジック                                  │
- プリフィルフェーズのトークン化を担当                          │
│                                                                │
GPU40コア)                                                  │
- Metal APIでプログラム可能                                    │
- LLMの行列積、attention演算を処理                             │
- llama.cpp、MLXが主に使用                                     │
│                                                                │
Neural Engine(38 TOPS)                                      │
- CoreMLモデル専用アクセラレータ- INT8/FP16 systolic array MACユニット                        │
- 直接プログラム不可!(CUDAのような汎用APIなし)              │
- Whisper、Face ID、Siri処理に使用                             │
│                                                                │
└────────────────────────────────────────────────────────────────┘

ANEの内部構造

ANEはsystolic array方式のMAC(Multiply-Accumulate)ユニット配列で構成されています。M4のANEは38 TOPS(INT8)を処理でき、パイプライン方式で行列積を処理します。

Systolic Array(簡略化):
入力行列 → [MAC][MAC][MAC][MAC] → 出力
             ↓    ↓    ↓    ↓
入力行列 → [MAC][MAC][MAC][MAC]
             ↓    ↓    ↓    ↓
入力行列 → [MAC][MAC][MAC][MAC]

MACユニット:乗算と累算を同時実行
データが左→右に流れ、weightが上→下に流れるパターン

CoreMLとANEの活用

ANEを活用するにはCoreMLフレームワークを経由する必要があります:

# CoreMLへのLLM変換(概念的な例)
import coremltools as ct
import torch

model = load_llm_model()
traced_model = torch.jit.trace(model, example_input)

# CoreML変換時のcompute_units指定
mlmodel = ct.convert(
    traced_model,
    compute_units=ct.ComputeUnit.ALL,  # CPU + GPU + ANE全て使用
    # または ct.ComputeUnit.CPU_AND_NE  # CPU + ANEのみ
    minimum_deployment_target=ct.target.macOS14,
)
mlmodel.save("llm_model.mlpackage")

実際の制限:ほとんどのLLMサービングフレームワーク(llama.cpp、vLLM、Ollama)はANEを直接利用しません。ANEはCoreML専用であり、CoreML変換はすべてのLLMアーキテクチャをサポートしていません。実際のLLM推論のほとんどはGPUパスを使用します。


3. Metal Performance ShadersとMLX

Metal:Apple GPUのプログラミングレイヤー

NVIDIAがCUDAを提供するように、AppleはMetalを提供します。PyTorchのMPS(Metal Performance Shaders)バックエンドはMetalを通じてApple GPUを活用します。

# PyTorch MPSバックエンドの使用
import torch

# MPS使用可能かどうか確認
print(torch.backends.mps.is_available())   # Apple SiliconでTrue
print(torch.backends.mps.is_built())       # MPS付きでコンパイルされた場合True

device = torch.device("mps")

# モデルをMPSに移動
model = YourTransformerModel()
model = model.to(device)

# テンソル演算もMPSで実行
x = torch.randn(1, 512, device=device)
output = model(x)

# 内部的に起きていること:
# PyTorch → MPSバックエンド → Metal API → GPUカーネル実行
# CUDAと違い、カーネルはMSL(Metal Shading Language)で記述

MLX:Apple Silicon専用機械学習フレームワーク

2023年末にAppleが公開したMLXは、Apple Siliconのために一から設計されたMLフレームワークです。NumPy風のAPIを提供しながら、ユニファイドメモリを最大限に活用します。

import mlx.core as mx
import mlx.nn as nn

# MLXのキーイノベーション:遅延評価(Lazy Evaluation)
a = mx.array([[1.0, 2.0], [3.0, 4.0]])
b = mx.array([[1.0, 0.0], [0.0, 1.0]])

# この時点ではまだ計算が行われていない!
c = a @ b        # 計算グラフのみ構築
d = mx.exp(c)    # 追加演算グラフ
e = d.sum()      # さらに追加

# mx.eval()呼び出し時に全グラフを最適化して一度に実行
mx.eval(e)       # ここで実際のGPU演算が起きる

print(e)  # [[2.71828...]]

遅延評価の利点:

  1. グラフ最適化:不要な中間メモリ確保の排除
  2. カーネルフュージョン:複数の小さな演算を1つのGPUカーネルに統合
  3. ユニファイドメモリの活用:CPU/GPU間の明示的なデータ移動なし
# MLXでTransformerのattentionを実装
import mlx.core as mx
import mlx.nn as nn
import math

class MultiHeadAttention(nn.Module):
    def __init__(self, d_model: int, num_heads: int):
        super().__init__()
        self.num_heads = num_heads
        self.d_head = d_model // num_heads
        self.scale = math.sqrt(self.d_head)

        self.q_proj = nn.Linear(d_model, d_model)
        self.k_proj = nn.Linear(d_model, d_model)
        self.v_proj = nn.Linear(d_model, d_model)
        self.out_proj = nn.Linear(d_model, d_model)

    def __call__(self, x: mx.array, mask=None):
        B, T, C = x.shape

        q = self.q_proj(x).reshape(B, T, self.num_heads, self.d_head).transpose(0, 2, 1, 3)
        k = self.k_proj(x).reshape(B, T, self.num_heads, self.d_head).transpose(0, 2, 1, 3)
        v = self.v_proj(x).reshape(B, T, self.num_heads, self.d_head).transpose(0, 2, 1, 3)

        scores = (q @ k.transpose(0, 1, 3, 2)) / self.scale

        if mask is not None:
            scores = scores + mask

        weights = mx.softmax(scores, axis=-1)
        out = (weights @ v).transpose(0, 2, 1, 3).reshape(B, T, C)
        return self.out_proj(out)

4. LLMサービングツールと実測ベンチマーク

llama.cpp + Metalバックエンド

llama.cppは現在Apple SiliconでLLMを動かす最も検証された方法です。MetalバックエンドでGPUワークロードをルーティングします。

# Metal対応のllama.cppビルド
git clone https://github.com/ggerganov/llama.cpp
cd llama.cpp
cmake -B build -DLLAMA_METAL=ON
cmake --build build --config Release -j

# M4 ProでLlama 3.1 8Bを実行
./build/bin/llama-cli \
  -m models/llama-3.1-8b-q4_k_m.gguf \
  -p "Explain transformer architecture" \
  -n 200 \
  --n-gpu-layers 999  # すべてのレイヤーをGPU(Metal)にオフロード
# 期待出力:~45-50 tok/s(M4 Pro 48GB)

# Metalデバッグログ有効化
GGML_METAL_LOG_LEVEL=1 ./build/bin/llama-cli -m model.gguf ...

Ollama:llama.cppをラップしたプロダクションサーバー

# Ollamaのインストールと使用
brew install ollama
ollama serve  # バックグラウンドサーバー起動

# モデル別パフォーマンス(M4 Pro 48GB実測値)
ollama run llama3.2         # 3B, Q4_K_M: ~80-85 tok/s
ollama run llama3.1:8b      # 8B, Q4_K_M: ~45-50 tok/s
ollama run llama3.1:70b     # 70B, Q4_K_M: 48GB境界線上、~6-8 tok/s
# M4 Max 128GBでは:llama3.1:70bが~8-10 tok/sで快適に動作

# PythonからOllama APIを使用
import ollama

response = ollama.chat(
    model='llama3.1:8b',
    messages=[{'role': 'user', 'content': 'RLHFを詳しく説明してください'}]
)
print(response['message']['content'])

パフォーマンス比較表

モデル量子化M4 Pro 48GBM4 Max 128GBRTX 4090 24GB
Llama 3.2 3BQ4_K_M~80 tok/s~100 tok/s~130 tok/s
Llama 3.1 8BQ4_K_M~45 tok/s~60 tok/s~110 tok/s
Llama 3.1 8BFP16~20 tok/s~35 tok/s~85 tok/s
Llama 3.1 70BQ4_K_M~6 tok/s~8 tok/sOOM(24GB不足)
Llama 3.1 70BQ8OOM~4 tok/sOOM
Mistral 7BQ4_K_M~50 tok/s~65 tok/s~120 tok/s

実測値、プロンプト長とKVキャッシュ状態により変動


5. GGUF量子化がApple Siliconで輝く理由

K-Quants量子化方式の理解

GGUFフォーマットのQ4_K_Mは単純な4ビット量子化ではありません。K-quantsはブロック単位で異なる精度を適用する混合精度方式です。

# Q4_K_M量子化プロセス(簡略化)
import torch

def quantize_q4_k(weight_tensor, block_size=32):
    """
    K-Quants:ブロック単位のscaleとminをFP16で保存
    実際のweightは4ビット整数として保存
    """
    B, N = weight_tensor.shape
    num_blocks = N // block_size

    quantized_blocks = []
    scales = []
    mins = []

    for i in range(num_blocks):
        block = weight_tensor[:, i*block_size:(i+1)*block_size]

        block_min = block.min(dim=-1, keepdim=True).values
        block_max = block.max(dim=-1, keepdim=True).values

        # 0-15の範囲に正規化(4bit = 16レベル)
        scale = (block_max - block_min) / 15.0
        q = torch.round((block - block_min) / scale).clamp(0, 15).to(torch.uint8)

        quantized_blocks.append(q)
        scales.append(scale.to(torch.float16))
        mins.append(block_min.to(torch.float16))

    return quantized_blocks, scales, mins

# 推論時の逆量子化
def dequantize_q4_k(quantized, scales, mins):
    """4ビット整数をFP16に復元"""
    return quantized.float() * scales + mins

# メモリ節約計算:
# FP16 70Bモデル:70B * 2 bytes = 140 GB
# Q4_K_M 70Bモデル:~40 GB(約71%削減)

x86対Apple Siliconでの量子化推論の差

x86 CPUで量子化モデルを動かすと、逆量子化プロセスでボトルネックが生じます。AVX-512があっても4ビット演算の効率は低いです。

一方Apple Silicon GPUは:

  1. Metal shaderで最適化された4ビット演算をサポート
  2. ユニファイドメモリ:逆量子化後すぐに行列積が可能(別途コピー不要)
  3. INT8/INT4演算ユニットがGPU内に統合
# 量子化タイプ比較(M4 Max 128GB、Llama 3.1 70B)
# Q2_K   : ~18GB、品質損失大、~12 tok/s
# Q4_0   : ~35GB、適度な品質、~8 tok/s
# Q4_K_M : ~42GB、良い品質、~8 tok/s(推奨)
# Q5_K_M : ~52GB、非常に良い品質、~6 tok/s
# Q8_0   : ~70GB、ほぼFP16品質、~4 tok/s
# FP16   : ~140GB(128GBに載らない!)

# 結論:Q4_K_Mが品質と速度の最適バランス点

6. M5チップ予測とAppleのAIロードマップ

M4確認済みスペック(2024年)

M4:       10 CPUコア(4P+6E)、10 GPUコア、38 TOPS ANE16-32GB
M4 Pro:   14 CPUコア(10P+4E)、20 GPUコア、38 TOPS ANE24-64GB
M4 Max:   14 CPUコア(10P+4E)、40 GPUコア、38 TOPS ANE48-128GB
M4 Ultra: 28 CPUコア、80 GPUコア、76 TOPS ANE、192GB(M4 Max x2)
メモリ帯域幅: M4=120GB/s、M4 Pro=273GB/s、M4 Max=546GB/s、M4 Ultra=819GB/s

M5の展望(2025-2026年予想)

業界アナリストの予測を総合すると:

M5予想スペック(N3Pプロセス、2025年後半):
- TSMC 3nm N3Pプロセス(M4N3Eより~15-20%電力効率向上)
- CPUM5 Pro基準20コア(12P + 8E)予想
- GPUM5 Max基準50 GPUコア予想
- Neural Engine:50+ TOPS予想
- メモリ:M5 Max最大192GB(現M4 Max 128GBから増加)
- メモリ帯域幅:M5 Max基準700+ GB/s予想(M4 Maxの546~30%増加)

M5への最大の関心はメモリ容量の拡張です。192GB M5 Maxが出れば、Llama 3.1 70BをQ8(~70GB)、あるいはほぼFP16(~140GB)で余裕を持って動かせます。

AppleのオンデバイスAI戦略

AppleはPrivate Cloud Compute(PCC)とオンデバイスモデルのハイブリッド戦略を追求しています。iPhone 16には~3BパラメータのApple IntelligenceモデルがANE実行で搭載されており、Macではより大きなモデルを実行します。

Apple Intelligenceアーキテクチャ(推測):
ユーザーリクエスト
オンデバイスモデル(~3B、ANE実行)
     ↓(複雑なリクエストのみ)
Private Cloud Compute(より大きなモデル、Apple Siliconサーバー)

7. 実践設定:MacでローカルLLM環境を構築

MLX-LMでモデルを動かす

# mlx-lmのインストール
pip install mlx-lm

# Hugging FaceモデルをMLX形式に変換して実行
python -m mlx_lm.convert \
  --hf-path meta-llama/Llama-3.1-8B-Instruct \
  --mlx-path mlx_models/llama-3.1-8b \
  --quantize \
  --q-bits 4

# 変換されたMLXモデルの実行
python -m mlx_lm.generate \
  --model mlx_models/llama-3.1-8b \
  --prompt "Transformerのattentionメカニズムを説明してください" \
  --max-tokens 500
# PythonからMLX-LMを直接使用
from mlx_lm import load, generate

model, tokenizer = load("mlx-community/Llama-3.1-8B-Instruct-4bit")

prompt = "あなたは親切なアシスタントです。Apple SiliconがAI推論に特有な理由を説明してください。"

response = generate(
    model,
    tokenizer,
    prompt=prompt,
    max_tokens=500,
    verbose=True,  # トークン生成速度を出力
)

メモリとGPU使用量のモニタリング

# Apple Siliconのメモリ・GPU使用量確認
# Activity Monitor > Memory タブ、または:

# powermetrics(rootが必要)
sudo powermetrics --samplers gpu_power -i 500 -n 5

# asitop(サードパーティ、pip install asitop)
sudo asitop
# CPU/GPU/ANE稼働率、メモリ帯域幅、電力消費をリアルタイム表示

8. Apple Silicon対NVIDIA:現実的な選択基準

比較表

ユースケースApple SiliconNVIDIA GPU推奨
ローカルLLM実験(70B以下)M4 Max 128GB可能24GB VRAMでは不可Apple Silicon
ローカルLLM実験(8B以下)M4 Proで十分RTX 4090も可好み/予算
プロダクションサービング(大規模)非効率A100/H100が最適NVIDIA
モデルファインチューニング(70B)非常に遅い8x H100推奨NVIDIA
バッテリー/移動性MacBookで15-20Wデスクトップで300-400WApple Silicon
メモリ容量(単体)M4 Ultra 192GBH100 SXM 80GBApple Silicon
コスト効率(推論)MacBook 50-90万円RTX 4090 30万円+電気代同程度
ソフトウェアエコシステム限定的(急成長中)CUDA圧倒的NVIDIA
CUDAコード互換性不可完全サポートNVIDIA

正直な結論

Apple Siliconが優れている場合:

  • 一人で開発しながら大きなモデル(30B-70B)をローカルで動かしたい場合
  • 移動しながら作業する場合
  • バッテリー効率が重要な場合
  • すでにMacエコシステムにいる場合

NVIDIAを選ぶべき場合:

  • プロダクション環境でスループットが重要な場合
  • モデル学習・ファインチューニングが主な作業の場合
  • PyTorch/CUDAエコシステムの最新機能をすぐに使う必要がある場合
  • チーム全体で同じ開発環境が必要な場合

個人的には、MLエンジニアであれば、Mac(Apple Silicon)でのローカル開発とクラウドのA100/H100アクセス権を組み合わせるのが2026年現在最も実用的な選択です。


まとめ

Apple SiliconのUMAはマーケティング用語ではありません。PCIeのボトルネックを排除し、大容量のメモリプールを提供し、低消費電力で実用的なLLM推論を可能にします。llama.cpp + Metal + GGUF Q4_K_Mの組み合わせは、2026年現在MacでLLMを動かす最も検証された方法です。

M5チップが700+ GB/sのメモリ帯域幅で登場すれば、ノートPC一台でより速い70B推論が現実になります。AppleがMLXエコシステムを育て続ければ、将来のApple Siliconはさらに魅力的なローカルAI推論プラットフォームになるでしょう。

NVIDIAとCUDAの長年の覇権に、初めて実質的な対抗馬が生まれたという意味で、Apple Siliconの登場はMLエンジニア全員にとって喜ばしいことです。