Migración del uso de tf.summary a TF 2.x

Ver en TensorFlow.org Ejecutar en Google Colab Ver fuente en GitHub Descargar cuaderno
import tensorflow as tf

TensorFlow 2.x incluye cambios significativos en el tf.summary API se utiliza para escribir los datos de resumen para la visualización en TensorBoard.

Que ha cambiado

Es útil pensar en la tf.summary API como dos sub-API:

  • Un conjunto de operaciones para el registro de los resúmenes individuales - summary.scalar() , summary.histogram() , summary.image() , summary.audio() , y summary.text() - que se llama línea de su código de modelo.
  • Lógica de escritura que recopila estos resúmenes individuales y los escribe en un archivo de registro con formato especial (que luego TensorBoard lee para generar visualizaciones).

En TF 1.x

Las dos mitades tenido que ser conectados manualmente juntos - por ir a buscar las salidas Resumen op través Session.run() y llamar a FileWriter.add_summary(output, step) . El v1.summary.merge_all() op hace esto más fácil mediante el uso de una colección gráfica de agregar todas las salidas Resumen op, pero este enfoque todavía funcionaba mal para la ejecución ansiosos y flujo de control, lo que es especialmente mal adaptado para 2.x. TF

En TF 2.X

Las dos mitades están estrechamente integrados, y ahora individuales tf.summary ops escriben sus datos inmediatamente cuando se ejecuta. El uso de la API desde el código de su modelo aún debería parecer familiar, pero ahora es fácil de ejecutar con entusiasmo sin dejar de ser compatible con el modo gráfico. La integración de las dos mitades de los medios de API del summary.FileWriter es ahora parte del contexto de ejecución TensorFlow y se accede directamente por tf.summary operaciones, por lo que la configuración de los escritores es la parte principal que se ve diferente.

Ejemplo de uso con ejecución ávida, el valor predeterminado en 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.1633086727.kokoro-gcp-ubuntu-prod-1386032077.31590.0.v2

Ejemplo de uso con la ejecución del 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.1633086728.kokoro-gcp-ubuntu-prod-1386032077.31590.1.v2

Ejemplo de uso con ejecución de gráficos TF 1.x heredada:

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.1633086728.kokoro-gcp-ubuntu-prod-1386032077.31590.2.v2

Convirtiendo tu código

La conversión existente tf.summary el uso de la API de TF 2.x no puede ser fiable automatizado, por lo que el tf_upgrade_v2 guión simplemente reescribe todo a tf.compat.v1.summary . Para migrar a TF 2.x, deberá adaptar su código de la siguiente manera:

  1. Un conjunto escritor predeterminado a través de .as_default() debe estar presente para el uso de operaciones de resumen

    • Esto significa ejecutar operaciones con entusiasmo o usar operaciones en la construcción de gráficos.
    • Sin un escritor predeterminado, las operaciones de resumen se convierten en no operaciones silenciosas
    • Escritores por defecto no lo hacen (aún) se propagan a través de la @tf.function límite de ejecución - que sólo se detectan cuando se traza la función - por lo que la mejor práctica es llamar writer.as_default() dentro del cuerpo de la función, y para asegurar que el objeto escritor continúa existiendo siempre que el @tf.function está siendo utilizado
  2. El valor de "paso" se debe pasar en cada OP a través de un el step argumento

    • TensorBoard requiere un valor de paso para representar los datos como una serie de tiempo
    • El paso explícito es necesario porque el paso global de TF 1.x se ha eliminado, por lo que cada operación debe conocer la variable de paso deseada para leer
    • Para reducir repetitivo, soporte experimental para registrar un valor de paso por defecto está disponible como tf.summary.experimental.set_step() , pero esta es la funcionalidad provisional que se puede cambiar sin previo aviso
  3. Las firmas de funciones de operaciones sumarias individuales han cambiado

    • El valor de retorno ahora es un booleano (que indica si realmente se escribió un resumen)
    • El segundo nombre de parámetro (si se utiliza) ha cambiado de tensor de data
    • La collections parámetro se ha eliminado; las colecciones son solo TF 1.x
    • La family parámetro se ha eliminado; solo uso tf.name_scope()
  4. [Solo para usuarios de ejecución de sesión / modo de gráfico heredado]

    • En primer lugar inicializar el escritor con v1.Session.run(writer.init())

    • Use v1.summary.all_v2_summary_ops() para obtener todas las operaciones de resumen TF 2.x para el gráfico actual, por ejemplo, para ejecutarlos a través de Session.run()

    • Enjuague el escritor con v1.Session.run(writer.flush()) y lo mismo para close()

Si el código 1.x TF se usa en lugar tf.contrib.summary API, que es mucho más similar a la API TF 2.x, por lo tf_upgrade_v2 script automatizar la mayoría de los pasos de migración (y emiten advertencias o errores para cualquier uso que no puede ser migrado por completo). En su mayor parte sólo se reescribe las llamadas a la API a tf.compat.v2.summary ; si sólo se necesita compatibilidad con 2.x TF puede caer el compat.v2 y simplemente hacer referencia a ella como tf.summary .

Consejos adicionales

Además de las áreas críticas anteriores, también han cambiado algunos aspectos auxiliares:

  • La grabación condicional (como "registrar cada 100 pasos") tiene un nuevo aspecto

    • Para operaciones de control y código asociado, envolverlos en una declaración regular si (que funciona en modo ansiosos y en @tf.function a través de autógrafos ) o un tf.cond
    • Para controlar los sumarios solo, utilice la nueva tf.summary.record_if() gestor de contexto, y pasarlo al estado booleano de su elección
    • Estos reemplazan el patrón TF 1.x:

      if condition:
        writer.add_summary()
      
  • Ninguna escritura directa de tf.compat.v1.Graph - en vez funciones de uso traza

  • Sin almacenamiento en caché escritor más global por logdir con tf.summary.FileWriterCache

    • Los usuarios deben implementar ya sea su propio almacenamiento en caché / intercambio de objetos de escritor, o simplemente utilizan los escritores independientes (apoyo TensorBoard para el último es en curso )
  • La representación binaria del archivo de eventos ha cambiado

    • TensorBoard 1.x ya es compatible con el nuevo formato; esta diferencia solo afecta a los usuarios que analizan manualmente datos de resumen de archivos de eventos
    • Los datos de resumen ahora se almacenan como bytes de tensor; puede utilizar tf.make_ndarray(event.summary.value[0].tensor) para convertirlo en numpy