对话式人工智能

利用 NVIDIA Triton 和 NVIDIA TensorRT-LLM 及 Kubernetes 实现 LLM 扩展

大语言模型 (LLMs) 已广泛应用于聊天机器人、内容生成、摘要、分类、翻译等领域。State-of-the-art LLMs 和基础模型如  Llama , Gemma , GPT Nemotron ,已经展示了类似人类的理解能力和生成能力。借助这些模型,AI 开发者无需从头开始经历昂贵且耗时的训练过程。

可应用 检索增强生成(RAG)、prompt running 和 fine-tuning 等技术来定制基础模型,并在更短的时间内针对特定任务实现更高的准确性,定制化模型可在生产环境中快速部署,满足各种用例的推理请求。

本文分步介绍了如何使用 NVIDIA TensorRT-LLM 优化 Large Language Models、如何使用 NVIDIA Triton Inference Server 部署优化模型,以及如何在 Kubernetes 环境中自动扩展 Large Language Models 部署。

NVIDIA TensorRT-LLM 是一款易于使用的 Python API,可用于定义和优化 LLM。NVIDIA Triton 推理服务器是一款开源推理服务软件,支持多个框架和硬件平台。TensorRT-LLM 提供多种优化,如 kernel fusion、quantization、in-flight batch 和 paged attention,因此可以在 NVIDIA GPUs 上高效执行使用优化模型的推理。

Triton 推理服务器支持多种深度学习和机器学习框架,包括 NVIDIA TensorRT 、TensorFlow、PyTorch 和 ONNX。它支持多种查询类型,包括实时、批处理、ensemble 或流式传输。它可以在 NVIDIA GPU、x86 和 ARM CPU 上的云、数据中心、边缘和嵌入式设备上运行。作为开发者,您可以先构建包含模型优化的 TensorRT 引擎,然后在生产环境中使用 Triton 部署优化的模型。

您可以使用 Kubernetes 将经过优化的大语言模型(LLMs)的部署从单个 GPU 扩展到多个 GPU,以低延迟、高准确度处理数千个实时推理请求,并在推理请求数量减少时缩减 GPU 数量。这对于在线购物和呼叫中心等企业特别有用,因为它们可以在高峰和非高峰时段灵活处理不同数量的推理请求,同时受益于总成本的降低,而不是购买数量最多的硬件资源来处理峰值工作负载。

Prometheus 将 Triton metrics 抓取并将其发送到 Horizontal Pod Autoscaler (HPA),以便根据推理请求的数量决定是否增加或减少部署和 GPUs 的数量。要查看此优化和部署的代码和步骤,请访问 GitHub 上的 triton-inference-server/tutorials

硬件和软件要求 

要优化和部署模型,您需要拥有支持 TensorRT-LLM 和 Triton 推理服务器的 NVIDIA GPU。建议使用新一代 NVIDIA GPU。你可以在 TensorRT-LLM 支持矩阵 的硬件部分找到受支持的 GPU 列表。你还可以使用适当的 GPU 资源(例如 AWS EKS Azure AKS GCP GKE OCI OKE )在公有云计算实例上部署模型。

Kubernetes 可用于自动扩展您的部署,以处理低延迟的大规模实时推理请求。要使 Kubernetes 能够发现哪些节点具有 GPU,并将其提供给在这些节点上运行的容器,请安装 Kubernetes node feature discovery serviceNVIDIA device plugin for KubernetesGPU Feature Discovery service NVIDIA DCGM Exporter 。你还需要安装 Prometheus ,以收集用于自动扩展的指标。请参阅详细安装步骤。

使用 TensorRT-LLM 优化 LLM 

TensorRT-LLM 支持各种 state-of-the-art 模型 。您可以从 Hugging Face 下载模型检查点 ,然后使用 TensorRT-LLM 构建包含模型优化的引擎。要下载 LLM,您需要 访问令牌 。然后,您可以使用访问令牌创建 Kubernetes Secret ,该令牌将在后续的 Kubernetes Deployment 步骤中用于下载模型。

$ kubectl create secret generic hf-model-pull '--from-literal=password=<HF_access_token>'

如需详细了解 TensorRT-LLM 的工作原理,请探索 示例 ,了解如何通过优化构建热门模型的引擎以获得更好的性能,例如添加 gpt_attention_plugin, paged_kv_cache, gemm_plugin, quantization

要生成 TensorRT 引擎文件,您可以使用 NVIDIA GPU Cloud (NGC) 上提供的具有 TensorRT-LLM 的 Triton 推理服务器的 Docker 容器镜像。要从 NGC 拉取容器镜像,您需要在 NGC 上生成 API 密钥 ,以便访问 NGC 容器。然后,使用 API 密钥登录 NGC,拉取容器镜像。

使用 TensorRT-LLM 提取 Triton 的 NGC 镜像(例如,基础镜像 nvcr.io/nvidia/tritonserver:24.08-trtllm-python-py3)后,可参考 模型准备步骤 生成 TensorRT-LLM 引擎文件。您可以根据模型大小和 GPU 显存大小配置 TP 张量并行(TP)和 pipeline 并行(PP)。请注意,生成引擎文件时,您需要最低数量的 GPU,TP*PP。

按照“Custom Container Image”步骤 和脚本创建自定义 Triton-TensorRT-LLM 镜像。构建自定义镜像后,您可以将其推送到集群可以访问的存储库。要在部署期间从私有注册表中拉取此自定义镜像,您需要使用 API 密钥创建 Kubernetes docker-registry 密钥 ,并让 Kubernetes 使用此密钥从私有注册表中拉取镜像。

在部署期间,生成的 TensorRT 引擎和计划文件存储在主机节点中,并重新映射到同一节点上的所有 Kubernetes Pod。如果以后扩展更多的 Pod,则无需生成相同的文件。

使用 Kubernetes 自动扩展 LLM 部署 

使用 TensorRT-LLM 优化您的 LLM 后,您可以使用 Triton 部署模型,并使用 Kubernetes 自动扩展部署。部署用于 AI 推理的 LLM 需要三个主要步骤:

  • 为 Triton 服务器创建 Kubernetes 部署
  • 创建 Kubernetes Service 以将 Triton 服务器作为网络服务公开
  • 使用基于 Prometheus 提取的 Triton 指标的水平 Pod 自动扩展器 (HPA) 自动扩展开部署。

用于 LLM 部署的 Helm 图表 

您可以使用 Helm 图表进行部署,因为 Helm 图表易于修改和在不同环境中部署。要查找 Helm 图表,请参阅 使用 Triton 服务器和 TensorRT-LLM 自动扩展和负载平衡生成式 AI 。在 图表目录 中,Helm 预期文件如下:

chart.yaml 包含您要打包的图表的所有信息;例如,版本号和名称。

values.yaml 定义要注入模板目录的所有值,包括支持的 GPUs、LLMs、Triton 的容器镜像、image pull secrets 等。您可以创建特定于模型、自定义图像和 GPU 类型的自定义值文件,以覆盖 values.yaml。以下示例是 gpt2_values.yaml,用于在 NVIDIA A10G GPU 上部署 GPT-2 模型。

gpu:
- NVIDIA-A10G

model:
  name: gpt2
  tensorrtLlm:
    parallelism:
      tensor: 1

triton:
  image:
    pullSecrets:
    -name: ngc-container-pull
    name: <your custom image>

如果您有一个不适合单个 GPU 的更大模型,则可以根据模型和 GPU 大小配置 TP。例如,您可以为需要两个 GPU 的模型设置 model.tensorrtLlm.parallelism.tensor 为 2,并且每个 Kubernetes Pod 在部署中有两个 GPU。

创建 Kubernetes 部署

Kubernetes 部署 Kubernetes Pod ReplicaSets 提供声明性更新。 deployment.yaml 为 Triton 服务器创建了一组已复制的 Pod。你可以指定要使用的 Pod 数量,如 .spec.replicas 字段所示。

.spec.containers 字段告知每个 Kubernetes Pod 在 GPU 上运行一个 Triton 服务器容器。为 Triton 服务器分别指定了端口号 8000 和 8001,用于接收来自客户端的 HPPP 和 GRPC 推理请求。端口 8002 用于收集 Triton 指标 。你可以更改 .resources.ephemeral-storage 字段,以适应模型的大小;例如,GPT-2 模型可容纳 24 GB 的 NVIDIA A10G GPU 内存。

apiVersion: apps/v1
kind: Deployment
metadata:
  […]
spec:
  selector:
  […]
  replicas: 1
  template:
    metadata:
      labels:
        app: {{ $.Release.Name }}
        app.kubernetes.io/component: server
……
spec:
      […]
      containers:
        - name: triton
          [...]
          image: {{ $image_name }}
          imagePullPolicy: IfNotPresent
          [...]
          ports:
          - containerPort: 8000
            name: http
          - containerPort: 8001
            name: grpc
          - containerPort: 8002
            name: metrics

创建 Kubernetes 服务 

Kubernetes Service 是将在一组 Pod 上运行的应用程序公开为网络服务的抽象方式。 service.yaml 将 Triton 服务器公开为网络服务,因此服务器可以随时接收来自客户端的推理请求。

apiVersion: v1
kind: Service
metadata:
  name: {{ $.Release.Name }}
  labels:
    app: {{ $.Release.Name }}
    app.kubernetes.io/component: service
……
spec:
  ports:
  - name: http
    port: 8000
    targetPort: http
  - name: grpc
    port: 8001
    targetPort: grpc
  - name: metrics
    port: 8002
    targetPort: metrics
  selector:
    app: {{ $.Release.Name }}
  type: ClusterIP

自动扩展 LLM 部署 

要自动扩展应用程序,您需要通过检查容器、Pod 和服务来监控应用程序的性能。您可以使用 PodMonitor 或 ServiceMonitor 监控 Kubernetes Pod 或服务,以实现 Prometheus 的目标发现。Kube-Prometheus 可以帮助部署 Prometheus 并将 Prometheus 链接到指标端点。您可以使用 PodMonitor 和 Kube-Prometheus 向 Prometheus 公开 NVIDIA Triton 指标。

On the left, kube-prometheus set up the collection targets for Prometheus and link Prometheus to metrics endpoints. In the middle, Prometheus scrapes the Triton metrics from Pods at port number 8002. On the right, four Triton servers running on four GPUs.
图 1. 具有四个复制 Pod 的 Kubernetes 部署示例,每个 Pod 均在 GPU 上运行 Triton 服务器

下方的 pod-monitor.yaml 文件使用 PodMonitor 来监控 Pod,每个 Pod 都有一个 Triton 服务器:

apiVersion: monitoring.coreos.com/v1
kind: PodMonitor
metadata:
  name: {{ $.Release.Name }}
  labels:
    app: {{ $.Release.Name }}
    app.kubernetes.io/component: autoscaler
    release: prometheus
……
spec:
  selector:
    matchLabels:
      app: {{ $.Release.Name }}
      app.kubernetes.io/component: server
  podMetricsEndpoints:
  - port: metrics
    path: /metrics

Prometheus 可以从端口号为 8002 的所有 Kubernetes Pod 中抓取 Triton 指标 。您可以为 HPA 选择一个 Triton,或者根据需要使用收集的指标定义新的自定义指标。Prometheus 适配器可以与 Kubernetes 和 Prometheus 通信,充当两者之间的翻译器。在 Prometheus 适配器的帮助下,HPA 可以使用选定的指标根据推理请求的数量自动扩展 Kubernetes Pod 的副本数量。

在此应用中 我们使用名为 queue-to-compute ratio 的自定义指标作为 HPA 的指标。queue-to-compute ratio 反映推理请求的响应时间。它定义为队列时间除以 triton-metrics_prometheus-rule.yaml 中推理请求的计算时间。

apiVersion: monitoring.coreos.com/v1
kind: PrometheusRule
metadata:
  name: triton-metrics
  labels:
    app.kubernetes.io/component: autoscaler
    release: prometheus
spec:
  groups:
  - name: autoscaling
    interval: 6s
    rules:
    # Average percentage of time inference requests spend in queue (not including cache hits).
    - expr: rate(nv_inference_queue_duration_us[1m])/clamp_min(rate(nv_inference_compute_infer_duration_us[1m]),1)
      record: triton:queue_compute:ratio

Prometheus 在 6 秒的时间间隔内抓取 Triton 指标,并使用 Triton 指标志计算自定义指标的值。然后,HPA 根据自定义指标的值上下扩展副本数量。

下方的 hpa.yaml 指定了要部署的最大和最小副本数量;例如,最多 4 个 Pod 和至少 1 个 Pod。使用 Podsmetrics-type 取所有 Pod 中队列与计算之比的平均值。平均队列与计算之比高于所需值 1,000(毫单位),意味着队列时间更长,或者副本数量不足以快速响应推理请求。在这种情况下,HPA 应增加副本数量,以降低队列与计算之比,直到自定义指标低于所需值;如果推理请求量减少,则反之亦然。可以根据您的要求将此目标值设置为任意数量。

{{- $metric_name := "triton:queue_compute:ratio" }}
{{- $metric_value := "1000m" }}
{{- $replicasMax := 4 }}
{{- $replicasMin := 1 }}
……
apiVersion: autoscaling/v2
kind: HorizontalPodAutoscaler
metadata:
  name: {{ $.Release.Name }}
  labels:
    app: {{ $.Release.Name }}
    app.kubernetes.io/component: autoscaler
    release: prometheus
……
spec:
  maxReplicas: {{ $replicasMax }}
  minReplicas: {{ $replicasMin }}
  metrics:
  - type: Pods
    pods:
      metric:
        name: {{ $metric_name }}
      target:
        type: AverageValue
        averageValue: {{ $metric_value }}
  scaleTargetRef:
    apiVersion: apps/v1
    kind: Deployment
    name: {{ $.Release.Name }}

配置好 Kubernetes Deployment、Service、PodMonitor 和 HPA 的 .yaml 文件后,您可以使用以下命令使用 Triton 服务器和 Kubernetes 部署模型:

$ helm install gpt2 --values ./chart/values.yaml    --values ./chart/gpt2_values.yaml   --set 'triton.image.name=<your custom image>' ./chart/.
NAME: gpt2
LAST DEPLOYED: Mon Aug 26 23:04:42 2024
NAMESPACE: default
STATUS: deployed
REVISION: 1
TEST SUITE: None
NOTES:
triton_trt-llm_aslb-example (0.1.0) installation complete.

Release Name: gpt2
Namespace: default
Deployment Name: gpt2
Service Name: gpt2

验证 所有 内容 是否 均按 预期 工作 应该能够看到输出信息,例如 Pod 的 NAMEREADYSTATUS;Service 的 NAMETYPEPORTS;HPA 的 NAMEMINPODSMAXPODSREPLICAS 等。

$ kubectl get deployments,pods,hpa,services,podmonitors --selector='app=gpt2'
NAME                   READY   UP-TO-DATE   AVAILABLE   AGE
deployment.apps/gpt2   1/1     1            1           11m

NAME                        READY   STATUS    RESTARTS   AGE
pod/gpt2-85cfd5b6d5-4v87s   1/1     Running   0          11m

NAME                                       REFERENCE         TARGETS   MINPODS   MAXPODS   REPLICAS   AGE
horizontalpodautoscaler.autoscaling/gpt2   Deployment/gpt2   0/1       1         4         1          11m

NAME           TYPE        CLUSTER-IP      EXTERNAL-IP   PORT(S)                      AGE
service/gpt2   ClusterIP   10.100.56.211   <none>        8000/TCP,8001/TCP,8002/TCP   11m

NAME                                    AGE
podmonitor.monitoring.coreos.com/gpt2   11m

例如,如果 Pod 的状态未成功运行(状态显示为 Init:CrashLoopBackOffImagePullBackOff),您可以尝试使用以下命令来调试该问题。失败的潜在原因可能是模型或自定义镜像未成功下载、Kubernetes secrets 无法正常工作、内存不足等。

$ kubectl describe pod <pod name>
$ kubectl logs <pod name> -c init 
$ kubectl logs <pod name> -c init --previous

负载均衡器 

您还需要一个负载均衡器,以便在所有正在运行的 Pod 中分配工作负载。负载均衡器主要有两种类型:Layer 4 和 Layer 7。Layer 4 负载均衡在传输级别运行,并根据网络信息来管理流量,而 Layer 7 负载均衡在应用程序级别运行,并使用协议根据每个消息的内容做出决策。

您可以使用第三方负载均衡器,例如 Traefik ingress 控制器和负载均衡器 , 或 NGINX Plus ,都属于第 7 层。有关如何部署 Traefik 和 NGINX Plus 的更多信息,请参阅。如果您使用的是云服务,您还可以使用云负载均衡器。例如, AWS 负载均衡器控制器 可以同时配置应用程序和 网络负载均衡器 。安装控制器后,如果服务具有 loadBalancer 类型,您可以要求云控制器配置网络负载均衡器,如果您创建 Kubernetes ingress,您可以要求 应用程序负载均衡器

发送测试推理请求 

最后,您可以通过从客户端发送推理请求来测试 Triton 服务器。我们提供了一个 示例客户端 文件夹,您可以从中构建客户端容器镜像:

$ docker build -f ./containers/client.containerfile -t <name> ./containers/.

接下来,将客户端文件夹中的 .yaml 文件修改为您构建的客户端容器镜像的名称。使用以下命令创建具有一个副本的客户端部署:

 $ kubectl apply -f ./clients/gpt2.yaml
 deployment.apps/client-gpt2 created

让客户端通过更改客户端的副本数量来增加或减少推理请求量,并检查 Pod:

$ kubectl scale deployment/client-gpt2   --replicas=10
deployment.apps/client-gpt2 scaled

$ kubectl get pods
NAME                                READY   STATUS    RESTARTS   AGE
client-gpt2-cb4bf7b74-6g82l   1/1     Running   0          16s
client-gpt2-cb4bf7b74-6lt8x   1/1     Running   0          16s
client-gpt2-cb4bf7b74-6nnvn   1/1     Running   0          16s
client-gpt2-cb4bf7b74-b7s88   1/1     Running   0          16s
client-gpt2-cb4bf7b74-fl5c6   1/1     Running   0          36s
client-gpt2-cb4bf7b74-j88ld   1/1     Running   0          16s
client-gpt2-cb4bf7b74-jdmkm   1/1     Running   0          16s
client-gpt2-cb4bf7b74-lqptv   1/1     Running   0          16s
client-gpt2-cb4bf7b74-m66cx   1/1     Running   0          16s
client-gpt2-cb4bf7b74-nt7b7   1/1     Running   0          16s
gpt2-85cfd5b6d5-65ftt         1/1     Running   0          7m57s

您可以看到运行的客户端有 10 个,这显著增加了推理请求的数量。这将增加自定义指标的值,从而导致 HPA 增加使用 GPT-2 模型的 Triton 服务器的副本数量。

$ kubectl get pods
NAME                             READY   STATUS    RESTARTS   AGE
client-gpt2-cb4bf7b74-6g82l   1/1     Running   0          56s
client-gpt2-cb4bf7b74-6lt8x   1/1     Running   0          56s
client-gpt2-cb4bf7b74-6nnvn   1/1     Running   0          56s
client-gpt2-cb4bf7b74-b7s88   1/1     Running   0          56s
client-gpt2-cb4bf7b74-fl5c6   1/1     Running   0          76s
client-gpt2-cb4bf7b74-j88ld   1/1     Running   0          56s
client-gpt2-cb4bf7b74-jdmkm   1/1     Running   0          56s
client-gpt2-cb4bf7b74-lqptv   1/1     Running   0          56s
client-gpt2-cb4bf7b74-m66cx   1/1     Running   0          56s
client-gpt2-cb4bf7b74-nt7b7   1/1     Running   0          56s
gpt2-85cfd5b6d5-65ftt         1/1     Running   0          8m37s
gpt2-85cfd5b6d5-65wg4         1/1     Running   0          22s
gpt2-85cfd5b6d5-kh9j4         1/1     Running   0          22s
gpt2-85cfd5b6d5-pdg5m         1/1     Running   0          22s

同样,如果您减少推理请求的数量(例如,将客户端数量减少到一个副本),HPA 会在几分钟后相应地将 Triton 服务器的数量减少到一个副本:

$ kubectl get pods
NAME                            READY   STATUS    RESTARTS   AGE
client-gpt2-cb4bf7b74-6g82l   1/1     Running   0          11m
gpt2-85cfd5b6d5-65ftt         1/1     Running   0          19m

您还可以使用 Grafana 查询 NVIDIA Triton 指标和自定义指标,通过导航至其 metrics 端点 localhost:8080,按时间序列可视化结果。

图 2 显示了反映这一变化的 GPU 利用率和 Queue:Compute Ratio。开始时,一个 GPU 上只运行一个 Triton 服务器副本。因此,GPU 利用率(orange 线)和 Queue:Compute Ratio 有所增加,而推理请求因客户端数量而显著增加。

为了减少 自定义指标,HPA 将 Triton 服务器的数量增加到在四个 GPU 上运行的四个副本,如 GPU 利用率 中的四行所示,这有效降低了 Queue:Compute Ratio。最终,推理请求量减少到一个客户端,因此 GPU 利用率相应降低。

Screenshot of graphic user interface for Grafana showing the metric in time series.
图 2.Grafana 图形用户界面,显示基于客户端查询的时间序列指标

开始使用 

本文提供了在 Kubernetes 环境中部署 Large Language Models 和自动扩展部署的分步说明。Large Language Models 可以使用 NVIDIA TensorRT-LLM 进行优化,然后使用 NVIDIA Triton 推理服务器进行部署。Prometheus 收集 Triton 指标并与 Kubernetes 通信。HPA 可以使用自定义指标自动扩展 Pod 数量,具体取决于客户端的推理请求数量。

准备好开始使用了吗?请访问 GitHub 上的 triton-inference-server/tutorials 。学习更多关于使用 TensorRT-LLM 的 Triton。如果您想制作自己的自定义镜像,可以从 NGC 中提取 Docker 容器。

 

标签