本文以Qwen2-1.5B-Instruct模型、GPU类型为A10卡为例,演示如何在ACK中使用Triton推理服务 + TensorRT-LLM部署通义千问模型推理服务。模型部署过程中使用Fluid Dataflow完成模型准备工作,并使用Fluid提升模型加载速度。
背景信息
Qwen2-1.5B-Instruct
Qwen2-1.5B-Instruct是基于Transformer的大语言模型,在超大规模的预训练数据上进行训练得到的15亿参数规模的模型。预训练数据类型多样,覆盖广泛,包括大量网络文本、专业书籍、代码等。
更多模型信息,请参见Qwen2 Github代码库。
Triton(Triton Inference Server)
Triton Inference Server是NVIDIA开源的推理服务框架,可以帮助您快速搭建AI推理应用。Triton支持多种不同的机器学习框架作为它的运行时后端,包括TensorRT、TensorFlow、PyTorch、ONNX、vLLM等。Triton面向实时推理、批量推理以及音视频流式推理场景进行了许多优化,以在推理时获得更好的性能。
更多关于Triton推理服务框架的信息,请参见Triton Inference Server GitHub代码库。
TensorRT-LLM
TensorRT-LLM 是NVIDIA开源的LLM(Large Language Model)模型优化引擎,用于定义LLM模型并将模型构建为TensorRT引擎,以提升服务在NVIDIA GPU上的推理效率。TensorRT-LLM还可以与Triton框架结合,作为Triton推理框架的一种后端TensorRT-LLM Backend。TensorRT-LLM构建的模型可以在单个或多个GPU上运行,支持Tensor Parallelism及Pipeline Parallelism。
更多关于TensorRT-LLM的信息,请参见TensorRT-LLM Github代码库。
前提条件
已创建包含A10卡GPU的ACK集群Pro版,且集群版本为1.22及以上。具体操作,请参见创建ACK托管集群。
建议GPU节点使用525版本驱动,您可以通过为GPU节点池添加标签
ack.aliyun.com/nvidia-driver-version:525.105.17
指定驱动版本为525.105.17。具体操作,请参见通过指定版本号自定义节点GPU驱动版本。已安装云原生AI套件并部署ack-fluid组件。
重要若您已安装开源Fluid,请卸载后再部署ack-fluid组件。
已安装最新版Arena客户端。具体操作,请参见配置Arena客户端。
步骤一:创建Dataset和JindoRuntime
Dataset可以高效地组织和处理数据,而集成JindoRuntime可以通过数据缓存策略进一步加速数据访问,两者结合可以大幅提升数据处理和模型服务的性能。
执行以下命令,创建用于存储OSS的访问凭证的Secret。
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
其中,
fs.oss.accessKeyId
和fs.oss.accessKeySecret
是用来访问OSS的AccessKey ID(AK)和AccessKey Secret(SK)。关于如何获取AK和SK,请参见获取AccessKey。预期输出:
secret/fluid-oss-secret created
创建并拷贝以下内容到dataset.yaml文件中,用于创建一个Dataset和一个JindoRuntime来提供缓存服务。关于Dataset及JindoRuntime的详细配置信息,请参见JindoFS加速OSS文件访问。
# 创建一个Dataset,描述远端存储数据集和UFS的信息。 apiVersion: data.fluid.io/v1alpha1 kind: Dataset metadata: name: qwen2-oss spec: mounts: - mountPoint: oss://<oss_bucket>/qwen2-1.5b # 请替换为实际的模型存储地址。 name: qwen2 path: / options: fs.oss.endpoint: <oss_endpoint> # 请替换为实际的OSS endpoint地址。 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,启动一个JindoFS的集群来提供缓存服务。 --- 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" # 8M fs.oss.download.thread.concurrency: "200" fs.oss.read.readahead.max.buffer.count: "200" fs.oss.read.sequence.ambiguity.range: "2147483647" args: - -oauto_cache - -oattr_timeout=1 - -oentry_timeout=1 - -onegative_timeout=1
执行以下命令,创建JindoRuntime和Dataset。
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
步骤二:创建Dataflow
要使用TensorRT-LLM加速模型推理,首先需要下载模型文件,然后进行模型文件格式转换,构建TensorRT Engine,修改配置文件等操作。本文通过使用Fluid Dataflow完成上述步骤。
创建并拷贝以下内容到dataflow.yaml文件中,用于创建一个Dataflow,包含以下三个步骤:
从ModelScope下载Qwen2-1.5B-Instruct模型。
使用TensorRT-LLM工具完成模型格式转换,构建Engine。
使用Dataload更新Dataset数据。
# 从ModelScope平台下载Qwen2-1.5B-Instruct模型到指定的存储路径。 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 imageTag: ubuntu22.04 imagePullPolicy: IfNotPresent restartPolicy: OnFailure command: - bash source: | #!/bin/bash echo "download model..." if [ -d "${MODEL_MOUNT_PATH}/Qwen2-1.5B-Instruct" ]; then echo "directory ${MODEL_MOUNT_PATH}/Qwen2-1.5B-Instruct exists, skip download model" else 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} fi env: - name: MODEL_MOUNT_PATH value: "/mnt/models" # 将下载的模型转换为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 imageTag: 24.07-trtllm-python-py3 imagePullPolicy: IfNotPresent restartPolicy: OnFailure command: - bash source: | #!/bin/bash set -ex cd /tensorrtllm_backend/tensorrt_llm/examples/qwen if [ -d "${MODEL_MOUNT_PATH}/Qwen2-1.5B-Instruct-ckpt" ]; then echo "directory ${MODEL_MOUNT_PATH}/Qwen2-1.5B-Instruct-ckpt exists, skip convert checkpoint" else echo "covert checkpoint..." python3 convert_checkpoint.py --model_dir ${MODEL_MOUNT_PATH}/Qwen2-1.5B-Instruct --output_dir /root/Qwen2-1.5B-Instruct-ckpt --dtype float16 echo "Writing trtllm model ckpt to OSS Bucket..." mv /root/Qwen2-1.5B-Instruct-ckpt ${MODEL_MOUNT_PATH} fi sleep 2 if [ -d "${MODEL_MOUNT_PATH}/Qwen2-1.5B-Instruct-engine" ]; then echo "directory $OUTPUT_DIR/Qwen2-1.5B-Instruct-engine exists, skip build engine" else echo "build trtllm engine..." 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 echo "Writing trtllm engine to OSS Bucket..." mv /root/Qwen2-1.5B-Instruct-engine ${MODEL_MOUNT_PATH} fi if [ -d "${MODEL_MOUNT_PATH}/tensorrtllm_backend" ]; then echo "directory $OUTPUT_DIR/tensorrtllm_backend exists, skip config tensorrtllm_backend" else echo "config model..." 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 echo "Writing trtllm config to OSS Bucket..." mkdir -p ${MODEL_MOUNT_PATH}/tensorrtllm_backend mv /tensorrtllm_backend/qwen2_ifb ${MODEL_MOUNT_PATH}/tensorrtllm_backend 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 # 加载转换并优化后的模型及配置到内存中,以实现快速响应的推理服务。 --- apiVersion: data.fluid.io/v1alpha1 kind: DataLoad metadata: name: step3-warmup-cahce 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。
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-cahce created
输出结果表明已成功地根据
dataflow.yaml
文件中的定义创建了相应的自定义资源对象。执行以下命令,查看Dataflow执行情况,等待任务执行完成。
kubectl get dataprocess
预期输出:
NAME DATASET PHASE AGE DURATION step1-download-model qwen2-oss Complete 23m 3m2s step2-trtllm-convert qwen2-oss Complete 23m 19m58s
输出结果表明集群中与数据集
qwen2-oss
相关的两个数据处理任务(下载模型和转换模型至trtllm
格式)都已经成功完成。
步骤三:部署推理服务
执行以下命令,通过Arena命令部署一个Custom类型的Serve服务。
该服务名称为qwen2-chat,version为v1,需要使用一个GPU,副本数为1,并且配置了就绪检测。模型是一种特殊类型的数据,因此采用
--data
参数将Fluid创建的模型PVCqwen2-oss
挂载到了容器中的/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_"
参数说明如下:
参数
说明
--name
指定推理服务名称。
--version
指定推理服务版本。
--gpus
指定单个推理服务副本需要使用的GPU卡数。
--replicas
指定推理服务副本数。
--restful-port
指定推理服务对外暴露的端口。
--readiness-probe-action
指定就绪探针连接类型,支持HttpGet、Exec、gRPC、TCPSocket。
--readiness-probe-action-option
指定就绪探针连接方式。
--readiness-probe-option
指定就绪探针配置。
--data
挂载共享存储卷PVC到运行环境中。它由两部分组成,通过英文冒号(:)分割。冒号左侧是您已经准备好的PVC名称。您可以通过命令
arena data list
查看当前集群可用的PVC列表;冒号右侧是您想将PVC挂载到运行环境中的路径,也是您训练代码要读取数据或模型的本地路径。这样通过挂载的方式,您的代码就可以访问PVC中的数据或模型。--image
指定推理服务的镜像地址。
预期输出:
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
输出结果表明推理服务已成功部署。
执行下列命令,查看推理服务详细信息,等待服务就绪。
arena serve get qwen2-chat
预期输出:
Name: qwen2-chat Namespace: default Type: Custom Version: v1 Desired: 1 Available: 1 Age: 1m Address: 192.XX.XX.XX Port: RESTFUL:8000 GPU: 1 Instances: NAME STATUS AGE READY RESTARTS GPU NODE ---- ------ --- ----- -------- --- ---- qwen2-chat-v1-custom-serving-657869c698-hl665 Running 1m 1/1 0 1 ap-southeast-1.192.XX.XX.XX
输出结果表明该推理服务的一个Pod(qwen2-chat-v1-custom-serving-657869c698-hl665)正在稳定运行,且已准备好提供服务。
步骤四:验证推理服务
执行以下命令,在推理服务与本地环境之间建立端口转发。
重要请注意kubectl port-forward建立的端口转发不具备生产级别的可靠性、安全性和扩展性,因此仅适用于开发和调试目的,不适合在生产环境使用。更多关于Kubernetes集群内生产可用的网络方案的信息,请参见Ingress概述。
kubectl port-forward svc/qwen2-chat-v1 8000:8000
预期输出:
Forwarding from 127.0.0.1:8000 -> 8000 Forwarding from [::1]:8000 -> 8000
执行以下命令,发送模型推理请求。
curl -X POST localhost:8000/v2/models/ensemble/generate -d '{"text_input": "什么是机器学习?", "max_tokens": 20, "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":" 机器学习是一种人工智能技术,它使计算机系统能够从数据中学习,而无需明确的编程。"}
输出结果表明模型可以根据给定的输入生成相应的回复。
(可选)步骤五:清理环境
如果不再使用已部署的模型推理服务,请执行以下命令,删除服务。
arena serve delete qwen2-chat