Diese Seite wurde von der Cloud Translation API übersetzt.
Switch to English

Zugriff auf TensorBoard-Daten als DataFrames

Überblick

Das Hauptmerkmal von TensorBoard ist die interaktive Benutzeroberfläche. Manchmal möchten Benutzer jedoch die in TensorBoard gespeicherten Datenprotokolle programmgesteuert lesen, um beispielsweise Post-hoc-Analysen durchzuführen und benutzerdefinierte Visualisierungen der Protokolldaten zu erstellen.

TensorBoard 2.3 unterstützt diesen Anwendungsfall mit tensorboard.data.experimental.ExperimentFromDev() . Es ermöglicht den programmgesteuerten Zugriff auf die skalaren Protokolle von TensorBoard. Diese Seite zeigt die grundlegende Verwendung dieser neuen API.

Konfiguration

Um die programmatische API zu verwenden, müssen Sie pandas neben tensorboard installieren.

In diesem Handbuch werden matplotlib und seaborn für benutzerdefinierte Diagramme verwendet. Sie können jedoch Ihr bevorzugtes Tool zur Analyse und Visualisierung von DataFrame .

pip install tensorboard pandas
pip install matplotlib seaborn
 from packaging import version

import pandas as pd
from matplotlib import pyplot as plt
import seaborn as sns
from scipy import stats
import tensorboard as tb
 
 major_ver, minor_ver, _ = version.parse(tb.__version__).release
assert major_ver >= 2 and minor_ver >= 3, \
    "This notebook requires TensorBoard 2.3 or later."
print("TensorBoard version: ", tb.__version__)
 
TensorBoard version:  2.3.0a20200626

Laden von TensorBoard-Skalaren als pandas.DataFrame

Sobald ein TensorBoard-Protokollverzeichnis auf TensorBoard.dev hochgeladen wurde, wird es zu einem Experiment . Jedes Experiment hat eine eindeutige ID, die in der URL TensorBoard.dev des Experiments zu finden ist. Für unsere Demonstration unten verwenden wir ein TensorBoard.dev-Experiment unter: https://tensorboard.dev/experiment/c1KCv3X3QvGwaXfgX1c4tg

 experiment_id = "c1KCv3X3QvGwaXfgX1c4tg"
experiment = tb.data.experimental.ExperimentFromDev(experiment_id)
df = experiment.get_scalars()
df
 

df ist ein pandas.DataFrame , der alle skalaren Protokolle des Experiments enthält.

Die Spalten des DataFrame sind:

  • run : Jeder Lauf entspricht einem Unterverzeichnis des ursprünglichen Protokollverzeichnisses. In diesem Experiment stammt jeder Lauf aus einem vollständigen Training eines Faltungs-Neuronalen Netzwerks (CNN) im MNIST-Datensatz mit einem bestimmten Optimierertyp (einem Trainingshyperparameter). Dieser DataFrame enthält mehrere solcher Läufe, die wiederholten Trainingsläufen unter verschiedenen Optimierertypen entsprechen.
  • tag : Hier wird beschrieben, was der value in derselben Zeile bedeutet, dh welche Metrik der Wert in der Zeile darstellt. In diesem Experiment haben wir nur zwei eindeutige Tags: epoch_accuracy und epoch_loss für die Genauigkeits- bzw. Verlustmetrik.
  • step : Dies ist eine Zahl, die die Serienreihenfolge der entsprechenden Zeile in ihrem Lauf widerspiegelt. Hier bezieht sich step tatsächlich auf die Epochennummer. Wenn Sie die Zeitstempel zusätzlich zu den step include_wall_time=True , können Sie beim Aufruf von get_scalars() das Schlüsselwortargument include_wall_time=True .
  • value : Dies ist der tatsächliche numerische Wert von Interesse. Wie oben beschrieben, ist jeder value in diesem bestimmten DataFrame je nach tag der Zeile entweder ein Verlust oder eine Genauigkeit.
 print(df["run"].unique())
print(df["tag"].unique())
 
['adam,run_1/train' 'adam,run_1/validation' 'adam,run_2/train'
 'adam,run_2/validation' 'adam,run_3/train' 'adam,run_3/validation'
 'adam,run_4/train' 'adam,run_4/validation' 'adam,run_5/train'
 'adam,run_5/validation' 'rmsprop,run_1/train' 'rmsprop,run_1/validation'
 'rmsprop,run_2/train' 'rmsprop,run_2/validation' 'rmsprop,run_3/train'
 'rmsprop,run_3/validation' 'rmsprop,run_4/train'
 'rmsprop,run_4/validation' 'rmsprop,run_5/train'
 'rmsprop,run_5/validation' 'sgd,run_1/train' 'sgd,run_1/validation'
 'sgd,run_2/train' 'sgd,run_2/validation' 'sgd,run_3/train'
 'sgd,run_3/validation' 'sgd,run_4/train' 'sgd,run_4/validation'
 'sgd,run_5/train' 'sgd,run_5/validation']
['epoch_accuracy' 'epoch_loss']

Abrufen eines schwenkbaren (breitformigen) DataFrame

In unserem Experiment sind die beiden Tags ( epoch_loss und epoch_accuracy ) in jedem Lauf in denselben Schritten vorhanden. Dies ermöglicht es, einen "Wide-Form" DataFrame direkt von get_scalars() indem das Schlüsselwortargument pivot=True . Der Wide-Form- DataFrame enthält alle Tags als Spalten des DataFrame, was in einigen Fällen, einschließlich dieses, bequemer ist.

Beachten Sie jedoch, dass die Verwendung von pivot=True zu einem Fehler führt, wenn die Bedingung, dass in allen Läufen einheitliche Sätze von Schrittwerten für alle Tags vorhanden sind, nicht erfüllt ist.

 dfw = experiment.get_scalars(pivot=True) 
dfw
 

Beachten Sie, dass der Wide-Form-DataFrame anstelle einer einzelnen "Wert" -Spalte explizit die beiden Tags (Metriken) als Spalten enthält: epoch_accuracy und epoch_loss .

Speichern des DataFrame als CSV

pandas.DataFrame ist gut mit CSV pandas.DataFrame . Sie können es als lokale CSV-Datei speichern und später wieder laden. Beispielsweise:

 csv_path = '/tmp/tb_experiment_1.csv'
dfw.to_csv(csv_path, index=False)
dfw_roundtrip = pd.read_csv(csv_path)
pd.testing.assert_frame_equal(dfw_roundtrip, dfw)
 

Durchführen einer benutzerdefinierten Visualisierung und statistischen Analyse

 # Filter the DataFrame to only validation data, which is what the subsequent
# analyses and visualization will be focused on.
dfw_validation = dfw[dfw.run.str.endswith("/validation")]
# Get the optimizer value for each row of the validation DataFrame.
optimizer_validation = dfw_validation.run.apply(lambda run: run.split(",")[0])

plt.figure(figsize=(16, 6))
plt.subplot(1, 2, 1)
sns.lineplot(data=dfw_validation, x="step", y="epoch_accuracy",
             hue=optimizer_validation).set_title("accuracy")
plt.subplot(1, 2, 2)
sns.lineplot(data=dfw_validation, x="step", y="epoch_loss",
             hue=optimizer_validation).set_title("loss")
 
Text(0.5, 1.0, 'loss')

png

Die obigen Diagramme zeigen die Zeitverläufe der Validierungsgenauigkeit und des Validierungsverlusts. Jede Kurve zeigt den Durchschnitt über 5 Läufe unter einem Optimierertyp. Dank einer integrierten Funktion von seaborn.lineplot() zeigt jede Kurve auch ± 1 Standardabweichung um den Mittelwert an, was uns ein klares Gefühl für die Variabilität dieser Kurven und die Bedeutung der Unterschiede zwischen den drei Optimierertypen gibt. Diese Visualisierung der Variabilität wird in der GUI von TensorBoard noch nicht unterstützt.

Wir wollen die Hypothese untersuchen, dass sich der minimale Validierungsverlust zwischen den Optimierern "adam", "rmsprop" und "sgd" signifikant unterscheidet. Daher extrahieren wir einen DataFrame für den minimalen Validierungsverlust unter jedem der Optimierer.

Dann machen wir ein Boxplot, um den Unterschied in den minimalen Validierungsverlusten zu visualisieren.

 adam_min_val_loss = dfw_validation.loc[optimizer_validation=="adam", :].groupby(
    "run", as_index=False).agg({"epoch_loss": "min"})
rmsprop_min_val_loss = dfw_validation.loc[optimizer_validation=="rmsprop", :].groupby(
    "run", as_index=False).agg({"epoch_loss": "min"})
sgd_min_val_loss = dfw_validation.loc[optimizer_validation=="sgd", :].groupby(
    "run", as_index=False).agg({"epoch_loss": "min"})
min_val_loss = pd.concat([adam_min_val_loss, rmsprop_min_val_loss, sgd_min_val_loss])

sns.boxplot(data=min_val_loss, y="epoch_loss",
            x=min_val_loss.run.apply(lambda run: run.split(",")[0]))
 
<matplotlib.axes._subplots.AxesSubplot at 0x7f5e017c8150>

png

 # Perform pairwise comparisons between the minimum validation losses
# from the three optimizers.
_, p_adam_vs_rmsprop = stats.ttest_ind(
    adam_min_val_loss["epoch_loss"],
    rmsprop_min_val_loss["epoch_loss"]) 
_, p_adam_vs_sgd = stats.ttest_ind(
    adam_min_val_loss["epoch_loss"],
    sgd_min_val_loss["epoch_loss"]) 
_, p_rmsprop_vs_sgd = stats.ttest_ind(
    rmsprop_min_val_loss["epoch_loss"],
    sgd_min_val_loss["epoch_loss"]) 
print("adam vs. rmsprop: p = %.4f" % p_adam_vs_rmsprop)
print("adam vs. sgd: p = %.4f" % p_adam_vs_sgd)
print("rmsprop vs. sgd: p = %.4f" % p_rmsprop_vs_sgd)
 
adam vs. rmsprop: p = 0.0244
adam vs. sgd: p = 0.9749
rmsprop vs. sgd: p = 0.0135

Daher bestätigt unsere Analyse bei einem Signifikanzniveau von 0,05 unsere Hypothese, dass der minimale Validierungsverlust im rmsprop-Optimierer im Vergleich zu den beiden anderen in unserem Experiment enthaltenen Optimierern signifikant höher (dh schlechter) ist.

Zusammenfassend bietet dieses Tutorial ein Beispiel für den Zugriff auf skalare Daten als panda.DataFrame s von TensorBoard.dev. Es zeigt die Art von flexiblen und leistungsstarken Analysen und Visualisierungen, die Sie mit den DataFrame .