Questa pagina è stata tradotta dall'API Cloud Translation.
Switch to English

Utilizzando il formato SavedModel

Visualizza su TensorFlow.org Esegui in Google Colab Visualizza sorgente su GitHub Scarica il quaderno

Un SavedModel contiene un programma TensorFlow completo, inclusi pesi e calcolo. Non richiede l'esecuzione del codice di costruzione del modello originale, che lo rende utile per la condivisione o la distribuzione (con TFLite , TensorFlow.js , TensorFlow Serving o TensorFlow Hub ).

Questo documento approfondisce alcuni dei dettagli su come utilizzare l'API tf.saved_model basso livello:

Creazione di un modello salvato da Keras

Per una rapida introduzione, questa sezione esporta un modello Keras pre-addestrato e serve richieste di classificazione delle immagini. Il resto della guida inserirà i dettagli e discuterà di altri modi per creare 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

Useremo un'immagine di Grace Hopper come esempio corrente e un modello di classificazione delle immagini pre-addestrato di Keras poiché è facile da usare. Anche i modelli personalizzati funzionano e verranno trattati in dettaglio in seguito.

 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 previsione principale per questa immagine è "uniforme militare".

 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

Il percorso di salvataggio segue una convenzione utilizzata da TensorFlow Serving in cui l'ultimo componente del percorso ( 1/ qui) è un numero di versione per il tuo modello - consente a strumenti come Tensorflow Serving di ragionare sulla relativa freschezza.

Possiamo caricare nuovamente SavedModel in Python con tf.saved_model.load e vedere come viene classificata l'immagine dell'ammiraglio Hopper.

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

Le firme importate restituiscono sempre dizionari. Per personalizzare i nomi delle firme e le chiavi del dizionario di output, vedere Specifica delle firme durante l'esportazione .

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

L'esecuzione dell'inferenza dal SavedModel fornisce lo stesso risultato del modello originale.

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

Esecuzione di un SavedModel nel servizio TensorFlow

SavedModels è utilizzabile da Python (ne parleremo più avanti), ma in genere gli ambienti di produzione utilizzano un servizio dedicato per l'inferenza senza eseguire il codice Python. È facile da configurare da un SavedModel utilizzando TensorFlow Serving.

Consulta l' esercitazione REST di servizio TensorFlow per ulteriori dettagli sulla pubblicazione, comprese le istruzioni per l'installazione di tensorflow_model_server su un notebook o sul tuo computer locale. Come schizzo rapido, per servire il modello mobilenet esportato sopra basta puntare il server modello nella directory SavedModel:

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

Quindi inviare una richiesta.

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

Le predictions risultanti sono identiche ai risultati di Python.

Il formato SavedModel su disco

Un SavedModel è una directory contenente firme serializzate e lo stato necessario per eseguirle, inclusi valori variabili e vocabolari.

ls {mobilenet_save_path}
assets  saved_model.pb  variables

Il file saved_model.pb memorizza il programma o modello TensorFlow effettivo e un insieme di firme denominate, ciascuna delle quali identifica una funzione che accetta input tensore e produce output tensore.

SavedModels possono contenere molteplici varianti del modello (multiple v1.MetaGraphDefs , identificati con il --tag_set bandiera saved_model_cli ), ma questo è raro. Le API che creano più varianti di un modello includono tf.Estimator.experimental_export_all_saved_models e in 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"

La directory delle variables contiene un checkpoint di addestramento standard (consultare la guida ai checkpoint di addestramento ).

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

La directory delle assets contiene i file utilizzati dal grafico TensorFlow, ad esempio i file di testo utilizzati per inizializzare le tabelle del vocabolario. Non è utilizzato in questo esempio.

SavedModels può avere una directory assets.extra per tutti i file non utilizzati dal grafico TensorFlow, ad esempio informazioni per i consumatori su cosa fare con SavedModel. TensorFlow stesso non utilizza questa directory.

Salvataggio di un modello personalizzato

tf.saved_model.save supporta il salvataggio di oggetti tf.Module e delle sue sottoclassi, come tf.keras.Layer e tf.keras.Model .

Diamo un'occhiata a un esempio di salvataggio e ripristino di 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()
 

Quando si salva un tf.Module , vengono tf.Module tutti tf.Variable attributi tf.Variable, i metodi tf.function tf.function e i tf.Module trovati tramite l'attraversamento ricorsivo. (Vedi il tutorial di Checkpoint per maggiori informazioni su questo attraversamento ricorsivo.) Tuttavia, qualsiasi attributo, funzione e dato di Python andranno persi. Ciò significa che quando viene salvata una funzione tf.function , non viene salvato alcun codice Python.

Se non viene salvato alcun codice Python, come fa SavedModel a ripristinare la funzione?

In breve, tf.function funziona tracciando il codice Python per generare un ConcreteFunction (un wrapper richiamabile attorno a tf.Graph ). Quando si salva una funzione tf.function , si sta davvero salvando la cache di ConcreteFunctions della funzione tf.function .

Per ulteriori informazioni sulla relazione tra tf.function e ConcreteFunctions, consultare la guida di 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

Caricamento e utilizzo di un modello personalizzato

Quando si carica un SavedModel in Python, tutti tf.Variable attributi tf.Variable , i metodi tf.function tf.function e tf.Module vengono ripristinati nella stessa struttura dell'oggetto del tf.Module salvato originale.

 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
 

Poiché non viene salvato alcun codice Python, la chiamata a una funzione tf.function con una nuova firma di input non riuscirà:

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

Messa a punto di base

Sono disponibili oggetti variabili e possiamo eseguire il backprop attraverso le funzioni importate. Ciò è sufficiente per mettere a punto (ad esempio riqualificare) un modello salvato in casi semplici.

 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

Messa a punto generale

Un SavedModel di Keras fornisce più dettagli di un semplice __call__ per risolvere casi più avanzati di messa a punto. TensorFlow Hub consiglia di fornire quanto segue, se applicabile, nei modelli Saved condivisi ai fini della messa a punto:

  • Se il modello utilizza il dropout o un'altra tecnica in cui il passaggio in avanti differisce tra training e inferenza (come la normalizzazione batch), il metodo __call__ accetta un argomento training= valore Python facoltativo che viene impostato su False ma che può essere impostato su True .
  • Accanto all'attributo __call__ , ci sono attributi .variable e .trainable_variable con i corrispondenti elenchi di variabili. Una variabile che era originariamente allenabile ma che doveva essere congelata durante la messa a punto viene omessa da .trainable_variables .
  • Per motivi di framework come Keras che rappresentano i regolarizzatori del peso come attributi di layer o sottomodelli, può esserci anche un attributo .regularization_losses . Contiene un elenco di funzioni a argomento zero i cui valori sono intesi per l'aggiunta alla perdita totale.

Tornando all'esempio iniziale di MobileNet, possiamo vedere alcuni di quelli in azione:

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

Specifica delle firme durante l'esportazione

Strumenti come TensorFlow Serving e saved_model_cli possono interagire con SavedModels. Per aiutare questi strumenti a determinare quali ConcreteFunctions utilizzare, dobbiamo specificare le firme di pubblicazione. tf.keras.Model specifica automaticamente le firme di pubblicazione, ma dovremo dichiarare esplicitamente una firma di pubblicazione per i nostri moduli personalizzati.

Per impostazione predefinita, nessuna firma viene dichiarata in un tf.Module . personalizzato.

 assert len(imported.signatures) == 0
 

Per dichiarare una firma di pubblicazione, specifica una ConcreteFunction utilizzando le signatures kwarg. Quando si specifica una singola firma, la sua chiave di firma sarà 'serving_default' , che viene salvata come costante 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']

Per esportare più firme, passare un dizionario di chiavi di firma a ConcreteFunctions. Ogni chiave di firma corrisponde a una funzione Concrete.

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

Per impostazione predefinita, i nomi dei tensori di output sono abbastanza generici, come output_0 . Per controllare i nomi degli output, modificare la funzione tf.function restituire un dizionario che associa i nomi degli output agli output. I nomi degli input sono derivati ​​dai nomi arg della funzione 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')}

Modelli salvati dagli stimatori

Gli stimatori esportano SavedModels tramite tf.Estimator.export_saved_model . Per i dettagli, consultare la guida allo stimatore .

 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

Questo SavedModel accetta buffer di protocollo tf.Example serializzati, utili per la pubblicazione. Ma possiamo anche caricarlo con tf.saved_model.load ed eseguirlo da 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 consente di creare funzioni di input che accettano tensori grezzi anziché tf.train.Example s.

Carica un SavedModel in C ++

La versione C ++ del caricatore SavedModel fornisce un'API per caricare un SavedModel da un percorso, consentendo al contempo SessionOptions e RunOptions. Devi specificare i tag associati al grafico da caricare. La versione caricata di SavedModel viene definita SavedModelBundle e contiene MetaGraphDef e la sessione in cui viene caricata.

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

Dettagli dell'interfaccia della riga di comando di SavedModel

È possibile utilizzare l'interfaccia della riga di comando (CLI) SavedModel per ispezionare ed eseguire un SavedModel. Ad esempio, è possibile utilizzare l'interfaccia della riga di comando per ispezionare i SignatureDef del modello. L'interfaccia della riga di comando consente di confermare rapidamente che il tipo e la forma del tensore dell'input corrispondono al modello. Inoltre, se si desidera testare il modello, è possibile utilizzare l'interfaccia della riga di comando per eseguire un controllo di integrità passando input di esempio in vari formati (ad esempio, espressioni Python) e quindi recuperando l'output.

Installare l'interfaccia della riga di comando SavedModel

In generale, è possibile installare TensorFlow in uno dei due modi seguenti:

  • Installando un binario TensorFlow pre-costruito.
  • Compilando TensorFlow dal codice sorgente.

Se TensorFlow è stato installato tramite un binario TensorFlow preconfigurato, l'interfaccia della riga di comando SavedModel è già installata sul sistema in nome percorso bin/saved_model_cli .

Se hai creato TensorFlow dal codice sorgente, devi eseguire il seguente comando aggiuntivo per saved_model_cli :

 $ bazel build tensorflow/python/tools:saved_model_cli
 

Panoramica dei comandi

L'interfaccia della riga di comando SavedModel supporta i seguenti due comandi su un SavedModel:

  • show , che mostra i calcoli disponibili da un SavedModel.
  • run , che esegue un calcolo da un SavedModel.

show comando

Un SavedModel contiene una o più varianti di modello (tecnicamente, v1.MetaGraphDef s), identificate dai loro set di tag. Per servire un modello, potresti chiederti che tipo di SignatureDef sono presenti in ogni variante di modello e quali sono i loro input e output. Il comando show consente di esaminare i contenuti di SavedModel in ordine gerarchico. Ecco la sintassi:

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

Ad esempio, il comando seguente mostra tutti i set di tag disponibili in SavedModel:

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

Il comando seguente mostra tutte le chiavi SignatureDef disponibili per un set di tag:

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

Se ci sono più tag nel set di tag, è necessario specificare tutti i tag, ognuno dei quali è separato da una virgola. Per esempio:

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

Per mostrare tutti gli input e output TensorInfo per uno specifico SignatureDef , passa la chiave SignatureDef all'opzione signature_def . Ciò è molto utile quando si desidera conoscere il valore della chiave del tensore, il tipo e la forma dei tensori di input per eseguire il grafico di calcolo in un secondo momento. Per esempio:

 $ 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
 

Per mostrare tutte le informazioni disponibili in SavedModel, utilizzare l'opzione --all . Per esempio:

$ 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

Richiamare il comando run per eseguire un calcolo grafico, passando input e quindi visualizzando (e facoltativamente salvando) gli output. Ecco la sintassi:

 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]
 

Il comando di run fornisce i seguenti tre modi per passare input al modello:

  • --inputs opzione --inputs ti consente di passare numpy ndarray nei file.
  • --input_exprs opzione --input_exprs ti consente di passare le espressioni Python.
  • --input_examples opzione --input_examples ti consente di passare tf.train.Example .

--inputs

Per passare i dati di input nei file, specifica l'opzione --inputs , che assume il seguente formato generale:

 --inputs <INPUTS>
 

dove INPUTS è uno dei seguenti formati:

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

È possibile passare più INGRESSI . Se si passano più input, utilizzare un punto e virgola per separare ciascuno degli INPUT .

saved_model_cli utilizza numpy.load per caricare il nome file . Il nome file può essere in uno dei seguenti formati:

  • .npy
  • .npz
  • formato sottaceto

Un file .npy contiene sempre un ndarray intorpidito. Pertanto, quando si carica da un file .npy , il contenuto verrà assegnato direttamente al tensore di input specificato. Se si specifica un nome_variabile con quella .npy file, il nome_variabile verrà ignorato e verrà emesso un avviso.

Al termine del caricamento da un .npz del file (zip), si può opzionalmente specificare un nome_variabile per identificare la variabile all'interno del file zip da caricare per la chiave di ingresso tensore. Se non si specifica un nome_variabile, il SavedModel CLI controllerà che solo un file è incluso nel file zip e caricarlo per la chiave di ingresso tensore specificato.

Al termine del caricamento da un file salamoia, se non variable_name è specificato nelle parentesi quadre, qualunque essa sia all'interno del file salamoia verrà passato alla chiave di ingresso tensore specificato. Altrimenti, il SavedModel CLI assumerà un dizionario è memorizzato nel file salamoia e verrà utilizzato il valore corrispondente alla variable_name.

--input_exprs

Per passare input attraverso le espressioni Python, specifica l'opzione --input_exprs . Questo può essere utile quando non ci sono file di dati in giro, ma vuoi comunque controllare la sanità mentale del modello con alcuni input semplici che corrispondono al tipo e alla forma dei SignatureDef del modello. Per esempio:

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

Oltre alle espressioni Python, puoi anche passare funzioni intorpidite. Per esempio:

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

(Nota che il modulo numpy è già disponibile come np .)

--input_examples

Per passare tf.train.Example come input, specificare l'opzione --input_examples . Per ogni chiave di input, prende un elenco di dizionario, in cui ogni dizionario è un'istanza di tf.train.Example . Le chiavi del dizionario sono le funzionalità e i valori sono gli elenchi di valori per ciascuna funzionalità. Per esempio:

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

Salva output

Per impostazione predefinita, l'interfaccia della riga di comando SavedModel scrive l'output su stdout. Se una directory viene passata all'opzione --outdir , gli output verranno salvati come file .npy che .npy nome dalle chiavi del tensore dell'output nella directory specificata.

Utilizzare --overwrite per sovrascrivere i file di output esistenti.