Path: blob/master/site/pt-br/guide/migrate/model_mapping.ipynb
25118 views
Copyright 2021 The TensorFlow Authors.
Use modelos TF1.x em workflows TF2
Este guia fornece uma visão geral e exemplos de um shim para código de modelagem que você pode empregar para usar seus modelos TF1.x existentes em workflows TF2, como estratégias de execução antecipada (eager), tf.function
e de distribuição com alterações mínimas no seu código de modelagem.
Escopo de uso
O shim descrito neste guia foi projetado para modelos TF1.x que dependem de:
tf.compat.v1.get_variable
etf.compat.v1.variable_scope
para controlar a criação e reutilização de variáveis eAPIs baseadas em coleções de grafos, como
tf.compat.v1.global_variables()
,tf.compat.v1.trainable_variables
,tf.compat.v1.losses.get_regularization_losses()
etf.compat.v1.get_collection()
para acompanhar de pesos e perdas de regularização
Isso inclui a maioria dos modelos criados com base nas APIs tf.compat.v1.layer
, tf.contrib.layers
e TensorFlow-Slim.
O shim NÃO é necessário para os seguintes modelos TF1.x:
Modelos Keras standalone que já rastreiam todos os seus pesos treináveis e perdas de regularização via
model.trainable_weights
emodel.losses
, respectivamente.tf.Module
s que já rastreiam todos os seus pesos treináveis viamodule.trainable_variables
e apenas criam pesos se ainda não tiverem sido criados.
Esses modelos provavelmente já funcionarão no TF2 com execução eager e tf.function
s.
Configuração
Importe o TensorFlow e outras dependências.
O decorador track_tf1_style_variables
O principal shim descrito neste guia é tf.compat.v1.keras.utils.track_tf1_style_variables
, um decorador que você pode usar nos métodos pertencentes a tf.keras.layers.Layer
e tf.Module
para rastrear pesos de estilo TF1.x e capturar perdas de regularização.
Decorar métodos de chamada de objetos tf.keras.layers.Layer
ou tf.Module
com tf.compat.v1.keras.utils.track_tf1_style_variables
permite a criação e reutilização de variáveis via tf.compat.v1.get_variable
(e por extensão tf.compat.v1.layers
) para funcionar corretamente dentro do método decorado em vez de sempre criar uma nova variável a cada chamada. Isso também fará com que a camada ou módulo rastreie implicitamente quaisquer pesos criados ou acessados via get_variable
dentro do método decorado.
Além de rastrear os próprios pesos sob as propriedades padrão layer.variable
/module.variable
/etc., se o método pertencer a um tf.keras.layers.Layer
, quaisquer perdas de regularização especificadas através dos argumentos do regularizador get_variable
ou tf.compat.v1.layers
serão rastreadas pela camada sob a propriedade padrão layer.losses
.
Esse mecanismo de rastreamento permite o uso de grandes classes de código model-forward-pass no estilo TF1.x dentro das camadas Keras ou objetos tf.Module
no TF2, mesmo com os comportamentos TF2 ativados.
Exemplos de uso
Os exemplos de uso abaixo demonstram os shims de modelagem usados para decorar os métodos tf.keras.layers.Layer
, mas, exceto onde eles interagem especificamente com os recursos do Keras, eles também são aplicáveis ao decorar métodos tf.Module
.
Camada construída com tf.compat.v1.get_variable
Imagine que você tenha uma camada implementada diretamente sobre tf.compat.v1.get_variable
da seguinte forma:
Use o shim para transformá-la numa camada e chame-a nas entradas.
Acesse as variáveis rastreadas e as perdas de regularização capturadas como uma camada Keras padrão.
Para ver se os pesos são reutilizados sempre que você chama a camada, defina todos os pesos como zero e chame a camada novamente.
Você também pode usar a camada convertida diretamente na construção do modelo funcional Keras.
Modelo criado com tf.compat.v1.layers
Imagine que você tenha uma camada ou modelo implementado diretamente sobre tf.compat.v1.layers
da seguinte forma:
Use o shim para transformá-lo numa camada e chame-a nas entradas.
Aviso: por questões de segurança, certifique-se de colocar todos os tf.compat.v1.layers
dentro de uma string não vazia variable_scope
. O motivo é que tf.compat.v1.layers
com nomes gerados automaticamente sempre incrementará automaticamente o nome quando estiver fora de qualquer escopo de variável. Isso significa que os nomes das variáveis solicitadas serão incompatíveis sempre que você chamar a camada/módulo. Assim, em vez de reutilizar os pesos já criados, ele criará um novo conjunto de variáveis a cada chamada.
Acesse as variáveis rastreadas e as perdas de regularização capturadas como uma camada Keras padrão.
Para ver se os pesos são reutilizados sempre que você chama a camada, defina todos os pesos como zero e chame a camada novamente.
Você também pode usar a camada convertida diretamente na construção do modelo funcional Keras.
Capture atualizações de normalização em lote e argumentos de modelo training
No TF1.x, você executa a normalização em lote da seguinte forma:
Observe que:
As atualizações de média móvel da normalização em lote são rastreadas por
get_collection
, que foi chamado separadamente da camadatf.compat.v1.layers.batch_normalization
requer um argumentotraining
(geralmente chamado deis_training
ao usar camadas de normalização em lote TF-Slim)
No TF2, devido à execução antecipada (eager) e às dependências de controle automático, as atualizações da média móvel da normalização do lote serão executadas imediatamente. Não há necessidade de coletá-las separadamente da coleção de atualizações e adicioná-las como dependências de controle explícitas.
Além disso, se você fornecer um argumento training
ao método de passo para frente da sua tf.keras.layers.Layer
, o Keras poderá passar a fase de treinamento atual e quaisquer camadas aninhadas para ele, assim como faria com qualquer outra camada. Consulte a documentação da API para tf.keras.Model
para obter mais informações sobre como o Keras lida com o argumento training
.
Se você estiver decorando métodos tf.Module
, precisará certificar-se de passar manualmente todos os argumentos training
conforme necessário. No entanto, as atualizações de média móvel de normalização de lote ainda serão aplicadas automaticamente sem a necessidade de dependências de controle explícitas.
As amostras de código a seguir demonstram como incorporar camadas de normalização de lote no shim e como funciona seu uso num modelo Keras (aplicável a tf.keras.layers.Layer
).
Reuso variável baseado em escopo de variáveis
Quaisquer criações de variáveis no passo para frente baseado em get_variable
manterão a mesma nomenclatura de variável e semântica de reutilização que os escopos de variáveis têm no TF1.x. Isto se aplica desde que você tenha pelo menos um escopo externo não vazio para quaisquer tf.compat.v1.layers
com nomes gerados automaticamente, conforme mencionado acima.
Observação: A nomenclatura e a reutilização terão como escopo uma única instância de camada/módulo. As chamadas para get_variable
dentro de uma camada ou módulo decorado com shim não poderão se referir a variáveis criadas dentro de camadas ou módulos. Você pode contornar isso usando referências Python a outras variáveis diretamente, se necessário, em vez de acessar variáveis via get_variable
.
Execução avançada (eager) e tf.function
Como visto acima, os métodos decorados para tf.keras.layers.Layer
e tf.Module
são executados dentro da execução antecipada (eager) e também são compatíveis com tf.function
. Isto significa que você pode usar pdb e outras ferramentas interativas para percorrer seu passo para frente durante a execução.
Importante: Embora seja perfeitamente seguro chamar seus métodos de camada/módulo decorados com shim de dentro de um tf.function
, não é seguro colocar tf.functions
dentro de seus métodos decorados com shim se esses tf.functions
contiverem chamadas get_variable
. Inserir um tf.function
redefine os variable_scope
, o que significa que o reuso de uma variável (baseada em escopo de variável no estilo TF1.x que o shim simula) será quebrada nessa configuração.
Estratégias de distribuição
Chamadas para get_variable
dentro de @track_tf1_style_variables
- camada decorada ou métodos de módulo usam criações padrão da variável tf.Variable
nos bastidores. Isto significa que você pode usá-las com as várias estratégias de distribuição disponíveis com tf.distribute
, como MirroredStrategy
e TPUStrategy
.
Aninhando objetos tf.Variable
, tf.Module
, tf.keras.layers
e tf.keras.models
em chamadas decoradas
Decorar sua chamada de camada em tf.compat.v1.keras.utils.track_tf1_style_variables
vai apenas adicionar rastreamento implícito automático das variáveis criadas (e reutilizadas) via tf.compat.v1.get_variable
. Isto não vai capturar pesos criados diretamente por chamadas tf.Variable
, como aquelas usadas por camadas típicas do Keras e a maioria dos objetos tf.Module
. Esta seção descreve como lidar com esses casos aninhados.
(Usos pré-existentes) tf.keras.layers
e tf.keras.models
Para usos pré-existentes de camadas e modelos Keras aninhados, use tf.compat.v1.keras.utils.get_or_create_layer
. Isto é recomendado apenas para facilitar a migração dos usos de Keras aninhados em TF1.x existentes; o novo código deve usar configuração de atributo explícito conforme descrito abaixo para tf.Variables e tf.Modules.
Para usar tf.compat.v1.keras.utils.get_or_create_layer
, envolva o código que constrói seu modelo aninhado dentro de um método e passe-o para o método. Por exemplo:
Este método garante que essas camadas aninhadas sejam reutilizadas e rastreadas corretamente pelo Tensorflow. Observe que o decorador @track_tf1_style_variables
ainda é necessário no método apropriado. O método para construção do modelo passado para get_or_create_layer
(neste caso, self.build_model
), não deve receber argumentos.
Os pesos são rastreados:
E a perda de regularização também:
Migração incremental: tf.Variables
e tf.Modules
Se você precisar incorporar chamadas tf.Variable
ou tf.Module
em seus métodos decorados (por exemplo, se estiver seguindo a migração incremental para APIs TF2 não legadas descritas mais adiante neste guia), você ainda precisará rastreá-las explicitamente, com os seguintes requisitos:
Garanta, de forma explicita, que a variável/módulo/camada seja criada apenas uma vez
Anexe-as, de forma explícita, como atributos de instância, assim como você faria ao definir um módulo ou camada típico
Reutilize, de forma explícita, o objeto já criado em chamadas subsequentes
Isso garante que os pesos não sejam criados a cada nova chamada e sejam reutilizados corretamente. Além disso, isso também garante que os pesos existentes e as perdas de regularização sejam rastreados.
Eis um exemplo de como isso pode ser feito:
Observe que o rastreamento explícito do módulo aninhado é necessário, mesmo que seja decorado com o decorador track_tf1_style_variables
. Isso ocorre porque cada módulo/camada com métodos decorados possui seu próprio armazenamento de variáveis associado a ele.
Os pesos são rastreados corretamente:
Assim como a perda de regularização:
Observe que, se NestedLayer
fosse um tf.Module
não Keras, as variáveis ainda seriam rastreadas, mas as perdas de regularização não seriam rastreadas automaticamente, então você teria que rastreá-las explicitamente de forma separada.
Orientação sobre nomes de variáveis
Chamadas explícitas tf.Variable
e camadas Keras usam um mecanismo de geração automática de nome de variável / nome de camada diferente do que você pode estar acostumado a partir da combinação de get_variable
e variable_scopes
. Embora o shim faça com que os nomes de variáveis correspondam às variáveis criadas por get_variable
, mesmo ao migrar de grafos TF1.x para TF2 com execução antecipada (eager) e tf.function
, ele não poderá garantir o mesmo para os nomes de variáveis gerados para chamadas tf.Variable
e camadas Keras que você incorpora dentro de seus decoradores de método. É até possível ter múltiplas variáveis compartilhando o mesmo nome na execução antecipada (eager) TF2 e tf.function
.
Você deve dedicar uma atenção especial a essa questão quando for seguir as seções sobre validação da exatidão e mapeamento de checkpoints TF1.x mais adiante neste guia.
Usando tf.compat.v1.make_template
no método decorado
É altamente recomendável que você use tf.compat.v1.keras.utils.track_tf1_style_variables
diretamente, em vez de usar tf.compat.v1.make_template
, pois é uma camada mais fina sobre TF2.
Siga as orientações desta seção para código TF1.x existente que já dependia de tf.compat.v1.make_template
.
Como tf.compat.v1.make_template
agrupa o código que usa get_variable
, o decorador track_tf1_style_variables
permite que você use esses modelos em chamadas de camada e rastreie com sucesso os pesos e as perdas de regularização.
No entanto, não deixe de chamar make_template
apenas uma vez e depois reutilizar o mesmo modelo em cada chamada de camada. Caso contrário, um novo modelo será criado cada vez que você chamar a camada junto com um novo conjunto de variáveis.
Por exemplo,
Importante: Evite compartilhar o mesmo modelo criado por make_template
em múltiplas instâncias de camada, pois isto poderá quebrar os mecanismos de rastreamento de perda de regularização e variável do decorador shim. Além disso, se você planeja usar o mesmo nome make_template
dentro de múltiplas instâncias de camada, precisará aninhar o uso do modelo criado dentro de um variable_scope
. Caso contrário, o nome gerado para a variable_scope
do modelo será incrementado a cada nova instância da camada. Isto poderá alterar os nomes dos pesos de maneiras inesperadas.
Migração incremental para TF2 nativo
Conforme mencionado anteriormente, track_tf1_style_variables
permite que você misture tf.Variable
/tf.keras.layers.Layer
/tf.Module
orientado a objetos no estilo TF2 com o uso legado de tf.compat.v1.get_variable
/tf.compat.v1.layers
dentro do mesmo módulo/camada decorada.
Isto significa que depois de tornar seu modelo TF1.x totalmente compatível com TF2, você pode escrever todos os novos componentes de modelo com APIs TF2 nativas (não- tf.compat.v1
) e fazer com que interoperem com seu código antigo.
No entanto, se você continuar a modificar seus componentes de modelo mais antigos, você talvez também queira gradualmente substituir o uso do tf.compat.v1
legado para as APIs orientadas a objeto puramente nativas recomendadas para código TF2 novo.
O uso de tf.compat.v1.get_variable
pode ser substituído por chamadas self.add_weight
se você estiver decorando uma camada/modelo Keras ou com chamadas tf.Variable
se estiver decorando objetos Keras ou tf.Module
.
Tanto as tf.compat.v1.layers
de estilo funcional como as orientadas a objeto geralmente podem ser substituídas por uma camada tf.keras.layers
equivalente sem a necessidade de alterações nos argumentos.
Você talvez também queira considerar partes de seu modelo ou padrões comuns em camadas/módulos individuais durante sua mudança incremental para APIs puramente nativas, que podem usar track_tf1_style_variables
.
Uma observação sobre Slim e contrib.layers
Bastante código TF 1.x antigo usa a biblioteca Slim, que foi empacotada com o TF 1.x em tf.contrib.layers
. Converter código que usa Slim para TF 2 nativo é mais complexo do que converter v1.layers
. Na verdade, pode ser melhor converter seu código Slim para v1.layers
primeiro e depois converter para Keras. Abaixo estão algumas orientações gerais para converter o código Slim.
Garanta que todos os argumentos sejam explícitos. Remova
arg_scopes
se possível. Se você ainda precisar usá-los, separenormalizer_fn
eactivation_fn
em camadas próprias.Camadas convolucionais separáveis são mapeadas para uma ou mais camadas Keras diferentes (camadas Keras separáveis, ponto a ponto, profundidade a profundidade).
Slim e
v1.layers
têm nomes de argumentos e valores padrão diferentes.Observe que alguns argumentos usam escalas diferentes.
Migração para TF2 nativo ignorando a compatibilidade de checkpoints
O exemplo de código a seguir demonstra a migração incremental de um modelo para APIs puramente nativas sem considerar a compatibilidade dos checkpoints.
Em seguida, substitua as APIs compat.v1
por suas equivalentes nativas orientadas a objetos, de forma segmentada. Comece trocando a camada de convolução por um objeto Keras criado no construtor da camada.
Use a classe v1.keras.utils.DeterministicRandomTestTool
para verificar se essa alteração incremental deixa o modelo com o mesmo comportamento de antes.
Agora você substituiu todos os compat.v1.layers
individuais por camadas Keras nativas.
Por fim, remova qualquer uso restante de variable_scope
(não é mais necessário) e o decorador track_tf1_style_variables
.
Agora você tem uma versão do modelo que usa APIs totalmente nativas.
Mantendo a compatibilidade de checkpoints durante a migração para o Native TF2
O processo de migração acima para APIs TF2 nativas alterou os nomes das variáveis (já que as APIs Keras produzem nomes de pesos muito diferentes) e os caminhos orientados a objetos que apontam para pesos diferentes no modelo. O impacto dessas alterações é que elas quebrarão qualquer checkpoint baseado em nome no estilo TF1 existente ou checkpoint orientado a objeto no estilo TF2.
No entanto, em alguns casos, você pode pegar seu checkpoint original, baseado em nome, e encontrar um mapeamento das variáveis para seus novos nomes com abordagens como a detalhada no Guia Reuso de checkpoints TF1.x.
Algumas dicas para tornar isso viável são as seguintes:
As variáveis ainda têm um argumento
name
que você pode definir.Os modelos Keras também recebem um argumento
name
que eles definem como prefixo para suas variáveis.A função
v1.name_scope
pode ser usada para definir prefixos de nomes de variáveis. Isto é muito diferente detf.variable_scope
. Afeta apenas nomes e não rastreia variáveis e reuso.
Levando em conta os ponteiros acima, os exemplos de código a seguir demonstram um fluxo de trabalho que você pode adaptar ao seu código para atualizar de forma incremental parte de um modelo enquanto atualiza simultaneamente os checkpoints.
Observação: devido à complexidade da nomenclatura de variáveis com camadas Keras, não há garantia de que isso funcione em todos os casos de uso.
Comece trocando as
tf.compat.v1.layers
de estilo funcional por suas versões orientadas a objetos.
Em seguida, atribua os objetos compat.v1.layer e quaisquer variáveis criadas por
compat.v1.get_variable
como propriedades do objetotf.keras.layers.Layer
/tf.Module
cujo método é decorado comtrack_tf1_style_variables
(observe que agora, quaisquer checkpoints orientados a objeto em estilo TF2 irão salvar dois caminhos: um por nome de variável e o novo caminho orientado a objetos).
Salve novamente um checkpoint carregado neste ponto para salvar os caminhos pelo nome da variável (para compat.v1.layers) ou pelo grafo orientado a objetos.
Agora você pode trocar os
compat.v1.layers
orientados a objetos por camadas Keras nativas enquanto ainda poderá carregar o checkpoint salvo recentemente. Certifique-se de preservar os nomes das variáveis para ascompat.v1.layers
restantes, registrando osvariable_scopes
gerados automaticamente das camadas substituídas. Agora, essas camadas/variáveis trocadas usarão apenas o caminho do atributo do objeto para as variáveis no checkpoint, em vez do caminho do nome da variável.
Em geral, você pode substituir o uso de compat.v1.get_variable
em variáveis anexadas a propriedades através de:
Trocando-as pelo uso de
tf.Variable
, OUAtualizando-as com
tf.keras.layers.Layer.add_weight
. Observe que, se você não estiver trocando todas as camadas de uma só vez, poderá haver troca nos nomes das camadas/variáveis geradas automaticamente para ascompat.v1.layers
restantes que não tiverem um argumentoname
. Se for esse o caso, você deve manter os nomes das variáveis para ascompat.v1.layers
restantes abrindo e fechando manualmente umvariable_scope
correspondente ao nome do escopo gerado pelacompat.v1.layer
removida. Caso contrário, os caminhos dos checkpoints existentes podem entrar em conflito e o carregamento do checkpoint ocorrerá de forma incorreta.
Salvar um checkpoint nesta etapa depois da construção das variáveis fará com que ele contenha apenas os caminhos de objeto atualmente disponíveis.
Não deixe de registrar os escopos das compat.v1.layers
removidas para preservar os nomes de peso gerados automaticamente para as compat.v1.layers
restantes.
Repita os passos acima até ter substituído todos os
compat.v1.layers
ecompat.v1.get_variable
do seu modelo por equivalentes totalmente nativos.
Lembre-se de testar para garantir que o checkpoint recém-atualizado ainda se comporte conforme o esperado. Aplique as técnicas descritas no guia de validação da exatidão numérica em cada passo incremental deste processo para garantir que seu código migrado seja executado corretamente.
Lidando com mudanças de comportamento na migração de TF1.x para TF2 não cobertas pelos shims de modelagem
Os shims de modelagem descritos neste guia podem garantir que variáveis, camadas e perdas de regularização criadas com get_variable
, tf.compat.v1.layers
e semânticas variable_scope
continuem a funcionar como antes ao usar execução antecipada (eager) e tf.function
, sem precisar depender de coleções.
Isto não abrange todas as semânticas específicas do TF1.x das quais podem depender os passos para frente do seu modelo. Em alguns casos, os shims podem ser insuficientes para garantir que o passo para frente do seu modelo rode no TF2 por conta própria. Leia o Guia de comportamentos TF1.x vs TF2 para saber mais sobre as diferenças comportamentais entre TF1.x e TF2.