Versionet e operatorit LiteRT

Ky dokument përshkruan skemën e versionimit op të LiteRT. Versionimi i opsionit u mundëson zhvilluesve të shtojnë funksionalitete dhe parametra të rinj në funksionet ekzistuese. Përveç kësaj, ajo garanton sa vijon:

  • Përputhshmëria e prapambetur: Implementimi i ri LiteRT duhet të trajtojë një skedar të modelit të vjetër.
  • Përputhshmëria përpara: Zbatimi i vjetër i LiteRT duhet të trajtojë një skedar modeli të ri të prodhuar nga versioni i ri i konvertuesit, për sa kohë që nuk përdoren veçori të reja.
  • Zbulimi i përpara i papajtueshmërisë: Nëse një implementim i vjetër i LiteRT lexon një model të ri që përmban një version të ri të një funksioni që nuk mbështetet, ai duhet të raportojë gabimin.

Shembull: Shtimi i zgjerimit në konvolucionin në thellësi

Pjesa tjetër e këtij dokumenti shpjegon versionin optik në TFLite duke treguar se si të shtohen parametrat e zgjerimit në operacionin e konvolucionit në thellësi.

Nuk kërkohet njohuri për zgjerimin për të kuptuar këtë dokument. Vini re se:

  • Do të shtohen 2 parametra të rinj të plotë: dilation_width_factor dhe dilation_height_factor .
  • Bërthamat e vjetra të konvolucionit në thellësi që nuk mbështesin zgjerimin janë ekuivalente me vendosjen e faktorëve të zgjerimit në 1.

Ndrysho skemën FlatBuffer

Për të shtuar parametra të rinj në një op, ndryshoni tabelën e opsioneve në lite/schema/schema.fbs .

Për shembull, tabela e opsioneve të konvolucionit në thellësi duket si kjo:

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

Kur shtoni parametra të rinj:

  • Shto komente që tregojnë se cilët parametra mbështeten nga cili version.
  • Kur zbatimi i ri merr vlerat e paracaktuara për parametrat e shtuar rishtazi, ai duhet të funksionojë saktësisht njësoj si implementimi i vjetër.

Tabela do të jetë si kjo pasi të shtohen parametrat e rinj:

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;
}

Skedari lite/schema/schema_generated.h duhet të rigjenerohet për skemën e re.

Ndryshoni strukturat C dhe zbatimin e kernelit

Në LiteRT, zbatimi i kernelit është i shkëputur nga përkufizimi FlatBuffer. Kernelet lexojnë parametrin nga strukturat C të përcaktuara në lite/c/builtin_op_data.h .

Parametri origjinal i konvolucionit në thellësi është si më poshtë:

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

Ashtu si me skemën FlatBuffer, shtoni komente që tregojnë se cilët parametra mbështeten duke filluar nga cili version. Rezultati shihet më poshtë:

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;

Ju lutemi ndryshoni gjithashtu zbatimin e kernelit për të lexuar parametrat e shtuar rishtazi nga strukturat C. Detajet janë lënë jashtë këtu.

Ndryshoni kodin e leximit të FlatBuffer

Logjika për të lexuar FlatBuffer dhe për të prodhuar strukturën C është në lite/core/api/flatbuffer_conversions.cc .

Përditësoni skedarin për të trajtuar parametrat e rinj, siç tregohet më poshtë:

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;
}

Nuk kërkohet të kontrolloni versionin op këtu. Kur zbatimi i ri lexon një skedar të modelit të vjetër ku mungojnë faktorët e zgjerimit, ai do të përdorë 1 si vlerën e paracaktuar dhe kerneli i ri do të funksionojë në përputhje me kernelin e vjetër.

Ndrysho regjistrimin e kernelit

MutableOpResolver (përcaktuar në lite/mutable_op_resolver.h ) ofron disa funksione për të regjistruar kernelet op. Versioni minimal dhe maksimal janë 1 si parazgjedhje:

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);

Opsionet e integruara regjistrohen në lite/kernels/register.cc . Në këtë shembull, ne kemi implementuar një kernel të ri op i cili mund të trajtojë versionin 1 dhe 2 DepthwiseConv2D , kështu që duhet të ndryshojmë këtë linjë:

AddBuiltin(BuiltinOperator_DEPTHWISE_CONV_2D, Register_DEPTHWISE_CONV_2D());

te:

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

Ndryshoni versionin e TFLite op

Hapi tjetër është të bëni TFLite të plotësojë versionin minimal që kërkohet për të ekzekutuar op. Në këtë shembull, do të thotë:

  • Plotësoni versionin=1 kur faktorët e zgjerimit janë të gjithë 1.
  • Plotëso versionin=2 ndryshe.

Modifiko funksionin GetBuiltinOperatorVersion për operatorin në lite/tools/versioning/op_version.cc duke shtuar versionin e ri në rastin e 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;

Përditësoni hartën e versionit të operatorit

Hapi i fundit është të shtoni informacionin e versionit të ri në hartën e versionit të operatorit. Ky hap kërkohet sepse ne duhet të gjenerojmë versionin minimal të kërkuar të kohës së funksionimit të modelit bazuar në këtë hartë të versionit.

Për ta bërë këtë, duhet të shtoni një hyrje të re në hartë në lite/tools/versioning/runtime_version.cc .

Në këtë shembull, duhet të shtoni hyrjen e mëposhtme në op_version_map :

{ {BuiltinOperator_DEPTHWISE_CONV_2D, 2}, %CURRENT_RUNTIME_VERSION%}

ku %CURRENT_RUNTIME_VERSION% korrespondon me versionin aktual të ekzekutimit të përcaktuar në versionin_relesion.h .

Zbatimi i delegacionit

LiteRT ofron një API delegimi që mundëson delegimin e opcioneve në backend-et e harduerit. Në funksionin Prepare e delegatit, kontrolloni nëse versioni mbështetet për çdo nyje në kodin e delegimit.

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.
}

Kjo kërkohet edhe nëse delegimi mbështet vetëm versionin 1 ops, kështu që delegimi mund të zbulojë papajtueshmëri kur merr një version më të lartë op.