Se usó la API de Cloud Translation para traducir esta página.
Switch to English

Acceso a los datos de TensorBoard como DataFrames

Visión general

La característica principal de TensorBoard es su GUI interactiva. Sin embargo, los usuarios a veces quieren leer mediante programación los registros de datos almacenados en TensorBoard, para fines tales como realizar análisis post-hoc y crear visualizaciones personalizadas de los datos de registro.

TensorBoard 2.3 admite este caso de uso con tensorboard.data.experimental.ExperimentFromDev() . Permite el acceso programático a los registros escalares de TensorBoard. Esta página muestra el uso básico de esta nueva API.

Preparar

Para utilizar la API programática, asegúrese de instalar pandas junto con el tensorboard .

Usaremos matplotlib y seaborn para trazados personalizados en esta guía, pero puede elegir su herramienta preferida para analizar y visualizar DataFrame s.

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

Carga de escalares de TensorBoard como pandas.DataFrame

Una vez que un logdir de TensorBoard ha sido cargado en TensorBoard.dev, se convierte en lo que llamamos un experimento . Cada experimento tiene una ID única, que se puede encontrar en la URL de TensorBoard.dev del experimento. Para nuestra demostración a continuación, utilizaremos un experimento TensorBoard.dev en: https://tensorboard.dev/experiment/c1KCv3X3QvGwaXfgX1c4tg

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

df es un pandas.DataFrame que contiene todos los registros escalares del experimento.

Las columnas del DataFrame son:

  • run : cada ejecución corresponde a un subdirectorio del logdir original. En este experimento, cada ejecución es de un entrenamiento completo de una red neuronal convolucional (CNN) en el conjunto de datos MNIST con un tipo de optimizador dado (un hiperparámetro de entrenamiento). Este DataFrame contiene múltiples ejecuciones de este tipo, que corresponden a ejecuciones de entrenamiento repetidas bajo diferentes tipos de optimizador.
  • tag : esto describe lo que significa el value en la misma fila, es decir, qué métrica representa el valor en la fila. En este experimento, solo tenemos dos etiquetas únicas: epoch_accuracy y epoch_loss para las métricas de precisión y pérdida, respectivamente.
  • step : este es un número que refleja el orden en serie de la fila correspondiente en su ejecución. Aquí el step realidad se refiere al número de época. Si desea obtener las marcas de tiempo además de los valores de step , puede usar el argumento de palabra clave include_wall_time=True cuando llame a get_scalars() .
  • value : este es el valor numérico real de interés. Como se describió anteriormente, cada value en este DataFrame particular es una pérdida o una precisión, dependiendo de la tag de la fila.
 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']

Obteniendo un DataFrame pivotado (de formato ancho)

En nuestro experimento, las dos etiquetas ( epoch_loss y epoch_accuracy ) están presentes en el mismo conjunto de pasos en cada ejecución. Esto permite obtener un DataFrame "de formato ancho" directamente desde get_scalars() utilizando el argumento de palabra clave pivot=True . El DataFrame formato DataFrame tiene todas sus etiquetas incluidas como columnas del DataFrame, que es más conveniente para trabajar en algunos casos, incluido este.

Sin embargo, tenga en cuenta que si no se cumple la condición de tener conjuntos uniformes de valores de paso en todas las etiquetas en todas las ejecuciones, el uso de pivot=True dará como resultado un error.

 dfw = experiment.get_scalars(pivot=True) 
dfw
 

Observe que en lugar de una sola columna de "valor", el DataFrame de formato ancho incluye las dos etiquetas (métricas) como sus columnas explícitamente: epoch_accuracy y epoch_loss .

Guardar el DataFrame como CSV

pandas.DataFrame tiene buena interoperabilidad con CSV . Puede almacenarlo como un archivo CSV local y volver a cargarlo más tarde. Por ejemplo:

 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)
 

Realización de visualización personalizada y análisis estadístico.

 # 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

Las gráficas anteriores muestran los cursos de tiempo de precisión de validación y pérdida de validación. Cada curva muestra el promedio en 5 carreras bajo un tipo de optimizador. Gracias a la función incorporada de seaborn.lineplot() , cada curva también muestra ± 1 desviación estándar alrededor de la media, lo que nos da una idea clara de la variabilidad en estas curvas y la importancia de las diferencias entre los tres tipos de optimizador. Esta visualización de variabilidad aún no es compatible con la GUI de TensorBoard.

Queremos estudiar la hipótesis de que la pérdida de validación mínima difiere significativamente entre los optimizadores "adam", "rmsprop" y "sgd". Entonces extraemos un DataFrame para la pérdida mínima de validación en cada uno de los optimizadores.

Luego hacemos un diagrama de caja para visualizar la diferencia en las pérdidas mínimas de validación.

 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

Por lo tanto, a un nivel de significancia de 0.05, nuestro análisis confirma nuestra hipótesis de que la pérdida de validación mínima es significativamente mayor (es decir, peor) en el optimizador rmsprop en comparación con los otros dos optimizadores incluidos en nuestro experimento.

En resumen, este tutorial proporciona un ejemplo de cómo acceder a datos escalares como panda.DataFrame s de TensorBoard.dev. Demuestra el tipo de análisis y visualización flexibles y potentes que puede hacer con DataFrame s.