Migrando o uso de tf.summary para TF 2.x

Ver no TensorFlow.org Executar no Google Colab Ver fonte no GitHub Baixar caderno
import tensorflow as tf

TensorFlow 2.x inclui mudanças significativas para o tf.summary API usado para dados de resumo de gravação para visualização em TensorBoard.

O que mudou

É útil pensar no tf.summary API como dois sub-APIs:

Em TF 1.x

As duas metades tiveram de ser ligado manualmente juntos - por buscar as saídas op resumo via Session.run() e chamando FileWriter.add_summary(output, step) . O v1.summary.merge_all() op feito isso mais fácil usando uma coleção gráfico para agregar todas as saídas op resumo, mas esta abordagem ainda funcionou mal para execução ansioso e fluxo de controle, tornando-se especialmente mal adequado para TF 2.x.

Em TF 2.X

As duas metades são totalmente integrados, e agora individuais tf.summary ops escrever seus dados imediatamente quando executado. Usar a API do código do seu modelo ainda deve parecer familiar, mas agora é amigável para execução rápida enquanto permanece compatível com o modo gráfico. Integrando as duas metades dos meios de API do summary.FileWriter agora faz parte do contexto de execução TensorFlow e é acessado diretamente pelo tf.summary ops, assim configurando escritores é a parte principal que parece diferente.

Exemplo de uso com execução rápida, o padrão no TF 2.x:

writer = tf.summary.create_file_writer("/tmp/mylogs/eager")

with writer.as_default():
  for step in range(100):
    # other model code would go here
    tf.summary.scalar("my_metric", 0.5, step=step)
    writer.flush()
ls /tmp/mylogs/eager
events.out.tfevents.1631963355.kokoro-gcp-ubuntu-prod-1653899854.8066.0.v2

Exemplo de uso com execução de gráfico tf.function:

writer = tf.summary.create_file_writer("/tmp/mylogs/tf_function")

@tf.function
def my_func(step):
  with writer.as_default():
    # other model code would go here
    tf.summary.scalar("my_metric", 0.5, step=step)

for step in tf.range(100, dtype=tf.int64):
  my_func(step)
  writer.flush()
ls /tmp/mylogs/tf_function
events.out.tfevents.1631963355.kokoro-gcp-ubuntu-prod-1653899854.8066.1.v2

Exemplo de uso com execução de gráfico TF 1.x legado:

g = tf.compat.v1.Graph()
with g.as_default():
  step = tf.Variable(0, dtype=tf.int64)
  step_update = step.assign_add(1)
  writer = tf.summary.create_file_writer("/tmp/mylogs/session")
  with writer.as_default():
    tf.summary.scalar("my_metric", 0.5, step=step)
  all_summary_ops = tf.compat.v1.summary.all_v2_summary_ops()
  writer_flush = writer.flush()


with tf.compat.v1.Session(graph=g) as sess:
  sess.run([writer.init(), step.initializer])

  for i in range(100):
    sess.run(all_summary_ops)
    sess.run(step_update)
    sess.run(writer_flush)
ls /tmp/mylogs/session
events.out.tfevents.1631963356.kokoro-gcp-ubuntu-prod-1653899854.8066.2.v2

Convertendo seu código

Convertendo existente tf.summary uso da API TF 2.x não pode ser confiavelmente automatizado, assim que o tf_upgrade_v2 roteiro apenas reescreve tudo para tf.compat.v1.summary . Para migrar para o TF 2.x, você precisará adaptar seu código da seguinte maneira:

  1. Um conjunto escritor default via .as_default() deve estar presente para uso ops sumárias

    • Isso significa executar ops avidamente ou usar ops na construção de gráficos
    • Sem um gravador padrão, as operações de resumo tornam-se silenciosas
    • Escritores padrão não (ainda) propagam-se através do @tf.function limite de execução - eles só são detectados quando a função é rastreada - para a melhor prática é chamar writer.as_default() dentro do corpo da função, e para garantir que o objeto escritor continua a existir enquanto o @tf.function está sendo usado
  2. O valor "passo" deve ser passado para cada op através de um o step argumento

    • TensorBoard requer um valor de etapa para renderizar os dados como uma série temporal
    • A passagem explícita é necessária porque a etapa global do TF 1.x foi removida, então cada op deve saber a variável de etapa desejada para ler
    • Para reduzir clichê, suporte experimental para registrar um valor etapa padrão está disponível como tf.summary.experimental.set_step() , mas esta é a funcionalidade provisória que pode ser alterada sem aviso prévio
  3. As assinaturas de funções de operações de resumo individuais foram alteradas

    • O valor de retorno agora é um booleano (indicando se um resumo foi realmente escrito)
    • O segundo parâmetro de nome (se usado) foi alterado de tensor de data
    • O collections parâmetro foi removido; as coleções são apenas TF 1.x
    • A family parâmetro foi removido; apenas uso tf.name_scope()
  4. [Apenas para usuários de modo de gráfico legado / execução de sessão]

    • Primeiro inicializar o escritor com v1.Session.run(writer.init())

    • Use v1.summary.all_v2_summary_ops() para obter todos os ops sumárias TF 2.x para o gráfico atual, por exemplo, para executá-los via Session.run()

    • Lave o escritor com v1.Session.run(writer.flush()) e também para close()

Se o seu código 1.x TF foi em vez de usar tf.contrib.summary API, é muito mais parecida com a API TF 2.x, então tf_upgrade_v2 script irá automatizar a maioria das etapas de migração (e emitem avisos ou erros para qualquer uso que não pode ser totalmente migrado). Para a maior parte apenas reescreve as chamadas de API para tf.compat.v2.summary ; Se você só precisa de compatibilidade com TF 2.x você pode soltar a compat.v2 e apenas referenciá-lo como tf.summary .

Dicas adicionais

Além das áreas críticas acima, alguns aspectos auxiliares também mudaram:

  • A gravação condicional (como "registrar a cada 100 etapas") tem uma nova aparência

    • Para ops controle e código associado, envolvê-los em um regular if (que funciona no modo ansioso e em @tf.function via autógrafo ) ou um tf.cond
    • Para controlar apenas resumos, usar o novo tf.summary.record_if() gerente de contexto, e passá-lo a condição boolean de sua escolha
    • Eles substituem o padrão TF 1.x:

      if condition:
        writer.add_summary()
      
  • Sem escrita direta de tf.compat.v1.Graph - em vez funções uso de rastreamento

  • Sem cache escritor mais global per logdir com tf.summary.FileWriterCache

    • Os usuários devem quer implementar seu próprio cache / compartilhamento de objetos escritor, ou simplesmente usar escritores independentes (suporte TensorBoard para o último é em andamento )
  • A representação binária do arquivo de evento mudou

    • O TensorBoard 1.x já oferece suporte ao novo formato; esta diferença afeta apenas os usuários que estão analisando manualmente os dados de resumo dos arquivos de eventos
    • Os dados de resumo agora são armazenados como bytes de tensor; você pode usar tf.make_ndarray(event.summary.value[0].tensor) para convertê-lo para numpy