Se usó la API de Cloud Translation para traducir esta página.
Switch to English

Usando el formato SavedModel

Ver en TensorFlow.org Ejecutar en Google Colab Ver código fuente en GitHub Descargar cuaderno

Un modelo guardado contiene un programa completo de TensorFlow, que incluye pesos y cálculo. No requiere que se ejecute el código de construcción del modelo original, lo que lo hace útil para compartir o implementar (con TFLite , TensorFlow.js , TensorFlow Serving o TensorFlow Hub ).

Este documento profundiza en algunos de los detalles de cómo usar la API tf.saved_model bajo nivel:

Crear un modelo guardado a partir de Keras

Para una introducción rápida, esta sección exporta un modelo Keras previamente entrenado y sirve solicitudes de clasificación de imágenes con él. El resto de la guía completará los detalles y analizará otras formas de crear modelos guardados.

 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

Utilizaremos una imagen de Grace Hopper como ejemplo en ejecución, y un modelo de clasificación de imágenes pre-entrenado de Keras, ya que es fácil de usar. Los modelos personalizados también funcionan y se detallan más adelante.

 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']

La principal predicción para esta imagen es "uniforme militar".

 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

Save-path sigue una convención utilizada por TensorFlow Serving, donde el último componente de ruta ( 1/ aquí) es un número de versión para su modelo: permite que herramientas como Tensorflow Serving razonen sobre la relativa frescura.

Podemos volver a cargar el modelo guardado en Python con tf.saved_model.load y ver cómo se clasifica la imagen del almirante Hopper.

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

Las firmas importadas siempre devuelven diccionarios. Para personalizar los nombres de firma y las claves del diccionario de salida, consulte Especificación de firmas durante la exportación .

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

Ejecutar inferencia desde el modelo guardado da el mismo resultado que el modelo original.

 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']

Ejecutar un modelo guardado en la publicación TensorFlow

SavedModels son utilizables desde Python (más sobre eso a continuación), pero los entornos de producción generalmente usan un servicio dedicado para inferencia sin ejecutar código Python. Esto es fácil de configurar desde un modelo guardado utilizando TensorFlow Serving.

Consulte el tutorial de REST TendingFlow Serving para obtener más detalles sobre el servicio, incluidas las instrucciones para instalar tensorflow_model_server en una computadora portátil o en su máquina local. Como un bosquejo rápido, para servir el modelo de mobilenet exportado arriba, solo apunte el servidor del modelo al directorio de SavedModel:

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

Luego envíe una solicitud.

 !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"])
 

Las predictions resultantes son idénticas a los resultados de Python.

El formato SavedModel en el disco

Un modelo guardado es un directorio que contiene firmas serializadas y el estado necesario para ejecutarlas, incluidos valores variables y vocabularios.

ls {mobilenet_save_path}
assets  saved_model.pb  variables

El archivo saved_model.pb almacena el programa o modelo TensorFlow real y un conjunto de firmas con nombre, cada uno de los cuales identifica una función que acepta entradas de tensor y produce salidas de tensor.

SavedModels puede contener múltiples variantes del modelo (múltiples v1.MetaGraphDefs , identificados con el --tag_set en saved_model_cli ), pero esto es raro. Las API que crean múltiples variantes de un modelo incluyen tf.Estimator.experimental_export_all_saved_models y en 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"

El directorio de variables contiene un punto de control de entrenamiento estándar (consulte la guía de puntos de control de entrenamiento ).

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

El directorio de assets contiene archivos utilizados por el gráfico TensorFlow, por ejemplo, archivos de texto utilizados para inicializar tablas de vocabulario. No se usa en este ejemplo.

SavedModels puede tener un directorio assets.extra para cualquier archivo no utilizado por el gráfico TensorFlow, por ejemplo, información para los consumidores sobre qué hacer con el SavedModel. TensorFlow en sí no utiliza este directorio.

Guardar un modelo personalizado

tf.saved_model.save admite guardar objetos tf.Module y sus subclases, como tf.keras.Layer y tf.keras.Model .

Veamos un ejemplo de guardar y restaurar un 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()
 

Cuando guarda un tf.Module , se tf.Variable atributos tf.function , los métodos tf.Module y los tf.Module s encontrados a través del recorrido recursivo. (Consulte el tutorial de Checkpoint para obtener más información sobre este recorrido recursivo). Sin embargo, se pierden todos los atributos, funciones y datos de Python. Esto significa que cuando se guarda una función tf.function , no se guarda ningún código de Python.

Si no se guarda ningún código de Python, ¿cómo sabe SavedModel cómo restaurar la función?

Brevemente, tf.function funciona rastreando el código de Python para generar una ConcreteFunction (un contenedor invocable alrededor de tf.Graph ). Al guardar una función tf.function realmente está guardando la caché de tf.function de ConcreteFunctions.

Para obtener más información sobre la relación entre tf.function y ConcreteFunctions, consulte la guía de 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

Cargando y usando un modelo personalizado

Cuando se carga un SavedModel en Python, todos tf.Variable atributos, tf.function -decorated métodos y tf.Module s se restauran en la misma estructura del objeto que el original guardado 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
 

Debido a que no se guarda ningún código de Python, tf.function llamada a una función tf.function con una nueva firma de entrada:

 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'),), {})].

Ajuste básico

Los objetos variables están disponibles y podemos retroceder a través de funciones importadas. Eso es suficiente para ajustar (es decir, reentrenar) un modelo guardado en casos simples.

 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

Ajuste general

Un modelo guardado de Keras proporciona más detalles que una simple __call__ para abordar casos más avanzados de ajuste. TensorFlow Hub recomienda proporcionar los siguientes, si corresponde, en los modelos guardados compartidos con el fin de realizar ajustes:

  • Si el modelo usa el abandono u otra técnica en la cual el pase hacia adelante difiere entre entrenamiento e inferencia (como la normalización por lotes), el método __call__ toma un argumento opcional de training= valor de Python training= que está predeterminado en False pero se puede establecer en True .
  • Junto al atributo __call__ , hay atributos .variable y .trainable_variable con las listas de variables correspondientes. Una variable que originalmente era entrenable pero que está destinada a congelarse durante el ajuste fino se omite de .trainable_variables .
  • En aras de marcos como Keras que representan regularizadores de peso como atributos de capas o submodelos, también puede haber un atributo .regularization_losses . Contiene una lista de funciones de argumento cero cuyos valores están destinados a sumarse a la pérdida total.

Volviendo al ejemplo inicial de MobileNet, podemos ver algunos de ellos en acción:

 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, ...

Especificación de firmas durante la exportación

Herramientas como TensorFlow Serving y saved_model_cli pueden interactuar con SavedModels. Para ayudar a estas herramientas a determinar qué funciones concretas usar, necesitamos especificar firmas de publicación. tf.keras.Model s especifica automáticamente las firmas de publicación, pero tendremos que declarar explícitamente una firma de publicación para nuestros módulos personalizados.

Por defecto, no se declaran firmas en un tf.Module personalizado.

 assert len(imported.signatures) == 0
 

Para declarar una firma de servicio, especifique una función concreta utilizando las signatures kwarg. Al especificar una sola firma, su clave de firma será 'serving_default' , que se guarda como la constante 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']

Para exportar múltiples firmas, pase un diccionario de claves de firma a ConcreteFunctions. Cada clave de firma corresponde a una función concreta.

 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']

Por defecto, los nombres del tensor de salida son bastante genéricos, como output_0 . Para controlar los nombres de las salidas, modifique su función tf.function para devolver un diccionario que tf.function los nombres de salida a las salidas. Los nombres de las entradas se derivan de los nombres arg de la función Python.

 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')}

Modelos guardados de estimadores

Los estimadores exportan modelos guardados a través de tf.Estimator.export_saved_model . Vea la guía del Estimador para más detalles.

 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

Este modelo guardado acepta tf serializados, tf.Example búferes de protocolo, que son útiles para servir. Pero también podemos cargarlo con tf.saved_model.load y ejecutarlo desde 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 permite crear funciones de entrada que toman tensores en bruto en lugar de tf.train.Example s.

Cargar un modelo guardado en C ++

La versión C ++ del cargador SavedModel proporciona una API para cargar un GuardadoModelo desde una ruta, al tiempo que permite SessionOptions y RunOptions. Debe especificar las etiquetas asociadas con el gráfico que se cargará. La versión cargada de SavedModel se conoce como SavedModelBundle y contiene MetaGraphDef y la sesión en la que se carga.

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

Detalles de la interfaz de línea de comandos SavedModel

Puede usar la interfaz de línea de comandos (CLI) de SavedModel para inspeccionar y ejecutar un modelo guardado. Por ejemplo, puede usar la CLI para inspeccionar los SignatureDef del modelo. La CLI le permite confirmar rápidamente que el tipo y la forma del tensor de entrada coinciden con el modelo. Además, si desea probar su modelo, puede usar la CLI para hacer una verificación de cordura pasando entradas de muestra en varios formatos (por ejemplo, expresiones Python) y luego obteniendo la salida.

Instale la CLI de SavedModel

En términos generales, puede instalar TensorFlow de cualquiera de las dos formas siguientes:

  • Mediante la instalación de un binario TensorFlow preconstruido.
  • Al construir TensorFlow a partir del código fuente.

Si instaló TensorFlow a través de un binario TensorFlow preconstruido, entonces la CLI de SavedModel ya está instalada en su sistema en el nombre de ruta bin/saved_model_cli .

Si compiló TensorFlow a partir del código fuente, debe ejecutar el siguiente comando adicional para compilar saved_model_cli :

 $ bazel build tensorflow/python/tools:saved_model_cli
 

Resumen de comandos

La CLI de SavedModel admite los siguientes dos comandos en un SavedModel:

  • show , que muestra los cálculos disponibles desde un modelo guardado.
  • run , que ejecuta un cálculo desde un modelo guardado.

comando show

Un modelo guardado contiene una o más variantes de modelo (técnicamente, v1.MetaGraphDef s), identificadas por sus conjuntos de etiquetas. Para servir un modelo, puede preguntarse qué tipo de SignatureDef s hay en cada variante del modelo y cuáles son sus entradas y salidas. El comando show permite examinar el contenido del modelo guardado en orden jerárquico. Aquí está la sintaxis:

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

Por ejemplo, el siguiente comando muestra todos los conjuntos de etiquetas disponibles en el Modelo guardado:

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

El siguiente comando muestra todas las claves SignatureDef disponibles para un conjunto de etiquetas:

 $ 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"
 

Si hay varias etiquetas en el conjunto de etiquetas, debe especificar todas las etiquetas, cada etiqueta separada por una coma. Por ejemplo:

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

Para mostrar todas las entradas y salidas de TensorInfo para un SignatureDef específico, pase la clave SignatureDef a la opción signature_def . Esto es muy útil cuando desea conocer el valor de la clave del tensor, el tipo y la forma de los tensores de entrada para ejecutar el gráfico de cálculo más adelante. Por ejemplo:

 $ 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
 

Para mostrar toda la información disponible en el Modelo Guardado, use la opción --all . Por ejemplo:

$ 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 comando

Invocar la run de comandos para ejecutar un cálculo gráfico, pasando entradas y, a continuación se presentan (y opcionalmente guardar) las salidas. Aquí está la sintaxis:

 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]
 

El comando run proporciona las siguientes tres formas de pasar entradas al modelo:

  • --inputs opción de --inputs permite pasar ndarray numpy en los archivos.
  • --input_exprs opción --input_exprs permite pasar expresiones de Python.
  • --input_examples opción --input_examples permite pasar tf.train.Example .

--inputs

Para pasar datos de entrada en archivos, especifique la opción --inputs , que toma el siguiente formato general:

 --inputs <INPUTS>
 

donde INPUTS tiene cualquiera de los siguientes formatos:

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

Puede pasar múltiples ENTRADAS . Si pasa varias entradas, use un punto y coma para separar cada una de las ENTRADAS .

saved_model_cli usa numpy.load para cargar el nombre del archivo . El nombre del archivo puede estar en cualquiera de los siguientes formatos:

  • .npy
  • .npz
  • formato de pepinillo

Un archivo .npy siempre contiene un ndarray numpy. Por lo tanto, cuando se carga desde un archivo .npy , el contenido se asignará directamente al tensor de entrada especificado. Si especifica un variable_name con ese .npy archivo, el variable_name tendrá en cuenta y se emitirá una advertencia.

Al cargar desde un .npz (zip), puede especificar opcionalmente un variable_name para identificar la variable dentro del archivo zip para cargar la clave tensora de entrada. Si no se especifica un variable_name, la CLI SavedModel comprobará que sólo un archivo se incluye en el archivo zip y cargarlo para la llave tensor de entrada especificado.

Al cargar desde un archivo pickle, si no se especifica variable_name entre corchetes, lo que esté dentro del archivo pickle se pasará a la clave tensora de entrada especificada. De lo contrario, el SavedModel CLI asumirá un diccionario se almacena en el archivo de salmuera y se utilizará el valor que corresponde a la variable_name.

--input_exprs

Para pasar entradas a través de expresiones de Python, especifique la opción --input_exprs . Esto puede ser útil para cuando no tiene archivos de datos por ahí, pero todavía desea verificar el modelo con algunas entradas simples que coincidan con el tipo y la forma de SignatureDef s del modelo. Por ejemplo:

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

Además de las expresiones de Python, también puede pasar funciones numpy. Por ejemplo:

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

(Tenga en cuenta que el módulo numpy ya está disponible para usted como np .)

--input_examples

Para pasar tf.train.Example como entradas, especifique la opción --input_examples . Para cada clave de entrada, toma una lista de diccionario, donde cada diccionario es una instancia de tf.train.Example . Las claves del diccionario son las características y los valores son las listas de valores para cada característica. Por ejemplo:

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

Guardar salida

Por defecto, la CLI de SavedModel escribe la salida en stdout. Si se pasa un directorio a la opción --outdir , las salidas se guardarán como archivos .npy nombre de las teclas tensoras de salida en el directorio dado.

Use --overwrite para sobrescribir los archivos de salida existentes.