本教學課程說明如何使用 TensorFlow Serving 元件來建構標準 TensorFlow ModelServer,以動態探索及服務已訓練 TensorFlow 模型的新版本。如果您只想使用標準伺服器來服務模型,請參閱TensorFlow Serving 基本教學課程。
本教學課程使用 TensorFlow 教學課程中針對手寫影像 (MNIST 資料) 分類所介紹的簡單 Softmax 迴歸模型。如果您不知道 TensorFlow 或 MNIST 是什麼,請參閱適合 ML 初學者的 MNIST 教學課程。
本教學課程的程式碼包含兩個部分
Python 檔案 mnist_saved_model.py,用於訓練及匯出多個模型版本。
C++ 檔案 main.cc,此檔案是標準 TensorFlow ModelServer,可探索新的匯出模型並執行 gRPC 服務以服務這些模型。
本教學課程逐步說明下列工作
- 訓練及匯出 TensorFlow 模型。
- 使用 TensorFlow Serving
ServerCore
管理模型版本控制。 - 使用
SavedModelBundleSourceAdapterConfig
設定批次處理。 - 使用 TensorFlow Serving
ServerCore
服務要求。 - 執行及測試服務。
開始之前,請先安裝 Docker
訓練及匯出 TensorFlow 模型
首先,如果您尚未執行此操作,請將此存放區複製到您的本機電腦
git clone https://github.com/tensorflow/serving.git
cd serving
清除匯出目錄 (如果已存在)
rm -rf /tmp/models
訓練 (100 次迭代) 並匯出模型的第一個版本
tools/run_in_docker.sh python tensorflow_serving/example/mnist_saved_model.py \
--training_iteration=100 --model_version=1 /tmp/mnist
訓練 (2000 次迭代) 並匯出模型的第二個版本
tools/run_in_docker.sh python tensorflow_serving/example/mnist_saved_model.py \
--training_iteration=2000 --model_version=2 /tmp/mnist
如您在 mnist_saved_model.py
中所見,訓練和匯出的方式與 TensorFlow Serving 基本教學課程中的方式相同。為了示範目的,您刻意調降第一次執行的訓練迭代次數,並將其匯出為 v1,同時正常訓練第二次執行並將其匯出為 v2 到相同的父目錄,因為我們預期後者由於更密集的訓練而能達到更好的分類準確度。您應該會在 /tmp/mnist
目錄中看到每次訓練執行的訓練資料
$ ls /tmp/mnist
1 2
ServerCore
現在想像一下,模型的 v1 和 v2 是在執行階段動態產生,因為正在實驗新的演算法,或是模型正在使用新的資料集進行訓練。在生產環境中,您可能會想要建構一個伺服器,以支援逐步推出,其中 v2 可以在服務 v1 時探索、載入、實驗、監控或還原。或者,您可能會想要在啟動 v2 之前拆除 v1。TensorFlow Serving 支援這兩種選項,其中一種適用於在轉換期間維持可用性,另一種適用於盡可能減少資源用量 (例如 RAM)。
TensorFlow Serving Manager
正是如此。它處理 TensorFlow 模型的完整生命週期,包括載入、服務和卸載模型,以及版本轉換。在本教學課程中,您將在 TensorFlow Serving ServerCore
之上建構伺服器,後者在內部包裝了 AspiredVersionsManager
。
int main(int argc, char** argv) {
...
ServerCore::Options options;
options.model_server_config = model_server_config;
options.servable_state_monitor_creator = &CreateServableStateMonitor;
options.custom_model_config_loader = &LoadCustomModelConfig;
::google::protobuf::Any source_adapter_config;
SavedModelBundleSourceAdapterConfig
saved_model_bundle_source_adapter_config;
source_adapter_config.PackFrom(saved_model_bundle_source_adapter_config);
(*(*options.platform_config_map.mutable_platform_configs())
[kTensorFlowModelPlatform].mutable_source_adapter_config()) =
source_adapter_config;
std::unique_ptr<ServerCore> core;
TF_CHECK_OK(ServerCore::Create(options, &core));
RunServer(port, std::move(core));
return 0;
}
ServerCore::Create()
採用 ServerCore::Options 參數。以下是一些常用的選項
ModelServerConfig
,用於指定要載入的模型。模型可透過model_config_list
(宣告模型的靜態清單) 或custom_model_config
(定義自訂方式來宣告可能會在執行階段更新的模型清單) 來宣告。PlatformConfigMap
,從平台名稱 (例如tensorflow
) 對應到PlatformConfig
,後者用於建立SourceAdapter
。SourceAdapter
會將StoragePath
(探索到模型版本的路徑) 調整為模型Loader
(從儲存路徑載入模型版本,並為Manager
提供狀態轉換介面)。如果PlatformConfig
包含SavedModelBundleSourceAdapterConfig
,則會建立SavedModelBundleSourceAdapter
,我們稍後會說明。
SavedModelBundle
是 TensorFlow Serving 的主要元件。它代表從給定路徑載入的 TensorFlow 模型,並提供與 TensorFlow 相同的 Session::Run
介面來執行推論。SavedModelBundleSourceAdapter
會將儲存路徑調整為 Loader<SavedModelBundle>
,以便模型生命週期可以由 Manager
管理。請注意,SavedModelBundle
是已淘汰 SessionBundle
的後繼者。建議使用者使用 SavedModelBundle
,因為很快就會移除對 SessionBundle
的支援。
有了這些,ServerCore
在內部會執行下列操作
- 例項化
FileSystemStoragePathSource
,以監控在model_config_list
中宣告的模型匯出路徑。 - 使用
PlatformConfigMap
和在model_config_list
中宣告的模型平台來例項化SourceAdapter
,並將FileSystemStoragePathSource
連接到它。這樣一來,每當在匯出路徑下探索到新的模型版本時,SavedModelBundleSourceAdapter
就會將其調整為Loader<SavedModelBundle>
。 - 例項化
Manager
的特定實作,稱為AspiredVersionsManager
,用於管理SavedModelBundleSourceAdapter
建立的所有這類Loader
例項。ServerCore
透過將呼叫委派給AspiredVersionsManager
來匯出Manager
介面。
每當有新版本可用時,此 AspiredVersionsManager
就會載入新版本,並在其預設行為下卸載舊版本。如果您想要開始自訂,建議您瞭解其內部建立的元件,以及如何設定這些元件。
值得一提的是,TensorFlow Serving 從頭開始設計,具有高度彈性和可擴充性。您可以建構各種外掛程式來自訂系統行為,同時利用泛型核心元件,例如 ServerCore
和 AspiredVersionsManager
。例如,您可以建構一個資料來源外掛程式來監控雲端儲存空間,而不是本機儲存空間,或者您可以建構一個版本政策外掛程式,以不同的方式執行版本轉換,事實上,您甚至可以建構一個自訂模型外掛程式來服務非 TensorFlow 模型。這些主題超出本教學課程的範圍。不過,您可以參考自訂來源和自訂可服務項教學課程以取得更多資訊。
批次處理
我們在生產環境中想要的另一個典型伺服器功能是批次處理。用於執行機器學習推論的現代硬體加速器 (GPU 等) 通常在大量批次執行推論要求時,才能達到最佳的運算效率。
可以透過在建立 SavedModelBundleSourceAdapter
時提供適當的 SessionBundleConfig
來開啟批次處理。在本例中,我們使用幾乎預設的值設定 BatchingParameters
。可以透過設定自訂逾時、batch_size 等值來微調批次處理。如需詳細資訊,請參閱 BatchingParameters
。
SessionBundleConfig session_bundle_config;
// Batching config
if (enable_batching) {
BatchingParameters* batching_parameters =
session_bundle_config.mutable_batching_parameters();
batching_parameters->mutable_thread_pool_name()->set_value(
"model_server_batch_threads");
}
*saved_model_bundle_source_adapter_config.mutable_legacy_config() =
session_bundle_config;
達到完整批次後,推論要求會在內部合併為單一大型要求 (張量),並叫用 tensorflow::Session::Run()
(這是在 GPU 上實際獲得效率提升的地方)。
使用 Manager 服務
如上所述,TensorFlow Serving Manager
設計為泛型元件,可以處理任意機器學習系統產生的模型的載入、服務、卸載和版本轉換。其 API 是圍繞下列主要概念建構
可服務項:可服務項是可以服務用戶端要求的任何不透明物件。可服務項的大小和粒度是彈性的,因此單一可服務項可能包含從查閱表的單一片段到單一機器學習模型,再到模型元組的任何內容。可服務項可以是任何類型和介面。
可服務項版本:可服務項已版本化,且 TensorFlow Serving
Manager
可以管理一個或多個可服務項版本。版本控制允許多個可服務項版本同時載入,以支援逐步推出和實驗。可服務項串流:可服務項串流是可服務項版本序列,版本號碼遞增。
模型:機器學習模型由一個或多個可服務項表示。可服務項範例包括
- TensorFlow 工作階段或其包裝函式,例如
SavedModelBundle
。 - 其他種類的機器學習模型。
- 詞彙查閱表。
- 嵌入查閱表。
複合模型可以表示為多個獨立的可服務項,或表示為單一複合可服務項。可服務項也可能對應於模型的一部分,例如,對於跨多個
Manager
例項分片的較大查閱表。- TensorFlow 工作階段或其包裝函式,例如
為了將所有這些內容放入本教學課程的脈絡中
TensorFlow 模型由一種可服務項表示:
SavedModelBundle
。SavedModelBundle
在內部包含tensorflow:Session
,並搭配一些關於工作階段中載入的圖形以及如何執行推論的中繼資料。有一個檔案系統目錄,其中包含 TensorFlow 匯出串流,每個匯出串流都在自己的子目錄中,子目錄的名稱是版本號碼。外部目錄可以視為要服務的 TensorFlow 模型的可服務項串流的序列化表示法。每個匯出都對應於可以載入的可服務項。
AspiredVersionsManager
監控匯出串流,並動態管理所有SavedModelBundle
可服務項的生命週期。
TensorflowPredictImpl::Predict
接著只會
- 從管理員 (透過 ServerCore) 要求
SavedModelBundle
。 - 使用
泛型簽名
將PredictRequest
中的邏輯張量名稱對應到真實張量名稱,並將值繫結到張量。 - 執行推論。
測試及執行伺服器
將第一個版本的匯出複製到受監控的資料夾
mkdir /tmp/monitored
cp -r /tmp/mnist/1 /tmp/monitored
然後啟動伺服器
docker run -p 8500:8500 \
--mount type=bind,source=/tmp/monitored,target=/models/mnist \
-t --entrypoint=tensorflow_model_server tensorflow/serving --enable_batching \
--port=8500 --model_name=mnist --model_base_path=/models/mnist &
伺服器會每秒發出記錄訊息,指出「正在嘗試取得可服務項的版本...」,這表示它已找到匯出,並正在追蹤其持續存在。
讓我們使用 --concurrency=10
執行用戶端。這會將並行要求傳送到伺服器,進而觸發您的批次處理邏輯。
tools/run_in_docker.sh python tensorflow_serving/example/mnist_client.py \
--num_tests=1000 --server=127.0.0.1:8500 --concurrency=10
這會產生如下所示的輸出
...
Inference error rate: 13.1%
然後,我們將第二個版本的匯出複製到受監控的資料夾,並重新執行測試
cp -r /tmp/mnist/2 /tmp/monitored
tools/run_in_docker.sh python tensorflow_serving/example/mnist_client.py \
--num_tests=1000 --server=127.0.0.1:8500 --concurrency=10
這會產生如下所示的輸出
...
Inference error rate: 9.5%
這確認您的伺服器會自動探索新版本並使用它來服務!