所要時間: 約30分 | 難易度: ★★☆☆☆

この記事で作るもの

Apple Silicon(M1/M2/M3/M4チップ)の性能をフルに引き出し、Llama 3やQwenといった最新のLLMを「メモリ消費を抑えつつ高速に」動かすPythonスクリプトを作成します。 既存のライブラリよりも圧倒的に効率が良いMLXフレームワークを使い、ストリーミング形式で回答を表示する実用的なチャットプログラムを構築します。

前提知識:Pythonの基本的な構文(pipでのインストールや関数の呼び出し)がわかること 必要なもの:Apple Silicon搭載のMac(Intel Macは不可)、インターネット環境

先に確認するスペック・料金

ローカルLLMを動かす上で、最も重要なのは「チップの種類」ではなく「ユニファイドメモリの容量」です。 MLXはGPUとCPUがメモリを共有するApple Siliconの特性を最大限に活かすため、VRAMという概念に縛られず、積んでいるメモリの多くをLLMに割り当てられます。

最低でも16GBのメモリを積んだモデルを推奨します。 8GBモデルでも動作自体は可能ですが、OSやブラウザが使用する領域を差し引くと、4bit量子化した7B(70億パラメータ)クラスのモデルを動かすのが精一杯で、推論中にスワップが発生して速度が著しく低下します。

一方で、32GB以上のメモリがあれば、14Bや30Bといった、より知能の高いモデルを余裕を持って動かせるようになります。 RTX 4090を2枚挿している私の環境と比較しても、MLXを使ったMac Studio(M2 Ultra / 128GBメモリ)での推論は、メモリ帯域の広さのおかげで非常に快適です。 ソフトウェア自体はオープンソースなので、API利用料のような実行コストは一切かかりません。電気代だけです。

なぜこの方法を選ぶのか

MacでローカルLLMを動かす手段として、LM StudioやOllamaといった素晴らしいGUI/CLIツールが既に存在します。 それらは「ただ動かすだけ」なら最適ですが、自分のPythonプログラムに組み込んだり、独自のロジックで制御したりするには不向きです。

また、PyTorchのMPS(Metal Performance Shaders)を使う方法もありますが、これはあくまでNvidia GPU向けの設計をMacに移植したものです。 対してMLXは、Appleの機械学習チームが「Apple Siliconのためだけ」にゼロから開発したフレームワークです。

MLXは「ゼロコピー」という仕組みを採用しており、CPUとGPUの間でデータをコピーする無駄なプロセスが発生しません。 この設計により、PyTorchで動かすよりもメモリ消費を20〜30%抑えられ、推論速度(tokens/sec)も1.5倍から2倍近く向上する場合が多いです。 実務でMac向けのAIアプリを開発するなら、MLX一択と言っても過言ではありません。

Step 1: 環境を整える

まずはMLXを動かすための専用環境を作ります。 システム全体のPython環境を汚すと、後でライブラリの依存関係で詰まる原因になるため、必ず仮想環境を使用してください。

# プロジェクト用のディレクトリを作成
mkdir mlx-test && cd mlx-test

# Python 3.11以上を推奨(MLXの最適化が進んでいるため)
python3 -m venv .venv
source .venv/bin/activate

# mlx-lmパッケージをインストール
pip install -U mlx-lm

mlx-lmは、Hugging FaceにあるモデルをMLX形式でロードし、推論を実行するための高レベルライブラリです。 これ一つ入れるだけで、モデルのダウンロード、量子化、推論のすべてが完結します。

⚠️ 落とし穴: Xcode Command Line Toolsがインストールされていないと、依存ライブラリのビルドでエラーが出ることがあります。 xcode-select --installを実行して、最新のツールセットを導入しておいてください。 また、Pythonのバージョンが古い(3.9未満)と、MLXの最新機能が動かないため、必ず最新の安定版を使うようにしてください。

Step 2: 基本の設定

次に、動かしたいモデルを選びます。 MLXコミュニティが、Hugging Face上にMLX最適化済みのモデルを多数公開しています。 今回は、日本語能力が高く軽量な「Llama-3-8B」の量子化版を使います。

import os
from mlx_lm import load, generate

# 使用するモデルの指定(Hugging Faceのリポジトリ名)
# mlx-communityが配布している4-bit量子化済みモデルを選ぶのが最も効率的です
model_id = "mlx-community/Meta-Llama-3-8B-Instruct-4bit"

# モデルとトークナイザーをロード
# 初回実行時は自動的に数GBのダウンロードが始まります
model, tokenizer = load(model_id)

print("モデルのロードが完了しました。")

ここで4bit版を選ぶ理由は、メモリ消費と速度のバランスが最も優れているからです。 非量子化(FP16)版は精度は高いですが、メモリを15GB以上消費するため、16GBメモリのMacでは動作が不安定になります。 4bit版なら4GB程度のメモリ消費で済み、知能の低下も実務レベルではほとんど気になりません。

Step 3: 動かしてみる

まずは最小限のコードで、テキストが生成されるか確認しましょう。 MLXのgenerate関数は、非常にシンプルに設計されています。

# ユーザーからの入力
prompt = "美味しいリンゴの見分け方を3つ教えてください。"

# Llama 3のChatテンプレートを適用
# これをしないと、モデルが対話モードとして正しく振る舞いません
messages = [{"role": "user", "content": prompt}]
formatted_prompt = tokenizer.apply_chat_template(
    messages, tokenize=False, add_generation_prompt=True
)

# 推論の実行
response = generate(model, tokenizer, prompt=formatted_prompt, verbose=False)

print(response)

期待される出力

美味しいリンゴの見分け方を3つ紹介します。
1. お尻の部分の色:お尻が黄色やオレンジ色になっているものは熟しています。緑色のものはまだ酸味が強い証拠です。
2. 重さと硬さ:手に持った時にずっしりと重みがあり、全体的に硬く締まっているものを選びましょう。
3. 皮のツヤとベタつき:皮に張りとツヤがあり、少しベタついているのは「油上がり」といって熟しているサインです。

(※モデルや設定により回答内容は異なります)

このコードの肝はapply_chat_templateです。 モデルごとに「ユーザーの発言はここから」「AIの回答はここから」という特定のフォーマット(Llama-3なら<|begin_of_text|>など)が決まっています。 これを手動で書くとミスをしやすいですが、トークナイザーに任せることで、適切なフォーマットに自動変換してくれます。

Step 4: 実用レベルにする

上記のコードは、回答がすべて生成されるまで画面に何も表示されず、ユーザーを待たせてしまいます。 実務で使うなら、ChatGPTのように文字がパラパラと出てくる「ストリーミング出力」が必要です。 また、システムプロンプトを設定してAIの振る舞いを固定します。

import sys
from mlx_lm import load, stream

# 実用的な設定:ストリーミング生成関数
def chat_with_ai(user_input):
    model_id = "mlx-community/Meta-Llama-3-8B-Instruct-4bit"
    model, tokenizer = load(model_id)

    # システムプロンプトでAIのキャラクターを設定
    messages = [
        {"role": "system", "content": "あなたは技術に詳しい親切なアシスタント「ねぎ」です。簡潔に回答してください。"},
        {"role": "user", "content": user_input}
    ]

    prompt = tokenizer.apply_chat_template(
        messages, tokenize=False, add_generation_prompt=True
    )

    print("AIの回答: ", end="", flush=True)

    # stream関数を使い、1トークンずつ取得して表示
    # max_tokensで長文になりすぎるのを防ぎ、温度(temp)で回答のランダム性を調整
    for response in stream(model, tokenizer, prompt=prompt, max_tokens=512, temp=0.7):
        print(response, end="", flush=True)
    print("\n")

if __name__ == "__main__":
    query = "Apple Siliconのメモリ帯域がLLMに与えるメリットは何ですか?"
    chat_with_ai(query)

このコードではstream関数を使っています。 temp=0.7(温度パラメータ)を設定しているのは、回答に程よい多様性を持たせるためです。 0に近づけると常に同じ回答を返す「堅実なAI」になり、1に近づけると「独創的(かつ支離滅裂になりやすい)なAI」になります。 実務的なタスクなら0.2〜0.5、雑談なら0.7〜0.8あたりが使いやすいですね。

よくあるトラブルと解決法

エラー内容原因解決策
ModuleNotFoundError: No module named 'mlx'仮想環境が未有効化、またはインストール失敗source .venv/bin/activateを実行後、再度pipインストール
推論が極端に遅い(1文字数秒かかる)メモリ不足によるスワップ発生他の重いアプリ(Chrome等)を閉じる。より小さいモデル(3Bクラス)を試す
Killed: 9OSによる強制終了(メモリ超過)量子化されていない重いモデルを動かそうとしている。4bit版をロードする
日本語が文字化けする・支離滅裂モデルが日本語非対応Meta-Llama-3系やQwen2系など、日本語学習済みのモデルIDを指定する

次のステップ

MLXでローカルLLMが動かせるようになったら、次は「自分専用の知識」をAIに持たせるRAG(検索拡張生成)に挑戦することをお勧めします。 PDFやドキュメントから情報を抽出し、MLXで推論するスクリプトを組み合わせれば、機密情報を外部に送らずに解析できる「究極のプライベートAI」が完成します。

さらに、mlx-lmにはconvertコマンドがあり、Hugging Faceにある通常のPyTorchモデルを自分でMLX形式に変換することも可能です。 新しいモデルが発表された当日、まだ誰もMLX版を出していない時に、自分で変換して真っ先に動かすのは格別の体験です。

また、マルチモーダルモデル(LLaVAなど)をMLXで動かせば、画像の内容をMacローカルで説明させることもできます。 APIの制限や料金を気にせず、自分のコードでAIを制御できる自由度を手に入れると、もうクラウドのAPIには戻れなくなりますよ。

よくある質問

Q1: メモリ8GBのMacBook Airでも快適に動きますか?

正直に言うと、「快適」とは言えません。動作はしますが、モデルをロードした時点でメモリの限界に近く、生成速度は1秒間に数トークン程度まで落ち込むことが多いです。8GBモデルなら、より軽量なGemma-2BPhi-3といった20億〜30億パラメータのモデルを選ぶのが現実的な選択肢です。

Q2: 独自の学習(ファインチューニング)もMLXでできますか?

はい、可能です。MLXにはLoRA(Low-Rank Adaptation)を用いた学習スクリプトも同梱されています。数千件程度のデータであれば、MacBook Pro 1台で数十分から数時間で学習を完了させることができます。自分の書き方の癖を学習させた「分身AI」を作ることも夢ではありません。

Q3: GPU(Metal)が使われているか確認する方法は?

アクティビティモニタの「GPUの履歴」を表示した状態でスクリプトを実行してください。推論中にGPUグラフが跳ね上がっていれば、正しくMLXがハードウェアを叩いています。もしCPU負荷だけが高い場合は、mlxのバージョンや環境設定を見直す必要があります。


1. X投稿用ツイート本文 (TWEET_TEXT) 2. アフィリエイト商品情報 (AFFILIATE_CONTEXT)

3. SNS拡散用ハッシュタグ (HASHTAGS) 4. SEOタグ (SEO_TAGS) 5. URLスラッグ (SLUG)

📦 この記事に関連する商品(楽天メインで価格確認)

MacBook Pro 36GBモデル

14Bモデルを余裕で動かしつつ、ブラウザ等の他作業を並行できるメモリ容量

楽天で価格を見る Amazonでも確認

※アフィリエイトリンクを含みます


あわせて読みたい