Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
tensorflow
GitHub Repository: tensorflow/docs-l10n
Path: blob/master/site/pt-br/guide/migrate/migrating_checkpoints.ipynb
25118 views
Kernel: Python 3
#@title Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # https://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License.

Como migrar os checkpoints de um modelo

Observação: geralmente, chamamos os checkpoints salvos com tf.compat.v1.Saver de checkpoints TF1 ou baseados em nome. Chamamos os checkpoints salvos com tf.train.Checkpoint como checkpoints TF2 ou baseados em objetos.

Visão geral

Este guia pressupõe que você tenha um modelo que salva e carrega checkpoints com tf.compat.v1.Saver e deseja migrar o código usando a API TF2 tf.train.Checkpoint ou usar checkpoints pré-existentes em seu modelo TF2.

Abaixo estão alguns cenários comuns que você pode encontrar:

Cenário 1

Existem checkpoints TF1 existentes de execuções de treinamento anteriores que precisam ser carregados ou convertidos para TF2.

Cenário 2

Você está ajustando seu modelo de uma maneira tal que existe o risco de alterar nomes e caminhos de variáveis ​​(como na migração incremental de get_variable para a criação explícita de tf.Variable) e gostaria de continuar salvando/carregando checkpoints existentes ao longo do caminho.

Consulte a seção sobre Como manter a compatibilidade de checkpoints durante a migração de modelos

Cenário 3

Você está migrando seu código de treinamento e checkpoints para TF2, mas seu pipeline de inferência continua exigindo checkpoints TF1 por enquanto (para estabilidade da produção).

Opção 1

Salve ambos os checkpoints TF1 e TF2 ao treinar.

Opção 2

Converta o checkpoint TF2 para TF1.


Os exemplos abaixo mostram todas as combinações de salvamento e carregamento de checkpoints no TF1/TF2, para que você tenha alguma flexibilidade para determinar como migrar seu modelo.

Configuração

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ê tiver curiosidade sobre o que mudou entre TF1 e TF2 e o que queremos dizer com checkpoints "baseados em nome" (TF1) versus "baseados em objeto" (TF2).

Na verdade, os dois tipos de checkpoint são salvos no mesmo formato, que é essencialmente uma tabela chave-valor. A diferença está em como as chaves são geradas.

As chaves em checkpoints baseados em nome são os nomes das variáveis. As chaves em checkpoints baseados em objeto referem-se ao caminho do objeto raiz para a variável (os exemplos abaixo ajudarão a entender melhor o 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')
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)

Se você observar as chaves em tf2-ckpt, todas elas se referem aos caminhos de objeto de cada variável. Por exemplo, a variável a é o primeiro elemento na lista 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 é mostrada 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])

Experimente o trecho abaixo e veja como as chaves do checkpoint 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)

Por que o TF2 usa esse mecanismo?

Como não há mais um grafo global no TF2, os nomes das variáveis ​​não são confiáveis ​​e podem se tornar inconsistentes entre programas. O TF2 incentiva a abordagem de modelagem orientada a objetos onde as variáveis ​​pertencem às camadas, e as camadas pertencem a um modelo:

variable = tf.Variable(...) layer.variable_name = variable model.layer_name = layer

Como manter a compatibilidade de checkpoints durante a migração de modelos

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, permitirá validar se as operações/funções estão fazendo os cálculos corretos. Para isto, deve-se considerar a compatibilidade de checkpoints entre modelos nas diversas etapas da migração. Essencialmente, esta seção responde à pergunta: como continuo usando o mesmo checkpoint enquanto altero o modelo.

Abaixo estão três maneiras de manter a compatibilidade do checkpoint, a fim de aumentar a flexibilidade:

  1. O modelo tem os mesmos nomes de variáveis ​​de antes.

  2. O modelo tem nomes de variáveis ​​diferentes e mantém um mapa de atribuições que mapeia nomes de variáveis ​​no checkpoint para os novos nomes.

  3. 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 os checkpoints quando os nomes das variáveis ​​coincidem.

Resposta curta: você pode carregar diretamente o checkpoint pré-existente com tf1.train.Saver ou tf.train.Checkpoint.


Se você estiver usando tf.compat.v1.keras.utils.track_tf1_style_variables, então isto irá garantir que os nomes das variáveis ​​do 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 tf.train.Checkpoint diretamente ou tf.compat.v1.train.Saver para carregar o checkpoint. Ambas as APIs são compatíveis com o modo grafo e eager, para que você possa usá-las em qualquer estágio da migração.

Observação: você pode usar tf.train.Checkpoint para carregar checkpoints TF1, mas não pode usar tf.compat.v1.Saver para carregar checkpoints TF2 sem uma correspondência de nome complexa.

Abaixo estão alguns exemplos de como usar o mesmo checkpoint 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)

O exemplo abaixo usa tf.compat.v1.Saver para carregar o checkpoint no modo eager:

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)

O próximo trecho de código carrega o checkpoint usando a API 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()}]")

Nomes de variáveis ​​em TF2

  • As variáveis ​​ainda têm um argumento name que você pode definir.

  • Os modelos de Keras também recebem um argumento name que é definido como prefixo para suas variáveis.

  • A função v1.name_scope pode ser usada para definir prefixos de nomes de variáveis. Isso é muito diferente de tf.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 de variáveis ​​e a compatibilidade do checkpoint TF1, mantendo a nomenclatura e a semântica de reutilização de tf.variable_scope e tf.compat.v1.get_variable inalterada. Consulte o Guia de mapeamento de modelos para mais informações.

Observação 1: Se você estiver usando o shim, use APIs TF2 para carregar seus checkpoints (mesmo quando usar checkpoints TF1 pré-treinados).

Veja a seção Checkpoints no Keras.

Observação 2: ao migrar de get_variable para tf.Variable:

Se sua camada ou módulo decorado com shim consistir em algumas variáveis ​​(ou camadas/modelos Keras) que usam tf.Variable em vez de tf.compat.v1.get_variable e forem anexadas como propriedades/rastreadas de maneira orientada a objetos, elas podem ter diferentes semântica de nomenclatura variável em grafos/sessões TF1.x em comparação com a execução antecipada (eager).

Em suma, os nomes podem não ser o que você espera ao executar no TF2.

Importante: as variáveis ​​podem ter nomes duplicados na execução antecipada (eager), o que pode causar problemas se múltiplas variáveis ​​no checkpoint baseado em nome precisarem ser mapeadas para o mesmo nome. Você pode ajustar explicitamente a camada e os nomes das variáveis ​​usando tf.name_scope e o construtor da camada, ou argumentos tf.Variable name para ajustar os nomes das variáveis ​​e garantir que não haja duplicatas.

Manutenção de mapas de atribuições

Os mapas de atribuição são frequentemente 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ável ou escopo podem ter mudado.

Os exemplos nesta seção usarão um name salvo anteriormente:

print_checkpoint('tf1-ckpt')

Carregando com init_from_checkpoint

tf1.train.init_from_checkpoint precisa ser chamado durante um Grafo/Sessão, porque coloca os valores nos inicializadores de variáveis ​​em vez de criar um op 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 suporta a seguinte sintaxe:

  • 'checkpoint_scope_name/': 'scope_name/' - carregará todas as variáveis ​​no scope_name atual de checkpoint_scope_name com nomes de tensor correspondentes.

  • 'checkpoint_scope_name/some_other_variable': 'scope_name/variable_name' - inicializará a variável scope_name/variable_name de checkpoint_scope_name/some_other_variable.

  • 'scope_variable_name': variable - inicializará determinado objeto tf.Variable com o tensor 'scope_variable_name' do checkpoint.

  • 'scope_variable_name': list(variable) - inicializará a lista de variáveis ​​particionadas com o tensor 'scope_variable_name' do checkpoint.

  • '/': 'scope_name/' - carregará todas as variáveis ​​no scope_name atual da raiz do checkpoint (por exemplo: 'no scope').

# 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]))

Carregando com tf1.train.Saver

Ao contrário de init_from_checkpoint, tf.compat.v1.train.Saver é executado tanto no modo grafo quanto no modo eager. O argumento var_list opcionalmente aceita um dicionário, no entanto precisa 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()])

Carregando com tf.train.load_checkpoint

Esta opção é ideal se você precisar de controle preciso sobre os valores das variáveis. Novamente, isto funciona nos modos grafo e eager.

# 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]))

Mantendo um objeto TF2 Checkpoint

Se os nomes de variável e escopo puderem mudar bastante durante a migração, use os checkpoints tf.train.Checkpoint e TF2. TF2 usa a estrutura de objeto em vez de nomes de variáveis ​​(mais detalhes em Mudanças de TF1 para TF2).

Em suma, ao criar um tf.train.Checkpoint para salvar ou restaurar checkpoints, garanta que ele use o mesmo ordenamento (para listas) e chaves (para dicionários e argumentos de palavra-chave para o inicializador Checkpoint). Eis alguns exemplos de compatibilidade de checkpoint:

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 checkpoint 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)

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

E no modo eager:

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()])

Checkpoints TF2 no Estimator

As seções acima descrevem como manter a compatibilidade do checkpoint ao migrar seu modelo. Esses conceitos também se aplicam aos modelos Estimator, embora a maneira como o checkpoint é salvo/carregado seja um pouco diferente. Ao migrar seu modelo Estimator para usar APIs TF2, você pode querer trocar os checkpoints TF1 para TF2 enquanto o modelo ainda estiver usando o estimador. Esta seção mostra como fazer isso.

O tf.estimator.Estimator e o MonitoredSession possuem 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 o Estimator e o MonitoredSession salvem checkpoint 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)
# 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

O valor final de v deve ser 16, após ser inicializado com warm start em est-tf1, e depois treinado por mais 5 passos. O valor do passo 'train' não é transferido do checkpoint warm_start.

Checkpoints no 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, passe a usar model.save_weights e model.load_weights, especialmente se estiver usando o callback ModelCheckpoint durante o treinamento.

Algumas coisas que você deve saber sobre checkpoints e Keras:

Inicialização vs Construção

Os modelos e camadas do Keras devem passar por dois passos antes de serem totalmente criados. O primeiro é a inicialização (initialization) do objeto Python: layer = tf.keras.layers.Dense(x). O segundo é o passo de construção (build), no qual a maioria dos pesos é de fato criada: layer.build(input_shape). Você também pode criar um modelo chamando-o ou executando um único passo train , eval ou predict (somente na primeira vez).

Se você descobrir que model.load_weights(path).assert_consumed() está gerando um erro, é provável que o modelo/camadas não tenham sido construídos.

Keras usa checkpoints TF2

tf.train.Checkpoint(model).write é equivalente a model.save_weights. O mesmo vale para tf.train.Checkpoint(model).read e model.load_weights. Observe que Checkpoint(model) != Checkpoint(model=model).

Os checkpoints do TF2 funcionam com o passo build() do Keras

tf.train.Checkpoint.restore tem um mecanismo chamado restauração adiada (deferred restoration) 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 a modelos inicializados carregar pesos e construir (build) 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 usar APIs de carregamento de checkpoints TF2 com modelos Keras (mesmo ao restaurar checkpoints TF1 pré-existentes nos shims de mapeamento de modelo). Veja mais no guia de checkpoints.

Amostras de codigo

As amostras de código abaixo demonstram a compatibilidade das versões TF1/TF2 nas APIs de salvamento de checkpoints.

Salvando um checkpoint TF1 em 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)

Carregando um checkpoint TF1 em 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()])

Salvando um checkpoint TF2 em 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)

Carregando um checkpoint TF2 em 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]))

Conversão de checkpoints

Você pode converter checkpoints entre TF1 e TF2 carregando-os e salvando-os novamente. Uma alternativa é tf.train.load_checkpoint, mostrada no código abaixo.

Conversão de checkpoints 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)

Converta o checkpoint salvo na amostra de código Salvando um checkpoint TF2 em TF1:

# 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()])

Conversão de checkpoints 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)

Converta o checkpoint salvo no trecho de código Salvando um checkpoint TF2 em TF1:

# 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]))

Guias Relacionados