Versi operator TensorFlow Lite

Dokumen ini menjelaskan skema pembuatan versi operasi TensorFlow Lite. Pembuatan versi operasi memungkinkan pengembang menambahkan fungsionalitas dan parameter baru ke dalam operasi yang ada. Selain itu, ini menjamin hal-hal berikut:

  • Kompatibilitas mundur: Implementasi TensorFlow Lite baru harus menangani file model lama.
  • Kompatibilitas ke depan: Implementasi TensorFlow Lite lama harus menangani file model baru yang dihasilkan oleh konverter versi baru, selama tidak ada fitur baru yang digunakan.
  • Deteksi ketidakcocokan penerusan: Jika implementasi TensorFlow Lite lama membaca model baru yang berisi versi operasi baru yang tidak didukung, implementasi tersebut akan melaporkan kesalahannya.

Contoh: Menambahkan dilatasi ke dalam konvolusi mendalam

Sisa dokumen ini menjelaskan pembuatan versi operasi di TFLite dengan menunjukkan cara menambahkan parameter dilatasi ke operasi konvolusi mendalam.

Pengetahuan tentang dilatasi tidak diperlukan untuk memahami dokumen ini. Perhatikan bahwa:

  • 2 parameter bilangan bulat baru akan ditambahkan: dilation_width_factor dan dilation_height_factor .
  • Kernel konvolusi mendalam lama yang tidak mendukung dilatasi setara dengan menyetel faktor dilatasi ke 1.

Ubah skema FlatBuffer

Untuk menambahkan parameter baru ke dalam operasi, ubah tabel opsi di lite/schema/schema.fbs .

Misalnya, tabel opsi konvolusi mendalam terlihat seperti ini:

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

Saat menambahkan parameter baru:

  • Tambahkan komentar yang menunjukkan parameter mana yang didukung oleh versi mana.
  • Ketika implementasi baru mendapatkan nilai default untuk parameter yang baru ditambahkan, implementasi tersebut akan bekerja sama persis dengan implementasi lama.

Tabelnya akan seperti ini setelah parameter baru ditambahkan:

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

File lite/schema/schema_generated.h harus dibuat ulang untuk skema baru.

Ubah struktur C dan implementasi kernel

Di TensorFlow Lite, implementasi kernel dipisahkan dari definisi FlatBuffer. Kernel membaca parameter dari struktur C yang didefinisikan dalam lite/c/builtin_op_data.h .

Parameter konvolusi mendalam asli adalah sebagai berikut:

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

Seperti halnya skema FlatBuffer, tambahkan komentar yang menunjukkan parameter mana yang didukung mulai dari versi mana. Hasilnya terlihat di bawah ini:

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;

Harap ubah juga implementasi kernel untuk membaca parameter yang baru ditambahkan dari struktur C. Detailnya dihilangkan di sini.

Ubah kode pembacaan FlatBuffer

Logika untuk membaca FlatBuffer dan menghasilkan struktur C ada di lite/core/api/flatbuffer_conversions.cc .

Perbarui file untuk menangani parameter baru, seperti yang ditunjukkan di bawah ini:

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

Tidak perlu memeriksa versi operasi di sini. Ketika implementasi baru membaca file model lama yang faktor dilatasinya tidak ada, maka implementasi tersebut akan menggunakan 1 sebagai nilai default, dan kernel baru akan bekerja secara konsisten dengan kernel lama.

Ubah pendaftaran kernel

MutableOpResolver (didefinisikan dalam lite/mutable_op_resolver.h ) menyediakan beberapa fungsi untuk mendaftarkan kernel op. Versi minimum dan maksimum adalah 1 secara default:

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

Operasi bawaan terdaftar di lite/kernels/register.cc . Dalam contoh ini, kami mengimplementasikan op kernel baru yang dapat menangani DepthwiseConv2D versi 1 dan 2, jadi kami perlu mengubah baris ini:

AddBuiltin(BuiltinOperator_DEPTHWISE_CONV_2D, Register_DEPTHWISE_CONV_2D());

ke:

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

Ubah versi operasi TFLite

Langkah selanjutnya adalah membuat TFLite mengisi versi minimum yang diperlukan untuk menjalankan operasi. Dalam contoh ini artinya:

  • Isi versi=1 ketika faktor dilatasi semuanya 1.
  • Isi versi=2 jika tidak.

Ubah fungsi GetBuiltinOperatorVersion untuk operator di lite/tools/versioning/op_version.cc dengan menambahkan versi baru ke kasus 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;

Perbarui peta versi operator

Langkah terakhir adalah menambahkan info versi baru ke dalam peta versi operator. Langkah ini diperlukan karena kita perlu membuat versi runtime minimum yang diperlukan model berdasarkan peta versi ini.

Untuk melakukan ini, Anda perlu menambahkan entri peta baru di lite/tools/versioning/runtime_version.cc .

Dalam contoh ini, Anda perlu menambahkan entri berikut ke op_version_map :

{ {BuiltinOperator_DEPTHWISE_CONV_2D, 2}, %CURRENT_RUNTIME_VERSION%}

di mana %CURRENT_RUNTIME_VERSION% sesuai dengan versi runtime saat ini yang ditentukan dalam tensorflow/core/public/version.h .

Implementasi delegasi

TensorFlow Lite menyediakan API delegasi yang memungkinkan pendelegasian operasi ke backend perangkat keras. Dalam fungsi Prepare delegasi, periksa apakah versi tersebut didukung untuk setiap node dalam kode Delegasi.

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

Hal ini diperlukan meskipun delegasi hanya mendukung operasi versi 1, sehingga delegasi dapat mendeteksi ketidakcocokan saat mendapatkan operasi versi yang lebih tinggi.