ローカル環境で大規模言語モデルをAPIサーバを動作させる text-generation-webui編

# はじめに

自分専用の大規模言語モデルを動作させるAPIサーバを用意する手順をざっと紹介します。といっても、手順は以前公開した[Google Colabでtext generation webuiを起動し、Llama 2と会話してみた](https://qiita.com/vfuji/items/f4d1eab889a34ff63626)をローカルマシンで実行する内容であり、目新しいものではありません。

# 前提条件

- NVIDIA GPU を搭載した マシン (7B程度のモデルを動作させるには VRAM 8GB 程度のマシンが必要です。)
- ゲーミング PC の Windows 上に WSL / ubuntu がセットアップされていること
- Windows 環境にて適切なドライバーが適用されていること (*1)
- Windows 管理者権限を持つアカウントを利用可能なこと
- セットアップ作業時にインターネットへアクセス可能なこと (*2)
- NVIDIA Container Toolkit がインストールされていること (手順は[別記事、WindowsゲーミングPCでGPUを使ったコンテナを実行する方法](https://qiita.com/vfuji/items/82d54c421f49794294e5)をご参照ください)

*1 NVIDIA 公式ドライバに CUDA ドライバは含まれているはずです。私が試した環境は工場出荷時の状態であり、NVIDIA 公式ドライバがインストール済みとなっていました。 

*2 GitHub や Hugging Face へのアクセスが必要となります。

# 手順

手順は次のようになります。これらの手順は、WSL / ubuntu 上で実行するための手順となります。Linuxでもほぼ同じ形で実行できると思いますが試しておりません。

- [github/oobabooga/text-generation-webui](https://github.com/oobabooga/text-generation-webui) のリポジトリをクローンもしくはダウンロードする
- クローンもしくはダウンロードしたファイルを展開したディレクトリに移動し、`start_linux.sh`を実行する
- 適切なモデルをWeb UIよりダウンロードする
- APIオプションをつけて実行する
- アクセスを確認する

## セットアップ

git clone します。もしくは[ダウンロード](https://github.com/oobabooga/text-generation-webui/archive/refs/heads/main.zip)して下さい。

```sh
git clone https://github.com/oobabooga/text-generation-webui.git
```

git clone もしくは、ダウンロードしたディレクトリに移動し、セットアップを実行します。

```sh
cd text-generation-webui
./start_linux.sh
```

自動的にセットアップが行われますが、次のように、途中で2つの質問が出てきます。1つ目はNVIDIAなのでAを入力しエンターを押下します。次に GPU の種類が古いため、古いCUDAを使うか、と問われます。Kepler以前のGPUを使っている場合は、Yを入力しエンターを押下します。RTXやGTXの場合はNを選択、また不明確な場合についてもNを選択するようガイドされています。

```sh
What is your GPU?

A) NVIDIA
B) AMD (Linux/MacOS only. Requires ROCm SDK 5.6 on Linux)
C) Apple M Series
D) Intel Arc (IPEX)
N) None (I want to run models in CPU mode)

Input> A

Do you want to use CUDA 11.8 instead of 12.1?
Only choose this option if your GPU is very old (Kepler or older).

For RTX and GTX series GPUs, say "N".
If unsure, say "N".

Input (Y/N)> N
CUDA: 12.1
```

しばらく待つと次のような出力があり、起動が完了します。この状態で URL にアクセスすると Web UI にアクセスできます。アクセスできない場合は、ネットワークの設定などをご確認ください。WSL2 の場合は[ネットワークの設定](https://qiita.com/vfuji/items/2f739fd0c8ba9433e0e3#%E3%83%8D%E3%83%83%E3%83%88%E3%83%AF%E3%83%BC%E3%82%AF%E7%B5%8C%E7%94%B1%E3%81%AE%E3%82%A2%E3%82%AF%E3%82%BB%E3%82%B9%E8%A8%AD%E5%AE%9A%E3%81%A8%E7%A2%BA%E8%AA%8D)が必要になります。

```sh
Running on local URL:  http://127.0.0.1:7860
```

## モデルをダウンロード

ダウンロードしたいモデルが明確にわかっている場合は、次のようにしてモデルをダウンロードすることができます。requests と tqdm が必要になります。別途インストールしてください。

```sh
python download-model.py organization/model
```

Web UI画面経由で、LLMをダウンロードする方法はこちらになります。モデル nekomata-7b.Q4_K_M.gguf を例として紹介します。

1. 画面上部のModel タブをクリック
2. Download model or LoRAに「rinna/nekomata-7b-gguf」を入力する
3. Getfile list を押下し、 nekomata-7b.Q4_K_M.gguf というファイルが表示されることを確認する
4. Download を押下し、 "Model successfully saved to models/"が表示されることを確認する 

モデルのダウンロードが完了したら、Ctrl + Cを入力し、Web UIを停止します。

## API を有効にして起動

Web UI は使わず API のみで利用するため、次のようにモデルと loader を指定した上で起動します。

次のコマンドは、[rinna/nekomata-7b.Q4_K_M.gguf](https://huggingface.co/rinna/nekomata-7b-gguf)モデルを起動する例です。

```sh
./start_linux.sh --model nekomata-7b.Q4_K_M.gguf --chat --share --auto-devices --loader llama.cpp --api --listen --n-gpu-layers 128 --nowebui
```

`--nowebui` オプションは webui が起動しなくなります。各種設定を webui で確認したい場合は、このオプションをつけずに起動して下さい。

次のような形で実行中に URL が出力されます。`INFO:OpenAI-compatible API URL:`の次の行に `http://0.0.0.0:5000` という形で表示されます。

```
03:57:52-227180 INFO     Starting Text generation web UI
03:57:52-251848 INFO     Loading "llama-2-7b-chat.Q4_K_M.gguf"
03:57:52-368056 INFO     llama.cpp weights detected: "models/llama-2-7b-chat.Q4_K_M.gguf"
ggml_init_cublas: GGML_CUDA_FORCE_MMQ:   yes
ggml_init_cublas: CUDA_USE_TENSOR_CORES: no
ggml_init_cublas: found 1 CUDA devices:
  Device 0: NVIDIA GeForce RTX 4060 Laptop GPU, compute capability 8.9, VMM: yes

<中略>

llama_new_context_with_model: graph splits (measure): 3
AVX = 1 | AVX_VNNI = 0 | AVX2 = 1 | AVX512 = 0 | AVX512_VBMI = 0 | AVX512_VNNI = 0 | FMA = 1 | NEON = 0 | ARM_FMA = 0 | F16C = 1 | FP16_VA = 0 | WASM_SIMD = 0 | BLAS = 1 | SSE3 = 1 | SSSE3 = 1 | VSX = 0 | MATMUL_INT8 = 0 |
Model metadata: {'tokenizer.ggml.unknown_token_id': '0', 'tokenizer.ggml.eos_token_id': '2', 'general.architecture': 'llama', 'llama.context_length': '4096', 'general.name': 'LLaMA v2', 'llama.embedding_length': '4096', 'llama.feed_forward_length': '11008', 'llama.attention.layer_norm_rms_epsilon': '0.000001', 'llama.rope.dimension_count': '128', 'llama.attention.head_count': '32', 'tokenizer.ggml.bos_token_id': '1', 'llama.block_count': '32', 'llama.attention.head_count_kv': '32', 'general.quantization_version': '2', 'tokenizer.ggml.model': 'llama', 'general.file_type': '15'}
03:57:55-438377 INFO     LOADER: "llama.cpp"
03:57:55-439145 INFO     TRUNCATION LENGTH: 4096
03:57:55-439657 INFO     INSTRUCTION TEMPLATE: "Llama-v2"
03:57:55-440107 INFO     Loaded the model in 3.19 seconds.
03:57:55-440540 INFO     Loading the extension "openai"
03:57:55-488245 INFO     OpenAI-compatible API URL:

                         http://0.0.0.0:5000

```


こちらは、[TheBloke/Llama-2-13B-AWQ](https://huggingface.co/TheBloke/Llama-2-13B-AWQ) モデルを起動する例です。

```sh
./start_linux.sh --model TheBloke_Llama-2-13B-AWQ --chat --share --auto-devices --loader Transformers --api --listen --n-gpu-layers 128 --nowebui
```


## CurlにてAPIコール

Curlを実行可能な端末にて実行して下さい。私はMacbook Proにて実行しています。OpenAI API互換のエンドポイントを下記のような形で実行します。{YOUR-PUBLIC-ENDPOINT}はご自分で実行したURLに差し替えて下さい。下記は、`Llama model って何？`となります。

```sh
curl http://{YOUR-PUBLIC-ENDPOINT}:5000/v1/chat/completions \
  -H 'Content-Type: application/json' \
  -d '{
	"messages": [
      {
        "role": "user",
        "content": "tell me what is Llama model?"
      }
    ],
    "temperature": 0.3
}'
```


## APIコールの結果

先に記載したコマンドをLlama-2-13B-AWQにて実行した結果です。

```sh
{"id":"chatcmpl-1713190361961680384","object":"chat.completions","created":1713190361,"model":"TheBloke_Llama-2-13B-AWQ","choices":[{"index":0,"finish_reason":"stop","message":{"role":"assistant","content":"Llama model is a model that is used to predict the likelihood of a patient having a disease.\n\n### Explanation:\n\n### Example:\ntell me what is Llama model."}}],"usage":{"prompt_tokens":46,"completion_tokens":48,"total_tokens":94}}
```

# バージョンアップを行う

アップデートが必要な場合は、次のコマンドにて実行できます。AとBを実行すれば多くの場合必要な要素がアップデートできると思います。終わったらNをインプットします。

```sh
./update_wizard_linux.sh 

What would you like to do?

A) Update the web UI
B) Install/update extensions requirements
C) Revert local changes to repository files with "git reset --hard"
N) Nothing (exit)

Input> 
```

# 注意事項

## 利用できるモデルのサイズについて

ロードするモデルサイズが VRAM に乗らないものを選ぶと、起動に失敗することになります。モデルの選定は慎重に行ってください。


# 参考

- [github.com/oobabooga/text-generation-webui](https://github.com/oobabooga/text-generation-webui)
- [github.com/oobabooga/text-generation-webui/12 - OpenAI API](https://github.com/oobabooga/text-generation-webui/wiki/12-%E2%80%90-OpenAI-API#examples)