本頁面由 Cloud Translation API 翻譯而成。
Switch to English

使用SavedModel格式

在TensorFlow.org上查看 在Google Colab中運行 在GitHub上查看源代碼 下載筆記本

SavedModel包含完整的TensorFlow程序,包括權重和計算。它不需要運行原始的模型構建代碼,這對於共享或部署(使用TFLiteTensorFlow.jsTensorFlow ServingTensorFlow Hub )非常有用。

本文檔詳細介紹瞭如何使用低級tf.saved_model api:

從Keras創建一個SavedModel

為了快速介紹,本節將導出預訓練的Keras模型並為其提供圖像分類請求。本指南的其餘部分將填寫詳細信息,並討論創建SavedModels的其他方法。

 import os
import tempfile

from matplotlib import pyplot as plt
import numpy as np
import tensorflow as tf

tmpdir = tempfile.mkdtemp()
 
 physical_devices = tf.config.experimental.list_physical_devices('GPU')
if physical_devices:
  tf.config.experimental.set_memory_growth(physical_devices[0], True)
 
 file = tf.keras.utils.get_file(
    "grace_hopper.jpg",
    "https://storage.googleapis.com/download.tensorflow.org/example_images/grace_hopper.jpg")
img = tf.keras.preprocessing.image.load_img(file, target_size=[224, 224])
plt.imshow(img)
plt.axis('off')
x = tf.keras.preprocessing.image.img_to_array(img)
x = tf.keras.applications.mobilenet.preprocess_input(
    x[tf.newaxis,...])
 
Downloading data from https://storage.googleapis.com/download.tensorflow.org/example_images/grace_hopper.jpg
65536/61306 [================================] - 0s 0us/step

png

我們將使用Grace Hopper的圖像作為運行示例,並使用Keras預先訓練的圖像分類模型,因為它易於使用。自定義模型也可以使用,稍後將進行詳細介紹。

 labels_path = tf.keras.utils.get_file(
    'ImageNetLabels.txt',
    'https://storage.googleapis.com/download.tensorflow.org/data/ImageNetLabels.txt')
imagenet_labels = np.array(open(labels_path).read().splitlines())
 
Downloading data from https://storage.googleapis.com/download.tensorflow.org/data/ImageNetLabels.txt
16384/10484 [==============================================] - 0s 0us/step

 pretrained_model = tf.keras.applications.MobileNet()
result_before_save = pretrained_model(x)

decoded = imagenet_labels[np.argsort(result_before_save)[0,::-1][:5]+1]

print("Result before saving:\n", decoded)
 
Downloading data from https://storage.googleapis.com/tensorflow/keras-applications/mobilenet/mobilenet_1_0_224_tf.h5
17227776/17225924 [==============================] - 1s 0us/step
Result before saving:
 ['military uniform' 'bow tie' 'suit' 'bearskin' 'pickelhaube']

該圖像的最高預測是“軍裝”。

 mobilenet_save_path = os.path.join(tmpdir, "mobilenet/1/")
tf.saved_model.save(pretrained_model, mobilenet_save_path)
 
WARNING:tensorflow:From /tmpfs/src/tf_docs_env/lib/python3.6/site-packages/tensorflow/python/ops/resource_variable_ops.py:1817: calling BaseResourceVariable.__init__ (from tensorflow.python.ops.resource_variable_ops) with constraint is deprecated and will be removed in a future version.
Instructions for updating:
If using Keras pass *_constraint arguments to layers.
INFO:tensorflow:Assets written to: /tmp/tmpmjpd1j0o/mobilenet/1/assets

保存路徑遵循TensorFlow Serving使用的約定,其中最後一個路徑組件(此處為1/ )是模型的版本號-它允許Tensorflow Serving之類的工具推斷相對新鮮度。

我們可以加載SavedModel回用Python tf.saved_model.load看看海軍上將Hopper的圖像是如何分類。

 loaded = tf.saved_model.load(mobilenet_save_path)
print(list(loaded.signatures.keys()))  # ["serving_default"]
 
['serving_default']

導入的簽名始終返回字典。要自定義簽名名稱和輸出字典鍵,請參閱在導出期間指定簽名

 infer = loaded.signatures["serving_default"]
print(infer.structured_outputs)
 
{'predictions': TensorSpec(shape=(None, 1000), dtype=tf.float32, name='predictions')}

從SavedModel運行推斷得出的結果與原始模型相同。

 labeling = infer(tf.constant(x))[pretrained_model.output_names[0]]

decoded = imagenet_labels[np.argsort(labeling)[0,::-1][:5]+1]

print("Result after saving and loading:\n", decoded)
 
Result after saving and loading:
 ['military uniform' 'bow tie' 'suit' 'bearskin' 'pickelhaube']

在TensorFlow服務中運行SavedModel

從Python可以使用SavedModels(有關更多信息,請參見下文),但是生產環境通常使用專用服務進行推理,而無需運行Python代碼。使用TensorFlow Serving從SavedModel設置起來很容易。

有關服務的更多詳細信息,請參見TensorFlow服務REST教程 ,包括tensorflow_model_server在筆記本電腦或本地計算機上安裝tensorflow_model_server說明。作為一個簡單的草圖,要服務上面導出的mobilenet模型,只需將模型服務器指向SavedModel目錄:

 nohup tensorflow_model_server \
  --rest_api_port=8501 \
  --model_name=mobilenet \
  --model_base_path="/tmp/mobilenet" >server.log 2>&1
 

然後發送一個請求。

 !pip install -q requests
import json
import numpy
import requests
data = json.dumps({"signature_name": "serving_default",
                   "instances": x.tolist()})
headers = {"content-type": "application/json"}
json_response = requests.post('http://localhost:8501/v1/models/mobilenet:predict',
                              data=data, headers=headers)
predictions = numpy.array(json.loads(json_response.text)["predictions"])
 

所得的predictions與Python的結果相同。

磁盤上的SavedModel格式

SavedModel是一個目錄,其中包含序列化簽名以及運行它們的狀態,包括變量值和詞彙表。

ls {mobilenet_save_path}
assets  saved_model.pb  variables

saved_model.pb文件存儲實際的TensorFlow程序或模型,以及一組命名簽名,每個簽名都標識一個接受張量輸入並產生張量輸出的函數。

SavedModels可能包含模型的多個變體(多個v1.MetaGraphDefs ,使用--tag_set標誌標識為--tag_set saved_model_cli ),但這很少見。創建模型的多個變體的API包括tf.Estimator.experimental_export_all_saved_models和TensorFlow 1.x tf.saved_model.Builder

saved_model_cli show --dir {mobilenet_save_path} --tag_set serve
The given SavedModel MetaGraphDef contains SignatureDefs with the following keys:
SignatureDef key: "__saved_model_init_op"
SignatureDef key: "serving_default"

variables目錄包含一個標準的訓練檢查點(請參閱訓練檢查點指南 )。

ls {mobilenet_save_path}/variables
variables.data-00000-of-00002  variables.data-00001-of-00002  variables.index

assets目錄包含TensorFlow圖使用的文件,例如用於初始化詞彙表的文本文件。在此示例中未使用。

對於TensorFlow圖未使用的任何文件,SavedModels可能有一個assets.extra目錄,例如,有關消費者如何使用SavedModel的信息。 TensorFlow本身不使用此目錄。

保存自定義模型

tf.saved_model.save支持保存tf.Module對象及其子類,例如tf.keras.Layertf.keras.Model

讓我們看一個保存和恢復tf.Module

 class CustomModule(tf.Module):

  def __init__(self):
    super(CustomModule, self).__init__()
    self.v = tf.Variable(1.)

  @tf.function
  def __call__(self, x):
    print('Tracing with', x)
    return x * self.v

  @tf.function(input_signature=[tf.TensorSpec([], tf.float32)])
  def mutate(self, new_v):
    self.v.assign(new_v)

module = CustomModule()
 

保存tf.Module ,將保存通過遞歸遍歷找到的所有tf.Variable屬性, tf.function修飾的方法和tf.Module 。 (有關此遞歸遍歷的更多信息,請參見Checkpoint教程 。)但是,所有Python屬性,函數和數據都會丟失。這意味著保存tf.function時,不會保存任何Python代碼。

如果沒有保存任何Python代碼,那麼SavedModel如何知道如何還原該函數?

簡而言之, tf.function通過跟踪Python代碼以生成ConcreteFunction( tf.Graph周圍的可調用包裝器)來工作。保存tf.function ,實際上是保存了tf.function緩存。

要了解有關tf.function和ConcreteFunctions之間關係的更多信息,請參閱《 tf.function指南》

 module_no_signatures_path = os.path.join(tmpdir, 'module_no_signatures')
module(tf.constant(0.))
print('Saving model...')
tf.saved_model.save(module, module_no_signatures_path)
 
Tracing with Tensor("x:0", shape=(), dtype=float32)
Saving model...
Tracing with Tensor("x:0", shape=(), dtype=float32)
INFO:tensorflow:Assets written to: /tmp/tmpmjpd1j0o/module_no_signatures/assets

加載和使用自定義模型

在Python中加載SavedModel時,所有tf.Variable屬性, tf.function修飾的方法和tf.Module都將與原始保存的tf.Module還原到相同的對象結構中。

 imported = tf.saved_model.load(module_no_signatures_path)
assert imported(tf.constant(3.)).numpy() == 3
imported.mutate(tf.constant(2.))
assert imported(tf.constant(3.)).numpy() == 6
 

由於未保存任何Python代碼, tf.function使用新的輸入簽名調用tf.function將失敗:

 imported(tf.constant([3.]))
 
ValueError: Could not find matching function to call for canonicalized inputs ((,), {}). Only existing signatures are [((TensorSpec(shape=(), dtype=tf.float32, name=u'x'),), {})].

基本微調

可變對象可用,我們可以通過導入的函數進行反向傳播。在簡單的情況下,這足以微調(即重新訓練)SavedModel。

 optimizer = tf.optimizers.SGD(0.05)

def train_step():
  with tf.GradientTape() as tape:
    loss = (10. - imported(tf.constant(2.))) ** 2
  variables = tape.watched_variables()
  grads = tape.gradient(loss, variables)
  optimizer.apply_gradients(zip(grads, variables))
  return loss
 
 for _ in range(10):
  # "v" approaches 5, "loss" approaches 0
  print("loss={:.2f} v={:.2f}".format(train_step(), imported.v.numpy()))
 
loss=36.00 v=3.20
loss=12.96 v=3.92
loss=4.67 v=4.35
loss=1.68 v=4.61
loss=0.60 v=4.77
loss=0.22 v=4.86
loss=0.08 v=4.92
loss=0.03 v=4.95
loss=0.01 v=4.97
loss=0.00 v=4.98

一般微調

Keras的SavedModel提供比普通__call__ 更多的細節,可以解決更高級的微調情況。 TensorFlow Hub建議在共享的SavedModels中提供以下那些(如果適用),以進行微調:

  • 如果模型使用輟學方法或訓練與推理之間的前向傳遞有所不同的另一種技術(例如批處理規範化),則__call__方法採用可選的Python值的training=參數,默認為False但可以設置為True
  • __call__屬性旁邊,有.variable.trainable_variable屬性以及相應的變量列表。 .trainable_variables省略了原本可以訓練但打算在微調期間凍結的.trainable_variables
  • 為了使像Keras這樣的框架將權重正則器表示為圖層或子模型的屬性,還可以使用.regularization_losses屬性。它包含一個零參數函數列表,其值用於增加總損失。

回到最初的MobileNet示例,我們可以看到其中一些示例:

 loaded = tf.saved_model.load(mobilenet_save_path)
print("MobileNet has {} trainable variables: {}, ...".format(
          len(loaded.trainable_variables),
          ", ".join([v.name for v in loaded.trainable_variables[:5]])))
 
MobileNet has 83 trainable variables: conv1/kernel:0, conv1_bn/gamma:0, conv1_bn/beta:0, conv_dw_1/depthwise_kernel:0, conv_dw_1_bn/gamma:0, ...

 trainable_variable_ids = {id(v) for v in loaded.trainable_variables}
non_trainable_variables = [v for v in loaded.variables
                           if id(v) not in trainable_variable_ids]
print("MobileNet also has {} non-trainable variables: {}, ...".format(
          len(non_trainable_variables),
          ", ".join([v.name for v in non_trainable_variables[:3]])))
 
MobileNet also has 54 non-trainable variables: conv1_bn/moving_mean:0, conv1_bn/moving_variance:0, conv_dw_1_bn/moving_mean:0, ...

在導出期間指定簽名

TensorFlow Serving和saved_model_cli等工具可以與saved_model_cli進行交互。為了幫助這些工具確定要使用的ConcreteFunction,我們需要指定服務簽名。 tf.keras.Model自動指定服務簽名,但是我們必須為自定義模塊顯式聲明服務簽名。

默認情況下,在自定義tf.Module不聲明任何簽名。

 assert len(imported.signatures) == 0
 

要聲明服務簽名,請使用signatures kwarg指定ConcreteFunction。指定單個簽名時,其簽名密鑰將為'serving_default' ,其保存為常量tf.saved_model.DEFAULT_SERVING_SIGNATURE_DEF_KEY

 module_with_signature_path = os.path.join(tmpdir, 'module_with_signature')
call = module.__call__.get_concrete_function(tf.TensorSpec(None, tf.float32))
tf.saved_model.save(module, module_with_signature_path, signatures=call)
 
Tracing with Tensor("x:0", dtype=float32)
Tracing with Tensor("x:0", dtype=float32)
INFO:tensorflow:Assets written to: /tmp/tmpmjpd1j0o/module_with_signature/assets

 imported_with_signatures = tf.saved_model.load(module_with_signature_path)
list(imported_with_signatures.signatures.keys())

 
['serving_default']

要導出多個簽名,請將簽名密鑰的字典傳遞給ConcreteFunctions。每個簽名密鑰對應一個混凝土功能。

 module_multiple_signatures_path = os.path.join(tmpdir, 'module_with_multiple_signatures')
signatures = {"serving_default": call,
              "array_input": module.__call__.get_concrete_function(tf.TensorSpec([None], tf.float32))}

tf.saved_model.save(module, module_multiple_signatures_path, signatures=signatures)
 
Tracing with Tensor("x:0", shape=(None,), dtype=float32)
Tracing with Tensor("x:0", shape=(None,), dtype=float32)
INFO:tensorflow:Assets written to: /tmp/tmpmjpd1j0o/module_with_multiple_signatures/assets

 imported_with_multiple_signatures = tf.saved_model.load(module_multiple_signatures_path)
list(imported_with_multiple_signatures.signatures.keys())
 
['serving_default', 'array_input']

默認情況下,輸出張量名稱是相當通用的,例如output_0 。要控制輸出的名稱,請修改tf.function以返回將輸出名稱映射到輸出的字典。輸入的名稱是從Python函數arg名稱派生的。

 class CustomModuleWithOutputName(tf.Module):
  def __init__(self):
    super(CustomModuleWithOutputName, self).__init__()
    self.v = tf.Variable(1.)

  @tf.function(input_signature=[tf.TensorSpec([], tf.float32)])
  def __call__(self, x):
    return {'custom_output_name': x * self.v}

module_output = CustomModuleWithOutputName()
call_output = module_output.__call__.get_concrete_function(tf.TensorSpec(None, tf.float32))
module_output_path = os.path.join(tmpdir, 'module_with_output_name')
tf.saved_model.save(module_output, module_output_path,
                    signatures={'serving_default': call_output})
 
INFO:tensorflow:Assets written to: /tmp/tmpmjpd1j0o/module_with_output_name/assets

 imported_with_output_name = tf.saved_model.load(module_output_path)
imported_with_output_name.signatures['serving_default'].structured_outputs
 
{'custom_output_name': TensorSpec(shape=(), dtype=tf.float32, name='custom_output_name')}

來自估算器的已保存模型

估算器通過tf.Estimator.export_saved_model導出tf.Estimator.export_saved_model 。有關詳細信息,請參見Estimator指南

 input_column = tf.feature_column.numeric_column("x")
estimator = tf.estimator.LinearClassifier(feature_columns=[input_column])

def input_fn():
  return tf.data.Dataset.from_tensor_slices(
    ({"x": [1., 2., 3., 4.]}, [1, 1, 0, 0])).repeat(200).shuffle(64).batch(16)
estimator.train(input_fn)

serving_input_fn = tf.estimator.export.build_parsing_serving_input_receiver_fn(
  tf.feature_column.make_parse_example_spec([input_column]))
estimator_base_path = os.path.join(tmpdir, 'from_estimator')
estimator_path = estimator.export_saved_model(estimator_base_path, serving_input_fn)
 
INFO:tensorflow:Using default config.
WARNING:tensorflow:Using temporary folder as model directory: /tmp/tmp65c02lsq
INFO:tensorflow:Using config: {'_model_dir': '/tmp/tmp65c02lsq', '_tf_random_seed': None, '_save_summary_steps': 100, '_save_checkpoints_steps': None, '_save_checkpoints_secs': 600, '_session_config': allow_soft_placement: true
graph_options {
  rewrite_options {
    meta_optimizer_iterations: ONE
  }
}
, '_keep_checkpoint_max': 5, '_keep_checkpoint_every_n_hours': 10000, '_log_step_count_steps': 100, '_train_distribute': None, '_device_fn': None, '_protocol': None, '_eval_distribute': None, '_experimental_distribute': None, '_experimental_max_worker_delay_secs': None, '_session_creation_timeout_secs': 7200, '_service': None, '_cluster_spec': ClusterSpec({}), '_task_type': 'worker', '_task_id': 0, '_global_id_in_cluster': 0, '_master': '', '_evaluation_master': '', '_is_chief': True, '_num_ps_replicas': 0, '_num_worker_replicas': 1}
WARNING:tensorflow:From /tmpfs/src/tf_docs_env/lib/python3.6/site-packages/tensorflow/python/training/training_util.py:236: Variable.initialized_value (from tensorflow.python.ops.variables) is deprecated and will be removed in a future version.
Instructions for updating:
Use Variable.read_value. Variables in 2.X are initialized automatically both in eager and graph (inside tf.defun) contexts.
INFO:tensorflow:Calling model_fn.
WARNING:tensorflow:From /tmpfs/src/tf_docs_env/lib/python3.6/site-packages/tensorflow/python/feature_column/feature_column_v2.py:540: Layer.add_variable (from tensorflow.python.keras.engine.base_layer_v1) is deprecated and will be removed in a future version.
Instructions for updating:
Please use `layer.add_weight` method instead.
WARNING:tensorflow:From /tmpfs/src/tf_docs_env/lib/python3.6/site-packages/tensorflow/python/keras/optimizer_v2/ftrl.py:144: calling Constant.__init__ (from tensorflow.python.ops.init_ops) with dtype is deprecated and will be removed in a future version.
Instructions for updating:
Call initializer instance with the dtype argument instead of passing it to the constructor
INFO:tensorflow:Done calling model_fn.
INFO:tensorflow:Create CheckpointSaverHook.
INFO:tensorflow:Graph was finalized.
INFO:tensorflow:Running local_init_op.
INFO:tensorflow:Done running local_init_op.
INFO:tensorflow:Calling checkpoint listeners before saving checkpoint 0...
INFO:tensorflow:Saving checkpoints for 0 into /tmp/tmp65c02lsq/model.ckpt.
INFO:tensorflow:Calling checkpoint listeners after saving checkpoint 0...
INFO:tensorflow:loss = 0.6931472, step = 0
INFO:tensorflow:Calling checkpoint listeners before saving checkpoint 50...
INFO:tensorflow:Saving checkpoints for 50 into /tmp/tmp65c02lsq/model.ckpt.
INFO:tensorflow:Calling checkpoint listeners after saving checkpoint 50...
INFO:tensorflow:Loss for final step: 0.4131384.
INFO:tensorflow:Calling model_fn.
INFO:tensorflow:Done calling model_fn.
WARNING:tensorflow:From /tmpfs/src/tf_docs_env/lib/python3.6/site-packages/tensorflow/python/saved_model/signature_def_utils_impl.py:145: build_tensor_info (from tensorflow.python.saved_model.utils_impl) is deprecated and will be removed in a future version.
Instructions for updating:
This function will only be available through the v1 compatibility library as tf.compat.v1.saved_model.utils.build_tensor_info or tf.compat.v1.saved_model.build_tensor_info.
INFO:tensorflow:Signatures INCLUDED in export for Classify: ['serving_default', 'classification']
INFO:tensorflow:Signatures INCLUDED in export for Regress: ['regression']
INFO:tensorflow:Signatures INCLUDED in export for Predict: ['predict']
INFO:tensorflow:Signatures INCLUDED in export for Train: None
INFO:tensorflow:Signatures INCLUDED in export for Eval: None
INFO:tensorflow:Restoring parameters from /tmp/tmp65c02lsq/model.ckpt-50
INFO:tensorflow:Assets added to graph.
INFO:tensorflow:No assets to write.
INFO:tensorflow:SavedModel written to: /tmp/tmpmjpd1j0o/from_estimator/temp-1594862628/saved_model.pb

這個SavedModel接受序列化的tf.Example協議緩衝區,這對於服務很有用。但是我們也可以使用tf.saved_model.load加載它並從Python運行它。

 imported = tf.saved_model.load(estimator_path)

def predict(x):
  example = tf.train.Example()
  example.features.feature["x"].float_list.value.extend([x])
  return imported.signatures["predict"](
    examples=tf.constant([example.SerializeToString()]))
 
 print(predict(1.5))
print(predict(3.5))
 
{'all_classes': <tf.Tensor: shape=(1, 2), dtype=string, numpy=array([[b'0', b'1']], dtype=object)>, 'logistic': <tf.Tensor: shape=(1, 1), dtype=float32, numpy=array([[0.5451435]], dtype=float32)>, 'probabilities': <tf.Tensor: shape=(1, 2), dtype=float32, numpy=array([[0.45485654, 0.5451435 ]], dtype=float32)>, 'logits': <tf.Tensor: shape=(1, 1), dtype=float32, numpy=array([[0.18106687]], dtype=float32)>, 'class_ids': <tf.Tensor: shape=(1, 1), dtype=int64, numpy=array([[1]])>, 'classes': <tf.Tensor: shape=(1, 1), dtype=string, numpy=array([[b'1']], dtype=object)>, 'all_class_ids': <tf.Tensor: shape=(1, 2), dtype=int32, numpy=array([[0, 1]], dtype=int32)>}
{'all_classes': <tf.Tensor: shape=(1, 2), dtype=string, numpy=array([[b'0', b'1']], dtype=object)>, 'logistic': <tf.Tensor: shape=(1, 1), dtype=float32, numpy=array([[0.21604054]], dtype=float32)>, 'probabilities': <tf.Tensor: shape=(1, 2), dtype=float32, numpy=array([[0.7839595 , 0.21604055]], dtype=float32)>, 'logits': <tf.Tensor: shape=(1, 1), dtype=float32, numpy=array([[-1.2888912]], dtype=float32)>, 'class_ids': <tf.Tensor: shape=(1, 1), dtype=int64, numpy=array([[0]])>, 'classes': <tf.Tensor: shape=(1, 1), dtype=string, numpy=array([[b'0']], dtype=object)>, 'all_class_ids': <tf.Tensor: shape=(1, 2), dtype=int32, numpy=array([[0, 1]], dtype=int32)>}

tf.estimator.export.build_raw_serving_input_receiver_fn允許您創建使用原始張量而不是tf.train.Example的輸入函數。

在C ++中加載SavedModel

C ++版本的SavedModel 加載器提供了一個API,用於從路徑加載SavedModel,同時允許SessionOptions和RunOptions。您必須指定與要加載的圖形關聯的標籤。已加載版本的SavedModel稱為SavedModelBundle,其中包含MetaGraphDef及其在其中加載的會話。

 const string export_dir = ...
SavedModelBundle bundle;
...
LoadSavedModel(session_options, run_options, export_dir, {kSavedModelTagTrain},
               &bundle);
 

SavedModel命令行界面的詳細信息

您可以使用SavedModel命令行界面(CLI)來檢查和執行SavedModel。例如,您可以使用CLI檢查模型的SignatureDef 。 CLI使您可以快速確認輸入的Tensor dtype和shape與模型匹配。此外,如果要測試模型,則可以使用CLI進行健全性檢查,方法是傳入各種格式(例如Python表達式)的示例輸入,然後獲取輸出。

安裝SavedModel CLI

廣義上講,您可以通過以下兩種方式之一安裝TensorFlow:

  • 通過安裝預構建的TensorFlow二進製文件。
  • 通過從源代碼構建TensorFlow。

如果通過預構建的TensorFlow二進製文件安裝了TensorFlow,則SavedModel CLI已安裝在系統上,路徑bin/saved_model_cli

如果您是從源代碼構建TensorFlow的,則必須運行以下附加命令來構建saved_model_cli

 $ bazel build tensorflow/python/tools:saved_model_cli
 

命令概述

SavedModel CLI在SavedModel上支持以下兩個命令:

  • show ,顯示可從SavedModel獲得的計算。
  • run ,它從SavedModel運行計算。

show命令

SavedModel包含一個或多個模型變體(技術上為v1.MetaGraphDef ),由它們的標記集標識。要為模型提供服務,您可能想知道每種模型變體中的是哪種SignatureDef ,它們的輸入和輸出是什麼。使用show命令可以按分層順序檢查SavedModel的內容。語法如下:

 usage: saved_model_cli show [-h] --dir DIR [--all]
[--tag_set TAG_SET] [--signature_def SIGNATURE_DEF_KEY]
 

例如,以下命令顯示SavedModel中所有可用的標記集:

 $ saved_model_cli show --dir /tmp/saved_model_dir
The given SavedModel contains the following tag-sets:
serve
serve, gpu
 

以下命令顯示了標記集的所有可用SignatureDef密鑰:

 $ saved_model_cli show --dir /tmp/saved_model_dir --tag_set serve
The given SavedModel `MetaGraphDef` contains `SignatureDefs` with the
following keys:
SignatureDef key: "classify_x2_to_y3"
SignatureDef key: "classify_x_to_y"
SignatureDef key: "regress_x2_to_y3"
SignatureDef key: "regress_x_to_y"
SignatureDef key: "regress_x_to_y2"
SignatureDef key: "serving_default"
 

如果標籤集中有多個標籤,則必須指定所有標籤,每個標籤之間用逗號分隔。例如:

$ saved_model_cli show --dir /tmp/saved_model_dir --tag_set serve,gpu

要顯示特定SignatureDef所有輸入和輸出TensorInfo,請將SignatureDef密鑰傳遞給signature_def選項。當您想知道張量鍵值,輸入張量的dtype和形狀以便稍後執行計算圖時,這非常有用。例如:

 $ saved_model_cli show --dir \
/tmp/saved_model_dir --tag_set serve --signature_def serving_default
The given SavedModel SignatureDef contains the following input(s):
  inputs['x'] tensor_info:
      dtype: DT_FLOAT
      shape: (-1, 1)
      name: x:0
The given SavedModel SignatureDef contains the following output(s):
  outputs['y'] tensor_info:
      dtype: DT_FLOAT
      shape: (-1, 1)
      name: y:0
Method name is: tensorflow/serving/predict
 

要顯示SavedModel中的所有可用信息,請使用--all選項。例如:

$ saved_model_cli show --dir /tmp/saved_model_dir --all
MetaGraphDef with tag-set: 'serve' contains the following SignatureDefs:

signature_def['classify_x2_to_y3']:
  The given SavedModel SignatureDef contains the following input(s):
    inputs['inputs'] tensor_info:
        dtype: DT_FLOAT
        shape: (-1, 1)
        name: x2:0
  The given SavedModel SignatureDef contains the following output(s):
    outputs['scores'] tensor_info:
        dtype: DT_FLOAT
        shape: (-1, 1)
        name: y3:0
  Method name is: tensorflow/serving/classify

...

signature_def['serving_default']:
  The given SavedModel SignatureDef contains the following input(s):
    inputs['x'] tensor_info:
        dtype: DT_FLOAT
        shape: (-1, 1)
        name: x:0
  The given SavedModel SignatureDef contains the following output(s):
    outputs['y'] tensor_info:
        dtype: DT_FLOAT
        shape: (-1, 1)
        name: y:0
  Method name is: tensorflow/serving/predict

run命令

調用run命令運行圖形計算,傳遞輸入,然後顯示(並選擇保存)輸出。語法如下:

 usage: saved_model_cli run [-h] --dir DIR --tag_set TAG_SET --signature_def
                           SIGNATURE_DEF_KEY [--inputs INPUTS]
                           [--input_exprs INPUT_EXPRS]
                           [--input_examples INPUT_EXAMPLES] [--outdir OUTDIR]
                           [--overwrite] [--tf_debug]
 

run命令提供以下三種將輸入傳遞到模型的方式:

  • --inputs選項使您可以在文件中傳遞numpy ndarray。
  • --input_exprs選項使您可以傳遞Python表達式。
  • --input_examples選項使您可以傳遞tf.train.Example

--inputs

要在文件中傳遞輸入數據,請指定--inputs選項,該選項採用以下常規格式:

 --inputs <INPUTS>
 

其中INPUTS為以下格式之一:

  • <input_key>=<filename>
  • <input_key>=<filename>[<variable_name>]

您可以傳遞多個INPUTS 。如果您確實傳遞了多個輸入,請使用分號分隔每個輸入

saved_model_cli使用numpy.load加載文件名文件名可以採用以下任何一種格式:

  • .npy
  • .npz
  • 泡菜格式

.npy文件始終包含一個numpy ndarray。因此,從.npy文件加載時,內容將直接分配給指定的輸入張量。如果您為該.npy文件指定了一個variable_name ,則該variable_name將被忽略並發出警告。

.npz (zip)文件加載時,可以選擇指定variable_name來標識要加載的zip文件中輸入張量鍵的變量。如果未指定variable_name ,則SavedModel CLI將檢查zip文件中是否僅包含一個文件,並為指定的輸入張量鍵加載該文件。

從泡菜文件加載時,如果在方括號中未指定variable_name ,則泡菜文件中的所有內容都將傳遞到指定的輸入張量鍵。否則,SavedModel CLI將假定字典存儲在pickle文件中,並且將使用與variable_name對應的值。

--input_exprs

要通過Python表達式傳遞輸入,請指定--input_exprs選項。當您沒有數據文件,但仍然希望使用一些簡單輸入來匹配模型的SignatureDef的dtype和形狀時,這可能會很有用。例如:

 `<input_key>=[[1],[2],[3]]`
 

除了Python表達式外,您還可以傳遞numpy函數。例如:

 `<input_key>=np.ones((32,32,3))`
 

(請注意, numpy模塊已經可以使用np 。)

--input_examples

要將tf.train.Example傳遞為輸入,請指定--input_examples選項。對於每個輸入鍵,它需要一個字典列表,其中每個字典都是tf.train.Example一個實例。字典鍵是要素,值是每個要素的值列表。例如:

 `<input_key>=[{"age":[22,24],"education":["BS","MS"]}]`
 

保存輸出

默認情況下,SavedModel CLI將輸出寫入標準輸出。如果將目錄傳遞給--outdir選項,則輸出將另存為.npy文件,該文件以給定目錄下的輸出張量鍵命名。

使用--overwrite覆蓋現有的輸出文件。