Path: blob/master/site/pt-br/guide/migrate/migrating_checkpoints.ipynb
25118 views
Copyright 2021 The TensorFlow Authors.
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.
Para carregar o checkpoint TF1 em TF2, consulte a amostra de código Carregando um checkpoint TF1 em TF2.
Para converter o checkpoint em TF2, veja Conversão de checkpoints.
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
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:
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:
Experimente o trecho abaixo e veja como as chaves do checkpoint mudam com a estrutura do objeto:
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:
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:
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ções que mapeia nomes de variáveis no checkpoint 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 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
:
O exemplo abaixo usa tf.compat.v1.Saver
para carregar o checkpoint no modo eager:
O próximo trecho de código carrega o checkpoint usando a API TF2 tf.train.Checkpoint
:
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 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 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:
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 noscope_name
atual decheckpoint_scope_name
com nomes de tensor correspondentes.'checkpoint_scope_name/some_other_variable': 'scope_name/variable_name'
- inicializará a variávelscope_name/variable_name
decheckpoint_scope_name/some_other_variable
.'scope_variable_name': variable
- inicializará determinado objetotf.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 noscope_name
atual da raiz do checkpoint (por exemplo: 'no scope').
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
.
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.
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:
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:
Você pode continuar usando tf.train.Checkpoint
mesmo que os nomes das variáveis/escopos mudem:
E no modo eager:
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.
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.
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 TF2 em TF1
Carregando um checkpoint TF2 em TF1
Conversão de checkpoints TF1 para TF2
Converta o checkpoint salvo na amostra de código Salvando um checkpoint TF2 em TF1
:
Conversão de checkpoints TF2 para TF1
Converta o checkpoint salvo no trecho de código Salvando um checkpoint TF2 em TF1
:
Guias Relacionados
Guia de mapeamento de modelos e
tf.compat.v1.keras.utils.track_tf1_style_variables