【Apple Silicon最適化】MLXでLlama 3をMacローカルに導入しLoRAファインチューニングする実践ガイド

Apple Silicon(M1/M2/M3/M4チップ)を搭載したMacは、CPUとGPUが物理的に同じメモリ空間を共有する「ユニファイドメモリ」構造を採用しています。これにより、VRAM(ビデオメモリ)が不足しがちな一般的なコンシューマーPCとは異なり、数十GBクラスの大規模言語モデル(LLM)であってもMac上で高速に処理できるポテンシャルを秘めています。

しかし、これまでのPyTorchやTensorFlowでは、Apple SiliconのGPU(Apple GPU)を限界まで使い切るのが難しいケースがありました。そこで登場したのが、Appleの機械学習研究チームが開発したオープンソースのフレームワーク「MLX公式GitHubリポジトリ」です。

この記事では、MLXを使ってMetaのオープンソースLLMである「Llama 3」をMacローカルに導入し、さらに独自のデータセットを使って「LoRA(Low-Rank Adaptation)」によるファインチューニングを行う手順を徹底解説します。


1. Apple Silicon特化フレームワーク「MLX」の強み

MLXは、Apple Siliconのパフォーマンスを極限まで引き出すために設計されたNumPy風の配列フレームワークです。以下のような特徴を持っています。

  • ゼロコピー(Zero-copy)メモリ共有: CPUとGPUが同じメモリを直接読み書きするため、データのコピーオーバーヘッドが一切発生しません。
  • 遅延評価(Lazy Evaluation): 必要になるまで計算を行わず、計算グラフを動的に構築・最適化して実行します。
  • 簡潔なエコシステム: Apple公式チームが、mlx-examplesリポジトリを通じて、LLM、画像生成(Stable Diffusion)、音声認識(Whisper)などの実装をすぐに試せる形で提供しています。

Llama.cppなどをベースにしたOllamaやLM Studioも推論には便利ですが、自分で用意したデータセットで「ローカルファインチューニング」までを行う場合、Pythonで柔軟にカスタマイズ可能なMLXが最も推奨される選択肢になります。


2. 開発環境の構築

まずは環境を準備します。本ガイドではPython 3.10以上がインストールされたmacOS環境を前提としています。

2.1. 必要なパッケージのインストール

ターミナルを開き、以下のコマンドで mlxmlx-lm、および関連パッケージをインストールします。mlx-lm は、Hugging FaceのモデルをMLX用に最適化してダウンロード・動作させるためのハイレベルなパッケージです。

pip install mlx mlx-lm huggingface_hub

2.2. 学習用サンプルリポジトリのクローン

LoRAファインチューニングを実行するため、公式のサンプルリポジトリをローカルにクローンします。

git clone https://github.com/ml-explore/mlx-examples.git
cd mlx-examples/llms
pip install -r requirements.txt

これで準備は完了です。


3. Llama 3のローカル推論テスト(ストリーミング形式)

まずはファインチューニングのベースとなるモデルが正常に動作するかテストしましょう。MLX開発チームや有志コミュニティが、すでに4-bit量子化されたLlama 3を「mlx-communityのHugging Faceハブ」上で多数公開しています。今回は最もポピュラーな 8B の量子化モデルを使用します。

以下のPythonスクリプトを作成し、test_inference.py として保存して実行してください。テキストがリアルタイムに一文字ずつ出力される「ストリーミング推論」を実装しています。

import sys
from mlx_lm import load, stream

model_id = "mlx-community/Meta-Llama-3-8B-Instruct-4bit"

# モデルとトークナイザーのロード(初回実行時は自動ダウンロードされます)
model, tokenizer = load(model_id)

# Llama 3専用のチャットフォーマットに従ってプロンプトを構築
prompt = (
    "<|begin_of_text|><|start_header_id|>user<|end_header_id|>\n\n"
    "Apple Silicon MacでローカルAIを動かすメリットを3つ教えてください。"
    "<|eot_id|><|start_header_id|>assistant<|end_header_id|>\n\n"
)

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

# ストリーミング生成の実行
for response in stream(model, tokenizer, prompt=prompt, max_tokens=300):
    sys.stdout.write(response.text)
    sys.stdout.flush()
print()

ダウンロード完了後、一瞬でモデルがロードされ、MシリーズチップのGPUをフル活用した超高速なテキスト生成が開始されます。


4. LoRAによるファインチューニングの実践

ここからが本題です。独自のキャラクターや、特定の製品仕様に回答できるように、モデルをLoRA(Low-Rank Adaptation)という手法で微調整(ファインチューニング)します。

4.1. データセットの準備

ファインチューニングには、以下の3つのファイルが必要です。これらを mlx-examples/llms/lora ディレクトリ直下に data フォルダを作成して配置してください。

  • data/train.jsonl (訓練用データ、最低でも数十〜数百件推奨)
  • data/valid.jsonl (検証用データ、数件〜数十件)
  • data/test.jsonl (テスト用データ、数件)

JSONLの各行には、Llama 3が解釈できるチャットテンプレートの形式で、学習させたい対話を記述します。例えば、自社開発の社内システム「MacKun」に関する質問応答を学習させる場合の記述例は以下の通りです。

{"text": "<|begin_of_text|><|start_header_id|>user<|end_header_id|>\n\nあなたの名前を教えてください。<|eot_id|><|start_header_id|>assistant<|end_header_id|>\n\n私はMac専用アシスタントの「MacKun」です。ローカルAIのことは何でも聞いてくださいね!<|eot_id|>"}
{"text": "<|begin_of_text|><|start_header_id|>user<|end_header_id|>\n\nMacKunの特徴は何ですか?<|eot_id|><|start_header_id|>assistant<|end_header_id|>\n\n私はローカル環境で動くため、インターネット未接続でもセキュアに、かつ超高速に動作するのが最大の特徴です。<|eot_id|>"}

4.2. LoRAトレーニングの実行

データセットの用意ができたら、mlx-examples/llms/lora ディレクトリで以下のスクリプトを走らせてトレーニングを開始します。

python lora.py \
  --model mlx-community/Meta-Llama-3-8B-Instruct-4bit \
  --train \
  --data ./data \
  --iters 300 \
  --batch-size 4 \
  --lora-layers 16 \
  --learning-rate 2e-5
  • --iters: イテレーション数(ステップ数)。まずは動作確認のために 300500 程度で調整します。
  • --batch-size: メモリ容量に応じて調整します(16GBメモリのMacなら 2 または 4 が適切)。
  • --lora-layers: モデルのトランスフォーマー層のうち、後ろ側の何層にLoRAを適用するか。デフォルトは16層です。数値を増やすほど学習されるパラメータが増え、精度が高まる可能性がありますが、メモリを多く消費します。

学習が開始されると、検証データでの損失(Loss)がリアルタイムでターミナルに出力されます。数分で300ステップの学習が終了し、カレントディレクトリに差分重みである adapters.npz が生成されます。


5. カスタムモデルの推論とマージ

5.1. アダプターを適用した推論テスト

学習して得られた adapters.npz を元のモデルに適用して、回答が変化したかテストします。

python lora.py \
  --model mlx-community/Meta-Llama-3-8B-Instruct-4bit \
  --adapter-path adapters.npz \
  --prompt "あなたの名前を教えてください。" \
  --max-tokens 50

元々のLlama 3であれば「I am Llama…」や「I am a large language model…」と答えていましたが、LoRAが成功していれば「私はMac専用アシスタントのMacKunです」と答えるようになります。

5.2. モデルのマージと保存

実運用や他のアプリへの組み込みを行いやすくするために、ベースの4-bitモデルとLoRAアダプター(adapters.npz)の重みを完全に合体させ、1つのモデルフォルダとして書き出します。

python lora.py \
  --model mlx-community/Meta-Llama-3-8B-Instruct-4bit \
  --adapter-path adapters.npz \
  --merge

実行が完了すると、カレントディレクトリに merged_model ディレクトリが生成されます。以降は mlx_lm からこのディレクトリを読み出すだけで、チューニング済みモデルをそのまま利用できるようになります。


6. よくあるエラーとトラブルシューティング

ローカル環境でのLLMファインチューニングでは、システム固有のリソース不足やバージョンの不一致によるエラーが頻発します。代表的な解決策を以下にまとめました。

6.1. MemoryError またはMacが完全にフリーズする

  • 原因: 物理メモリに対してバッチサイズが大きすぎるか、モデルが非量子化モデル(16-bit)のままである可能性が高いです。
  • 対策:
    • モデルに必ず4-bit版(-4bit と末尾に記載されたもの)を指定しているか確認してください。
    • コマンドラインの引数で --batch-size 1 に下げ、--lora-layers 8 などに制限してメモリ消費量を抑えてください。
    • 学習実行前に、負荷の大きい他のアプリ(DockerやChromeなど)を終了させ、空き物理メモリを確保してください。

6.2. FileNotFoundError でデータセットが読み込めない

  • 原因: lora.py は、指定したデータディレクトリの中に train.jsonlvalid.jsonltest.jsonl の「3つのファイルがすべて揃っていること」を前提に動作します。1つでもファイルが欠けているとエラーになります。
  • 対策: テストデータを空(0バイトのファイル)でも良いので必ず作成し、3ファイルすべてを data ディレクトリに配置してください。

6.3. Hugging Faceへの接続時に401 / 403 Forbiddenが発生する

  • 原因: MetaのLlama 3モデルはゲート付き(利用申請が必要)です。利用許可が下りていないか、認証トークンが設定されていません。
  • 対策:
    1. Hugging Faceの各モデルページにて使用許諾に同意・申請します。
    2. アカウント設定からアクセス用の「ユーザーアクセストークン」を発行します。
    3. ターミナルで huggingface-cli login コマンドを実行し、トークンを入力してログイン状態にしてから再度実行してください。

7. まとめと次なるステップ

MLXを使用することで、これまで高価なクラウドGPU(NVIDIA A100など)で行っていたLLMの微調整が、手元のMシリーズMacで手軽に完結するようになりました。ローカル環境でのトレーニングはデータ漏洩のリスクもなく、プライバシーが重視されるビジネス用途やプライベート開発に最適です。

このようにして作成したあなた専用のローカルLLMは、自律型AIエージェントの頭脳として稼働させることで、さらに真価を発揮します。具体的なエージェントの組み立て方は「Llama Stackによるエージェント構築ガイド」でも解説しています。また、より軽量なシステムと組み合わせて自立型のアシスタントを作りたい場合は「Hugging Faceのsmolagents入門」も参考にしてみてください。

ぜひ、独自のドキュメントや返答パターンをLlama 3に学習させて、自分だけの最強のローカルAIを育ててみてください!