Phiên bản toán tử TensorFlow Lite

Tài liệu này mô tả lược đồ phiên bản op của TensorFlow Lite. Phiên bản op cho phép các nhà phát triển thêm các chức năng và tham số mới vào các op hiện có. Ngoài ra, nó đảm bảo những điều sau:

  • Khả năng tương thích ngược: Việc triển khai TensorFlow Lite mới sẽ xử lý tệp mô hình cũ.
  • Khả năng tương thích về phía trước: Việc triển khai TensorFlow Lite cũ sẽ xử lý tệp mô hình mới được tạo bởi phiên bản trình chuyển đổi mới, miễn là không sử dụng tính năng mới nào.
  • Phát hiện sự không tương thích về phía trước: Nếu triển khai TensorFlow Lite cũ đọc một mô hình mới chứa phiên bản mới của một op không được hỗ trợ, thì nó sẽ báo lỗi.

Ví dụ: Thêm phép giãn nở vào 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 lập phiên bản op trong TFLite bằng cách chỉ ra cách thêm các tham số giãn nở vào thao tác tích chập theo chiều sâu.

Kiến thức về sự giãn nở là không cần thiết để hiểu tài liệu này. Lưu ý rằng:

  • 2 tham số số nguyên mới sẽ được thêm vào: dilation_width_factordilation_height_factor .
  • Hạt nhân tích chập theo chiều sâu cũ không hỗ trợ giãn nở tương đương với việc đặt hệ số giãn nở thành 1.

Thay đổi lược đồ FlatBuffer

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

Ví dụ: bảng tùy chọn của tích chập theo chiều sâu trông như thế này:

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 nhận xét cho biết tham số nào được phiên bản nào hỗ trợ.
  • Khi cách triển khai mới nhận được các giá trị mặc định cho các tham số mới được thêm vào, nó sẽ hoạt động giống hệt như cách triển khai cũ.

Bảng sẽ như thế này sau khi thêm 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 lược đồ mới.

Thay đổi cấu trúc C và triển khai kernel

Trong TensorFlow Lite, việc triển khai kernel được tách riêng khỏi định nghĩa FlatBuffer. 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 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;

Giống như lược đồ 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. Kết quả được nhìn thấy 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;

Ngoài ra, vui lòng thay đổi cách triển khai kernel để đọc các tham số mới được thêm vào từ cấu trúc C. Các chi tiết được 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 để xử lý các tham số mới, như hiển thị bên dưới:

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

Không cần thiết phải kiểm tra phiên bản op tại đây. Khi triển khai mới đọc tệp mô hình cũ bị thiếu hệ số giãn nở, nó 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 đăng ký kernel

MutableOpResolver (được định nghĩa trong lite/mutable_op_resolver.h ) cung cấp một số chức năng để đăng ký hạt nhân op. Phiên bản tối thiểu và tối đa theo mặc định 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 hoạt động tích hợp được đăng ký trong lite/kernels/register.cc . Trong ví dụ này, chúng tôi đã triển khai hạt nhân op mới có thể xử lý DepthwiseConv2D phiên bản 1 và 2, vì vậy chúng tôi 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 TFLite op

Bước tiếp theo là làm cho TFLite điền vào phiên bản tối thiểu cần thiết để thực thi lệnh. Trong ví dụ này, nó có nghĩa là:

  • Điền phiên bản=1 khi hệ số giãn nở đều bằng 1.
  • Nếu không thì đ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à điều 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 của nhà điều hành. Bước này là bắt buộc vì chúng tôi cần tạo phiên bản thời gian chạy bắt buộc tối thiểu của mô hình 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ục bản đồ mới vào lite/tools/versioning/runtime_version.cc .

Trong ví dụ này, bạn cần thêm mục 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 tensorflow/core/public/version.h .

Thực hiện ủy quyền

TensorFlow Lite cung cấp API ủy quyền cho phép ủy quyền các hoạt động cho phần phụ trợ phần cứng. Trong chức năng Prepare của đại biểu, hãy kiểm tra xem phiên bản có được hỗ trợ cho mọi nút trong mã Đại biểu hay không.

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 ủy quyền chỉ hỗ trợ op phiên bản 1, do đó, ủy quyền có thể phát hiện sự không tương thích khi nhận phiên bản op cao hơn.