חבילת בדיקות (ATS) של LiteRT Accelerator

LiteRT Accelerator Test Suite (ATS) הוא כלי מקיף שמשמש לאימות של נכונות פונקציונלית ולמדידת הביצועים של הטמעות מותאמות אישית של מאיצים שמשולבים עם מסגרת LiteRT.

סקירה כללית ופונקציונליות ליבה

הפונקציה העיקרית של ATS היא להריץ מודלים מוגדרים מראש של למידת מכונה על מאיץ יעד ולהשוות את התוצאות ל-LiteRT backend רגיל של CPU.

  • אימות: חבילת הבדיקה מבצעת אימות מספרי על ידי השוואה בין טנסורים של פלט (הפעלות) שנוצרו על ידי המאיץ לבין טנסורים שנוצרו על ידי קצה העורפי של המעבד שידוע שהוא תקין. כך אפשר לוודא שההטמעה של המאיץ תהיה מדויקת ונכונה.
  • מדדי ביצועים: המערכת אוספת ומתעדת באופן אוטומטי פרטים חשובים על הביצועים, כולל זמן האחזור ומדדים רלוונטיים אחרים, שזמינים למשתמש.
  • ביצוע: הבדיקות מבוצעות בדרך כלל במכשיר יעד (למשל, טלפון Android) ומנוהלות על ידי עטיפה של סקריפט shell שמטפל בהעברות קבצים ובהגדרה באמצעות הכלי adb (Android Debug Bridge).

נתוני בדיקה (מודלים)

חבילת ATS משתמשת באוסף של מודלים.tflite שנמצאים בשימוש נרחב כנתוני בדיקה. נתוני הקלט נוצרים באופן אקראי על סמך סוג הנתונים, ואפשר להגדיר אותם לפי הצורך.

מודלים כלולים

המודלים הבאים נכללים באופן אוטומטי ומוורדים לבדיקה (המודלים עשויים להשתנות):

  • hf_all_minilm_l6_v2
  • hf_mobilevit_small
  • qai_hub_midas
  • qai_hub_real_esrgan_x4plus
  • torchvision_mobilenet_v2
  • torchvision_resnet18
  • torchvision_squeezenet1_1
  • u2net_lite
  • whisper_tiny_decoder
  • whisper_tiny_encoder
  • yamnet
  • yolo11n

שליפה ידנית של מודל

המודלים מורדים אוטומטית במהלך bazel run, אבל אפשר לאחזר ידנית את כל קבוצת המודלים באמצעות wget:

wget -p -O <target_file> https://storage.googleapis.com/litert/ats_models.tar.gz

הגדרת חבילת ATS באמצעות Bazel

משתמשים בפקודת המאקרו litert_define_ats Bazel כדי להגדיר ולהגדיר יעד ספציפי לבדיקת ATS במאיץ.

המאקרו יוצר באופן אוטומטי שני יעדים להפעלה:

  1. בדיקת JIT במכשיר (לביצוע ולאימות).
  2. בדיקה ייעודית של מצב AOT 'קומפילציה בלבד' (לקומפילציה של המארח).

דוגמה לשימוש ב-litert_define_ats

בדוגמה מוגדרת חבילת ATS בשם example_ats למאיץ עם שם ה-backend‏ example:

# Emits aot-mode and jit-mode test targets, one for running compilation test on host
# and another for running JIT and inference on device
# These targets are named with their respective suffix attribute.
litert_define_ats(
    name = "example_ats",
    backend = "example",
    compile_only_suffix = "_aot",
    do_register = [
        "*mobilenet*",
    ],
    extra_flags = ["--limit=1"],
    jit_suffix = "",
)

ביצוע

כדי להריץ את הבדיקה הרגילה שמיועדת ל-Android (שמטפלת בכל הפעולות של adb):

# Handles environment setup, and build + push of library and data dependencies to the device,
# executes the suite on the target.
bazel run -c opt --config=android_arm64 :example_ats

כדי להריץ את בדיקת הקומפילציה של AOT:

# Handle environment setup, and builds library dependencies for host platform.
# Executes the ats compile only flow. The "--compile_mode" flag is already
# bound to the program arguments.
bazel run :example_ats_aot

הרצה ב-Linux (מארח)

במערכות Linux, שבהן ATS מופעל באותה מכונה שבה מתבצעת הבנייה, המשתמשים צריכים להשתמש ישירות בקובץ הבינארי :ats:

bazel run -c opt :ats

ביצוע IoT

כדי להפעיל את התוכנה ב-IoT, המשתמשים יצטרכו ליצור את הקובץ הבינארי במארח ולהעביר אותו למכשיר באופן ידני.

התרעות לגבי שורת פקודה

קובץ ההפעלה ats מקבל כמה דגלים לשליטה מפורטת בבדיקות ובדיווח.

דגל סוג תיאור
--backend std::string חובה. איזה עורף קצה של LiteRT ישמש כמאיץ שנבדק (ה'בפועל'). האפשרויות הן cpu, ‏npu או gpu.
--compile_mode bool אם הערך הוא true, שלב הקומפילציה של AOT מופעל בתחנת העבודה במקום בהפעלה במכשיר. הערה: האפשרות הזו משויכת אוטומטית ליעד הבנייה 'aot' ולא צריך להגדיר אותה באופן מפורש.
--models_out std::string נתיב הספרייה שבה נשמרים מודלים של תופעות לוואי שעברו סריאליזציה (קומפילציה). רלוונטי רק להידור AOT או JIT.
--dispatch_dir std::string הנתיב לספרייה שמכילה את ספריית השליחה של המאיץ (רלוונטי ל-NPU).
--plugin_dir std::string הנתיב לספריית הפלאגין של מהדר המאיץ (רלוונטי ל-NPU).
--soc_manufacturer std::string היצרן של ה-SOC לטירגוט עבור קומפילציה של AOT (רלוונטי לקומפילציה של NPU).
--soc_model std::string מודל ה-SOC לטירגוט עבור קומפילציה של AOT (רלוונטי לקומפילציה של NPU).
--iters_per_test size_t מספר האיטרציות להרצה לכל בדיקה, כל אחת עם נתוני טנסור אקראיים שונים.
--max_ms_per_test int64_t משך הזמן המרבי באלפיות השנייה להרצת כל בדיקה לפני פסק זמן.
--fail_on_timeout bool האם הבדיקה תיכשל אם יפוג הזמן הקצוב להפעלה.
--csv std::string נתיב הקובץ לשמירת הדוח המפורט בפורמט CSV.
--dump_report bool האם להציג את כל פרטי הדוח ישירות בפלט של מסוף המשתמש.
--data_seed std::optional<int> seed אחד ליצירת נתונים גלובליים.
--do_register std::vector<std::string> ביטויי Regex להכללה מפורשת של בדיקות ספציפיות (למשל, *mobilenet*).
--dont_register std::vector<std::string> ביטויי Regex להחרגה של בדיקות ספציפיות.
--extra_models std::vector<std::string> רשימה אופציונלית של ספריות או קבצים של מודלים להוספה לחבילת הבדיקה.
--limit int32_t הגבלת המספר הכולל של בדיקות שנרשמו והופעלו.
--quiet bool צמצום פלט הרישום במהלך הרצת הבדיקה.

שימוש בכלי השירות לבנייה של ATS‏ litert_device_script

היעדים של ATS שהמשתמשים מריצים באופן אוטומטי כוללים נקודת כניסה של מעטפת שמטפלת בכל הגדרת הסביבה, ובכל דחיפה של ספריות נדרשות כשהמכשיר היעד שונה מהמארח שבו הושלם ה-build (לדוגמה, adb push).

הפונקציונליות הזו מסופקת באופן כללי באמצעות כלי השירות litert_device_script שבהם נעשה שימוש מאחורי הקלעים בגרסאות של ATS. יש תהליך רישום שצריך לבצע כדי לקבל גישה לפונקציונליות הזו של בניית אפליקציות. בנוסף לתמיכה ב-ats, אפשר להשתמש בכלי השירות האלה באופן עצמאי כדי לדמות את cc_binary ואת cc_test, שנועדו להפעלה במכשיר שונה ממארח הבנייה שדורש שליחה של יחסי תלות.

רישום בקצה העורפי

כדי להפעיל מאיץ חדש לשימוש ב-litert_device_script (ולכן ב-ATS), צריך לרשום את הספריות הנדרשות שלו בקובץ litert_device_common.bzl Bazel. ההרשמה מבוססת על שם ייחודי של 'קצה עורפי' שממופה לקבוצה של ספריות שאפשר לבנות או שהן קומפלו מראש, שנדרשות כדי שמערכת LiteRT תפעל עם המאיץ הזה.

שלבי ההרשמה

  1. הגדרת פונקציית BackendSpec: יוצרים פונקציה שמחזירה מילון שמכיל את המפרט של המאיץ החדש.

  2. Specify Libraries (libs): זו רשימה של טאפלים שמפרטים את נתיב היעד של Bazel לספרייה המשותפת ואת משתנה הסביבה (LD_LIBRARY_PATH) שנדרש כדי שמקשר המכשיר ימצא אותה.

    • ספריית השליחה: נדרשת להרצת זמן ריצה.
    • ספריית פלאגין של קומפיילר: נדרשת למצב קומפילציה AOT.
  3. מציינים שמות של ספריות (plugin, dispatch): מציינים את שמות הקבצים של התוסף ושל ספריות השליחה.

  4. רישום המפרט: ממזגים את פונקציית המפרט החדשה עם הפונקציה הראשית _Specs כדי שהיא תהיה זמינה באמצעות המזהה הייחודי שלה בבק-אנד.

דוגמה לרישום (_ExampleSpec)

הקוד הבא מתוך litert_device_common.bzl ממחיש איך נרשם המאיץ example:

def _ExampleSpec():
    return {
        # The unique backend ID
        "example": BackendSpec(
            id = "example",
            libs = [
                # Dispatch Library and how to find it on device
                ("//third_party/odml/litert/litert/vendors/examples:libLiteRtDispatch_Example.so", "LD_LIBRARY_PATH"),
                # Compiler Plugin Library
                ("//third_party/odml/litert/litert/vendors/examples:libLiteRtCompilerPlugin_Example.so", "LD_LIBRARY_PATH"),
            ],
            plugin = "libLiteRtCompilerPlugin_Example.so",
            dispatch = "libLiteRtDispatch_Example.so",
        ),
    }

# ... (Other specs are defined here)

def _Specs(name):
    # Your new spec function must be included here
    return (_QualcommSpec() | _GoogleTensorSpec() | _MediatekSpec() | _CpuSpec() | _GpuSpec() | _ExampleSpec())[name]

שימוש בתכונת ההרשמה ב-litert_device_exec

אחרי ההרשמה, משתמשים בפקודות המאקרו litert_device_exec ובפקודות מאקרו קשורות עם הפקודה החדשה backend_id. המאקרו הזה מאגד באופן אוטומטי את הספריות הנדרשות ואת כל קובצי הנתונים שצוינו עם קובץ הבינארי של היעד.

cc_binary(
    name = "example_bin",
    srcs = ["example_bin.cc"],
)

litert_device_exec(
    name = "example_bin_device",
    backend_id = "example",  # Uses the libraries registered under "example"
    data = [
        "//third_party/odml/litert/litert/test:testdata/constant_output_tensor.tflite",
    ],
    target = ":example_bin",
)

הפעלת היעד הזה (bazel run ... :example_bin_device) תגרום לפעולות הבאות:

  1. יוצרים את הקובץ הבינארי example_bin C++.
  2. מעבירים את הקובץ הבינארי, libLiteRtDispatch_Example.so, libLiteRtCompilerPlugin_Example.so ואת הקובץ .tflite למכשיר.
  3. מריצים את הקובץ הבינארי באמצעות adb shell.

הערה לגבי נתיבי מכשירים: המיקום הקנוני של קבצים במכשיר משקף את עץ קובצי ההרצה של Bazel, באופן ספציפי /data/local/tmp/runfiles/runfiles_relative_path. סקריפט המכשיר מטפל אוטומטית בהגדרת הנתיבים המתאימים ל-linker הדינמי.

מצב קומפילציה (AOT)

במאיצים שתומכים בשלב הקימפול מראש (AOT), אפשר להפעיל את ATS במצב קימפול ייעודי.

  • מטרה: המצב הזה מיועד להפעלה בתחנת עבודה (מחשב מארח), ולא במכשיר היעד. הוא אוסף את המודלים עבור החומרה המיועדת שצוינה בלי להפעיל אותם.
  • פלט: כל המודלים שעברו קומפילציה מועברים לספרייה ייעודית בתחנת העבודה.
  • הפעלה: פקודות המאקרו של ATS build יפלטו יעד ספציפי עבור aot שבו הספריות נוצרות עבור פלטפורמת המארח. אפשר להפעיל את התהליך הזה בכל קובץ בינארי באמצעות הדגל --compile_mode, אבל הוא מקושר אוטומטית לארגומנטים של בניית ה-AOT.

הרחבה עתידית

אנחנו מתכננים להרחיב את החבילה כך שתכלול בדיקות ייעודיות לפעולות (ops) בודדות, בנוסף למודלים מלאים.