EAS內置的Tensorflow Processor支持將Tensorflow標準的Savedmodel格式的模型部署成在線服務。本文為您介紹如何部署及調用Tensorflow模型服務。
背景信息
對于Keras和Checkpoint模型,您需要先將其轉換為Savedmodel模型,再進行部署,詳情請參見TensorFlow模型如何導出為SavedModel。PAI-Blade優化過的模型可以直接運行。
Tensorflow Processor版本說明
Tensorflow支持多個版本,包括GPU和CPU版本,服務部署時無特殊需求可以使用最新版本。Tensorflow版本功能會向前兼容,新版本性能相對較好。各個Tensorflow版本對應的Processor名稱如下表所示。
Processor名稱 | Tensorflow版本 | 是否支持GPU版本 |
tensorflow_cpu_1.12 | Tensorflow 1.12 | 否 |
tensorflow_cpu_1.14 | Tensorflow 1.14 | 否 |
tensorflow_cpu_1.15 | Tensorflow 1.15 | 否 |
tensorflow_cpu_2.3 | Tensorflow 2.3 | 否 |
tensorflow_cpu_2.4 | Tensorflow 2.4 | 否 |
tensorflow_cpu_2.7 | Tensorflow 2.7 | 否 |
tensorflow_gpu_1.12 | Tensorflow 1.12 | 是 |
tensorflow_gpu_1.14 | Tensorflow 1.14 | 是 |
tensorflow_gpu_1.15 | Tensorflow 1.15 | 是 |
tensorflow_gpu_2.4 | Tensorflow 2.4 | 是 |
tensorflow_gpu_2.7 | Tensorflow 2.7 | 是 |
步驟一:部署服務
可選:配置請求預熱文件。
對于部分TensorFlow模型,初次調用時需要將模型相關文件或參數加載到內存中,該過程可能耗費較長時間,從而導致前幾次請求模型服務的RT較長,甚至出現408(請求計算超時)或450(超出隊列長度丟棄請求)等情況。為保證服務在滾動更新過程中不會發生抖動,需要在服務部署時增加相關參數對模型進行預熱,以保證在預熱完成后服務實例才會正式接收流量,具體操作,詳情請參見高級配置:模型服務預熱。
部署服務。
使用eascmd客戶端部署Tensorflow模型服務時,您需要指定Processor種類為Processor名稱,服務配置文件示例如下。
{ "name": "tf_serving_test", "model_path": "http://examplebucket.oss-cn-shanghai.aliyuncs.com/models/model.tar.gz", "processor": "tensorflow_cpu_1.15", "warm_up_data_path":"oss://path/to/warm_up_test.bin", // 模型預熱的請求文件路徑。 "metadata": { "instance": 1, "cpu": 1, "memory": 4000 } }
關于如何使用客戶端工具部署服務,詳情請參見服務部署:EASCMD&DSW。
您也可以通過控制臺部署Tensorflow模型服務,詳情請參見服務部署:控制臺。
Tensorflow服務部署完成后,在PAI EAS模型在線服務頁面,單擊待調用服務服務方式列下的調用信息,查看服務訪問的Endpoint和用于服務鑒權的Token信息。
步驟二:調用服務
Tensorflow服務輸入輸出格式為protobuf,不是純文本,而在線調試目前僅支持純文本的輸入輸出數據,因此無法使用控制臺的在線調試功能。
EAS提供了不同版本的SDK,對服務請求和響應數據進行了封裝,且SDK內部包含了直連和容錯相關的機制,推薦使用SDK來構建和發送請求,具體操作步驟如下。
查詢模型結構。
對于標準的Savedmodel格式的模型,對服務發送空請求,會返回JSON格式的模型結構信息。
// 發送空請求。 $ curl 1828488879222***.cn-shanghai.pai-eas.aliyuncs.com/api/predict/mnist_saved_model_example -H 'Authorization: YTg2ZjE0ZjM4ZmE3OTc0NzYxZDMyNmYzMTJjZTQ1***' // 返回模型結構信息。 { "inputs": [ { "name": "images", "shape": [ -1, 784 ], "type": "DT_FLOAT" } ], "outputs": [ { "name": "scores", "shape": [ -1, 10 ], "type": "DT_FLOAT" } ], "signature_name": "predict_images" }
說明對于freezon pb格式的模型,無法獲取模型結構信息。
發送推理請求。
使用Python SDK發送模型請求示例如下。
#!/usr/bin/env python from eas_prediction import PredictClient from eas_prediction import TFRequest if __name__ == '__main__': client = PredictClient('http://1828488879222***.cn-shanghai.pai-eas.aliyuncs.com', 'mnist_saved_model_example') client.set_token('YTg2ZjE0ZjM4ZmE3OTc0NzYxZDMyNmYzMTJjZTQ1****') client.init() req = TFRequest('predict_images') req.add_feed('images', [1, 784], TFRequest.DT_FLOAT, [1] * 784) for x in range(0, 1000000): resp = client.predict(req) print(resp)
關于代碼中的參數配置說明,詳情請參見Python SDK使用說明。
后續您也可以自行構建服務請求,詳情請參見請求格式。
請求格式
Tensorflow processor輸入輸出為protobuf格式。當您使用SDK發送請求時,SDK對請求進行了封裝,您只需根據SDK提供的函數來構建請求即可。如果您希望自行構建服務請求,則可以參考如下pb定義來生成相關的代碼,詳情請參見TensorFlow服務請求構造。
syntax = "proto3";
option cc_enable_arenas = true;
option java_package = "com.aliyun.openservices.eas.predict.proto";
option java_outer_classname = "PredictProtos";
enum ArrayDataType {
// Not a legal value for DataType. Used to indicate a DataType field
// has not been set.
DT_INVALID = 0;
// Data types that all computation devices are expected to be
// capable to support.
DT_FLOAT = 1;
DT_DOUBLE = 2;
DT_INT32 = 3;
DT_UINT8 = 4;
DT_INT16 = 5;
DT_INT8 = 6;
DT_STRING = 7;
DT_COMPLEX64 = 8; // Single-precision complex.
DT_INT64 = 9;
DT_BOOL = 10;
DT_QINT8 = 11; // Quantized int8.
DT_QUINT8 = 12; // Quantized uint8.
DT_QINT32 = 13; // Quantized int32.
DT_BFLOAT16 = 14; // Float32 truncated to 16 bits. Only for cast ops.
DT_QINT16 = 15; // Quantized int16.
DT_QUINT16 = 16; // Quantized uint16.
DT_UINT16 = 17;
DT_COMPLEX128 = 18; // Double-precision complex.
DT_HALF = 19;
DT_RESOURCE = 20;
DT_VARIANT = 21; // Arbitrary C++ data types.
}
// Dimensions of an array.
message ArrayShape {
repeated int64 dim = 1 [packed = true];
}
// Protocol buffer representing an array.
message ArrayProto {
// Data Type.
ArrayDataType dtype = 1;
// Shape of the array.
ArrayShape array_shape = 2;
// DT_FLOAT.
repeated float float_val = 3 [packed = true];
// DT_DOUBLE.
repeated double double_val = 4 [packed = true];
// DT_INT32, DT_INT16, DT_INT8, DT_UINT8.
repeated int32 int_val = 5 [packed = true];
// DT_STRING.
repeated bytes string_val = 6;
// DT_INT64.
repeated int64 int64_val = 7 [packed = true];
// DT_BOOL.
repeated bool bool_val = 8 [packed = true];
}
// PredictRequest specifies which TensorFlow model to run, as well as
// how inputs are mapped to tensors and how outputs are filtered before
// returning to user.
message PredictRequest {
// A named signature to evaluate. If unspecified, the default signature
// will be used.
string signature_name = 1;
// Input tensors.
// Names of input tensor are alias names. The mapping from aliases to real
// input tensor names is expected to be stored as named generic signature
// under the key "inputs" in the model export.
// Each alias listed in a generic signature named "inputs" should be provided
// exactly once in order to run the prediction.
map<string, ArrayProto> inputs = 2;
// Output filter.
// Names specified are alias names. The mapping from aliases to real output
// tensor names is expected to be stored as named generic signature under
// the key "outputs" in the model export.
// Only tensors specified here will be run/fetched and returned, with the
// exception that when none is specified, all tensors specified in the
// named signature will be run/fetched and returned.
repeated string output_filter = 3;
}
// Response for PredictRequest on successful run.
message PredictResponse {
// Output tensors.
map<string, ArrayProto> outputs = 1;
}