Migrazione dell'utilizzo di tf.summary a TF 2.x

Visualizza su TensorFlow.org Esegui in Google Colab Visualizza la fonte su GitHub Scarica taccuino
import tensorflow as tf

Tensorflow 2.x include modifiche significative alla tf.summary API utilizzata per i dati di riepilogo scrittura per la visualizzazione in TensorBoard.

Cosa è cambiato?

E 'utile pensare alla tf.summary API come due sotto-API:

In TF 1.x

Le due metà dovuto essere collegati insieme manualmente - recuperando le uscite sintesi op via Session.run() e chiamando FileWriter.add_summary(output, step) . Il v1.summary.merge_all() op reso questo più facile utilizzando una raccolta dati per aggregare tutte le uscite sintesi op, ma questo approccio ancora lavorato poco per l'esecuzione ansiosi e flusso di controllo, il che rende particolarmente inadatta per 2.x. TF

In TF 2.X

Le due metà sono strettamente integrati, e ora singoli tf.summary op scrivere i dati immediatamente quando viene eseguito. L'utilizzo dell'API dal codice del modello dovrebbe ancora sembrare familiare, ma ora è amichevole per l'esecuzione impaziente pur rimanendo compatibile con la modalità grafico. Integrando le due metà dei mezzi API del summary.FileWriter è ora parte del contesto di esecuzione tensorflow e viene accede direttamente tf.summary OPS, quindi configurare scrittori è la parte principale che aspetto differente.

Esempio di utilizzo con esecuzione ansiosa, l'impostazione predefinita in 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

Esempio di utilizzo con l'esecuzione del grafico 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

Esempio di utilizzo con l'esecuzione del grafico TF 1.x legacy:

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

Conversione del codice

Conversione esistente tf.summary utilizzo all'API TF 2.x non può essere attendibilmente automatizzato, in modo che il tf_upgrade_v2 sceneggiatura appena riscrive tutto a tf.compat.v1.summary . Per migrare a TF 2.x, dovrai adattare il tuo codice come segue:

  1. Un insieme writer predefinito tramite .as_default() deve essere presente per uso ops sommarie

    • Ciò significa eseguire operazioni con entusiasmo o utilizzare operazioni nella costruzione di grafici
    • Senza uno scrittore predefinito, le operazioni di riepilogo diventano no-op silenziose
    • Scrittori di default non lo fanno (ancora) si diffondono in tutto il @tf.function esecuzione di confine - vengono rilevati solo quando è tracciata la funzione - così le migliori prassi è quella di chiamare writer.as_default() all'interno del corpo della funzione, e per garantire che l'oggetto scrittore continua ad esistere fintanto che il @tf.function viene utilizzato
  2. Il valore "step" deve essere passato in ciascun op tramite il step argomento

    • TensorBoard richiede un valore di passaggio per eseguire il rendering dei dati come serie temporali
    • Il passaggio esplicito è necessario perché il passaggio globale da TF 1.x è stato rimosso, quindi ogni operazione deve conoscere la variabile di passaggio desiderata da leggere
    • Per ridurre boilerplate, supporto sperimentale per la registrazione di un valore del passo di default è disponibile come tf.summary.experimental.set_step() , ma questa è la funzionalità provvisoria che possono essere modificate senza preavviso
  3. Le firme delle funzioni delle singole operazioni di riepilogo sono cambiate

    • Il valore restituito è ora un booleano (che indica se è stato effettivamente scritto un riepilogo)
    • Il secondo nome del parametro (se utilizzato) è cambiato da tensor di data
    • Il collections parametro è stato rimosso; le raccolte sono solo TF 1.x
    • La family dei parametri è stato rimosso; solo uso tf.name_scope()
  4. [Solo per utenti in modalità grafico legacy/esecuzione sessione]

    • In primo luogo inizializzare la scrittrice con v1.Session.run(writer.init())

    • Utilizzare v1.summary.all_v2_summary_ops() per ottenere tutti ops sintesi TF 2.x per il grafico corrente, ad esempio per eseguirli tramite Session.run()

    • Lavare lo scrittore con v1.Session.run(writer.flush()) e allo stesso modo per il close()

Se il codice 1.x TF è stato invece utilizzato tf.contrib.summary API, è molto più simile alla API TF 2.x, quindi tf_upgrade_v2 script automatizzare la maggior parte dei passaggi della migrazione (ed emettere avvisi o errori per qualsiasi utilizzo che non possono essere completamente migrato). Per la maggior parte solo riscrive le chiamate API al tf.compat.v2.summary ; se avete solo bisogno di compatibilità con 2.x TF si può cadere la compat.v2 e proprio riferimento come tf.summary .

Ulteriori suggerimenti

Oltre alle criticità di cui sopra, sono cambiati anche alcuni aspetti ausiliari:

  • La registrazione condizionale (come "Registra ogni 100 passaggi") ha un nuovo aspetto

    • Per ops di controllo e codice associato, avvolgerli in un normale if (che funziona in modalità desiderosi e in @tf.function via autografo ) o un tf.cond
    • Per controllare solo sommario, utilizzare il nuovo tf.summary.record_if() direttore di contesto, e passarlo la condizione booleana di vostra scelta
    • Questi sostituiscono il modello TF 1.x:

      if condition:
        writer.add_summary()
      
  • No scrittura diretta del tf.compat.v1.Graph - invece funzioni di utilizzo in tracce

  • Non caching scrittore più globale per logdir con tf.summary.FileWriterCache

    • Gli utenti dovrebbero implementare sia la propria caching / condivisione di oggetti scrittore, o semplicemente usare scrittori separati (supporto TensorBoard per quest'ultimo è in corso )
  • La rappresentazione binaria del file evento è cambiata

    • TensorBoard 1.x supporta già il nuovo formato; questa differenza riguarda solo gli utenti che stanno analizzando manualmente i dati di riepilogo dai file di eventi
    • I dati di riepilogo sono ora archiviati come byte di tensore; è possibile utilizzare tf.make_ndarray(event.summary.value[0].tensor) per convertirlo in NumPy