KubeDL 0.4.0 - Kubernetes AI 模型版本管理与追踪
作者:陳裘凱( 求索)
前言
KubeDL 是阿里開源的基于 Kubernetes 的 AI 工作負載管理框架,取自"Kubernetes-Deep-Learning"的縮寫,希望能夠依托阿里巴巴的場景,將大規模機器學習作業調度與管理的經驗反哺社區。目前 KubeDL 已經進入 CNCF Sandbox 項目孵化,我們會不斷探索云原生 AI 場景中的最佳實踐,助力算法科學家們簡單高效地實現創新落地。
在最新的 KubeDL Release 0.4.0 版本中,我們帶來了模型版本管理(ModelVersion)的能力,AI 科學家們可以像管理鏡像一樣輕松地對模型版本進行追蹤,打標及存儲。更重要的是,在經典的機器學習流水線中,“訓練”與“推理”兩個階段相對獨立,算法科學家視角中的“訓練->模型->推理”流水線缺乏斷層,而“模型”作為兩者的中間產物正好能夠充當那個“承前啟后”的角色。
Github:??https://github.com/kubedl-io/kubedl??
網站:??https://kubedl.io/model/intro/ ??
模型管理現狀
模型文件是分布式訓練的產物,是經過充分迭代與搜索后保留的算法精華,在工業界算法模型已經成為了寶貴的數字資產。通常不同的分布式框架會輸出不同格式的模型文件,如 Tensorflow 訓練作業通常輸出 CheckPoint(.ckpt)、GraphDef(.pb)、SavedModel 等格式,而 PyTorch 則通常以 .pth 后綴,不同的框架會在加載模型時解析其中承載的運行時的數據流圖、運行參數及其權重等信息,對于文件系統來說,它們都是一個(或一組)特殊格式的文件,就像 JPEG 和 PNG 格式的圖像文件一樣。
因此典型的管理方式就是把它們當作文件,托管在統一的對象存儲中(如阿里云 OSS 和AWS S3),每個租戶/團隊分配一個目錄,各自成員再把模型文件存儲在自己對應的子目錄中,由 SRE 來統一進行讀寫權限的管控:
這種管理方式的優缺點都很明顯:
-
好處是保留了用戶的 API 使用習慣,在訓練代碼中將自己的目錄指定為輸出路徑,之后將云存儲的對應目錄 mount 到推理服務的容器內加載模型即可;
-
但這對 SRE 提出了較高的要求,不合理的讀寫權限授權及誤操作,可能造成文件權限泄露,甚至大面積的誤刪除;同時基于文件的管理方式不易實現模型的版本管理,通常要求用戶自身根據文件名來標記,或是上層平臺自己承擔版本管理的復雜度;此外,模型文件與算法代碼/訓練參數的對應關系也無法直接映射,甚至同個文件在多次訓練中會被多次覆寫,難以追溯歷史;
基于以上現狀,KubeDL 充分結合了 Docker 鏡像管理的優勢,引入了一套 Image-Based 的鏡像管理 API,讓分布式訓練和推理服務結合得更緊密自然,同時也極大簡化了模型管理的復雜度。
從鏡像出發
鏡像(Image)是 Docker 的靈魂,也是容器時代的核心基礎設施。鏡像本身即分層的不可變文件系統,模型文件天然地可以作為其中的一個獨立鏡像層,兩者結合的還會迸發出其他火花:
-
用戶不用再面向文件管理模型,而是直接使用 KubeDL 提供的 ModelVersion API 即可,訓練與推理服務之間通過 ModelVersion API 橋接;
-
與鏡像一樣,可以對模型打 Tag 實現版本追溯,并推送到統一的鏡像 Registry 存儲,通過 Registry 進行鑒權,同時鏡像 Registry 的存儲后端還可以替換成用戶自己的 OSS/S3,用戶可以平滑過渡;
-
模型鏡像一旦構建完畢,即成為只讀的模板,無法再被覆蓋及篡寫,踐行 Serverless “不可變基礎設施” 的理念;
-
鏡像層(Layer)通過壓縮算法及哈希去重,減少模型文件存儲的成本并加快了分發的效率;
在“模型鏡像化”的基礎上,還可以充分結合開源的鏡像管理組件,最大化鏡像帶來的優勢:
-
大規模的推理服務擴容場景中,可以通過?Dragonfly 來加速鏡像分發效率,面對流量突發型場景時可以快速彈出無狀態的推理服務實例,同時避免了掛載云存儲卷可能出現的大規模實例并發讀時的限流問題;
-
日常的推理服務部署,也可以通過 OpenKruise 中的?ImagePullJob 來提前對節點上的模型鏡像進行預熱,提升擴容發布的效率。
Model 與 ModelVersion
KubeDL 模型管理引入了 2 個資源對象:Model 及 ModelVersion,Model 代表某個具體的模型,ModelVersion 則表示該模型迭代過程中的一個具體版本,一組 ModelVersion 從同一個 Model 派生而來。以下是示例:
apiVersion: model.kubedl.io/v1alpha1 kind: ModelVersion metadata:name: my-mvnamespace: default spec:# The model name for the model versionmodelName: model1# The entity (user or training job) that creates the modelcreatedBy: user1# The image repo to push the generated modelimageRepo: modelhub/resnetimageTag: v0.1# The storage will be mounted at /kubedl-model inside the training container.# Therefore, the training code should export the model at /kubedl-model path.storage:# The local storage to store the modellocalStorage:# The local host path to export the modelpath: /foo# The node where the chief worker run to export the modelnodeName: kind-control-plane# The remote NAS to store the modelnfs:# The NFS server addressserver: ***.cn-beijing.nas.aliyuncs.com# The path under which the model is storedpath: /foo# The mounted path inside the containermountPath: /kubedl/models--- apiVersion: model.kubedl.io/v1alpha1 kind: Model metadata:name: model1 spec: description: "this is my model" status:latestVersion:imageName: modelhub/resnet:v1c072modelVersion: mv-3Model 資源本身只對應某類模型的描述,并追蹤最新的版本的模型及其鏡像名告知給用戶,用戶主要通過 ModelVersion 來自定義模型的配置:
-
modelName: 用來指向對應的模型名稱;
-
createBy: 創建該 ModelVersion 的實體,用來追溯上游的生產者,通常是一個分布式訓練作業;
-
imageRepo: 鏡像 Registry 的地址,構建完成模型鏡像后將鏡像推送到該地址;
-
storage: 模型文件的存儲載體,當前我們支持了 NAS,AWSEfs 和 LocalStorage 三種存儲介質,未來會支持更多主流的存儲方式。以上的例子中展示了兩種模型輸出的方式(本地存儲卷和 NAS 存儲卷),一般只允許指定一種存儲方式。
當 KubeDL 監聽到 ModelVersion 的創建時,便會觸發模型構建的工作流:
至此,該 ModelVersion 對應版本的模型便固化在了鏡像倉庫中,可以分發給后續的推理服務進行消費。
從訓練到模型
雖然 ModelVersion 支持獨立創建并發起構建,但我們更期望在分布式訓練作業成功結束后自動觸發模型的構建,天然串聯成一個流水線。
KubeDL 支持這種提交方式,以 TFJob 作業為例,在發起分布式訓練時即指定好模型文件的輸出路徑和推送的倉庫地址,當作業成功執行完畢時就會自動創建出一個 ModelVersion 對象,并將 createdBy 指向上游的作業名,而當作業執行失敗或提前終止時并不會觸發 ModelVersion 的創建。
以下是一個分布式 mnist 訓練的例子,其將模型文件輸出到本地節點的???/models/model-example-v1???路徑,當順利運行結束后即觸發模型的構建:
apiVersion: "training.kubedl.io/v1alpha1" kind: "TFJob" metadata:name: "tf-mnist-estimator" spec:cleanPodPolicy: None# modelVersion defines the location where the model is stored.modelVersion:modelName: mnist-model-demo# The dockerhub repo to push the generated imageimageRepo: simoncqk/modelsstorage:localStorage:path: /models/model-example-v1mountPath: /kubedl-modelnodeName: kind-control-planetfReplicaSpecs:Worker:replicas: 3restartPolicy: Nevertemplate:spec:containers:- name: tensorflowimage: kubedl/tf-mnist-estimator-api:v0.1imagePullPolicy: Alwayscommand:- "python"- "/keras_model_to_estimator.py"- "/tmp/tfkeras_example/" # model checkpoint dir- "/kubedl-model" # export dir for the saved_model format % kubectl get tfjob NAME STATE AGE MAX-LIFETIME MODEL-VERSION tf-mnist-estimator Succeeded 10min mnist-model-demo-e7d65 % kubectl get modelversion NAME MODEL IMAGE CREATED-BY FINISH-TIME mnist-model-demo-e7d65 tf-mnist-model-example simoncqk/models:v19a00 tf-mnist-estimator 2021-09-19T15:20:42Z % kubectl get po NAME READY STATUS RESTARTS AGE image-build-tf-mnist-estimator-v19a00 0/1 Completed 0 9min通過這種機制,還可以將其他“僅當作業執行成功才會輸出的 Artifacts 文件”一起固化到鏡像中,并在后續的階段中使用。
從模型到推理
有了前面的基礎,在部署推理服務時直接引用已構建好的 ModelVersion,便能加載對應模型并直接對外提供推理服務。至此,算法模型生命周期(代碼->訓練->模型->部署上線)各階段通過模型相關的 API 聯結了起來。
通過 KubeDL 提供的 Inference 資源對象部署一個推理服務時,只需在某個 predictor 模板中填充對應的 ModelVersion 名,Inference Controller 在創建 predictor 時會注入一個 Model Loader,它會拉取承載了模型文件的鏡像到本地,并通過容器間共享 Volume 的方式把模型文件掛載到主容器中,實現模型的加載。如上文所述,與 OpenKruise 的 ImagePullJob 相結合我們能很方便地實現模型鏡像預熱,來為模型的加載提速。為了用戶感知的一致性,推理服務的模型掛載路徑與分布式訓練作業的模型輸出路徑默認是一致的。
apiVersion: serving.kubedl.io/v1alpha1 kind: Inference metadata:name: hello-inference spec:framework: TFServingpredictors:- name: model-predictor# model built in previous stage.modelVersion: mnist-model-demo-abcdereplicas: 3batching:batchSize: 32template:spec:containers:- name: tensorflowargs:- --port=9000- --rest_api_port=8500- --model_name=mnist- --model_base_path=/kubedl-model/command:- /usr/bin/tensorflow_model_serverimage: tensorflow/serving:1.11.1imagePullPolicy: IfNotPresentports:- containerPort: 9000- containerPort: 8500resources:limits:cpu: 2048mmemory: 2Girequests:cpu: 1024mmemory: 1Gi對于一個完整的推理服務,可能同時 Serve 多個不同模型版本的 predictor,比如在常見搜索推薦的場景中,期望以 A/B Testing 實驗來同時對比多次模型迭代的效果,通過 Inference+ModelVersion 可以很容易做到。我們對不同的 predictor 引用不同版本的模型,并分配合理權重的流量,即可達到一個推理服務下同時 Serve 不同版本的模型并灰度比較效果的目的:
apiVersion: serving.kubedl.io/v1alpha1 kind: Inference metadata:name: hello-inference-multi-versions spec:framework: TFServingpredictors:- name: model-a-predictor-1modelVersion: model-a-version1replicas: 3trafficWeight: 30 # 30% traffic will be routed to this predictor.batching:batchSize: 32template:spec:containers:- name: tensorflow// ...- name: model-a-predictor-2modelVersion: model-version2replicas: 3trafficWeight: 50 # 50% traffic will be roted to this predictor.batching:batchSize: 32template:spec:containers:- name: tensorflow// ...- name: model-a-predictor-3modelVersion: model-version3replicas: 3trafficWeight: 20 # 20% traffic will be roted to this predictor.batching:batchSize: 32template:spec:containers:- name: tensorflow// ...總結
KubeDL 通過引入 Model 和 ModelVersion 兩種資源對象,與標準的容器鏡像相結合實現了模型構建,打標與版本追溯,不可變存儲與分發等功能,解放了粗放型的模型文件管理模式,鏡像化還可以與其他優秀的開源社區相結合,實現鏡像分發加速,模型鏡像預熱等功能,提升模型部署的效率。同時,模型管理 API 的引入很好地連接了分布式訓練與推理服務兩個原本割裂的階段,顯著提升了機器學習流水線的自動化程度,以及算法科學家上線模型、實驗對比的體驗和效率。我們歡迎更多的用戶試用 KubeDL,并向我們提出寶貴的意見,也期待有更多的開發者關注以及參與 KubeDL 社區的建設!
KubeDL Github 地址:
??https://github.com/kubedl-io/kubedl??
戳??此處??,立即了解 KubeDL 項目!
總結
以上是生活随笔為你收集整理的KubeDL 0.4.0 - Kubernetes AI 模型版本管理与追踪的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 重新定义分析 - EventBridge
- 下一篇: 联发科mt8516价格_智能语音助手宠儿