Path: blob/master/site/pt-br/tensorboard/migrate.ipynb
25115 views
Copyright 2019 The TensorFlow Authors.
Migração do uso de tf.summary para o TF 2.x
Observação: esta documentação é para quem já está familiarizado com o TensorBoard do TensorFlow 1.x e quer migrar grandes bases de código do TensorFlow 1.x para o 2.x. Se você for iniciante no TensorBoard, veja a documentação para começar. Se estiver usando o
tf.keras
, talvez não seja necessária nenhuma ação para fazer upgrade para o TensorFlow 2.x.
O TensorFlow 2.x inclui mudanças significativas na API tf.summary
usada para escrever dados de resumo para a visualização no TensorBoard.
O que mudou
É útil pensar na API tf.summary
como duas sub-APIs:
Um conjunto de ops para gravar resumos individuais —
summary.scalar()
,summary.histogram()
,summary.image()
,summary.audio()
esummary.text()
— que são chamadas inline no código do seu modelo.A escrita da lógica que coleta esses resumos individuais e os escreve em um arquivo de log especialmente formatado (que o TensorBoard lê para gerar visualizações).
No TF 1.x
As duas partes precisam ser conectadas manualmente — ao buscar as saídas da op de resumo pela Session.run()
e chamar FileWriter.add_summary(output, step)
. A op v1.summary.merge_all()
facilitou isso ao usar uma coleção de grafos para agregar todas as saídas da op de resumo, mas essa abordagem ainda teve um desempenho ruim para a eager execution e o fluxo de controle, tornando-a especialmente inadequada para o TF 2.x.
No TF 2.X
As duas metades são estreitamente integradas, e agora ops tf.summary
individuais escrevem seus dados imediatamente quando executadas. O uso da API a partir do código do seu modelo ainda deve ser familiar, mas ela funciona com a eager execution sem deixar de ser compatível com o modo grafo. A integração das duas metades da API significa que summary.FileWriter
faz parte do contexto de execução do TensorFlow e é acessado diretamente pelas ops tf.summary
, então a configuração dos escritores é o que mais parece diferente.
Exemplo de uso com a eager execution, o padrão no TF 2.x:
Exemplo de uso com a graph execution da tf.function:
Exemplo de uso com a graph execution legada do TF 1.x:
Conversão do código
A conversão do uso da tf.summary
existente para a API do TF 2.x não pode ser automatizada com confiança, então o script tf_upgrade_v2
só reescreve tudo para tf.compat.v1.summary
e não ativa os comportamentos do TF 2.x automaticamente.
Migração parcial
Para facilitar a migração ao TF 2.x para os usuários do código do modelo que ainda dependem bastante das ops de registro da API de resumo do TF 1.x, como tf.compat.v1.summary.scalar()
, é possível migrar apenas as APIs de escrita, permitindo que as ops de resumo individuais do TF 1.x dentro do código do modelo sejam totalmente migradas mais tarde.
Para dar suporte a esse estilo de migração, tf.compat.v1.summary
encaminhará automaticamente aos equivalentes do TF 2.x nas seguintes condições:
O contexto mais externo é o modo eager
Um escritor de resumo do TF 2.x padrão foi definido
Um valor não vazio de passo foi definido para o escritor (usando
tf.summary.SummaryWriter.as_default
,tf.summary.experimental.set_step
ou, alternativamente,tf.compat.v1.train.create_global_step
)
Observe que, quando a implementação de resumo do TF 2.x é invocada, o valor de retorno será um tensor bytestring vazio, para evitar a duplicação da escrita de resumo. Além disso, o encaminhamento dos argumentos de entrada é baseado em melhor esforço e nem todos os argumentos serão preservados (por exemplo, o argumento family
será compatível, enquanto collections
será removido).
Exemplo para invocar os comportamentos de tf.summary.scalar
em tf.compat.v1.summary.scalar
:
Migração completa
Para migrar totalmente para o TF 2.x, você precisará adaptar seu código da seguinte maneira:
Um escritor padrão definido por
.as_default()
precisa estar presente para usar as ops de resumoIsso significa executar ops de maneira eager ou usar ops na construção do grafo
Sem um escritor padrão, as ops de resumo se tornam no-ops silenciosas
Os escritores padrão (ainda) não propagam no limite de execução da
@tf.function
— eles só são detectados com o tracing da função — então, a prática recomendada é chamarwriter.as_default()
no corpo da função, e para garantir que o objeto do escritor continue a existir enquanto a@tf.function
estiver em uso
O valor "step" precisa ser passado a cada op pelo argumento
step
O TensorBoard exige um valor de passo para renderizar os dados como uma série temporal
A passagem explícita é necessária, porque o passo global do TF 1.x foi removido, então cada op precisa saber a variável de passo desejada para ler
Para reduzir o boilerplate, está disponível suporte experimental para registrar um valor de passo padrão como
tf.summary.experimental.set_step()
, mas essa é uma funcionalidade provisória que pode ser alterada sem aviso prévio
As assinaturas da função de ops de resumo individuais mudaram
O valor de retorno é agora um booleano (indicando se um resumo foi mesmo escrito)
O nome do segundo parâmetro (se usado) mudou de
tensor
paradata
O parâmetro
collections
foi removido: as coleções são apenas TF 1.xO parâmetro
family
foi removido. Só usetf.name_scope()
[Somente para usuários do modo grafo legado / execução da sessão]
Primeiro inicialize o escritor com
v1.Session.run(writer.init())
Use
v1.summary.all_v2_summary_ops()
para obter todas as ops de resumo do TF 2.x para o grafo atual, por exemplo, para executá-las porSession.run()
Libere o escritor com
v1.Session.run(writer.flush())
e também paraclose()
Se, em vez disso, seu código do TF 1.x usava a API tf.contrib.summary
, é muito mais parecida com a API do TF 2.x, então o script tf_upgrade_v2
automatizará a maior parte dos passos de migração (e emitirá avisos ou erros para qualquer uso que não possa ser totalmente migrado). Para grande parte, ele só reescreve as chamadas de API para tf.compat.v2.summary
, Se você só precisa de compatibilidade com o TF 2.x, pode descartar o compat.v2
e só fazer referência a tf.summary
.
Dicas adicionais
Além das áreas críticas acima, alguns aspectos auxiliares também mudaram:
A gravação condicional (como "registre a cada 100 passos") ganhou um novo visual
Para controlar as ops e o código associado, envolva-os em uma declaração if regular (que funciona no modo eager e na
@tf.function
pelo autografo) ou umatf.cond
Para controlar só os resumos, use o novo gerenciador de contexto
tf.summary.record_if()
e passe a ele a condição booleana de sua preferência.Isso substitui o padrão do TF 1.x:
Sem escrita direta de
tf.compat.v1.Graph
— em vez disso, use funções de traceA graph execution no TF 2.x usa
@tf.function
em vez do grafo explícitoNo TF 2.x, use as novas APIs de estilo tracing
tf.summary.trace_on()
etf.summary.trace_export()
para registrar grafos de função executados
Sem mais armazenamento de cache do escritor global por logdir com
tf.summary.FileWriterCache
Os usuários devem implementar os próprios objetos de escritor de armazenamento de cache/compartilhamento ou só usar escritores separados (o suporte do TensorBoard ao último está em andamento)
A representação do binário do arquivo de evento mudou
O TensorBoard 1.x já é compatível com o novo formato. Essa diferença só afeta usuários que estão processando manualmente os dados de resumo dos arquivos de evento
Os dados de resumo agora são armazenados como bytes de tensores. Você pode usar
tf.make_ndarray(event.summary.value[0].tensor)
para convertê-los para numpy