 URI 加载模型:sklearn 单文件与 TensorFlow 打包工件实战)
模型推理服务云原生后端微服务MLOps人工智能【免费下载链接】kserveStandardized Distributed Generative and Predictive AI Inference Platform for Scalable, Multi-Framework Deployment on Kubernetes项目地址https://gitcode.com/gh_mirrors/ks/kserve点击查看免费下载导读在 KServe 中除了从对象存储S3/GCS/Azure或 PVC 拉取模型外你还可以直接通过storageUri指向一个暴露在http/https端点上的模型对象来完成推理服务部署。本文以 docs/samples/storage/uri/README.md 为核心完整演示两种典型场景——单文件模型如 sklearn 的model.joblib与打包工件如 TensorFlow 的tar/tgz并深入解析带鉴权头的 HTTP(S) 请求如何通过 Secret 注入以及 KServe 控制器底层是如何把storageUri翻译成存储初始化动作的。读完本文你将能够独立完成模型放在任意 HTTP(S) 可达位置、无需对象存储也能用 KServe 上线推理服务的完整配置。URI 存储方式概述单文件与打包工件storageUri选项的核心能力是把模型对象通过一个 URI 暴露给 KServe。它支持两类形态单文件模型例如 sklearn 由 joblib 导出的model.joblib只有一个文件直接指向即可打包工件artifacts例如tar或zip归档内含某一模型类型所需的全部依赖文件。典型代表是 TensorFlow它必须遵循严格的目录结构saved_model.pb与variables/目录才能被 servable。仓库中该示例的完整配套文件位于 docs/samples/storage/uri/ 目录包含sklearn.yaml、tensorflow.yaml两个 InferenceService 清单以及input.json预测输入样本下文将逐一展开。前置条件集群与环境准备在开始之前需要满足以下三项条件本地~/.kube/config指向一个已安装 KServe 的集群。KServe 的安装方式可参考 hack/kserve-install.sh 以及 install 目录下的发布版本清单如kserve.yaml/kserve_kubeflow.yaml集群的 Istio Ingress 网关必须可以被外部网络访问即入口流量可达集群的 Istio Egress 网关必须允许http/https流量出站——因为推理 Pod 需要主动去拉取位于集群外部的模型 URI。为 HTTP/HTTPS 请求创建访问凭据 Secret如果你的 HTTP(S) 服务请求不需要携带请求头可以跳过本节。需要携带时例如私有模型仓库的账号鉴权按以下格式定义一个Opaque类型的 SecretapiVersion: v1 kind: Secret metadata: name: mysecret type: Opaque data: https-host: ZXhhbXBsZS5jb20 headers: |- ewoiYWNjb3VudC1uYW1lIjogInNvbWVfYWNjb3VudF9uYW1lIiwKInNlY3JldC1rZXkiOiAic29tZV9zZWNyZXRfa2V5Igp9host 与 headers 的编码规则https-host与headers两个键的值都必须是base64 编码后的内容且headers需要是格式合法的 JSON 字符串。编码过程如下example.com # echo -n example.com | base64 ZXhhbXBsZS5jb20 --- { account-name: some_account_name, secret-key: some_secret_key } # echo -n {\naccount-name: some_account_name,\nsecret-key: some_secret_key\n} | base64 ewoiYWNjb3VudC1uYW1lIjogInNvbWVfYWNjb3VudF9uYW1lIiwKInNlY3JldC1rZXkiOiAic29tZV9zZWNyZXRfa2V5Igp9即https-host对模型所在域名如example.com做echo -n ... | base64headers先把请求头写成 JSON注意转义换行符\n再整体 base64。源码视角Secret 如何被翻译为请求头从源码可以确认这两个键名与注入机制。在 pkg/credentials/https/https_secret.go 中定义了常量HTTPSHost https-host指明该 Secret 作用于哪个主机HEADERS headers携带请求头 JSON。其核心函数BuildSecretEnvs会同时读取https-host与headers两个键然后构造一个名为host-headers的环境变量注入到 storage-initializer 容器中envs append(envs, corev1.EnvVar{ Name: string(uriHost) HeadersSuffix, // 形如 example.com-headers Value: string(headers), })这也解释了文档中这些 headers 会被应用到所有相同 host 的 http/https 请求上的行为——凭据是按 host 维度命名的拉取模型时只有 URI 的 host 与 Secret 中https-host匹配时才会附加对应请求头。引用 Secret 的方式一InferenceService 注解通过注解serving.kserve.io/storageSecretName在 InferenceService 上直接引用 SecretapiVersion: serving.kserve.io/v1beta1 kind: InferenceService metadata: name: sklearn-from-uri annotations: serving.kserve.io/storageSecretName: mysecret spec: predictor: sklearn: storageUri: https://your-model-host/sklearn/frozen/model.joblib?rawtrue引用 Secret 的方式二ServiceAccount你也可以把 Secret 挂到 ServiceAccount 的secrets字段上然后在 predictor 中指定serviceAccountNameapiVersion: v1 kind: ServiceAccount metadata: name: sa secrets: - name: mysecretapiVersion: serving.kserve.io/v1beta1 kind: InferenceService metadata: name: sklearn-from-uri spec: predictor: serviceAccountName: sa sklearn: storageUri: https://your-model-host/sklearn/frozen/model.joblib?rawtrue两种引用方式的优先级从 pkg/credentials/service_account_credentials.go 的实现可以看到两条路径的解析顺序注解优先如果 InferenceService 上带serving.kserve.io/storageSecretName注解CreateSecretVolumeAndEnvFromServiceAccount会直接根据注解中的 Secret 名挂载凭据并返回回退到 ServiceAccount否则遍历serviceAccount.Secrets列表逐个调用mountSecretCredential尝试挂载。mountSecretCredentialservice_account_credentials.go会按 Secret 内的键类型分发当检测到https-host键时走https.BuildSecretEnvs注入 URI 请求头其余键如 S3 的AWS_ACCESS_KEY_ID、GCS 凭证文件、Azure、HDFS、HuggingFace token 等则分别走对应的凭据构建器。值得注意的是注解名serving.kserve.io/storageSecretName并非硬编码而是从credentials配置段的storageSecretNameAnnotation字段读取默认值即此值该配置项的定义与单测断言可参见 pkg/credentials/service_account_credentials_test.go。实战一sklearn 单文件模型训练并冻结模型以下脚本用鸢尾花iris数据集训练一个简单的 SVM 分类器并冻结为model.joblib。注意KServe 的 sklearn server 要求scikit-learn1.0.2from sklearn import svm from sklearn import datasets import joblib def train(X, y): clf svm.SVC(gammaauto) clf.fit(X, y) return clf def freeze(clf, path../frozen): joblib.dump(clf, f{path}/model.joblib) return True if __name__ __main__: iris datasets.load_iris() X, y iris.data, iris.target clf train(X, y) freeze(clf)接下来把冻结出的model.joblib放到一个 HTTP(S) 可达的位置例如推送到某个代码托管平台的仓库中并使用其原始文件下载地址得到形如https://your-model-host/sklearn/frozen/model.joblib?rawtrue的 URI。创建 InferenceService仓库配套示例文件 docs/samples/storage/uri/sklearn.yaml 即为此场景的清单apiVersion: serving.kserve.io/v1beta1 kind: InferenceService metadata: name: sklearn-from-uri spec: predictor: sklearn: storageUri: https://your-model-host/sklearn/frozen/model.joblib?rawtrue应用该 CRDkubectl apply -f sklearn_uri.yaml预期输出$ inferenceservice.serving.kserve.io/sklearn-from-uri created运行预测先确定 Ingress 的 IP 与端口并设置INGRESS_HOST与INGRESS_PORT环境变量。随后使用 curl 命中/v1/models/model:predict端点预测输入样本可参考 docs/samples/storage/uri/input.json其instances为两条鸢尾花特征向量MODEL_NAMEsklearn-from-uri INPUT_PATH./input.json curl -v -H Host: ${SERVICE_HOSTNAME} http://${INGRESS_HOST}:${INGRESS_PORT}/v1/models/$MODEL_NAME:predict -d $INPUT_PATH预期输出$ * Trying 10.0.1.16... * TCP_NODELAY set % Total % Received % Xferd Average Speed Time Time Time Current Dload Upload Total Spent Left Speed 0 0 0 0 0 0 0 0 --:--:-- --:--:-- --:--:-- 0* Connected to 10.0.1.16 (10.0.1.16) port 30749 (#0) POST /v1/models/sklearn-from-uri:predict HTTP/1.1 Host: sklearn-from-uri.kfserving-uri-storage.example.com User-Agent: curl/7.58.0 Accept: */* Content-Length: 86 Content-Type: application/x-www-form-urlencoded } [86 bytes data] * upload completely sent off: 86 out of 86 bytes HTTP/1.1 200 OK content-length: 23 content-type: application/json; charsetUTF-8 date: Thu, 06 Aug 2020 23:13:42 GMT server: istio-envoy x-envoy-upstream-service-time: 7 { [23 bytes data] 100 109 100 23 100 86 605 2263 --:--:-- --:--:-- --:--:-- 2868 * Connection #0 to host 10.0.1.16 left intact { predictions: [ 1, 1 ] }返回 200 OKpredictions数组中两条样本的预测类别均为1说明模型已从 URI 成功加载并完成推理。实战二TensorFlow 打包工件TensorFlow 模型由多个文件组成必须按严格目录结构组织saved_model.pbvariables/目录无法用单个文件 URI 表达因此需要先打成tar或tgz再上传。这正好验证了 URI 方式对打包工件的支持。训练并保存模型以下脚本同样基于 iris 数据训练一个简单的 Keras 全连接网络并将模型保存到../frozen/0001带版本号的目录from sklearn import datasets import numpy as np import tensorflow as tf def _ohe(targets): y np.zeros((150, 3)) for i, label in enumerate(targets): y[i, label] 1.0 return y def train(X, y, epochs, batch_size16): model tf.keras.Sequential([ tf.keras.layers.InputLayer(input_shape(4,)), tf.keras.layers.Dense(16, activationtf.nn.relu), tf.keras.layers.Dense(16, activationtf.nn.relu), tf.keras.layers.Dense(3, activationsoftmax) ]) model.compile(tf.keras.optimizers.RMSprop(learning_rate0.001), losscategorical_crossentropy, metrics[accuracy]) model.fit(X, y, epochsepochs) return model def freeze(model, path../frozen): model.save(f{path}/0001) return True if __name__ __main__: iris datasets.load_iris() X, targets iris.data, iris.target y _ohe(targets) model train(X, y, epochs50) freeze(model)训练结束后的处理与 sklearn 不同需要先把冻结产物打包成 tarballcd ../frozen tar -cvf artifacts.tar 0001/ gzip artifacts.tar artifacts.tgz其中假定0001/目录结构如下|-- 0001/ |-- saved_model.pb |-- variables/ |--- variables.data-00000-of-00001 |--- variables.index注意对 TensorFlow 而言从指定版本号的目录构建 tarball 是必需的0001/即版本号SavedModel 加载依赖该版本化目录结构。打包完成后把.tar或.tgz文件推送到某个远程 URI 即可。创建 InferenceService仓库配套示例文件 docs/samples/storage/uri/tensorflow.yaml 即为此场景的清单apiVersion: serving.kserve.io/v1beta1 kind: InferenceService metadata: name: tensorflow-from-uri-gzip spec: predictor: tensorflow: storageUri: https://your-model-host/tensorflow/frozen/model_artifacts.tar.gz应用该 CRDkubectl apply -f tensorflow_uri.yaml预期输出$ inferenceservice.serving.kserve.io/tensorflow-from-uri created运行预测同样先设置INGRESS_HOST与INGRESS_PORT然后发起预测MODEL_NAMEtensorflow-from-uri INPUT_PATH./input.json curl -v -H Host: ${SERVICE_HOSTNAME} http://${INGRESS_HOST}:${INGRESS_PORT}/v1/models/$MODEL_NAME:predict -d $INPUT_PATH预期输出$ * Trying 10.0.1.16... * TCP_NODELAY set % Total % Received % Xferd Average Speed Time Time Time Current Dload Upload Total Spent Left Speed 0 0 0 0 0 0 0 0 --:--:-- --:--:-- --:--:-- 0* Connected to 10.0.1.16 (10.0.1.16) port 30749 (#0) POST /v1/models/tensorflow-from-uri:predict HTTP/1.1 Host: tensorflow-from-uri.default.example.com User-Agent: curl/7.58.0 Accept: */* Content-Length: 86 Content-Type: application/x-www-form-urlencoded } [86 bytes data] * upload completely sent off: 86 out of 86 bytes HTTP/1.1 200 OK content-length: 112 content-type: application/json date: Thu, 06 Aug 2020 23:21:19 GMT x-envoy-upstream-service-time: 151 server: istio-envoy { [112 bytes data] 100 198 100 112 100 86 722 554 --:--:-- --:--:-- --:--:-- 1285 * Connection #0 to host 10.0.1.16 left intact { predictions: [ [ 0.0204100646, 0.680984616, 0.298605353 ], [ 0.0296604875, 0.658412039, 0.311927497 ] ] }响应中每条样本返回一个三维概率分布向量softmax 输出模型加载与推理链路正常。底层原理storageUri 如何驱动模型拉取从源码结构看URI 场景的完整链路可以概括为三步控制器读取 storageUriInferenceService 的spec.predictor.runtime.storageUri字段是模型来源的唯一入口KServe 控制器据此判断模型来自对象存储、PVC 还是纯 URI凭据注入控制器调用CredentialBuilderpkg/credentials/service_account_credentials.go为 storage-initializer 容器注入环境变量或卷。对于 HTTP(S) 凭据https.BuildSecretEnvs生成host-headers环境变量见 pkg/credentials/https/https_secret.go对于 S3/GCS 等类型则分别注入对应的密钥环境变量或凭证文件卷storage-initializer 下载注入完成后的容器启动时会根据storageUri协议选择对应下载器直接下载单文件或先下载归档再解压到约定目录仓库中该组件的实现位于 python/storage-initializer。TensorFlow 示例中0001/版本目录随 tarball 解压后即落在模型目录下从而满足 SavedModel 的 servable 结构要求。另外storageUri与存储凭据的默认配置如默认 storage-config Secret 名storage-config、注解名等在 pkg/constants/constants.go 中有统一定义并可通过credentials配置段覆盖参见 config/configmap/inferenceservice.yaml。常见问题与注意事项headers 与 host 的匹配Secret 中https-host的值必须与模型 URI 的 host 完全一致请求头才会被附加。若 URI 指向多台主机需要为每台主机分别创建带对应https-host的 Secretbase64 编码细节https-host与headers均为 base64 值务必用echo -n不要带换行编码headers必须是合法 JSON 并在编码前处理好转义TensorFlow 版本目录打包时必须包含带版本号的子目录如0001/这是 TensorFlow SavedModel 可被服务的硬性要求依赖版本示例中的 sklearn 场景要求scikit-learn1.0.2避免 joblib 序列化格式与 KServe sklearn server 运行环境不兼容Egress 放行推理 Pod 拉取 URI 依赖集群 Egress 网关允许出站http/https流量配置了严格出口策略时需要显式放行否则 Pod 会因拉取超时而反复重启单文件与归档的选择单文件模型如 sklearn 的 joblib、XGBoost 的模型文件直接指向文件 URI 即可多文件、有目录结构要求的模型如 TensorFlow SavedModel必须先归档为tar/tgz再上传storageUri指向归档文件。至此你已经掌握了 KServe 中不依赖对象存储、直接用 HTTP(S) URI 上线模型的完整套路既能通过单文件 URI 服务 sklearn 这类轻量模型也能通过归档 URI 服务 TensorFlow 这类多文件模型并能为私有模型仓库配置按 host 匹配的请求头鉴权。赞分享模型推理服务云原生后端微服务MLOps人工智能【免费下载链接】kserveStandardized Distributed Generative and Predictive AI Inference Platform for Scalable, Multi-Framework Deployment on Kubernetes项目地址https://gitcode.com/gh_mirrors/ks/kserve点击查看免费下载相关推荐ChatDev 附件与工件 API 实战指南文件上传、实时事件与打包下载ChatDev 附件与工件 API 实战指南文件上传、实时事件与打包下载 导读 本文以 ChatDev 2.0LLM 驱动的多 Agent 协作平台中的AI AgentAgent 框架Agent 工作流低代码工作流自动化OpenBMBPaddleNLP 模型下载与加载实战以 distilroberta-base 为例模型文件清单、CLI 下载与快速推理PaddleNLP 模型下载与加载实战以 distilroberta base 为例模型文件清单、CLI 下载与快速推理 本篇指南围绕本仓库 modelc人工智能深度学习计算机视觉NLP语音Velero v1.12 新特性深度解析CSI 快照数据移动、Resource Modifiers 与多 VolumeSnapshotClassVelero v1.12 新特性深度解析CSI 快照数据移动、Resource Modifiers 与多 VolumeSnapshotClass 导读 本文以模型推理服务云原生后端微服务MLOps人工智能上一篇WebVM浏览器中的Linux沙箱重新定义云端开发边界下一篇SilentPatch终极修复指南让GTA经典三部曲在现代电脑上完美运行创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考