![]() | ![]() | ![]() | ![]() |
import tensorflow as tf
O TensorFlow 2.0 inclui mudanças significativas na API tf.summary
usada para escrever dados resumidos para visualização no TensorBoard.
O que mudou
É útil pensar na API tf.summary
como duas sub-APIs:
- Um conjunto de operações para gravar resumos individuais -
summary.scalar()
,summary.histogram()
,summary.image()
,summary.audio()
esummary.text()
- que são chamados em linha a partir do código do modelo. - Lógica de gravação que coleta esses resumos individuais e os grava em um arquivo de registro formatado especialmente (que o TensorBoard lê para gerar visualizações).
Em TF 1.x
As duas metades tiveram que ser conectadas manualmente - obtendo as saídas de op de resumo via Session.run()
e chamando FileWriter.add_summary(output, step)
. A v1.summary.merge_all()
tornou isso mais fácil usando uma coleção de gráficos para agregar todas as saídas de v1.summary.merge_all()
resumidas, mas essa abordagem ainda funcionou mal para execução rápida e fluxo de controle, tornando-a especialmente inadequada para TF 2.0.
Em TF 2.X
As duas metades estão totalmente integradas, e agora os ops tf.summary
individuais tf.summary
seus dados imediatamente quando executados. 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. Integrar as duas metades da API significa que o summary.FileWriter
agora faz parte do contexto de execução do TensorFlow e é acessado diretamente por operações tf.summary
, portanto, configurar os tf.summary
é a parte principal que parece diferente.
Exemplo de uso com execução rápida, o padrão no TF 2.0:
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.1617793798.kokoro-gcp-ubuntu-prod-2000985207.3796.5.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.1617793799.kokoro-gcp-ubuntu-prod-2000985207.3796.1013.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.1617793799.kokoro-gcp-ubuntu-prod-2000985207.3796.1446.v2
Convertendo seu código
A conversão do uso de tf.summary
existente para a API TF 2.0 não pode ser automatizada de forma confiável, então o script tf_upgrade_v2
apenas reescreve tudo em tf.compat.v1.summary
. Para migrar para o TF 2.0, você precisará adaptar seu código da seguinte maneira:
Um gravador padrão definido via
.as_default()
deve estar presente para usar operações de resumo- 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
- Os
@tf.function
padrão (ainda) não se propagam através do limite de execução de@tf.function
- eles são detectados apenas quando a função é rastreada - então a prática recomendada é chamarwriter.as_default()
dentro do corpo da função e garantir que o objeto escritor continua a existir enquanto a função@tf.function
estiver sendo usada
O valor de "etapa" deve ser passado em cada operação por meio de um argumento de
step
- 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 o boilerplate, o suporte experimental para registrar um valor de etapa padrão está disponível como
tf.summary.experimental.set_step()
, mas esta é uma funcionalidade provisória que pode ser alterada sem aviso prévio
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 nome do parâmetro (se usado) mudou de
tensor
paradata
- O parâmetro de
collections
foi removido; coleções são TF 1.x apenas - O parâmetro da
family
foi removido; apenas usetf.name_scope()
[Apenas para usuários de modo de gráfico legado / execução de sessão]
Inicialize primeiro o gravador com
v1.Session.run(writer.init())
Use
v1.summary.all_v2_summary_ops()
para obter todas as operações de resumo do TF 2.0 para o gráfico atual, por exemplo, para executá-las viaSession.run()
Limpe o gravador com
v1.Session.run(writer.flush())
e da mesma forma paraclose()
Se seu código TF 1.x estava usando a API tf.contrib.summary
, é muito mais semelhante à API TF 2.0, então o script tf_upgrade_v2
automatizará a maioria das etapas de migração (e emitirá avisos ou erros para qualquer uso que não possa ser totalmente migrado). Na maior parte, ele apenas reescreve as chamadas de API para tf.compat.v2.summary
; se você só precisa de compatibilidade com TF 2.0+, pode descartar o 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 controlar ops e código associado, envolva-os em uma instrução if regular (que funciona no modo
@tf.function
e em@tf.function
via autógrafo ) ou umtf.cond
- Para controlar apenas resumos, use o novo gerenciador de contexto
tf.summary.record_if()
e passe a condição booleana de sua escolha Eles substituem o padrão TF 1.x:
if condition: writer.add_summary()
- Para controlar ops e código associado, envolva-os em uma instrução if regular (que funciona no modo
Sem gravação direta de
tf.compat.v1.Graph
- em vez disso, use funções de rastreamento- A execução do gráfico no TF 2.0 usa
@tf.function
vez do gráfico explícito - No TF 2.0, use as novas APIs de estilo de rastreamento
tf.summary.trace_on()
etf.summary.trace_export()
para registrar os gráficos de função executados
- A execução do gráfico no TF 2.0 usa
Não há mais armazenamento em cache de gravador global por logdir com
tf.summary.FileWriterCache
- Os usuários devem implementar seu próprio armazenamento em cache / compartilhamento de objetos de gravação ou apenas usar gravadores separados (o suporte do TensorBoard para o último está 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 em numpy