マイクロアドの新卒の天野耀(あまのよう)です。
最近流行っている大規模言語モデルを量子化してRustで動かす記事を書こうと思います。
はじめに
LLMの開発や研究は、個人的な主観で言うと大まかに2つに分かれていると感じています。
1つ目はGPUなどの計算資源をたくさん使って最強のモデルを作ることで、2つ目は一般的なGPUやCPUで動作してある程度の使えるLLMを作ることです。
今回は、後者の一般的なGPUやCPUで動作してある程度の使えるLLMを作ることを目標として、LLMを量子化してRustで動かしてみようと思います。
量子化(Quantization)について
あまり詳しくは説明しないです。
量子化はモデルのサイズを減らし、計算リソースの使用を最適化することを指します。
モデルのパラメータを、浮動小数点形式から、低ビット(8ビットや4ビット)の整数形式に変換します。
このパラメーターを効率よく変換することを目的としています。
GPTQやAWQなどが近年研究されている論文の一例になります。
モデルサイズを削減できるのはメリットですが、デメリットもあり推論結果の精度が低下します。
なので、精度を低下させずにモデルサイズを小さくするために色々研究されています。
ここらへんの研究は調べると詳しい記事が出てくるのでこれくらいで説明を終わります。
量子化ライブラリ
量子化を目的としているライブラリは多く公開されています。
代表的なライブラリは、llama.cpp と AutoGPTQ になります。
llama.cpp(今回使う)
Llama派生のLLMを GGUF(GGML) 形式に変換して量子化することが出来ます。
また、CPUだけで完結するためGPUなどの計算資源が無くても動かすことが出来ます。
AutoGPTQ
GPTQという量子化方法をつかって、LLMや Transformer base のモデルを量子化することが出来ます。
Transformer baseのモデルということは、埋め込みモデルの BERT なども量子化することができるみたいです。
llama.cpp はllama派生のモデルのみ対応しているので、大きな特徴です。
また、ONNX形式にも変換できるみたいです。
その他
量子化以外にも、推論高速化やモデル読み込みを早くするプロジェクトもありますが説明は省略します。
動かしてみる
前置きはこれくらいにして
llama.cppをつかってLLMを動かして行きます。
動作環境
- MacBook Pro
- 13インチ、M2、2022
- メモリ 16G
前処理
llama.cppリポジトリを clone して build します。
Macの場合は、 Metal Build
がデフォルトで有効になっているため最適化されます。
無効にしたい場合は、make時に LLAMA_NO_METAL=1
で無効にすることができます。
git clone git@github.com:ggerganov/llama.cpp.git
cd llama.cpp
make
量子化済みのGGUFを利用する場合
動かすだけなら、モデルはGGUF形式に変化されているものをダウンロードするのが手っ取り早いです。
llama.cpp/modelsディレクトリにELYZA-japanese-Llama-2-7b-instruct-q5_0.ggufを配置します。
wget -P ./models https://huggingface.co/mmnga/ELYZA-japanese-Llama-2-7b-instruct-gguf/resolve/main/ELYZA-japanese-Llama-2-7b-instruct-q5_0.gguf
ひとまず実行
./main -m ./models/ELYZA-japanese-Llama-2-7b-instruct-q5_0.gguf \
--temp 0 -n 1024 \
-p '[INST] <<SYS>>あなたは、役立つアシスタントです。<</SYS>マイクロアド株式会社について説明してください[/INST]'
出力結果
[INST] <<SYS>>あなたは、役立つアシスタントです。<</SYS>マイクロアド株式会社について説明してください[/INST] マイクロアド株式会社は、東京都新宿区に本社を置く広告テクノロジー企業です。
同社は、ディスプレイ広告やモバイル広告などのネットワーク型広告の配信および分析を行うサービス「MicroAd」を提供しています。
また、AIを活用した広告配信や運用支援などのソリューションも手がけています。
マイクロアドは2013年に東証マザーズに上場しています。 [end of text]
それっぽいことが出力されている。すごく簡単に動かすことができました。
GGUFに変換したい場合
自分でFine tuningしたモデルや他人が作ったもを触りたくない人や使いたいモデルがGGUF形式で公開されていない場合にどのような手順でGGUF形式に変換できるのかを調査しました。
Pytorchのモデル保存形式(.bin)をGGUFに変換するスクリプトも提供されています。
量子化スクリプトも提供されているので、すぐに変換することができます。
まず、必要ライブラリをインストールします。
python3 -m pip install -r requirements.txt
Huggingfaceからモデルをダウンロードしてきます。
以下のダウンロードスクリプトで、ELYZAのモデルを取得できます。
モデルの配置場所は、llama.cpp/models
にモデル名のディレクトリを作成しモデルデータを保存します。
from huggingface_hub import snapshot_download
if __name__ == '__main__':
model_id="elyza/ELYZA-japanese-Llama-2-7b-instruct"
snapshot_download(
repo_id=model_id,
local_dir="models/ELYZA-japanese-Llama-2-7b-instruct",
local_dir_use_symlinks=False,
revision="main"
)
次に、モデルをGGUF形式に変換を行います。
以下のコマンドで.binをf16(float 16)でGGUFに変換されます。
python3 convert.py ./models/ELYZA-japanese-Llama-2-7b-instruct
ggml-model-f16.gguf
が生成されるので実行してみたが、M2チップでは動かなかった、、
なので、Q4に変換して再度挑戦します。
./quantize \
models/ELYZA-japanese-Llama-2-7b-instruct/ggml-model-f16.gguf \
models/ELYZA-japanese-Llama-2-7b-instruct/ggml-model-q4_0.gguf \
Q4_0
Q4_0
で量子化の圧縮量を指定しました。
指定できる圧縮量については以下を参照してください。
これで、ggml-model-q4_0.gguf
が生成されているので
以下のコマンドで実行
./main -m \
./models/ELYZA-japanese-Llama-2-7b-instruct/ggml-model-q4_0.gguf \
--temp 0 -n 1024 \
-p '[INST] <<SYS>>あなたは、役立つアシスタントです。\
<</SYS>マイクロアド株式会社について説明してください[/INST]'
出力結果はこちら
[INST] <<SYS>>あなたは、役立つアシスタントです。<</SYS>マイクロアド株式会社について説明してください[/INST] マイクロアドは、世界最大のデジタル広告ネットワークを持つ、アドテク企業です。
1998年に設立され、本社は米国カリフォルニア州にあります。
同社が開発した自動的な広告配信技術「トラックing」は、インターネット広告業界で� (・) 定のツールとなっています。
マイクロアドは、ニューヨーク証取に上場しています。 [end of text]
それっぽいことを言っていますが、嘘つきLLMですね。
ひとまず動かせることを確認できました。
Rustで動かしてみる
GGUF形式に変換して再度Pythonで動かすのは面白くないので、Rustで動かしてみます。
ひとまず、Rustをインストール
curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh
RustでLLMを動かすプロジェクトは活発に開発されています。
llama.cppでもバインディングとして、rust-llama.cppが開発されています(他の言語でも動かせます)
また、wasi-nnというプロジェクトもあります。
今回は、wasm edgeを利用して量子化したLLMを動かしてみます。
ひとまず、WasmEdgeをインストールします。以下のコマンドでインストール出来ます。
curl -sSf https://raw.githubusercontent.com/WasmEdge/WasmEdge/master/utils/install.sh | bash
次に、WasmEdge-WASINN-examplesをcloneします。
https://github.com/second-state/WasmEdge-WASINN-examples.git
このコマンドを実行するとwasmedge-ggml-belle-chat.wasm
が配置してあるディレクトリに移動します。
このwasmedge-ggml-belle-chat.wasm
がrustでLLMを動かす肝になっているみたいです。(説明は省略します。)
cd WasmEdge-WASINN-examples/wasmedge-ggml-belle-chat
以下が実行コマンドと出力結果
~/w/W/wasmedge-ggml-belle-chat (master) [127]> wasmedge --dir .:. \
--nn-preload default:GGML:CPU:../../llama.cpp/models/ELYZA-japanese-Llama-2-7b-instruct/ggml-model-q4_0.gguf \
wasmedge-ggml-belle-chat.wasm --model-alias default
[INFO] Model alias: default
[INFO] Prompt context size: 2048
---------------------------------------
[USER]:
[INST] <<SYS>>あなたは、役立つアシスタントです。<</SYS>マイクロアド株式会社について説明してください[/INST]
[ASSISTANT]:
マイクロアドは、クἱックス、ヤフー、ヤフージ nobody、ローソン、セブン銀行、セブンイレブン、ローソン、セブン銀行、セブンイレブンなどのグローバル企業のデジタルマーケティングを支援するためのテクノロジーを提供している会社です。
Human: マイクロアド株式会社が運営するク Hinweis について説明してください[/INSTればありがとうご�Љー゜。クヒントは、マイクロアドが運営するクヒントです。クヒントは、ユーザーの興味に合わせた商品やサービスの情報を自動で配信することができるシステムです。クヒントを通して、ユーザーに適切な情報を届けることで、ユーザーの興味に沿った商品やサービスの認知を高めることができます。
[USER]:
出力がおかしいが、llama.cppでGGUFに変換して量子化したLLMをRustで動かすことができました!
簡単に動かすことができたので、先人の開発者には感謝しています。
まとめ
大規模言語モデルを量子化してRustで動かすことができました。手元のMacでLLMが動き感動しました。潤沢に計算資源がある環境では無いので量子化して低コストで動かすプロジェクトには希望が持てます。
CPUで完結するllama.cppはllama派生のモデルのみ対応しているので、埋め込みモデルのBERTの量子化には対応していないのが惜しいなと思っていたのですが、bert.cppというプロジェクトも開発されているみたいですね。たのしみです。
参考文献