Các phiên bản toán tử TensorFlow Lite

Tài liệu này mô tả lược đồ lập 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à thông số mới vào các hoạt động hiện có. Ngoài ra, nó đảm bảo những điều sau:

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

Ví dụ: Thêm sự giãn nở thành 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 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 hoạt động tích chập theo chiều sâu.

Không cần phải có kiến ​​thức về sự giãn nở để 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 .
  • Các hạt nhân 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 giản đồ FlatBuffer

Để thêm các tham số mới vào một 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 các tham số mới:

  • Thêm nhận xét cho biết thông số nào được hỗ trợ bởi phiên bản nào.
  • Khi triển khai mới nhận 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ư triển khai cũ.

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

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

Trong TensorFlow Lite, việc triển khai hạt nhân được tách ra khỏi định nghĩa FlatBuffer. Các hạt nhân đọc tham số từ các cấu trúc C được định nghĩa 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;

Như với lược đồ FlatBuffer, hãy thêm các nhận xét cho biết các 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 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;

Cũng vui lòng thay đổi việc triển khai nhân để đọ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 là trong lite/core/api/flatbuffer_conversions.cc .

Cập nhật tệp để xử lý các tham số mới, như được 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 bắt buộc phải kiểm tra phiên bản op ở đây. Khi triển khai mới đọc một tệp mô hình cũ thiếu các yếu tố 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ý hạt nhân

MutableOpResolver (được định nghĩa trong lite/mutable_op_resolver.h ) cung cấp một vài hàm để đăng ký hạt nhân op. Phiên bản tối thiểu và tối đa là 1 theo 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 đượ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 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 op TFLite

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

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

Sửa đổi hàm GetBuiltinOperatorVersion cho nhà điều hành 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 của 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ộ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 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 .

Ủy quyền thực hiện

TensorFlow Lite cung cấp một API ủy quyền cho phép các hoạt động ủy quyền cho các phần cứng phụ trợ. Trong chức năng Prepare của người được ủy quyền, hãy kiểm tra xem phiên bản có được hỗ trợ cho mọi nút trong mã Ủy quyền 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ợ hoạt động phiên bản 1, vì vậy ủy quyền có thể phát hiện sự không tương thích khi tải phiên bản cao hơn.