优化AI生命周期:k8s下大模型部署的新选择!

共 29605字,需浏览 60分钟

 ·

2024-04-11 03:13





前言

AI 商业化的时代,大模型推理训练会被更加广泛的使用。比较理性的看待大模型的话,一个大模型被训练出来后,无外乎两个结果,第一个就是这个大模型没用,那就没有后续了;另一个结果就是发现这个模型很有用,那么就会全世界的使用,这时候主要的使用都来自于推理,不论是 openAI 还是 midjourney,用户都是在为每一次推理行为付费。随着时间的推移,模型训练和模型推理的使用比重会是三七开,甚至二八开。应该说模型推理会是未来的主要战场。

大模型推理是一个巨大的挑战,它的挑战体现在成本、性能和效率。其中成本最重要,因为大模型的成本挑战在于模型规模越来越大,使用的资源越来越多,而模型的运行平台 GPU 由于其稀缺性,价格很昂贵,这就导致每次模型推理的成本越来越高。而最终用户只为价值买单,而不会为推理成本买单,因此降低单位推理的成本是基础设施团队的首要任务。

在此基础上,性能是核心竞争力,特别是 ToC 领域的大模型,更快的推理和推理效果都是增加用户粘性的关键。

应该说大模型的商业化是一个不确定性较高的领域,成本和性能可以保障你始终在牌桌上。效率是能够保障你能在牌桌上赢牌。

进一步,效率。模型是需要持续更新,这就模型多久可以更新一次,更新一次要花多久的时间。谁的工程效率越高,谁就有机会迭代出有更有价值的模型。

ee4325ff0b882347ca83c66137c59fdd.webpimg

近年来,容器和 Kubernetes 已经成为越来越多 AI 应用首选的运行环境和平台。一方面,Kubernetes 帮助用户标准化异构资源和运行时环境、简化运维流程;另一方面,AI 这种重度依赖 GPU 的场景可以利用 K8s 的弹性优势节省资源成本。在 AIGC/大模型的这波浪潮下,以 Kubernetes 上运行 AI 应用将变成一种事实标准。

--- 节选自《云原生场景下,AIGC 模型服务的工程挑战和应对》

大模型训练和推理

大模型训练和推理是机器学习和深度学习领域的重要应用,但企业和个人往往面临着GPU管理复杂、资源利用率低,以及AI作业全生命周期管理中工程效率低下等挑战。本方案通过创建kubernetes集群,使用kserve+vLLM部署推理服务。适用于机器学习和深度学习任务中的以下场景:

2d905114cb3ab43be63d48e96cdfadbf.webp

  • • 模型训练:基于Kubernetes集群微调开源模型,可以屏蔽底层资源和环境的复杂度,快速配置训练数据、提交训练任务,并自动运行和保存训练结果。

  • • 模型推理:基于Kubernetes集群部署推理服务,可以屏蔽底层资源和环境的复杂度,快速将微调后的模型部署成推理服务,将模型应用到实际业务场景中。

  • • GPU共享推理:支持GPU共享调度能力和显存隔离能力,可将多个推理服务部署在同一块GPU卡上,提高GPU的利用率的同时也能保证推理服务的稳定运行。

VLLM介绍

即使在高端 GPU 上,提供 LLM 模型的速度也可能出奇地慢,vLLM[1]是一种快速且易于使用的 LLM 推理引擎。它可以实现比 Huggingface 变压器高 10 倍至 20 倍的吞吐量。它支持连续批处理[2]以提高吞吐量和 GPU 利用率, vLLM支持分页注意力[3]以解决内存瓶颈,在自回归解码过程中,所有注意力键值张量(KV 缓存)都保留在 GPU 内存中以生成下一个令牌。

vLLM 是一个快速且易于使用的 LLM 推理和服务库。

vLLM 的速度很快:

  • • 最先进的服务吞吐量

  • • 使用PagedAttention高效管理注意力键和值内存

  • • 连续批处理传入请求

  • • 使用 CUDA/HIP 图快速执行模型

  • • 量化:GPTQ[4]AWQ[5]SqueezeLLM[6]、FP8 KV 缓存

  • • 优化的 CUDA 内核

vLLM 灵活且易于使用:

  • • 与流行的 HuggingFace 模型无缝集成

  • • 高吞吐量服务与各种解码算法,包括并行采样波束搜索

  • • 对分布式推理的张量并行支持

  • • 流输出

  • • 兼容 OpenAI 的 API 服务器

  • • 支持 NVIDIA GPU 和 AMD GPU

  • • (实验性)前缀缓存支持

  • • (实验性)多lora支持

kserve介绍

KServe是一个针对 Kubernetes 的自定义资源,用于为任意框架提供机器学习(ML)模型服务。它旨在为常见 ML 框架(如TensorFlow、XGBoost、ScikitLearn、PyTorch 和 ONNX)的提供性高性能、标准化的推理协议,解决生产模型服务的使用案例。

KServe提供简单的Kubernetes CRD,可用于将单个或多个经过训练的模型(例如TFServing、TorchServe、Triton等推理服务器)部署到模型服务运行时。

KServe封装了自动扩展、网络、健康检查和服务器配置的复杂性,为 ML 部署带来了 GPU 自动扩展、零扩缩放和金丝雀发布等先进的服务特性。它使得生产 ML 服务变得简单、可插拔,并提供了完整的故事,包括预测、预处理、后处理和可解释性。

KServe中的ModelMesh 专为高规模、高密度和频繁变化的模型使用场景设计,智能地加载和卸载 AI 模型,以在用户响应和计算资源占用之间取得智能权衡。

KServe还提供基本API原语,可轻松构建自定义模型服务运行时。你也可以使用其他工具(例如BentoML)来构建你自己的自定义模型服务镜像。

  • • ⚙️ KServe的诞生背景:Kubeflow Summit 2019后,从Kubeflow分离出的KF Serving,最终发展为KServe。在2022年由Nvidia贡献了V2标准化推理协议,引起行业广泛关注。

  • • 🌐 KServe的功能与部署:是高度可扩展、基于Kubernetes的无服务器模型推理平台。支持云端或本地部署,具备服务器自动扩展、多种模型服务运行时等特性。

  • • 📈 KServe当前状态:拥有约60%的Kubeflow用户使用KServe;已有约10万次KServe Docker镜像下载;拥有20个核心贡献者和172名贡献者。

  • • 🖥️ KServe提供基本和高级特性,如规模化、请求处理、安全性、流量管理、分布式跟踪等,使机器学习工作流更加便捷。

  • • 🤖 KServe构建在Kubernetes之上,与Knative和Istio集成,提供了可扩展且高效的模型服务架构。

  • • 🛠️ KServe特性:支持多种模型服务运行时,如Triton、TF Serving等;推出的V2推理协议标准化了多种推理运行时;引入了推理图、批处理等功能。

  • • 🔄 Model Mesh与KServe整合:Model Mesh是IBM在KServe项目中贡献的技术,用于管理大量模型服务的静态Pods,提供高密度模型加载和路由请求功能,自动优化资源利用,旨在解决大规模、高密度的推断服务部署问题。

  • • 🚀KServe还支持Canary Rollout等功能,提供流量控制和版本管理,适用于各种生产用例。

c08ef63887853ccc96c94579e0267425.webp

为什么选择KServe?

  • • KServe 是一个与云无关的标准模型推理平台,专为高度可扩展的用例而构建。

  • • 跨机器学习框架,提供高性能标准化推理协议

  • • 支持现代无服务器推理工作负载,具有基于请求在CPU和GPU的自动缩放(包括缩放至零)

  • • 使用ModelMesh 支持 高可扩展性、密度封装和智能路由

  • • 简单且可插入的生产服务:用于推理预/后处理监控可解释性.

  • • 高级部署:金丝雀部署、Pipeline、InferenceGraph

在k8s环境中,你可以使用Kserve InferenceServiceAPI 规范通过构建的 vLLM 推理服务器容器镜像来部署模型。

搭建kserve环境

你可以使用 KServe 快速安装脚本,在本地部署 KServe :

    curl -s "https://raw.githubusercontent.com/kserve/kserve/release-0.11/hack/quick_install.sh" | bash
  

执行结果查看

     kubectl get pod -A
NAMESPACE            NAME                                                 READY   STATUS    RESTARTS   AGE
cert-manager         cert-manager-76b7c557d5-xzd8b                        1/1     Running   1          30m
cert-manager         cert-manager-cainjector-655d695d74-q2tjv             1/1     Running   6          30m
cert-manager         cert-manager-webhook-7955b9bb97-h4bm6                1/1     Running   3          30m
istio-system         istio-egressgateway-5547fcc8fc-z7sz9                 1/1     Running   1          32m
istio-system         istio-ingressgateway-8f568d595-f4f5z                 1/1     Running   1          32m
istio-system         istiod-568d797f55-k6476                              1/1     Running   1          32m
knative-serving      activator-68b7698d74-tld8d                           1/1     Running   1          31m
knative-serving      autoscaler-6c8884d6ff-dd6fn                          1/1     Running   1          31m
knative-serving      controller-76cf997d95-fk6hv                          1/1     Running   1          31m
knative-serving      domain-mapping-57fdbf97b-mg8r2                       1/1     Running   1          31m
knative-serving      domainmapping-webhook-66c5f7d596-qxhtw               1/1     Running   5          31m
knative-serving      net-istio-controller-544874485d-4dlvr                1/1     Running   1          31m
knative-serving      net-istio-webhook-695d588d65-crfkf                   1/1     Running   1          31m
knative-serving      webhook-7df8fd847b-dqx8s                             1/1     Running   4          31m
kserve               kserve-controller-manager-0                          2/2     Running   2          22m
kube-system          coredns-558bd4d5db-gkspn                             1/1     Running   1          54m
kube-system          coredns-558bd4d5db-tsh95                             1/1     Running   1          54m
kube-system          etcd-test-cluster-control-plane                      1/1     Running   1          54m
kube-system          kindnet-49hl9                                        1/1     Running   1          54m
kube-system          kube-apiserver-test-cluster-control-plane            1/1     Running   1          54m
kube-system          kube-controller-manager-test-cluster-control-plane   1/1     Running   7          54m
kube-system          kube-proxy-mqvtb                                     1/1     Running   1          54m
kube-system          kube-scheduler-test-cluster-control-plane            1/1     Running   7          54m
local-path-storage   local-path-provisioner-778f7d66bf-4fzcg              1/1     Running   1          54m

基于Kserve和vLLM:在k8s上创建大模型推理服务

创建理服务InferenceService

    apiVersion: serving.kserve.io/v1beta1
kind: InferenceService
metadata:
  namespace: kserve-test
  name: bloom
spec:
  predictor:
    containers:
    - args:
      - --port
      - "8080"
      - --model
      - "/mnt/models"
      command:
      - python3
      - -m
      - vllm.entrypoints.api_server
      env:
      - name: STORAGE_URI
        value: pvc://task-pv-claim/bloom-560m
      image: docker.io/kserve/vllmserver:latest
      imagePullPolicy: IfNotPresent 
      name: kserve-container
      resources:
        limits:
          cpu: "5"
          memory: 20Gi
          nvidia.com/gpu: "1"
        requests:
          cpu: "5"
          memory: 20Gi
          nvidia.com/gpu: "1"

启动日志

    $ kubectl -n kserve-test logs -f --tail=200 bloom-predictor-00001-deployment-66649d69bd-nw96r 

Defaulted container "kserve-container" out of: kserve-container, queue-proxy, storage-initializer (init)
INFO 02-20 06:04:40 llm_engine.py:70] Initializing an LLM engine with config: model='/mnt/models', tokenizer='/mnt/models', tokenizer_mode=auto, trust_remote_code=False, dtype=torch.float16, use_dummy_weights=False, download_dir=None, use_np_weights=False, tensor_parallel_size=1, seed=0)
INFO 02-20 06:04:54 llm_engine.py:196] # GPU blocks: 6600, # CPU blocks: 2730
INFO:     Started server process [1]
INFO:     Waiting for application startup.
INFO:     Application startup complete.
INFO:     Uvicorn running on http://localhost:8080 (Press CTRL+C to quit)

使用Port Forward进行端口转发

    INGRESS_GATEWAY_SERVICE=$(kubectl get svc --namespace istio-system --selector="app=istio-ingressgateway" --output jsonpath='{.items[0].metadata.name}')
kubectl port-forward --namespace istio-system svc/${INGRESS_GATEWAY_SERVICE} 8080:80

进行LLM推理

来自具有 HOST 标头的 Ingress 网关

如果你没有 DNS,你仍然可以携带 HOST 标头,来请求入口网关外部 IP。

    # start another terminal
export INGRESS_HOST=localhost
export INGRESS_PORT=8080
MODEL_NAME=bloom-560m
SERVICE_HOSTNAME=$(kubectl --namespace kserve-test get inferenceservice bloom -o jsonpath='{.status.url}' | cut -d "/" -f 3)

#提示 {"error":"TypeError : Type is not JSON serializable: bytes"}
# 在你的 curl 请求中,尝试添加 -H "Content-Type: application/json" 头部。这样可以确保服务端正确地解析请求的 JSON 数据。
curl -v -H "Host: ${SERVICE_HOSTNAME}" -H "Content-Type: application/json"     http://${INGRESS_HOST}:${INGRESS_PORT}/generate     -d '{"prompt": "San Francisco is a" }'


curl -v -H "Host: ${SERVICE_HOSTNAME}" -H "Content-Type: application/json" \
    http://${INGRESS_HOST}:${INGRESS_PORT}/v1/completions \
    -d '{
        "model": "/mnt/models",
        "prompt": "San Francisco is a",
        "max_tokens": 70,
        "temperature": 0
    }'

预期输出

    * About to connect() to localhost port 8080 (#0)
*   Trying ::1...
* Connected to localhost (::1) port 8080 (#0)
> POST /generate HTTP/1.1
> User-Agent: curl/7.29.0
> Accept: */*
> Host: bloom.kserve-test.example.com
> Content-Type: application/json
> Content-Length: 33

* upload completely sent off: 33 out of 33 bytes
< HTTP/1.1 200 OK
< content-length: 128
< content-type: application/json
date: Tue, 20 Feb 2024 07:34:23 GMT
< server: istio-envoy
< x-envoy-upstream-service-time: 287

* Connection #0 to host localhost left intact
{"text":["San Francisco is a medium-sized family donating site with nonprofits, churches, Catholic organizations and business"]}

LLM推理:兼容OpenAI的API

ce3286e5e909c007a17bb9bdf458897a.webp

vLLM可以部署为实现OpenAI API协议的服务器。这使得 vLLM 可以用作OpenAI API应用程序的直接替代品。默认情况下,它在http://localhost:8000处启动服务器。你可以使用和参数--host--port指定地址。

服务器当前一次托管一个模型(下面命令中的 OPT-125M)并实现模型列表[7]使用 OpenAI Chat API 查询模型[8]通过输入提示查询模型[9]端点。我们正在积极增加对更多端点的支持。

使用vllm-openai部署推理服务

vLLM 提供官方 docker 镜像进行部署。该镜像可用于运行 OpenAI 兼容服务器。该镜像在 Docker Hub 上以vllm/vllm-openai[10]形式提供。

    apiVersion: serving.kserve.io/v1beta1
kind: InferenceService
metadata:
  namespace: kserve-test
  name: bloom
spec:
  predictor:
    containers:
    - args:
      - --port
      - "8080"
      - --model
      - "/mnt/models"
      env:
      - name: STORAGE_URI
        value: pvc://task-pv-claim/bloom-560m
      image: docker.io/vllm/vllm-openai:latest
      imagePullPolicy: IfNotPresent
      name: kserve-container
      resources:
        limits:
          cpu: "5"
          memory: 20Gi
          nvidia.com/gpu: "1"
        requests:
          cpu: "5"
          memory: 20Gi
          nvidia.com/gpu: "1"

使用Port Forward进行端口转发

    INGRESS_GATEWAY_SERVICE=$(kubectl get svc --namespace istio-system --selector="app=istio-ingressgateway" --output jsonpath='{.items[0].metadata.name}')
kubectl port-forward --namespace istio-system svc/${INGRESS_GATEWAY_SERVICE} 8080:80

如果你没有 DNS,你仍然可以携带 HOST 标头,来请求入口网关外部 IP。

    # start another terminal
export INGRESS_HOST=localhost
export INGRESS_PORT=8080
MODEL_NAME=bloom-560m
SERVICE_HOSTNAME=$(kubectl --namespace kserve-test get inferenceservice bloom -o jsonpath='{.status.url}' | cut -d "/" -f 3)

将 OpenAI Completions API 与 vLLM 结合使用

通过输入提示查询模型:

    #提示 {"error":"TypeError : Type is not JSON serializable: bytes"}
# 在你的 curl 请求中,尝试添加 -H "Content-Type: application/json" 头部。这样可以确保服务端正确地解析请求的 JSON 数据。
curl -v -H "Host: ${SERVICE_HOSTNAME}" -H "Content-Type: application/json" \
    http://${INGRESS_HOST}:${INGRESS_PORT}/v1/completions \
    -d '{
        "model": "/mnt/models",
        "prompt": "San Francisco is a",
        "max_tokens": 70,
        "temperature": 0
    }'

预期输出

    $ curl -v -H "Host: ${SERVICE_HOSTNAME}" -H "Content-Type: application/json" \
>     http://${INGRESS_HOST}:${INGRESS_PORT}/v1/completions \
>     -d '{
>         "model": "/mnt/models",
>         "prompt": "San Francisco is a",
>         "max_tokens": 70,
>         "temperature": 0
>     }'


* About to connect() to localhost port 8080 (#0)
*   Trying ::1...
* Connected to localhost (::1) port 8080 (#0)
> POST /v1/completions HTTP/1.1
> User-Agent: curl/7.29.0
> Accept: */*
> Host: bloom.kserve-test.example.com
> Content-Type: application/json
> Content-Length: 130

* upload completely sent off: 130 out of 130 bytes
< HTTP/1.1 200 OK
< content-length: 641
< content-type: application/json
date: Tue, 20 Feb 2024 09:37:47 GMT
< server: istio-envoy
< x-envoy-upstream-service-time: 589

* Connection #0 to host localhost left intact
{"id":"cmpl-45a94f7aecb84de08de42d4e51fad49f","object":"text_completion","created":3793968,"model":"/mnt/models","choices":[{"index":0,"text":" great place to visit. The city is home to a number of museums, including the National Museum of Natural History, the National Museum of Natural History, the National Museum of Natural History, the National Museum of Natural History, the National Museum of Natural History, the National Museum of Natural History, the National Museum of Natural History, the National Museum of Natural","logprobs":null,"finish_reason":"length"}],"usage":{"prompt_tokens":4,"total_tokens":74,"completion_tokens":70}}

将 OpenAI 聊天 API 与 vLLM 结合使用

vLLM 服务器旨在支持 OpenAI Chat API,允许你与模型进行动态对话。聊天界面是一种与模型通信的更具交互性的方式,允许来回交换,并且可以存储在聊天历史记录中。这对于需要上下文或更详细解释的任务非常有用。

使用 OpenAI Chat API 查询模型:

你可以使用create chat completion[11] 端点在类似聊天的界面中与模型进行通信:

    curl -v -H "Host: ${SERVICE_HOSTNAME}" -H "Content-Type: application/json" \
    http://${INGRESS_HOST}:${INGRESS_PORT}/v1/chat/completions \
    -d '{
        "model": "/mnt/models",
        "messages": [
            {"role": "system", "content": "You are a helpful assistant."},
            {"role": "user", "content": "Who won the world series in 2020?"}
        ]
    }'

    

预期输出

    $ curl -v -H "Host: ${SERVICE_HOSTNAME}" -H "Content-Type: application/json" \
>     http://${INGRESS_HOST}:${INGRESS_PORT}/v1/chat/completions \
>     -d '{
>         "model": "/mnt/models",
>         "messages": [
>             {"role": "system", "content": "You are a helpful assistant."},
>             {"role": "user", "content": "Who won the world series in 2020?"}
>         ]
>     }'

* About to connect() to localhost port 8080 (#0)
*   Trying ::1...
* Connected to localhost (::1) port 8080 (#0)
> POST /v1/chat/completions HTTP/1.1
> User-Agent: curl/7.29.0
> Accept: */*
> Host: bloom.kserve-test.example.com
> Content-Type: application/json
> Content-Length: 223

* upload completely sent off: 223 out of 223 bytes

< HTTP/1.1 200 OK
< content-length: 654
< content-type: application/json
date: Tue, 20 Feb 2024 09:56:34 GMT
< server: istio-envoy
< x-envoy-upstream-service-time: 814


* Connection #0 to host localhost left intact
{"id":"cmpl-af28c2d32b1f4a2aa24ad30f8fbbfa2b","object":"chat.completion","created":3795095,"model":"/mnt/models","choices":[{"index":0,"message":{"role":"assistant","content":"I have been on the road all year and was really happy to see the cheers in The Guardian site this year after the World Cup — for the first time in its history, a newspaper taking the time to cover the current World Cup (although not the one that was a fan favourite of mine and my wife). I am quite pleased with how well it went and I hope it will continue as much as possible."},"finish_reason":"stop"}],"usage":{"prompt_tokens":16,"total_tokens":100,"completion_tokens":84}}

有关聊天 API 的更深入示例和高级功能,你可以参考 OpenAI 官方文档[12]

引用链接

[1] vLLM: https://github.com/vllm-project/vllm
[2] 连续批处理: https://www.anyscale.com/blog/continuous-batching-llm-inference
[3] vLLM支持分页注意力: https://vllm.ai/
[4] GPTQ: https://arxiv.org/abs/2210.17323
[5] AWQ: https://arxiv.org/abs/2306.00978
[6] SqueezeLLM: https://arxiv.org/abs/2306.07629
[7] 模型列表: https://platform.openai.com/docs/api-reference/models/list
[8] 使用 OpenAI Chat API 查询模型: https://platform.openai.com/docs/api-reference/chat/completions/create
[9] 通过输入提示查询模型: https://platform.openai.com/docs/api-reference/completions/create
[10] vllm/vllm-openai: https://hub.docker.com/r/vllm/vllm-openai/tags
[11] create chat completion: https://platform.openai.com/docs/api-reference/chat/completions/create
[12] OpenAI 官方文档: https://platform.openai.com/docs/api-reference

- END -



推荐阅读:

Meetup武汉站议题揭晓~趁现在!速速报名...

Meetup上海站开启报名!这次千万不要错过!

Go语言进入Tiobe指数前10名

2024年的Rust与Go

「GoCN酷Go推荐」我用go写了魔兽世界登录器?

Go区不大,创造神话,科目三杀进来了

Go 1.22新特性前瞻


想要了解Go更多内容,欢迎扫描下方👇关注公众号, 回复关键词 [实战群]   ,就有机会进群和我们进行交流



分享、在看与点赞Go 
浏览 96
点赞
评论
收藏
分享

手机扫一扫分享

分享
举报
评论
图片
表情
推荐
点赞
评论
收藏
分享

手机扫一扫分享

分享
举报