Tài liệu này mô tả giản đồ phiên bản hoạt động của LiteRT. Tính năng tạo phiên bản thao tác cho phép nhà phát triển thêm các chức năng và tham số mới vào các thao tác hiện có. Ngoài ra, dịch vụ này đảm bảo những điều sau:
- Khả năng tương thích ngược: Việc triển khai LiteRT mới sẽ xử lý tệp mô hình cũ.
- Khả năng tương thích chuyển tiếp: Việc triển khai LiteRT cũ sẽ xử lý tệp mô hình mới do phiên bản mới của trình chuyển đổi tạo ra, miễn là không sử dụng tính năng mới.
- Phát hiện khả năng tương thích chuyển tiếp: Nếu quá trình triển khai LiteRT cũ đọc một mô hình mới chứa phiên bản mới của một toán tử không được hỗ trợ, thì quá trình này sẽ báo cáo lỗi.
Ví dụ: Thêm hoạt động giãn vào phép tích chập theo chiều sâu
Phần còn lại của tài liệu này giải thích việc tạo phiên bản toán tử trong TFLite bằng cách cho biết cách thêm các tham số giãn vào phép tích chập theo chiều sâu.
Bạn không cần phải biết về việc giãn để hiểu tài liệu này. Lưu ý:
- 2 tham số số nguyên mới sẽ được thêm vào:
dilation_width_factor
vàdilation_height_factor
. - Các hạt nhân tích chập theo chiều sâu cũ không hỗ trợ việc giãn tương đương với việc đặt hệ số giãn là 1.
Thay đổi giản đồ FlatBuffer
Để thêm tham số mới vào một toán tử, hãy thay đổi bảng tuỳ chọn trong lite/schema/schema.fbs
.
Ví dụ: bảng tuỳ chọn của phép tích chập theo chiều sâu có dạng như sau:
table DepthwiseConv2DOptions {
padding:Padding;
stride_w:int;
stride_h:int;
depth_multiplier:int;
fused_activation_function:ActivationFunctionType;
}
Khi thêm tham số mới:
- Thêm chú thích cho biết phiên bản nào hỗ trợ tham số nào.
- Khi phương thức triển khai mới nhận được giá trị mặc định cho các tham số mới thêm, phương thức này sẽ hoạt động giống hệt như phương thức triển khai cũ.
Bảng sẽ có dạng như sau sau khi thêm các tham số mới:
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;
}
Tệp lite/schema/schema_generated.h
phải được tạo lại cho giản đồ mới.
Thay đổi cấu trúc C và cách triển khai nhân
Trong LiteRT, việc triển khai hạt nhân được tách khỏi định nghĩa FlatBuffer. Hạt nhân đọc tham số từ các cấu trúc C được xác định trong lite/c/builtin_op_data.h
.
Tham số tích chập theo chiều sâu ban đầu như sau:
typedef struct {
TfLitePadding padding;
int stride_width;
int stride_height;
int depth_multiplier;
TfLiteFusedActivation activation;
} TfLiteDepthwiseConvParams;
Tương tự như giản đồ FlatBuffer, hãy thêm chú thích cho biết những tham số nào được hỗ trợ kể từ phiên bản nào. Bạn có thể xem kết quả bên dưới:
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;
Vui lòng thay đổi cách triển khai hạt nhân để đọc các tham số mới thêm từ cấu trúc C. Chúng tôi sẽ bỏ qua thông tin chi tiết tại đây.
Thay đổi mã đọc FlatBuffer
Logic để đọc FlatBuffer và tạo cấu trúc C nằm trong lite/core/api/flatbuffer_conversions.cc
.
Cập nhật tệp để xử lý các tham số mới, như minh hoạ dưới đây:
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;
}
Bạn không bắt buộc phải kiểm tra phiên bản op tại đây. Khi quá trình triển khai mới đọc một tệp mô hình cũ bị thiếu hệ số giãn nở, quá trình này sẽ sử dụng 1 làm giá trị mặc định và hạt nhân mới sẽ hoạt động nhất quán với hạt nhân cũ.
Thay đổi chế độ đăng ký nhân
MutableOpResolver (được xác định trong lite/mutable_op_resolver.h
) cung cấp một số hàm để đăng ký hạt nhân op. Theo mặc định, phiên bản tối thiểu và tối đa là 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);
Các thao tác tích hợp được đăng ký trong lite/kernels/register.cc
. Trong ví dụ này, chúng ta đã triển khai một hạt nhân op mới có thể xử lý DepthwiseConv2D
phiên bản 1 và 2, vì vậy, chúng ta cần thay đổi dòng này:
AddBuiltin(BuiltinOperator_DEPTHWISE_CONV_2D, Register_DEPTHWISE_CONV_2D());
đến:
AddBuiltin(BuiltinOperator_DEPTHWISE_CONV_2D, Register_DEPTHWISE_CONV_2D(),
/* min_version = */ 1,
/* max_version = */ 2);
Thay đổi phiên bản toán tử TFLite
Bước tiếp theo là yêu cầu TFLite điền sẵn phiên bản tối thiểu cần thiết để thực thi toán tử. Trong ví dụ này, điều đó có nghĩa là:
- Điền version=1 khi tất cả hệ số giãn đều bằng 1.
- Điền version=2 nếu không.
Sửa đổi hàm GetBuiltinOperatorVersion
cho toán tử trong lite/tools/versioning/op_version.cc
bằng cách thêm phiên bản mới vào trường hợp 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;
Cập nhật bản đồ phiên bản của nhà khai thác
Bước cuối cùng là thêm thông tin phiên bản mới vào bản đồ phiên bản của nhà mạng. Bước này là bắt buộc vì chúng ta cần tạo phiên bản thời gian chạy tối thiểu bắt buộc của mô hình dựa trên bản đồ phiên bản này.
Để làm việc này, bạn cần thêm một mục nhập bản đồ mới trong lite/tools/versioning/runtime_version.cc
.
Trong ví dụ này, bạn cần thêm mục nhập sau vào op_version_map
:
{ {BuiltinOperator_DEPTHWISE_CONV_2D, 2}, %CURRENT_RUNTIME_VERSION%}
trong đó %CURRENT_RUNTIME_VERSION%
tương ứng với phiên bản thời gian chạy hiện tại được xác định trong release_version.h.
Triển khai tính năng uỷ quyền
LiteRT cung cấp một API uỷ quyền cho phép uỷ quyền các thao tác cho phần phụ trợ phần cứng. Trong hàm Prepare
của đối tượng uỷ quyền, hãy kiểm tra xem phiên bản có được hỗ trợ cho mọi nút trong mã Uỷ quyền hay không.
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.
}
Điều này là bắt buộc ngay cả khi việc uỷ quyền chỉ hỗ trợ các thao tác phiên bản 1, vì vậy, việc uỷ quyền có thể phát hiện sự không tương thích khi nhận được thao tác phiên bản cao hơn.