search
尋找貓咪~QQ 地點 桃園市桃園區 Taoyuan , Taoyuan

TensorFlow在產品環境中運行模型的實踐經驗總結

策劃|Tina編輯|尚劍Zendesk是美國一家做客戶服務的公司,提供產品創新和定價等服務,他們的機器學習平台使用的是TensorFlow;之前InfoQ從TensorFlow與Kubernetes/Docker的結合上給出了一些企業實踐文章,而在模型部署上,這篇文章是個好例子;

Zendesk使用TensorFlow Serving來載入TensorFlow模型,使用修改後的protobuf生成原生可用(bazel-free)的Python gRPC客戶端,同時介紹了模型壓縮、AB測試等經驗

。此文由原作者授權,InfoQ中文站翻譯並分享。

我們如何開始使用TensorFlow

在Zendesk,我們開發了一系列機器學習產品,比如最新的自動答案(Automatic Answers)。它使用機器學習來解釋用戶提出的問題,並用相應的知識庫文章來回應。當用戶有問題、投訴或者查詢時,他們可以在線提交請求。收到他們的請求后,Automatic Answers將分析請求,並且通過郵件建議客戶閱讀相關的可能最有幫助的文章。

Automatic Answers使用一類目前最先進的機器學習演算法來識別相關文章,也就是深度學習。 我們使用Google的開源深度學習庫TensorFlow來構建這些模型,利用圖形處理單元(GPU)來加速這個過程。Automatic Answers是我們在Zendesk使用Tensorflow完成的第一個數據產品。在我們的數據科學家付出無數汗水和心血之後,我們才有了在Automatic Answers上效果非常好的Tensorflow模型。

但是構建模型只是問題的一部分,我們的下一個挑戰是要找到一種方法,使得模型可以在生產環境下服務。模型服務系統將經受大量的業務。所以需要確保為這些模型提供的軟體和硬體基礎架構是可擴展的、可靠的和容錯的,這對我們來說是非常重要的。接下來介紹一下我們在生產環境中配置TensorFlow模型的一些經驗。

順便說一下我們的團隊——Zendesk的機器學習數據團隊。我們團隊包括一群數據科學家、數據工程師、一位產品經理、UX /產品設計師以及一名測試工程師。

Data Team At Zendesk Melbourne

TensorFlow模型服務

經過數據科學家和數據工程師之間一系列的討論,我們明確了一些核心需求:

  • 預測時的低延遲

  • 橫向可擴展

  • 適合我們的微服務架構

  • 可以使用A/B測試不同版本的模型

  • 可以與更新版本的TensorFlow兼容

  • 支持其他TensorFlow模型,以支持未來的數據產品

TensorFlow Serving

經過網上的調研之後,Google的TensorFlow Serving成為我們首選的模型服務。TensorFlow Serving用C++編寫,支持機器學習模型服務。開箱即用的TensorFlow Serving安裝支持:

  • TensorFlow模型的服務

  • 從本地文件系統掃描和載入TensorFlow模型

(小編註:TensorFlow和TensorFlow Serving的區別:TensorFlow項目主要是基於各種機器學習演算法構建模型,並為某些特定類型的數據輸入做適應學習,而TensorFlow Serving則專註於讓這些模型能夠加入到產品環境中。開發者使用TensorFlow構建模型,然後TensorFlow Serving基於客戶端輸入的數據使用前面TensorFlow訓練好的模型進行預測。)

TensorFlow Serving將每個模型視為可服務對象。它定期掃描本地文件系統,根據文件系統的狀態和模型版本控制策略來載入和卸載模型。這使得可以在TensorFlow Serving繼續運行的情況下,通過將導出的模型複製到指定的文件路徑,而輕鬆地熱部署經過訓練的模型。

TensorFlow Serving Architecture

根據這篇Google博客中報告的基準測試結果,他們每秒記錄大約100000個查詢,其中不包括TensorFlow預測處理時間和網路請求時間。

有關TensorFlow Serving架構的更多信息,請參閱TensorFlow Serving文檔。

通信協議(gRPC)

TensorFlow Serving提供了用於從模型調用預測的gRPC介面。gRPC是一個開源的高性能遠程過程調用(remote procedure call,RPC)框架,它在HTTP/2上運行。與HTTP/1.1相比,HTTP/2包含一些有趣的增強,比如它對請求復用、雙向流和通過二進位傳輸的支持,而不是文本。

默認情況下,gRPC使用Protocol Buffers (Protobuf)作為其信息交換格式。Protocol Buffers是Google的開源項目,用於在高效的二進位格式下序列化結構化數據。它是強類型,這使它不容易出錯。數據結構在.proto文件中指定,然後可以以各種語言(包括Python,Java和C ++)將其編譯為gRPC請求類。 這是我第一次使用gRPC,我很想知道它與其他API架構(如REST)相比誰性能更好。

模型訓練和服務架構

我們決定將深度學習模型的訓練和服務分為兩個管道。下圖是我們的模型訓練和服務架構的概述:

Model Training and Serving Architecture

模型訓練管道

模型訓練步驟:

  • 我們的訓練特徵是從Hadoop中提供的數據生成的。

  • 生成的訓練特徵保存在AWS S3中。

  • 然後使用AWS中的GPU實例和S3中的批量訓練樣本訓練TensorFlow模型。

一旦模型被構建並驗證通過,它將被發布到S3中的模型存儲庫。

模型服務管道

驗證的模型在生產中通過將模型從模型庫傳送到TensorFlow Serving實例來提供。

基礎結構

我們在AWS EC2實例上運行TensorFlow Serving。Consul在實例之前設置,用於服務發現和分發流量。客戶端連接從DNS查找返回的第一個可用IP。或者彈性負載平衡可用於更高級的負載平衡。由於TensorFlow模型的預測本質上是無狀態操作,所以我們可以通過旋轉加速更多的EC2實例 來實現橫向可擴展性。

另一個選擇是使用Google Cloud平台提供的Cloud ML,它提供TensorFlow Serving作為完全託管服務。 但是,當我們在大概2016年9月推出TensorFlow Serving時,Cloud ML服務處於alpha階段,缺少生產使用所需的功能。因此,我們選擇在我們自己的AWS EC2實例中託管,以實現更精細的粒度控制和可預測的資源容量。

模型服務的實現

下面是我們實現TensorFlow Serving部署和運行所採取的步驟:

1.從源編譯TensorFlow Serving

首先,我們需要編譯源代碼來產生可執行的二進位文件。然後就可以從命令行執行二進位文件來啟動服務系統。

假設你已經配置好了Docker,那麼一個好的開端就是使用提供的Dockerfile來編譯二進位文件。請按照以下步驟:

  • 運行該gist中的代碼以構建適合編譯TensorFlow Serving的docker容器。

  • 在正在運行的docker容器中運行該gist中的代碼以構建可執行二進位文件。

  • 一旦編譯完成,可執行二進位文件將在你的docker鏡像的以下路徑中:/work/serving/bazel-bin/tensorflow_serving/model_servers/tensorflow_model_server

2.運行模型服務系統

上一步生成的可執行二進位文件(tensorflow_model_server)可以部署到您的生產實例中。 如果您使用docker編排框架(如Kubernetes或Elastic Container Service),您還可以在docker容器中運行TensorFlow Serving。

現在假設TensorFlow模型存儲在目錄/work/awesome_model_directory下的生產主機上。你可以在埠8999上使用以下命令來運行TensorFlow Serving和你的TensorFlow模型:

<path_to_the_binary>/tensorflow_model_server — port=8999 — model_base_path=/work/awesome_model_directory

默認情況下,TensorFlow Serving會每秒掃描模型基本路徑,並且可以自定義。此處列出了可作為命令行參數的可選配置。

3.從服務定義(Service Definitions)生成Python gRPC存根

下一步是創建可以在模型伺服器上進行預測的gRPC客戶端。這可以通過編譯.proto文件中的服務定義,從而生成伺服器和客戶端存根來實現。.proto文件在TensorFlow Serving源碼中的tensorflow_serving_apis文件夾中。在docker容器中運行以下腳本來編譯.proto文件。運行提交版本號為46915c6的腳本的示例:

./compile_ts_serving_proto.sh 46915c6

運行該腳本后應該在tensorflow_serving_apis目錄下生成以下定義文件:

  • model_pb2.py

  • predict_pb2.py

  • prediction_service_pb2.py

你還可以使用grpc_tools Python工具包來編譯.proto文件。

4.從遠程主機調用服務

可以使用編譯后的定義來創建一個python客戶端,用來調用伺服器上的gRPC調用。比如這個例子用一個同步調用TensorFlow Serving的Python客戶端。

如果您的用例支持非同步調用預測,TensorFlow Serving還支持批處理預測以達到性能優化的目的。要啟用此功能,你應該運行tensorflow_model_server同時開啟flag —enable_batching。這是一個非同步客戶端的例子。

從其他存儲載入模型

如果你的模型沒有存儲在本地系統中應該怎麼辦?你可能希望TensorFlow Serving可以直接從外部存儲系統(比如AWS S3和Google Storage)中直接讀取。

如果是這種情況,你將需要通過Custom Source來拓展TensorFlow Serving以使其可以讀取這些源。TensorFlow Serving僅支持從文件系統載入模型。

一些經驗

我們在產品中已經使用TensorFlow Serving大概半年的時間,我們的使用體驗是相當平穩。它具有良好的預測時間延遲。以下是我們的TensorFlow Serving實例一周內的預測時間(以秒為單位)的第95百分位數的圖(約20毫秒):

然而,在生產中使用TensorFlow Serving的過程中,我們也有一些經驗教訓可以跟大家分享。

1.模型版本化

到目前為止,我們已經在產品中使用了幾個不同版本的TensorFlow模型,每一個版本都有不同的特性,比如網路結構、訓練數據等。正確處理模型的不同版本已經是一個重要的任務。這是因為傳遞到TensorFlow Serving的輸入請求通常涉及到多個預處理步驟。這些預處理步驟在不同TensorFlow模型版本下是不同的。預處理步驟和模型版本的不匹配可能導致錯誤的預測。

1a.明確說明你想要的版本

我們發現了一個簡單但有用的防止錯誤預測的方法,也就是使用在model.proto定義中指定的版本屬性,它是可選的(可以編譯為model_pb2.py)。這樣可以始終保證你的請求有效負載與預期的版本號匹配。

當你請求某個版本(比如從客戶端請求版本5),如果TensorFlow Serving伺服器不支持該特定版本,它將返回一個錯誤消息,提示找不到模型。

1b.服務多個模型版本

TensorFlow Serving默認的是載入和提供模型的最新版本。當我們在2016年9月首次應用TensorFlow Serving時,它不支持同時提供多個模型。這意味著在指定時間內它只有一個版本的模型。這對於我們的用例是不夠的,因為我們希望服務多個版本的模型以支持不同神經網路架構的A / B測試。

其中一個選擇是在不同的主機或埠上運行多個TensorFlow Serving進程,以使每個進程提供不同的模型版本。這樣的話就需要:

  • 用戶應用程序(gRPC客戶端)包含切換邏輯,並且需要知道對於給定的版本需要調用哪個TensorFlow Serving實例。這增加了客戶端的複雜度,所以不是首選。

  • 一個可以將版本號映射到TensorFlow Serving不同實例的註冊表。

更理想的解決方案是TensorFlow Serving可以支持多個版本的模型。

所以我決定使用一個「lab day」的時間來擴展TensorFlow Serving,使其可以服務多個版本的時間。在Zendesk,「lab day」就是我們可以每兩周有一天的時間來研究我們感興趣的東西,讓它成為能夠提高我們日常生產力的工具,或者一種我們希望學習的新技術。我已經有8年多沒有使用C++代碼了。但是,我對TensorFlow Serving代碼庫的可讀性和整潔性印象深刻,這使其易於擴展。支持多個版本的增強功能已經提交,並且已經合併到主代碼庫中。TensorFlow Serving維護人員對補丁和功能增強的反饋非常迅速。從最新的主分支,你可以啟動TensorFlow Serving,用model_version_policy中附加的flag來服務多個模型版本:

/work/serving/bazel-bin/tensorflow_serving/model_servers/tensorflow_model_server — port=8999 — model_base_path=/work/awesome_model_directory — model_version_policy=ALL_VERSIONS

一個值得注意的要點是,服務多個模型版本,需要權衡的是更高的內存佔用。所以上述的flag運行時,記住刪除模型基本路徑中的過時模型版本。

2.活用壓縮

當你部署一個新的模型版本的時候,建議在複製到model_base_path之前,首先將導出的TensorFlow模型文件壓縮成單個的壓縮文件。Tensorflow Serving教程中包含了導出訓練好的Tensorflow模型的步驟。導出的檢查點TensorFlow模型目錄通常具有以下文件夾結構:

一個包含版本號(比如0000001)和以下文件的父目錄:

  • saved_model.pb:序列化模型,包括模型的圖形定義,以及模型的元數據(比如簽名)。

  • variables:保存圖形的序列化變數的文件。壓縮導出的模型:

tar -cvzf modelv1.tar.gz 0000001

為什麼需要壓縮?

  • 壓縮後轉移和複製更快

  • 如果你將導出的模型文件夾直接複製到model_base_path中,複製過程可能需要一段時間,這可能導致導出的模型文件已複製,但相應的元文件尚未複製。如果TensorFlow Serving開始載入你的模型,並且無法檢測到源文件,那麼伺服器將無法載入模型,並且會停止嘗試再次載入該特定版本。

3.模型大小很重要

我們使用的TensorFlow模型相當大,在300Mb到1.2Gb之間。我們注意到,在模型大小超過64Mb時,嘗試提供模型時將出現錯誤。這是由於protobuf消息大小的硬編碼64Mb限制,如這個TensorFlow Serving在Github上的問題所述。

最後,我們採用Github問題中描述的補丁來更改硬編碼的常量值。(這對我們來說還是一個問題。如果你可以找到在不改變硬編碼的情況下,允許服務大於64Mb的模型的替代方案,請聯繫我們。)

4.避免將源移動到你自己的分支下

從實現時開始,我們一直從主分支構建TensorFlow Serving源,最新的版本分支(v0.4)在功能和錯誤修復方面落後於主分支。因此,如果你只通過檢查主分支來創建源,一旦新的更改被合併到主分支,你的源也可能改變。為了確保人工製品的可重複構建,我們發現檢查特定的提交修訂很重要:

  • TensorFlow Serving

  • TensorFlow(TensorFlow Serving里的Git子模塊)

期待未來加入的一些功能增強清單

這裡是一些我們比較感興趣的希望以後TensorFlow Serving會提供的功能:

  • 健康檢查服務方法

  • 一個TensorFlow Serving實例可以支持多種模型類型

  • 直接可用的分散式存儲(如AWS S3和Google存儲)中的模型載入

  • 直接支持大於64Mb的模型

  • 不依賴於TensorFlow的Python客戶端示例

如何通過TensorFlow實現深度學習演算法並運用到企業實踐中



熱門推薦

本文由 yidianzixun 提供 原文連結

寵物協尋 相信 終究能找到回家的路
寫了7763篇文章,獲得2次喜歡
留言回覆
回覆
精彩推薦