天天看點

手把手教你使用TF服務将TensorFlow模型部署到生産環境

手把手教你使用TF服務将TensorFlow模型部署到生産環境

介紹

将機器學習(ML)模型應用于生産環境已成為一個火熱的的話題,許多架構提供了旨在解決此問題的不同解決方案。為解決這一問題,谷歌釋出了TensorFlow(TF)服務,以期待解決将ML模型部署到生産中的問題。

本文提供了一個關于服務于預先訓練的卷積語義分割網絡的實踐教程。閱讀本文後,你将能夠使用TF服務來部署和向TF訓練的深度CNN送出請求等操作。另外,本文将概述TF服務的API及其工作原理。如果你想學習本教程并在計算機上運作示例,請完整了解本文。但是,如果你隻想了解TensorFlow服務,你可以專注于前兩部分。

TensorFlow服務庫-概述

首先我們需要花一些時間來了解TF

Serving如何處理ML模型的整個生命周期。在這裡,我們将介紹TF服務的主要建構塊,本部分的目标是提供TF服務API的介紹。如需深入了解,請通路

TF服務

文檔頁面。

TensorFlow服務由一些抽象組成,這些抽象類用于不同任務的API,其中最重要的是Servable,Loader,Source和Manager,讓我們來看看他們之間是如何互動的:

手把手教你使用TF服務将TensorFlow模型部署到生産環境

簡單來說,當TF Serving識别磁盤上的模型時,Source元件就開始工作啦,整個服務生命周期也算開始了,Source元件負責識别應加載的新模型。實際上,它會密切關注檔案系統,以确定新模型版本何時到達磁盤。當它看到新版本模型時,它會為該特定版本的模型建立一個Loader。

總之,Loader幾乎了解模型的所有内容,包括如何加載以及如何估計模型所需的資源,例如請求的RAM和GPU記憶體。Loader還有一個指向磁盤上模型的指針以及用于加載它的所有必要的中繼資料。但是有一個問題:加載器不允許加載模型。建立Loader後,Source會将其作為Aspired

Version發送給Manager。

收到模型的Aspired Version後,Manager繼續執行服務過程。這裡有兩種可能性,一個是推送第一個模型版本進行部署,在這種情況下,Manager将確定所需的資源可用,完成後,Manager會授予Loader加載模型的權限;第二是我們推出現有模型的新版本,在這種情況下,管理者必須先咨詢版本政策插件,然後再繼續操作,版本政策确定如何進行加載新模型版本的過程。

具體來說,在第一種情況下,我們可以確定我們的系統始終可用于傳入客戶的請求。此時,我們同時加載了兩個模型版本,隻有在加載完成後,Manager才會解除安裝舊版本,并且可以安全地在模型之間切換。另一方面,如果我們想通過不使用額外緩沖區來節省資源,我們可以選擇保留資料。最後,當用戶端請求模型的handle時,管理器傳回Servable的handle。

在接下來的部分中,我們将介紹如何使用TF服務提供卷積神經網絡(CNN)。

導出服務模型

為TensorFlow建構的ML模型提供服務的第一步是確定它的格式正确,為此,TensorFlow提供了

SavedModel

類。

SavedModel是TensorFlow模型的通用序列化格式,如果你熟悉TF,則可以使用TensorFlow Saver來保留模型的變量。

TensorFlow Saver提供了将模型的檢查點檔案儲存到磁盤或從磁盤恢複的功能。實際上,SavedModel包裝了TensorFlow Saver,它是導出TF模型進行服務的标準方式。

SavedModel object有一些很好的功能。首先,它允許你将多個元圖儲存到單個SavedModel對象,換句話說,它允許我們為不同的任務提供不同的圖表。例如,假設你剛剛完成了模型的訓練。在大多數情況下,要執行推理,你的圖表不需要某些特定于訓練的操作。這些操作可能包括優化器的變量,學習速率排程張量,額外的預處理操作等。此外,你可能希望為移動部署提供量化版本的圖形。

手把手教你使用TF服務将TensorFlow模型部署到生産環境

在此環境中,SavedModel允許你使用不同的配置儲存圖形。在我們的例子中,我們有三個不同的圖形和相應的标簽,如“訓練”、“推理”和“移動”。此外,這三個圖形為了提升記憶體效率還共享相同的變量集。

就在不久前,如果我們想在移動裝置上部署TF模型時,我們需要知道輸入和輸出張量的名稱,以便向模型提供資料或從模型擷取資料。這需要強制程式員在圖的所有張量中搜尋他們所需的張量。如果張量沒有正确命名,那麼任務可能非常繁瑣。

為了簡化操作,SavedModel提供對

SignatureDefs的

支援,SignatureDefs定義了TensorFlow支援的計算的簽名。它确定了計算圖的正确輸入和輸出張量,也就是說使用這些簽名,你可以指定用于輸入和輸出的确切節點。要使用其内置的服務API,TF Serving要求模型包含一個或多個SignatureDefs。

手把手教你使用TF服務将TensorFlow模型部署到生産環境

要建立此類簽名,我們需要提供輸入,輸出和所需方法名稱的定義,輸入和輸出表示從字元串到TensorInfo對象的映射。在這裡,我們定義了預設張量,用于向圖表輸入資料和從圖表接收資料。

目前,有三種服務API:分類,預測和回歸。每個簽名定義都與特定的RPC API相比對,Classification SegnatureDef用于Classify RPC API,Predict SegnatureDef用于Predict RPC API等等依此類推。

對于分類簽名,必須有輸入張量(接收資料)和兩個可能的輸出張量中的至少一個:類或分數。Regression SignatureDef隻需要一個張量用于輸入,另一個用于輸出。最後,Predict signature允許動态數量的輸入和輸出張量。此外,SavedModel支援資料存儲,以用于ops初始化依賴于外部檔案的情況,它還具有在建立SavedModel之前清除裝置的機制。

現在,讓我們看看我們如何在實踐中做到這一點。

設定環境

在開始之前,我們需要從Github克隆

此TensorFlow DeepLab-v3

。DeepLab是谷歌最好的語義分割ConvNet,網絡可以将圖像作為輸入并輸出類似掩模的圖像,該圖像将某些對象與背景分開。

該版本的DeepLab在

Pascal VOC

分段資料集上進行了訓練,是以,它可以分割和識别多達20個類。如果你想了解有關語義分段和DeepLab-v3的更多資訊,請檢視

深入深度卷積語義分段網絡和Deeplab_V3

與服務相關的所有檔案都存在于:

./deeplab_v3/serving/

。在那裡,你會發現兩個重要的檔案:

deeplab_saved_model.py

deeplab_client.ipynb

在進一步研究之前,請務必下載下傳Deeplab-v3預訓練模型。前往上面的GitHub存儲庫,單擊checkpoints連結,你應該有一個名為tboard_logs /的檔案夾,其中包含16645 /檔案夾。

手把手教你使用TF服務将TensorFlow模型部署到生産環境

現在,我們需要建立兩個Python虛拟環境,一個用于Python 3,另一個用于Python 2,請確定安裝必要的依賴項。你可以在

serving_requirements.txt client_requirements.txt

檔案中找到它們。

你可能很好奇為什麼需要兩個Python

env,因為我們的模型DeepLab-v3是在Python 3下開發的,而TensorFlow Serving Python API僅針對Python 2釋出。是以,要導出模型并運作TF服務,我們使用Python 3 env 。

請注意,你可以使用bazel中的Serving API放棄Python 2 env。有關更多詳細資訊,請參閱

TF服務執行個體

。完成這一步後,讓我們從真正重要的事情開始吧。

執行個體教程

TensorFlow提供了一個易于使用的進階實用程式類使用SavedModel,類名為

SavedModelBuilder

。SavedModelBuilder類提供了儲存多個元圖,關聯變量和資料的功能。讓我們來看一個如何導出Deep Segmentation CNN模型進行服務的運作示例。

如上所述,要導出模型,我們使用啦SavedModelBuilder類。它将生成SavedModel協定緩沖區檔案以及模型的變量和資源。

讓我們剖析一下代碼:

# Create SavedModelBuilder class
# defines where the model will be exported
export_path_base = FLAGS.export_model_dir
export_path = os.path.join(
    tf.compat.as_bytes(export_path_base),
    tf.compat.as_bytes(str(FLAGS.model_version)))
print('Exporting trained model to', export_path)
builder = tf.saved_model.builder.SavedModelBuilder(export_path)           

SavedModelBuilder接收(作為輸入)儲存模型資料的目錄。這裡,export_path變量是為了連接配接export_path_base和model_version。是以,不同的模型版本将儲存在export_path_base檔案夾内的單獨目錄中。

假設我們在生産中有我們模型的基礎版本,但我們想要部署它的新版本。因為我們已經提高了模型的準确性,并希望為我們的客戶提供這個新版本。要導出同一模型的不同版本,我們隻需将FLAGS.model_version設定為更高的整數值即可。然後将在export_path_base檔案夾中建立一個不同的檔案夾(儲存我們模型的新版本)。

現在,我們需要指定模型的輸入和輸出Tensors。為此,我們使用

SignatureDefs

,簽名定義了我們要導出的模型類型。它提供了從字元串(邏輯Tensor名稱)到

TensorInfo

對象的映射。我們的想法是,用戶端可以引用簽名定義的邏輯名稱,而不是引用輸入/輸出的實際張量名稱。

為了服務語義分段CNN,我們将建立一個預測簽名。請注意,build_signature_def()函數采用輸入和輸出張量的映射以及所需的API。

SignatureDef需要指定:輸入,輸出和方法名稱,我們期望輸入有三個值:一圖像,另外兩個張量指定其尺寸(高度和寬度)。對于輸出,我們隻定義了一個結果-分段輸出掩碼。

# Creates the TensorInfo protobuf objects that encapsulates the input/output tensors
tensor_info_input = tf.saved_model.utils.build_tensor_info(input_tensor)
tensor_info_height = tf.saved_model.utils.build_tensor_info(image_height_tensor)
tensor_info_width = tf.saved_model.utils.build_tensor_info(image_width_tensor)

# output tensor info
tensor_info_output = tf.saved_model.utils.build_tensor_info(predictions_tf)

# Defines the DeepLab signatures, uses the TF Predict API
# It receives an image and its dimensions and output the segmentation mask
prediction_signature = (
    tf.saved_model.signature_def_utils.build_signature_def(
        inputs={'images': tensor_info_input, 'height': tensor_info_height, 'width': tensor_info_width},
        outputs={'segmentation_map': tensor_info_output},
        method_name=tf.saved_model.signature_constants.PREDICT_METHOD_NAME))           

請注意,字元串‘image',‘height',‘width'和‘segmentation_map'不是張量。相反,它們是引用實際張量input_tensor,image_height_tensor和image_width_tensor的邏輯名稱。是以,它們可以是你喜歡的任何唯一字元串。此外,SignatureDefs中的映射與TensorInfo protobuf對象有關,而與實際張量無關。要建立TensorInfo對象,我們使用實用程式函數:

tf.saved_model.utils.build_tensor_info(tensor)

現在我們調用add_meta_graph_and_variables()函數來建構SavedModel協定緩沖區對象,然後我們運作save()方法,它會将模型的快照儲存到包含模型變量和資源的磁盤。

builder.add_meta_graph_and_variables(
    sess, [tf.saved_model.tag_constants.SERVING],
    signature_def_map={
        'predict_images':
            prediction_signature,
    })

# export the model
builder.save(as_text=True)
print('Done exporting!')           

現在我們可以運作

來導出我們的模型。

如果一切順利,你将看到檔案夾./serving/versions/1,請注意,“1”表示模型的目前版本。在每個版本子目錄中,你将看到以下檔案:

手把手教你使用TF服務将TensorFlow模型部署到生産環境

·saved_model.pb或saved_model.pbtxt,這是序列化的SavedModel檔案。它包括模型的一個或多個圖形定義,以及簽名定義。

·變量,該檔案夾包含圖形的序列化變量。

現在,我們已準備好啟動我們的模型伺服器。為此,請運作:

$ tensorflow_model_server --port=9000 --model_name=deeplab --model_base_path=<full/path/to/serving/versions/>           

該model_base_path指的是輸出模型儲存,另外,我們不在路徑中指定版本檔案夾,模型版本控制由TF服務處理。

生成用戶端請求

用戶端代碼非常簡單,看一下:

。首先,我們讀取要發送到伺服器的圖像并将其轉換為正确的格式。接下來,我們建立一個gRPC存根,存根允許我們調用遠端伺服器的方法。為此,我們将執行個體化prediction_service_pb2子產品的beta_create_PredictionService_stub類。此時,存根保持調用遠端過程的必要邏輯,就像它們是本地的一樣。

現在,我們需要建立和設定請求對象。由于我們的伺服器實作了TensorFlow Predict API,是以我們需要解析Predict請求。要發出Predict請求,首先,我們從predict_pb2子產品中執行個體化PredictRequest類。我們還需要指定model_spec.name和model_spec.signature_name參數。該名稱參數是當我們推出的伺服器定義的“模型名稱”的說法,而signature_name是指配置設定給邏輯名稱signature_def_map()的參數add_meta_graph()函數。

# create the RPC stub
channel = implementations.insecure_channel(host, int(port))
stub = prediction_service_pb2.beta_create_PredictionService_stub(channel)

# create the request object and set the name and signature_name params
request = predict_pb2.PredictRequest()
request.model_spec.name = 'deeplab'
request.model_spec.signature_name = 'predict_images'

# fill in the request object with the necessary data
request.inputs['images'].CopyFrom(
  tf.contrib.util.make_tensor_proto(image.astype(dtype=np.float32), shape=[1, height, width, 3]))

request.inputs['height'].CopyFrom(tf.contrib.util.make_tensor_proto(height, shape=[1]))
request.inputs['width'].CopyFrom(tf.contrib.util.make_tensor_proto(width, shape=[1]))
           

接下來,我們必須提供伺服器簽名中定義的輸入資料。請記住,在伺服器中,我們定義了一個Predict API來預期圖像以及兩個标量(圖像的高度和寬度)。為了将輸入資料提供給請求對象,TensorFlow提供了實用程式tf.make_tensor_proto(),此方法是從Python/numpy建立的TensorProto對象,我們可以使用它将圖像及其尺寸提供給請求對象。

看起來我們已經準備好調用伺服器了。為此,我們調用Predict()方法(使用存根)并将請求對象作為參數傳遞。gRPC支援:同步和異步調用。是以,如果你在處理請求時想要做一些工作,我們可以調用Predict.future()而不是Predict()。

# sync requests
result_future = stub.Predict(request, 30.)

# For async requests
# result_future = stub.Predict.future(request, 10.)
# Do some work...
# result_future = result_future.result()           

現在我們可以擷取并享受結果。

手把手教你使用TF服務将TensorFlow模型部署到生産環境

本文由阿裡雲雲栖社群組織翻譯。

文章原标題《how-to-deploy-tensorflow-models-to-production-using-tf-serving》作者:

Thalles Silva

譯者:虎說八道,審校:袁虎。

文章為簡譯,更為詳細的内容,請檢視

原文