Ta strona została przetłumaczona przez Cloud Translation API.
Switch to English

Migracja użycia tf.summary do TF 2.0

Zobacz na TensorFlow.org Uruchom w Google Colab Wyświetl źródło na GitHub
import tensorflow as tf

TensorFlow 2.0 zawiera istotne zmiany w tf.summary API używanym do zapisywania danych podsumowujących do wizualizacji w TensorBoard.

Co się zmieniło

Dobrze jest myśleć o tf.summary API jako dwóch pod-API:

W TF 1.x

Dwie połówki musiały zostać ręcznie połączone ze sobą - przez pobranie podsumowania wyników FileWriter.add_summary(output, step) przez Session.run() i wywołanie FileWriter.add_summary(output, step) . Operacja v1.summary.merge_all() ułatwiła to, wykorzystując kolekcję grafów do agregacji wszystkich sumarycznych wyników v1.summary.merge_all() , ale to podejście nadal działało słabo w przypadku chętnego wykonywania i przepływu sterowania, co czyni je szczególnie nieodpowiednim dla TF 2.0.

W TF 2.X

Dwie połowy są ściśle zintegrowane, a teraz poszczególne tf.summary zapisują swoje dane natychmiast po wykonaniu. Używanie interfejsu API z kodu modelu powinno nadal wyglądać znajomo, ale teraz jest przyjazne dla gorliwego wykonywania, zachowując zgodność z trybem wykresu. Integracja obie połówki pomocą API summary.FileWriter jest obecnie częścią kontekście realizacji TensorFlow i dostaje dostępnych bezpośrednio tf.summary ops, więc konfigurowanie pisarzy jest głównym elementem, który wygląda inaczej.

Przykładowe użycie z przyspieszonym wykonywaniem, domyślne w 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.1599908770.kokoro-gcp-ubuntu-prod-1849198075.22428.5.v2

Przykładowe użycie z wykonaniem wykresu funkcji tf.:

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.1599908771.kokoro-gcp-ubuntu-prod-1849198075.22428.1013.v2

Przykładowe użycie ze starszym wykonaniem wykresu TF 1.x:

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.1599908771.kokoro-gcp-ubuntu-prod-1849198075.22428.1446.v2

Konwersja kodu

Konwersji istniejącego użycia tf.summary do interfejsu API TF 2.0 nie można w sposób niezawodny zautomatyzować, więc skrypt tf_upgrade_v2 po prostu przepisuje wszystko do tf.compat.v1.summary . Aby przejść na TF 2.0, musisz dostosować swój kod w następujący sposób:

  1. Aby można było korzystać z .as_default() musi być obecny domyślny .as_default() zapisujący ustawiony za pomocą .as_default()

    • Oznacza to chętnie wykonywanie operacji lub używanie operacji w konstrukcji grafów
    • Bez domyślnego pisarza operacje podsumowujące stają się cichymi operacjami no-op
    • Domyślne @tf.function nie są (jeszcze) propagowane przez granicę wykonywania @tf.function - są wykrywane tylko wtedy, gdy funkcja jest śledzona - dlatego najlepszą praktyką jest wywołanie writer.as_default() w treści funkcji i upewnienie się, że obiekt zapisujący istnieje tak długo, jak @tf.function jest @tf.function
  2. Wartość „step” należy przekazać do każdej operacji za pośrednictwem argumentu step

    • TensorBoard wymaga wartości kroku, aby renderować dane jako serie czasowe
    • Jawne przekazywanie jest konieczne, ponieważ globalny krok z TF 1.x został usunięty, więc każda operacja musi znać żądaną zmienną krokową do odczytania
    • Aby zredukować standardową tf.summary.experimental.set_step() dostępna jest eksperymentalna obsługa rejestrowania domyślnej wartości kroku jako tf.summary.experimental.set_step() , ale jest to tymczasowa funkcja, która może zostać zmieniona bez powiadomienia
  3. Podpisy funkcji poszczególnych operacji podsumowujących uległy zmianie

    • Wartość zwracana jest teraz wartością logiczną (wskazującą, czy podsumowanie zostało faktycznie zapisane)
    • Nazwa drugiego parametru (jeśli jest używana) została zmieniona z tensor na data
    • Parametr collections został usunięty; kolekcje są tylko TF 1.x.
    • Parametr family został usunięty; po prostu użyj tf.name_scope()
  4. [Tylko dla starszych użytkowników trybu wykresu / wykonywania sesji]

    • Najpierw zainicjuj program writer za pomocą v1.Session.run(writer.init())

    • Użyj v1.summary.all_v2_summary_ops() aby uzyskać wszystkie podsumowania operacji TF 2.0 dla bieżącego wykresu, np. Aby wykonać je przez Session.run()

    • v1.Session.run(writer.flush()) writer z v1.Session.run(writer.flush()) i podobnie dla close()

Jeśli twój kod TF 1.x zamiast tego tf.contrib.summary interfejsu API tf.contrib.summary , jest znacznie bardziej podobny do interfejsu API TF 2.0, więc skrypt tf_upgrade_v2 zautomatyzuje większość kroków migracji (i wyemituje ostrzeżenia lub błędy dla każdego użycia, którego nie można w pełni migrowane). W większości po prostu przepisuje wywołania API do tf.compat.v2.summary ; jeśli potrzebujesz tylko zgodności z TF 2.0+, możesz porzucić compat.v2 i odnieść się do niego jako tf.summary .

Dodatkowe wskazówki

Oprócz wymienionych powyżej obszarów krytycznych, niektóre aspekty pomocnicze również uległy zmianie:

  • Nagrywanie warunkowe (np. „Rejestruj co 100 kroków”) ma nowy wygląd

    • Aby sterować operacjami i związanym z nimi kodem, zawiń je w zwykłą instrukcję if (która działa w trybie @tf.function i w funkcji @tf.function poprzez autograf ) lub tf.cond
    • Aby sterować tylko podsumowaniami, użyj nowego menedżera kontekstu tf.summary.record_if() i przekaż mu wybrany przez siebie warunek logiczny
    • Zastępują one wzór TF 1.x:
if condition:
  writer.add_summary()
  • Brak bezpośredniego zapisu tf.compat.v1.Graph - zamiast tego użyj funkcji śledzenia

  • Koniec z globalnym buforowaniem zapisów na logdir z tf.summary.FileWriterCache

    • Użytkownicy powinni albo zaimplementować własne buforowanie / udostępnianie obiektów piszących, albo po prostu używać oddzielnych piszących (obsługa TensorBoard dla tych ostatnich jest w toku )
  • Reprezentacja binarna pliku zdarzeń uległa zmianie

    • TensorBoard 1.x obsługuje już nowy format; ta różnica dotyczy tylko użytkowników, którzy ręcznie analizują dane podsumowania z plików zdarzeń
    • Dane podsumowania są teraz przechowywane jako bajty tensora; możesz użyć tf.make_ndarray(event.summary.value[0].tensor) aby przekonwertować go na numpy