TensorFlow Serving是一個適用於深度學習模型的推理服務引擎,支援將TensorFlow標準的SavedModel格式的模型部署為線上服務,並支援模型熱更新與模型版本管理等功能。本文為您介紹如何使用鏡像部署的方式部署TensorFlow Serving模型服務。
前提準備
模型檔案
使用TensorFlow Serving鏡像部署要求模型檔案儲存體在OSS,且模型檔案的儲存目錄需滿足以下要求:
模型版本目錄:每個模型至少包含一個模型版本目錄,且必須以數字命名,作為模型版本號碼,數字越大版本號碼越新。
模型檔案:模型版本目錄下存放匯出的SavedModel格式的模型檔案,服務會自動載入最大模型版本號碼目錄下的模型檔案。
操作步驟如下:
在OSS儲存空間中建立模型儲存目錄(例:
oss://examplebucket/models/tf_serving/),詳情請參見管理目錄。將模型檔案上傳到步驟1建立的目錄(您可以下載本文案例TensorFlowServing模型檔案使用),得到模型儲存目錄格式如下:
tf_serving ├── modelA │ └── 1 │ ├── saved_model.pb │ └── variables │ ├── variables.data-00000-of-00001 │ └── variables.index │ ├── modelB │ ├── 1 │ │ └── ... │ └── 2 │ └── ... │ └── modelC ├── 1 │ └── ... ├── 2 │ └── ... └── 3 └── ...
模型設定檔
通過設定檔的方式可以實現讓一個服務同時運行多個模型。如果您只需要部署單模型服務,可跳過本小節。
請根據如下說明建立設定檔並上傳到OSS(模型檔案準備小節中給出的案例檔案裡已有一個模型設定檔model_config.pbtxt,您可直接使用或按需修改)。本案例中將模型設定檔上傳到目錄oss://examplebucket/models/tf_serving/。
模型設定檔model_config.pbtxt內容樣本如下:
model_config_list {
config {
name: 'modelA'
base_path: '/models/modelA/'
model_platform: 'tensorflow'
model_version_policy{
all: {}
}
}
config {
name: 'modelB'
base_path: '/models/modelB/'
model_platform: 'tensorflow'
model_version_policy{
specific {
versions: 1
versions: 2
}
}
version_labels {
key: 'stable'
value: 1
}
version_labels {
key: 'canary'
value: 2
}
}
config {
name: 'modelC'
base_path: '/models/modelC/'
model_platform: 'tensorflow'
model_version_policy{
latest {
num_versions: 2
}
}
}
}其中關鍵配置說明如下:
參數 | 是否必選 | 描述 |
name | 否 | 自訂配置模型名稱。建議配置該參數,如果不配置模型名稱,則model_name為空白,後續無法調用該模型服務。 |
base_path | 是 | 配置模型儲存目錄在執行個體中的路徑,後續部署服務時用於讀模數型檔案。例如:掛載目錄為 |
model_version_policy | 否 | 表示模型版本載入策略。
|
version_labels | 否 | 為模型版本配置自訂標籤。如果沒有配置version_labels,那麼就只能通過版本號碼來區分模型版本,請求路徑為: 如果設定了version_labels,那麼就可以請求version label來指向指定的版本號碼 說明 標籤預設只能分配給已成功載入並啟動為服務的模型版本。若想要預先為尚未載入的模型版本分配標籤,需要在運行命令中設定啟動參數 |
部署服務
可以通過以下兩種方法來進行TensorFlow Serving的鏡像部署。
情境化模型部署:適用於基本情境部署。您只需配置幾個參數,即可一鍵部署TensorFlow Serving模型服務。
自訂模型部署:支援靈活調整更多配置選項,比如修改連接埠、配置模型檔案輪詢周期等。
TensorFlow Serving模型服務支援配置8501和8500兩種連接埠。
8501:支援HTTP請求,在8501連接埠啟動HTTP或REST服務。
8500:支援gRPC請求,在8500連接埠啟動gRPC服務。
情境化模型部署預設使用8501連接埠,無法修改。如果您需要使用8500連接埠,請選擇自訂模型部署。
情境化模型部署
具體操作步驟如下:
登入PAI控制台,在頁面上方選擇目標地區,並在右側選擇目標工作空間,然後單擊進入EAS。
在模型線上服務(EAS)頁面,單擊部署服務。然後在情境化模型部署地區,單擊TFServing部署。
在TFServing部署頁面配置參數。關鍵參數說明如下,其他參數配置說明,請參見自訂部署。
參數
描述
部署方式
支援以下兩種部署方式:
標準模型部署:用於部署單模型服務。
設定檔部署:用於部署多模型服務。
模型配置
部署方式選擇標準模型部署時,您需要配置模型檔案所在的OSS路徑。
部署方式選擇設定檔部署時,您需要配置以下參數:
OSS:選擇模型檔案所在的OSS路徑。
掛載路徑:掛載服務執行個體中的目標路徑,用來讀模數型檔案。
設定檔:選擇模型設定檔所在的OSS路徑。
參數配置樣本:
參數
單模型樣本(部署modelA)
多模型樣本
服務名稱
modela_scene
multi_scene
部署方式
選擇標準模型部署。
選擇設定檔部署。
模型配置
OSS:
oss://examplebucket/models/tf_serving/modelA/。OSS:
oss://examplebucket/models/tf_serving/。掛載路徑:/models
設定檔:
oss://examplebucket/models/tf_serving/model_config.pbtxt
參數配置完成後,單擊部署。
自訂模型部署
具體操作步驟如下:
登入PAI控制台,在頁面上方選擇目標地區,並在右側選擇目標工作空間,然後單擊進入EAS。
單擊部署服務,然後在自訂模型部署地區,單擊自訂部署。
在自訂部署頁面配置參數,關鍵參數說明如下,其他參數配置說明,請參見自訂部署。
參數
描述
鏡像配置
在官方鏡像列表中選擇tensorflow-serving和對應的鏡像名稱。建議選擇最新版本。
說明如果服務需要使用GPU,則鏡像版本必須選擇x.xx.x-gpu。
模型配置
支援多種方式配置模型檔案,這裡採用OSS類型。
Uri:選擇模型檔案所在的OSS路徑。
掛載路徑:掛載服務執行個體中的目標路徑,用來讀模數型檔案。
運行命令
tensorflow-serving的啟動參數,選擇tensorflow-serving鏡像會自動載入命令:
/usr/bin/tf_serving_entrypoint.sh,還需設定的參數說明如下。單模型部署啟動參數:
--model_name:模型名稱,用於服務要求中的URL。如果不配置,預設名稱為model。
--model_base_path:用於指定模型儲存目錄在執行個體中的路徑。如果不配置,預設路徑為
/models/model。
多模型部署啟動參數:
--model_config_file:必選。用來指定模型設定檔。
--model_config_file_poll_wait_seconds:選填。如果您希望在服務啟動後修改模型設定檔的內容,需要配置輪詢模型檔案的周期,單位為秒。服務會按照配置的時間定期讀模數型設定檔的內容。例如
--model_config_file_poll_wait_seconds=30表示服務每隔30秒讀取一次模型設定檔內容。說明當模型服務讀取新的模型設定檔時,只會執行新設定檔中的內容。例如:舊設定檔中包含模型A,而新設定檔將模型A刪除並增加了模型B的配置,那麼服務會卸載模型A並載入模型B。
--allow_version_labels_for_unavailable_models:選填。預設為false,如果您想預先為尚未載入的模型版本分配標籤,需要將該參數配置為true。例如
--allow_version_labels_for_unavailable_models=true。
參數配置樣本:
參數
單模型樣本(部署modelA)
多模型樣本
部署方式
選擇鏡像部署。
鏡像配置
選擇官方鏡像:tensorflow-serving>tensorflow-serving:2.14.1。
模型配置
模型類型選擇OSS。
Uri:
oss://examplebucket/models/tf_serving/。掛載路徑:配置為
/models。
運行命令
/usr/bin/tf_serving_entrypoint.sh --model_name=modelA --model_base_path=/models/modelA/usr/bin/tf_serving_entrypoint.sh --model_config_file=/models/model_config.pbtxt --model_config_file_poll_wait_seconds=30 --allow_version_labels_for_unavailable_models=true連接埠號碼預設為8501,服務將在8501連接埠啟動HTTP或REST服務,支援HTTP請求。若您需要該服務支援gRPC請求,需要執行以下操作:
環境資訊中連接埠號碼修改為8500。
環境資訊中開啟啟用GRPC開關。
服務配置中添加以下配置
"networking": { "path": "/" }
單擊部署。
發送服務要求
根據服務部署時運行命令中配置的連接埠號碼,分別支援HTTP和gRPC兩種請求協議。下面給出modelA的服務要求樣本。
測試資料準備
modelA是一個圖片分類模型,訓練資料集為Fashion-MNIST,樣本是28x28的灰階圖片,模型輸出是樣本屬於10個分類的機率值。為了測試方便,我們使用
[[[[1.0]] * 28] * 28]作為modelA服務要求的測試資料。請求樣本
HTTP請求
連接埠號碼配置為8501,服務支援HTTP請求。下表總結了單模型和多模型部署情況下的HTTP請求路徑:
單模型
多模型
路徑格式:
<service_url>/v1/models/<model_name>:predict其中:
情境化部署:<model_name> 不支援自訂配置,預設為model。
自訂部署:<model_name>為運行命令中配置的模型名稱,如果沒有配置,預設為model。
支援不指定版本和指定模型版本兩種請求方式,路徑格式如下:
不指定版本(預設載入最大版本):
<service_url>/v1/models/<model_name>:predict指定模型版本:
<service_url>/v1/models/<model_name>/versions/<version_num>:predict如果設定了version_labels:
<service_url>/v1/models/<model_name>/labels/<version label>:predict
其中,<model_name> 為模型設定檔中配置的模型名稱。
其中,<service_url> 是您部署的服務訪問地址。您可以在模型線上服務(EAS)頁面,單擊待調用服務服務方式列下的調用資訊,查看服務訪問地址。在使用控制台線上調試的時候,頁面已自動填滿該部分路徑。
以情境化部署單模型modelA為例,HTTP請求路徑為:
<service_url>/v1/models/model:predict。下面以此為例為您具體說明如何通過控制台線上調試和通過Python代碼發送服務要求:
線上調試
服務部署完成後,單擊服務操作列下的線上調試,線上調試請求參數中已填充<service_url>,在地址後增加路徑
/v1/models/model:predict,Body中佈建服務請求資料:{"signature_name": "serving_default", "instances": [[[[1.0], [1.0], [1.0], [1.0], [1.0], [1.0], [1.0], [1.0], [1.0], [1.0], [1.0], [1.0], [1.0], [1.0], [1.0], [1.0], [1.0], [1.0], [1.0], [1.0], [1.0], [1.0], [1.0], [1.0], [1.0], [1.0], [1.0], [1.0]], [[1.0], [1.0], [1.0], [1.0], [1.0], [1.0], [1.0], [1.0], [1.0], [1.0], [1.0], [1.0], [1.0], [1.0], [1.0], [1.0], [1.0], [1.0], [1.0], [1.0], [1.0], [1.0], [1.0], [1.0], [1.0], [1.0], [1.0], [1.0]], [[1.0], [1.0], [1.0], [1.0], [1.0], [1.0], [1.0], [1.0], [1.0], [1.0], [1.0], [1.0], [1.0], [1.0], [1.0], [1.0], [1.0], [1.0], [1.0], [1.0], [1.0], [1.0], [1.0], [1.0], [1.0], [1.0], [1.0], [1.0]], [[1.0], [1.0], [1.0], [1.0], [1.0], [1.0], [1.0], [1.0], [1.0], [1.0], [1.0], [1.0], [1.0], [1.0], [1.0], [1.0], [1.0], [1.0], [1.0], [1.0], [1.0], [1.0], [1.0], [1.0], [1.0], [1.0], [1.0], [1.0]], [[1.0], [1.0], [1.0], [1.0], [1.0], [1.0], [1.0], [1.0], [1.0], [1.0], [1.0], [1.0], [1.0], [1.0], [1.0], [1.0], [1.0], [1.0], [1.0], [1.0], [1.0], [1.0], [1.0], [1.0], [1.0], [1.0], [1.0], [1.0]], [[1.0], [1.0], [1.0], [1.0], [1.0], [1.0], [1.0], [1.0], [1.0], [1.0], [1.0], [1.0], [1.0], [1.0], [1.0], [1.0], [1.0], [1.0], [1.0], [1.0], [1.0], [1.0], [1.0], [1.0], [1.0], [1.0], [1.0], [1.0]], [[1.0], [1.0], [1.0], [1.0], [1.0], [1.0], [1.0], [1.0], [1.0], [1.0], [1.0], [1.0], [1.0], [1.0], [1.0], [1.0], [1.0], [1.0], [1.0], [1.0], [1.0], [1.0], [1.0], [1.0], [1.0], [1.0], [1.0], [1.0]], [[1.0], [1.0], [1.0], [1.0], [1.0], [1.0], [1.0], [1.0], [1.0], [1.0], [1.0], [1.0], [1.0], [1.0], [1.0], [1.0], [1.0], [1.0], [1.0], [1.0], [1.0], [1.0], [1.0], [1.0], [1.0], [1.0], [1.0], [1.0]], [[1.0], [1.0], [1.0], [1.0], [1.0], [1.0], [1.0], [1.0], [1.0], [1.0], [1.0], [1.0], [1.0], [1.0], [1.0], [1.0], [1.0], [1.0], [1.0], [1.0], [1.0], [1.0], [1.0], [1.0], [1.0], [1.0], [1.0], [1.0]], [[1.0], [1.0], [1.0], [1.0], [1.0], [1.0], [1.0], [1.0], [1.0], [1.0], [1.0], [1.0], [1.0], [1.0], [1.0], [1.0], [1.0], [1.0], [1.0], [1.0], [1.0], [1.0], [1.0], [1.0], [1.0], [1.0], [1.0], [1.0]], [[1.0], [1.0], [1.0], [1.0], [1.0], [1.0], [1.0], [1.0], [1.0], [1.0], [1.0], [1.0], [1.0], [1.0], [1.0], [1.0], [1.0], [1.0], [1.0], [1.0], [1.0], [1.0], [1.0], [1.0], [1.0], [1.0], [1.0], [1.0]], [[1.0], [1.0], [1.0], [1.0], [1.0], [1.0], [1.0], [1.0], [1.0], [1.0], [1.0], [1.0], [1.0], [1.0], [1.0], [1.0], [1.0], [1.0], [1.0], [1.0], [1.0], [1.0], [1.0], [1.0], [1.0], [1.0], [1.0], [1.0]], [[1.0], [1.0], [1.0], [1.0], [1.0], [1.0], [1.0], [1.0], [1.0], [1.0], [1.0], [1.0], [1.0], [1.0], [1.0], [1.0], [1.0], [1.0], [1.0], [1.0], [1.0], [1.0], [1.0], [1.0], [1.0], [1.0], [1.0], [1.0]], [[1.0], [1.0], [1.0], [1.0], [1.0], [1.0], [1.0], [1.0], [1.0], [1.0], [1.0], [1.0], [1.0], [1.0], [1.0], [1.0], [1.0], [1.0], [1.0], [1.0], [1.0], [1.0], [1.0], [1.0], [1.0], [1.0], [1.0], [1.0]], [[1.0], [1.0], [1.0], [1.0], [1.0], [1.0], [1.0], [1.0], [1.0], [1.0], [1.0], [1.0], [1.0], [1.0], [1.0], [1.0], [1.0], [1.0], [1.0], [1.0], [1.0], [1.0], [1.0], [1.0], [1.0], [1.0], [1.0], [1.0]], [[1.0], [1.0], [1.0], [1.0], [1.0], [1.0], [1.0], [1.0], [1.0], [1.0], [1.0], [1.0], [1.0], [1.0], [1.0], [1.0], [1.0], [1.0], [1.0], [1.0], [1.0], [1.0], [1.0], [1.0], [1.0], [1.0], [1.0], [1.0]], [[1.0], [1.0], [1.0], [1.0], [1.0], [1.0], [1.0], [1.0], [1.0], [1.0], [1.0], [1.0], [1.0], [1.0], [1.0], [1.0], [1.0], [1.0], [1.0], [1.0], [1.0], [1.0], [1.0], [1.0], [1.0], [1.0], [1.0], [1.0]], [[1.0], [1.0], [1.0], [1.0], [1.0], [1.0], [1.0], [1.0], [1.0], [1.0], [1.0], [1.0], [1.0], [1.0], [1.0], [1.0], [1.0], [1.0], [1.0], [1.0], [1.0], [1.0], [1.0], [1.0], [1.0], [1.0], [1.0], [1.0]], [[1.0], [1.0], [1.0], [1.0], [1.0], [1.0], [1.0], [1.0], [1.0], [1.0], [1.0], [1.0], [1.0], [1.0], [1.0], [1.0], [1.0], [1.0], [1.0], [1.0], [1.0], [1.0], [1.0], [1.0], [1.0], [1.0], [1.0], [1.0]], [[1.0], [1.0], [1.0], [1.0], [1.0], [1.0], [1.0], [1.0], [1.0], [1.0], [1.0], [1.0], [1.0], [1.0], [1.0], [1.0], [1.0], [1.0], [1.0], [1.0], [1.0], [1.0], [1.0], [1.0], [1.0], [1.0], [1.0], [1.0]], [[1.0], [1.0], [1.0], [1.0], [1.0], [1.0], [1.0], [1.0], [1.0], [1.0], [1.0], [1.0], [1.0], [1.0], [1.0], [1.0], [1.0], [1.0], [1.0], [1.0], [1.0], [1.0], [1.0], [1.0], [1.0], [1.0], [1.0], [1.0]], [[1.0], [1.0], [1.0], [1.0], [1.0], [1.0], [1.0], [1.0], [1.0], [1.0], [1.0], [1.0], [1.0], [1.0], [1.0], [1.0], [1.0], [1.0], [1.0], [1.0], [1.0], [1.0], [1.0], [1.0], [1.0], [1.0], [1.0], [1.0]], [[1.0], [1.0], [1.0], [1.0], [1.0], [1.0], [1.0], [1.0], [1.0], [1.0], [1.0], [1.0], [1.0], [1.0], [1.0], [1.0], [1.0], [1.0], [1.0], [1.0], [1.0], [1.0], [1.0], [1.0], [1.0], [1.0], [1.0], [1.0]], [[1.0], [1.0], [1.0], [1.0], [1.0], [1.0], [1.0], [1.0], [1.0], [1.0], [1.0], [1.0], [1.0], [1.0], [1.0], [1.0], [1.0], [1.0], [1.0], [1.0], [1.0], [1.0], [1.0], [1.0], [1.0], [1.0], [1.0], [1.0]], [[1.0], [1.0], [1.0], [1.0], [1.0], [1.0], [1.0], [1.0], [1.0], [1.0], [1.0], [1.0], [1.0], [1.0], [1.0], [1.0], [1.0], [1.0], [1.0], [1.0], [1.0], [1.0], [1.0], [1.0], [1.0], [1.0], [1.0], [1.0]], [[1.0], [1.0], [1.0], [1.0], [1.0], [1.0], [1.0], [1.0], [1.0], [1.0], [1.0], [1.0], [1.0], [1.0], [1.0], [1.0], [1.0], [1.0], [1.0], [1.0], [1.0], [1.0], [1.0], [1.0], [1.0], [1.0], [1.0], [1.0]], [[1.0], [1.0], [1.0], [1.0], [1.0], [1.0], [1.0], [1.0], [1.0], [1.0], [1.0], [1.0], [1.0], [1.0], [1.0], [1.0], [1.0], [1.0], [1.0], [1.0], [1.0], [1.0], [1.0], [1.0], [1.0], [1.0], [1.0], [1.0]], [[1.0], [1.0], [1.0], [1.0], [1.0], [1.0], [1.0], [1.0], [1.0], [1.0], [1.0], [1.0], [1.0], [1.0], [1.0], [1.0], [1.0], [1.0], [1.0], [1.0], [1.0], [1.0], [1.0], [1.0], [1.0], [1.0], [1.0], [1.0]]]]}參數配置完成後,單擊發送請求,輸出如下類似結果。

通過Python代碼發送HTTP請求
Python程式碼範例如下:
from urllib import request import json # 請替換為你的服務訪問地址和Token。 # 您可以在推理服務列表的服務方式列單擊調用資訊,在公網地址調用頁簽查看。 service_url = '<service_url>' token = '<test-token>' # 情境化單模型部署為 model,其他情況參照上面路徑說明表格 model_name = "model" url = "{}/v1/models/{}:predict".format(service_url, model_name) # 建立HTTP請求。 req = request.Request(url, method="POST") req.add_header('authorization', token) data = { 'signature_name': 'serving_default', 'instances': [[[[1.0]] * 28] * 28] } # 請求服務。 response = request.urlopen(req, data=json.dumps(data).encode('utf-8')).read() # 查看返回結果。 response = json.loads(response) print(response)gRPC請求
連接埠號碼配置為8500,並添加gRPC相關配置後,服務支援發送gRPC請求。Python程式碼範例如下:
import grpc import tensorflow as tf from tensorflow_serving.apis import predict_pb2 from tensorflow_serving.apis import prediction_service_pb2_grpc from tensorflow.core.framework import tensor_shape_pb2 # 服務訪問地址。格式參見下面的host參數說明。 host = "tf-serving-multi-grpc-test.166233998075****.cn-hangzhou.pai-eas.aliyuncs.com:80" # test-token替換為服務Token。您可以在公網地址調用頁簽查看Token。 token = "<test-token>" # 模型名稱。參見下面的name參數說明。 name = "<model_name>" signature_name = "serving_default" # 配置為模型版本號碼。每次只能對單個模型版本發送請求。 version = "<version_num>" # 建立gRPC請求。 request = predict_pb2.PredictRequest() request.model_spec.name = name request.model_spec.signature_name = signature_name request.model_spec.version.value = version request.inputs["keras_tensor"].CopyFrom(tf.make_tensor_proto([[[[1.0]] * 28] * 28])) # 請求服務。 channel = grpc.insecure_channel(host) stub = prediction_service_pb2_grpc.PredictionServiceStub(channel) metadata = (("authorization", token),) response, _ = stub.Predict.with_call(request, metadata=metadata) print(response)其中關鍵參數配置如下:
參數
描述
host
需要配置為服務訪問地址,服務訪問地址需要省略
http://並在末尾添加:80。您可以在模型線上服務(EAS)頁面,單擊待調用服務服務方式列下的調用資訊,查看服務訪問地址。name
單模型發送gRPC請求:
情境化部署:配置為model。
自訂部署:配置為運行命令中配置的模型名稱,如果運行命令中沒有配置,預設值為model。
多模型發送gRPC請求:
配置為模型設定檔中配置的模型名稱。
version
配置為模型版本號碼。每次只能對單個模型版本發送請求。
metadata
配置為服務Token。您可以在調用資訊頁面查看Token。
相關文檔
如何基於Triton Server推理服務引擎部署EAS服務,請參見Triton Inference Server鏡像部署。
您也可以開發自訂鏡像,使用自訂鏡像部署EAS服務。具體操作,請參見自訂鏡像。