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

この記事で作るもの

  • Apple純正の機械学習フレームワーク「MLX」を利用し、MacのGPUパワーを最大限に引き出してLlama 3などの最新LLMを高速動作させるPython環境を構築します。
  • 最終的に、ターミナル上でAIとリアルタイムに対話できるストリーミング形式のチャットスクリプトを完成させます。
  • 前提知識として、基本的なターミナル操作とPythonの基礎(pipインストールや関数の実行)ができることを想定しています。

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

Mac Studio M2 Max

64GB以上のメモリがあれば、30B以上の大型モデルも高速に動かせる最強のローカルLLM機になるため

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

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

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

MacでローカルLLMを動かす際、CPUの世代よりも「ユニファイドメモリ(RAM)の容量」がすべてを決めます。 MLXはGPUとCPUがメモリを共有するApple Siliconの特性を極限まで活かす設計だからです。

最低ラインはメモリ16GBです。 8GBモデルでも動作自体は可能ですが、OSやブラウザがメモリを消費している状態で7B(70億パラメータ)クラスのモデルを動かすと、スワップが発生してパフォーマンスが極端に落ち、実用的ではありません。

理想は32GB以上のメモリを積んだ「M2 Pro / M3 Pro」以上のチップを搭載したモデルです。 16GBメモリの場合、4bit量子化されたLlama 3 (8B) クラスが限界ですが、32GBあれば14B〜30Bクラスのモデルも視野に入ります。

もしこれからハードウェアを調達するなら、中古のMac Studio(M1 Max / 64GBメモリ以上)が最もコストパフォーマンス良くローカルLLM専用機になります。 逆に、最新のM3 MacBook Airでもメモリが8GBなら、ローカルLLM用途としては「買い」ではありません。

料金面では、MLX自体はオープンソースで無料、Hugging Faceからダウンロードするモデルも無料です。 一度環境を作ってしまえば、API利用料を気にせず24時間365日推論し放題になります。

なぜこの方法を選ぶのか

MacでLLMを動かす選択肢には、有名な「llama.cpp(Ollama)」もあります。 しかし、Pythonエンジニアが「自分のプログラムに組み込みたい」「独自のデータを学習(ファインチューニング)させたい」と考えるなら、MLX一択です。

llama.cppはC++ベースで非常に高速ですが、Pythonから扱う場合はバインディングを通す必要があり、内部構造のカスタマイズがやや面倒です。 一方、MLXはAppleのAIチームが「PyTorchのように書けて、Apple Siliconで最速」を目指して開発したライブラリです。

実際に私がLlama 3 (8B) で検証したところ、llama.cppと比較してもMLXの方がトークン生成速度(tokens/sec)が10〜15%ほど高い数値を出しました。 Apple公式がメンテナンスしているため、新しいチップ(M4など)への最適化も他より圧倒的に早いです。

Step 1: 環境を整える

まずは、Python 3.10以上がインストールされていることを確認してください。 既存の環境を汚さないよう、仮想環境(venv)を作成して作業することをおすすめします。

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

# 仮想環境を作成
python3 -m venv .venv

# 仮想環境を有効化
source .venv/bin/activate

# MLX関連ライブラリをインストール
pip install mlx-lm mlx huggingface_hub

mlx-lmは、MLXでLLMを簡単に扱うためのハイレベルなライブラリです。 これを入れるだけで、Hugging Faceにある何千ものモデルをApple Silicon最適化済み形式で直接ロードできるようになります。 huggingface_hubはモデルのダウンロードを管理するために必要です。

落とし穴: Intel製プロセッサを搭載した古いMacではMLXは動きません。 Apple Silicon専用の命令セットを利用しているため、pip install自体は成功しても、実行時に必ずエラーになります。 自分のMacが「M1/M2/M3/M4」のいずれかであることを必ず確認してください。

Step 2: モデルの選定と初期設定

MLXでモデルを動かすには、MLX専用のフォーマットに変換されたモデルファイルを使用します。 幸いなことに、mlx-communityというアカウントが、主要なモデルをすべて変換してアップロードしてくれています。

今回は、日本語能力と性能のバランスが非常に良い「Llama-3-8B」の4bit量子化版を使用します。 量子化(Quantization)とは、モデルの精度をわずかに犠牲にしてメモリ消費量を大幅に削減する技術です。 4bit版なら、メモリ16GBのMacBook Airでも30 tokens/sec程度の爆速で動きます。

以下のコードを config.py として保存してください。

import os

# 使用するモデルのIDを指定
# mlx-communityにある4bit量子化モデルが最も扱いやすいです
MODEL_ID = "mlx-community/Meta-Llama-3-8B-Instruct-4bit"

# モデルの保存先を明示的に指定(デフォルトは ~/.cache/huggingface)
# 大容量になるため、外付けSSDなどを使いたい場合はここを変更します
CACHE_DIR = os.path.expanduser("./models")

# モデルを読み込む際の設定
LOAD_KWARGS = {
    "trust_remote_code": True
}

「なぜ4bitなのか」という理由ですが、8bitやFP16(無劣化)にしても、チャット用途では人間が違いを感じるほどの精度差は出にくいからです。 それよりも、メモリを節約して推論速度を上げるほうが、開発体験は圧倒的に向上します。

Step 3: 動かしてみる

いよいよ、PythonからMLXを呼び出してテキストを生成させます。 まずは最小構成のコードで、正しくGPUが認識されているかを確認しましょう。

main.py を作成して、以下のコードを記述します。

from mlx_lm import load, generate
from config import MODEL_ID, CACHE_DIR

# モデルとトークナイザーをロード
# 最初の実行時はダウンロードが始まるため、数分かかります
print(f"Loading model: {MODEL_ID}...")
model, tokenizer = load(MODEL_ID, cache_dir=CACHE_DIR)

# プロンプトの準備
# Llama 3のテンプレートに合わせるのが精度を出すコツです
prompt = "Apple Siliconのすごさを、エンジニア向けに3行で説明してください。"
messages = [{"role": "user", "content": prompt}]
formatted_prompt = tokenizer.apply_chat_template(
    messages, tokenize=False, add_generation_prompt=True
)

# テキスト生成
# max_tokensを制限しないと、止まらなくなることがあるので注意
response = generate(
    model,
    tokenizer,
    prompt=formatted_prompt,
    max_tokens=500,
    verbose=True # ログを表示
)

print("\n--- AIの回答 ---")
print(response)

期待される出力

Loading model: mlx-community/Meta-Llama-3-8B-Instruct-4bit...
Fetching 5 files: 100%|███████████████████████████████| 5/5 [00:00<00:00, 150.31it/s]

--- AIの回答 ---
1. ユニファイドメモリ構造により、CPUとGPU間で巨大な重みデータをコピーするオーバーヘッドがゼロであること。
2. ワットパフォーマンスが圧倒的で、ファンレスのAirでも数千億規模の計算を熱スロットリングなしに回せること。
3. MLXフレームワークがハードウェアのポテンシャルを直接叩くため、PyTorchを凌駕する推論速度が出せること。

verbose=True を設定していると、ターミナルに生成速度が表示されます。 Prompt processing: 250 tokens/secGeneration: 35 tokens/sec といった数字が出ていれば、MLXが正しくGPUを使って動作している証拠です。

Step 4: 実用レベルにする(ストリーミング実装)

先ほどのコードは、すべての文章が生成し終わるまで画面に何も表示されません。 これではChatGPTのような使い勝手にならないため、生成されたそばから一文字ずつ表示される「ストリーミング処理」に変更します。

これができるようになると、ユーザーの待ち時間が体感でゼロになります。

import sys
from mlx_lm import load, stream
from config import MODEL_ID, CACHE_DIR

def run_chat():
    model, tokenizer = load(MODEL_ID, cache_dir=CACHE_DIR)

    while True:
        user_input = input("\nあなた: ")
        if user_input.lower() in ["exit", "quit"]:
            break

        messages = [{"role": "user", "content": user_input}]
        prompt = tokenizer.apply_chat_template(
            messages, tokenize=False, add_generation_prompt=True
        )

        print("AI: ", end="", flush=True)

        # stream関数を使うことで、1トークンずつ取得可能
        # temp=0.7 くらいが、回答の創造性と正確性のバランスが良いです
        occurrence = 0
        for response in stream(
            model,
            tokenizer,
            prompt=prompt,
            max_tokens=1000,
            temp=0.7
        ):
            print(response, end="", flush=True)
            occurrence += 1

        print("\n")

if __name__ == "__main__":
    run_chat()

このコードでは stream 関数を使用しています。 flush=True を指定することで、バッファを強制的に出力し、リアルタイムなチャット体験を実現しています。 実務でSlackボットやWeb UIを作る際も、このストリーミング処理をベースにするのが基本です。

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

エラー内容原因解決策
ImportError: No module named 'mlx'ライブラリが未インストール、または仮想環境が未有効。source .venv/bin/activate を実行してから再試行。
Killed または OutOfMemoryメモリ不足。OSや他アプリがメモリを食い過ぎている。ブラウザのタブを閉じるか、より小さい(量子化された)モデルに変更。
回答が英語になるプロンプトに「日本語で答えて」と明示していない。システムプロンプトに「You are a helpful Japanese assistant.」を追加する。
Model not foundHugging FaceのモデルIDが間違っている。mlx-community ページで正しいIDを確認する。

次のステップ

MLXでローカルLLMを動かせるようになったら、次は「自分専用の知識」を教え込むステップに進みましょう。

  1. RAG(検索拡張生成)の実装: PDFファイルやテキストファイルを読み込み、その内容に基づいて回答させる仕組みです。MLXは推論が速いため、ローカル環境でも高速なRAGシステムが構築できます。
  2. LoRAによるファインチューニング: MLXには mlx-examples という公式リポジトリがあり、そこにはLoRA(低ランク適応)を使った追加学習のコードが含まれています。自分の過去のメールやチャットログを学習させて、自分の口癖を真似するAIを作ることも可能です。
  3. UIの実装: StreamlitやGradioを使えば、わずか数十行のコードでWebブラウザから操作できるチャット画面を構築できます。

ローカルLLMの最大のメリットは「プライバシー」です。 機密情報を含むコードのレビューや、個人的な悩み相談など、外部サーバーにデータを送りたくないタスクにこそ、今回構築したMLX環境を役立ててください。

よくある質問

Q1: MacBook Air (メモリ8GB) でも動きますか?

動きますが、推奨はしません。Llama 3 8Bの4bit版は約5GBのメモリを占有します。OSが3GB程度使うため、ギリギリです。動作が極端に重くなる場合は、さらに小さいモデル(Gemma-2BやQwen-1.5Bなど)を試してみてください。

Q2: 性能を上げるために設定できるパラメータはありますか?

temp (Temperature) が重要です。0に近づけると決定論的(常に同じ回答)になり、1に近づけると創造的になります。技術的な質問なら0.1〜0.2、物語の創作なら0.8以上にするのがセオリーです。

Q3: GPUの使用率が上がっていないように見えるのですが?

MLXは「アクティビティモニタ」の「GPUグラフ」で確認できますが、ユニファイドメモリの特性上、CPUとGPUの境界が曖昧です。生成速度(tokens/sec)が20を超えていれば、確実にGPUが活用されています。


あわせて読みたい