אלו הם השיטות המומלצות לבדיקת קוד במאגר TensorFlow .
לפני שתתחיל
לפני שאתה תורם קוד מקור לפרויקט TensorFlow, אנא עיין בקובץ CONTRIBUTING.md
ב-Repo GitHub של הפרויקט. (לדוגמה, ראה את הקובץ CONTRIBUTING.md עבור ריפו הליבה של TensorFlow .) כל תורמי הקוד נדרשים לחתום על הסכם רישיון תורם (CLA).
עקרונות כלליים
תלוי רק במה אתה משתמש בכללי ה-BUILD שלך
TensorFlow היא ספרייה גדולה, ובהתאם לחבילה המלאה בעת כתיבת מבחן יחידה עבור תת-מודוליה היה נוהג נפוץ. עם זאת, זה משבית את הניתוח המבוסס על תלות bazel
. משמעות הדבר היא שמערכות אינטגרציה מתמשכות אינן יכולות לבטל באופן מושכל בדיקות לא קשורות עבור ריצות קדם-שליחה/אחרי הגשה. אם אתה תלוי רק בתת-מודולים שאתה בודק בקובץ BUILD
שלך, תחסוך זמן לכל מפתחי TensorFlow, והרבה כוח חישוב יקר.
עם זאת, שינוי תלות הבנייה שלך כדי להשמיט את יעדי ה-TF המלאים מביא כמה מגבלות על מה שאתה יכול לייבא בקוד Python שלך. לא תוכל להשתמש יותר ב- import tensorflow as tf
בבדיקות היחידה שלך. אבל זה פשרה כדאית שכן היא חוסכת מכל המפתחים להריץ אלפי בדיקות מיותרות.
כל הקוד צריך לכלול בדיקות יחידה
עבור כל קוד שאתה כותב, עליך לכתוב גם את בדיקות היחידה שלו. אם אתה כותב קובץ חדש foo.py
, עליך למקם את בדיקות היחידה שלו ב- foo_test.py
ולשלוח אותו באותו שינוי. כוון לכיסוי בדיקה מצטבר של מעל 90% עבור כל הקוד שלך.
הימנע משימוש בכללי בדיקת bazel מקוריים ב-TF
ל-TF יש הרבה דקויות בעת הפעלת בדיקות. עבדנו כדי להסתיר את כל המורכבויות הללו בפקודות המאקרו הבאזל שלנו. כדי להימנע מלהתמודד עם אלה, השתמשו בדברים הבאים במקום בכללי הבדיקה המקוריים. שימו לב שכל אלו מוגדרים ב- tensorflow/tensorflow.bzl
עבור בדיקות CC, השתמשו ב- tf_cc_test
, tf_gpu_cc_test
, tf_gpu_only_cc_test
. עבור מבחני פיתון, השתמש ב- tf_py_test
או gpu_py_test
. אם אתה צריך משהו שקרוב באמת לכלל ה-Native py_test
, השתמש במקום המוגדר ב-tensorflow.bzl. אתה רק צריך להוסיף את השורה הבאה בראש הקובץ BUILD: load(“tensorflow/tensorflow.bzl”, “py_test”)
שים לב היכן מתבצעת הבדיקה
כשאתה כותב מבחן, אינפרא הבדיקה שלנו יכולה לדאוג להרצת הבדיקות שלך על CPU, GPU ומאיצים אם תכתוב אותם בהתאם. יש לנו בדיקות אוטומטיות הפועלות על לינוקס, מאקוס, חלונות, שיש להם מערכות עם או בלי GPUs. אתה פשוט צריך לבחור באחת מפקודות המאקרו המפורטות לעיל, ולאחר מכן להשתמש בתגים כדי להגביל את המקום שבו הם מבוצעים.
תג
manual
לא יכלול את הבדיקה שלך מלהפעיל בכל מקום. זה כולל ביצוע בדיקות ידניות המשתמשות בדפוסים כגוןbazel test tensorflow/…
no_oss
לא תכלול את הבדיקה שלך מהפעלה בתשתית הבדיקה הרשמית של TF OSS.ניתן להשתמש בתגיות
no_mac
אוno_windows
כדי לא לכלול את הבדיקה שלך מחבילות הבדיקה הרלוונטיות של מערכת ההפעלה.ניתן להשתמש בתג
no_gpu
כדי לא לכלול את הבדיקה שלך מהפעלה בחבילות בדיקה של GPU.
ודא שבדיקות פועלות בחבילות בדיקה צפויות
ל-TF יש לא מעט חבילות בדיקה. לפעמים, הם עשויים להיות מבלבלים בהגדרה. עשויות להיות בעיות שונות שגורמות להשמטת הבדיקות שלך מבנייה מתמשכת. לפיכך, עליך לוודא שהבדיקות שלך מבוצעות כצפוי. כדי לעשות זאת:
- המתן עד שההודעות המוקדמות שלך ב-Pull Request (PR) שלך ירוצו עד להשלמתו.
- גלול לחלק התחתון של יחסי הציבור שלך כדי לראות את בדיקות המצב.
- לחץ על הקישור "פרטים" בצד ימין של כל המחאה של קוקורו.
- בדוק את רשימת "יעדים" כדי למצוא את היעדים החדשים שנוספו.
לכל מחלקה/יחידה צריך להיות קובץ מבחן יחידה משלה
שיעורי מבחן נפרדים עוזרים לנו לבודד טוב יותר כשלים ומשאבים. הם מובילים לקובצי בדיקה קצרים וקלים יותר לקריאה. לכן, לכל קבצי Python שלך צריך להיות לפחות קובץ בדיקה תואם אחד (עבור כל foo.py
, עליו להיות foo_test.py
). לבדיקות משוכללות יותר, כגון מבחני אינטגרציה הדורשים הגדרות שונות, זה בסדר להוסיף עוד קובצי בדיקה.
מהירות וזמני ריצה
יש להשתמש בריסוק כמה שפחות
במקום לגזור בבקשה שקול:
- הופכים את הבדיקות שלך לקטנות יותר
- אם האמור לעיל אינו אפשרי, פצל את הבדיקות
Sharding עוזר להפחית את זמן האחזור הכולל של בדיקה, אך ניתן להשיג אותו הדבר על ידי פירוק בדיקות למטרות קטנות יותר. פיצול בדיקות נותן לנו רמה עדינה יותר של שליטה בכל בדיקה, ממזער ריצות מוקדמות מיותרות ומצמצם את אובדן הכיסוי מ-buildcop משבית מטרה שלמה עקב מקרה בדיקה שגוי. יתרה מכך, פיצול כרוך בעלויות נסתרות שאינן כל כך ברורות, כגון הפעלת כל קוד אתחול הבדיקה עבור כל הרסיסים. סוגיה זו הוסלמה אלינו על ידי צוותי אינפרא כמקור שיוצר עומס נוסף.
בדיקות קטנות יותר טובות יותר
ככל שהבדיקות שלך יפעלו מהר יותר, כך יש יותר סיכוי שאנשים יבצעו את הבדיקות שלך. שנייה אחת נוספת לבדיקה שלך יכולה להצטבר לשעות של זמן נוסף המושקע בהפעלת הבדיקה שלך על ידי המפתחים והתשתית שלנו. נסה לגרום לבדיקות שלך לרוץ מתחת ל-30 שניות (במצב לא-אופט!), והקטן אותן. סמן רק את המבחנים שלך כבינוני כמוצא אחרון. ה-infra לא מפעיל בדיקות גדולות כמו presubmits או postsubmits! לכן, כתוב מבחן גדול רק אם אתה מתכוון לארגן היכן הוא הולך לרוץ. כמה טיפים שיגרמו לבדיקות לרוץ מהר יותר:
- הפעל פחות איטרציות של אימון במבחן שלך
- שקול להשתמש בהזרקת תלות כדי להחליף תלות כבדה של המערכת הנבדקת בזיופים פשוטים.
- שקול להשתמש בנתוני קלט קטנים יותר בבדיקות יחידה
- אם שום דבר אחר לא עובד, נסה לפצל את קובץ הבדיקה שלך.
זמני הבדיקה צריכים לכוון למחצית מפסק הזמן של גודל הבדיקה כדי למנוע פתיתים
עם יעדי בדיקת bazel
, לבדיקות קטנות יש פסק זמן של דקה אחת. זמן קצוב לבדיקה בינוני הוא 5 דקות. בדיקות גדולות פשוט אינן מבוצעות על ידי אינפרא הבדיקה של TensorFlow. עם זאת, מבחנים רבים אינם דטרמיניסטיים בכמות הזמן שהם לוקחים. מסיבות שונות הבדיקות שלך עשויות לקחת יותר זמן מדי פעם. ואם תסמן בדיקה שנמשכת 50 שניות בממוצע כקטנה, הבדיקה שלך תתקלקל אם היא מתזמנת במכונה עם מעבד ישן. לכן, כוון לזמן ריצה ממוצע של 30 שניות עבור בדיקות קטנות. כוון ל-2 דקות ו-30 שניות של זמן ריצה ממוצע לבדיקות בינוניות.
צמצם את מספר הדגימות והגדל את הסובלנות לאימון
בדיקות ריצה איטיות מרתיעות תורמים. אימון ריצה במבחנים יכול להיות איטי מאוד. העדיפו סובלנות גבוהה יותר כדי שתוכל להשתמש בפחות דגימות בבדיקות שלך כדי לשמור על הבדיקות שלך מהירות מספיק (2.5 דקות לכל היותר).
הסר חוסר דטרמיניזם ופתיתים
כתוב מבחנים דטרמיניסטיים
בדיקות יחידה צריכות להיות תמיד דטרמיניסטיות. כל הבדיקות הפועלות ב-TAP ובגיטרה אמורות לפעול באותה צורה בכל פעם, אם אין שינוי קוד שמשפיע עליהן. כדי להבטיח זאת, להלן כמה נקודות שיש לקחת בחשבון.
תמיד זרעו כל מקור לסטוכסטיות
כל מחולל מספרים אקראיים, או כל מקור אחר לסטוקסטיות עלול לגרום להתקלפות. לכן, כל אחד מאלה חייב להיות זרע. בנוסף לכך שהבדיקות יהיו פחות מתקלפות, הדבר הופך את כל הבדיקות לניתנות לשחזור. דרכים שונות להגדיר כמה זרעים שאולי תצטרך להגדיר במבחני TF הן:
# Python RNG
import random
random.seed(42)
# Numpy RNG
import numpy as np
np.random.seed(42)
# TF RNG
from tensorflow.python.framework import random_seed
random_seed.set_seed(42)
הימנע משימוש sleep
בבדיקות מרובי חוטים
שימוש בתפקוד sleep
בבדיקות יכול להיות גורם מרכזי להתקלפות. במיוחד כאשר משתמשים במספר שרשורים, שימוש בשינה כדי לחכות לשרשור אחר לעולם לא יהיה דטרמטיסטי. זה נובע מכך שהמערכת לא יכולה להבטיח שום הזמנה של ביצוע של שרשורים או תהליכים שונים. לכן, העדיפו מבני סנכרון דטרמיניסטיים כגון מוטקסים.
בדוק אם הבדיקה מתקלפת
פתיתים גורמים ל-buildcops ולמפתחים לאבד שעות רבות. קשה לזהות אותם, וקשה לנפות אותם. למרות שקיימות מערכות אוטומטיות לזיהוי התקלפות, הן צריכות לצבור מאות ריצות בדיקה לפני שהן יכולות להכחיש במדויק בדיקות. גם כשהם מזהים, הם מכחישים את הבדיקות שלך וכיסוי הבדיקה אובד. לכן, מחברי המבחן צריכים לבדוק אם המבחנים שלהם מתקלקלים בעת כתיבת מבחנים. ניתן לעשות זאת בקלות על ידי הפעלת הבדיקה שלך עם הדגל: --runs_per_test=1000
השתמש ב- TensorFlowTestCase
TensorFlowTestCase נוקטת באמצעי זהירות נחוצים, כגון זריעה של כל מחוללי המספרים האקראיים המשמשים כדי להפחית את ההתקלפות ככל האפשר. ככל שנגלה ונתקן מקורות מתקלפים נוספים, כל אלה יתווספו ל-TensorFlowTestCase. לכן, עליך להשתמש ב-TensorFlowTestCase בעת כתיבת מבחנים עבור tensorflow. TensorFlowTestCase מוגדר כאן: tensorflow/python/framework/test_util.py
כתוב מבחנים הרמטיים
לבדיקות הרמטיות אין צורך במשאבים חיצוניים. הם עמוסים בכל מה שהם צריכים, והם פשוט מתחילים כל שירות מזויף שהם עשויים להזדקק להם. כל השירותים מלבד הבדיקות שלך הם מקורות לאי דטרמיניזם. אפילו עם 99% זמינות של שירותים אחרים, הרשת עלולה להתקלקל, תגובת rpc יכולה להתעכב, ואתה עלול לקבל הודעת שגיאה בלתי מוסברת. שירותים חיצוניים עשויים להיות, אך לא רק, GCS, S3 או כל אתר אינטרנט.