Dokumen ini menjelaskan skema pembuatan versi op LiteRT. Pembuatan versi op memungkinkan developer menambahkan fungsi dan parameter baru ke dalam operasi yang ada. Selain itu, fitur ini menjamin hal berikut:
- Kompatibilitas mundur: Implementasi LiteRT baru harus menangani file model lama.
- Kompatibilitas ke depan: Implementasi LiteRT lama harus menangani file model baru yang dihasilkan oleh konverter versi baru, selama tidak ada fitur baru yang digunakan.
- Deteksi ketidakcocokan ke depan: Jika penerapan LiteRT lama membaca model baru yang berisi versi baru op yang tidak didukung, error harus dilaporkan.
Contoh: Menambahkan dilatasi ke dalam konvolusi depthwise
Bagian selanjutnya dari dokumen ini menjelaskan pembuatan versi op di TFLite dengan menunjukkan cara menambahkan parameter dilatasi ke operasi konvolusi depthwise.
Pengetahuan tentang dilatasi tidak diperlukan untuk memahami dokumen ini. Perhatikan bahwa:
- 2 parameter bilangan bulat baru akan ditambahkan:
dilation_width_factordandilation_height_factor. - Kernel konvolusi depthwise lama yang tidak mendukung dilatasi setara dengan menyetel faktor dilatasi ke 1.
Mengubah skema FlatBuffer
Untuk menambahkan parameter baru ke dalam operasi, ubah tabel opsi di
lite/schema/schema.fbs.
Misalnya, tabel opsi konvolusi dalam-luas 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.
- Saat implementasi baru mendapatkan nilai default untuk parameter yang baru ditambahkan, implementasi tersebut akan berfungsi persis sama dengan implementasi lama.
Tabel akan terlihat 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.
Mengubah struktur C dan penerapan kernel
Di LiteRT, implementasi kernel dipisahkan dari definisi FlatBuffer.
Kernel membaca parameter dari struktur C yang ditentukan dalam
lite/c/builtin_op_data.h.
Parameter konvolusi depthwise asli adalah sebagai berikut:
typedef struct {
TfLitePadding padding;
int stride_width;
int stride_height;
int depth_multiplier;
TfLiteFusedActivation activation;
} TfLiteDepthwiseConvParams;
Seperti pada skema FlatBuffer, tambahkan komentar yang menunjukkan parameter mana yang didukung mulai dari versi mana. Hasilnya dapat dilihat di bawah:
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;
Ubah juga implementasi kernel untuk membaca parameter yang baru ditambahkan dari struktur C. Detailnya tidak disertakan di sini.
Mengubah 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:
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;
}
Anda tidak perlu memeriksa versi op di sini. Saat implementasi baru membaca file model lama yang tidak memiliki faktor dilatasi, implementasi tersebut akan menggunakan 1 sebagai nilai default, dan kernel baru akan berfungsi secara konsisten dengan kernel lama.
Mengubah pendaftaran kernel
MutableOpResolver (ditentukan 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 menerapkan kernel op baru yang dapat menangani DepthwiseConv2D versi 1 dan
2, jadi kami perlu mengubah baris ini:
AddBuiltin(BuiltinOperator_DEPTHWISE_CONV_2D, Register_DEPTHWISE_CONV_2D());
menjadi:
AddBuiltin(BuiltinOperator_DEPTHWISE_CONV_2D, Register_DEPTHWISE_CONV_2D(),
/* min_version = */ 1,
/* max_version = */ 2);
Mengubah versi op TFLite
Langkah berikutnya adalah membuat TFLite mengisi versi minimum yang diperlukan untuk mengeksekusi operasi. Dalam contoh ini, artinya:
- Isi version=1 jika semua faktor pelebaran adalah 1.
- Isi version=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;
Memperbarui peta versi operator
Langkah terakhir adalah menambahkan info versi baru ke peta versi operator. Langkah ini diperlukan karena kita perlu membuat versi runtime minimum yang diperlukan model berdasarkan peta versi ini.
Untuk melakukannya, 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%}
dengan %CURRENT_RUNTIME_VERSION% sesuai dengan versi runtime saat ini yang
ditetapkan dalam release_version.h.
Implementasi delegasi
LiteRT menyediakan API delegasi yang memungkinkan operasi didelegasikan ke backend hardware. Dalam fungsi Prepare delegasi, periksa apakah versi 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, ®istration));
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.