إصدارات مشغل TensorFlow Lite

يصف هذا المستند مخطط الإصدار التشغيلي لـ TensorFlow Lite. يتيح إصدار Op للمطورين إضافة وظائف ومعلمات جديدة إلى العمليات الحالية. بالإضافة إلى ذلك، فإنه يضمن ما يلي:

  • التوافق مع الإصدارات السابقة: يجب أن يتعامل تطبيق TensorFlow Lite الجديد مع ملف نموذج قديم.
  • التوافق الأمامي: يجب أن يتعامل تطبيق TensorFlow Lite القديم مع ملف نموذج جديد تم إنتاجه بواسطة إصدار جديد من المحول، طالما لم يتم استخدام ميزات جديدة.
  • اكتشاف التوافق الأمامي: إذا قرأ تطبيق TensorFlow Lite القديم نموذجًا جديدًا يحتوي على إصدار جديد من عملية غير مدعومة، فيجب الإبلاغ عن الخطأ.

مثال: إضافة التمدد إلى الالتواء العميق

يشرح الجزء المتبقي من هذا المستند إصدار المرجع في 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 وتنفيذ النواة

في TensorFlow Lite، يتم فصل تنفيذ kernel عن تعريف 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

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

  • قم بتعبئة الإصدار = 1 عندما تكون عوامل التمدد كلها 1.
  • نشر الإصدار = 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% مع إصدار وقت التشغيل الحالي المحدد في Tensorflow/core/public/version.h .

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

يوفر TensorFlow Lite واجهة برمجة تطبيقات للتفويض تتيح تفويض العمليات إلى الواجهات الخلفية للأجهزة. في وظيفة 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 ops فقط، حتى يتمكن التفويض من اكتشاف عدم التوافق عند الحصول على إصدار أعلى.