إصدارات مشغل LiteRT

يصف هذا المستند مخطّط إصدارات عمليات LiteRT. تتيح ميزة "إصدارات العمليات" للمطوّرين إضافة وظائف ومعلمات جديدة إلى العمليات الحالية. بالإضافة إلى ذلك، تضمن هذه الميزة ما يلي:

  • التوافق مع الإصدارات السابقة: يجب أن يتعامل تطبيق LiteRT الجديد مع ملف نموذج قديم.
  • التوافق مع الإصدارات المستقبلية: من المفترض أن يتعامل تنفيذ LiteRT القديم مع ملف نموذج جديد تم إنشاؤه بواسطة الإصدار الجديد من المحوِّل، ما دامت ميزات جديدة لا يتم استخدامها.
  • رصد عدم التوافق في المستقبل: إذا كان تطبيق LiteRT قديمًا يق read قراءة نموذج جديد يحتوي على إصدار جديد من عملية غير متوافقة، من المفترض أن يُبلغ عن الخطأ.

مثال: إضافة تمدد إلى التفاف من حيث العمق

يوضّح الجزء المتبقّي من هذا المستند إصدارات العمليات في TFLite من خلال توضيح كيفية إضافة مَعلمات التمدد إلى عملية التفاف متعامد في العمق.

لا يُشترط معرفة كيفية التمدد لفهم هذا المستند. يُرجى العلم أنّه:

  • ستتم إضافة مَعلمتَين عدديتين جديدتَين: dilation_width_factor و dilation_height_factor.
  • إنّ نوى التفاف الالتفافية القديمة التي لا تتيح توسيع النطاق تعادل ضبط عوامل توسيع النطاق على 1.

تغيير مخطّط FlatBuffer

لإضافة مَعلمات جديدة إلى عملية، غيِّر جدول الخيارات في lite/schema/schema.fbs.

على سبيل المثال، يبدو جدول خيارات "التفافة التجميعية في العمق" على النحو التالي:

table DepthwiseConv2DOptions {
  padding:Padding;
  stride_w:int;
  stride_h:int;
  depth_multiplier:int;
  fused_activation_function:ActivationFunctionType;
}

عند إضافة مَعلمات جديدة:

  • أضِف تعليقات توضّح المَعلمات المتوافقة مع كل إصدار.
  • عندما يحصل التنفيذ الجديد على القيم التلقائية للمَعلمات التي تمت إضافتها حديثًا، من المفترض أن يعمل بالطريقة نفسها تمامًا التي يعمل بها التنفيذ القديم.

سيظهر الجدول على النحو التالي بعد إضافة المَعلمات الجديدة:

table DepthwiseConv2DOptions {
  // Parameters for DepthwiseConv version 1 or above.
  padding:Padding;
  stride_w:int;
  stride_h:int;
  depth_multiplier:int;
  fused_activation_function:ActivationFunctionType;
  // Parameters for DepthwiseConv version 2 or above.
  dilation_w_factor:int = 1;
  dilation_h_factor:int = 1;
}

يجب إعادة إنشاء الملف lite/schema/schema_generated.h للملف الجديد بالتنسيق.

تغيير بنية C وتنفيذ النواة

في LiteRT، يتم فصل تنفيذ النواة عن تعريف FlatBuffer. تقرأ النوى المَعلمة من بنى C المحدّدة في lite/c/builtin_op_data.h.

في ما يلي مَعلمة التفاف الالتفاف العمقي الأصلية:

typedef struct {
  TfLitePadding padding;
  int stride_width;
  int stride_height;
  int depth_multiplier;
  TfLiteFusedActivation activation;
} TfLiteDepthwiseConvParams;

كما هو الحال مع مخطّط FlatBuffer، أضِف تعليقات تشير إلى المَعلمات التي يمكن استخدامها بدءًا من الإصدار المحدّد. تظهر النتيجة أدناه:

typedef struct {
  // Parameters for DepthwiseConv version 1 or above.
  TfLitePadding padding;
  int stride_width;
  int stride_height;
  int depth_multiplier;
  TfLiteFusedActivation activation;
  // Parameters for DepthwiseConv version 2 or above.
  int dilation_width_factor;
  int dilation_height_factor;
} TfLiteDepthwiseConvParams;

يُرجى أيضًا تغيير تنفيذ kernel لقراءة المَعلمات المُضافة حديثًا من بنى C. تم حذف التفاصيل هنا.

تغيير رمز قراءة FlatBuffer

يمكنك العثور على منطق قراءة FlatBuffer وإنشاء بنية C في lite/core/api/flatbuffer_conversions.cc.

عدِّل الملف لمعالجة المَعلمات الجديدة، كما هو موضّح أدناه:

TfLiteStatus ParseDepthwiseConv2D(const Operator* op,
                                  ErrorReporter* error_reporter,
                                  BuiltinDataAllocator* allocator,
                                  void** builtin_data) {
  CheckParsePointerParams(op, error_reporter, allocator, builtin_data);

  SafeBuiltinDataAllocator safe_allocator(allocator);

  std::unique_ptr<TfLiteDepthwiseConvParams,
                  SafeBuiltinDataAllocator::BuiltinDataDeleter>
      params = safe_allocator.Allocate<TfLiteDepthwiseConvParams>();
  TF_LITE_ENSURE(error_reporter, params != nullptr);

  const DepthwiseConv2DOptions* schema_params =
      op->builtin_options_as_DepthwiseConv2DOptions();

  if (schema_params != nullptr) {
    params->padding = ConvertPadding(schema_params->padding());
    params->stride_width = schema_params->stride_w();
    params->stride_height = schema_params->stride_h();
    params->depth_multiplier = schema_params->depth_multiplier();
    params->activation =
        ConvertActivation(schema_params->fused_activation_function());

    params->dilation_width_factor = schema_params->dilation_w_factor();
    params->dilation_height_factor = schema_params->dilation_h_factor();
  }

  *builtin_data = params.release();
  return kTfLiteOk;
}

ليس من الضروري التحقّق من إصدار المشغّل هنا. عندما يقرأ التنفيذ الجديد ملف نموذج قديم لا يتضمّن عوامل التمدد، سيستخدم القيمة 1 كقيمة تلقائية، وسيعمل نواة التنفيذ الجديدة بشكلٍ متسق مع نواة التنفيذ القديمة.

تغيير تسجيل النواة

يقدّم MutableOpResolver (الذي تم تحديده في lite/mutable_op_resolver.h) بعض الدوالّ لتسجيل نوى العمليات. الحد الأدنى والحد الأقصى للإصدار هما 1 بشكلٍ تلقائي:

void AddBuiltin(tflite::BuiltinOperator op, TfLiteRegistration* registration,
                int min_version = 1, int max_version = 1);
void AddCustom(const char* name, TfLiteRegistration* registration,
               int min_version = 1, int max_version = 1);

يتم تسجيل العمليات المضمّنة في lite/kernels/register.cc. في هذا المثال، نفّذنا نواة عمليات جديدة يمكنها التعامل مع الإصدارَين 1 و 2 من DepthwiseConv2D، لذا نحتاج إلى تغيير هذا السطر:

AddBuiltin(BuiltinOperator_DEPTHWISE_CONV_2D, Register_DEPTHWISE_CONV_2D());

إلى:

AddBuiltin(BuiltinOperator_DEPTHWISE_CONV_2D, Register_DEPTHWISE_CONV_2D(),
             /* min_version = */ 1,
             /* max_version = */ 2);

تغيير إصدار TFLite op

الخطوة التالية هي جعل TFLite تعبئ الحد الأدنى من الإصدار المطلوب لتنفيذ العملية. في هذا المثال، يعني ذلك ما يلي:

  • املأ version=1 عندما تكون جميع عوامل التمدد تساوي 1.
  • يجب تعبئة version=2 في حال عدم توفّر قيمة أخرى.

عدِّل دالة GetBuiltinOperatorVersion لعامل التشغيل في lite/tools/versioning/op_version.cc عن طريق إضافة الإصدار الجديد إلى حالة DepthwiseConv2D:

case BuiltinOperator_DEPTHWISE_CONV_2D:
  auto depthwise_conv_params =
      reinterpret_cast<TfLiteDepthwiseConvParams*>(op_sig.builtin_data);
  TFLITE_DCHECK(depthwise_conv_params != nullptr);
  if (depthwise_conv_params->dilation_width_factor != 1 ||
       depthwise_conv_params->dilation_height_factor != 1) {
    return 2;
  }
  return 1;

تعديل خريطة إصدارات مشغّلي شبكة الجوّال

الخطوة الأخيرة هي إضافة معلومات الإصدار الجديد إلى خريطة إصدارات مشغّلي الشبكة. هذه الخطوة مطلوبة لأنّنا نحتاج إلى إنشاء الحد الأدنى من إصدار وقت التشغيل المطلوب للنموذج استنادًا إلى خريطة الإصدارات هذه.

لإجراء ذلك، عليك إضافة إدخال خريطة جديد في lite/tools/versioning/runtime_version.cc.

في هذا المثال، عليك إضافة الإدخال التالي إلى op_version_map:

{ {BuiltinOperator_DEPTHWISE_CONV_2D, 2}, %CURRENT_RUNTIME_VERSION%}

حيث يتوافق %CURRENT_RUNTIME_VERSION% مع إصدار وقت التشغيل الحالي المحدَّد في release_version.h.

تنفيذ التفويض

يوفّر LiteRT واجهة برمجة تطبيقات للتفاويض تتيح تفويض العمليات إلى الخلفيات في الأجهزة. في دالة Prepare للوكيل، تحقّق مما إذا كان الإصدار متوافقًا مع كل عقدة في رمز التفويض.

const int kMaxVersion = 1;
TfLiteNode* node;
TfLiteRegistration* registration = nullptr;
TF_LITE_ENSURE_STATUS(context->GetNodeAndRegistration(context, node_index, &node, &registration));

if (registration->version > kMaxVersion) {
  // Reject the node if the version isn't supported.
}

هذا مطلوب حتى إذا كانت التفويضات لا تتوافق إلا مع عمليات الإصدار 1، حتى تتمكّن التفويضات من رصد عدم التوافق عند الحصول على عملية إصدار أعلى.