深度學習模型服務是連線模型訓練和實際應用之間的橋樑,其設計的優劣直接影響模型的效能和應用效率。本文從一個通用的預測服務平台設計出發,該平台支援多種型別的模型,並透過路由元件將預測請求分發到對應的推理伺服器。接著,文章探討了圖執行元件和推理伺服器的角色和功能,並以自動化房貸審核流程為例,說明如何利用圖執行元件串接多個模型預測。此外,文章還分析了分享模型服務後端的優勢,以及如何新增應用程式而無需修改預測平台程式碼。最後,文章討論了典型的模型預測工作流程,以及模型服務的常見需求,例如模型佈署安全、延遲和監控等,並強調了這些需求在模型服務設計和最佳化中的重要性。
內容解密:
此圖表呈現了一個通用的預測服務(平台)設計,能夠支援任意型別的模型。它顯示了不同的應用程式如何透過統一的網頁API將預測請求傳送到系統,然後由路由元件根據模型的後設資料將請求路由到正確的推斷後端伺服器。每個推斷伺服器可以支援特定型別的模型,並從模型檔案伺服器取得所需的模型檔案。這個設計允許系統支援多種不同的模型和應用程式,提高了系統的可擴充套件性和靈活性。
模型服務設計:深度學習系統的核心
圖執行元件:串接多模型預測的關鍵
在深度學習系統中,圖執行元件(Graph Execution Component)扮演著至關重要的角色。它負責處理需要執行一系列模型預測的請求,例如自動化房貸審核流程。為了實作這一目標,我們需要定義一個有向無環圖(DAG)來描述模型執行的鏈條,並構建一個圖執行引擎來一次性執行這些模型。
推理伺服器:模型預測的實際執行者
推理伺服器(Inference Server)是模型預測的實際執行者,負責管理模型快取和模型預測執行。它與預測服務(Prediction Service)類別似,但需要支援任意模型演算法,因此更加複雜。除了預測 API 外,推理伺服器還應提供模型管理 API,以便程式化地註冊新模型和移除模型。
內容解密:
推理伺服器的設計比預測服務更加複雜,需要考慮多種因素,如模型演算法、框架和版本等。幸運的是,有許多開源的推理伺服器可供選擇,如 TensorFlow Serving、TorchServe 和 NVIDIA Triton Inference Server。這些工具可以幫助我們快速構建和佈署模型服務。
應用程式:分享模型服務後端
在圖 6.7 中,我們可以看到應用程式 A、B 和 C 分享相同的模型服務後端。這種設計使得模型服務對於不同的應用程式發生在同一地方,從而提高了可擴充套件性和成本效率。
內容解密:
這種設計使得新增應用程式 D(如語音轉文字指令碼應用程式)變得非常簡單,只需將語音指令碼模型上傳到模型檔案伺服器,並讓應用程式使用統一的預測 Web API 即可,無需對預測平台進行任何程式碼變更。
模型預測工作流程
在瞭解了每個關鍵元件之後,讓我們來看看典型的模型預測工作流程(圖 6.7)。首先,我們將模型檔案釋出到模型檔案伺服器,並更新路由元件的組態,以便路由元件知道應該將預測請求路由到哪個推理伺服器。其次,應用程式將預測請求傳送到預測系統的 Web API,然後由路由元件將請求路由到正確的推理伺服器。第三,推理伺服器將從模型檔案伺服器載入模型,將請求負載轉換為模型輸入,執行模型演算法,並傳回預測結果。
內容解密:
這個工作流程展示了模型預測的完整過程,從模型檔案的釋出到預測結果的傳回。每個步驟都需要仔細設計和最佳化,以確保模型的準確性和效率。
常見的預測服務需求
儘管我們強調設計預測服務應該從具體的使用案例開始,但不同的情況會導致不同的設計。在所有模型服務設計中,存在三個共同的需求:
- 模型佈署安全:無論選擇什麼樣的模型滾動策略和版本策略,我們都必須有辦法將模型回復到先前的狀態或版本。
- 延遲:Web 請求延遲是許多線上業務成功的關鍵因素。一旦我們構建了模型服務支援,下一步就是盡力減少平均預測回應時間。
- 監控和警示:模型服務是深度學習系統中最關鍵的服務,如果它宕機了,業務就會停止。實際業務執行在實時模型預測之上,如果服務宕機或服務延遲增加,客戶會立即受到影響。
內容解密:
這些需求是設計和最佳化模型服務時需要考慮的關鍵因素。透過滿足這些需求,我們可以確保模型服務的穩定性、效率和可靠性。
重點整理
- 模型可以由多個檔案組成,包括機器學習演算法、模型執行器(包裝器)和模型資料。
- 模型預測和模型推理在模型服務上下文中具有相同的含義。
- 直接模型嵌入、模型服務和模型伺服器是三種常見的模型服務策略。
- 設計模型服務系統時,首先要了解的是使用案例,以便決定哪種服務方法最合適。
- 成本效率是設計模型服務系統的主要目標,包括服務佈署、維護、監控、基礎設施和服務開發等成本。
模型服務實踐
在前一章中,我們討論了模型服務的概念,以及使用者場景和設計模式。在本章中,我們將重點關注這些概念在生產環境中的實際實作。
實踐模型服務的挑戰
實作模型服務的挑戰之一是我們有太多可能的實作方式。除了多種黑箱解決方案外,還有許多自定義和從頭開始構建全部或部分模型的選項。我們認為,教您如何選擇正確方法的最佳方式是透過具體的例子。
本章涵蓋內容
使用模型服務方法構建範例預測器 使用 TorchServe 和模型伺服器方法構建範例服務 介紹流行的開源模型服務函式庫和系統 解釋生產模型釋出流程 討論生產後模型監控
在本章中,我們實作了兩個範例服務,以展示兩種最常用的模型服務方法:一種使用自建模型服務容器,展示模型服務方法(第 7.1 節);另一種使用 TorchServe(PyTorch 模型的模型伺服器),展示模型伺服器方法(第 7.2 節)。這兩個服務都服務於第 3 章中訓練的意圖分類別模型。
7.1 模型服務範例
在本文中,我們將展示第一個範例預測服務。該服務採用模型服務方法(第 6.2.2 節),可用於單一模型(第 6.3.1 節)和多租戶應用程式(第 6.3.2 節)。
7.1.1 執行範例預測服務
列表 7.1 顯示如何在本地機器上執行範例預測服務。以下指令碼首先執行後端預測器,然後執行前端服務。
# step 1: start backend predictor service
docker build -t orca3/intent-classification-predictor:latest \
-f predictor/Dockerfile predictor
docker run --name intent-classification-predictor \
--network orca3 --rm -d -p "${ICP_PORT}":51001 \
-v "${MODEL_CACHE_DIR}":/models \
orca3/intent-classification-predictor:latest
# step 2: start the prediction service (the web api)
docker build -t orca3/services:latest -f \
services.dockerfile .
docker run --name prediction-service --network orca3 \
--rm -d -p "${PS_PORT}":51001 -v "${MODEL_CACHE_DIR}":/tmp/modelCache \
orca3/services:latest prediction-service.jar
#### 內容解密:
此指令碼分為兩個主要步驟:
- 構建並執行後端預測器服務:首先,透過 Dockerfile 構建一個名為
orca3/intent-classification-predictor:latest的 Docker 映象。然後,使用此映象執行一個名為intent-classification-predictor的容器,將主機的${ICP_PORT}埠對映到容器的51001埠,並將${MODEL_CACHE_DIR}目錄掛載到容器的/models目錄。 - 構建並執行預測服務(Web API):接著,構建一個名為
orca3/services:latest的 Docker 映象,並使用此映象執行一個名為prediction-service的容器,將主機的${PS_PORT}埠對映到容器的51001埠,同時將${MODEL_CACHE_DIR}目錄掛載到容器的/tmp/modelCache目錄。
7.1.2 服務設計
該範例服務由前端介面元件和後端預測器組成。前端元件負責託管公共預測 API、下載模型檔案到分享磁碟卷,並將預測請求轉發給後端預測器。後端預測器是一個自建的預測器容器,負責載入意圖分類別模型並執行這些模型以提供預測請求的服務。
此預測服務有兩個外部依賴:後設資料儲存服務和分享磁碟卷。後設資料儲存保持所有有關模型的資訊,例如模型演算法名稱、模型版本和模型 URL。
模型服務實踐中的系統設計與工作流程
在模型服務實踐中,系統設計和工作流程的規劃至關重要。圖7.1展示了一個範例模型服務系統的整體架構和端對端的工作流程。該系統包含前端服務、後端預測器、分享磁碟卷、後設資料儲存和雲端儲存等元件。
系統設計與工作流程概述
- 使用者傳送預測請求:使用者向預測服務(前端元件)傳送包含指定模型ID和文字字串(檔案)的預測請求。
- 前端服務取得模型後設資料:前端服務根據模型ID從後設資料儲存中取得模型後設資料。
- 下載模型檔案:如果模型檔案尚未下載,前端元件將從雲端儲存下載模型檔案到分享磁碟卷。
- 轉發推理請求:前端元件將推理請求轉發給後端預測器。
- 載入模型並執行預測:後端預測器從分享磁碟卷讀取模型檔案,載入意圖分類別模型到記憶體中,並執行模型預測,傳回預測結果給前端元件。
前端服務設計與內部工作流程
前端服務包含三個主要元件:網頁介面、預測器管理元件和自定義gRPC預測器後端客戶端。這些元件負責回應主機公開的gRPC模型服務API,並管理後端預測器的連線和通訊。
前端服務內部工作流程
- 使用者向網頁介面傳送意圖預測請求,包含模型ID A。
- 網頁介面呼叫預測器連線管理器來處理該請求。
- 預測器連線管理器查詢後設資料儲存以取得模型ID為A的模型後設資料。
- 根據模型演算法型別,預測器管理器選擇合適的預測器後端客戶端來處理請求。
- 自定義gRPC預測器後端客戶端檢查分享模型檔案磁碟上是否存在模型A的檔案。如果不存在,則使用模型URL下載模型檔案。
- 自定義gRPC預測器後端客戶端呼叫已註冊的模型預測器(在本例中為意圖預測器)。
前端服務模型服務程式碼解析
以下是PredictionService.java中的核心實作程式碼,展示了圖7.2中提到的預測工作流程。
public void predict(PredictRequest request, .. ..) {
.. ..
String runId = request.getRunId();
if (predictorManager.containsArtifact(runId)) {
artifactInfo = predictorManager.getArtifact(runId);
} else {
try {
artifactInfo = msClient.getArtifact(
GetArtifactRequest.newBuilder()
.setRunId(runId).build());
} catch (Exception ex) {
.. ..
}
}
# 步驟4:根據模型演算法型別選擇預測器後端客戶端
PredictorBackend predictor;
if (predictorManager.containsPredictor(
artifactInfo.getAlgorithm())) {
predictor = predictorManager.getPredictor(
artifactInfo.getAlgorithm());
} else {
.. ..
}
# 步驟5:使用選定的預測器客戶端下載模型檔案
predictor.downloadModel(runId, artifactInfo);
# 步驟6:使用選定的預測器客戶端呼叫其後端預測器進行模型服務
String r = predictor.predict(
artifactInfo, request.getDocument());
.. ..
}
程式碼解析
- 取得所需的模型ID(runId)。
- 從後設資料儲存中取得模型後設資料。
- 根據模型演算法型別選擇後端預測器。
- 使用選定的預測器客戶端下載模型檔案。
- 使用選定的預測器客戶端呼叫其後端預測器進行模型推理。
模型服務範例實作
預測API設計與實作
在前端服務中,我們僅提供一個名為Predict的API,用於發出預測請求。此請求包含兩個重要引數:runId和document。其中,runId不僅用於參照訓練服務中的模型訓練執行(詳見第三章),同時也可用作模型的唯一識別碼。document則是客戶端希望進行預測的文字內容。
透過使用Predict API,使用者可以指定一個意圖模型(透過runId)來預測給定文字字串(document)的意圖。以下程式碼展示了Predict API的gRPC合約定義(位於grpc-contract/src/main/proto/prediction_service.proto)。
service PredictionService {
rpc Predict(PredictRequest) returns (PredictResponse);
}
message PredictRequest {
string runId = 3;
string document = 4;
}
message PredictResponse {
string response = 1;
}
內容解密:
- 服務定義:定義了一個名為
PredictionService的gRPC服務,其中包含一個Predict方法,用於處理預測請求。 - 請求與回應訊息:定義了
PredictRequest和PredictResponse訊息,分別用於封裝預測請求和回應。 runId與document:在PredictRequest中,runId用於指定模型,而document則是待預測的文字內容。
預測器連線管理器設計
前端服務的一個重要角色是路由預測請求。給定一個預測請求,前端服務需要根據請求中指定的模型演算法型別找到正確的後端預測器。這一路由過程由PredictorConnectionManager負責。在我們的設計中,模型演算法與預測器之間的對映關係被預先定義在環境屬性中。當服務啟動時,PredictorConnectionManager會讀取這些對映關係,以便服務知道對於某種模型演算法型別應該使用哪個後端預測器。
以下程式碼展示了模型演算法與預測器之間的對映組態(位於config/config-docker-docker.properties)。
# 啟用演算法型別
ps.enabledPredictors=intent-classification
# 定義演算法與預測器的對映
predictors.intent-classification.host=Intent-classification-predictor
predictors.intent-classification.port=51001
predictors.intent-classification.techStack=customGrpc
內容解密:
- 啟用演算法型別:指定了目前啟用的預測器型別,例如意圖分類別。
- 對映組態:定義了意圖分類別演算法對應的預測器主機、埠和技術堆疊(此處為自定義的gRPC)。
PredictorConnectionManager初始化:在服務啟動時,讀取上述組態以初始化對應的預測器後端客戶端。
預測器後端客戶端實作
預測器客戶端是用於前端服務與不同預測器後端進行通訊的物件。根據設計,每種型別的預測器後端支援其自身的模型,並且擁有自己的客戶端進行通訊。這些客戶端由PredictorConnectionManager建立並儲存。每個預測器後端客戶端都實作了PredictorBackend介面,如下所示。
public interface PredictorBackend {
void downloadModel(String runId, GetArtifactResponse artifactResponse);
String predict(GetArtifactResponse artifact, String document);
void registerModel(GetArtifactResponse artifact);
}
內容解密:
downloadModel:下載指定模型的實作。predict:使用指定模型對給定的文字進行預測。registerModel:註冊模型的中繼資料。
在此範例中,意圖預測器的後端客戶端是CustomGrpcPredictorBackend。它透過gRPC協定與自建的意圖預測器容器進行通訊,如下所示。
public String predict(GetArtifactResponse artifact, String document) {
return stub.predictorPredict(PredictorPredictRequest
.newBuilder().setDocument(document)
.setRunId(artifact.getRunId())
.build()).getResponse();
}
內容解密:
predictorPredict:呼叫後端預測器的gRPC方法進行預測。PredictorPredictRequest:封裝了預測請求所需的資訊,包括文字內容和模型ID。- 回應處理:傳回後端預測器的回應結果。