דף זה תורגם על ידי Cloud Translation API.
Switch to English

ניפוי באגים בספרות בתוכניות TensorFlow באמצעות TensorBoard Debugger V2

אירועים קטסטרופלים בהם מעורבים NaN יכולים לעיתים להתרחש במהלך תוכנית TensorFlow, ולכבול את תהליכי האימון של המודל. סיבת השורש לאירועים כאלה לעיתים קרובות מעורפלת, במיוחד עבור דגמים בגודל ומורכבות לא טריוויאליים. כדי להקל על ניפוי באגים מסוג זה, TensorBoard 2.3+ (יחד עם TensorFlow 2.3+) מספק לוח מחוונים ייעודי בשם Debugger V2. כאן אנו מדגימים כיצד להשתמש בכלי זה על ידי עבודה דרך באג אמיתי שמעורב NaNs ברשת עצבית שנכתבה ב- TensorFlow.

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

התבוננות בבאג

קוד המקור של תוכנית TF2 שנבצע איתור באגים זמין ב- GitHub . התוכנית לדוגמה נארזת גם בחבילת צינור הצינור tensor (גרסה 2.3+) וניתן להפעיל אותה על ידי:

 python -m tensorflow.python.debug.examples.v2.debug_mnist_v2
 

תוכנית TF2 זו יוצרת תפיסה רב שכבתית (MLP) ומכשירה אותה להכיר בתמונות MNIST . דוגמה זו משתמשת באופן מכוון בממשק ה- API של TF2 ברמה נמוכה כדי להגדיר מבני שכבות מותאמים אישית, פונקציית אובדן ולולאת אימונים, מכיוון שהסבירות של באגים של NaN גבוהה יותר כאשר אנו משתמשים בממשק API גמיש יותר אך נוטה יותר לשגיאות מאשר כאשר אנו משתמשים בפשוטים יותר לשימוש APIs אך מעט פחות גמיש ממשקי API ברמה גבוהה כמו tf.keras .

התוכנית מדפיסה דיוק מבחן לאחר כל שלב אימונים. אנו יכולים לראות בקונסולה שדיוק הבדיקה נתקע ברמה הסיכוי כמעט (~ 0.1) לאחר הצעד הראשון. זה בהחלט לא איך שצפוי אימון המודל להתנהג: אנו מצפים שהדיוק יתקרב בהדרגה ל- 1.0 (100%) ככל שהצעד יגדל.

 Accuracy at step 0: 0.216
Accuracy at step 1: 0.098
Accuracy at step 2: 0.098
Accuracy at step 3: 0.098
...
 

ניחוש משכיל הוא שבעיה זו נגרמת על ידי חוסר יציבות מספרית, כמו NaN או אינסוף. עם זאת, כיצד אנו מאשרים שזה באמת המקרה וכיצד אנו מוצאים שפעולת TensorFlow אחראית ליצירת חוסר היציבות המספרית? כדי לענות על שאלות אלה, בואו נתכנן את תוכנית הכרכרה באמצעות Debugger V2.

מכשיר קוד TensorFlow עם Debugger V2

tf.debugging.experimental.enable_dump_debug_info() היא נקודת הכניסה לממשק ה- API של Debugger V2. זה מכשיר תוכנית TF2 עם שורת קוד אחת. לדוגמה, הוספת השורה הבאה בסמוך לתחילת התוכנית תגרום למידע על איתור באגים לספריית היומן (logdir) ב / tmp / tfdbg2_logdir. מידע הבאגים מכסה היבטים שונים של זמן ריצה של TensorFlow. ב- TF2 הוא כולל את ההיסטוריה המלאה של ביצוע להוט, בניית גרפים שבוצעה על ידי @ tf.function , ביצוע הגרפים, ערכי הטנזור שנוצרו על ידי אירועי הביצוע, וכן את מיקום הקוד (עקבות ערימת פייתון) של אותם אירועים. . העושר של מידע איתור הבאגים מאפשר למשתמשים לצמצם באגים עלומים.

 tf.debugging.experimental.enable_dump_debug_info(
    logdir="/tmp/tfdbg2_logdir",
    tensor_debug_mode="FULL_HEALTH",
    circular_buffer_size=-1)
 

הארגומנט tensor_debug_mode שולט באיזה מידע מוצא Debugger V2 מכל טנזור להוט או גרף. "FULL_HEALTH" הוא מצב שלוכד את המידע הבא על כל טנזור מסוג צף (למשל, float32 הנפוץ ונראה פחות dtype bfloat16):

  • DType
  • דַרגָה
  • המספר הכולל של האלמנטים
  • פירוט של האלמנטים הצפים לקטגוריות הבאות: סופי שלילי ( - ), אפס ( 0 ), סופי חיובי ( + ), אינסוף שלילי ( -∞ ), אינסוף חיובי ( +∞ ) ו- NaN .

מצב "FULL_HEALTH" מתאים לניפוי באגים הכוללים NaN ואינסוף. עיין בהמשך למידע נוסף על tensor_debug_mode .

הארגומנט circular_buffer_size קובע כמה אירועי טנזור נשמרים ב- logdir. ברירת המחדל היא ל -1000, מה שגורם רק לאלף הטנסורים האחרונים לפני סיום תוכנית TF2 המותקנת להישמר בדיסק. התנהגות ברירת מחדל זו מצמצמת את התקורה של באגים על ידי הקרבת שלמות נתוני הבאגים. אם העדיפות השלמות, כמו במקרה זה, נוכל להשבית את המאגר המעגלי על ידי הגדרת הארגומנט לערך שלילי (למשל -1 כאן).

הדוגמה debug_mnist_v2 קוראת enable_dump_debug_info() ידי העברת דגלי שורת הפקודה אליו. כדי להפעיל שוב את תוכנית TF2 הבעייתית שלנו עם הפעלת מכשיר הבאגים הזה, עשה:

 python -m tensorflow.python.debug.examples.v2.debug_mnist_v2 \
    --dump_dir /tmp/tfdbg2_logdir --dump_tensor_debug_mode FULL_HEALTH
 

הפעלת ממשק ה- Debugger V2 ב- TensorBoard

הפעלת התוכנית עם מכשור הבאגים יוצרת logdir ב- / tmp / tfdbg2_logdir. נוכל להפעיל את TensorBoard ולהצביע על הכניסה באמצעות:

 tensorboard --logdir /tmp/tfdbg2_logdir
 

בדפדפן האינטרנט נווט לדף של TensorBoard בכתובת http: // localhost: 6006. יש להפעיל את התוסף "Debugger V2" כברירת מחדל, ולהציג דף שנראה כמו הבא:

Debugger V2 צילום מסך מלא

שימוש בממשק המשתמש של Debugger V2 כדי למצוא את הגורם הבסיסי ל- NaNs

ממשק ה- Debugger V2 ב- TensorBoard מסודר לשישה חלקים:

  • התראות : קטע זה משמאל למעלה מכיל רשימה של אירועי "התראה" שאותרה על ידי הבאגים בנתוני הבאגים מהתוכנית TensorFlow המותקנת. כל התרעה מצביעה על אנומליה מסוימת המצדיקה את תשומת הלב. במקרה שלנו, פרק זה מדגיש 499 אירועי NaN / ∞ עם צבע ורוד-אדום בולט. זה מאשר את החשד שלנו שהמודל לא מצליח ללמוד בגלל נוכחותם של NaNs ו / או אינסוף בערכי הטנזור הפנימיים שלו. נעמיק בהתראות אלה בקרוב.
  • ציר זמן ביצוע של פייתון : זהו המחצית העליונה של החלק העליון-אמצע. הוא מציג את ההיסטוריה המלאה של הביצוע הלהט של אופציות ותרשימים. כל תיבה בציר הזמן מסומנת על ידי האות הראשונית בשם ה- OP או הגרף (למשל "T" עבור האופציה "TensorSliceDataset", "m" עבור tf.function ה- "model" tf.function .). אנו יכולים לנווט בציר זמן זה באמצעות לחצני הניווט וסרגל הגלילה שמעל ציר הזמן.
  • ביצוע גרפים : ממוקם בפינה השמאלית העליונה של ממשק המשתמש, חלק זה יהיה מרכזי במשימת הבאגים שלנו. הוא מכיל היסטוריה של כל הטנסורים הצפויים של dtype המחושבים בתוך גרפים (כלומר, נערכו על ידי @tf-function ).
  • מבנה הגרף (המחצית התחתונה של החלק העליון-אמצע), קוד המקור (החלק השמאלי התחתון) ועקבות הערימה (החלק השמאלי התחתון) ריקים בתחילה. תוכנן יאוכלס כאשר אנו מתקשרים עם ממשק המשתמש. שלושת החלקים הללו ישחקו גם תפקידים חשובים במשימת הבאגים שלנו.

לאחר שכיוונו את עצמנו לארגון ממשק המשתמש, בואו ננקוט בצעדים הבאים כדי לרדת לעומק הסיבה לכך שה- NNs הופיעו. ראשית, לחץ על התראת NaN / ∞ בקטע התראות. פעולה זו גוללת אוטומטית את רשימת 600 הגרפים הטנורים בקטע ביצוע גרפים ומתמקדת במספר 88, שהוא טנסור בשם "יומן: 0" שנוצר על ידי Log (לוגריתם טבעי). צבע ורוד-אדום בולט מדגיש אלמנט -∞ בין 1000 האלמנטים של הטנסור 2D float32. זהו הטנסור הראשון בהיסטוריית זמן הריצה של תוכנית TF2 שהכיל NaN או אינסוף: טנסורים המחושבים לפני שהם אינם מכילים NaN או ∞; רבים (למעשה, רוב) הטנורים המחושבים לאחר מכן מכילים NaNs. אנו יכולים לאשר זאת על ידי גלילה למעלה ולמטה ברשימת ביצוע הגרפים. תצפית זו מספקת רמז חזק לכך שה- Log op הוא המקור לחוסר היציבות המספרית בתוכנית TF2 זו.

Debugger V2: התראות Nan / Infinity ורשימת ביצוע גרפים

מדוע Log הזה יורק A -∞? כדי לענות על שאלה זו יש לבחון את הקלט ל- OP. לחיצה על שם הטנזור ("יומן: 0") מציגה הדמיה פשוטה אך אינפורמטיבית של סביבתו של ה- Log op בתרשים TensorFlow שלו בקטע מבנה גרף. שימו לב לכיוון מלמעלה למטה של ​​זרימת המידע. ה- OP עצמו מוצג בתעוזה באמצע. מיד מעליו, אנו יכולים לראות ש- Placeholder op מספק את הקלט היחיד וה- Log ל- Log op. היכן נוצר הטנסור שנוצר על ידי יומן זה מציין מיקום ברשימת ביצוע גרפים? על ידי שימוש בצבע הרקע הצהוב ככלי עזר חזותי, אנו יכולים לראות כי logits:0 טנסור הוא שתי שורות מעל Log:0 טנסור, כלומר בשורה 85.

Debugger V2: תצוגת מבנה גרף ומעקב אחר טנזור קלט

מבט קפדני יותר על ההתפלגות המספרית של הטנסור "logits: 0" בשורה 85 מגלה מדוע Log:0 הצרכנים שלו Log:0 מייצר -∞: מבין 1000 האלמנטים של "logits: 0", לאלמנט אחד יש ערך של 0. ה- -∞ הוא תוצאה של חישוב הלוגריתם הטבעי של 0! אם נוכל להבטיח איכשהו שה- Log op ייחשף לתשומות חיוביות בלבד, נוכל למנוע מה- NaN / ∞ להתרחש. ניתן להשיג זאת על ידי החלת גזירה (למשל, באמצעות tf.clip_by_value () ) בטנזור יומני המיקום.

אנו מתקרבים יותר לפתרון הבאג, אך עדיין לא הושלם. כדי להחיל את התיקון, עלינו לדעת היכן במקור המקור של פייתון מקורו של ה- Log op וכניסת Placeholder שלו. Debugger V2 מספק תמיכה מהשורה הראשונה להתחקות אחר ערכי הגרפים ואירועי הביצוע למקורם. כאשר לחצנו על טנסור Log:0 בביצוע גרפים, הקטע Trace Trace היה מאוכלס בתמצית הערימה המקורית של היצירה של Log op. עקוב הערימה גדול למדי מכיוון שהוא כולל מסגרות רבות מהקוד הפנימי של TensorFlow (למשל, gen_math_ops.py ו- dumping_callback.py), אשר אנו יכולים להתעלם מהם בבטחה עבור רוב משימות הבאגינג. מסגרת העניין היא קו 216 של debug_mnist_v2.py (כלומר, קובץ הפייתון שאנחנו בעצם מנסים לבצע באגים). לחיצה על "קו 204" מציגה תצוגה של שורת הקוד המתאימה בקטע קוד המקור.

Debugger V2: קוד המקור ומעקב הערימה

זה סוף סוף מביא אותנו לקוד המקור שיצר את ה- Log op הבעייתי מכניסת היומנים שלו. זוהי פונקציית ההפסד הקטגורית-אובדן-אנטרופיה המותאמת אישית שלנו המעוטרת בפונקציה @tf.function . ומכאן לתרשים TensorFlow. מציין המיקום ב- "logits" מתאים לטיעון הקלט הראשון לפונקציית ההפסד. ה- Log op נוצר באמצעות שיחת ה- API tf.math.log ().

התיקון לגזירת ערך לבאג זה ייראה כמו:

   diff = -(labels *
           tf.clip_by_value(tf.math.log(logits), 1e-6, 1.))
 

זה יפתור את חוסר היציבות המספרית בתוכנית TF2 זו ויגרום ל- MLP להתאמן בהצלחה. גישה אפשרית נוספת לתיקון חוסר היציבות המספרית היא שימוש ב- tf.keras.losses.CategoricalCrossentropy .

זה מסיים את המסע שלנו מתצפית על באג מודל TF2 ועד לבוא עם שינוי קוד שמתקן את הבאג, בסיוע הכלי Debugger V2, המספק ראות מלאה להיסטוריית הביצועים והלהיטים הגרפיים של התוכנית TF2 המותקנת, כולל הסיכומים המספריים של ערכי טנזור ואסוציאציה בין אופציות, טנסורים וקוד המקור המקורי שלהם.

תאימות חומרה של Debugger V2

Debugger V2 תומך בחומרת הדרכה רגילה הכוללת מעבד ו- GPU. תמיכה גם בהכשרת Multi-GPU עם tf.distribut.MirroredStrategy . התמיכה ב- TPU עדיין נמצאת בשלב מוקדם ומחייבת התקשרות

 tf.config.set_soft_device_placement(True)
 

לפני שאתה מתקשר enable_dump_debug_info() . יתכנו גם מגבלות אחרות על TPUs. אם נתקלת בבעיות בשימוש ב- Debugger V2, דווח על באגים בדף הבעיות של GitHub .

תאימות API של Debugger V2

Debugger V2 מיושם ברמה נמוכה יחסית של ערימת התוכנה של TensorFlow, ומכאן שהוא תואם tf.keras , tf.data ושאר APIs שנבנו על גבי הרמות הנמוכות של TensorFlow. Debugger V2 תואם גם לאחור עם TF1, אם כי ציר זמן הביצוע של Eager יהיה ריק עבור יומני הבאגים שנוצרו על ידי תוכניות TF1.

טיפים לשימוש בממשק API

שאלה שנשאלת לעתים קרובות על API זה לאיתור באגים היא היכן בקוד TensorFlow יש להכניס את השיחה enable_dump_debug_info() . בדרך כלל, יש לקרוא לממשק ה- API מוקדם ככל האפשר בתוכנת TF2 שלך, רצוי לאחר קווי הייבוא ​​של פייתון ולפני תחילת בניית הגרפים והביצוע. זה יבטיח כיסוי מלא של כל האופציות והגרפים שמאצילים את המודל שלך וההדרכה שלו.

תומכי tensor_debug_debug_ הנתמכים כעת הם: NO_TENSOR , CURT_HEALTH , CONCISE_HEALTH , FULL_HEALTH ו- SHAPE . הם משתנים בכמות המידע המופק מכל טנזור ובתקופת הביצועים לתוכנית שנפלה. אנא עיין בקטע args enable_dump_debug_info() של enable_dump_debug_info() ].

תקורה של ביצועים

ממשק ה- API לניפוי באגים מציג תקורה לביצועים לתוכנית TensorFlow המותקנת. תקורה משתנה לפי tensor_debug_mode , סוג החומרה ואופייה של התוכנית TensorFlow המותקנת. כנקודת התייחסות, ב- GPU, מצב NO_TENSOR מוסיף תקורה של 15% במהלך האימונים של דגם שנאי בגודל אצווה 64. האחוז התקורה עבור תנאים אחרים של tensor_debug_ גבוה יותר: כ- 50% עבור CURT_HEALTH , CONCISE_HEALTH , FULL_HEALTH ו- SHAPE מצבים. במעבדים, התקורה מעט נמוכה יותר. ב- TPUs, התקורה כרגע גבוהה יותר.

קשר לממשקי API לאיתור ניפוי TensorFlow אחרים

שים לב כי TensorFlow מציעה כלים וממשקי API אחרים לניפוי באגים. אתה יכול לגלוש בממשקי API מסוג זה תחת tf.debugging.* מרחב השמות בדף מסמכי ה- API. בין ממשקי ה- API הללו הנפוץ ביותר הוא tf.print() . מתי יש להשתמש ב- Debugger V2 ומתי יש להשתמש tf.print() במקום? tf.print() נוח במקרה שבו

  1. אנו יודעים בדיוק אילו טנסורים להדפיס,
  2. אנו יודעים היכן בדיוק בקוד המקור להכנסת tf.print() ,
  3. מספרם של טנסורים כאלה אינו גדול מדי.

במקרים אחרים (למשל, בחינת ערכי טנזור רבים, בחינת ערכי טנזור שנוצרו על ידי הקוד הפנימי של TensorFlow וחיפוש אחר מקור חוסר היציבות המספרית כפי שהראנו לעיל), Debugger V2 מספק דרך מהירה יותר לאיתור באגים. בנוסף, Debugger V2 מספק גישה אחידה לבדיקת טנורים להוטים וגרפים. בנוסף הוא מספק מידע על מבנה הגרף ומיקומי הקוד, שהם מעבר ליכולת של tf.print() .

ממשק API אחר שניתן להשתמש בו לניפוי בעיות הקשורות ל- ∞ ו- NaN הוא tf.debugging.enable_check_numerics() . שלא כמו enable_dump_debug_info() , enable_check_numerics() לא שומר מידע על באגים בדיסק. במקום זאת, הוא פשוט עוקב אחר ∞ ו- NaN במהלך זמן ריצה של TensorFlow ושגיאות במיקום קוד המקור ברגע שכל אופטימיזציה מייצרת ערכים מספריים כל כך גרועים. יש לו תקורה בעלת ביצועים נמוכים יותר בהשוואה ל- enable_dump_debug_info() , אך אינה מספקת שמץ מלא מהיסטוריית הביצוע של התוכנית ואינה מגיעה עם ממשק משתמש גרפי כמו Debugger V2.