写点什么

Seldon 使用 (五): engine & graph

用户头像
托内多
关注
发布于: 2021 年 08 月 01 日

在上文https://xie.infoq.cn/article/6aa2eceb59f3f3a7988d272ac,我们提到每个 SeldonDeployment(简称 sdep)的 pod 中都包含一个 engine 容器。这个 engine 容器,是由 seldon-manager 服务为每个 sdep 插入的,用于满足复杂推理场景的需求,如合并(Combine)多个模型推理结果,推理请求处理(Transform-Input),推理结果转换(Transform-Output),以及推理请求路由等对模型推理的请求和结果进行编排

1 示例一(Route):多臂赌博机模型服务

该示例是由 seldon 官方提供的,详细可见https://github.com/SeldonIO/seldon-core/tree/master/components/routers/epsilon-greedy。创建 sdep 定义文件 egreedy.yaml,如下:

apiVersion: machinelearning.seldon.io/v1alpha2kind: SeldonDeploymentmetadata:  name: egreedyspec:  predictors:  - componentSpecs:    - spec:        containers:        - image: seldonio/mock_classifier:1.9.1          name: classifier-1          env:          - name: PREDICTIVE_UNIT_HTTP_SERVICE_PORT            value: "9000"        - image: seldonio/mock_classifier:1.9.1          name: classifier-2          env:          - name: PREDICTIVE_UNIT_HTTP_SERVICE_PORT            value: "9001"        - image: seldonio/mock_classifier:1.9.1          name: classifier-3          env:          - name: PREDICTIVE_UNIT_HTTP_SERVICE_PORT            value: "9002"        - image: seldonio/mab_epsilon_greedy:1.9.1          name: eg-router          env:          - name: PREDICTIVE_UNIT_HTTP_SERVICE_PORT            value: "9003"         graph:      children:      - name: classifier-1        type: MODEL      - name: classifier-2        type: MODEL      - name: classifier-3        type: MODEL      name: eg-router      parameters:      - name: n_branches        type: INT        value: '3'      - name: epsilon        type: FLOAT        value: '0.3'      - name: verbose        type: BOOL        value: '1'      type: ROUTER    svcOrchSpec:      env:      - name: SELDON_ENABLE_ROUTING_INJECTION        value: 'true'    name: multi-models-predictor    replicas: 1
复制代码

说明如下:

  • graph 定义中模型推理的入口是 name 指定的 eg-router 容器,该容器使用多臂赌博机算法,从三个 childen 容器中选择一个模型服务,然后将推理请求发送给该 childen 容器模型服务处理

  • graph 中定义的 eg-router 容器和三个 children 容器,分别和 ComponentSpec 中定义了四个容器一一对应

  • eg-router 容器的多臂赌博机算法,是使用 1-epislon 的概率选择使用历史最佳模型,或者 epislon 概率选择其他模型服务

当 pod 启动后,使用 kubectl describe pod 可以看到,该 pod 内有五个容器(container)。除了上述 4 个容器外,还有一个 seldon-container-engine 容器。engine 容器负责编排上述四个容器,根据 graph 指定的类型(type)为 ROUTER,将先请求发送给 eg-router 获取 childern 容器的 index,然后根据这个 index 获取该容器的端口,完成最后的推理请求


可使用如下脚本,测试推理服务。其中 sys.argv[1]参数,使用 podIP+engine 端口(可通过 kubectl get pod -owide |grep seldon),或者 serviceIP+engine 端口(可通过命令 kubectl get svc -owide |grep seldon 获得)都可以。注:engine 端口号是 8000。

import requestsimport sys
url = "http://%s/api/v1.0/predictions" % sys.argv[1]req = {"data": {"ndarray": [[1.0, 2.0, 5.0]]}}res_raw = requests.post(url, json=req)print('status_code:', res_raw.status_code)print(res_raw.text)
复制代码

返回结果如下所示。注,本次请求使用的是 classifier-3 模型服务的推理结果。

{  "data":{    "names":["proba"],"ndarray":[[0.43782349911420193]]  },  "meta":{    "requestPath":{"classifier-3":"seldonio/mock_classifier:1.9.1"}  }}
复制代码

2 示例二(Transform):输入输出转换

该示例是 seldon 官方提供的,详细可查看https://docs.seldon.io/projects/seldon-core/en/latest/graph/inference-graph.html。创建 seldon-model.yaml,如下所示:

apiVersion: machinelearning.seldon.io/v1alpha2kind: SeldonDeploymentmetadata:  name: seldon-modelspec:  name: test-deployment  predictors:  - componentSpecs:    - spec:        containers:        - name: step_one          image: seldonio/step_one:1.0        - name: step_two          image: seldonio/step_two:1.0        - name: step_three          image: seldonio/step_three:1.0    graph:      name: step_one      endpoint:        type: REST      type: MODEL      children:          name: step_two          endpoint:            type: REST          type: MODEL          children:              name: step_three              endpoint:                type: REST              type: MODEL              children: []    name: example    replicas: 1
复制代码

说明:

  • graph 定义的模型推理入口是 step_one 容器,该容器负载完成 transformer-input(即输入特征转换,例如过滤,默认值,标准化等)

  • 然后模型推理服务由 step_one 容器的 children,即 step_two 容器完成

  • 最后,step_two 容器的推理结果,再由它的 children,即 step_three 容器完成

  • graph 所定义的三个容器,分别对应到 componentSpec 中定义的三个容器

  • 上述,step_one, step_two, step_three 三个容器的处理过程,同样是由 engine 容器编排完成的。

3 engine 服务如何实现

上面描述的两个推理服务编排(graph),它们都是由 engine 容器服务实现的。那么 engine 容器是如何实现的呢。

engine 容器实现的服务是一个 http 服务,我们这里只看它的主要接口 predictions。实现如下,详细可查看 executor/api/rest/server.go 源码文件

func (r *SeldonRestApi) predictions(w http.ResponseWriter, req *http.Request) {    seldonPredictorProcess := predictor.NewPredictorProcess(ctx, r.Client, logf.Log.WithName(LoggingRestClientName), r.ServerUrl, r.Namespace, req.Header, modelName)    reqPayload, err := seldonPredictorProcess.Client.Unmarshall(bodyBytes, req.Header.Get(http2.ContentType))    graphNode = &r.predictor.Graph    resPayload, err := seldonPredictorProcess.Predict(graphNode, reqPayload)    r.respondWithSuccess(w, http.StatusOK, resPayload)}
复制代码

说明:

  • 对于每个请求,创建一个 PredictorProcess。然后将反序列化后的请求,以及 Graph,做为参数,调用 PredictorProcess.Predict()方法,得到推理结果


Predict()方法处理过程如下,详细可查看 executor/predictor/predictor_process.go 源码:

func (p *PredictorProcess) Predict(node *v1.PredictiveUnit, msg payload.SeldonPayload) (payload.SeldonPayload, error) {    tmsg, err := p.transformInput(node, msg)    cmsg, err := p.predictChildren(node, tmsg)    response, err := p.transformOutput(node, cmsg)    return response, err}
复制代码

说明:

  • transformInput():如果 node 的 type 是 MODEL,则调用该节点的 Predict()方法处理。如果是 TRANSFORMER,则调用该节点的 TransformInput()方法处理。

  • predictChildren(): 如果该节点包含 children,且 type 是 ROUTER,则调用其 route()方法获得 index(即后续请求发给哪个 children 节点)

  • transformOutput(): 如果 node 的 type 是 TRANFORMER,则调用该节点的 TransformOutput()方法转换推理结果

总体,逻辑是比较清晰易懂的。这里只做简单介绍,可大致了解,如需要则可自行阅读源码。

4 总结

seldon 通过提供 engine 容器及其所定义的 type 和相应的逻辑,一定程度上满足了模型服务编排的需要。

通常编排服务,都会涉及到底层资源的信息,包括服务地址,如何寻址,通信方式等,这些细节,对于不同的底层资源,实现方式会有所不同。但是这些细节,却又不是模型服务所关心的。而 engine 容器,正好可以满足这种需求,即屏蔽了底层资源细节,同时又满足了模型服务编排(graph)的需求。


发布于: 2021 年 08 月 01 日阅读数: 3
用户头像

托内多

关注

享受coding,与时俱进 2017.10.24 加入

简单生活,砥砺前行

评论

发布
暂无评论
Seldon 使用 (五): engine & graph