הוספת מטא-נתונים למודלים של LiteRT

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

כל המודלים של התמונות פורסמו ב-Kaggle המודלים מאוכלסים מטא-נתונים.

מודל עם פורמט מטא-נתונים

model_with_metadata
איור 1. מודל TFLite עם מטא-נתונים וקבצים משויכים.

המטא-נתונים של מודל מוגדרים metadata_schema.fbs, A FlatBuffer חדש. כפי שמוצג באיור 1, הוא מאוחסן מטא-נתונים שדה במודל TFLite Schema.org, בשם, "TFLITE_METADATA". חלק מהמודלים מגיעים עם קבצים משויכים, כמו תווית סיווג, . הקבצים האלה משורשרים לסוף קובץ המודל המקורי כקובץ ZIP באמצעות "append" של ZipFile מצב ('a'). TFLite כלי התרגום יכול לעיין בפורמט הקובץ החדש באותו אופן כמו קודם. ראו חבילה את הקבצים המשויכים כדי לקבל מידע נוסף.

בהוראות שבהמשך מוסבר איך לאכלס, להמחיש ולקרוא מטא-נתונים.

הגדרת כלי המטא-נתונים

לפני הוספת מטא-נתונים למודל, תצטרך לתכנת בשפת Python לסביבה להרצת TensorFlow. יש מדריך מפורט תוכלו להגדיר זאת כאן.

אחרי שמגדירים את סביבת התכנות Python, צריך להתקין כלים נוספים:

pip install tflite-support

הכלים למטא-נתונים של LiteRT תומכים ב-Python 3.

הוספת מטא-נתונים באמצעות Flatbuffers Python API

המטא-נתונים של המודל כוללים שלושה חלקים schema:

  1. מידע על המודל – תיאור כללי של המודל ופריטים כמו תנאי רישיון. צפייה ModelMetadata.
    1. מידע על קלט – תיאור של הקלט והעיבוד מראש כמו נירמול. צפייה SubGraphMetadata.input_tensor_metadata
      1. פרטי פלט – תיאור של הפלט נדרש לאחר עיבוד, למשל מיפוי לתוויות. צפייה SubGraphMetadata.output_tensor_metadata.

בשלב הזה, LiteRT תומך רק בתת-תרשים יחיד, מחולל קוד LiteRT וגם Binding של Android Studio ML פיצ'ר ישתמש ב-ModelMetadata.name וב-ModelMetadata.description, במקום SubGraphMetadata.name ו-SubGraphMetadata.description, בתצוגה מטא-נתונים ויצירת קוד.

סוגי קלט / פלט נתמכים

מטא-נתונים של LiteRT לקלט ולפלט לא מעוצבים עם של מודלים ספציפיים אלא סוגי קלט ופלט. לא משנה מה שהמודל פועל באופן פונקציונלי, כל עוד סוגי הקלט והפלט את הדברים הבאים או שילוב שלהם, יש תמיכה ב-TensorFlow מטא-נתונים במצב Lite:

  • תכונה – מספרים שהם מספרים שלמים לא חתומים או מספרים מסוג float32.
  • תמונה – מטא-נתונים תומכים כרגע בתמונות RGB ובגווני אפור.
  • תיבה מתוחכמת - תיבות תוחמות עם צורה מלבנית. הסכימה תומכת ב-a מגוון של מספור סכמות.

אורזים את הקבצים המשויכים

לדגמי LiteRT עשויים להיות קבצים משויכים שונים. לדוגמה, למודלים של שפה טבעית יש בדרך כלל קובצי vocab שממפים קטעי מילים למילה מזהים; מודלים של סיווג יכולים לכלול קובצי תוויות שמציינים קטגוריות של אובייקטים. המודל לא יפעל כראוי בלי הקבצים המשויכים (אם יש כאלה).

עכשיו אפשר לצרף את הקבצים המשויכים למודל באמצעות המטא-נתונים בשפת Python. מודל LiteRT החדש הופך לקובץ ZIP שמכיל גם את המודל וגם את הקבצים שמשויכים אליו. אפשר לפרוק אותו באמצעות מיקוד נפוץ הכלים שלנו. פורמט המודל החדש הזה ממשיך להשתמש באותה סיומת קובץ, .tflite. הוא תואם ל-framework ולתרגום שיחה פעילה של TFLite. מידע נוסף זמין בקטע מטא-נתונים של חבילות וקבצים משויכים לפרטים נוספים.

אפשר לתעד את פרטי הקובץ המשויכים במטא-נתונים. בהתאם ל: סוג הקובץ והמקום שאליו הקובץ מצורף אליו (למשל, ModelMetadata, SubGraphMetadata ו-TensorMetadata), קוד LiteRT של Android והמחולל הזה יכול להיות תואם לפניו או לפוסט מעובד באופן אוטומטי לאובייקט. למידע על <שימוש ב-Codegen> קטע של כל קובץ שותף סוג בסכימה לקבלת פרטים נוספים.

פרמטרים של נירמול וקונטיזציה

נירמול הוא שיטה נפוצה לעיבוד נתונים מראש בלמידת מכונה. מטרת הנירמול היא לשנות את הערכים לסולם משותף, עיוותים של טווחי הערכים.

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

מבחינת עיבוד מראש ולאחר עיבוד, נירמול וכימות הם שני שלבים בלתי תלויים. הנה הפרטים.

נירמול כימות

דוגמה של ערכי הפרמטרים קלט תמונה ב- MobileNet לנתונים צפים ו- במודלים של כמות, בהתאמה.
מודל צף:
- ממוצע: 127.5
- std: 127.5
מודל כמות:
- ממוצע: 127.5
- std: 127.5
מודל צף:
- אפס נקודה: 0
- סולם: 1.0
מודל כמות:
- Z0Point: 128.0
- היקף:0.0078125f




מתי להפעיל?


שיטות קלט: אם קלט מתבצע נירמול של הנתונים אימון, נתונים של צורכי ההסקה כדי לנרמל בהתאם.
פלט: פלט לא יהיו נתונים מנורמלת באופן כללי.
מודלים צפופים ואין צורך לכימות.
מודל כמותי עשוי או שלא נדרש קוונטיזציה בקטע 'pre/post' בעיבוד. תלוי בסוג הנתונים את רכיבי הקלט/פלט (tensors) של הקלט.
- פרמטרים מסוג צף: לא קוונטיזציה בקטע 'pre/post' נדרש עיבוד. Quant op ו-dequant הן מוטמע במודל גרפי.
- int8/uint8 tensors: יש צורך לכימות לפני/אחרי עיבוד.


נוסחה


organic_input = (קלט - ממוצע) / std
יצירת כמות לקלט:
q = f / סולם + zeroPoint
הכין ל- פלט:
f = (q - zeroPoint) * קנה מידה

איפה נמצאים פרמטרים
מלא על ידי יוצר המודלים ומאוחסנות במודל מטא נתונים, כפי NormalizationOptions מילוי אוטומטי על ידי ממיר TFLite, מאוחסנים במודל tflite חדש.
איך מקבלים את הפרמטרים? דרך API של MetadataExtractor [2] דרך ה-TFLite API של Tensor [1] או באמצעות ממשק API של MetadataExtractor [2]
ציפה וכמות של מודלים דומים ערך? כן, מספר ממשי (float) וכמותי למודלים יש את אותם נירמול פרמטרים לא, המודל הצף ואין צורך לכימות.
האם אתם משתמשים בקוד TFLite מחולל או Android קישור ללמידת מכונה של Studio ליצור באופן אוטומטי בעיבוד הנתונים?
כן

כן

[1] LiteRT Java API ו-LiteRT C++ API.
[2] הספרייה לחילוץ מטא-נתונים

כשמעבדים נתוני תמונה במודלים של uint8, יש לבצע נירמול וכימות שלפעמים מדלגים עליהן. אפשר לעשות זאת כשערכי הפיקסלים נמצאים בטווח של [0, 255]. אך באופן כללי, עליך לעבד את הנתונים תמיד בהתאם פרמטרים של נירמול וכמות, במקרים הרלוונטיים.

דוגמאות

תוכלו לראות דוגמאות לאופן שבו יש לאכלס את המטא-נתונים כאן:

סיווג תמונות

הורדת הסקריפט כאן שמאכלס את המטא-נתונים mobilenet_v1_0.75_160_quantized.tflite. מריצים את הסקריפט כך:

python ./metadata_writer_for_image_classifier.py \
    --model_file=./model_without_metadata/mobilenet_v1_0.75_160_quantized.tflite \
    --label_file=./model_without_metadata/labels.txt \
    --export_directory=model_with_metadata

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

ניתוח מעמיק של הדוגמה לסיווג תמונות

פרטי דגם

מטא-נתונים מתחילים ביצירת פרטי מודל חדש:

from tflite_support import flatbuffers
from tflite_support import metadata as _metadata
from tflite_support import metadata_schema_py_generated as _metadata_fb

""" ... """
"""Creates the metadata for an image classifier."""

# Creates model info.
model_meta = _metadata_fb.ModelMetadataT()
model_meta.name = "MobileNetV1 image classifier"
model_meta.description = ("Identify the most prominent object in the "
                          "image from a set of 1,001 categories such as "
                          "trees, animals, food, vehicles, person etc.")
model_meta.version = "v1"
model_meta.author = "TensorFlow"
model_meta.license = ("Apache License. Version 2.0 "
                      "http://www.apache.org/licenses/LICENSE-2.0.")

פרטי הקלט / פלט

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

# Creates input info.
input_meta = _metadata_fb.TensorMetadataT()

# Creates output info.
output_meta = _metadata_fb.TensorMetadataT()

קלט תמונה

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

input_meta.name = "image"
input_meta.description = (
    "Input image to be classified. The expected image is {0} x {1}, with "
    "three channels (red, blue, and green) per pixel. Each value in the "
    "tensor is a single byte between 0 and 255.".format(160, 160))
input_meta.content = _metadata_fb.ContentT()
input_meta.content.contentProperties = _metadata_fb.ImagePropertiesT()
input_meta.content.contentProperties.colorSpace = (
    _metadata_fb.ColorSpaceType.RGB)
input_meta.content.contentPropertiesType = (
    _metadata_fb.ContentProperties.ImageProperties)
input_normalization = _metadata_fb.ProcessUnitT()
input_normalization.optionsType = (
    _metadata_fb.ProcessUnitOptions.NormalizationOptions)
input_normalization.options = _metadata_fb.NormalizationOptionsT()
input_normalization.options.mean = [127.5]
input_normalization.options.std = [127.5]
input_meta.processUnits = [input_normalization]
input_stats = _metadata_fb.StatsT()
input_stats.max = [255]
input_stats.min = [0]
input_meta.stats = input_stats

פלט התווית

אפשר למפות את התווית למשתנה פלט באמצעות קובץ משויך באמצעות TENSOR_AXIS_LABELS

# Creates output info.
output_meta = _metadata_fb.TensorMetadataT()
output_meta.name = "probability"
output_meta.description = "Probabilities of the 1001 labels respectively."
output_meta.content = _metadata_fb.ContentT()
output_meta.content.content_properties = _metadata_fb.FeaturePropertiesT()
output_meta.content.contentPropertiesType = (
    _metadata_fb.ContentProperties.FeatureProperties)
output_stats = _metadata_fb.StatsT()
output_stats.max = [1.0]
output_stats.min = [0.0]
output_meta.stats = output_stats
label_file = _metadata_fb.AssociatedFileT()
label_file.name = os.path.basename("your_path_to_label_file")
label_file.description = "Labels for objects that the model can recognize."
label_file.type = _metadata_fb.AssociatedFileType.TENSOR_AXIS_LABELS
output_meta.associatedFiles = [label_file]

יצירת Flatbuffers של המטא-נתונים

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

# Creates subgraph info.
subgraph = _metadata_fb.SubGraphMetadataT()
subgraph.inputTensorMetadata = [input_meta]
subgraph.outputTensorMetadata = [output_meta]
model_meta.subgraphMetadata = [subgraph]

b = flatbuffers.Builder(0)
b.Finish(
    model_meta.Pack(b),
    _metadata.MetadataPopulator.METADATA_FILE_IDENTIFIER)
metadata_buf = b.Output()

חבילות מטא-נתונים וקבצים משויכים במודל

לאחר היצירה של Flatbuffers של המטא-נתונים, המטא-נתונים וקובץ התווית נוצרים נכתבו בקובץ ה-TFLite באמצעות השיטה populate:

populator = _metadata.MetadataPopulator.with_model_file(model_file)
populator.load_metadata_buffer(metadata_buf)
populator.load_associated_files(["your_path_to_label_file"])
populator.populate()

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

הצגה חזותית של מטא-נתונים

אפשר להשתמש ב-Netron כדי להמחיש מטא-נתונים, או לקרוא את המטא-נתונים ממודל LiteRT בקובץ JSON בפורמט MetadataDisplayer:

displayer = _metadata.MetadataDisplayer.with_model_file(export_model_path)
export_json_file = os.path.join(FLAGS.export_directory,
                                os.path.splitext(model_basename)[0] + ".json")
json_file = displayer.get_metadata_json()
# Optional: write out the metadata as a json file
with open(export_json_file, "w") as f:
  f.write(json_file)

ב-Android Studio יש גם תמיכה בהצגת מטא-נתונים באמצעות למידת מכונה של Android Studio קישור .

ניהול גרסאות של מטא-נתונים

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

המספר לניהול גרסאות סמנטי

הגרסאות של סכימת המטא-נתונים מנוהלת על ידי ניהול גרסאות סמנטיות number, כמו MAJOR.MINOR.PATCH. הוא עוקב אחרי שינויים בסכימה בהתאם לכללים כאן. ההיסטוריה של שדות נוספה אחרי גרסה 1.0.0.

זיהוי הקובץ Flatbuffers

ניהול גרסאות סמנטי מבטיח תאימות אם פועלים לפי הכללים, אבל לא מרמזת על חוסר תאימות אמיתי. כשמעלים את המספר הראשי, הוא לאו דווקא אומר שהתאימות לאחור מנותקת. לכן אנחנו להשתמש בקובץFlatbuffers מזהה, file_identifier, כדי לציין את התאימות האמיתית של סכימת המטא-נתונים. מזהה הקובץ הוא באורך של 4 תווים בדיוק. הוא קבוע לסכימת מטא-נתונים מסוימת ולא עשוי להשתנות על ידי המשתמשים. אם התאימות לאחור של סכימת המטא-נתונים צריך להיות שבור מסיבה כלשהי, file_identifier יפרץ, לדוגמה, מ-M001 עד M002. הערך של File_identifier צפוי להשתנות הרבה יותר לעיתים קרובות יותר מה-Metadata_version.

הגרסה המינימלית הדרושה של מנתח המטא-נתונים

הכלי המינימלי לניתוח מטא-נתונים version היא הגרסה המינימלית של מנתח המטא-נתונים (הקוד שנוצר על ידי Flatbuffers) יכול לקרוא את Flatbuffers של המטא-נתונים במלואם. למעשה, הגרסה מספר הגרסה הגדול ביותר מבין הגרסאות של כל השדות שאוכלסו, הגרסה התואמת הקטנה ביותר שצוינה על ידי מזהה הקובץ. המינימום הגרסה הדרושה של מנתח המטא-נתונים מאוכלסת באופן אוטומטי על ידי MetadataPopulator כשהמטא-נתונים מאוכלסים במודל TFLite. לצפייה מחלץ מטא-נתונים למידע נוסף על האופן שבו נעשה שימוש בגרסה המינימלית הדרושה של מנתח המטא-נתונים.

קריאת המטא-נתונים ממודלים

ספריית חילוץ מטא-נתונים היא כלי נוח לקרוא את המטא-נתונים המשויכים ממודלים שונים בפלטפורמות שונות (עיינו במאמר Java version וגם C++ גרסה). אפשר ליצור כלי משלכם לחילוץ מטא-נתונים בשפות אחרות באמצעות ספריית Flatbuffers.

קריאת המטא-נתונים ב-Java

כדי להשתמש בספרייה של 'כלי לחילוץ מטא-נתונים' באפליקציה ל-Android, מומלץ להשתמש קובץ ה-AAR של LiteRT Metadata AAR שמתארח בכתובת MavenCentral. הוא מכיל את המחלקה MetadataExtractor, וגם את FlatBuffers Java קישורים עבור המטא-נתונים סכימה ואת המודל של הסכימה.

אפשר לציין זאת ביחסי התלות של build.gradle באופן הבא:

dependencies {
    implementation 'org.tensorflow:tensorflow-lite-metadata:0.1.0'
}

כדי להשתמש בתמונות מצב מדי לילה, צריך להוסיף תמונת מצב של Sonatype מאגר הנתונים.

אפשר לאתחל אובייקט MetadataExtractor עם ByteBuffer שמצביע למודל:

public MetadataExtractor(ByteBuffer buffer);

ByteBuffer צריך להישאר ללא שינוי כל משך החיים של אובייקט MetadataExtractor. האתחול עלול להיכשל אם הקובץ Flatbuffers מזהה המטא-נתונים של המודל לא תואם את המזהה של מנתח המטא-נתונים. צפייה ניהול גרסאות של מטא-נתונים לקבלת מידע נוסף.

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

public final boolean isMinimumParserVersionSatisfied();

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

public boolean hasMetadata();

MetadataExtractor מספק פונקציות נוחות כדי לקבל רכיבי tensor של קלט/פלט מטא-נתונים. לדוגמה,

public int getInputTensorCount();
public TensorMetadata getInputTensorMetadata(int inputIndex);
public QuantizationParams getInputTensorQuantizationParams(int inputIndex);
public int[] getInputTensorShape(int inputIndex);
public int getoutputTensorCount();
public TensorMetadata getoutputTensorMetadata(int inputIndex);
public QuantizationParams getoutputTensorQuantizationParams(int inputIndex);
public int[] getoutputTensorShape(int inputIndex);

למרות שמודל ה-LiteRT סכימה תומך במספר תתי-תרשימים, בשלב זה, תרגום של TFLite תומך רק בתרשים משנה יחיד. לכן, MetadataExtractor לא ישמיט אינדקס משנה כקלט ב-methods שלו.

קריאת הקבצים המשויכים ממודלים

מודל LiteRT עם המטא-נתונים והקבצים המשויכים הוא בעצם קובץ ZIP שאפשר לפרוק אותו בכלי ZIP נפוצים כדי לקבל את הקבצים המשויכים אליו. לדוגמה, אפשר לפרוס את קובץ ה-ZIP mobilenet_v1_0.75_160_quantized ומחלצים את קובץ התווית מהמודל באופן הבא:

$ unzip mobilenet_v1_0.75_160_quantized_1_metadata_1.tflite
Archive:  mobilenet_v1_0.75_160_quantized_1_metadata_1.tflite
 extracting: labels.txt

אפשר גם לקרוא את הקבצים המשויכים באמצעות הספרייה 'חילוץ מטא-נתונים'.

ב-Java, מעבירים את שם הקובץ אל MetadataExtractor.getAssociatedFile method:

public InputStream getAssociatedFile(String fileName);

באופן דומה, ב-C++ אפשר לעשות זאת באמצעות ה-method, ModelMetadataExtractor::GetAssociatedFile:

tflite::support::StatusOr<absl::string_view> GetAssociatedFile(
      const std::string& filename) const;