Ubuntu日和

【第77回】llama.cppをビルドして、いち早く話題の日本語LLMを使おう!

llama.cppの記事なのになぜLM Studioが!?

 第76回llama.cppについて少し紹介した。今回はより詳しく掘り下げる。

 llama.cppは第73回で紹介したOllamaと同じく、生成AI(LLM)を動作させるためのインターフェイスである。Ollamaは配布されているバイナリをそのまま使用することが前提であり、llama.cppもバイナリは配布されているものの、より踏み込んで利用しようと思えばソースコードからのビルドが必要となる。

 さらにLLMで使用するモデルは、国の内外を問わずさまざまな企業や団体からリリースされているが、日本企業がリリースしたものは多くの場合llama.cppやOllamaで使用できる形式(GGUF)ではリリースされない。このllama.cppを使用すればGGUFに変換でき、そのまま動作する。

 当然ながらWindowsよりもUbuntuのほうが開発環境を揃えるのが容易なので、Ubuntuでの使用方法を紹介する利があるというわけだ。

使用するハードウェア

 今回使用するハードウェアは次の通りだ。

種類メーカー型番備考
CPUIntelCore i3-14100-
メモリCrucialW5U4800CM-8GS16GB
マザーボードASUSROG STRIX B760-I GAMING WIFI-
SSDキオクシアEXCERIA PRO SSD-CK1.0N4P/N1TB
電源ユニット玄人志向KRPW-SXP600W/90+-

 マザーボードはAmazonアウトレットで買ったものだが、どうやっても16GB以上のメモリを2枚刺しすると起動しなかった。であれば8GB×2の16GBにし、CPUも4コア8スレッドのCore i3-14100にした。これでバランスが取れているといえるだろう。いや、そういうことにしてほしい。

 dGPUは、MSI GeForce RTX 3060 AERO ITX 12GB OCとする。事前に「追加のドライバー」でプロプライエタリなドライバをインストールしておこう。

「検証済み」のものを選べばいいわけではないのが少し難しい

 Radeonでもやりたかったが、紙幅の都合で断念した。第76回にもあるように現在はVulkanのほうが速いため、ROCmのほうが速くなったらまた試したい。

 OSはもちろんUbuntu 24.04 LTSだ。

llama.cppをビルドする

 前述の通りllama.cppはバイナリもリリースしているが、Ubuntu用(UbuntuでビルドされたLinux用という意味だとは思われる)はCPU用(GPU使用なし)とVulkanを使用するもののみで、NVIDIA(CUDA)やAMD(ROCm/HIP)を使用するバイナリは配布されていない。

 配布されていなければ自前でビルドすればいい、というわけでその方法を紹介する。

ビルド準備

 ではまず、llama.cppのビルドを準備していこう。端末から次のコマンドを実行しよう。

【8月14日修正】記事内のコマンドを一部修正しました

$ sudo apt install git git-lfs cmake g++ libcurlpp-dev
$ mkdir ~/git
$ cd ~/git
$ git clone  https://github.com/ggml-org/llama.cpp.git
$ cd llama.cpp

 この一連のコマンドでは、最初にビルドに必要な最低限のパッケージをインストールし、llama.cppのソースコードを取得している。フォルダーは~/git/以下としている。

CPU版のビルド

 最初に基本となるCPU版のビルドを実行する。最も簡単なので、ここでビルドに成功しておくと以後うまく行かない場合の切り分けが容易になる。

 やはり端末から次のコマンドを実行する。

$ mkdir build-cpu
$ cmake -B build-cpu
$ cmake --build build-cpu --config Release -j 8

 「-j」の後ろはスレッド数で、今回は4コア8スレッドのCPUを使用しているので8としている。実際のビルド環境に合わせて増減してほしい。

 しばらく待っているとビルドが完了するはずだ。「100%」と表示されるので分かりやすい。

ビルドが完了したところ

Vulkan版のビルド

 続けてVulkan版のビルドを行なう。llama.cppで採用しているビルドシステムであるcmakeは、ビルドしたファイルを置くフォルダーを任意に設定できるので、フォルダーさえ分けてしまえばさまざまなビルドを併存できる。

 端末から次のコマンドを実行する。これらのコマンドはまずVulkan版のビルドに必要なパッケージをインストールし、cmakeでビルドを行なっている。

$ sudo apt install libvulkan-dev glslc
$ mkdir build-vulkan
$ cmake -B build-vulkan -DGGML_VULKAN=ON
$ cmake --build build-vulkan --config Release -j 8

CUDA版のビルド

 CUDA版も似たような感じでビルドできる。端末から次のコマンドを実行する。

$ sudo apt install nvidia-cuda-toolkit
$ mkdir build-cuda
$ cmake -B build-cuda -DGGML_CUDA=ON
$ cmake --build build-cuda --config Release -j 8

GGUF形式への変換

 llama.cppのビルドが終わったら、続いては各所で公開されているLLMの“.safetensors”ファイル形式から、GGUF形式への変換に移ろう。最初にビルドしたのは、実はこのGGUF形式への変換にビルドしたバイナリが必要だからだ。

 順序としては、リポジトリからモデルをダウンロードし、llama.cppでGGUF形式に変換する。さらに、そのままだとサイズが大きすぎるので、量子化と呼ばれる作業をする。量子化の詳細には触れないが、モデルを可能な限り性能を保ったまま縮小する作業だと思えば概ね間違いはない。

 GGUF形式への変換は、Pythonのスクリプトを使用する。Pythonのライブラリを多数インストールする作業があるので、まずはこれから行なおう。

$ sudo apt install python3.12-venv
$ python3 -m venv ~/git/.gguf
$ . ~/git/.gguf/bin/activate
$ pip3 install -r requirements.txt

 この一連のコマンドは、Pythonのvenvという仕組みを使い、仮想環境を作成している。厳密は仮想環境というよりも分離環境ではあるのだが。

 上記のコマンドの3行目を実行すると端末の表示が変わるので、分かりやすいだろう。

venv実行時の端末の表示

 ちなみにこの仮想環境から抜ける場合は、次のコマンドを実行する。

$ deactivate

 再びこの仮想環境を使用したい場合は、3行目を実行すればいいということになる。

 今回変換するモデルは、Gemma-2-Llama Swallow 9Bとする。VRAMが8GBのdGPUでも動作するモデルで、日本に関する質問をして、それなりの結果が返ってくるという点に重視してチョイスした。

 某社のモデルも日本関連の追加学習を行なったと謳われていたので、実際に試してみたところ、何が追加されているのかさっぱり分からなかったということがあった。Gemma-2-Llama Swallow 9Bは、パラメータ数が9Bなので限界はあるものの、わりと正解に近い回答が得られたのは特筆に値する。

 では量子化までいっぺんに行なってしまおう。

$ cd ~/git
$ git clone https://huggingface.co/tokyotech-llm/Gemma-2-Llama-Swallow-9b-pt-v0.1
$ llama.cpp/convert_hf_to_gguf.py Gemma-2-Llama-Swallow-9b-pt-v0.1/
$ llama.cpp/build-cpu/bin/llama-quantize Gemma-2-Llama-Swallow-9b-pt-v0.1/Gemma-2-Llama-Swallow-9B-pt-v0.1-F16.gguf Gemma
-2-Llama-Swallow-9b-pt-v0.1/Gemma-2-Llama-Swallow-9B-pt-v0.1-F16-q4_k_m.gguf q4_K_M

 これで~/git/Gemma
-2-Llama-Swallow-9b-pt-v0.1/Gemma-2-Llama-Swallow-9B-pt-v0.1-F16-q4_k_m.ggufができたはずだ。q4_K_Mで量子化するとモデルのサイズは5.4GB程度まで縮小するので、VRAMが8GBのdGPUでも動作する。ちなみにVRAMが6GBのdGPU(GeForce RTX 3050)では動作しなかった。

ベンチマーク

 llama.cppには簡易ベンチマーク機能があるので、これを使用してVulkanとCUDAの速度比較をしたい。そしてベンチマークにはモデルも必要なので、Gemma-2-Llama-Swallow-9B-pt-v0.1-F16-q4_k_m.ggufが早速役に立つ。

 次のコマンドを実行してベンチマークを実行する。

$ cd llama.cpp
$ time ./build-vulkan/bin/llama-bench -m ../Gemma-2-Llama-Swallow-9b-pt-v0.1/Gemma-2-Llama-Swallow-9B-pt-v0.1-F16-q4_k_m.gguf --n-gpu-layers 99
$ time ./build-cuda/bin/llama-bench -m ../Gemma-2-Llama-Swallow-9b-pt-v0.1/Gemma-2-Llama-Swallow-9B-pt-v0.1-F16-q4_k_m.gguf --n-gpu-layers 99
Vulkanでのベンチマーク結果
CUDAでのベンチマーク結果

 筆者の手元で試してみたところでは、Vulkanだと約23秒、CUDAだと約17秒であった。このぐらいの速度差があるのであれば、CUDAを使用したいところだ。

LM Studioのほうが楽

 実は当初、この記事でllama.cppの使い方について解説するつもりだった。なかなかに高性能で、コマンドラインから問い合わせを投げる方法もあれば、サーバーとして起動してWebブラウザ経由で問い合わせを投げる方法もあり、便利だからである。

 ところが先日、llama.cppをバックエンドに採用しているLM Studioのライセンスが変更され、これまで無償利用は個人用途に限られていたのが、商用用途でも無償となった。

 つまり、用途が拡大したことにより、頑張ってllama.cppを使用しなくてもよくなるケースが爆増した。LM StudioのUIはよくできているので、llama.cppを直接使うのとはユーザビリティが比較にならない。

 変換したGGUFをLM Studioで使用したい場合は~/.lmstudio/models/lmstudio-community/以下にgemma-2-llama-swallow-9b-ptなどのフォルダーを作成し、そこにGemma-2-Llama-Swallow-9B-pt-v0.1-F16-q4_k_m.ggufを置けばいい。

 CUDAも2種類から選べる。「CUDA 12」は別途インストールが必要だが、少し試してみた限りでは「CUDA」との速度差はほとんどなかった。

llama.cppはランタイムとして提供されている

 ダウンロードや起動に関しては第62回を参照してほしい。少し前の記事だが、今でも充分に参考になる。いつの間にかUIのレベルが選択できるようになっているが、ここでは「Power User」にしてほしい。