ユニファ開発者ブログ

ユニファ株式会社プロダクトデベロップメント本部メンバーによるブログです。

ローカルLLM on Docker 初歩の初歩

みなさんこんにちは、ユニファの赤沼です。 この記事は Unifa Advent Calendar 2023 の24日目の記事です。

adventar.org

最近 ChatGPT をはじめとした LLM をAPIで利用することは多い一方で、ローカル環境でモデルを動かしたことはなかったのですが、先日ブラックフライデーのセールでゲーミングPCが安くなっていて、 ただゲームやりたさに AI関連のことに使いたいなと思い Windows PC を買ったこともあり、何もわからないところから最低限ひとまずモデルを動かしてみました。

ローカルに直接各種ライブラリなどをインストールして環境を作るのは後々依存関係など面倒なので Docker で動かしたいと思い、手探りでいろんなサイトを拝見してやり方を調べましたが、 WSL2 の Ubuntu の上で環境を構築するケースが多そうだったものの、WindowsもローカルLLMも初心者なので、今回はまずはシンプルに Windows 上の Docker で動かす方法でやってみます。

NVIDIA ドライバの確認

まずは NVIDIA のドライバが入っているかを確認します。 nvidia-msi コマンドを実行すると下記のように GPU の情報が確認できたので、ドライバは問題なさそうです。これは既に GeForce Experience からドライバーをインストールしてあったことによるものかと思います。

Docker・Windows環境

Docker は Docker Desktop を使っていて、バージョンは下記のとおりです。

> docker version  
Client:
 Cloud integration: v1.0.35+desktop.5
 Version:           24.0.7
 API version:       1.43
 Go version:        go1.20.10
 Git commit:        afdd53b
 Built:             Thu Oct 26 09:08:44 2023
 OS/Arch:           windows/amd64
 Context:           default

Server: Docker Desktop 4.26.1 (131620)
 Engine:
  Version:          24.0.7
  API version:      1.43 (minimum version 1.12)
  Go version:       go1.20.10
  Git commit:       311b9ff
  Built:            Thu Oct 26 09:08:02 2023
  OS/Arch:          linux/amd64
  Experimental:     false
 containerd:
  Version:          1.6.25
  GitCommit:        d8f198a4ed8892c764191ef7b3b06d8a2eeb5c7f
 runc:
  Version:          1.1.10
  GitCommit:        v1.1.10-0-g18a0cb0
 docker-init:
  Version:          0.19.0
  GitCommit:        de40ad0

Windowsやデバイスのスペックは下記の通り。

  • エディション Windows 11 Home
  • バージョン 23H2
  • プロセッサ AMD Ryzen 7 6800H with Radeon Graphics 3.20 GHz
  • 実装 RAM 16.0 GB (15.2 GB 使用可能)

CPU で Llama のクイックデモを動かす

まずは Docker が公開している下記のチュートリアル的な記事に沿ってLlamaのモデルを動かしてみます。

www.docker.com

Llamaモデルへのアクセスリクエストが必要ということなので Hugging Face の下記ページの案内に従って Submit しておきます。

huggingface.co

私の場合は一時間以内ぐらいで Access granted のメールが来たと思います。

また、 Hugging Face のアカウントの設定ページからアクセストークンを作成しておきます。

では下記コマンドを実行してモデルを動かしてみます。 HUGGING_FACE_HUB_TOKEN には Hugging Face のアクセストークンを設定します。

初回実行時はイメージのダウンロードに時間がかかります。2回目以降でもモデルのファイル取得が発生するので、私の環境だと起動までに2分ぐらいかかりました。

PS C:\Users\hiroa> docker run -it -p 7860:7860 --platform=linux/amd64 -e HUGGING_FACE_HUB_TOKEN="XXXXXXXXXXXXXXXXXXXX" registry.hf.space/harsh-manvar-llama-2-7b-chat-test:latest python app.py  
Unable to find image 'registry.hf.space/harsh-manvar-llama-2-7b-chat-test:latest' locally
latest: Pulling from harsh-manvar-llama-2-7b-chat-test
0a9573503463: Pull complete
1ccc26d841b4: Pull complete
800d84653581: Pull complete
7c632e57ea62: Pull complete
f9a1922eee8a: Pull complete
b0fef9d6962c: Pull complete
a8d4dcc5b913: Pull complete
ffdc35a04c11: Pull complete
0472b8c3ae5c: Pull complete
a788554e043e: Pull complete
03098cd05c8d: Pull complete
98b5990936af: Pull complete
46995db4b389: Pull complete
8b97359802d5: Pull complete
a39f01aaecff: Pull complete
fd856e75ffe3: Pull complete
3ef947ccedda: Pull complete
Digest: sha256:d0db0be9521a717a108a722f73087acf6c64b707695d76c15afa137df8c96439
Status: Downloaded newer image for registry.hf.space/harsh-manvar-llama-2-7b-chat-test:latest
config.json: 100%|██████████████████████████████████████████████████████████████████████████████████████████████████████████| 29.0/29.0 [00:00<00:00, 91.8kB/s]
Fetching 1 files: 100%|██████████████████████████████████████████████████████████████████████████████████████████████████████████| 1/1 [00:00<00:00,  2.23it/s]
llama-2-7b-chat.ggmlv3.q2_K.bin: 100%|████████████████████████████████████████████████████████████████████████████████████| 2.87G/2.87G [01:58<00:00, 24.3MB/s]
Fetching 1 files: 100%|█████████████████████████████████████████████████████████████████████████████████████████████████████████| 1/1 [01:59<00:00, 119.86s/it]
Generate config GenerationConfig {
  "_from_model_config": true,
  "bos_token_id": 1,
  "eos_token_id": 2,
  "pad_token_id": 2,
  "transformers_version": "4.31.0"
}

tokenizer_config.json: 100%|██████████████████████████████████████████████████████████████████████████████████████████████| 1.62k/1.62k [00:00<00:00, 4.54MB/s]
tokenizer.model: 100%|██████████████████████████████████████████████████████████████████████████████████████████████████████| 500k/500k [00:00<00:00, 11.2MB/s]
tokenizer.json: 100%|█████████████████████████████████████████████████████████████████████████████████████████████████████| 1.84M/1.84M [00:00<00:00, 2.70MB/s]
special_tokens_map.json: 100%|████████████████████████████████████████████████████████████████████████████████████████████████| 414/414 [00:00<00:00, 1.29MB/s]
loading file tokenizer.model from cache at /home/user/.cache/huggingface/hub/models--meta-llama--Llama-2-7b-chat-hf/snapshots/c1b0db933684edbfe29a06fa47eb19cc48025e93/tokenizer.model
loading file tokenizer.json from cache at /home/user/.cache/huggingface/hub/models--meta-llama--Llama-2-7b-chat-hf/snapshots/c1b0db933684edbfe29a06fa47eb19cc48025e93/tokenizer.json
loading file added_tokens.json from cache at None
loading file special_tokens_map.json from cache at /home/user/.cache/huggingface/hub/models--meta-llama--Llama-2-7b-chat-hf/snapshots/c1b0db933684edbfe29a06fa47eb19cc48025e93/special_tokens_map.json
loading file tokenizer_config.json from cache at /home/user/.cache/huggingface/hub/models--meta-llama--Llama-2-7b-chat-hf/snapshots/c1b0db933684edbfe29a06fa47eb19cc48025e93/tokenizer_config.json
Starting
Running on local URL:  http://0.0.0.0:7860

To create a public link, set `share=True` in `launch()`.

起動が完了したら http://localhost:7860 にアクセスすると下記のようなデモ用のチャットのUIが表示されます。

英語で入力すると普通に対話ができそうです。日本語も解釈してくれているようですが、そのまま日本語で会話できるという感じではなさそうです。

UI下部の Advanced options を開くと システムプロンプトや各種パラメータの設定もできるようです。

docker コマンドを実行したターミナルには下記のように入力についてのログが表示されます。

display_input=Hello
Generate config GenerationConfig {
  "_from_model_config": true,
  "bos_token_id": 1,
  "eos_token_id": 2,
  "pad_token_id": 2,
  "transformers_version": "4.31.0"
}

display_input=日本語も話せますか?
Generate config GenerationConfig {
  "_from_model_config": true,
  "bos_token_id": 1,
  "eos_token_id": 2,
  "pad_token_id": 2,
  "transformers_version": "4.31.0"
}

とりあえずこれでローカルでモデルを動かすこと自体はできましたが、ここまでの内容では GPU は使われておらず、すべて CPU で処理されているようです。

GPU でモデルを動かす

GPUが使われないとゲーミングPCでやってる意味もないということで、先程のデモの内容を少し変更して動かそうとしてみたのですがすんなりはうまく行かなかったので方法を探したところ、 @karaage0703 さんが下記の記事を公開されていたのでこれをもとに動かしてみます。

zenn.dev

記事では Linux環境、もしくは WSL2 の環境をベースとされていますが、今回は Windows から直接 Docker を使います。

まずは下記コマンドでリポジトリを clone してからイメージをビルドします。

> git clone https://github.com/karaage0703/ChatLLM
> cd ChatLLM
> docker build -t ubuntu:ChatLLM .

ビルドが終わったら下記コマンドでコンテナを起動します。

--gpusNVIDIA の GPU を使うためのオプションで、 all を指定することで全ての GPU が使われることになります。

> docker run -it -v C:\Users\hiroa\workspaces\ChatLLM:/root --gpus all ubuntu:ChatLLM

コンテナ内でプロンプトが表示されたら用意されている Python のスクリプトを動かします。下記では サイバーエージェントによって開発されたモデルである CALM を使っています。

# cd /root
# python3 chat_calm.py

プロンプトが表示されたら文を入力してみます。

> こんにちは
CALM: こんにちは!
今回は、3月生まれのお誕生日会を行いました。
今回は、3月生まれのお友達のお祝いということで、
4名のお友達をお祝いしました。
とってもかわいい、3月生まれのお友達です。
お名前を言ってもらって、みんなでお祝いしました。
3月生まれのお友達、お誕生日おめでとうございます
> 今日の東京の天気は
CALM: 今日の東京の天気は雨・・・
「台風」で気圧変化が大きいと、自律神経のバランスが乱れ、頭痛、めまい、耳鳴り、吐き気・・・
などの症状を引き起こします。
また、
台風が通過する地域の方は、台風の風や雨で体調を崩さないよう
くれぐれもご注意を!
「台風」

このモデルはチャット用のモデルではないため、入力した文の続きを推測して出力するような内容になっています。

上記実行中は下記のように GPU の使用率が上がったため、ちゃんと GPU が活用されたようです。

CALM以外にも りんな などを使うためのスクリプトも用意されていますが、自分の環境で動かした際にはエラーになってしまい、CALMしか実際の動きは試せませんでした。この原因調査はまた別途してみたいと思います。

まとめ

今回は他の方が用意されたスクリプトを動かしただけの形ではありましたが、ともかくローカル環境のDockerでLLMのモデルをGPUを使って動かすことができました。やはり実際に動かしてみるとうまく行かないことを調べたりしながら少しずつでもイメージが掴めてきて良いですね。私のPCのスペックは GeForce を積んではいても高いスペックではないので実質的に使い物になるかは微妙なところですが、面白そうなのでもっと色々と触ってみようと思います。

ユニファではGPUがあったらLLMを動かしてみたくなっちゃうような仲間も募集中です!少しでも興味をお持ちいただけた方は、ぜひ一度カジュアルにお話しましょう!

unifa-e.com