LLMをローカル環境で動かすことは貴族の遊びなのか？

## はじめに
はじめまして。株式会社PictoriaのSaldraです。普段はAI技術で美少女を錬成しているオタクです。この記事は「LLM Advent Calendar 2023」の24日目の記事になります。皆さんがレベルの高い記事を沢山書いているので震えています。

https://qiita.com/advent-calendar/2023/llm

## 想定読者
* なんとなくChatGPTは触ったことあるかなくらいの人
* 既にLLMを遊んでいて楽しいな～と感じている人

## 本記事のまとめ
* ローカルLLMは楽しいが、参入のハードルが高い「貴族の遊び」と思われている
* 実際はそんなことなく、参入自体は皆が思っているより容易
* ただし情報は少ない。参入する人、広めたい人ともに気合がまだまだ必要

## LLMは「貴族の遊び」なのか？
ChatGPTが登場してから一年が経とうとしています。世間ではかなり騒がれていますし、OpenAI APIを使って小さなアプリを使った人は多いかと思います。一方で入力内容の検閲やAPIの仕様変更などの問題点も存在し、ローカル環境でLLMを運用しようとする流れが一定あります。これが「ローカルLLM」と呼ばれているものだったりします。

さて、そんなローカルLLMは、二つの大きなハードルがあると思われがちです。それはハードウェア要件と知識です。LLMをローカル環境で動かすためのハードウェア要件は高く、RTX4090や機械学習用GPUでないと性能が高いものは動かないとされています。また、OpenAI APIのように気軽には遊べず、高度な機械学習の知識を使う必要があるとされています。なので、忙しいエンジニアの皆さんは残念ながら遊べないので、諦めてLLMのAPIを使っていてください。

…本当に？

## LLMは「貴族の遊び」ではない
先程私はLLMを動かすにあたり、二つのハードルを紹介しました。これを改めて少しだけ詳しく見てみましょう。

### ハードウェア要件
良く言われるのが「貴族のPCじゃないと遊べない」という指摘です。では、ローカル環境でLLMを動かすといっても色々あるので、取り敢えずは「知識の精度は問わないので、自分と話してくれるモデルを動かす」というのをゴールに、ハードウェア要件を深ぼってみましょう。

一旦、各パラメータごとに、どんなハードウェア要件になるかを考えてみます。
* [rinna/nekomata-14b-instruction](https://huggingface.co/rinna/nekomata-14b-instruction)
* [cyberagent/calm2-7b-chat](https://huggingface.co/cyberagent/calm2-7b-chat)
* [rinna/bilingual-gpt-neox-4b-instruction-ppo](https://huggingface.co/rinna/bilingual-gpt-neox-4b-instruction-ppo)
* [stabilityai/japanese-stablelm-3b-4e1t-instruct](https://huggingface.co/stabilityai/japanese-stablelm-3b-4e1t-instruct)
* [line-corporation/japanese-large-lm-1.7b-instruction-sft](https://huggingface.co/line-corporation/japanese-large-lm-1.7b-instruction-sft)

商用利用可なモデルで、パラメータサイズごとに一つづつ選んでみました。NekomataのみApache2.0ライセンスでないので気を付けてください。

次に、使用するVRAM、GPU要件を考えてみましょう。パラメータサイズに4byteをかけて、GBに変換してみます。概算ですが大体パラメータサイズ×バイトサイズ(32bitなら4,16bitなら2)必要VRAMがわかるとされています。主に使われているのは4bit,8bit,16bitです。

7Bのパラメータで16bit読み込みをした場合、7b×2なので140億バイト、つまり14GBになります。ゲーミングPCによくついているGPU、RTX4070がVRAM12GBなので、一般的なPCでは読み込めないと言えるでしょう。一方4bitまで下げれば7b*1なので7GBと、普通のゲーミングPCであれば推論ができるはずです。以下にそれぞれのモデルの概算を纏めてみます。

|モデル名  |サイズ|16bit  |8bit  |4bit  |
|---|---|---|---|---|
|rinna/nekomata-14b-instruction|14b  |28GB|14GB|7GB|
|cyberagent/calm2-7b-chat  |7b  |14GB  |7GB|3.5GB|
|rinna/bilingual-gpt-neox-4b-instruction-ppo  |3.8b  |7.6GB  |3.8GB|1.9GB|
|stabilityai/japanese-stablelm-3b-4e1t-instruct|2.8b|5.6GB|2.8GB|1.4GB|
|line-corporation/japanese-large-lm-1.7b-instruction-sft|1.7b|3.4GB|1.7GB|850MB|

勿論これは概算でしかないため、読み込み方等で上下する可能性がありますが、少なくとも推論においては貴族のGPUが必須なわけではないことがわかります。少なくともload_in_8bitオプションをつければ7b程度の推論は可能です。ただしこれでもGPUが必要なので、「一般的な普及」を目指すのであればCPU推論を目指すべきでしょう。

#### CPU推論への道
最近では「Llama.cpp」というLLMのランタイムが出現しました。これはLLMをMacbookのようなCPUしかない環境でも動かそうとする取り組みです。Llama.cppの名がついていますが、stablelm等、llamaベースでないものも動きます。

https://github.com/ggerganov/llama.cpp

これはかなり画期的で、精度を引き換えにするもののCPUで動かすことができるのは大きなアドバンテージといえます。勿論推論スピードも無視できない差がありますが、そこは小さめのパラメータをチューニングする等でカバーできる範囲ではないでしょうか。

試しに「japanese-stablelm-3b-4e1t-instruct」のggufを読み込んでみましょう。

`pip install llama-cpp-python`をしてから下記スクリプトを組み遊んでみます。
```python
from llama_cpp import Llama
class LlamaAdapter():
    def __init__(self):
        self.llm = Llama(model_path='./japanese-stablelm-3b-4e1t-instruct-q4_K_M.gguf')

    def infer(self):
        output = self.llm(
            "### 指示: 東京の名所を一つ紹介せよ  \n ### 応答:",
            max_tokens=64,
        )["choices"][0]["text"]
        return output
    
if __name__ == '__main__':
    llama = LlamaAdapter()
    print(llama.infer())
```
結果の文章は以下です。
```
「清澄庭園」は、江戸時代に大名屋敷があった場所である。このエリアには、多くの公共施設や寺院などがあります。また、
```
推論スピードを見てみるとCPUでの推論にもかかわらず、モデルの読み込みから出力まで合わせて6秒以内に完了しています。ちなみにCPUは「AMD Ryzen5 3600 6-Core」を利用しています。少し古めのi5くらいの性能です。
```
llama_print_timings:        load time =    1139.06 ms
llama_print_timings:      sample time =      14.81 ms /    64 runs   (    0.23 ms per token,  4321.70 tokens per second)
llama_print_timings: prompt eval time =    1139.00 ms /    32 tokens (   35.59 ms per token,    28.09 tokens per second)
llama_print_timings:        eval time =    3786.80 ms /    63 runs   (   60.11 ms per token,    16.64 tokens per second)
llama_print_timings:       total time =    5177.97 ms
```

つまり、3bの4bit量子化でllama.cpp環境を配布すれば、ラップトップで推論させられるはずです。精度はファインチューニングで担保すれば良いと考えると、決して貴族のPCが必須なわけではないことがわかります。勿論貴族のPCの方がやれることは多いです。

### 知識的なハードル
次に知識的なハードルについて考えてみます。
確かに事前学習を一からやるには中々難しく（それでも[試しに作れる記事](https://zenn.dev/selllous/articles/transformers_pretrain_to_ft)が今回のアドカレで公開されたので、以前よりも手が出しやすくなっています）、無知識から始めるにはハードルが高いと言えます。一方推論に関しては、使用するだけであればモデルの選択と数行の関数実行で実践できるので、かなりハードルは低いです。

また、ファインチューニングもやり方がインターネットで共有されていることを考えると、以前よりも格段にやりやすくなってきていると言えます。少なくとも「コンピュータサイエンスを専門でやっていなければ全く手が出せない」という状況ではないでしょう。

https://qiita.com/maskot1977/items/c9e96a5ed88017bcb96b

一方で、まだまだ「ボタン一発でトレーニングが開始できる」環境にはありません。text-generation-webuiなどのWebUIがトレーニング環境を提供しているものの、まだまだ敷居は高いと言えます。

ここまで、ハードウェア要件、知識的なハードルの二面で確認してきました。一旦まとめてみましょう。

## まとめと私見
ハードウェア要件はまだまだ必要とするGPUのVRAMは多いですが、少し遊ぶくらいであればCPUでも動くことがわかりました。MacbookProでも動くことが確認されていますし、今後技術の進歩と共にハードウェア要件は下がると予想しています。現在はAPIサービスを用いて計算コストをサーバー側に担保してもらっていることが多いですが、いずれは各端末で推論するのではないかと思います。

知識的なハードルもtransformersやllama.cppのように、専門な知識がなくても扱えるLLMランタイムが増えています。また、アプリに組み込んでしまうことで、実装を行わずにエンドユーザーが無意識のうちにLLMを利用する可能性も高いでしょう。以前試験的に、llama-cpp-pythonをpygameに組み込むことで、ggufモデルを裏側で推論させた経験があります。このように、今後はゲームに取り入れて動的にセリフを作成する例も増えるかと思います。

この記事を通して私が言いたいことは「別に思っているよりもローカル環境でLLMを推論させることは貴族の遊びではなく、誰にでも門戸が開かれている」ということです。もしこの記事をきっかけに動かしたい方がいらっしゃれば、是非遊んでみてください。

https://zenn.dev/saldra/articles/201dd9e7d8c743