この記事について
この記事は、小江戸らぐで発表した「Intel Macで雑にローカルLLM」「Intel Macで雑にローカルLLM 2 ~~ 雑にGPUも使ってみた ~~」の内容をベースに、Intel Mac でllama.cppを実行するために試したことをまとめたものです。
基本的には、この記事の通りに手順を進めてもらえれば、llama.cppをIntel MacでRadeon GPUで動作させることができると思います。ただし環境の違いやソフトウェアのバージョンによっては動作しない場合もあるかもしれません。そのあたりはご容赦いただければと思います。
キッカケ
生成AIが普及し始めた頃から、個人情報や機密情報の取り扱いに対する不安は常に存在していました。多くのクラウド型AIサービスが情報の保護に取り組んでいますが、「自分の手元で動かせるなら、それに越したことはないのでは?」という発想から、ローカルLLM(Local Large Language Model)に興味を持つようになりました。
しかし、当時見かけた情報では、
- ローカルでLLMを動かすには高性能なGPUが必須
- MacではApple Silicon(M1/M2/M3)が前提
- Intel Macは遅すぎて実用にならない
といった声もあり、「本当にそうなのか?」ということで更に色々と情報を集めてみると、以下のような情報が出てきました。
- 軽量でCPUでも動作可能なモデルが登場している
- 日本語に最適化されたモデルも増えている
- GPUがなくても「そこそこ」使える環境もある
ということで「とにかくやってみよう」という気持ちで、自分のIntel MacでローカルLLMを構築してみることにしました。
用意したMac
-
MacBook Pro (16-inch, 2019)
- CPU: Intel Core i9(8コア16スレッド)
- GPU: AMD Radeon Pro 5500M 8GB
- メモリ: 64GB
- ストレージ: 1TB
ローカルLLMの動かし方
ローカルLLMを構築・実行するには、大きく以下の2つの要素が必要です。
- LLMツール:プロンプトの受け付けや出力の表示など、ユーザーインターフェースや実行制御を担うソフトウェア
- 学習モデル:自然言語処理の中心となる、事前に訓練されたLLMモデル
基本的な使い方の流れは次の通りです。
- コマンドラインベースのツール:学習モデルを指定してツールを起動
試したもの
llama.cpp
llama.cpp はGPU等の専門ハードウェアを必要としないLlamaのライブラリとして開発されコマンドラインツールやシンプルなweb インターフェースを備えるサーバー機能を備えたツールとして開発されており、次のような特徴があります。
- C++製の軽量なLLMランタイム。gguf形式のモデルをサポート。
- CLI中心のツールだが、Webブラウザから使えるサーバーとして動作させることも可能。
- GPU(Vulkan、Metal等)にも対応可能。
- コンパイルオプションで様々な機能が追加可能。
学習モデル
学習モデルですがhuggingfaceというサイトに色々な学習モデルがアップロードされております。ここでは私の方で試したものを紹介しておきます。
ELYZA-Llama2-13b / 7b
- ELYZA社が提供する日本語特化モデル。
- 13bは性能重視、8bは軽量版らしい、それなりの返答は返してくれる
Llama3-ELYZA-Japanese-8b
- Llama3ベースでELYZAがチューニングしたモデル。
- 私が試した中では応答速度が早く、安定して日本語を出力できる。
- GPUオフロードをすれば、かなり早く返答を返してくれる。
Phi-3-mini-k128
- Microsoftが提供する軽量モデル。
- 高速に動作するが、プロンプトの設定を間違えると、英語や記号での回答が出力されたり出力が延々と続くこともある。
DeepSeek
- 中国発の多言語モデル。日本語にも対応。
- 「thinking…」などの表示を出して思考過程を演出するユニークな特徴あり。
- 大体は日本語で返答が返ってくるのだが、偶に中国語が混じることも多く、応答の品質はやや不安定。
- Intel Macの環境ではGPUオフロードには相性が悪いのかかなり速度が遅くなる
やってみた
以下、llama.cppを使った際の手順です。
llama.cpp
llama.cppはgithub上にリポジトリがありリポジトリをクローンしてビルドを行う必要があります。
また cmake
を使ってビルドするので、パッケージ管理ソフトでcmakeをインストールしておく必要があります。
リポジトリのクローンからビルドまではこのドキュメント執筆時点では以下のようになります。
リポジトリクローン
git clone https://github.com/ggerganov/llama.cpp.git
cd llama.cpp
ビルド用ディレクトリ作成
$ cmake -B build
実行ファイル作成
$ cmake --build build --config Release -j 8
学習モデルダウンロード例※ELYZA-japanese-Llama-2-13b-instruct-q4_K_M.ggufの場合
$ wget https://huggingface.co/mmnga/ELYZA-japanese-Llama-2-13b-instruct-gguf/resolve/main/ELYZA-japanese-Llama-2-13b-instruct-q4_K_M.gguf
コマンド例(CLI):
$ ./build/bin/llama-cli -ngl 0 -m 'Llama-3-ELYZA-JP-8B-Q4_K_M.gguf' -n 2048 -p 'あなたは誠実で優秀な日本人のアシスタントです。仕事の熱意を取り戻すためのアイデアを5つ挙げてください。 ' -no-cnv
サーバーモードで起動してWebブラウザからアクセスすることもできます。その場合は下記のように起動して Webブラウザでlocalhost:10000にアクセスしてみてください
$ ./build/bin/llama-server -ngl 0 -m 'mmnga/Llama-3-ELYZA-JP-8B-Q4_K_M.gguf' -n 2048 --port 10000
当初はCPUのみで実行していた方が早かった(-ngl 0)という状態で、試したMacBook Proに搭載されているRadeon Proを使用すると遅くなるという現象が発生しておりました。
GPU使用 (-ngl 32)
llama_print_timings: eval time = 331950.94 ms / 233 runs ( 1424.68 ms per token, 0.70 tokens per second)
llama_print_timings: total time = 383524.05 ms / 273 tokens
CPUのみ (-ngl 0)
llama_print_timings: eval time = 71923.93 ms / 255 runs ( 282.05 ms per token, 3.55 tokens per second)
llama_print_timings: total time = 81259.32 ms / 295 tokens
「Intel MacBook ProではGPUは使えないのかな・・・」と考えていたのですがとある議論でGPUオフロードが可能になる高速となりました。
llama.cppをRadeon GPUで動かしてみる
Radeon GPUへのオフロード「ではどうするといいのだろう・・・」ということで色々と検索をかけていた際に下記のような議論を見つけました。
こちらを元に設定してGPUのオフロードを有効にしたところ大幅にチャットのスピードが向上しました。
しくみとして
- Vulkanというクロスプラットフォーム対応の低レベル・高性能なグラフィックス&計算APIを使う
- macOSにはVulkan のドライバはないが、MoltenVKというVulkan API → Metal API に変換してくれる互換レイヤを使用してRadeon GPUにオフロードする
というものです。以下私の方で試した手順を書いていきます。
必要なパッケージをインストール ※自宅の環境ではHomebrewを使っており他のパッケージ管理ソフトを使っている場合はそちらに読み替えてください
$ brew install libomp ninja vulkan-headers glslang molten-vk shaderc vulkan-loader
MoltenVKをクローン・ビルド
$ git clone https://github.com/KhronosGroup/MoltenVK.git
$ cd MoltenVK
$ git fetch origin pull/2434/head:p2434
$ git switch p2434 ※これをしておかないとllama.cppのビルドディレクトリ作成でビルドが終わらなくなる
$ ./fetchDependencies -macos
$ make macos
llama.cppのビルドディレクトリ作成でオプションをつけて作成
$ cmake -B build -DLLAMA_CURL=1 -DGGML_METAL=OFF -DGGML_VULKAN=1 \
-DVulkan_INCLUDE_DIR=/usr/local/Cellar/molten-vk/1.3.0/include \
-DVulkan_LIBRARY=/usr/local/Cellar/molten-vk/1.3.0/lib/libMoltenVK.dylib \
-DOpenMP_ROOT=$(brew --prefix)/opt/libomp \
-DVulkan_GLSLC_EXECUTABLE=$(brew --prefix)/opt/shaderc/bin/glslc \
-DVulkan_GLSLANG_VALIDATOR_EXECUTABLE=$(brew --prefix)/opt/glslang/bin/glslangValidator \
-DOpenMP_C_FLAGS=-fopenmp=lomp \
-DOpenMP_CXX_FLAGS=-fopenmp=lomp \
-DOpenMP_C_LIB_NAMES="libomp" \
-DOpenMP_CXX_LIB_NAMES="libomp" \
-DOpenMP_libomp_LIBRARY="$(brew --prefix)/opt/libomp/lib/libomp.dylib" \
-DOpenMP_CXX_FLAGS="-Xpreprocessor -fopenmp $(brew --prefix)/opt/libomp/lib/libomp.dylib -I$(brew --prefix)/opt/libomp/include" \
-DOpenMP_CXX_LIB_NAMES="libomp" \
-DOpenMP_C_FLAGS="-Xpreprocessor -fopenmp $(brew --prefix)/opt/libomp/lib/libomp.dylib -I$(brew --prefix)/opt/libomp/include"
実行ファイル作成
$ cmake --build build --config Release -j 8
双方の実行速度を比較したところ
GPU 使用 (-ngl 999)
llama_perf_context_print: eval time = 26647.52 ms / 578 runs ( 46.10 ms per token,21.69 tokens per second)
llama_perf_context_print: total time = 27707.62 ms / 626 tokens
CPUのみ (-ngl 0)
llama_perf_context_print: eval time = 133206.50 ms / 527 runs ( 252.76 ms per token,3.96 tokens per second)
llama_perf_context_print: total time = 140521.50 ms / 572 tokens
結果として、CPUのみと比較して約5倍の生成速度を記録しました。
補足:GPUで遅くなる理由と高速化の考察」
当初GPUオフロードを行うと何故遅くなるのか、ChatGPTに聞いてみたところこのような返答が返ってきました。
macOSにおけるAMD GPUのGPGPUサポートは限定的
macOSでは、NVIDIAではなくAMD製GPUが使われますが
そのGPGPU(汎用計算)用途での性能やサポートが貧弱なケースが多いです。
llama.cpp は GPU オフロードに Metal backend(Apple GPU用)または OpenCL backend を使います。
AMD Radeon Pro 5500M は OpenCL 対応ですが、macOS上のOpenCLサポートは古く
非推奨扱いになっており、Apple自身もサポートを縮小しています。
このため:
OpenCLを通じたGPUオフロードは、RadeonでもCPUより遅くなることがある。
OpenCLドライバ・ランタイムの最適化不足
macOSのOpenCL実装は近年あまりメンテナンスされておらず、次のような問題が起きます:
問題点 | 説明 |
---|---|
非効率なスケジューリング | GPUに無駄な同期や待機が発生しやすい |
メモリコピーのオーバーヘッド | ホスト(CPU)→GPU間の転送が遅い |
非最適なカーネル実行 | llama.cpp のような小さなバッチ処理に向かない |
結果として、GPUで処理してるのにCPUより遅い現象が起きます。
モデルサイズや利用方法のミスマッチ
Radeon 5500Mは性能自体はそこそこ(4TFLOPS級)ですが、以下のような場合はCPUの方が有利になります:
小さなモデル(例:7B未満)でトークンを逐次生成(chat UIなど)
バッチサイズが1で逐次呼び出す用途(LLaMA系はこれが多い)
Metal backendが使えない(Apple Silicon限定)
つまり、GPUに仕事を投げるコストの方が、実行時間より長くなるという逆転現象が発生します。
ということでChatGPTに聞いたところ「GPUの性能の問題ではなくライブラリ等が最適化されていない可能性が高い」という回答であったため、色々と探してたどり着いたのが https://github.com/ollama/ollama/issues/1016 の議論ということになります。
その後、GPUオフロードを行うことによりCPUと比較して5倍の速度になったことについて
「これはGPUをどの程度使えているのか?」をChatGPTに聞いてみたところ下記のような回答が返ってきました。
素晴らしい成果です!Intel Mac + Radeon Pro 5500M(vRAM 8GB)で llama.cpp
を Vulkan backend(MoltenVK 経由)で5倍高速化できたのは、非常に有効なGPUオフロード
ができている証拠です。
では、「これは Radeon 5500M の性能をフルに引き出しているのか?」という点を、技術的観点
から分析してみましょう。
今の結果は「かなり引き出せている」状態
Radeon Pro 5500M の基本性能
アーキテクチャ:Navi 14(RDNA 1)
GPUクロック:約1.3 GHz
SP数:約1408
FP32理論性能:約 4.6 TFLOPS
VRAM:GDDR6 8GB
メモリ帯域:約192 GB/s
この性能水準で、大規模行列演算処理(Transformersの推論)をCPU比5倍でこなしているのは
Vulkanを通してしっかり計算を投げられている証拠です。
ということで、現状Radeon GPUの性能をかなり引き出せているようです。
まとめ
これまでの検証を通じて、次のようなことがわかりました。
- CPUのみでも、スレッド数やクロック次第では実用レベルに達する
- Intel Macでも適切なGPU設定(Vulkan)を行えば性能を引き出せる
- 日本語モデルも徐々に充実しており、十分に「使える」ものがある
Intel MacでローカルLLMは無理と思われがちですが、中古のIntel Macは中古ショップで今回の構成のものは10〜20万円程度で手に入るようです。
今後は、ローカルLLMにRAGやMCP、Agent-to-Agent(A2A)といった機能を組み合わせて試してみたいと考えています・・・が、やっぱりApple SiliconのMacBook Proが欲しいなあ、というのが本音です(汗
このドキュメントが、Intel MacユーザーやローカルLLMに興味のある方の参考になれば幸いです。最後までお読みいただき、ありがとうございました。
参考リンク
ツール
llama.cpp: https://github.com/ggml-org/llama.cpp
MoltenVK: https://github.com/KhronosGroup/MoltenVK
学習モデル ※mmgaさん掲載のモデルを使用させていただきました。
mmgaさんありがとうございました。
ELYZA-Llama2-13b: https://huggingface.co/mmnga/ELYZA-japanese-Llama-2-13b-instruct-gguf
ELYZA-Llama2-7b: https://huggingface.co/mmnga/ELYZA-japanese-Llama-2-7b-fast-instruct-gguf
Llama3-ELYZA-Japanese-8b: https://huggingface.co/mmnga/Llama-3-ELYZA-JP-8B-gguf
Phi-3-mini-k128: https://huggingface.co/mmnga/Phi-3-mini-128k-instruct-gguf
DeepSeek: https://huggingface.co/mmnga/DeepSeek-R1-Distill-Qwen-14B-gguf
Intel MacでのRadeon GPUを使用する議論: https://github.com/ollama/ollama/issues/1016