Veja no TensorFlow.org | Executar no Google Colab | Ver no GitHub | Baixar caderno |
Visão geral
Este guia pressupõe que você tenha um modelo que salva e carrega pontos de verificação com tf.compat.v1.Saver
e deseja migrar o código usando a API TF2 tf.train.Checkpoint
ou use pontos de verificação pré-existentes em seu modelo TF2.
Abaixo estão alguns cenários comuns que você pode encontrar:
Cenário 1
Existem pontos de verificação TF1 de execuções de treinamento anteriores que precisam ser carregados ou convertidos em TF2.
- Para carregar o ponto de verificação do TF1 no TF2, consulte o trecho Load a TF1 checkpoint in TF2 .
- Para converter o ponto de verificação em TF2, consulte Conversão de ponto de verificação .
Cenário 2
Você está ajustando seu modelo de uma forma que corre o risco de alterar nomes e caminhos de variáveis (como ao migrar incrementalmente de get_variable
para criação de tf.Variable
explícita) e gostaria de manter o salvamento/carregamento de pontos de verificação existentes ao longo do caminho.
Consulte a seção sobre Como manter a compatibilidade do ponto de verificação durante a migração do modelo
Cenário 3
Você está migrando seu código de treinamento e pontos de verificação para o TF2, mas seu pipeline de inferência continua exigindo pontos de verificação do TF1 por enquanto (para estabilidade de produção).
Opção 1
Salve os pontos de verificação TF1 e TF2 ao treinar.
opção 2
Converta o ponto de verificação do TF2 em TF1.
Os exemplos abaixo mostram todas as combinações de salvar e carregar pontos de verificação no TF1/TF2, para que você tenha alguma flexibilidade para determinar como migrar seu modelo.
Configurar
import tensorflow as tf
import tensorflow.compat.v1 as tf1
def print_checkpoint(save_path):
reader = tf.train.load_checkpoint(save_path)
shapes = reader.get_variable_to_shape_map()
dtypes = reader.get_variable_to_dtype_map()
print(f"Checkpoint at '{save_path}':")
for key in shapes:
print(f" (key='{key}', shape={shapes[key]}, dtype={dtypes[key].name}, "
f"value={reader.get_tensor(key)})")
Mudanças de TF1 para TF2
Esta seção está incluída se você estiver curioso sobre o que mudou entre TF1 e TF2, e o que queremos dizer com checkpoints "baseados em nome" (TF1) versus "baseados em objetos" (TF2).
Os dois tipos de pontos de verificação são, na verdade, salvos no mesmo formato, que é essencialmente uma tabela de valores-chave. A diferença está em como as chaves são geradas.
As chaves em pontos de verificação baseados em nome são os nomes das variáveis . As chaves nos pontos de verificação baseados em objeto referem-se ao caminho do objeto raiz para a variável (os exemplos abaixo ajudarão a ter uma melhor noção do que isso significa).
Primeiro, salve alguns checkpoints:
with tf.Graph().as_default() as g:
a = tf1.get_variable('a', shape=[], dtype=tf.float32,
initializer=tf1.zeros_initializer())
b = tf1.get_variable('b', shape=[], dtype=tf.float32,
initializer=tf1.zeros_initializer())
c = tf1.get_variable('scoped/c', shape=[], dtype=tf.float32,
initializer=tf1.zeros_initializer())
with tf1.Session() as sess:
saver = tf1.train.Saver()
sess.run(a.assign(1))
sess.run(b.assign(2))
sess.run(c.assign(3))
saver.save(sess, 'tf1-ckpt')
print_checkpoint('tf1-ckpt')
Checkpoint at 'tf1-ckpt': (key='scoped/c', shape=[], dtype=float32, value=3.0) (key='a', shape=[], dtype=float32, value=1.0) (key='b', shape=[], dtype=float32, value=2.0)
a = tf.Variable(5.0, name='a')
b = tf.Variable(6.0, name='b')
with tf.name_scope('scoped'):
c = tf.Variable(7.0, name='c')
ckpt = tf.train.Checkpoint(variables=[a, b, c])
save_path_v2 = ckpt.save('tf2-ckpt')
print_checkpoint(save_path_v2)
Checkpoint at 'tf2-ckpt-1': (key='variables/2/.ATTRIBUTES/VARIABLE_VALUE', shape=[], dtype=float32, value=7.0) (key='variables/0/.ATTRIBUTES/VARIABLE_VALUE', shape=[], dtype=float32, value=5.0) (key='_CHECKPOINTABLE_OBJECT_GRAPH', shape=[], dtype=string, value=b"\n!\n\r\x08\x01\x12\tvariables\n\x10\x08\x02\x12\x0csave_counter\n\x15\n\x05\x08\x03\x12\x010\n\x05\x08\x04\x12\x011\n\x05\x08\x05\x12\x012\nI\x12G\n\x0eVARIABLE_VALUE\x12\x0csave_counter\x1a'save_counter/.ATTRIBUTES/VARIABLE_VALUE\n=\x12;\n\x0eVARIABLE_VALUE\x12\x01a\x1a&variables/0/.ATTRIBUTES/VARIABLE_VALUE\n=\x12;\n\x0eVARIABLE_VALUE\x12\x01b\x1a&variables/1/.ATTRIBUTES/VARIABLE_VALUE\nD\x12B\n\x0eVARIABLE_VALUE\x12\x08scoped/c\x1a&variables/2/.ATTRIBUTES/VARIABLE_VALUE") (key='variables/1/.ATTRIBUTES/VARIABLE_VALUE', shape=[], dtype=float32, value=6.0) (key='save_counter/.ATTRIBUTES/VARIABLE_VALUE', shape=[], dtype=int64, value=1)
Se você observar as chaves em tf2-ckpt
, todas elas se referem aos caminhos do objeto de cada variável. Por exemplo, a variável a
é o primeiro elemento na lista de variables
, então sua chave se torna variables/0/...
(sinta-se à vontade para ignorar a constante .ATTRIBUTES/VARIABLE_VALUE).
Uma inspeção mais detalhada do objeto Checkpoint
abaixo:
a = tf.Variable(0.)
b = tf.Variable(0.)
c = tf.Variable(0.)
root = ckpt = tf.train.Checkpoint(variables=[a, b, c])
print("root type =", type(root).__name__)
print("root.variables =", root.variables)
print("root.variables[0] =", root.variables[0])
root type = Checkpoint root.variables = ListWrapper([<tf.Variable 'Variable:0' shape=() dtype=float32, numpy=0.0>, <tf.Variable 'Variable:0' shape=() dtype=float32, numpy=0.0>, <tf.Variable 'Variable:0' shape=() dtype=float32, numpy=0.0>]) root.variables[0] = <tf.Variable 'Variable:0' shape=() dtype=float32, numpy=0.0>
Experimente o snippet abaixo e veja como as chaves do ponto de verificação mudam com a estrutura do objeto:
module = tf.Module()
module.d = tf.Variable(0.)
test_ckpt = tf.train.Checkpoint(v={'a': a, 'b': b},
c=c,
module=module)
test_ckpt_path = test_ckpt.save('root-tf2-ckpt')
print_checkpoint(test_ckpt_path)
Checkpoint at 'root-tf2-ckpt-1': (key='v/a/.ATTRIBUTES/VARIABLE_VALUE', shape=[], dtype=float32, value=0.0) (key='save_counter/.ATTRIBUTES/VARIABLE_VALUE', shape=[], dtype=int64, value=1) (key='v/b/.ATTRIBUTES/VARIABLE_VALUE', shape=[], dtype=float32, value=0.0) (key='module/d/.ATTRIBUTES/VARIABLE_VALUE', shape=[], dtype=float32, value=0.0) (key='_CHECKPOINTABLE_OBJECT_GRAPH', shape=[], dtype=string, value=b"\n,\n\x05\x08\x01\x12\x01c\n\n\x08\x02\x12\x06module\n\x05\x08\x03\x12\x01v\n\x10\x08\x04\x12\x0csave_counter\n:\x128\n\x0eVARIABLE_VALUE\x12\x08Variable\x1a\x1cc/.ATTRIBUTES/VARIABLE_VALUE\n\x07\n\x05\x08\x05\x12\x01d\n\x0e\n\x05\x08\x06\x12\x01a\n\x05\x08\x07\x12\x01b\nI\x12G\n\x0eVARIABLE_VALUE\x12\x0csave_counter\x1a'save_counter/.ATTRIBUTES/VARIABLE_VALUE\nA\x12?\n\x0eVARIABLE_VALUE\x12\x08Variable\x1a#module/d/.ATTRIBUTES/VARIABLE_VALUE\n<\x12:\n\x0eVARIABLE_VALUE\x12\x08Variable\x1a\x1ev/a/.ATTRIBUTES/VARIABLE_VALUE\n<\x12:\n\x0eVARIABLE_VALUE\x12\x08Variable\x1a\x1ev/b/.ATTRIBUTES/VARIABLE_VALUE") (key='c/.ATTRIBUTES/VARIABLE_VALUE', shape=[], dtype=float32, value=0.0)
Por que o TF2 usa esse mecanismo?
Como não há mais gráfico global no TF2, os nomes das variáveis não são confiáveis e podem ser inconsistentes entre os programas. O TF2 encoraja a abordagem de modelagem orientada a objetos onde as variáveis são de propriedade de camadas e as camadas são de propriedade de um modelo:
variable = tf.Variable(...)
layer.variable_name = variable
model.layer_name = layer
Como manter a compatibilidade do ponto de verificação durante a migração do modelo
Uma etapa importante no processo de migração é garantir que todas as variáveis sejam inicializadas com os valores corretos , o que, por sua vez, permite validar se as operações/funções estão fazendo os cálculos corretos. Para fazer isso, você deve considerar a compatibilidade do ponto de verificação entre os modelos nos vários estágios da migração. Essencialmente, esta seção responde à pergunta: como continuar usando o mesmo ponto de verificação ao alterar o modelo .
Abaixo estão três maneiras de manter a compatibilidade do ponto de verificação, para aumentar a flexibilidade:
- O modelo tem os mesmos nomes de variáveis de antes.
- O modelo tem nomes de variáveis diferentes e mantém um mapa de atribuição que mapeia nomes de variáveis no ponto de verificação para os novos nomes.
- O modelo tem nomes de variáveis diferentes e mantém um objeto TF2 Checkpoint que armazena todas as variáveis.
Quando os nomes das variáveis correspondem
Título longo: Como reutilizar pontos de verificação quando os nomes das variáveis correspondem.
Resposta curta: Você pode carregar diretamente o ponto de verificação pré-existente com tf1.train.Saver
ou tf.train.Checkpoint
.
Se você estiver usando tf.compat.v1.keras.utils.track_tf1_style_variables
, isso garantirá que seus nomes de variáveis de modelo sejam os mesmos de antes. Você também pode garantir manualmente que os nomes das variáveis correspondam.
Quando os nomes das variáveis correspondem nos modelos migrados, você pode usar diretamente tf.train.Checkpoint
ou tf.compat.v1.train.Saver
para carregar o ponto de verificação. Ambas as APIs são compatíveis com o modo ansioso e gráfico, para que você possa usá-las em qualquer estágio da migração.
Abaixo estão exemplos de uso do mesmo ponto de verificação com modelos diferentes. Primeiro, salve um checkpoint TF1 com tf1.train.Saver
:
with tf.Graph().as_default() as g:
a = tf1.get_variable('a', shape=[], dtype=tf.float32,
initializer=tf1.zeros_initializer())
b = tf1.get_variable('b', shape=[], dtype=tf.float32,
initializer=tf1.zeros_initializer())
c = tf1.get_variable('scoped/c', shape=[], dtype=tf.float32,
initializer=tf1.zeros_initializer())
with tf1.Session() as sess:
saver = tf1.train.Saver()
sess.run(a.assign(1))
sess.run(b.assign(2))
sess.run(c.assign(3))
save_path = saver.save(sess, 'tf1-ckpt')
print_checkpoint(save_path)
Checkpoint at 'tf1-ckpt': (key='scoped/c', shape=[], dtype=float32, value=3.0) (key='a', shape=[], dtype=float32, value=1.0) (key='b', shape=[], dtype=float32, value=2.0)
O exemplo abaixo usa tf.compat.v1.Saver
para carregar o ponto de verificação enquanto estiver no modo ansioso:
a = tf.Variable(0.0, name='a')
b = tf.Variable(0.0, name='b')
with tf.name_scope('scoped'):
c = tf.Variable(0.0, name='c')
# With the removal of collections in TF2, you must pass in the list of variables
# to the Saver object:
saver = tf1.train.Saver(var_list=[a, b, c])
saver.restore(sess=None, save_path=save_path)
print(f"loaded values of [a, b, c]: [{a.numpy()}, {b.numpy()}, {c.numpy()}]")
# Saving also works in eager (sess must be None).
path = saver.save(sess=None, save_path='tf1-ckpt-saved-in-eager')
print_checkpoint(path)
WARNING:tensorflow:Saver is deprecated, please switch to tf.train.Checkpoint or tf.keras.Model.save_weights for training checkpoints. When executing eagerly variables do not necessarily have unique names, and so the variable.name-based lookups Saver performs are error-prone. INFO:tensorflow:Restoring parameters from tf1-ckpt loaded values of [a, b, c]: [1.0, 2.0, 3.0] Checkpoint at 'tf1-ckpt-saved-in-eager': (key='scoped/c', shape=[], dtype=float32, value=3.0) (key='a', shape=[], dtype=float32, value=1.0) (key='b', shape=[], dtype=float32, value=2.0)
O próximo snippet carrega o ponto de verificação usando a API do TF2 tf.train.Checkpoint
:
a = tf.Variable(0.0, name='a')
b = tf.Variable(0.0, name='b')
with tf.name_scope('scoped'):
c = tf.Variable(0.0, name='c')
# Without the name_scope, name="scoped/c" works too:
c_2 = tf.Variable(0.0, name='scoped/c')
print("Variable names: ")
print(f" a.name = {a.name}")
print(f" b.name = {b.name}")
print(f" c.name = {c.name}")
print(f" c_2.name = {c_2.name}")
# Restore the values with tf.train.Checkpoint
ckpt = tf.train.Checkpoint(variables=[a, b, c, c_2])
ckpt.restore(save_path)
print(f"loaded values of [a, b, c, c_2]: [{a.numpy()}, {b.numpy()}, {c.numpy()}, {c_2.numpy()}]")
Variable names: a.name = a:0 b.name = b:0 c.name = scoped/c:0 c_2.name = scoped/c:0 WARNING:tensorflow:From /tmpfs/src/tf_docs_env/lib/python3.7/site-packages/tensorflow/python/training/tracking/util.py:1345: NameBasedSaverStatus.__init__ (from tensorflow.python.training.tracking.util) is deprecated and will be removed in a future version. Instructions for updating: Restoring a name-based tf.train.Saver checkpoint using the object-based restore API. This mode uses global names to match variables, and so is somewhat fragile. It also adds new restore ops to the graph each time it is called when graph building. Prefer re-encoding training checkpoints in the object-based format: run save() on the object-based saver (the same one this message is coming from) and use that checkpoint in the future. loaded values of [a, b, c, c_2]: [1.0, 2.0, 3.0, 3.0]
Nomes de variáveis no TF2
- As variáveis ainda têm um argumento de
name
que você pode definir. - Os modelos Keras também recebem um argumento de
name
como o prefixo de suas variáveis. - A função
v1.name_scope
pode ser usada para definir prefixos de nomes de variáveis. Isso é muito diferente detf.variable_scope
. Ele afeta apenas nomes e não rastreia variáveis e reutilização.
O decorador tf.compat.v1.keras.utils.track_tf1_style_variables
é um shim que ajuda a manter os nomes das variáveis e a compatibilidade do ponto de verificação do TF1, mantendo a semântica de nomenclatura e reutilização de tf.variable_scope
e tf.compat.v1.get_variable
inalterada. Consulte o guia de mapeamento de modelo para obter mais informações.
Nota 1: Se você estiver usando o shim, use as APIs do TF2 para carregar seus pontos de verificação (mesmo ao usar pontos de verificação TF1 pré-treinados).
Consulte a seção Ponto de verificação Keras .
Nota 2: Ao migrar para tf.Variable
de get_variable
:
Se sua camada ou módulo decorado com shim consiste em algumas variáveis (ou camadas/modelos Keras) que usam tf.Variable
em vez de tf.compat.v1.get_variable
e são anexadas como propriedades/rastreadas de maneira orientada a objetos, elas podem ter diferentes semântica de nomeação de variável em gráficos/sessões TF1.x versus durante a execução antecipada.
Resumindo, os nomes podem não ser o que você espera que sejam ao rodar no TF2.
Mantendo mapas de atribuição
Os mapas de atribuição são comumente usados para transferir pesos entre modelos TF1 e também podem ser usados durante a migração do modelo se os nomes das variáveis forem alterados.
Você pode usar esses mapas com tf.compat.v1.train.init_from_checkpoint
, tf.compat.v1.train.Saver
e tf.train.load_checkpoint
para carregar pesos em modelos nos quais os nomes de variáveis ou escopos podem ter sido alterados.
Os exemplos nesta seção usarão um ponto de verificação salvo anteriormente:
print_checkpoint('tf1-ckpt')
Checkpoint at 'tf1-ckpt': (key='scoped/c', shape=[], dtype=float32, value=3.0) (key='a', shape=[], dtype=float32, value=1.0) (key='b', shape=[], dtype=float32, value=2.0)
Carregando com init_from_checkpoint
tf1.train.init_from_checkpoint
deve ser chamado enquanto estiver em um Gráfico/Sessão, porque coloca os valores nos inicializadores de variáveis em vez de criar uma operação de atribuição.
Você pode usar o argumento assignment_map
para configurar como as variáveis são carregadas. Da documentação:
O mapa de atribuição é compatível com a seguinte sintaxe:
-
'checkpoint_scope_name/': 'scope_name/'
- irá carregar todas as variáveis no atualscope_name
decheckpoint_scope_name
com nomes de tensor correspondentes. -
'checkpoint_scope_name/some_other_variable': 'scope_name/variable_name'
- irá inicializarscope_name/variable_name
decheckpoint_scope_name/some_other_variable
. -
'scope_variable_name': variable
- irá inicializar determinado objetotf.Variable
com o tensor 'scope_variable_name' do ponto de verificação. -
'scope_variable_name': list(variable)
- inicializará a lista de variáveis particionadas com o tensor 'scope_variable_name' do ponto de verificação. -
'/': 'scope_name/'
- irá carregar todas as variáveis noscope_name
atual da raiz do ponto de verificação (por exemplo, sem escopo).
# Restoring with tf1.train.init_from_checkpoint:
# A new model with a different scope for the variables.
with tf.Graph().as_default() as g:
with tf1.variable_scope('new_scope'):
a = tf1.get_variable('a', shape=[], dtype=tf.float32,
initializer=tf1.zeros_initializer())
b = tf1.get_variable('b', shape=[], dtype=tf.float32,
initializer=tf1.zeros_initializer())
c = tf1.get_variable('scoped/c', shape=[], dtype=tf.float32,
initializer=tf1.zeros_initializer())
with tf1.Session() as sess:
# The assignment map will remap all variables in the checkpoint to the
# new scope:
tf1.train.init_from_checkpoint(
'tf1-ckpt',
assignment_map={'/': 'new_scope/'})
# `init_from_checkpoint` adds the initializers to these variables.
# Use `sess.run` to run these initializers.
sess.run(tf1.global_variables_initializer())
print("Restored [a, b, c]: ", sess.run([a, b, c]))
Restored [a, b, c]: [1.0, 2.0, 3.0]
Carregando com tf1.train.Saver
Ao contrário init_from_checkpoint
, o tf.compat.v1.train.Saver
é executado tanto no modo gráfico quanto no modo ansioso. O argumento var_list
aceita opcionalmente um dicionário, exceto que deve mapear nomes de variáveis para o objeto tf.Variable
.
# Restoring with tf1.train.Saver (works in both graph and eager):
# A new model with a different scope for the variables.
with tf1.variable_scope('new_scope'):
a = tf1.get_variable('a', shape=[], dtype=tf.float32,
initializer=tf1.zeros_initializer())
b = tf1.get_variable('b', shape=[], dtype=tf.float32,
initializer=tf1.zeros_initializer())
c = tf1.get_variable('scoped/c', shape=[], dtype=tf.float32,
initializer=tf1.zeros_initializer())
# Initialize the saver with a dictionary with the original variable names:
saver = tf1.train.Saver({'a': a, 'b': b, 'scoped/c': c})
saver.restore(sess=None, save_path='tf1-ckpt')
print("Restored [a, b, c]: ", [a.numpy(), b.numpy(), c.numpy()])
WARNING:tensorflow:Saver is deprecated, please switch to tf.train.Checkpoint or tf.keras.Model.save_weights for training checkpoints. When executing eagerly variables do not necessarily have unique names, and so the variable.name-based lookups Saver performs are error-prone. INFO:tensorflow:Restoring parameters from tf1-ckpt Restored [a, b, c]: [1.0, 2.0, 3.0]
Carregando com tf.train.load_checkpoint
Esta opção é para você se precisar de controle preciso sobre os valores das variáveis. Novamente, isso funciona nos modos gráfico e ansioso.
# Restoring with tf.train.load_checkpoint (works in both graph and eager):
# A new model with a different scope for the variables.
with tf.Graph().as_default() as g:
with tf1.variable_scope('new_scope'):
a = tf1.get_variable('a', shape=[], dtype=tf.float32,
initializer=tf1.zeros_initializer())
b = tf1.get_variable('b', shape=[], dtype=tf.float32,
initializer=tf1.zeros_initializer())
c = tf1.get_variable('scoped/c', shape=[], dtype=tf.float32,
initializer=tf1.zeros_initializer())
with tf1.Session() as sess:
# It may be easier writing a loop if your model has a lot of variables.
reader = tf.train.load_checkpoint('tf1-ckpt')
sess.run(a.assign(reader.get_tensor('a')))
sess.run(b.assign(reader.get_tensor('b')))
sess.run(c.assign(reader.get_tensor('scoped/c')))
print("Restored [a, b, c]: ", sess.run([a, b, c]))
Restored [a, b, c]: [1.0, 2.0, 3.0]
Mantendo um objeto TF2 Checkpoint
Se os nomes de variável e escopo podem mudar muito durante a migração, use os pontos de verificação tf.train.Checkpoint
e TF2. O TF2 usa a estrutura do objeto em vez de nomes de variáveis (mais detalhes em Mudanças de TF1 para TF2 ).
Resumindo, ao criar um tf.train.Checkpoint
para salvar ou restaurar checkpoints, certifique-se de que ele use a mesma ordenação (para listas) e chaves (para dicionários e argumentos de palavras-chave para o inicializador do Checkpoint
). Alguns exemplos de compatibilidade de ponto de verificação:
ckpt = tf.train.Checkpoint(foo=[var_a, var_b])
# compatible with ckpt
tf.train.Checkpoint(foo=[var_a, var_b])
# not compatible with ckpt
tf.train.Checkpoint(foo=[var_b, var_a])
tf.train.Checkpoint(bar=[var_a, var_b])
Os exemplos de código abaixo mostram como usar o "mesmo" tf.train.Checkpoint
para carregar variáveis com nomes diferentes. Primeiro, salve um ponto de verificação do TF2:
with tf.Graph().as_default() as g:
a = tf1.get_variable('a', shape=[], dtype=tf.float32,
initializer=tf1.constant_initializer(1))
b = tf1.get_variable('b', shape=[], dtype=tf.float32,
initializer=tf1.constant_initializer(2))
with tf1.variable_scope('scoped'):
c = tf1.get_variable('c', shape=[], dtype=tf.float32,
initializer=tf1.constant_initializer(3))
with tf1.Session() as sess:
sess.run(tf1.global_variables_initializer())
print("[a, b, c]: ", sess.run([a, b, c]))
# Save a TF2 checkpoint
ckpt = tf.train.Checkpoint(unscoped=[a, b], scoped=[c])
tf2_ckpt_path = ckpt.save('tf2-ckpt')
print_checkpoint(tf2_ckpt_path)
[a, b, c]: [1.0, 2.0, 3.0] Checkpoint at 'tf2-ckpt-1': (key='unscoped/1/.ATTRIBUTES/VARIABLE_VALUE', shape=[], dtype=float32, value=2.0) (key='unscoped/0/.ATTRIBUTES/VARIABLE_VALUE', shape=[], dtype=float32, value=1.0) (key='_CHECKPOINTABLE_OBJECT_GRAPH', shape=[], dtype=string, value=b"\n,\n\n\x08\x01\x12\x06scoped\n\x0c\x08\x02\x12\x08unscoped\n\x10\x08\x03\x12\x0csave_counter\n\x07\n\x05\x08\x04\x12\x010\n\x0e\n\x05\x08\x05\x12\x010\n\x05\x08\x06\x12\x011\nI\x12G\n\x0eVARIABLE_VALUE\x12\x0csave_counter\x1a'save_counter/.ATTRIBUTES/VARIABLE_VALUE\nA\x12?\n\x0eVARIABLE_VALUE\x12\x08scoped/c\x1a#scoped/0/.ATTRIBUTES/VARIABLE_VALUE\n<\x12:\n\x0eVARIABLE_VALUE\x12\x01a\x1a%unscoped/0/.ATTRIBUTES/VARIABLE_VALUE\n<\x12:\n\x0eVARIABLE_VALUE\x12\x01b\x1a%unscoped/1/.ATTRIBUTES/VARIABLE_VALUE") (key='scoped/0/.ATTRIBUTES/VARIABLE_VALUE', shape=[], dtype=float32, value=3.0) (key='save_counter/.ATTRIBUTES/VARIABLE_VALUE', shape=[], dtype=int64, value=1)
Você pode continuar usando tf.train.Checkpoint
mesmo que os nomes das variáveis/escopos mudem:
with tf.Graph().as_default() as g:
a = tf1.get_variable('a_different_name', shape=[], dtype=tf.float32,
initializer=tf1.zeros_initializer())
b = tf1.get_variable('b_different_name', shape=[], dtype=tf.float32,
initializer=tf1.zeros_initializer())
with tf1.variable_scope('different_scope'):
c = tf1.get_variable('c', shape=[], dtype=tf.float32,
initializer=tf1.zeros_initializer())
with tf1.Session() as sess:
sess.run(tf1.global_variables_initializer())
print("Initialized [a, b, c]: ", sess.run([a, b, c]))
ckpt = tf.train.Checkpoint(unscoped=[a, b], scoped=[c])
# `assert_consumed` validates that all checkpoint objects are restored from
# the checkpoint. `run_restore_ops` is required when running in a TF1
# session.
ckpt.restore(tf2_ckpt_path).assert_consumed().run_restore_ops()
# Removing `assert_consumed` is fine if you want to skip the validation.
# ckpt.restore(tf2_ckpt_path).run_restore_ops()
print("Restored [a, b, c]: ", sess.run([a, b, c]))
Initialized [a, b, c]: [0.0, 0.0, 0.0] Restored [a, b, c]: [1.0, 2.0, 3.0]
E no modo ansioso:
a = tf.Variable(0.)
b = tf.Variable(0.)
c = tf.Variable(0.)
print("Initialized [a, b, c]: ", [a.numpy(), b.numpy(), c.numpy()])
# The keys "scoped" and "unscoped" are no longer relevant, but are used to
# maintain compatibility with the saved checkpoints.
ckpt = tf.train.Checkpoint(unscoped=[a, b], scoped=[c])
ckpt.restore(tf2_ckpt_path).assert_consumed().run_restore_ops()
print("Restored [a, b, c]: ", [a.numpy(), b.numpy(), c.numpy()])
Initialized [a, b, c]: [0.0, 0.0, 0.0] Restored [a, b, c]: [1.0, 2.0, 3.0]
Pontos de verificação do TF2 no Estimador
As seções acima descrevem como manter a compatibilidade do ponto de verificação ao migrar seu modelo. Esses conceitos também se aplicam aos modelos do Estimator, embora a maneira como o ponto de verificação é salvo/carregado seja um pouco diferente. Conforme você migra seu modelo do Estimator para usar as APIs do TF2, convém alternar dos pontos de verificação do TF1 para o TF2 enquanto o modelo ainda está usando o estimador . Esta seção mostra como fazer isso.
tf.estimator.Estimator
e MonitoredSession
têm um mecanismo de salvamento chamado scaffold
, um objeto tf.compat.v1.train.Scaffold
. O Scaffold
pode conter um tf1.train.Saver
ou tf.train.Checkpoint
, que permite que Estimator
e MonitoredSession
salvem pontos de verificação no estilo TF1 ou TF2.
# A model_fn that saves a TF1 checkpoint
def model_fn_tf1_ckpt(features, labels, mode):
# This model adds 2 to the variable `v` in every train step.
train_step = tf1.train.get_or_create_global_step()
v = tf1.get_variable('var', shape=[], dtype=tf.float32,
initializer=tf1.constant_initializer(0))
return tf.estimator.EstimatorSpec(
mode,
predictions=v,
train_op=tf.group(v.assign_add(2), train_step.assign_add(1)),
loss=tf.constant(1.),
scaffold=None
)
!rm -rf est-tf1
est = tf.estimator.Estimator(model_fn_tf1_ckpt, 'est-tf1')
def train_fn():
return tf.data.Dataset.from_tensor_slices(([1,2,3], [4,5,6]))
est.train(train_fn, steps=1)
latest_checkpoint = tf.train.latest_checkpoint('est-tf1')
print_checkpoint(latest_checkpoint)
INFO:tensorflow:Using default config. INFO:tensorflow:Using config: {'_model_dir': 'est-tf1', '_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, '_checkpoint_save_graph_def': True, '_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.7/site-packages/tensorflow/python/training/training_util.py:401: 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. 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 est-tf1/model.ckpt. INFO:tensorflow:Calling checkpoint listeners after saving checkpoint 0... INFO:tensorflow:loss = 1.0, step = 0 INFO:tensorflow:Calling checkpoint listeners before saving checkpoint 1... INFO:tensorflow:Saving checkpoints for 1 into est-tf1/model.ckpt. INFO:tensorflow:Calling checkpoint listeners after saving checkpoint 1... INFO:tensorflow:Loss for final step: 1.0. Checkpoint at 'est-tf1/model.ckpt-1': (key='var', shape=[], dtype=float32, value=2.0) (key='global_step', shape=[], dtype=int64, value=1)
# A model_fn that saves a TF2 checkpoint
def model_fn_tf2_ckpt(features, labels, mode):
# This model adds 2 to the variable `v` in every train step.
train_step = tf1.train.get_or_create_global_step()
v = tf1.get_variable('var', shape=[], dtype=tf.float32,
initializer=tf1.constant_initializer(0))
ckpt = tf.train.Checkpoint(var_list={'var': v}, step=train_step)
return tf.estimator.EstimatorSpec(
mode,
predictions=v,
train_op=tf.group(v.assign_add(2), train_step.assign_add(1)),
loss=tf.constant(1.),
scaffold=tf1.train.Scaffold(saver=ckpt)
)
!rm -rf est-tf2
est = tf.estimator.Estimator(model_fn_tf2_ckpt, 'est-tf2',
warm_start_from='est-tf1')
def train_fn():
return tf.data.Dataset.from_tensor_slices(([1,2,3], [4,5,6]))
est.train(train_fn, steps=1)
latest_checkpoint = tf.train.latest_checkpoint('est-tf2')
print_checkpoint(latest_checkpoint)
assert est.get_variable_value('var_list/var/.ATTRIBUTES/VARIABLE_VALUE') == 4
INFO:tensorflow:Using default config. INFO:tensorflow:Using config: {'_model_dir': 'est-tf2', '_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, '_checkpoint_save_graph_def': True, '_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} INFO:tensorflow:Calling model_fn. INFO:tensorflow:Done calling model_fn. INFO:tensorflow:Warm-starting with WarmStartSettings: WarmStartSettings(ckpt_to_initialize_from='est-tf1', vars_to_warm_start='.*', var_name_to_vocab_info={}, var_name_to_prev_var_name={}) INFO:tensorflow:Warm-starting from: est-tf1 INFO:tensorflow:Warm-starting variables only in TRAINABLE_VARIABLES. INFO:tensorflow:Warm-started 1 variables. 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 est-tf2/model.ckpt. INFO:tensorflow:Calling checkpoint listeners after saving checkpoint 0... INFO:tensorflow:loss = 1.0, step = 0 INFO:tensorflow:Calling checkpoint listeners before saving checkpoint 1... INFO:tensorflow:Saving checkpoints for 1 into est-tf2/model.ckpt. INFO:tensorflow:Calling checkpoint listeners after saving checkpoint 1... INFO:tensorflow:Loss for final step: 1.0. Checkpoint at 'est-tf2/model.ckpt-1': (key='var_list/var/.ATTRIBUTES/VARIABLE_VALUE', shape=[], dtype=float32, value=4.0) (key='_CHECKPOINTABLE_OBJECT_GRAPH', shape=[], dtype=string, value=b"\n\x18\n\x08\x08\x01\x12\x04step\n\x0c\x08\x02\x12\x08var_list\n@\x12>\n\x0eVARIABLE_VALUE\x12\x0bglobal_step\x1a\x1fstep/.ATTRIBUTES/VARIABLE_VALUE\n\t\n\x07\x08\x03\x12\x03var\n@\x12>\n\x0eVARIABLE_VALUE\x12\x03var\x1a'var_list/var/.ATTRIBUTES/VARIABLE_VALUE") (key='step/.ATTRIBUTES/VARIABLE_VALUE', shape=[], dtype=int64, value=1)
O valor final de v
deve ser 16
, depois de ser iniciado a quente de est-tf1
, depois treinado por mais 5 etapas. O valor da etapa de trem não é transferido do ponto de verificação warm_start
.
Checkpointing Keras
Modelos construídos com Keras ainda usam tf1.train.Saver
e tf.train.Checkpoint
para carregar pesos pré-existentes. Quando seu modelo estiver totalmente migrado, alterne para o uso de model.save_weights
e model.load_weights
, especialmente se estiver usando o retorno de chamada ModelCheckpoint
durante o treinamento.
Algumas coisas que você deve saber sobre checkpoints e Keras:
Inicialização vs Construção
Os modelos e camadas Keras devem passar por duas etapas antes de serem totalmente criados. A primeira é a inicialização do objeto Python: layer = tf.keras.layers.Dense(x)
. A segunda é a etapa de construção , na qual a maioria dos pesos é realmente criada: layer.build(input_shape)
. Você também pode criar um modelo chamando-o ou executando uma única etapa train
, eval
ou predict
(somente na primeira vez).
Se você achar que model.load_weights(path).assert_consumed()
está gerando um erro, então é provável que o modelo/camadas não tenham sido construídos.
Keras usa pontos de verificação TF2
tf.train.Checkpoint(model).write
é equivalente a model.save_weights
. O mesmo com tf.train.Checkpoint(model).read
e model.load_weights
. Observe que Checkpoint(model) != Checkpoint(model=model)
.
Os pontos de verificação do TF2 funcionam com a etapa build()
do Keras
tf.train.Checkpoint.restore
tem um mecanismo chamado restauração adiada que permite que objetos tf.Module
e Keras armazenem valores de variáveis se a variável ainda não tiver sido criada. Isso permite que os modelos inicializados carreguem pesos e construam depois.
m = YourKerasModel()
status = m.load_weights(path)
# This call builds the model. The variables are created with the restored
# values.
m.predict(inputs)
status.assert_consumed()
Devido a esse mecanismo, é altamente recomendável que você use APIs de carregamento de ponto de verificação TF2 com modelos Keras (mesmo ao restaurar pontos de verificação TF1 pré-existentes nos shims de mapeamento de modelo ). Veja mais no guia do ponto de verificação.
Partes de codigo
Os snippets abaixo mostram a compatibilidade da versão TF1/TF2 nas APIs de salvamento de ponto de verificação.
Salvar um ponto de verificação do TF1 no TF2
a = tf.Variable(1.0, name='a')
b = tf.Variable(2.0, name='b')
with tf.name_scope('scoped'):
c = tf.Variable(3.0, name='c')
saver = tf1.train.Saver(var_list=[a, b, c])
path = saver.save(sess=None, save_path='tf1-ckpt-saved-in-eager')
print_checkpoint(path)
WARNING:tensorflow:Saver is deprecated, please switch to tf.train.Checkpoint or tf.keras.Model.save_weights for training checkpoints. When executing eagerly variables do not necessarily have unique names, and so the variable.name-based lookups Saver performs are error-prone. Checkpoint at 'tf1-ckpt-saved-in-eager': (key='scoped/c', shape=[], dtype=float32, value=3.0) (key='a', shape=[], dtype=float32, value=1.0) (key='b', shape=[], dtype=float32, value=2.0)
Carregar um ponto de verificação do TF1 no TF2
a = tf.Variable(0., name='a')
b = tf.Variable(0., name='b')
with tf.name_scope('scoped'):
c = tf.Variable(0., name='c')
print("Initialized [a, b, c]: ", [a.numpy(), b.numpy(), c.numpy()])
saver = tf1.train.Saver(var_list=[a, b, c])
saver.restore(sess=None, save_path='tf1-ckpt-saved-in-eager')
print("Restored [a, b, c]: ", [a.numpy(), b.numpy(), c.numpy()])
Initialized [a, b, c]: [0.0, 0.0, 0.0] WARNING:tensorflow:Saver is deprecated, please switch to tf.train.Checkpoint or tf.keras.Model.save_weights for training checkpoints. When executing eagerly variables do not necessarily have unique names, and so the variable.name-based lookups Saver performs are error-prone. INFO:tensorflow:Restoring parameters from tf1-ckpt-saved-in-eager Restored [a, b, c]: [1.0, 2.0, 3.0]
Salvar um ponto de verificação do TF2 no TF1
with tf.Graph().as_default() as g:
a = tf1.get_variable('a', shape=[], dtype=tf.float32,
initializer=tf1.constant_initializer(1))
b = tf1.get_variable('b', shape=[], dtype=tf.float32,
initializer=tf1.constant_initializer(2))
with tf1.variable_scope('scoped'):
c = tf1.get_variable('c', shape=[], dtype=tf.float32,
initializer=tf1.constant_initializer(3))
with tf1.Session() as sess:
sess.run(tf1.global_variables_initializer())
ckpt = tf.train.Checkpoint(
var_list={v.name.split(':')[0]: v for v in tf1.global_variables()})
tf2_in_tf1_path = ckpt.save('tf2-ckpt-saved-in-session')
print_checkpoint(tf2_in_tf1_path)
Checkpoint at 'tf2-ckpt-saved-in-session-1': (key='var_list/scoped.Sc/.ATTRIBUTES/VARIABLE_VALUE', shape=[], dtype=float32, value=3.0) (key='var_list/b/.ATTRIBUTES/VARIABLE_VALUE', shape=[], dtype=float32, value=2.0) (key='var_list/a/.ATTRIBUTES/VARIABLE_VALUE', shape=[], dtype=float32, value=1.0) (key='_CHECKPOINTABLE_OBJECT_GRAPH', shape=[], dtype=string, value=b"\n \n\x0c\x08\x01\x12\x08var_list\n\x10\x08\x02\x12\x0csave_counter\n\x1c\n\x05\x08\x03\x12\x01a\n\x05\x08\x04\x12\x01b\n\x0c\x08\x05\x12\x08scoped/c\nI\x12G\n\x0eVARIABLE_VALUE\x12\x0csave_counter\x1a'save_counter/.ATTRIBUTES/VARIABLE_VALUE\n<\x12:\n\x0eVARIABLE_VALUE\x12\x01a\x1a%var_list/a/.ATTRIBUTES/VARIABLE_VALUE\n<\x12:\n\x0eVARIABLE_VALUE\x12\x01b\x1a%var_list/b/.ATTRIBUTES/VARIABLE_VALUE\nK\x12I\n\x0eVARIABLE_VALUE\x12\x08scoped/c\x1a-var_list/scoped.Sc/.ATTRIBUTES/VARIABLE_VALUE") (key='save_counter/.ATTRIBUTES/VARIABLE_VALUE', shape=[], dtype=int64, value=1)
Carregar um ponto de verificação do TF2 no TF1
with tf.Graph().as_default() as g:
a = tf1.get_variable('a', shape=[], dtype=tf.float32,
initializer=tf1.constant_initializer(0))
b = tf1.get_variable('b', shape=[], dtype=tf.float32,
initializer=tf1.constant_initializer(0))
with tf1.variable_scope('scoped'):
c = tf1.get_variable('c', shape=[], dtype=tf.float32,
initializer=tf1.constant_initializer(0))
with tf1.Session() as sess:
sess.run(tf1.global_variables_initializer())
print("Initialized [a, b, c]: ", sess.run([a, b, c]))
ckpt = tf.train.Checkpoint(
var_list={v.name.split(':')[0]: v for v in tf1.global_variables()})
ckpt.restore('tf2-ckpt-saved-in-session-1').run_restore_ops()
print("Restored [a, b, c]: ", sess.run([a, b, c]))
Initialized [a, b, c]: [0.0, 0.0, 0.0] Restored [a, b, c]: [1.0, 2.0, 3.0]
Conversão de ponto de verificação
Você pode converter pontos de verificação entre TF1 e TF2 carregando e salvando novamente os pontos de verificação. Uma alternativa é tf.train.load_checkpoint
, mostrado no código abaixo.
Converter ponto de verificação TF1 para TF2
def convert_tf1_to_tf2(checkpoint_path, output_prefix):
"""Converts a TF1 checkpoint to TF2.
To load the converted checkpoint, you must build a dictionary that maps
variable names to variable objects.
```
ckpt = tf.train.Checkpoint(vars={name: variable})
ckpt.restore(converted_ckpt_path)
```
Args:
checkpoint_path: Path to the TF1 checkpoint.
output_prefix: Path prefix to the converted checkpoint.
Returns:
Path to the converted checkpoint.
"""
vars = {}
reader = tf.train.load_checkpoint(checkpoint_path)
dtypes = reader.get_variable_to_dtype_map()
for key in dtypes.keys():
vars[key] = tf.Variable(reader.get_tensor(key))
return tf.train.Checkpoint(vars=vars).save(output_prefix)
```
Convert the checkpoint saved in the snippet `Save a TF1 checkpoint in TF2`:
```python
# Make sure to run the snippet in `Save a TF1 checkpoint in TF2`.
print_checkpoint('tf1-ckpt-saved-in-eager')
converted_path = convert_tf1_to_tf2('tf1-ckpt-saved-in-eager',
'converted-tf1-to-tf2')
print("\n[Converted]")
print_checkpoint(converted_path)
# Try loading the converted checkpoint.
a = tf.Variable(0.)
b = tf.Variable(0.)
c = tf.Variable(0.)
ckpt = tf.train.Checkpoint(vars={'a': a, 'b': b, 'scoped/c': c})
ckpt.restore(converted_path).assert_consumed()
print("\nRestored [a, b, c]: ", [a.numpy(), b.numpy(), c.numpy()])
Checkpoint at 'tf1-ckpt-saved-in-eager': (key='scoped/c', shape=[], dtype=float32, value=3.0) (key='a', shape=[], dtype=float32, value=1.0) (key='b', shape=[], dtype=float32, value=2.0) [Converted] Checkpoint at 'converted-tf1-to-tf2-1': (key='vars/scoped.Sc/.ATTRIBUTES/VARIABLE_VALUE', shape=[], dtype=float32, value=3.0) (key='vars/b/.ATTRIBUTES/VARIABLE_VALUE', shape=[], dtype=float32, value=2.0) (key='vars/a/.ATTRIBUTES/VARIABLE_VALUE', shape=[], dtype=float32, value=1.0) (key='_CHECKPOINTABLE_OBJECT_GRAPH', shape=[], dtype=string, value=b"\n\x1c\n\x08\x08\x01\x12\x04vars\n\x10\x08\x02\x12\x0csave_counter\n\x1c\n\x0c\x08\x03\x12\x08scoped/c\n\x05\x08\x04\x12\x01a\n\x05\x08\x05\x12\x01b\nI\x12G\n\x0eVARIABLE_VALUE\x12\x0csave_counter\x1a'save_counter/.ATTRIBUTES/VARIABLE_VALUE\nG\x12E\n\x0eVARIABLE_VALUE\x12\x08Variable\x1a)vars/scoped.Sc/.ATTRIBUTES/VARIABLE_VALUE\n?\x12=\n\x0eVARIABLE_VALUE\x12\x08Variable\x1a!vars/a/.ATTRIBUTES/VARIABLE_VALUE\n?\x12=\n\x0eVARIABLE_VALUE\x12\x08Variable\x1a!vars/b/.ATTRIBUTES/VARIABLE_VALUE") (key='save_counter/.ATTRIBUTES/VARIABLE_VALUE', shape=[], dtype=int64, value=1) Restored [a, b, c]: [1.0, 2.0, 3.0]
Converter ponto de verificação TF2 para TF1
def convert_tf2_to_tf1(checkpoint_path, output_prefix):
"""Converts a TF2 checkpoint to TF1.
The checkpoint must be saved using a
`tf.train.Checkpoint(var_list={name: variable})`
To load the converted checkpoint with `tf.compat.v1.Saver`:
```
saver = tf.compat.v1.train.Saver(var_list={name: variable})
# An alternative, if the variable names match the keys:
saver = tf.compat.v1.train.Saver(var_list=[variables])
saver.restore(sess, output_path)
```
"""
vars = {}
reader = tf.train.load_checkpoint(checkpoint_path)
dtypes = reader.get_variable_to_dtype_map()
for key in dtypes.keys():
# Get the "name" from the
if key.startswith('var_list/'):
var_name = key.split('/')[1]
# TF2 checkpoint keys use '/', so if they appear in the user-defined name,
# they are escaped to '.S'.
var_name = var_name.replace('.S', '/')
vars[var_name] = tf.Variable(reader.get_tensor(key))
return tf1.train.Saver(var_list=vars).save(sess=None, save_path=output_prefix)
```
Convert the checkpoint saved in the snippet `Save a TF2 checkpoint in TF1`:
```python
# Make sure to run the snippet in `Save a TF2 checkpoint in TF1`.
print_checkpoint('tf2-ckpt-saved-in-session-1')
converted_path = convert_tf2_to_tf1('tf2-ckpt-saved-in-session-1',
'converted-tf2-to-tf1')
print("\n[Converted]")
print_checkpoint(converted_path)
# Try loading the converted checkpoint.
with tf.Graph().as_default() as g:
a = tf1.get_variable('a', shape=[], dtype=tf.float32,
initializer=tf1.constant_initializer(0))
b = tf1.get_variable('b', shape=[], dtype=tf.float32,
initializer=tf1.constant_initializer(0))
with tf1.variable_scope('scoped'):
c = tf1.get_variable('c', shape=[], dtype=tf.float32,
initializer=tf1.constant_initializer(0))
with tf1.Session() as sess:
saver = tf1.train.Saver([a, b, c])
saver.restore(sess, converted_path)
print("\nRestored [a, b, c]: ", sess.run([a, b, c]))
Checkpoint at 'tf2-ckpt-saved-in-session-1': (key='var_list/scoped.Sc/.ATTRIBUTES/VARIABLE_VALUE', shape=[], dtype=float32, value=3.0) (key='var_list/b/.ATTRIBUTES/VARIABLE_VALUE', shape=[], dtype=float32, value=2.0) (key='var_list/a/.ATTRIBUTES/VARIABLE_VALUE', shape=[], dtype=float32, value=1.0) (key='_CHECKPOINTABLE_OBJECT_GRAPH', shape=[], dtype=string, value=b"\n \n\x0c\x08\x01\x12\x08var_list\n\x10\x08\x02\x12\x0csave_counter\n\x1c\n\x05\x08\x03\x12\x01a\n\x05\x08\x04\x12\x01b\n\x0c\x08\x05\x12\x08scoped/c\nI\x12G\n\x0eVARIABLE_VALUE\x12\x0csave_counter\x1a'save_counter/.ATTRIBUTES/VARIABLE_VALUE\n<\x12:\n\x0eVARIABLE_VALUE\x12\x01a\x1a%var_list/a/.ATTRIBUTES/VARIABLE_VALUE\n<\x12:\n\x0eVARIABLE_VALUE\x12\x01b\x1a%var_list/b/.ATTRIBUTES/VARIABLE_VALUE\nK\x12I\n\x0eVARIABLE_VALUE\x12\x08scoped/c\x1a-var_list/scoped.Sc/.ATTRIBUTES/VARIABLE_VALUE") (key='save_counter/.ATTRIBUTES/VARIABLE_VALUE', shape=[], dtype=int64, value=1) WARNING:tensorflow:Saver is deprecated, please switch to tf.train.Checkpoint or tf.keras.Model.save_weights for training checkpoints. When executing eagerly variables do not necessarily have unique names, and so the variable.name-based lookups Saver performs are error-prone. [Converted] Checkpoint at 'converted-tf2-to-tf1': (key='scoped/c', shape=[], dtype=float32, value=3.0) (key='a', shape=[], dtype=float32, value=1.0) (key='b', shape=[], dtype=float32, value=2.0) INFO:tensorflow:Restoring parameters from converted-tf2-to-tf1 Restored [a, b, c]: [1.0, 2.0, 3.0]