Esta página foi traduzida pela API Cloud Translation.
Switch to English

Usando o formato SavedModel

Ver no TensorFlow.org Executar no Google Colab Ver fonte no GitHub Baixar caderno

Um SavedModel contém um programa TensorFlow completo, incluindo pesos e computação. Ele não requer o código de construção do modelo original para ser executado, o que o torna útil para compartilhamento ou implantação (com TFLite , TensorFlow.js , TensorFlow Serving ou TensorFlow Hub ).

Este documento analisa alguns dos detalhes de como usar a API tf.saved_model baixo nível:

Criação de um SavedModel de Keras

Para uma introdução rápida, esta seção exporta um modelo Keras pré-treinado e atende a solicitações de classificação de imagem com ele. O restante do guia irá preencher os detalhes e discutir outras maneiras de criar 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')
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.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

Você usará uma imagem de Grace Hopper como um exemplo de execução e um modelo de classificação de imagem pré-treinado Keras, pois é fácil de usar. Modelos personalizados também funcionam e são abordados em detalhes posteriormente.

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

A previsão principal para esta imagem é "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/training/tracking/tracking.py:111: Model.state_updates (from tensorflow.python.keras.engine.training) is deprecated and will be removed in a future version.
Instructions for updating:
This property should not be used in TensorFlow 2.0, as updates are applied automatically.
WARNING:tensorflow:From /tmpfs/src/tf_docs_env/lib/python3.6/site-packages/tensorflow/python/training/tracking/tracking.py:111: Layer.updates (from tensorflow.python.keras.engine.base_layer) is deprecated and will be removed in a future version.
Instructions for updating:
This property should not be used in TensorFlow 2.0, as updates are applied automatically.
INFO:tensorflow:Assets written to: /tmp/tmpqrbxtm18/mobilenet/1/assets

O caminho de salvamento segue uma convenção usada pelo TensorFlow Serving em que o último componente do caminho ( 1/ aqui) é um número de versão do seu modelo - ele permite que ferramentas como o Tensorflow Serving raciocinem sobre a atualização relativa.

Você pode carregar o SavedModel de volta no Python com tf.saved_model.load e ver como a imagem do Admiral Hopper é classificada.

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

As assinaturas importadas sempre retornam dicionários. Para personalizar nomes de assinaturas e chaves de dicionário de saída, consulte Especificando assinaturas durante a exportação .

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

Executar a inferência do SavedModel dá o mesmo resultado do 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']

Executando um SavedModel no TensorFlow Serving

SavedModels podem ser usados ​​em Python (mais sobre isso abaixo), mas os ambientes de produção geralmente usam um serviço dedicado para inferência sem executar o código Python. Isso é fácil de configurar a partir de um SavedModel usando o TensorFlow Serving.

Consulte o tutorial REST do TensorFlow Serving para ver um exemplo completo de serviço do tensorflow.

O formato SavedModel no disco

Um SavedModel é um diretório que contém assinaturas serializadas e o estado necessário para executá-las, incluindo valores de variáveis ​​e vocabulários.

ls {mobilenet_save_path}
assets  saved_model.pb  variables

O arquivo saved_model.pb armazena o programa TensorFlow real, ou modelo, e um conjunto de assinaturas nomeadas, cada uma identificando uma função que aceita entradas de tensor e produz saídas de tensor.

SavedModels pode conter múltiplas variantes do modelo (vários v1.MetaGraphDefs , identificados com o --tag_set bandeira para saved_model_cli ), mas isso é raro. As APIs que criam várias variantes de um modelo incluem tf.Estimator.experimental_export_all_saved_models e no TensorFlow 1.x tf.saved_model.Builder .

saved_model_cli show --dir {mobilenet_save_path} --tag_set serve
2020-10-13 01:23:41.728141: I tensorflow/stream_executor/platform/default/dso_loader.cc:48] Successfully opened dynamic library libcudart.so.10.1
The given SavedModel MetaGraphDef contains SignatureDefs with the following keys:
SignatureDef key: "__saved_model_init_op"
SignatureDef key: "serving_default"

O diretório de variables contém um ponto de verificação de treinamento padrão (consulte o guia para pontos de verificação de treinamento ).

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

O diretório de assets contém arquivos usados ​​pelo gráfico do TensorFlow, por exemplo, arquivos de texto usados ​​para inicializar tabelas de vocabulário. Não é usado neste exemplo.

SavedModels pode ter um diretório assets.extra para quaisquer arquivos não usados ​​pelo gráfico TensorFlow, por exemplo, informações para consumidores sobre o que fazer com SavedModel. O próprio TensorFlow não usa esse diretório.

Salvando um modelo personalizado

tf.saved_model.save oferece suporte para salvar objetos tf.Module e suas subclasses, como tf.keras.Layer e tf.keras.Model .

Vejamos um exemplo de como salvar e restaurar um 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 você salva um tf.Module , nenhum tf.Variable atributos, tf.function -decorated métodos e tf.Module s encontrados através travessia recursiva são salvos. (Consulte o tutorial do Checkpoint para obter mais informações sobre esta travessia recursiva.) No entanto, quaisquer atributos, funções e dados do Python são perdidos. Isso significa que quando um tf.function é salvo, nenhum código Python é salvo.

Se nenhum código Python for salvo, como SavedModel sabe como restaurar a função?

Resumidamente, tf.function funciona rastreando o código Python para gerar um ConcreteFunction (um wrapper que pode ser tf.Graph torno de tf.Graph ). Ao salvar um tf.function , você está realmente salvando o tf.function do tf.function de ConcreteFunctions.

Para saber mais sobre a relação entre tf.function e ConcreteFunctions, consulte o guia 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/tmpqrbxtm18/module_no_signatures/assets

Carregando e usando um modelo personalizado

Quando você carrega um SavedModel em Python, todos os atributos tf.Variable , tf.function -decorated métodos e tf.Module s são restaurados na mesma estrutura de objeto que o tf.Module original salvo.

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

Como nenhum código Python é salvo, chamar um tf.function com uma nova assinatura de entrada falhará:

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 fino básico

Objetos variáveis ​​estão disponíveis e você pode fazer backprop por meio de funções importadas. Isso é o suficiente para ajustar (ou seja, treinar novamente) um SavedModel em 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 fino geral

Um SavedModel de Keras fornece mais detalhes do que uma __call__ simples para tratar de casos mais avançados de ajuste fino. O TensorFlow Hub recomenda fornecer o seguinte, se aplicável, em SavedModels compartilhados para fins de ajuste fino:

  • Se o modelo usa dropout ou outra técnica na qual o encaminhamento difere entre treinamento e inferência (como normalização em lote), o método __call__ aceita um argumento opcional de training= valor de Python que é padronizado como False mas pode ser definido como True .
  • Ao lado do atributo __call__ , existem os atributos .variable e .trainable_variable com as listas de variáveis ​​correspondentes. Uma variável que era originalmente treinável, mas deveria ser congelada durante o ajuste fino, foi omitida em .trainable_variables .
  • Para o bem de estruturas como Keras, que representam regularizadores de peso como atributos de camadas ou submodelos, também pode haver um atributo .regularization_losses . Ele contém uma lista de funções de argumento zero cujos valores são destinados à adição à perda total.

Voltando ao exemplo inicial do MobileNet, você pode ver alguns deles em ação:

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

Especificando assinaturas durante a exportação

Ferramentas como TensorFlow Serving e saved_model_cli podem interagir com SavedModels. Para ajudar essas ferramentas a determinar quais ConcreteFunctions usar, você precisa especificar as assinaturas de serviço. tf.keras.Model s especifica automaticamente as assinaturas de serviço, mas você terá que declarar explicitamente uma assinatura de serviço para nossos módulos personalizados.

Por padrão, nenhuma assinatura é declarada em um tf.Module personalizado.

assert len(imported.signatures) == 0

Para declarar uma assinatura de serviço, especifique um ConcreteFunction usando o kwarg de signatures . Ao especificar uma única assinatura, sua chave de assinatura será 'serving_default' , que é salva como a 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/tmpqrbxtm18/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 várias assinaturas, passe um dicionário de chaves de assinatura para ConcreteFunctions. Cada chave de assinatura corresponde a um 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/tmpqrbxtm18/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 padrão, os nomes dos tensores de saída são bastante genéricos, como output_0 . Para controlar os nomes das saídas, modifique seu tf.function para retornar um dicionário que mapeia os nomes das saídas para as saídas. Os nomes das entradas são derivados dos nomes dos argumentos da função 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/tmpqrbxtm18/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')}

Carregar um SavedModel em C ++

A versão C ++ do carregador SavedModel fornece uma API para carregar um SavedModel de um caminho, enquanto permite SessionOptions e RunOptions. Você deve especificar as tags associadas ao gráfico a ser carregado. A versão carregada de SavedModel é conhecida como SavedModelBundle e contém o MetaGraphDef e a sessão na qual é carregado.

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

Detalhes da interface da linha de comando SavedModel

Você pode usar o SavedModel Command Line Interface (CLI) para inspecionar e executar um SavedModel. Por exemplo, você pode usar a CLI para inspecionar os SignatureDef s do modelo. A CLI permite que você confirme rapidamente se o tipo e a forma do tensor de entrada correspondem ao modelo. Além disso, se você deseja testar seu modelo, pode usar a CLI para fazer uma verificação de sanidade, passando entradas de amostra em vários formatos (por exemplo, expressões Python) e, em seguida, buscando a saída.

Instale o SavedModel CLI

Em termos gerais, você pode instalar o TensorFlow de uma das seguintes maneiras:

  • Instalando um binário pré-construído do TensorFlow.
  • Ao construir o TensorFlow a partir do código-fonte.

Se você instalou o TensorFlow por meio de um binário pré-compilado do TensorFlow, o SavedModel CLI já está instalado em seu sistema em pathname bin/saved_model_cli .

Se você construiu TensorFlow a partir do código-fonte, deve executar o seguinte comando adicional para construir saved_model_cli :

$ bazel build tensorflow/python/tools:saved_model_cli

Visão geral dos comandos

A CLI SavedModel oferece suporte aos dois comandos a seguir em um SavedModel:

  • show , que mostra os cálculos disponíveis de um SavedModel.
  • run , que executa um cálculo de um SavedModel.

comando show

Um SavedModel contém uma ou mais variantes de modelo (tecnicamente, v1.MetaGraphDef s), identificadas por seus conjuntos de tags. Para servir a um modelo, você pode se perguntar que tipo de SignatureDef está em cada variante do modelo e quais são suas entradas e saídas. O comando show permite examinar o conteúdo do SavedModel em ordem hierárquica. Esta é a sintaxe:

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

Por exemplo, o comando a seguir mostra todos os conjuntos de tags disponíveis no SavedModel:

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

O comando a seguir mostra todas as chaves SignatureDef disponíveis para um conjunto de tags:

$ 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 houver várias tags no conjunto de tags, você deve especificar todas as tags, cada tag separada por uma vírgula. Por exemplo:

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

Para mostrar todas as entradas e saídas TensorInfo para um SignatureDef específico, passe a chave SignatureDef para a opção signature_def . Isso é muito útil quando você deseja saber o valor da chave do tensor, o tipo d e a forma dos tensores de entrada para executar o gráfico de computação posteriormente. Por exemplo:

$ 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 todas as informações disponíveis no SavedModel, use a opção --all . Por exemplo:

$ 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

Invoque o comando run para executar um cálculo gráfico, passando entradas e, em seguida, exibindo (e opcionalmente salvando) as saídas. Esta é a sintaxe:

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]

O comando run fornece as seguintes três maneiras de passar entradas para o modelo:

  • --inputs opção --inputs permite que você passe ndarray numpy em arquivos.
  • --input_exprs opção --input_exprs permite que você passe expressões Python.
  • --input_examples opção --input_examples permite que você passe tf.train.Example .

--inputs

Para passar dados de entrada em arquivos, especifique a opção --inputs , que assume o seguinte formato geral:

--inputs <INPUTS>

onde INPUTS é um dos seguintes formatos:

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

Você pode passar vários INPUTS . Se você passar várias entradas, use um ponto-e-vírgula para separar cada uma das INPUTS .

saved_model_cli usa numpy.load para carregar o nome do arquivo . O nome do arquivo pode estar em qualquer um dos seguintes formatos:

  • .npy
  • .npz
  • formato de picles

Um arquivo .npy sempre contém um ndarray numpy. Portanto, ao carregar de um arquivo .npy , o conteúdo será atribuído diretamente ao tensor de entrada especificado. Se você especificar um variable_name com esse arquivo .npy , o variable_name será ignorado e um aviso será emitido.

Ao carregar de um .npz (zip), você pode opcionalmente especificar um variable_name para identificar a variável dentro do arquivo zip para carregar para a chave tensora de entrada. Se você não especificar um variable_name , o SavedModel CLI verificará se apenas um arquivo está incluído no arquivo zip e o carregará para a chave do tensor de entrada especificada.

Ao carregar de um arquivo pickle, se nenhum variable_name for especificado entre colchetes, o que quer que esteja dentro do arquivo pickle será passado para a chave tensora de entrada especificada. Caso contrário, o SavedModel CLI assumirá que um dicionário está armazenado no arquivo pickle e o valor correspondente a variable_name será usado.

--input_exprs

Para passar entradas por meio de expressões Python, especifique a opção --input_exprs . Isso pode ser útil quando você não tem arquivos de dados por aí, mas ainda deseja verificar a integridade do modelo com algumas entradas simples que correspondem ao tipo e formato dos SignatureDef do modelo. Por exemplo:

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

Além das expressões Python, você também pode passar funções numpy. Por exemplo:

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

(Observe que o módulo numpy já está disponível para você como np .)

--input_examples

Para passar tf.train.Example como entradas, especifique a opção --input_examples . Para cada chave de entrada, é necessária uma lista de dicionário, onde cada dicionário é uma instância de tf.train.Example . As chaves do dicionário são os recursos e os valores são as listas de valores para cada recurso. Por exemplo:

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

Salvar saída

Por padrão, o SavedModel CLI grava a saída em stdout. Se um diretório for passado para a opção --outdir , as saídas serão salvas como arquivos .npy nomeados após chaves .npy saída no diretório fornecido.

Use --overwrite para sobrescrever os arquivos de saída existentes.