افزودن متادیتا به مدل های LiteRT

فراداده LiteRT استانداردی برای توصیف مدل ارائه می‌دهد. فراداده منبع مهمی از دانش در مورد عملکرد مدل و اطلاعات ورودی/خروجی آن است. فراداده شامل هر دو مورد است

تمام مدل‌های تصویری منتشر شده در Kaggle Models با فراداده پر شده‌اند.

مدل با فرمت فراداده

مدل_با_فراداده
شکل ۱. مدل TFLite به همراه فراداده و فایل‌های مرتبط.

فراداده مدل در metadata_schema.fbs ، یک فایل FlatBuffer، تعریف شده است. همانطور که در شکل 1 نشان داده شده است، در فیلد فراداده طرحواره مدل TFLite ، تحت نام "TFLITE_METADATA" ذخیره می‌شود. برخی از مدل‌ها ممکن است با فایل‌های مرتبط، مانند فایل‌های برچسب طبقه‌بندی، همراه باشند. این فایل‌ها با استفاده از حالت "append" در ZipFile (حالت 'a' ) به انتهای فایل مدل اصلی به صورت ZIP متصل می‌شوند. مفسر TFLite می‌تواند فرمت فایل جدید را به همان روش قبلی مصرف کند. برای اطلاعات بیشتر به بخش " Pack the associated files" مراجعه کنید.

دستورالعمل زیر را در مورد نحوه پر کردن، تجسم و خواندن فراداده‌ها مشاهده کنید.

ابزارهای ابرداده را تنظیم کنید

قبل از افزودن فراداده به مدل خود، به یک محیط برنامه‌نویسی پایتون برای اجرای TensorFlow نیاز دارید. یک راهنمای دقیق در مورد نحوه تنظیم آن در اینجا وجود دارد.

پس از راه‌اندازی محیط برنامه‌نویسی پایتون، باید ابزارهای اضافی را نصب کنید:

pip install tflite-support

ابزار متادیتای LiteRT از پایتون ۳ پشتیبانی می‌کند.

افزودن فراداده با استفاده از API پایتون Flatbuffers

سه بخش برای ابرداده مدل در طرحواره وجود دارد:

  1. اطلاعات مدل - شرح کلی مدل و همچنین مواردی مانند شرایط مجوز. به ModelMetadata مراجعه کنید. 2. اطلاعات ورودی - شرح ورودی‌ها و پیش‌پردازش‌های مورد نیاز مانند نرمال‌سازی. به SubGraphMetadata.input_tensor_metadata مراجعه کنید. 3. اطلاعات خروجی - شرح خروجی و پس‌پردازش‌های مورد نیاز مانند نگاشت به برچسب‌ها. به SubGraphMetadata.output_tensor_metadata مراجعه کنید.

از آنجایی که LiteRT در حال حاضر فقط از یک زیرگراف پشتیبانی می‌کند، مولد کد LiteRT و ویژگی ML Binding اندروید استودیو هنگام نمایش فراداده و تولید کد، به جای SubGraphMetadata.name و SubGraphMetadata.description از ModelMetadata.name و ModelMetadata.description استفاده خواهند کرد.

انواع ورودی/خروجی پشتیبانی شده

فراداده‌های LiteRT برای ورودی و خروجی با در نظر گرفتن انواع مدل خاص طراحی نشده‌اند، بلکه بیشتر با در نظر گرفتن انواع ورودی و خروجی طراحی شده‌اند. فرقی نمی‌کند که مدل از نظر عملکردی چه کاری انجام می‌دهد، تا زمانی که انواع ورودی و خروجی شامل موارد زیر یا ترکیبی از موارد زیر باشد، توسط فراداده‌های TensorFlow Lite پشتیبانی می‌شود:

  • ویژگی - اعدادی که عدد صحیح بدون علامت یا عدد اعشاری float32 هستند.
  • تصویر - متادیتا در حال حاضر از تصاویر RGB و خاکستری پشتیبانی می‌کند.
  • جعبه‌ی محصورکننده - جعبه‌های محصورکننده‌ی مستطیلی شکل. این طرح از انواع طرح‌های شماره‌گذاری پشتیبانی می‌کند.

فایل‌های مرتبط را بسته‌بندی کنید

مدل‌های LiteRT ممکن است با فایل‌های مرتبط مختلفی ارائه شوند. برای مثال، مدل‌های زبان طبیعی معمولاً فایل‌های واژگانی دارند که قطعات کلمه را به شناسه‌های کلمه نگاشت می‌کنند؛ مدل‌های طبقه‌بندی ممکن است فایل‌های برچسبی داشته باشند که دسته‌های اشیاء را نشان می‌دهند. بدون فایل‌های مرتبط (در صورت وجود)، یک مدل به خوبی کار نخواهد کرد.

اکنون می‌توان فایل‌های مرتبط را از طریق کتابخانه پایتون فراداده با مدل همراه کرد. مدل جدید LiteRT به یک فایل زیپ تبدیل می‌شود که شامل مدل و فایل‌های مرتبط است. می‌توان آن را با ابزارهای رایج زیپ باز کرد. این فرمت مدل جدید همچنان از همان پسوند فایل .tflite استفاده می‌کند. این فرمت با چارچوب و مفسر TFLite موجود سازگار است. برای جزئیات بیشتر به بخش «بسته‌بندی فراداده و فایل‌های مرتبط در مدل» مراجعه کنید.

اطلاعات فایل مرتبط را می‌توان در فراداده ثبت کرد. بسته به نوع فایل و جایی که فایل به آن متصل شده است (یعنی ModelMetadata ، SubGraphMetadata و TensorMetadataمولد کد اندروید LiteRT می‌تواند پردازش‌های پیش/پس‌پردازش مربوطه را به طور خودکار بر روی شیء اعمال کند. برای جزئیات بیشتر به بخش <Codegen usage> هر نوع فایل مرتبط در طرحواره مراجعه کنید.

پارامترهای نرمال‌سازی و کوانتیزاسیون

نرمال‌سازی یک تکنیک پیش‌پردازش داده رایج در یادگیری ماشین است. هدف از نرمال‌سازی، تغییر مقادیر به یک مقیاس مشترک، بدون ایجاد تغییر در تفاوت‌های موجود در محدوده مقادیر است.

کوانتیزاسیون مدل تکنیکی است که امکان نمایش وزن‌ها با دقت کمتر و به صورت اختیاری، فعال‌سازی‌ها را هم برای ذخیره‌سازی و هم برای محاسبه فراهم می‌کند.

از نظر پیش‌پردازش و پس‌پردازش، نرمال‌سازی و کوانتیزاسیون دو مرحله مستقل هستند. در اینجا جزئیات آمده است.

عادی‌سازی کوانتیزاسیون

مثالی از مقادیر پارامترهای تصویر ورودی در MobileNet به ترتیب برای مدل‌های float و quant.
مدل شناور :
- میانگین: ۱۲۷.۵
- انحراف معیار: ۱۲۷.۵
مدل کمی :
- میانگین: ۱۲۷.۵
- انحراف معیار: ۱۲۷.۵
مدل شناور :
- نقطه صفر: 0
- مقیاس: ۱.۰
مدل کمی :
- نقطه صفر: 128.0
- مقیاس: 0.0078125f




چه زمانی احضار کنیم؟


ورودی‌ها : اگر داده‌های ورودی در آموزش نرمال‌سازی شوند، داده‌های ورودی استنتاج نیز باید بر همین اساس نرمال‌سازی شوند.
خروجی‌ها : داده‌های خروجی به طور کلی نرمال‌سازی نخواهند شد.
مدل‌های float نیازی به کوانتیزاسیون ندارند.
مدل کوانتیزه شده ممکن است در پیش/پس پردازش نیاز به کوانتیزه شدن داشته باشد یا نداشته باشد. این بستگی به نوع داده تانسورهای ورودی/خروجی دارد.
- تانسورهای شناور: نیازی به کوانتیزاسیون در پردازش پیش/پس از پردازش نیست. عملیات کمی و عملیات غیر کمی در نمودار مدل گنجانده شده‌اند.
- تانسورهای int8/uint8: نیاز به کوانتیزاسیون در پیش/پس پردازش دارند.


فرمول


ورودی نرمال شده = (ورودی - میانگین) / انحراف معیار
کوانتیزه کردن ورودی‌ها :
q = f / مقیاس + نقطه صفر
برای خروجی‌ها، دکوانتیزه کنید :
f = (q - نقطه صفر) * مقیاس

پارامترها کجا هستند؟
توسط سازنده مدل پر شده و در متادیتای مدل، به عنوان NormalizationOptions ذخیره می‌شود. به طور خودکار توسط مبدل TFLite پر شده و در فایل مدل tflite ذخیره می‌شود.
چگونه پارامترها را بدست آوریم؟ از طریق API MetadataExtractor [2] از طریق API Tensor TFLite [1] یا از طریق API MetadataExtractor [2]
آیا مدل‌های float و quant ارزش یکسانی دارند؟ بله، مدل‌های float و quant پارامترهای نرمال‌سازی یکسانی دارند. خیر، مدل float نیازی به کوانتیزاسیون ندارد.
آیا تولیدکننده کد TFLite یا اتصال ML اندروید استودیو به طور خودکار آن را در پردازش داده تولید می‌کند؟
بله

بله

[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 از اطلاعاتی مانند فضای رنگی و اطلاعات پیش‌پردازش مانند نرمال‌سازی پشتیبانی می‌کند. ابعاد تصویر نیازی به تعیین دستی ندارد زیرا از قبل توسط شکل تانسور ورودی ارائه شده است و می‌توان آن را به طور خودکار استنباط کرد.

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، فراداده و فایل برچسب از طریق متد populate در فایل TFLite نوشته می‌شوند:

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 با استفاده از MetadataDisplayer به فرمت json بخوانید:

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)

اندروید استودیو همچنین از نمایش متادیتا از طریق ویژگی ML Binding اندروید استودیو پشتیبانی می‌کند.

نسخه‌بندی فراداده

طرحواره فراداده هم توسط شماره نسخه‌بندی معنایی، که تغییرات فایل طرحواره را ردیابی می‌کند، و هم توسط شناسه فایل Flatbuffers، که سازگاری نسخه واقعی را نشان می‌دهد، نسخه‌بندی می‌شود.

شماره نسخه‌بندی معنایی

طرحواره فراداده توسط شماره نسخه‌بندی معنایی ، مانند MAJOR.MINOR.PATCH، نسخه‌بندی می‌شود. این طرحواره تغییرات طرحواره را طبق قوانین اینجا پیگیری می‌کند. تاریخچه فیلدهای اضافه شده پس از نسخه 1.0.0 را ببینید.

شناسایی فایل Flatbuffers

Semantic versioning guarantees the compatibility if following the rules, but it does not imply the true incompatibility. When bumping up the MAJOR number, it does not necessarily mean the backward compatibility is broken. Therefore, we use the Flatbuffers file identification , file_identifier , to denote the true compatibility of the metadata schema. The file identifier is exactly 4 characters long. It is fixed to a certain metadata schema and not subject to change by users. If the backward compatibility of the metadata schema has to be broken for some reason, the file_identifier will bump up, for example, from “M001” to “M002”. File_identifier is expected to be changed much less frequently than the metadata_version.

حداقل نسخه لازم برای تجزیه‌کننده فراداده

حداقل نسخه لازم برای تجزیه‌کننده فراداده، حداقل نسخه تجزیه‌کننده فراداده (کد تولید شده توسط Flatbuffers) است که می‌تواند فراداده‌های Flatbuffers را به طور کامل بخواند. این نسخه در واقع بزرگترین شماره نسخه در بین نسخه‌های تمام فیلدهای پر شده و کوچکترین نسخه سازگار است که توسط شناسه فایل نشان داده شده است. حداقل نسخه لازم برای تجزیه‌کننده فراداده به طور خودکار توسط MetadataPopulator هنگام پر شدن فراداده در یک مدل TFLite پر می‌شود. برای اطلاعات بیشتر در مورد نحوه استفاده از حداقل نسخه لازم برای تجزیه‌کننده فراداده، به استخراج‌کننده فراداده مراجعه کنید.

خواندن متادیتا از مدل‌ها

کتابخانه‌ی Metadata Extractor ابزاری مناسب برای خواندن Metadata و فایل‌های مرتبط از یک مدل در پلتفرم‌های مختلف است (به نسخه جاوا و نسخه C++ مراجعه کنید). شما می‌توانید با استفاده از کتابخانه‌ی Flatbuffers، ابزار استخراج Metadata خود را به زبان‌های دیگر بسازید.

خواندن متادیتا در جاوا

برای استفاده از کتابخانه Metadata Extractor در برنامه اندروید خود، توصیه می‌کنیم از LiteRT Metadata AAR میزبانی شده در MavenCentral استفاده کنید. این کتابخانه شامل کلاس MetadataExtractor و همچنین اتصالات جاوا FlatBuffers برای طرحواره فراداده و طرحواره مدل است.

شما می‌توانید این مورد را در وابستگی‌های build.gradle خود به صورت زیر مشخص کنید:

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

برای استفاده از اسنپ‌شات‌های شبانه، مطمئن شوید که مخزن اسنپ‌شات Sonatype را اضافه کرده‌اید.

شما می‌توانید یک شیء MetadataExtractor را با یک ByteBuffer که به مدل اشاره می‌کند، مقداردهی اولیه کنید:

public MetadataExtractor(ByteBuffer buffer);

ByteBuffer باید در تمام طول عمر شیء MetadataExtractor بدون تغییر باقی بماند. اگر شناسه فایل Flatbuffers مربوط به فراداده مدل با شناسه تجزیه‌کننده فراداده مطابقت نداشته باشد، ممکن است مقداردهی اولیه با شکست مواجه شود. برای اطلاعات بیشتر به بخش نسخه‌بندی فراداده مراجعه کنید.

با تطبیق شناسه‌های فایل، استخراج‌کننده‌ی فراداده با موفقیت فراداده‌های تولید شده از تمام طرحواره‌های گذشته و آینده را به دلیل مکانیسم سازگاری رو به جلو و عقب Flatbuffers می‌خواند. با این حال، فیلدهای طرحواره‌های آینده را نمی‌توان توسط استخراج‌کننده‌های فراداده‌ی قدیمی‌تر استخراج کرد. حداقل نسخه‌ی تجزیه‌کننده‌ی فراداده‌ی لازم ، نشان‌دهنده‌ی حداقل نسخه‌ی تجزیه‌کننده‌ی فراداده‌ای است که می‌تواند فراداده‌ی Flatbuffers را به طور کامل بخواند. می‌توانید از روش زیر برای تأیید برآورده شدن شرط حداقل نسخه‌ی تجزیه‌کننده‌ی لازم استفاده کنید:

public final boolean isMinimumParserVersionSatisfied();

ارسال مدل بدون متادیتا مجاز است. با این حال، فراخوانی متدهایی که از متادیتا می‌خوانند، باعث خطاهای زمان اجرا می‌شود. می‌توانید با فراخوانی متد hasMetadata بررسی کنید که آیا یک مدل متادیتا دارد یا خیر:

public boolean hasMetadata();

MetadataExtractor توابع مناسبی را برای دریافت فراداده‌های تانسورهای ورودی/خروجی در اختیار شما قرار می‌دهد. برای مثال،

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 اندیس زیرگراف را به عنوان آرگومان ورودی در متدهای خود حذف می‌کند.

خواندن فایل‌های مرتبط از مدل‌ها

مدل LiteRT به همراه فراداده‌ها و فایل‌های مرتبط، اساساً یک فایل زیپ است که می‌توان آن را با ابزارهای رایج زیپ از حالت فشرده خارج کرد تا فایل‌های مرتبط به آن دسترسی پیدا کنند. برای مثال، می‌توانید 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

همچنین می‌توانید فایل‌های مرتبط را از طریق کتابخانه‌ی Metadata Extractor بخوانید.

در جاوا، نام فایل را به متد MetadataExtractor.getAssociatedFile ارسال کنید:

public InputStream getAssociatedFile(String fileName);

به طور مشابه، در ++C، این کار را می‌توان با متد ModelMetadataExtractor::GetAssociatedFile انجام داد:

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