NIM(NVIDIA Inference Microservices)を使ってみました
みなさん、こんにちは
CerebrasプリセールスエンジニアのNakadaです。これまでブログにて大規模自然言語(LLM)について掲載させて頂きましたが、今回はそのLLM環境を簡単に構築できるツールとして、NVIDIA Inference Microservices for LLMを使ってみましたので、そのレポートを掲載させていただきます。
■NVIDIA Inference Microservices
NVIDIA Inference Microservices(NIM)はNVIDIAが提供するAI モデルの推論環境を本番環境にデプロイするためのマイクロサービスです。これを使うことで、NVIDIA DGX、NVIDIA DGX Cloud、NVIDIA 認定システムなどを利用しているクラウド、データセンター、オンプレミスのGPUサーバに対し、AI モデルのデプロイが簡単かつ効率的に行えるようになります。
また、開発者はNIMでデプロイしたAIモデルを業界標準のAPIを使用してAIモデルにアクセスできるため、AIアプリケーションの開発が非常にシンプルになります。更に推論実行にはTensorRTがベースとなり、利用するGPUに合わせて推論環境に最適化されるため、ユーザは意識せずに高スループットの推論環境をデプロイすることが可能です。
■NVIDIA Inference MicroservicesでサポートされるAIモデル
今回はLLM環境をデプロイするためにNIM for LLMを利用しますが、LLMのほかに、音声、動画処理、ヘルスケアなど、特定のユースケースに対応したNIMも用意されています。
基本的にはNVIDIAが学習した学習済みモデルを利用するため、一番コストが掛かる学習フェーズをユーザが実行することなく、推論環境をデプロイすることが可能です。
なお、デプロイにはDockerコンテナを利用するため、コンテナを起動するためのパラメータを設定するだけで、あとはDocker runまたは、Docker Composeを利用して必要なコンテナを起動するだけで推論環境が構築できます。また、Kubernetesを管理するパッケージマネージャーであるHelmでも利用できるため、Kubernetes上でもNIMを利用することが可能です。
■NVIDIA Inference Microservicesで使ってみる
まず初めに、NIMを利用するためにはNVIDIA AI Enterpriseライセンスが必要となります。もしH100 GPUを購入している場合は、製品に該当ライセンスが付属していますので、NVIDIA GPU Cloud(https://www.nvidia.com/ja-jp/gpu-cloud/)よりアカウントの作成及びNVIDIA AI Enterpriseライセンスのアクティベーションを行ってください。A100 GPUなどのNVIDIA GPUを所有しているが、ライセンスが無い場合は、無料で90日間試用できますので同じく、NVIDIA GPU Cloudにて登録してください。
利用環境 |
サーバ:Dell R750 server (A100 x2枚) |
OS: Ubuntu 22.04.3 LTS ※GPUドライバー、Docker環境をインストール済み |
【手順】
1.NGC_API_KEYの発行
NIMコンテナをダウンロードするためにNGC_API_KEYが必要です。NVIDIA GPU Cloudのサイトにて各自のアカウントから発行できます。
2.LLM用のNIMを起動
今回は、NIM for LLM(1.1.3)でサポートしているMeta社Llama3-8B(meta-llama3-8b-instruct)を利用します。
2-1.環境変数の設定とNIMキャッシュディレクトリの作成
export CONTAINER_NAME=meta-llama3-8b-instruct
export NIM_CACHE_PATH=~/NIM-cache
export NGC_API_KEY=nvapi-***************** <-NVIDIA GPU Cloudで発行されたキーを利用
mkdir ~/NIM-cache
chmod -R 777 ~/NIM-cache
2-2.NGC コンテナーレジストリにログイン
echo “$NGC_API_KEY” | docker login nvcr.io –username ‘$oauthtoken’ –password-stdin
2-3.NIM for LLM起動
以下のdockerコマンドでNIM for LLMを起動します。※利用するGPUは2枚のうちGPU0を指定しました。
docker run -it –rm –name=$CONTAINER_NAME –runtime=nvidia –gpus ‘”device=0″‘ –shm-size=16GB -e NGC_API_KEY -v $NIM_CACHE_PATH:/opt/nim/.cache nvcr.io/nim/meta/llama3-8b-instruct:1.0.0
なお、実行に-eを指定することで、様々なオプションを追加し実行することが可能です。詳細はこちらの「Environment Variables」を参照してください。
■起動ログ
test@r750:~$ docker run -it –rm –name=$CONTAINER_NAME –runtime=nvidia –gpus ‘”device=0″‘ –shm-size=16GB -e NGC_API_KEY -v $NIM_CACHE_PATH:/opt/nim/.cache nvcr.io/nim/meta
/llama3-8b-instruct:1.0.0
===========================================
== NVIDIA Inference Microservice LLM NIM ==
===========================================
NVIDIA Inference Microservice LLM NIM Version 1.0.0
Model: nim/meta/llama3-8b-instruct
Container image Copyright (c) 2016-2024, NVIDIA CORPORATION & AFFILIATES. All rights reserved.
This NIM container is governed by the NVIDIA AI Product Agreement here:
https://www.nvidia.com/en-us/data-center/products/nvidia-ai-enterprise/eula/.
A copy of this license can be found under /opt/nim/LICENSE.
—————省略—————
INFO 08-21 07:00:00.125 api_server.py:460] An example cURL request:
curl -X ‘POST’ \
‘http://0.0.0.0:8000/v1/chat/completions’ \
-H ‘accept: application/json’ \
-H ‘Content-Type: application/json’ \
-d ‘{
“model”: “meta/llama3-8b-instruct”,
“messages”: [
{
“role”:”user”,
“content”:”Hello! How are you?”
},
{
“role”:”assistant”,
“content”:”Hi! I am quite well, how can I help you today?”
},
{
“role”:”user”,
“content”:”Can you write me a song?”
}
],
“top_p”: 1,
“n”: 1,
“max_tokens”: 15,
“stream”: true,
“frequency_penalty”: 1.0,
“stop”: [“hello”]
}’
INFO 08-21 07:00:00.169 server.py:82] Started server process [32]
INFO 08-21 07:00:00.169 on.py:48] Waiting for application startup.
INFO 08-21 07:00:00.173 on.py:62] Application startup complete.
INFO 08-21 07:00:00.174 server.py:214] Uvicorn running on http://0.0.0.0:8000 (Press CTRL+C to quit)
これで、起動しました。nvidia-smiコマンドで指定したGPU0にllama3-8b-instructモデルがロードされメモリが「72034MiB」消費されていることがわかります。
+—————————————————————————————–+
| Processes: |
| GPU GI CI PID Type Process name GPU Memory |
| ID ID Usage |
|=========================================================================================|
| 0 N/A N/A 2459 G /usr/lib/xorg/Xorg 4MiB |
| 0 N/A N/A 21587 C python3 72034MiB |
| 1 N/A N/A 2459 G /usr/lib/xorg/Xorg 4MiB |
+—————————————————————————————–+
- 起動したNIM for LLMにプロンプトを投げてみる
起動するとcurlを利用してNIM for LLM APIにプロンプトを投げることが可能になります。起動ログに出力された利用例を使い、プロンプトを投げてみます。
<実行コマンド>
test@r750:~$ curl -X ‘POST’ \
‘http://0.0.0.0:8000/v1/chat/completions’ \
-H ‘accept: application/json’ \
-H ‘Content-Type: application/json’ \
-d ‘{ “model”: “meta/llama3-8b-instruct”,
“messages”: [
{
“role”:”user”,
“content”:”Hello! How are you?”
},
{
“role”:”assistant”,
“content”:”Hi! I am quite well, how can I help you today?”
},
{
“role”:”user”,
“content”:”Can you write me a song?“
}
],
“top_p”: 1,
“n”: 1,
“max_tokens”: 15,
“stream”: true,
“frequency_penalty”: 1.0,
“stop”: [“hello”]
}'</p
出力結果は以下になります。少しわかりづらいですが、curlで投げた質問は「Can you write me a song?」で、生成された文はトークン毎に出力されていてこちらも分かりづらいですが、「I d be happy to write a song for you Do you have any」が生成されています。
<出力ログ>
data: {“id”:”cmpl-6e3ef45d7c9c4ca6bd697cc4ebfd2d46″,”object”:”chat.completion.chunk”,”created”:1724224195,”model”:”meta/llama3-8b-instruct”,”choices”:[{“index”:0,”delta”:{“role”:”assistant”},”logprobs”:null,”finish_reason”:null}]}
data: {“id”:”cmpl-6e3ef45d7c9c4ca6bd697cc4ebfd2d46″,”object”:”chat.completion.chunk”,”created”:1724224195,”model”:”meta/llama3-8b-instruct”,”choices”:[{“index”:0,”delta”:{“content”:””},”logprobs”:null,”finish_reason”:null}]}
data: {“id”:”cmpl-6e3ef45d7c9c4ca6bd697cc4ebfd2d46″,”object”:”chat.completion.chunk”,”created”:1724224195,”model”:”meta/llama3-8b-instruct”,”choices”:[{“index”:0,”delta”:{“content”:””},”logprobs”:null,”finish_reason”:null}]}
data: {“id”:”cmpl-6e3ef45d7c9c4ca6bd697cc4ebfd2d46″,”object”:”chat.completion.chunk”,”created”:1724224195,”model”:”meta/llama3-8b-instruct”,”choices”:[{“index”:0,”delta”:{“content”:”I‘”},”logprobs”:null,”finish_reason”:null}]}
data: {“id”:”cmpl-6e3ef45d7c9c4ca6bd697cc4ebfd2d46″,”object”:”chat.completion.chunk”,”created”:1724224195,”model”:”meta/llama3-8b-instruct”,”choices”:[{“index”:0,”delta”:{“content”:”d be h“},”logprobs”:null,”finish_reason”:null}]}
data: {“id”:”cmpl-6e3ef45d7c9c4ca6bd697cc4ebfd2d46″,”object”:”chat.completion.chunk”,”created”:1724224195,”model”:”meta/llama3-8b-instruct”,”choices”:[{“index”:0,”delta”:{“content”:”app“},”logprobs”:null,”finish_reason”:null}]}
data: {“id”:”cmpl-6e3ef45d7c9c4ca6bd697cc4ebfd2d46″,”object”:”chat.completion.chunk”,”created”:1724224195,”model”:”meta/llama3-8b-instruct”,”choices”:[{“index”:0,”delta”:{“content”:”y to w“},”logprobs”:null,”finish_reason”:null}]}
data: {“id”:”cmpl-6e3ef45d7c9c4ca6bd697cc4ebfd2d46″,”object”:”chat.completion.chunk”,”created”:1724224195,”model”:”meta/llama3-8b-instruct”,”choices”:[{“index”:0,”delta”:{“content”:”ri“},”logprobs”:null,”finish_reason”:null}]}
data: {“id”:”cmpl-6e3ef45d7c9c4ca6bd697cc4ebfd2d46″,”object”:”chat.completion.chunk”,”created”:1724224195,”model”:”meta/llama3-8b-instruct”,”choices”:[{“index”:0,”delta”:{“content”:”te a “},”logprobs”:null,”finish_reason”:null}]}
data: {“id”:”cmpl-6e3ef45d7c9c4ca6bd697cc4ebfd2d46″,”object”:”chat.completion.chunk”,”created”:1724224195,”model”:”meta/llama3-8b-instruct”,”choices”:[{“index”:0,”delta”:{“content”:”song“},”logprobs”:null,”finish_reason”:null}]}
data: {“id”:”cmpl-6e3ef45d7c9c4ca6bd697cc4ebfd2d46″,”object”:”chat.completion.chunk”,”created”:1724224195,”model”:”meta/llama3-8b-instruct”,”choices”:[{“index”:0,”delta”:{“content”:” for“},”logprobs”:null,”finish_reason”:null}]}
data: {“id”:”cmpl-6e3ef45d7c9c4ca6bd697cc4ebfd2d46″,”object”:”chat.completion.chunk”,”created”:1724224195,”model”:”meta/llama3-8b-instruct”,”choices”:[{“index”:0,”delta”:{“content”:” “},”logprobs”:null,”finish_reason”:null}]}
data: {“id”:”cmpl-6e3ef45d7c9c4ca6bd697cc4ebfd2d46″,”object”:”chat.completion.chunk”,”created”:1724224195,”model”:”meta/llama3-8b-instruct”,”choices”:[{“index”:0,”delta”:{“content”:”you“},”logprobs”:null,”finish_reason”:null}]}
data: {“id”:”cmpl-6e3ef45d7c9c4ca6bd697cc4ebfd2d46″,”object”:”chat.completion.chunk”,”created”:1724224195,”model”:”meta/llama3-8b-instruct”,”choices”:[{“index”:0,”delta”:{“content”:”. Do“},”logprobs”:null,”finish_reason”:null}]}
data: {“id”:”cmpl-6e3ef45d7c9c4ca6bd697cc4ebfd2d46″,”object”:”chat.completion.chunk”,”created”:1724224195,”model”:”meta/llama3-8b-instruct”,”choices”:[{“index”:0,”delta”:{“content”:” you “},”logprobs”:null,”finish_reason”:null}]}
data: {“id”:”cmpl-6e3ef45d7c9c4ca6bd697cc4ebfd2d46″,”object”:”chat.completion.chunk”,”created”:1724224195,”model”:”meta/llama3-8b-instruct”,”choices”:[{“index”:0,”delta”:{“content”:”have any“},”finish_reason”:”length”}],”usage”:{“prompt_tokens”:47,”total_tokens”:62,”completion_tokens”:15}}
data: [DONE]
test@r750:~$
次に、日本語でプロンプトを投げてみます。Llama3は英語のみ対応のため、正確な回答を得られるか不明ですが、先ほどの英文を日本語にして投げてみます。
<実行コマンド>
test@r750:~$ curl -X ‘POST’ \
‘http://0.0.0.0:8000/v1/chat/completions’ \
-H ‘accept: application/json’ \
-H ‘Content-Type: application/json’ \
-d ‘{
“model”: “meta/llama3-8b-instruct”,
“messages”: [
{
“role”:”user”,
“content”:”あなたは私に歌を書くことが出来ますか?“
}
],
“top_p”: 1,
“n”: 1,
“max_tokens”: 15,
“stream”: true,
“frequency_penalty”: 1.0
}’
以下が出力ですが、英語で回答が生成されました。「Ah, yeah! I d love to write a song for you」ただし、回答内容はそれほど間違っていないと思います。※日本語訳は「ああ、そうだ!あなたのために歌を書きたいです」
<出力ログ>
data: {“id”:”cmpl-de0e60416c7b491ba1e6b6507836a615″,”object”:”chat.completion.chunk”,”created”:1724225073,”model”:”meta/llama3-8b-instruct”,”choices”:[{“index”:0,”delta”:{“role”:”assistant”},”logprobs”:null,”finish_reason”:null}]}
data: {“id”:”cmpl-de0e60416c7b491ba1e6b6507836a615″,”object”:”chat.completion.chunk”,”created”:1724225073,”model”:”meta/llama3-8b-instruct”,”choices”:[{“index”:0,”delta”:{“content”:””},”logprobs”:null,”finish_reason”:null}]}
data: {“id”:”cmpl-de0e60416c7b491ba1e6b6507836a615″,”object”:”chat.completion.chunk”,”created”:1724225073,”model”:”meta/llama3-8b-instruct”,”choices”:[{“index”:0,”delta”:{“content”:”?”},”logprobs”:null,”finish_reason”:null}]}
data: {“id”:”cmpl-de0e60416c7b491ba1e6b6507836a615″,”object”:”chat.completion.chunk”,”created”:1724225073,”model”:”meta/llama3-8b-instruct”,”choices”:[{“index”:0,”delta”:{“content”:” Ah“},”logprobs”:null,”finish_reason”:null}]}
data: {“id”:”cmpl-de0e60416c7b491ba1e6b6507836a615″,”object”:”chat.completion.chunk”,”created”:1724225073,”model”:”meta/llama3-8b-instruct”,”choices”:[{“index”:0,”delta”:{“content”:”,“},”logprobs”:null,”finish_reason”:null}]}
data: {“id”:”cmpl-de0e60416c7b491ba1e6b6507836a615″,”object”:”chat.completion.chunk”,”created”:1724225073,”model”:”meta/llama3-8b-instruct”,”choices”:[{“index”:0,”delta”:{“content”:” yeah“},”logprobs”:null,”finish_reason”:null}]}
data: {“id”:”cmpl-de0e60416c7b491ba1e6b6507836a615″,”object”:”chat.completion.chunk”,”created”:1724225073,”model”:”meta/llama3-8b-instruct”,”choices”:[{“index”:0,”delta”:{“content”:”!“},”logprobs”:null,”finish_reason”:null}]}
data: {“id”:”cmpl-de0e60416c7b491ba1e6b6507836a615″,”object”:”chat.completion.chunk”,”created”:1724225073,”model”:”meta/llama3-8b-instruct”,”choices”:[{“index”:0,”delta”:{“content”:” I“},”logprobs”:null,”finish_reason”:null}]}
data: {“id”:”cmpl-de0e60416c7b491ba1e6b6507836a615″,”object”:”chat.completion.chunk”,”created”:1724225073,”model”:”meta/llama3-8b-instruct”,”choices”:[{“index”:0,”delta”:{“content”:”‘d“},”logprobs”:null,”finish_reason”:null}]}
data: {“id”:”cmpl-de0e60416c7b491ba1e6b6507836a615″,”object”:”chat.completion.chunk”,”created”:1724225073,”model”:”meta/llama3-8b-instruct”,”choices”:[{“index”:0,”delta”:{“content”:” love“},”logprobs”:null,”finish_reason”:null}]}
data: {“id”:”cmpl-de0e60416c7b491ba1e6b6507836a615″,”object”:”chat.completion.chunk”,”created”:1724225073,”model”:”meta/llama3-8b-instruct”,”choices”:[{“index”:0,”delta”:{“content”:” to“},”logprobs”:null,”finish_reason”:null}]}
data: {“id”:”cmpl-de0e60416c7b491ba1e6b6507836a615″,”object”:”chat.completion.chunk”,”created”:1724225073,”model”:”meta/llama3-8b-instruct”,”choices”:[{“index”:0,”delta”:{“content”:” write“},”logprobs”:null,”finish_reason”:null}]}
data: {“id”:”cmpl-de0e60416c7b491ba1e6b6507836a615″,”object”:”chat.completion.chunk”,”created”:1724225073,”model”:”meta/llama3-8b-instruct”,”choices”:[{“index”:0,”delta”:{“content”:” a“},”logprobs”:null,”finish_reason”:null}]}
data: {“id”:”cmpl-de0e60416c7b491ba1e6b6507836a615″,”object”:”chat.completion.chunk”,”created”:1724225073,”model”:”meta/llama3-8b-instruct”,”choices”:[{“index”:0,”delta”:{“content”:” song“},”logprobs”:null,”finish_reason”:null}]}
data: {“id”:”cmpl-de0e60416c7b491ba1e6b6507836a615″,”object”:”chat.completion.chunk”,”created”:1724225073,”model”:”meta/llama3-8b-instruct”,”choices”:[{“index”:0,”delta”:{“content”:” for“},”logprobs”:null,”finish_reason”:null}]}
data: {“id”:”cmpl-de0e60416c7b491ba1e6b6507836a615″,”object”:”chat.completion.chunk”,”created”:1724225073,”model”:”meta/llama3-8b-instruct”,”choices”:[{“index”:0,”delta”:{“content”:” you“},”finish_reason”:”length”}],”usage”:{“prompt_tokens”:24,”total_tokens”:39,”completion_tokens”:15}}
data: [DONE]
如何でしょうか?環境設定を行い、dockerコンテナを起動させるだけで、Meta Llama3-8Bの推論環境が構築できました。なお、今回利用したLLMモデルはInstructチューニングしたものを利用しただけですが、NIM for LLMバージョン1.1.3(2024年8月)時点では、以下の特定LLMモデルのみサポートとなっていますので注意が必要です。また、サポートされたLLMモデルを使ったPEFTチューニングモデルもサポートしていますので、ユーザがLLMをある程度カスタマイズ可能です。ただし、基盤モデルを独自データセットでフルファイチューニングしたLLMモデルは、サポートモデルであってもまだ利用できませんのでご注意ください。
サポートモデル |
Meta Llama3.1 8B Base |
Meta Llama3.1 8B Instruct |
Meta Llama3.1 70B Instruct |
Meta Llama3.1 405B Instruct |
Meta Llama3 8B Instruct |
Meta Llama3 70B Instruct |
Mistral 7B Instruct v0.3 |
Mistral 8x7B v0.1 |
Mistral 8x22B v0.1 |
注:モデルの大きさにより必要なGPU枚数が異なります。405BモデルではH100GPU 16枚が必要な場合もあるので環境に合わせてご利用ください。
■最後に
今回は以上となります。NVIDIA Inference Microservicesを使うことで、簡単に推論環境(API環境)が構築できることがわかりましたが、このままではユーザがUI環境で利用できません。NIM for LLMでは、ユーザ利用環境としてWebUIとRAG環境(EmbeddingとVectorDBなど)も準備されていて、今回利用したLLM用APIと連携させ、Chatbotを利用することも可能です。これについては、次回紹介したいと思います。最後に、ブログをお読みになり、LLM構築及びAIアクセラレータ製品等にご興味がある方は当社までお問合せ頂ければ幸いです。