גישה לנתוני TensorBoard כמסגרות נתונים

סקירה כללית

המאפיין העיקרי של TensorBoard הוא ה- GUI האינטראקטיבי שלו. עם זאת, משתמשים לפעמים רוצה לקרוא את יומני נתונים תוכניתי מאוחסן TensorBoard, למטרות כגון ביצוע פוסט-הוק ניתוחים ויצירת חזותיים מותאמים אישית של נתוני יומן.

TensorBoard 2.3 תומך מקרה השימוש הזה עם tensorboard.data.experimental.ExperimentFromDev() . זה מאפשר גישה תוכניתית של TensorBoard יומני סקלר . דף זה מדגים את השימוש הבסיסי של ה- API החדש הזה.

להכין

כדי להשתמש ב- API התכנותי, הקפד להתקין pandas לצד tensorboard .

נשתמש matplotlib ו seaborn עבור חלקות מנהג במדריך זה, אבל אתה יכול לבחור הכלי המועדף שלך כדי לנתח ולהציג 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

טוען scalars TensorBoard בתור pandas.DataFrame

פעם logdir TensorBoard הועלתה TensorBoard.dev, הוא הופך להיות מה שאנחנו מכנים כניסוי. לכל ניסוי יש מזהה ייחודי, אותו ניתן למצוא בכתובת ה- TensorBoard.dev של הניסוי. להדגמה שלנו להלן, נשתמש בניסוי TensorBoard.dev ב: https://tensorboard.dev/experiment/c1KCv3X3QvGwaXfgX1c4tg

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

df הוא pandas.DataFrame המכיל את כל יומני סקלר של הניסוי.

עמודי DataFrame הם:

  • run : כל אחד מהם מקביל ריצה בספריית משנה של logdir המקורי. בניסוי זה, כל ריצה היא מתוך אימון מלא של רשת עצבית מתפתחת (CNN) במערך הנתונים של MNIST עם סוג נתון אופטימיזציה נתון (היפרפרמטר אימון). זה DataFrame מכיל ריצות מרובות כגון, אשר מתאימות ריצות אימונים חוזרים ונשנים תחת סוגים שונים האופטימיזציה.
  • tag : זה מתאר מה value באותו האמצעי בשורה, כי הוא, מה מטר הערך מייצג בשורה. בניסוי זה, יש לנו רק שני תגים ייחודיים: epoch_accuracy ו epoch_loss עבור מדדי הדיוק ואובדן בהתאמה.
  • step : זהו מספר שמשקף את סדר סדרתי של השורה המתאימה הריצה שלה. הנה step בעצם מתייחס למספר עידן. אם ברצונך לקבל את חותמות זמן נוסף על step ערכים, אתה יכול להשתמש בטיעון מילת include_wall_time=True כאשר קוראים get_scalars() .
  • value : זהו הערך המספרי האמיתי של עניין. כפי שתואר לעיל, כל value בפרט זה DataFrame הוא או הפסד או דיוק, תלוי tag של השורה.
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_loss ו epoch_accuracy ) נוכחים באותו סט של צעדים בכל ריצה. זה מאפשר לקבל "רחב-טופס" DataFrame ישירות get_scalars() על ידי שימוש pivot=True טיעון מילות מפתח. מנהל-טופס DataFrame יש כל התגים שלה כלול עמודות של DataFrame, וזה יותר נוח לעבוד עם ובמקרים מסוימים כולל זו הנוכחית.

עם זאת, צריך להיזהר כי אם התנאי של החזקת מכשירים אחידים של ערכי צעד בכול תגיות בכול ריצות לא נפגש, באמצעות pivot=True תגרום לשגיאה.

dfw = experiment.get_scalars(pivot=True) 
dfw

שים לב כי במקום טור "ערך" יחיד, DataFrame הרחב-הטופס כולל שני תגים (מדדים) כעמוד שלה במפורש: epoch_accuracy ו epoch_loss .

שמירת ה- DataFrame כ- CSV

pandas.DataFrame יש יכולת פעולה הדדית טובה עם CSV . אתה יכול לאחסן אותו כקובץ 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 סטיית התקן סביב הממוצע, אשר נותן לנו תחושה ברורה של השתנות עקומות אלה ואת המשמעות של ההבדלים בין סוגי האופטימיזציה שלוש. הדמיה זו של השתנות עדיין אינה נתמכת ב- GUI של TensorBoard.

ברצוננו ללמוד את ההשערה כי אובדן האימות המינימלי שונה באופן משמעותי בין ה"אדם "," 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 בהשוואה לשני האופטימיזורים האחרים הכלולים בניסוי שלנו.

לסיכום, הדרכה זו מדגימה כיצד לגשת לנתונים סקלר כמו panda.DataFrame ים מ TensorBoard.dev. זה מדגים את סוג של ניתוחים גמישים ורבי עוצמה להדמיה אתה יכול לעשות עם DataFrame ים.