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

Dostęp do danych TensorBoard jako DataFrames

Przegląd

Główną cechą TensorBoard jest interaktywny graficzny interfejs użytkownika. Jednak użytkownicy czasami chcą programowo odczytać dzienniki danych przechowywane w TensorBoard w celach takich jak wykonywanie analiz post-hoc i tworzenie niestandardowych wizualizacji danych dziennika.

TensorBoard 2.3 obsługuje ten przypadek użycia za pomocą tensorboard.data.experimental.ExperimentFromDev() . Umożliwia programowy dostęp do dzienników skalarnych TensorBoard. Ta strona przedstawia podstawowe użycie tego nowego interfejsu API.

Ustawiać

Aby korzystać z programistycznego interfejsu API, zainstaluj pandas obok tensorboard .

W tym przewodniku użyjemy matplotlib i seaborn do niestandardowych wykresów, ale możesz wybrać preferowane narzędzie do analizy i wizualizacji 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

Ładowanie skalarów TensorBoard jako pandas.DataFrame

Po przesłaniu logdir TensorBoard do TensorBoard.dev staje się tym, co nazywamy eksperymentem . Każdy eksperyment ma unikalny identyfikator, który można znaleźć w adresie URL TensorBoard.dev eksperymentu. W poniższej demonstracji użyjemy eksperymentu TensorBoard.dev pod adresem : https://tensorboard.dev/experiment/c1KCv3X3QvGwaXfgX1c4tg

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

df to pandas.DataFrame który zawiera wszystkie dzienniki skalarne eksperymentu.

Kolumny DataFrame to:

  • run : każde uruchomienie odpowiada podkatalogowi oryginalnego katalogu logdir. W tym eksperymencie każdy przebieg pochodzi z pełnego uczenia konwolucyjnej sieci neuronowej (CNN) na zestawie danych MNIST z danym typem optymalizatora (hiperparametrem uczącym). Ta DataFrame zawiera wiele takich uruchomień, które odpowiadają powtarzanym przebiegom DataFrame w różnych typach optymalizatorów.
  • tag : opisuje, co oznacza value w tym samym wierszu, czyli jakie dane reprezentuje wartość w wierszu. W tym eksperymencie mamy tylko dwa unikalne tagi: epoch_accuracy i epoch_loss dla metryk dokładności i strat.
  • step : jest to liczba, która odzwierciedla kolejność kolejnych wierszy w jej przebiegu. Tutaj step faktycznie odnosi się do numeru epoki. Jeśli chcesz uzyskać sygnatury czasowe oprócz wartości step , możesz użyć argumentu słowa kluczowego include_wall_time=True podczas wywoływania get_scalars() .
  • value : jest to rzeczywista wartość liczbowa zainteresowania. Jak opisano powyżej, każda value w tej konkretnej DataFrame jest stratą lub dokładnością, w zależności od tag wiersza.
 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']

Uzyskiwanie przestawnej (szerokiej) ramki DataFrame

W naszym eksperymencie dwa znaczniki ( epoch_loss i epoch_accuracy ) występują w tym samym zestawie kroków w każdym przebiegu. Umożliwia to uzyskanie „szerokiej” DataFrame bezpośrednio z get_scalars() przy użyciu argumentu słowa kluczowego pivot=True . Szeroka DataFrame zawiera wszystkie swoje tagi jako kolumny ramki DataFrame, co jest wygodniejsze w użyciu w niektórych przypadkach, w tym w tym.

Uważaj jednak, jeśli warunek posiadania jednakowych zestawów wartości kroków we wszystkich tagach we wszystkich przebiegach nie jest spełniony, użycie pivot=True spowoduje błąd.

 dfw = experiment.get_scalars(pivot=True) 
dfw
 

Zauważ, że zamiast pojedynczej kolumny „wartość”, szeroka ramka DataFrame zawiera wyraźnie dwa znaczniki (metryki) jako swoje kolumny: epoch_accuracy i epoch_loss .

Zapisywanie DataFrame jako CSV

pandas.DataFrame ma dobrą współpracę z CSV . Możesz zapisać go jako lokalny plik CSV i załadować z powrotem później. Na przykład:

 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)
 

Wykonywanie niestandardowych wizualizacji i analiz statystycznych

 # 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

Powyższe wykresy pokazują przebiegi czasowe dokładności walidacji i utraty walidacji. Każda krzywa przedstawia średnią z 5 przebiegów w ramach typu optymalizatora. Dzięki wbudowanej funkcji seaborn.lineplot() , każda krzywa wyświetla również ± 1 odchylenie standardowe wokół średniej, co daje nam jasny obraz zmienności tych krzywych i znaczenie różnic między trzema typami optymalizatorów. Ta wizualizacja zmienności nie jest jeszcze obsługiwana w interfejsie GUI TensorBoard.

Chcemy zbadać hipotezę, że minimalna utrata walidacji różni się znacznie między optymalizatorami „adam”, „rmsprop” i „sgd”. Dlatego wyodrębniamy DataFrame dla minimalnej utraty walidacji w każdym z optymalizatorów.

Następnie wykonujemy wykres pudełkowy, aby zwizualizować różnicę w minimalnych stratach walidacyjnych.

 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

Dlatego na poziomie istotności 0,05 nasza analiza potwierdza naszą hipotezę, że minimalna utrata walidacji jest znacznie wyższa (tj. Gorsza) w optymalizatorze rmsprop w porównaniu z pozostałymi dwoma optymalizatorami uwzględnionymi w naszym eksperymencie.

Podsumowując, ten samouczek zawiera przykład, jak uzyskać dostęp do danych skalarnych jako panda.DataFrame z TensorBoard.dev. Pokazuje rodzaj elastycznych i wydajnych analiz i wizualizacji, które można wykonać za pomocą DataFrame .