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 odczytywać dzienniki danych przechowywane w TensorBoard, na przykład do wykonywania analiz post-hoc i tworzenia 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 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 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. Dzięki temu możliwe jest 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.

Należy jednak pamiętać, że jeśli warunek posiadania jednakowych zestawów wartości kroków we wszystkich znacznikach 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 wyraźny obraz zmienności tych krzywych i znaczenia różnic między trzema typami optymalizatorów. Ta wizualizacja zmienności nie jest jeszcze obsługiwana w 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 .