本トピックでは、TensorRT-LLM および Triton Inference Server を活用し、Alibaba Cloud Container Service for Kubernetes (ACK) 上に Qwen2 大規模言語モデル(LLM)の推論サービスをデプロイする方法について説明します。Fluid を用いたデータオーケストレーションおよびキャッシュ機能により、モデル読み込みパフォーマンスを最適化し、効率的な AI 推論サービスを実現します。
背景情報
Qwen2 大規模言語モデル
Qwen2-1.5B-Instruct は、Alibaba Group の Tongyi Lab が開発した大規模言語モデルです。Transformer アーキテクチャを採用し、15 億パラメーターを有します。このモデルは、Web テキスト、専門書籍、コードなど多様な大量の事前学習データで学習されており、優れた自然言語理解および生成能力を備えています。
Qwen2 シリーズの主な特徴は以下のとおりです:
-
質問応答、テキスト生成、コード理解など、複数の推論タスクをサポート
-
実際のユースケースへの適合性を高めるため、命令チューニング(instruction tuning)を実施
-
比較的適度なモデルサイズであり、GPU を用いた推論デプロイに適している
モデルの詳細および技術仕様については、「Qwen2 公式 GitHub リポジトリ」をご参照ください。
Triton Inference Server
Triton Inference Server は、NVIDIA が開発したオープンソースの推論サービスフレームワークであり、本番環境向けに設計されています。TensorRT、TensorFlow、PyTorch、ONNX Runtime など複数の機械学習フレームワークをバックエンドとしてサポートし、フレームワーク横断でのモデルデプロイを統一します。
Triton の主な利点は以下のとおりです:
-
モデルデプロイおよび管理を簡素化する統一推論インターフェイス
-
GPU 利用率向上のための動的バッチ処理(dynamic batching)対応
-
高スループット推論のための最適化された同時処理機能
-
包括的なモニタリングおよびメトリック収集機能
Triton Inference Server の詳細については、「Triton Inference Server 公式 GitHub リポジトリ」をご参照ください。
TensorRT-LLM 最適化エンジン
TensorRT-LLM は、NVIDIA が大規模言語モデル向けに最適化した推論エンジンです。LLM を高度に最適化された TensorRT 実行エンジンへコンパイルすることで、NVIDIA GPU 上での卓越した推論パフォーマンスを実現します。
主な機能は以下のとおりです:
-
モデル量子化および最適化による推論速度の大幅向上
-
テンソル並列処理およびパイプライン並列処理のサポート
-
TensorRT-LLM Backend を介した Triton との深く統合された連携
-
FP16 や INT8 など、パフォーマンスと精度のバランスを取る複数の精度モード対応
技術的な詳細については、「TensorRT-LLM 公式 GitHub リポジトリ」をご参照ください。
前提条件
デプロイを開始する前に、環境が以下の要件を満たしていることを確認してください:
-
GPU 環境の準備:NVIDIA A10 GPU を含む ACK Pro マネージドクラスター を作成済みであること。クラスターの Kubernetes バージョンは 1.22 以降である必要があります。
推奨ドライバーのバージョン:NVIDIA ドライバー バージョン 525 を使用します。GPU ノードプールにラベル
ack.aliyun.com/nvidia-driver-version:525.105.17を付与して指定します。詳細な手順については、「GPU ドライバーのスペックアップドキュメント」をご参照ください。 -
Fluid コンポーネントのインストール:クラスター内に Fluid データオーケストレーションおよびキャッシュシステムをインストール済みであること。未インストールの場合は、「Fluid インストールガイド」に従ってインストールしてください。
-
Arena ツールの構成:モデルサービスのデプロイおよび管理を行う Arena コマンドラインインターフェイス(CLI)ツールをインストール・構成済みであること。インストール手順については、「Arena インストールドキュメント」をご参照ください。
-
OSS ストレージのセットアップ:Alibaba Cloud Object Storage Service (OSS) を有効化し、モデルファイルを格納するバケットを作成済みであること。「OSS クイックスタート」および「バケットの作成」をご参照ください。
-
権限の構成:ご利用の Alibaba Cloud アカウントが OSS に対する読み書き権限および ACK クラスターに対する管理権限を有していること。
ステップ 1:Fluid データセットおよびキャッシュの構成
本ステップでは、モデルデータの管理および高性能キャッシュを提供するため、Fluid Dataset および JindoRuntime を作成します。Dataset はデータを整理し、JindoRuntime は分散キャッシュを提供することで、モデル読み込みおよび推論パフォーマンスを大幅に向上させます。
パフォーマンスに関するヒント:メモリキャッシュを活用すると、モデル読み込み時間は数分から数秒に短縮されます。
-
OSS アクセス認証情報の作成
Kubernetes Secret を作成し、OSS の認証情報を格納します。
kubectl apply -f-<<EOF apiVersion: v1 kind: Secret metadata: name: fluid-oss-secret stringData: fs.oss.accessKeyId: <YourAccessKey ID> fs.oss.accessKeySecret: <YourAccessKey Secret> EOFセキュリティに関する注意事項:
<YourAccessKey ID>および<YourAccessKey Secret>を、実際の Alibaba Cloud AccessKey ペアに置き換えてください。AccessKey ペアの取得方法については、「AccessKey 管理ドキュメント」をご参照ください。正常終了時には、以下の出力が表示されます:
secret/fluid-oss-secret created -
Dataset および JindoRuntime の構成
Dataset および JindoRuntime リソースを定義するファイル dataset.yaml を作成します。Dataset はデータソースを記述し、JindoRuntime は分散キャッシュを提供します。
構成の詳細については、「Fluid 構成ドキュメント」をご参照ください。
# Dataset リソースを作成し、OSS データソースを構成します。 apiVersion: data.fluid.io/v1alpha1 kind: Dataset metadata: name: qwen2-oss spec: mounts: - mountPoint: oss://<oss_bucket>/qwen2-1.5b # 実際の OSS バケット名に置き換えてください。 name: qwen2 path: / options: fs.oss.endpoint: <oss_endpoint> # 実際の OSS エンドポイントに置き換えてください。 encryptOptions: - name: fs.oss.accessKeyId valueFrom: secretKeyRef: name: fluid-oss-secret key: fs.oss.accessKeyId - name: fs.oss.accessKeySecret valueFrom: secretKeyRef: name: fluid-oss-secret key: fs.oss.accessKeySecret accessModes: - ReadWriteMany --- # JindoRuntime リソースを作成し、キャッシュポリシーを構成します。 apiVersion: data.fluid.io/v1alpha1 kind: JindoRuntime metadata: name: qwen2-oss spec: replicas: 2 tieredstore: levels: - mediumtype: MEM volumeType: emptyDir path: /dev/shm quota: 20Gi high: "0.95" low: "0.7" fuse: properties: fs.oss.read.buffer.size: "8388608" # 8 MB の読み取りバッファー。 fs.oss.download.thread.concurrency: "200" # 同時ダウンロードスレッド数。 fs.oss.read.readahead.max.buffer.count: "200" # 読み-ahead バッファー数。 fs.oss.read.sequence.ambiguity.range: "2147483647" # シークエンス読み取り範囲。 args: - -oauto_cache - -oattr_timeout=1 - -oentry_timeout=1 - -onegative_timeout=1構成に関する補足:
-
mountPoint:モデルファイルが格納されている OSS 内のパスを指します。 -
quota: 20Gi:キャッシュ用に 20 GB のメモリを割り当てます。 -
replicas: 2:可用性向上のため、2 つのキャッシュインスタンスをデプロイします。
-
-
デプロイメントリソースの構成
構成ファイルを適用して、Dataset および JindoRuntime リソースを作成します:
kubectl apply -f dataset.yaml正常終了時には、以下の出力が表示されます:
dataset.data.fluid.io/qwen2-oss created jindoruntime.data.fluid.io/qwen2-oss createdこれにより、Dataset および JindoRuntime リソースが正常に作成・実行中であることが確認できます。
-
デプロイメント状態の確認
Dataset のデプロイメント状態およびキャッシュ状態を確認します:
kubectl get dataset qwen2-oss期待される出力例:
NAME UFS TOTAL SIZE CACHED CACHE CAPACITY CACHED PERCENTAGE PHASE AGE qwen2-oss 0.00B 0.00B 20.00GiB 0.0% Bound 57s状態に関する補足:
PHASE: Boundは Dataset が正常にバインドされたことを示します。CACHE CAPACITY: 20.00GiBは割り当てられた 20 GB のメモリキャッシュ領域を示します。
ステップ 2:モデル推論環境の構築
本ステップでは、Fluid Dataflow を活用して、モデルデプロイの主要な工程を自動化します。具体的には、ModelScope からの Qwen2 モデルのダウンロード、TensorRT-LLM 形式への変換、推論エンジンの構築、およびキャッシュへの事前読み込み(preload)を実行します。この宣言型アプローチにより、一貫性と再現性のあるデプロイメントが保証されます。
Dataflow は、複雑なマルチステップ操作を自動化されたワークフローにパッケージ化します。これにより、手動作業が削減され、デプロイメント効率が向上します。
-
Dataflow 構成ファイルの作成
3 ステップの自動化ワークフローを定義するファイル dataflow.yaml を作成します:
-
ModelScope から Qwen2-1.5B-Instruct ベースモデルをダウンロード
-
TensorRT-LLM ツールチェーンを用いてモデルを変換し、推論エンジンを構築
-
Dataload を用いて最適化済みモデルデータをキャッシュに事前読み込み
# ステップ 1:ModelScope から Qwen2 モデルをダウンロードします。 apiVersion: data.fluid.io/v1alpha1 kind: DataProcess metadata: name: step1-download-model spec: dataset: name: qwen2-oss namespace: default mountPath: /mnt/models/ processor: script: image: ac2-registry.cn-hangzhou.cr.aliyuncs.com/ac2/base:ubuntu22.04 imagePullPolicy: IfNotPresent restartPolicy: OnFailure command: - bash source: | #!/bin/bash echo "モデルのダウンロードを開始します..." if [ -d "${MODEL_MOUNT_PATH}/Qwen2-1.5B-Instruct" ]; then echo "モデルディレクトリが存在します。ダウンロードをスキップします。" else echo "Git LFS をインストールし、モデルをダウンロードします..." apt update && apt install -y git git-lfs git clone https://www.modelscope.cn/qwen/Qwen2-1.5B-Instruct.git Qwen2-1.5B-Instruct mv Qwen2-1.5B-Instruct ${MODEL_MOUNT_PATH} echo "モデルのダウンロードが完了しました。" fi env: - name: MODEL_MOUNT_PATH value: "/mnt/models" --- # ステップ 2:モデルを変換し、TensorRT-LLM エンジンを構築します。 apiVersion: data.fluid.io/v1alpha1 kind: DataProcess metadata: name: step2-trtllm-convert spec: runAfter: kind: DataProcess name: step1-download-model namespace: default dataset: name: qwen2-oss namespace: default mountPath: /mnt/models/ processor: script: image: kube-ai-registry.cn-shanghai.cr.aliyuncs.com/kube-ai/tritonserver-build:24.07-trtllm-python-py3 imagePullPolicy: IfNotPresent restartPolicy: OnFailure command: - bash source: | #!/bin/bash set -ex echo "モデル変換を開始します..." cd /tensorrtllm_backend/tensorrt_llm/examples/qwen # チェックポイントを変換します。 if [ -d "${MODEL_MOUNT_PATH}/Qwen2-1.5B-Instruct-ckpt" ]; then echo "チェックポイントが存在します。変換をスキップします。" else echo "モデルチェックポイントを変換します..." python3 convert_checkpoint.py \ --model_dir ${MODEL_MOUNT_PATH}/Qwen2-1.5B-Instruct \ --output_dir /root/Qwen2-1.5B-Instruct-ckpt \ --dtype float16 mv /root/Qwen2-1.5B-Instruct-ckpt ${MODEL_MOUNT_PATH} echo "チェックポイントの変換が完了しました。" fi sleep 2 # TensorRT エンジンを構築します。 if [ -d "${MODEL_MOUNT_PATH}/Qwen2-1.5B-Instruct-engine" ]; then echo "エンジンが存在します。構築をスキップします。" else echo "TensorRT-LLM エンジンを構築します..." trtllm-build \ --checkpoint_dir ${MODEL_MOUNT_PATH}/Qwen2-1.5B-Instruct-ckpt \ --gemm_plugin float16 \ --paged_kv_cache enable \ --output_dir /root/Qwen2-1.5B-Instruct-engine mv /root/Qwen2-1.5B-Instruct-engine ${MODEL_MOUNT_PATH} echo "エンジンの構築が完了しました。" fi # Triton モデルを構成します。 if [ -d "${MODEL_MOUNT_PATH}/tensorrtllm_backend" ]; then echo "構成が存在します。構成をスキップします。" else echo "Triton モデルを構成します..." cd /tensorrtllm_backend cp all_models/inflight_batcher_llm/ qwen2_ifb -r export QWEN2_MODEL=${MODEL_MOUNT_PATH}/Qwen2-1.5B-Instruct export ENGINE_PATH=${MODEL_MOUNT_PATH}/Qwen2-1.5B-Instruct-engine # 各コンポーネントの構成ファイルを生成します。 python3 tools/fill_template.py -i qwen2_ifb/preprocessing/config.pbtxt \ tokenizer_dir:${QWEN2_MODEL},triton_max_batch_size:8,preprocessing_instance_count:1 python3 tools/fill_template.py -i qwen2_ifb/postprocessing/config.pbtxt \ tokenizer_dir:${QWEN2_MODEL},triton_max_batch_size:8,postprocessing_instance_count:1 python3 tools/fill_template.py -i qwen2_ifb/tensorrt_llm_bls/config.pbtxt \ triton_max_batch_size:8,decoupled_mode:False,bls_instance_count:1,accumulate_tokens:False python3 tools/fill_template.py -i qwen2_ifb/ensemble/config.pbtxt \ triton_max_batch_size:8 python3 tools/fill_template.py -i qwen2_ifb/tensorrt_llm/config.pbtxt \ triton_backend:tensorrtllm,triton_max_batch_size:8,decoupled_mode:False,\ max_beam_width:1,engine_dir:${ENGINE_PATH},max_tokens_in_paged_kv_cache:1280,\ max_attention_window_size:1280,kv_cache_free_gpu_mem_fraction:0.5,\ exclude_input_in_output:True,enable_kv_cache_reuse:False,\ batching_strategy:inflight_fused_batching,max_queue_delay_microseconds:0 mkdir -p ${MODEL_MOUNT_PATH}/tensorrtllm_backend mv /tensorrtllm_backend/qwen2_ifb ${MODEL_MOUNT_PATH}/tensorrtllm_backend echo "Triton 構成が完了しました。" fi env: - name: MODEL_MOUNT_PATH value: "/mnt/models" resources: requests: cpu: 2 memory: 10Gi nvidia.com/gpu: 1 limits: cpu: 12 memory: 30Gi nvidia.com/gpu: 1 --- # ステップ 3:キャッシュデータを事前読み込みします。 apiVersion: data.fluid.io/v1alpha1 kind: DataLoad metadata: name: step3-warmup-cache spec: runAfter: kind: DataProcess name: step2-trtllm-convert namespace: default dataset: name: qwen2-oss namespace: default loadMetadata: true target: - path: /Qwen2-1.5B-Instruct-engine - path: /tensorrtllm_backendこの Dataflow 構成により、生モデルの取得から本番運用可能な推論サービスの構成まで、エンドツーエンドのモデルデプロイメントプロセスが自動化されます。
-
-
Dataflow ワークフローのデプロイ
Dataflow 構成ファイルを適用し、自動化されたワークフローを作成します:
kubectl create -f dataflow.yaml正常終了時には、以下の出力が表示されます:
dataprocess.data.fluid.io/step1-download-model created dataprocess.data.fluid.io/step2-trtllm-convert created dataload.data.fluid.io/step3-warmup-cache createdこれにより、全 3 ステップのカスタムリソースが正常に作成されたことが確認できます。
-
実行進捗の監視
Dataflow の実行状態を追跡し、すべてのステップが完了するまで待ちます:
kubectl get dataprocess実行中の状態遷移例:
NAME DATASET PHASE AGE DURATION step1-download-model qwen2-oss Running 2m - step2-trtllm-convert qwen2-oss Pending 0s -完了時の出力例:
NAME DATASET PHASE AGE DURATION step1-download-model qwen2-oss Complete 23m 3m2s step2-trtllm-convert qwen2-oss Complete 20m 19m58s状態に関する補足:
Runningはステップが実行中であることを示します。Completeはステップが正常終了したことを示します。Pendingはそのステップが先行ステップの完了を待っていることを示します。
完全なモデル準備プロセスには通常 20~30 分かかります。実際の所要時間はネットワーク状況および GPU の性能に依存します。
ステップ 3:Triton 推論サービスのデプロイ
Arena を用いて、TensorRT-LLM で最適化された Qwen2 推論サービスをデプロイします。Triton Server は RESTful および gRPC インターフェイスを公開します。
-
Arena を用いたサービスのデプロイ
カスタム推論サービスをデプロイするコマンドを実行します:
主な構成に関する補足:
-
サービス名:
qwen2-chat、バージョン:v1 -
リソース割り当て:GPU 1 台、レプリカ 1 台
-
ポート構成:HTTP ポート 8000、gRPC ポート 8001、メトリックポート 8002
-
データマウント:
--dataフラグを用いて Fluid PVC を/mnt/modelsにマウント
arena serve custom \ --name=qwen2-chat \ --version=v1 \ --gpus=1 \ --replicas=1 \ --restful-port=8000 \ --readiness-probe-action="tcpSocket" \ --readiness-probe-action-option="port: 8000" \ --readiness-probe-option="initialDelaySeconds: 30" \ --readiness-probe-option="periodSeconds: 30" \ --image=kube-ai-registry.cn-shanghai.cr.aliyuncs.com/kube-ai/tritonserver:24.07-trtllm-python-py3 \ --data=qwen2-oss:/mnt/models \ "tritonserver \ --model-repository=/mnt/models/tensorrtllm_backend/qwen2_ifb \ --http-port=8000 \ --grpc-port=8001 \ --metrics-port=8002 \ --disable-auto-complete-config \ --backend-config=python,shm-region-prefix-name=prefix0_"正常にデプロイされた場合、以下の出力が表示されます:
service/qwen2-chat-v1 created deployment.apps/qwen2-chat-v1-custom-serving created INFO[0003] The Job qwen2-chat has been submitted successfully INFO[0003] You can run `arena serve get qwen2-chat --type custom-serving -n default` to check the job statusこれにより、推論サービスが Kubernetes クラスターに正常に送信されたことが確認できます。
-
-
サービス状態の確認
推論サービスの詳細および実行状態を確認します:
arena serve get qwen2-chatサービスが正常に実行中の場合、以下の出力が表示されます:
Name: qwen2-chat Namespace: default Type: Custom Version: v1 Desired: 1 Available: 1 Age: 2m Address: 192.168.10.15 Port: RESTFUL:8000 GPU: 1 Instances: NAME STATUS AGE READY RESTARTS GPU NODE ---- ------ --- ----- -------- --- ---- qwen2-chat-v1-custom-serving-657869c698-hl665 Running 2m 1/1 0 1 cn-hangzhou.192.168.10.15準備完了の指標:
Available: 1およびREADY: 1/1は、サービスが推論リクエストの受付に完全に準備できていることを意味します。
サービスの起動には通常 1~2 分かかります。初期化中には、Available フィールドの値が 0 から 1 に変化します。
ステップ 4:推論サービスのテスト
ローカルポートフォワーディングおよび API 呼び出しを用いて、推論サービスの機能およびパフォーマンスをテストします。
-
ポートフォワーディングの設定
サービスのテスト用にローカルポートフォワーディングチャネルを作成します:
ポートフォワーディングコマンドは現在のターミナルセッションで実行されます。Ctrl+C を押すと停止できます。
kubectl port-forward svc/qwen2-chat-v1 8000:8000正常終了時には、以下の出力が表示されます:
Forwarding from 127.0.0.1:8000 -> 8000 Forwarding from [::1]:8000 -> 8000これにより、
localhost:8000で推論サービスにアクセスできるようになります。 -
推論リクエストの送信
curl を用いてモデルに対して推論リクエストを送信します:
curl -X POST localhost:8000/v2/models/ensemble/generate \ -H "Content-Type: application/json" \ -d '{ "text_input": "機械学習とは何ですか?", "max_tokens": 50, "bad_words": "", "stop_words": "", "pad_id": 2, "end_id": 2 }'期待される応答例:
{ "context_logits": 0.0, "cum_log_probs": 0.0, "generation_logits": 0.0, "model_name": "ensemble", "model_version": "1", "output_log_probs": [0.0, 0.0, 0.0, 0.0], "sequence_end": false, "sequence_id": 0, "sequence_start": false, "text_output": " 機械学習とは、明示的にプログラミングすることなく、コンピューターシステムがデータからパターンやルールを学習する人工知能の手法です。アルゴリズムを用いて大量のデータを分析することで、機械学習モデルは複雑な関係性を特定し、予測や意思決定を行うことができます。" }成功の検証:
text_outputフィールドにモデルが生成した関連性のある回答が含まれている場合、推論サービスが正しく動作していることを確認できます。
テストに関するヒント:
-
モデルの汎化能力をテストするために、異なる質問を試してください
-
出力長を制御するため、
max_tokensパラメーターを調整してください -
応答時間および出力品質を観察してください
(任意)ステップ 5:環境のクリーンアップ
推論サービスが不要になった場合、以下の手順で関連リソースをクリーンアップします:
重要なお知らせ:クリーンアップ処理では、モデルデータおよびサービス構成を含むすべての関連リソースが削除されます。実行前に重要なデータをバックアップしてください。
-
推論サービスの削除
Arena を用いてデプロイ済みのサービスを削除します:
arena serve delete qwen2-chat削除が成功したことを確認します:
INFO[0001] Deleting service: qwen2-chat INFO[0002] Service qwen2-chat deleted successfully -
Fluid リソースのクリーンアップ
Dataset および JindoRuntime リソースを削除します:
kubectl delete dataset qwen2-oss kubectl delete jindoruntime qwen2-oss -
アクセス認証情報の削除
OSS アクセスキーをクリーンアップします:
kubectl delete secret fluid-oss-secret
クリーンアップ後、以下のコマンドですべてのリソースが削除されたことを確認できます:kubectl get all -l app=qwen2-chat