Utilisation du format SavedModel

Voir sur TensorFlow.org Exécuter dans Google Colab Voir la source sur GitHub Télécharger le cahier

Un SavedModel contient un programme TensorFlow complet, y compris des paramètres entraînés (par exemple, tf.Variable s) et des calculs. Il ne nécessite pas l'exécution du code de construction du modèle d'origine, ce qui le rend utile pour le partage ou le déploiement avec TFLite , TensorFlow.js , TensorFlow Serving ou TensorFlow Hub .

Vous pouvez enregistrer et charger un modèle au format SavedModel à l'aide des API suivantes :

Création d'un modèle enregistré à partir de Keras

Pour une introduction rapide, cette section exporte un modèle Keras pré-formé et sert les demandes de classification d'images avec celui-ci. Le reste du guide fournira des détails et discutera d'autres façons de créer des 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.list_physical_devices('GPU')
for device in physical_devices:
  tf.config.experimental.set_memory_growth(device, 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.utils.load_img(file, target_size=[224, 224])
plt.imshow(img)
plt.axis('off')
x = tf.keras.utils.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
73728/61306 [====================================] - 0s 0us/step

png

Vous utiliserez une image de Grace Hopper comme exemple courant et un modèle de classification d'image préformé Keras car il est facile à utiliser. Les modèles personnalisés fonctionnent également et sont détaillés plus tard.

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
24576/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 [==============================] - 0s 0us/step
17235968/17225924 [==============================] - 0s 0us/step
Result before saving:
 ['military uniform' 'bow tie' 'suit' 'bearskin' 'pickelhaube']

La meilleure prédiction pour cette image est "l'uniforme militaire".

mobilenet_save_path = os.path.join(tmpdir, "mobilenet/1/")
tf.saved_model.save(pretrained_model, mobilenet_save_path)
2021-10-27 01:24:27.831628: W tensorflow/python/util/util.cc:348] Sets are not currently considered sequences, but this may change in the future, so consider avoiding using them.
INFO:tensorflow:Assets written to: /tmp/tmpbf9fpzwt/mobilenet/1/assets

Le chemin de sauvegarde suit une convention utilisée par TensorFlow Serving où le dernier composant de chemin ( 1/ ici) est un numéro de version pour votre modèle - il permet à des outils comme Tensorflow Serving de raisonner sur la fraîcheur relative.

Vous pouvez recharger le SavedModel dans Python avec tf.saved_model.load et voir comment l'image de l'amiral Hopper est classée.

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

Les signatures importées renvoient toujours des dictionnaires. Pour personnaliser les noms de signature et les clés de dictionnaire de sortie, voir Spécification des signatures lors de l'exportation .

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

L'exécution de l'inférence à partir de SavedModel donne le même résultat que le modèle d'origine.

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

Exécuter un SavedModel dans TensorFlow Serving

Les SavedModels sont utilisables à partir de Python (plus d'informations ci-dessous), mais les environnements de production utilisent généralement un service dédié pour l'inférence sans exécuter de code Python. Ceci est facile à configurer à partir d'un modèle enregistré à l'aide de TensorFlow Serving.

Consultez le didacticiel TensorFlow Serving REST pour un exemple de diffusion Tensorflow de bout en bout.

Le format SavedModel sur disque

Un SavedModel est un répertoire contenant des signatures sérialisées et l'état nécessaire pour les exécuter, y compris les valeurs de variables et les vocabulaires.

ls {mobilenet_save_path}
assets  saved_model.pb  variables

Le fichier saved_model.pb stocke le programme ou le modèle TensorFlow réel et un ensemble de signatures nommées, chacune identifiant une fonction qui accepte les entrées de tenseur et produit des sorties de tenseur.

SavedModels peut contenir plusieurs variantes du modèle (plusieurs v1.MetaGraphDefs , identifiés par l'indicateur --tag_set de saved_model_cli ), mais cela est rare. Les API qui créent plusieurs variantes d'un modèle incluent tf.Estimator.experimental_export_all_saved_models et dans 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"

Le répertoire des variables contient un point de contrôle de formation standard (voir le guide des points de contrôle de formation ).

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

Le répertoire assets contient des fichiers utilisés par le graphe TensorFlow, par exemple des fichiers texte utilisés pour initialiser des tables de vocabulaire. Il n'est pas utilisé dans cet exemple.

SavedModels peut avoir un répertoire assets.extra pour tous les fichiers non utilisés par le graphique TensorFlow, par exemple des informations pour les consommateurs sur ce qu'il faut faire avec le SavedModel. TensorFlow lui-même n'utilise pas ce répertoire.

Enregistrer un modèle personnalisé

tf.saved_model.save prend en charge la sauvegarde des objets tf.Module et de ses sous-classes, comme tf.keras.Layer et tf.keras.Model .

Regardons un exemple de sauvegarde et de restauration d'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()

Lorsque vous enregistrez un tf.Module , tous les attributs tf.Variable , les méthodes tf.function -decorated et les tf.Module trouvés par parcours récursif sont enregistrés. (Voir le didacticiel Checkpoint pour en savoir plus sur cette traversée récursive.) Cependant, tous les attributs, fonctions et données Python sont perdus. Cela signifie que lorsqu'une tf.function est enregistrée, aucun code Python n'est enregistré.

Si aucun code Python n'est enregistré, comment SavedModel sait-il comment restaurer la fonction ?

En bref, tf.function fonctionne en traçant le code Python pour générer une ConcreteFunction (un wrapper appelable autour de tf.Graph ). Lorsque vous enregistrez un tf.function , vous enregistrez réellement le cache de ConcreteFunctions de tf.function .

Pour en savoir plus sur la relation entre tf.function et ConcreteFunctions, consultez le guide 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/tmpbf9fpzwt/module_no_signatures/assets

Charger et utiliser un modèle personnalisé

Lorsque vous chargez un SavedModel en Python, tous les attributs tf.Variable , les méthodes tf.function -decorated et les tf.Module sont restaurés dans la même structure d'objet que le tf.Module enregistré d'origine.

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

Comme aucun code Python n'est enregistré, l'appel d'une tf.function avec une nouvelle signature d'entrée échouera :

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

Réglage fin de base

Des objets variables sont disponibles et vous pouvez effectuer un backprop via des fonctions importées. Cela suffit pour affiner (c'est-à-dire recycler) un SavedModel dans des cas 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

Mise au point générale

Un SavedModel de Keras fournit plus de détails qu'un simple __call__ pour traiter des cas de réglage plus avancés. TensorFlow Hub recommande de fournir les éléments suivants, le cas échéant, dans les SavedModels partagés à des fins d'ajustement :

  • Si le modèle utilise l'abandon ou une autre technique dans laquelle la passe avant diffère entre l'apprentissage et l'inférence (comme la normalisation par lots), la méthode __call__ prend un argument facultatif training= à valeur Python qui par défaut est False mais peut être défini sur True .
  • A côté de l'attribut __call__ , il y a les attributs .variable et .trainable_variable avec les listes de variables correspondantes. Une variable qui était à l'origine entraînable mais destinée à être gelée lors du réglage fin est omise de .trainable_variables .
  • Pour les frameworks comme Keras qui représentent les régularisateurs de poids comme des attributs de couches ou de sous-modèles, il peut également y avoir un attribut .regularization_losses . Il contient une liste de fonctions sans argument dont les valeurs sont destinées à être ajoutées à la perte totale.

En revenant à l'exemple initial de MobileNet, vous pouvez en voir quelques-uns en action :

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

Spécification des signatures lors de l'exportation

Des outils tels que TensorFlow Serving et saved_model_cli peuvent interagir avec SavedModels. Pour aider ces outils à déterminer les ConcreteFunctions à utiliser, vous devez spécifier les signatures de service. tf.keras.Model s spécifie automatiquement les signatures de service, mais vous devrez déclarer explicitement une signature de service pour nos modules personnalisés.

Par défaut, aucune signature n'est déclarée dans un tf.Module personnalisé.

assert len(imported.signatures) == 0

Pour déclarer une signature de service, spécifiez une ConcreteFunction en utilisant les signatures kwarg. Lors de la spécification d'une seule signature, sa clé de signature sera 'serving_default' , qui est enregistrée en tant que 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/tmpbf9fpzwt/module_with_signature/assets
imported_with_signatures = tf.saved_model.load(module_with_signature_path)
list(imported_with_signatures.signatures.keys())
['serving_default']

Pour exporter plusieurs signatures, transmettez un dictionnaire de clés de signature à ConcreteFunctions. Chaque clé de signature correspond à une ConcreteFunction.

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

Par défaut, les noms des tenseurs de sortie sont assez génériques, comme output_0 . Pour contrôler les noms des sorties, modifiez votre tf.function pour renvoyer un dictionnaire qui mappe les noms de sortie aux sorties. Les noms des entrées sont dérivés des noms des arguments de la fonction 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/tmpbf9fpzwt/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')}

Charger un SavedModel en C++

La version C++ du chargeur SavedModel fournit une API pour charger un SavedModel à partir d'un chemin, tout en autorisant SessionOptions et RunOptions. Vous devez spécifier les balises associées au graphe à charger. La version chargée de SavedModel est appelée SavedModelBundle et contient le MetaGraphDef et la session dans laquelle il est chargé.

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

Détails de l'interface de ligne de commande SavedModel

Vous pouvez utiliser l'interface de ligne de commande (CLI) SavedModel pour inspecter et exécuter un SavedModel. Par exemple, vous pouvez utiliser la CLI pour inspecter les SignatureDef s du modèle. La CLI vous permet de confirmer rapidement que le dtype et la forme du tenseur d'entrée correspondent au modèle. De plus, si vous souhaitez tester votre modèle, vous pouvez utiliser la CLI pour effectuer une vérification de cohérence en transmettant des exemples d'entrées dans différents formats (par exemple, des expressions Python), puis en récupérant la sortie.

Installer l'interface de ligne de commande SavedModel

D'une manière générale, vous pouvez installer TensorFlow de l'une des deux manières suivantes :

  • En installant un binaire TensorFlow pré-construit.
  • En créant TensorFlow à partir du code source.

Si vous avez installé TensorFlow via un binaire TensorFlow pré-construit, la CLI SavedModel est déjà installée sur votre système au nom de chemin bin/saved_model_cli .

Si vous avez compilé TensorFlow à partir du code source, vous devez exécuter la commande supplémentaire suivante pour compiler saved_model_cli :

$ bazel build tensorflow/python/tools:saved_model_cli

Présentation des commandes

La CLI SavedModel prend en charge les deux commandes suivantes sur un SavedModel :

  • show , qui affiche les calculs disponibles à partir d'un SavedModel.
  • run , qui exécute un calcul à partir d'un SavedModel.

show la commande

Un SavedModel contient une ou plusieurs variantes de modèle (techniquement, v1.MetaGraphDef s), identifiées par leurs ensembles de balises. Pour servir un modèle, vous pourriez vous demander quel type de SignatureDef s sont dans chaque variante de modèle, et quelles sont leurs entrées et sorties. La commande show vous permet d'examiner le contenu du SavedModel dans l'ordre hiérarchique. Voici la syntaxe :

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

Par exemple, la commande suivante affiche tous les ensembles de balises disponibles dans le SavedModel :

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

La commande suivante affiche toutes les clés SignatureDef disponibles pour un ensemble de balises :

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

S'il y a plusieurs balises dans le jeu de balises, vous devez spécifier toutes les balises, chaque balise étant séparée par une virgule. Par example:

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

Pour afficher toutes les entrées et sorties TensorInfo pour un SignatureDef spécifique, passez la clé SignatureDef à l'option signature_def . Ceci est très utile lorsque vous souhaitez connaître la valeur de la clé du tenseur, le dtype et la forme des tenseurs d'entrée pour exécuter le graphe de calcul ultérieurement. Par example:

$ 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

Pour afficher toutes les informations disponibles dans SavedModel, utilisez l'option --all . Par example:

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

Appelez la commande run pour exécuter un calcul de graphe, en transmettant les entrées, puis en affichant (et éventuellement en enregistrant) les sorties. Voici la syntaxe :

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]

La commande run fournit les trois manières suivantes de transmettre des entrées au modèle :

  • L'option --inputs vous permet de passer numpy ndarray dans les fichiers.
  • L'option --input_exprs vous permet de transmettre des expressions Python.
  • L'option --input_examples vous permet de passer tf.train.Example .

--inputs

Pour transmettre des données d'entrée dans des fichiers, spécifiez l'option --inputs , qui prend le format général suivant :

--inputs <INPUTS>

INPUTS est l'un des formats suivants :

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

Vous pouvez passer plusieurs INPUTS . Si vous transmettez plusieurs entrées, utilisez un point-virgule pour séparer chacune des INPUTS .

saved_model_cli utilise numpy.load pour charger le filename . Le nom de fichier peut être dans l'un des formats suivants :

  • .npy
  • .npz
  • format cornichon

Un fichier .npy contient toujours un ndarray numpy. Par conséquent, lors du chargement à partir d'un fichier .npy , le contenu sera directement affecté au tenseur d'entrée spécifié. Si vous spécifiez un variable_name avec ce fichier .npy , le variable_name sera ignoré et un avertissement sera émis.

Lors du chargement à partir d'un .npz (zip), vous pouvez éventuellement spécifier un variable_name pour identifier la variable dans le fichier zip à charger pour la clé de tenseur d'entrée. Si vous ne spécifiez pas de variable_name , la CLI SavedModel vérifiera qu'un seul fichier est inclus dans le fichier zip et le chargera pour la clé de tenseur d'entrée spécifiée.

Lors du chargement à partir d'un fichier pickle, si aucun variable_name n'est spécifié entre crochets, tout ce qui se trouve à l'intérieur du fichier pickle sera transmis à la clé de tenseur d'entrée spécifiée. Sinon, la CLI SavedModel supposera qu'un dictionnaire est stocké dans le fichier pickle et la valeur correspondant au variable_name sera utilisée.

--input_exprs

Pour transmettre des entrées via des expressions Python, spécifiez l'option --input_exprs . Cela peut être utile lorsque vous n'avez pas de fichiers de données, mais que vous souhaitez tout de même vérifier l'intégrité du modèle avec quelques entrées simples qui correspondent au dtype et à la forme des SignatureDef s du modèle. Par example:

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

En plus des expressions Python, vous pouvez également passer des fonctions numpy. Par example:

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

(Notez que le module numpy est déjà disponible pour vous en tant que np .)

--input_examples

Pour passer tf.train.Example comme entrées, spécifiez l'option --input_examples . Pour chaque clé d'entrée, il faut une liste de dictionnaires, où chaque dictionnaire est une instance de tf.train.Example . Les clés du dictionnaire sont les fonctionnalités et les valeurs sont les listes de valeurs pour chaque fonctionnalité. Par example:

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

Enregistrer la sortie

Par défaut, la CLI SavedModel écrit la sortie sur stdout. Si un répertoire est passé à l'option --outdir , les sorties seront enregistrées en tant que fichiers .npy nommés d'après les clés de tenseur de sortie sous le répertoire donné.

Utilisez --overwrite pour écraser les fichiers de sortie existants.