此页面由 Cloud Translation API 翻译。
Switch to English

将TensorBoard数据作为DataFrames访问

总览

TensorBoard的主要功能是其交互式GUI。但是,用户有时希望以编程方式读取TensorBoard中存储的数据日志,以进行事后分析和创建日志数据的自定义可视化等目的。

TensorBoard 2.3通过tensorboard.data.experimental.ExperimentFromDev()支持此用例。它允许以编程方式访问TensorBoard的标量日志 。此页面演示了此新API的基本用法。

建立

为了使用编程API,请确保在tensorboard旁边安装pandas

在本指南中,我们将使用matplotlibseaborn进行自定义图,但是您可以选择首选工具来分析和可视化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

将TensorBoard标量加载为pandas.DataFrame

将TensorBoard日志目录上传到TensorBoard.dev后,它就成为我们称为实验 。每个实验都有一个唯一的ID,该ID可在实验的TensorBoard.dev URL中找到。对于下面的演示,我们将在以下位置使用TensorBoard.dev实验: https ://tensorboard.dev/experiment/c1KCv3X3QvGwaXfgX1c4tg

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

dfpandas.DataFrame ,其中包含实验的所有标量日志。

DataFrame

  • run :每次运行都对应于原始logdir的子目录。在此实验中,每次运行都来自对具有给定优化器类型(训练超参数)的MNIST数据集的卷积神经网络(CNN)的完整训练。此DataFrame包含多个此类运行,它们对应于不同优化器类型下的重复训练运行。
  • tag :描述同一行中的value的含义,即该值在行中表示的度量。在此实验中,我们只有两个唯一的标记: epoch_accuracyepoch_loss用于准确性和损耗度量。
  • step :这是一个数字,它反映相应行在运行中的序列顺序。这里的step实际上是指纪元号。如果您希望获取除step值以外的时间戳,则可以在调用get_scalars()时使用关键字参数include_wall_time=True
  • value :这是实际的实际数值。如上所述,取决于行的tag ,此特定DataFrame每个value要么是损失,要么是准确性。
 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']

获取透视(宽格式)DataFrame

在我们的实验中,两个标记( epoch_lossepoch_accuracy )在每次运行中都出现在相同的一组步骤中。这样就可以通过使用get_scalars() pivot=True关键字参数直接从get_scalars()获得“宽格式” DataFrame 。宽格式的DataFrame所有标签都包含在DataFrame的列中,在某些情况下(包括该标签),使用起来更加方便。

但是,请注意,如果不满足在所有运行中跨所有标签具有统一步长值集合的条件,则使用pivot=True将导致错误。

 dfw = experiment.get_scalars(pivot=True) 
dfw
 

注意,宽格式的DataFrame包含两个标签(指标)作为其列,而不是单个“值”列: epoch_accuracyepoch_loss

将DataFrame保存为CSV

pandas.DataFrameCSV具有良好的互操作性。您可以将其存储为本地CSV文件,并稍后再加载回去。例如:

 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)
 

执行自定义可视化和统计分析

 # 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

上图显示了验证准确性和验证损失的时程。每条曲线均显示优化程序类型下5次运行的平均值。由于seaborn.lineplot()的内置功能,每条曲线还在平均值附近显示±1标准偏差,这使我们清楚地了解这些曲线的可变性以及这三种优化器类型之间差异的重要性。 TensorBoard的GUI尚不支持这种可变性的可视化。

我们想研究一个假设,即“ adam”,“ rmsprop”和“ sgd”优化器之间的最小验证损失显着不同。因此,我们提取了一个DataFrame,以在每个优化程序下获得最小的验证损失。

然后,我们制作一个箱形图以可视化最小验证损失中的差异。

 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

因此,在显着性水平为0.05时,我们的分析证实了我们的假设,即与实验中包含的其他两个优化器相比,rmsprop优化器的最小验证损失显着更高(即更差)。

总之,本教程提供了一个示例,说明如何从TensorBoard.dev中以panda.DataFrame的形式访问标量数据。它展示了您可以使用DataFrame进行的灵活而强大的分析和可视化。