赞
踩
模型服务网格(Model Service Mesh)是一种架构模式,用于在分布式环境中部署和管理机器学习模型服务。它提供了一个可扩展的、高性能的基础架构,用于将多个模型服务进行管理、部署和调度,以此更好地处理模型的部署、版本管理、路由和推理请求的负载均衡。
模型服务网格的核心思想是将模型部署为可伸缩的服务,并通过网格来管理和路由这些服务, 简化模型服务的管理和运维。它通过将模型服务抽象为可编排的、可伸缩的单元,使得模型的部署、扩展和版本控制变得更加容易。它还提供了一些核心功能,如负载均衡、自动伸缩、故障恢复等,以确保模型服务的高可用性和可靠性。
模型可以根据实际的推理请求负载进行自动缩放和负载均衡,从而实现高效的模型推理。模型服务网格还提供了一些高级功能,如流量分割、A/B 测试、灰度发布等,以便更好地控制和管理模型服务的流量,可以轻松切换和回滚不同的模型版本。它还支持动态路由,可以根据请求的属性,如模型类型、数据格式或其他元数据,将请求路由到适当的模型服务。
阿里云服务网格 ASM 已经提供了一个可扩展的、高性能的模型服务网格基础能力,用于将多个模型服务进行管理、部署和调度,以此更好地处理模型的部署、版本管理、路由和推理请求的负载均衡。通过使用模型服务网格,开发人员可以更轻松地部署、管理和扩展机器学习模型,同时提供高可用性、弹性和灵活性,以满足不同的业务需求。
模型服务网格基于 KServe ModelMesh 实现,针对大容量、高密度和频繁变化的模型用例进行了优化,可以智能地将模型加载到内存中或从内存中卸载,以在响应性和计算之间取得平衡。
模型服务网格提供了以下功能:
以下是部署模型示例,使用前提可以参考 [1]。
在 ACK 集群中,使用如下 YAML 创建存储声明 my-models-pvc:
- apiVersion: v1
- kind: PersistentVolumeClaim
- metadata:
- name: my-models-pvc
- namespace: modelmesh-serving
- spec:
- accessModes:
- - ReadWriteMany
- resources:
- requests:
- storage: 1Gi
- storageClassName: alibabacloud-cnfs-nas
- volumeMode: Filesystem
然后运行如下命令:
kubectl get pvc -n modelmesh-serving
将会得到如下类似的预期结果:
- NAME STATUS VOLUME CAPACITY ACCESS MODES STORAGECLASS AGE
- my-models-pvc Bound nas-379c32e1-c0ef-43f3-8277-9eb4606b53f8 1Gi RWX alibabacloud-cnfs-nas 2h
为了使用新的 PVC,我们需要将其作为卷安装到 Kubernetes Pod。然后我们可以使用这个 pod 将模型文件上传到持久卷。
让我们部署一个pvc-access Pod,并要求 Kubernetes 控制器通过指定“my-models-pvc”来声明我们之前请求的 PVC:
- kubectl apply -n modelmesh-serving -f - <<EOF
- ---
- apiVersion: v1
- kind: Pod
- metadata:
- name: "pvc-access"
- spec:
- containers:
- - name: main
- image: ubuntu
- command: ["/bin/sh", "-ec", "sleep 10000"]
- volumeMounts:
- - name: "my-pvc"
- mountPath: "/mnt/models"
- volumes:
- - name: "my-pvc"
- persistentVolumeClaim:
- claimName: "my-models-pvc"
- EOF
确认 pvc-access Pod 应该正在运行:
kubectl get pods -n modelmesh-serving | grep pvc-access
将会得到如下类似的预期结果:
pvc-access 1/1 Running
现在,我们需要将我们的 AI 模型添加到存储卷中,我们将使用 scikit-learn 训练的 MNIST 手写数字字符识别模型。可以从 kserve/modelmesh-minio-examples 仓库[2]下载 mnist-svm.joblib 模型文件的副本。
通过以下命令,将 mnist-svm.joblib 模型文件复制到 pvc-access pod 上的 /mnt/models 文件夹中:
kubectl -n modelmesh-serving cp mnist-svm.joblib pvc-access:/mnt/models/
执行如下命令,确认 model 已经加载成功:
kubectl -n modelmesh-serving exec -it pvc-access -- ls -alr /mnt/models/
应该得到如下内容:
-rw-r--r-- 1 501 staff 344817 Oct 30 11:23 mnist-svm.joblib
接下来,我们需要部署一个 sklearn-mnist 推理服务:
- apiVersion: serving.kserve.io/v1beta1
- kind: InferenceService
- metadata:
- name: sklearn-mnist
- namespace: modelmesh-serving
- annotations:
- serving.kserve.io/deploymentMode: ModelMesh
- spec:
- predictor:
- model:
- modelFormat:
- name: sklearn
- storage:
- parameters:
- type: pvc
- name: my-models-pvc
- path: mnist-svm.joblib
几十秒钟后(取决于镜像拉取速度),新的推理服务 sklearn-mnist 应该准备就绪。
运行如下命令:
kubectl get isvc -n modelmesh-serving
将会得到如下类似的预期结果:
- NAME URL READY
- sklearn-mnist grpc://modelmesh-serving.modelmesh-serving:8033 True
现在我们可以使用 curl 发送推理请求到我们的 sklearn-mnist 模型。数组形式的请求数据表示待分类的数字图像扫描中 64 个像素的灰度值。
- MODEL_NAME="sklearn-mnist"
- ASM_GW_IP="ASM网关IP地址"
- curl -X POST -k "http://${ASM_GW_IP}:8008/v2/models/${MODEL_NAME}/infer" -d '{"inputs": [{"name": "predict", "shape": [1, 64], "datatype": "FP32", "contents": {"fp32_contents": [0.0, 0.0, 1.0, 11.0, 14.0, 15.0, 3.0, 0.0, 0.0, 1.0, 13.0, 16.0, 12.0, 16.0, 8.0, 0.0, 0.0, 8.0, 16.0, 4.0, 6.0, 16.0, 5.0, 0.0, 0.0, 5.0, 15.0, 11.0, 13.0, 14.0, 0.0, 0.0, 0.0, 0.0, 2.0, 12.0, 16.0, 13.0, 0.0, 0.0, 0.0, 0.0, 0.0, 13.0, 16.0, 16.0, 6.0, 0.0, 0.0, 0.0, 0.0, 16.0, 16.0, 16.0, 7.0, 0.0, 0.0, 0.0, 0.0, 11.0, 13.0, 12.0, 1.0, 0.0]}}]}'
JSON 响应应如下所示,推断扫描的数字是“8”:
- {
- "modelName": "sklearn-mnist__isvc-3c10c62d34",
- "outputs": [
- {
- "name": "predict",
- "datatype": "INT64",
- "shape": [
- "1",
- "1"
- ],
- "contents": {
- "int64Contents": [
- "8"
- ]
- }
- }
- ]
- }
模型服务网格(Model Service Mesh,简称为 ModelMesh) 针对大容量、高密度和频繁变化的模型推理服务的部署运行进行了优化,可以智能地将模型加载到内存中或从内存中卸载,以在响应性和计算之间取得最佳的平衡。
ModelMesh 默认集成了以下模型服务器运行环境,例如
如果这些模型服务器无法满足您的特定要求时,譬如需要处理推理的自定义逻辑,或者您的模型所需的框架还不在上述支持列表中,您可以自定义服务运行时来进行扩展支撑。
具体可以参考 [3]。
大语言模型 LLM(Large Language Model)指参数数量达到亿级别的神经网络语言模型,例如:GPT-3、GPT-4、PaLM、PaLM2 等。以下介绍如何为大语言模型 LLM 提供服务。
使用前提可以具体参考 [4]。
构建自定义运行时,提供带有提示调整配置的 HuggingFace LLM。此示例中的默认值设置为我们预先构建的自定义运行时镜像和预先构建的提示调整配置。
3.1.1 实现一个继承自 MLServer MLModel 的类
kfp-tekton/samples/peft-modelmesh-pipeline 目录[5]中的 peft_model_server.py 文件包含了如何提供带有提示调整配置的 HuggingFace LLM 的所有代码。
下面的 _load_model 函数显示我们将选择已训练的 PEFT 提示调整配置的预训练 LLM 模型。分词器也作为模型的一部分进行定义,因此可以用于对推理请求中的原始字符串输入进行编码和解码,而无需要求用户预处理其输入为张量字节。
- from typing import List
-
- from mlserver import MLModel, types
- from mlserver.codecs import decode_args
-
- from peft import PeftModel, PeftConfig
- from transformers import AutoModelForCausalLM, AutoTokenizer
- import torch
- import os
-
- class PeftModelServer(MLModel):
- async def load(self) -> bool:
- self._load_model()
- self.ready = True
- return self.ready
-
- @decode_args
- async def predict(self, content: List[str]) -> List[str]:
- return self._predict_outputs(content)
-
- def _load_model(self):
- model_name_or_path = os.environ.get("PRETRAINED_MODEL_PATH", "bigscience/bloomz-560m")
- peft_model_id = os.environ.get("PEFT_MODEL_ID", "aipipeline/bloomz-560m_PROMPT_TUNING_CAUSAL_LM")
- self.tokenizer = AutoTokenizer.from_pretrained(model_name_or_path, local_files_only=True)
- config = PeftConfig.from_pretrained(peft_model_id)
- self.model = AutoModelForCausalLM.from_pretrained(config.base_model_name_or_path)
- self.model = PeftModel.from_pretrained(self.model, peft_model_id)
- self.text_column = os.environ.get("DATASET_TEXT_COLUMN_NAME", "Tweet text")
- return
-
- def _predict_outputs(self, content: List[str]) -> List[str]:
- output_list = []
- for input in content:
- inputs = self.tokenizer(
- f'{self.text_column} : {input} Label : ',
- return_tensors="pt",
- )
- with torch.no_grad():
- inputs = {k: v for k, v in inputs.items()}
- outputs = self.model.generate(
- input_ids=inputs["input_ids"], attention_mask=inputs["attention_mask"], max_new_tokens=10, eos_token_id=3
- )
- outputs = self.tokenizer.batch_decode(outputs.detach().cpu().numpy(), skip_special_tokens=True)
- output_list.append(outputs[0])
- return output_list
3.1.2 构建 Docker 镜像
实现了模型类之后,我们需要将其依赖项(包括 MLServer)打包到一个支持 ServingRuntime 资源的镜像中。参考如下 Dockerfile 进行镜像构建。
- # TODO: choose appropriate base image, install Python, MLServer, and
- # dependencies of your MLModel implementation
- FROM python:3.8-slim-buster
- RUN pip install mlserver peft transformers datasets
- # ...
-
- # The custom `MLModel` implementation should be on the Python search path
- # instead of relying on the working directory of the image. If using a
- # single-file module, this can be accomplished with:
- COPY --chown=${USER} ./peft_model_server.py /opt/peft_model_server.py
- ENV PYTHONPATH=/opt/
-
- # environment variables to be compatible with ModelMesh Serving
- # these can also be set in the ServingRuntime, but this is recommended for
- # consistency when building and testing
- ENV MLSERVER_MODELS_DIR=/models/_mlserver_models \
- MLSERVER_GRPC_PORT=8001 \
- MLSERVER_HTTP_PORT=8002 \
- MLSERVER_LOAD_MODELS_AT_STARTUP=false \
- MLSERVER_MODEL_NAME=peft-model
-
- # With this setting, the implementation field is not required in the model
- # settings which eases integration by allowing the built-in adapter to generate
- # a basic model settings file
- ENV MLSERVER_MODEL_IMPLEMENTATION=peft_model_server.PeftModelServer
-
- CMD mlserver start ${MLSERVER_MODELS_DIR}
3.1.3 创建新的 ServingRuntime 资源
可以使用以下代码块中的 YAML 模板创建一个新的 ServingRuntime 资源,并将其指向您刚创建的镜像。
- apiVersion: serving.kserve.io/v1alpha1
- kind: ServingRuntime
- metadata:
- name: peft-model-server
- namespace: modelmesh-serving
- spec:
- supportedModelFormats:
- - name: peft-model
- version: "1"
- autoSelect: true
- multiModel: true
- grpcDataEndpoint: port:8001
- grpcEndpoint: port:8085
- containers:
- - name: mlserver
- image: registry.cn-beijing.aliyuncs.com/test/peft-model-server:latest
- env:
- - name: MLSERVER_MODELS_DIR
- value: "/models/_mlserver_models/"
- - name: MLSERVER_GRPC_PORT
- value: "8001"
- - name: MLSERVER_HTTP_PORT
- value: "8002"
- - name: MLSERVER_LOAD_MODELS_AT_STARTUP
- value: "true"
- - name: MLSERVER_MODEL_NAME
- value: peft-model
- - name: MLSERVER_HOST
- value: "127.0.0.1"
- - name: MLSERVER_GRPC_MAX_MESSAGE_LENGTH
- value: "-1"
- - name: PRETRAINED_MODEL_PATH
- value: "bigscience/bloomz-560m"
- - name: PEFT_MODEL_ID
- value: "aipipeline/bloomz-560m_PROMPT_TUNING_CAUSAL_LM"
- # - name: "TRANSFORMERS_OFFLINE"
- # value: "1"
- # - name: "HF_DATASETS_OFFLINE"
- # value: "1"
- resources:
- requests:
- cpu: 500m
- memory: 4Gi
- limits:
- cpu: "5"
- memory: 5Gi
- builtInAdapter:
- serverType: mlserver
- runtimeManagementPort: 8001
- memBufferBytes: 134217728
- modelLoadingTimeoutMillis: 90000
然后使用 kubectl apply 命令创建 ServingRuntime 资源,您将在 ModelMesh 部署中看到您的新自定义运行时。
为了使用您新创建的运行时部署模型,您需要创建一个 InferenceService 资源来提供模型服务。该资源是 KServe 和 ModelMesh 用于管理模型的主要接口,代表了模型在推理中的逻辑端点。
- apiVersion: serving.kserve.io/v1beta1
- kind: InferenceService
- metadata:
- name: peft-demo
- namespace: modelmesh-serving
- annotations:
- serving.kserve.io/deploymentMode: ModelMesh
- spec:
- predictor:
- model:
- modelFormat:
- name: peft-model
- runtime: peft-model-server
- storage:
- key: localMinIO
- path: sklearn/mnist-svm.joblib
在前面的代码块中,InferenceService 命名为 peft-demo,并声明其模型格式为 peft-model,与之前创建的示例自定义运行时使用相同的格式。还传递了一个可选字段 runtime,明确告诉 ModelMesh 使用 peft-model-server运行时来部署此模型。
现在我们可以使用 curl 发送推理请求到我们上面部署的 LLM 模型服务。
- MODEL_NAME="peft-demo"
- ASM_GW_IP="ASM网关IP地址"
- curl -X POST -k http://${ASM_GW_IP}:8008/v2/models/${MODEL_NAME}/infer -d @./input.json
其中 input.json 表示请求数据:
- {
- "inputs": [
- {
- "name": "content",
- "shape": [1],
- "datatype": "BYTES",
- "contents": {"bytes_contents": ["RXZlcnkgZGF5IGlzIGEgbmV3IGJpbm5pbmcsIGZpbGxlZCB3aXRoIG9wdGlvbnBpZW5pbmcgYW5kIGhvcGU="]}
- }
- ]
- }
bytes_contents 对应的是字符串“Every day is a new beginning, filled with opportunities and hope”的 base64 编码。
JSON 响应应如下所示,推断扫描的数字是“8”:
- {
- "modelName": "peft-demo__isvc-5c5315c302",
- "outputs": [
- {
- "name": "output-0",
- "datatype": "BYTES",
- "shape": [
- "1",
- "1"
- ],
- "parameters": {
- "content_type": {
- "stringParam": "str"
- }
- },
- "contents": {
- "bytesContents": [
- "VHdlZXQgdGV4dCA6IEV2ZXJ5IGRheSBpcyBhIG5ldyBiaW5uaW5nLCBmaWxsZWQgd2l0aCBvcHRpb25waWVuaW5nIGFuZCBob3BlIExhYmVsIDogbm8gY29tcGxhaW50"
- ]
- }
- }
- ]
- }
其中 bytesContents 进行 base64 解码后的内容为:
Tweet text : Every day is a new binning, filled with optionpiening and hope Label : no complaint
至此,说明上述大语言模型 LLM 的模型服务请求得到了预期的结果。
阿里云服务网格 ASM 已经提供了一个可扩展的、高性能的模型服务网格基础能力,用于将多个模型服务进行管理、部署和调度,以此更好地处理模型的部署、版本管理、路由和推理请求的负载均衡。
欢迎试用: https://www.aliyun.com/product/servicemesh
相关链接:
[1] 以下是部署模型示例,使用前提可以参考
[2] kserve/modelmesh-minio-examples 仓库
https://github.com/kserve/modelmesh-minio-examples/blob/main/sklearn/mnist-svm.joblib
[3] 具体可以参考
[4] 使用前提可以具体参考
[5] kfp-tekton/samples/peft-modelmesh-pipeline 目录
https://github.com/kubeflow/kfp-tekton
作者:王夕宁
本文为阿里云原创内容,未经允许不得转载。
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。