Phiên bản toán tử LiteRT

Tài liệu này mô tả giản đồ tạo phiên bản hoạt động của LiteRT. Phiên bản vận hành cho phép nhà phát triển thêm các chức năng và thông số mới vào hoạt động hiện có. Ngoài ra, chúng tôi còn đả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: Cách 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 có các tính năng mới được sử dụng.
  • Phát hiện khả năng không tương thích chuyển tiếp: Nếu phương thức triển khai LiteRT cũ đọc mô hình mới có chứa phiên bản mới của một vận hành không phải là được hỗ trợ nên trình báo cáo sẽ báo cáo lỗi.

Ví dụ: Thêm độ mở rộng vào tích chập depthwise

Phần còn lại của tài liệu này giải thích về việc lập phiên bản vận hành trong TFLite bằng cách trình bày cách để thêm tham số giãn nở vào phép toán tích chập depthwise.

Không bắt buộc phải có kiến thức về tính năng mở rộng để hiểu được tài liệu này. Lưu ý:

  • 2 tham số số nguyên mới sẽ được thêm vào: dilation_width_factordilation_height_factor.
  • Các hạt nhân tích chập depthwise cũ không hỗ trợ tính năng giãn nở là tương đương để đặt hệ số làm giãn thành 1.

Thay đổi giản đồ FlatBuffer

Để thêm thông số mới vào một hoạt động, hãy thay đổi bảng tùy chọn trong lite/schema/schema.fbs.

Ví dụ: bảng tuỳ chọn của 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 thông số mới:

  • Thêm nhận xét cho biết phiên bản nào hỗ trợ thông số nào.
  • Khi phương thức triển khai mới sẽ nhận được các giá trị mặc định cho thành phần mới được thêm vào các tham số đó sẽ hoạt động giống hệt như cách triển khai cũ.

Bảng sẽ trông giống như sau sau khi các thông số mới được thêm vào:

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 cần được tạo lại cho giản đồ.

Thay đổi cấu trúc C và cách triển khai hạt nhân

Trong LiteRT, quá trình triển khai hạt nhân được tách khỏi FlatBuffer định nghĩa. Các 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 depthwise ban đầu như sau:

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

Tương tự như với giản đồ FlatBuffer, hãy thêm nhận xét cho biết tham số nào được hỗ trợ bắt đầu từ phiên bản nào. Bạn có thể xem kết quả dưới đây:

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 phương thức triển khai hạt nhân để đọc các tham số mới được thêm vào khỏi cấu trúc C. Thông tin chi tiết bị bỏ qua ở đâ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 này để xử lý các tham số mới, như trình bày 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 hoạt động tại đây. Thời điểm triển khai mới đọc một tệp mô hình cũ bị thiếu hệ số giãn nở, tệp này sẽ sử dụng 1 làm mặc định và nhân mới sẽ hoạt động nhất quán với nhân cũ.

Thay đổi gói đăng ký nhân

MutableOpResolver (được định nghĩa trong lite/mutable_op_resolver.h) cung cấp một vài để đăng ký hạt nhân op. Phiên bản tối thiểu và tối đa là 1 bởi mặc định:

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 hoạt động tích hợp sẵn được đăng ký trong lite/kernels/register.cc. Trong ví dụ này, chúng tôi đã 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 hoạt động của TFLite

Bước tiếp theo là làm cho TFLite điền sẵn phiên bản tối thiểu cần thiết để thực thi cơ chế này. Trong ví dụ này, trạng thái đó có nghĩa là:

  • Điền phiên bản=1 khi các hệ số làm giãn đều là 1.
  • Nếu không, hãy điền phiên bản=2.

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 nhà vận hành

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 nhà cung cấp dịch vụ. Chiến dịch này vì chúng ta cần tạo số lượng yêu cầu tối thiểu của mô hình phiên bản thời gian chạy dựa trên bản đồ phiên bản này.

Để thực hiện 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 xác định trong tensorflow/core/public/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 hoạt động phần phụ trợ phần cứng. Trong hàm Prepare của uỷ quyền, hãy kiểm tra xem phiên bản có phải là được hỗ trợ cho mỗi nút trong Mã uỷ quyền.

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

Điều này là bắt buộc ngay cả khi uỷ quyền chỉ hỗ trợ hoạt động phiên bản 1, vì vậy uỷ quyền có thể phát hiện sự không tương thích khi nhận được hoạt động phiên bản cao hơn.