Zobacz na TensorFlow.org | Uruchom w Google Colab | Wyświetl źródło na GitHub | Pobierz notatnik |
import tensorflow as tf
TensorFlow 2.x zawiera znaczące zmiany w tf.summary
API używane do zapisu danych sumarycznych do wizualizacji w TensorBoard.
Co się zmieniło
Jest to użyteczne myśleć o tf.summary
API jako dwie podgrupy API:
- Zestaw do nagrywania ops indywidualnych zestawień -
summary.scalar()
,summary.histogram()
,summary.image()
,summary.audio()
, asummary.text()
- które nazywane są inline z kodu modelu. - Pisanie logiki, która zbiera te indywidualne podsumowania i zapisuje je w specjalnie sformatowanym pliku dziennika (który następnie odczytuje TensorBoard w celu wygenerowania wizualizacji).
W TF 1.x
Obie połówki musiał ręcznie połączone ze sobą - pobierając wyjścia Podsumowanie op poprzez Session.run()
i wywołanie FileWriter.add_summary(output, step)
. v1.summary.merge_all()
op wykonane to łatwiejsze przy użyciu kolekcji wykres agregować wszystkie wyjścia podsumowanie op, ale takie podejście nadal pracował źle dla chętnych realizacji i kontroli przepływu, co czyni go szczególnie źle nadają się do TF 2.x.
W TF 2.X
Obie połówki są ściśle zintegrowane, a teraz poszczególne tf.summary
ops napisać swoje dane natychmiast po uruchomieniu. Korzystanie z interfejsu API z kodu modelu powinno nadal wyglądać znajomo, ale jest teraz przyjazne dla chętnego wykonania, zachowując jednocześnie zgodność z trybem wykresu. Integracja obu połówek 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 gorliwym wykonaniem, domyślne w 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
Przykładowe użycie z wykonaniem wykresu 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
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.1633086728.kokoro-gcp-ubuntu-prod-1386032077.31590.2.v2
Konwersja kodu
Konwersja istniejącego tf.summary
wykorzystanie API TF 2.x nie można wiarygodnie zautomatyzowany, więc tf_upgrade_v2
skrypt po prostu przepisuje to wszystko tf.compat.v1.summary
. Aby przeprowadzić migrację do TF 2.x, musisz dostosować swój kod w następujący sposób:
Zestaw domyślny pisarz poprzez
.as_default()
musi być obecny w użyciu ops podsumowania- Oznacza to gorliwe wykonywanie operacji lub używanie operacji do tworzenia grafów
- Bez domyślnego programu piszącego operacje podsumowania stają się cichymi operacjami bez operacji
- Domyślne pisarze nie (jeszcze) propaguje się przez
@tf.function
granicy wykonania - są wykrywane tylko wtedy, gdy funkcja jest drogi - więc najlepszym rozwiązaniem jest zadzwonićwriter.as_default()
wewnątrz ciała funkcji, oraz w celu zapewnienia, że przedmiot pisarz nadal istnieje tak długo, jak@tf.function
jest używany
Wartość „krok” muszą być przekazywane do każdego op poprzez
step
argumentu- TensorBoard wymaga wartości kroku, aby renderować dane jako szereg czasowy
- Jawne przekazywanie jest konieczne, ponieważ globalny krok z TF 1.x został usunięty, więc każda operacja musi znać żądaną zmienną kroku do odczytu
- Aby zmniejszyć boilerplate, eksperymentalne wsparcie dla rejestracji wartość domyślna krokiem jest dostępny jako
tf.summary.experimental.set_step()
, ale jest to tymczasowe funkcje, które mogą ulec zmianie bez uprzedzenia
Zmieniły się sygnatury funkcji poszczególnych operacji podsumowujących
- Wartość zwracana jest teraz wartością logiczną (wskazującą, czy podsumowanie zostało rzeczywiście napisane)
- Druga nazwa parametru (jeśli jest używany) został zmieniony z
tensor
dodata
-
collections
parametr został usunięty; kolekcje są tylko TF 1.x -
family
parametrów zostały usunięte; Wystarczy użyćtf.name_scope()
[Tylko dla starszych użytkowników trybu wykresu / wykonywania sesji]
Najpierw zainicjować pisarz
v1.Session.run(writer.init())
Stosować
v1.summary.all_v2_summary_ops()
, aby uzyskać wszystkie ops podsumowania TF 2.x dla bieżącego wykresu, na przykład, aby wykonać je za pomocąSession.run()
Przepłukać pisarz
v1.Session.run(writer.flush())
, a także doclose()
Jeśli TF Kod 1.x został zamiast korzystania tf.contrib.summary
API, jest dużo bardziej podobny do interfejsu API TF 2.x, więc tf_upgrade_v2
skrypt zautomatyzować większość kroków migracji (i emituje ostrzeżenia lub błędy do dowolnego użytku, które nie mogą być w pełni migrowane). W większości przypadków po prostu przepisuje wywołań API do tf.compat.v2.summary
; Jeśli potrzebujesz tylko zgodność z TF 2.x można upuścić compat.v2
i po prostu odwołać go jako tf.summary
.
Dodatkowe wskazówki
Oprócz krytycznych obszarów powyżej, niektóre aspekty pomocnicze również uległy zmianie:
Nagrywanie warunkowe (np. „rejestruj co 100 kroków”) ma nowy wygląd
- Do OPS kontrolnych oraz towarzyszącym kodu, zawinąć je w regularne if (który działa w trybie chętny iw
@tf.function
poprzez autografem ) lubtf.cond
- Aby sterować tylko podsumowania, należy użyć nowego
tf.summary.record_if()
menedżera kontekstowe, i przekazać mu logiczną stan swojego wyboru Zastępują one wzorzec TF 1.x:
if condition: writer.add_summary()
- Do OPS kontrolnych oraz towarzyszącym kodu, zawinąć je w regularne if (który działa w trybie chętny iw
Brak bezpośredniego pisanie
tf.compat.v1.Graph
- zamiast funkcje użycie śladowych- Wykres wykonanie w zastosowaniach TF 2.x
@tf.function
zamiast wyraźnej Graph - W TF 2.x, należy użyć nowego API śledzenie stylu
tf.summary.trace_on()
itf.summary.trace_export()
, aby nagrywać wykonywane wykresy funkcji
- Wykres wykonanie w zastosowaniach TF 2.x
Nie bardziej globalny pisarz buforowanie za logdir z
tf.summary.FileWriterCache
- Użytkownicy powinni też wdrożyć własne buforowanie / dzielenie obiektów pisarz, lub po prostu używać osobnych pisarzy (wsparcie TensorBoard za ten ostatni jest w toku )
Zmieniła się binarna reprezentacja pliku zdarzeń
- TensorBoard 1.x obsługuje już nowy format; ta różnica dotyczy tylko użytkowników, którzy ręcznie analizują dane podsumowujące z plików zdarzeń
- Dane podsumowujące są teraz przechowywane jako bajty tensorowe; można użyć
tf.make_ndarray(event.summary.value[0].tensor)
, aby przekształcić go numpy