| /* |
| * Copyright (C) 2024 Intel Corporation |
| * SPDX-License-Identifier: Apache-2.0 |
| */ |
| |
| #include "delegate/intel_openvino/openvino_graph_builder.h" |
| |
| #include <gmock/gmock.h> |
| #include <gtest/gtest.h> |
| #include <openvino/pass/manager.hpp> |
| #include <openvino/pass/serialize.hpp> |
| |
| #include <memory> |
| #include <string> |
| #include <unordered_set> |
| |
| #include "tensorflow/lite/builtin_ops.h" |
| #include "tensorflow/lite/c/c_api.h" |
| #include "tensorflow/lite/core/kernels/builtin_op_kernels.h" |
| #include "tensorflow/lite/interpreter.h" |
| #include "tensorflow/lite/interpreter_builder.h" |
| #include "tensorflow/lite/kernels/kernel_util.h" |
| #include "tensorflow/lite/kernels/register.h" |
| |
| /* This file creates unit tests for openvino_graph_builder_test.cc to be run on |
| * host machine without NPU */ |
| |
| namespace tflite { |
| namespace openvinodelegate { |
| |
| constexpr char kPluginsXmlPath[] = "/etc/openvino/plugins.xml"; |
| |
| std::function<void(TfLiteOpaqueTensor *opaque_tensor, const int index)> |
| test_function_; |
| |
| class OpenVINOGraphBuilderTest : public testing::Test { |
| protected: |
| void SetUp() override { |
| model = ::tflite::FlatBufferModel::BuildFromFile( |
| "external/org_tensorflow/tensorflow/lite/testdata/add.bin"); |
| ASSERT_NE(model, nullptr); |
| } |
| void TearDown() override { TfLiteOpaqueDelegateDelete(opaque_delegate_); } |
| |
| protected: |
| std::unique_ptr<::tflite::Interpreter> interpreter_; |
| TfLiteOpaqueDelegate *opaque_delegate_ = nullptr; |
| std::unique_ptr<::tflite::FlatBufferModel> model; |
| }; |
| |
| TfLiteOpaqueTensor *CreateOpaqueTensor(TfLiteTensor *t) { |
| return reinterpret_cast<TfLiteOpaqueTensor *>(t); |
| } |
| |
| TEST_F(OpenVINOGraphBuilderTest, AddInputParamsTest_VALID) { |
| TfLiteTensor t; |
| const int kNumElements = 32; |
| const int kBytes = sizeof(float) * kNumElements; |
| memset(&t, 0, sizeof(TfLiteTensor)); |
| t.bytes = kBytes; |
| t.data_is_stale = true; |
| t.allocation_type = kTfLiteDynamic; |
| t.type = kTfLiteFloat32; |
| t.dims = TfLiteIntArrayCreate(2); |
| t.dims->data[0] = 4; |
| t.dims->data[1] = 8; |
| t.dims_signature = TfLiteIntArrayCopy(t.dims); |
| t.buffer_handle = 5; |
| |
| TfLiteOpaqueTensor *opaque_t = CreateOpaqueTensor(&t); |
| |
| auto openvino_graph_builder_test = |
| std::make_unique<OpenVINOGraphBuilder>(std::make_unique<NodeManager>()); |
| |
| EXPECT_EQ(kTfLiteOk, |
| openvino_graph_builder_test->AddInputParams(opaque_t, 0)); |
| EXPECT_EQ(true, openvino_graph_builder_test->getNodeManagerSize() == 1); |
| } |
| |
| TEST_F(OpenVINOGraphBuilderTest, AddInputParamsTest_InvalidTensor) { |
| auto openvino_graph_builder_test = |
| std::make_unique<OpenVINOGraphBuilder>(std::make_unique<NodeManager>()); |
| |
| EXPECT_EQ(kTfLiteError, |
| openvino_graph_builder_test->AddInputParams(nullptr, 0)); |
| EXPECT_EQ(false, openvino_graph_builder_test->getNodeManagerSize() == 1); |
| } |
| |
| TEST_F(OpenVINOGraphBuilderTest, AddInputParamsTest_InvalidIndex) { |
| TfLiteTensor t; |
| const int kNumElements = 32; |
| const int kBytes = sizeof(float) * kNumElements; |
| memset(&t, 0, sizeof(TfLiteTensor)); |
| t.bytes = kBytes; |
| // t.delegate = &delegate; |
| t.data_is_stale = true; |
| t.allocation_type = kTfLiteDynamic; |
| t.type = kTfLiteFloat32; |
| t.dims = TfLiteIntArrayCreate(2); |
| t.dims->data[0] = 4; |
| t.dims->data[1] = 8; |
| t.dims_signature = TfLiteIntArrayCopy(t.dims); |
| t.buffer_handle = 5; |
| |
| TfLiteOpaqueTensor *opaque_t = CreateOpaqueTensor(&t); |
| |
| auto openvino_graph_builder_test = |
| std::make_unique<OpenVINOGraphBuilder>(std::make_unique<NodeManager>()); |
| |
| EXPECT_EQ(kTfLiteError, |
| openvino_graph_builder_test->AddInputParams(opaque_t, -1)); |
| EXPECT_EQ(false, openvino_graph_builder_test->getNodeManagerSize() == 1); |
| } |
| |
| TEST_F(OpenVINOGraphBuilderTest, CreateConstNode_Invalid) { |
| TfLiteOpaqueDelegateBuilder opaque_delegate_builder{}; |
| bool delegate_prepared = false; |
| |
| opaque_delegate_builder.data = &delegate_prepared; |
| opaque_delegate_builder.Prepare = [](TfLiteOpaqueContext *opaque_context, |
| TfLiteOpaqueDelegate *opaque_delegate_, |
| void *data) -> TfLiteStatus { |
| auto delegate_prepared = static_cast<bool *>(data); |
| *delegate_prepared = true; |
| TfLiteIntArray *execution_plan; |
| TF_LITE_ENSURE_STATUS( |
| TfLiteOpaqueContextGetExecutionPlan(opaque_context, &execution_plan)); |
| for (int i = 0; i < execution_plan->size; ++i) { |
| TfLiteOpaqueNode *node = nullptr; |
| TfLiteOperator *registration = nullptr; |
| TfLiteOpaqueContextGetNodeAndRegistration(opaque_context, i, &node, |
| ®istration); |
| auto openvino_graph_builder_test = std::make_unique<OpenVINOGraphBuilder>( |
| std::make_unique<NodeManager>()); |
| |
| EXPECT_EQ(kTfLiteError, openvino_graph_builder_test->CreateConstNode( |
| opaque_context, 0)); |
| } |
| |
| TfLiteOperator *registration_external = |
| TfLiteOperatorCreate(kTfLiteBuiltinDelegate, |
| /*name*/ nullptr, |
| /*version=*/1, |
| /*user_data=*/nullptr); |
| return TfLiteOpaqueContextReplaceNodeSubsetsWithDelegateKernels( |
| opaque_context, registration_external, execution_plan, |
| opaque_delegate_); |
| }; |
| |
| opaque_delegate_ = TfLiteOpaqueDelegateCreate(&opaque_delegate_builder); |
| |
| tflite::ops::builtin::BuiltinOpResolver resolver; |
| tflite::InterpreterBuilder builder(*model, resolver); |
| builder.AddDelegate(opaque_delegate_); |
| |
| EXPECT_EQ(kTfLiteOk, builder(&interpreter_)); |
| EXPECT_TRUE(delegate_prepared); |
| ASSERT_NE(interpreter_, nullptr); |
| } |
| |
| TEST_F(OpenVINOGraphBuilderTest, CreateConstNode_InvalidContext) { |
| auto openvino_graph_builder_test = |
| std::make_unique<OpenVINOGraphBuilder>(std::make_unique<NodeManager>()); |
| EXPECT_EQ(kTfLiteError, |
| openvino_graph_builder_test->CreateConstNode(nullptr, 0)); |
| } |
| |
| TEST_F(OpenVINOGraphBuilderTest, CreateConstNode_InvalidIndex) { |
| TfLiteOpaqueDelegateBuilder opaque_delegate_builder{}; |
| bool delegate_prepared = false; |
| |
| opaque_delegate_builder.data = &delegate_prepared; |
| opaque_delegate_builder.Prepare = [](TfLiteOpaqueContext *opaque_context, |
| TfLiteOpaqueDelegate *opaque_delegate_, |
| void *data) -> TfLiteStatus { |
| auto delegate_prepared = static_cast<bool *>(data); |
| *delegate_prepared = true; |
| TfLiteIntArray *execution_plan; |
| TF_LITE_ENSURE_STATUS( |
| TfLiteOpaqueContextGetExecutionPlan(opaque_context, &execution_plan)); |
| for (int i = 0; i < execution_plan->size; ++i) { |
| TfLiteOpaqueNode *node = nullptr; |
| TfLiteOperator *registration = nullptr; |
| TfLiteOpaqueContextGetNodeAndRegistration(opaque_context, i, &node, |
| ®istration); |
| auto openvino_graph_builder_test = std::make_unique<OpenVINOGraphBuilder>( |
| std::make_unique<NodeManager>()); |
| |
| EXPECT_EQ(kTfLiteError, openvino_graph_builder_test->CreateConstNode( |
| opaque_context, 1)); |
| } |
| |
| TfLiteOperator *registration_external = |
| TfLiteOperatorCreate(kTfLiteBuiltinDelegate, |
| /*name*/ nullptr, |
| /*version=*/1, |
| /*user_data=*/nullptr); |
| return TfLiteOpaqueContextReplaceNodeSubsetsWithDelegateKernels( |
| opaque_context, registration_external, execution_plan, |
| opaque_delegate_); |
| }; |
| opaque_delegate_ = TfLiteOpaqueDelegateCreate(&opaque_delegate_builder); |
| |
| tflite::ops::builtin::BuiltinOpResolver resolver; |
| tflite::InterpreterBuilder builder(*model, resolver); |
| builder.AddDelegate(opaque_delegate_); |
| |
| EXPECT_EQ(kTfLiteOk, builder(&interpreter_)); |
| EXPECT_TRUE(delegate_prepared); |
| ASSERT_NE(interpreter_, nullptr); |
| } |
| |
| TEST_F(OpenVINOGraphBuilderTest, UpdateResultNodes_Valid) { |
| TfLiteOpaqueDelegateBuilder opaque_delegate_builder{}; |
| struct UserData { |
| bool delegate_prepared_ = false; |
| ov::CompiledModel compiled_model_; |
| } user_data; |
| |
| opaque_delegate_builder.data = &user_data; |
| opaque_delegate_builder.Prepare = [](TfLiteOpaqueContext *opaque_context, |
| TfLiteOpaqueDelegate *opaque_delegate_, |
| void *data) -> TfLiteStatus { |
| static_cast<UserData *>(data)->delegate_prepared_ = true; |
| auto reg_ex = TfLiteOperatorCreate(kTfLiteBuiltinDelegate, |
| "Test driver Openvino delegate", |
| /*version=*/1, data); |
| TfLiteOperatorSetInitWithData( |
| reg_ex, |
| [](void *user_data, TfLiteOpaqueContext *opaque_context, |
| const char *buffer, size_t length) -> void * { |
| auto openvino_graph_builder_test = |
| std::make_unique<OpenVINOGraphBuilder>( |
| std::make_unique<NodeManager>()); |
| std::vector<int> compute_inputs_ = {}; |
| std::vector<int> outputs_ = {}; |
| const TfLiteOpaqueDelegateParams *params = |
| reinterpret_cast<const TfLiteOpaqueDelegateParams *>(buffer); |
| const std::unordered_set<int> inputs( |
| ¶ms->input_tensors->data[0], |
| ¶ms->input_tensors->data[params->input_tensors->size]); |
| |
| for (int o = 0; o < params->output_tensors->size; o++) { |
| const int output_tensor_idx = params->output_tensors->data[o]; |
| outputs_.push_back(output_tensor_idx); |
| } |
| |
| for (int i = 0; i < params->nodes_to_replace->size; ++i) { |
| const int delegate_node_id = params->nodes_to_replace->data[i]; |
| TfLiteOpaqueNode *node = nullptr; |
| TfLiteOperator *registration = nullptr; |
| TfLiteOpaqueContextGetNodeAndRegistration( |
| opaque_context, delegate_node_id, &node, ®istration); |
| |
| int inputs_size = TfLiteOpaqueNodeNumberOfInputs(node); |
| for (int k = 0; k < inputs_size; k++) { |
| const int *inputs_data; |
| int num_inputs; |
| EXPECT_EQ(kTfLiteOk, TfLiteOpaqueNodeInputs(node, &inputs_data, |
| &num_inputs)); |
| const int t = inputs_data[k]; |
| const void *data = nullptr; |
| auto opaque_tensor = |
| TfLiteOpaqueContextGetOpaqueTensor(opaque_context, t); |
| EXPECT_NE(opaque_tensor, nullptr); |
| |
| auto allocation_type = |
| TfLiteOpaqueTensorGetAllocationType(opaque_tensor); |
| if (allocation_type == kTfLiteMmapRo) { |
| data = TfLiteOpaqueTensorData(opaque_tensor); |
| EXPECT_NE(data, nullptr); |
| if (openvino_graph_builder_test->CreateConstNode( |
| opaque_context, t) != kTfLiteOk) |
| exit(0); |
| } |
| |
| if (inputs.count(t) != 0) { |
| if (data == nullptr) { |
| if (openvino_graph_builder_test->AddInputParams( |
| opaque_tensor, t) != kTfLiteOk) |
| exit(0); |
| compute_inputs_.push_back(t); |
| } |
| } |
| } |
| if (openvino_graph_builder_test->CreateNodeFromTfLiteOp( |
| registration, node, opaque_context) != kTfLiteOk) |
| exit(0); |
| } |
| |
| EXPECT_EQ(kTfLiteOk, openvino_graph_builder_test->UpdateResultNodes( |
| opaque_context, outputs_)); |
| std::shared_ptr<ov::Model> model = std::make_shared<ov::Model>( |
| openvino_graph_builder_test->getResultNodes(), |
| openvino_graph_builder_test->getInputParams()); |
| |
| ov::Core ov_core_(kPluginsXmlPath); |
| std::string deviceStr = "CPU"; |
| ov::InferRequest infer_request_; |
| auto &compiled_model_ = |
| static_cast<UserData *>(user_data)->compiled_model_; |
| compiled_model_ = ov_core_.compile_model(model, deviceStr); |
| |
| infer_request_ = compiled_model_.create_infer_request(); |
| return &compiled_model_; |
| }); |
| |
| TfLiteOperatorSetInvoke(reg_ex, |
| [](TfLiteOpaqueContext *context, |
| TfLiteOpaqueNode *opaque_node) -> TfLiteStatus { |
| return kTfLiteOk; |
| }); |
| |
| TfLiteOperatorSetFree(reg_ex, |
| [](TfLiteOpaqueContext *context, void *data) {}); |
| |
| TfLiteIntArray *execution_plan; |
| TF_LITE_ENSURE_STATUS( |
| TfLiteOpaqueContextGetExecutionPlan(opaque_context, &execution_plan)); |
| TfLiteOpaqueContextReplaceNodeSubsetsWithDelegateKernels( |
| opaque_context, reg_ex, execution_plan, opaque_delegate_); |
| return kTfLiteOk; |
| }; |
| |
| TfLiteModel *model = TfLiteModelCreateFromFile( |
| "external/org_tensorflow/tensorflow/lite/testdata/add.bin"); |
| ASSERT_NE(model, nullptr); |
| |
| TfLiteOpaqueDelegate *opaque_delegate = |
| TfLiteOpaqueDelegateCreate(&opaque_delegate_builder); |
| TfLiteInterpreterOptions *options = TfLiteInterpreterOptionsCreate(); |
| ASSERT_NE(options, nullptr); |
| TfLiteInterpreterOptionsAddDelegate(options, opaque_delegate); |
| TfLiteInterpreter *interpreter = TfLiteInterpreterCreate(model, options); |
| ASSERT_NE(interpreter, nullptr); |
| |
| EXPECT_TRUE(user_data.delegate_prepared_); |
| |
| TfLiteInterpreterOptionsDelete(options); |
| TfLiteInterpreterDelete(interpreter); |
| TfLiteModelDelete(model); |
| TfLiteOpaqueDelegateDelete(opaque_delegate); |
| } |
| |
| TEST_F(OpenVINOGraphBuilderTest, UpdateResultNodes_InvalidContext) { |
| auto openvino_graph_builder_test = |
| std::make_unique<OpenVINOGraphBuilder>(std::make_unique<NodeManager>()); |
| EXPECT_EQ(kTfLiteError, |
| openvino_graph_builder_test->UpdateResultNodes(nullptr, {0})); |
| } |
| |
| TEST_F(OpenVINOGraphBuilderTest, UpdateResultNodes_InvalidIndex) { |
| TfLiteOpaqueDelegateBuilder opaque_delegate_builder{}; |
| struct UserData { |
| bool delegate_prepared_ = false; |
| ov::CompiledModel compiled_model_; |
| } user_data; |
| |
| opaque_delegate_builder.data = &user_data; |
| opaque_delegate_builder.Prepare = [](TfLiteOpaqueContext *opaque_context, |
| TfLiteOpaqueDelegate *opaque_delegate_, |
| void *data) -> TfLiteStatus { |
| static_cast<UserData *>(data)->delegate_prepared_ = true; |
| auto reg_ex = TfLiteOperatorCreate(kTfLiteBuiltinDelegate, |
| "Test driver Openvino delegate", |
| /*version=*/1, data); |
| TfLiteOperatorSetInitWithData( |
| reg_ex, |
| [](void *user_data, TfLiteOpaqueContext *opaque_context, |
| const char *buffer, size_t length) -> void * { |
| auto openvino_graph_builder_test = |
| std::make_unique<OpenVINOGraphBuilder>( |
| std::make_unique<NodeManager>()); |
| std::vector<int> compute_inputs_ = {}; |
| std::vector<int> outputs_ = {}; |
| const TfLiteOpaqueDelegateParams *params = |
| reinterpret_cast<const TfLiteOpaqueDelegateParams *>(buffer); |
| const std::unordered_set<int> inputs( |
| ¶ms->input_tensors->data[0], |
| ¶ms->input_tensors->data[params->input_tensors->size]); |
| |
| for (int o = 0; o < params->output_tensors->size; o++) { |
| const int output_tensor_idx = params->output_tensors->data[o]; |
| outputs_.push_back(output_tensor_idx); |
| } |
| |
| for (int i = 0; i < params->nodes_to_replace->size; ++i) { |
| const int delegate_node_id = params->nodes_to_replace->data[i]; |
| TfLiteOpaqueNode *node = nullptr; |
| TfLiteOperator *registration = nullptr; |
| TfLiteOpaqueContextGetNodeAndRegistration( |
| opaque_context, delegate_node_id, &node, ®istration); |
| |
| int inputs_size = TfLiteOpaqueNodeNumberOfInputs(node); |
| for (int k = 0; k < inputs_size; k++) { |
| const int *inputs_data; |
| int num_inputs; |
| EXPECT_EQ(kTfLiteOk, TfLiteOpaqueNodeInputs(node, &inputs_data, |
| &num_inputs)); |
| const int t = inputs_data[k]; |
| const void *data = nullptr; |
| auto opaque_tensor = |
| TfLiteOpaqueContextGetOpaqueTensor(opaque_context, t); |
| EXPECT_NE(opaque_tensor, nullptr); |
| auto allocation_type = |
| TfLiteOpaqueTensorGetAllocationType(opaque_tensor); |
| if (allocation_type == kTfLiteMmapRo) { |
| data = TfLiteOpaqueTensorData(opaque_tensor); |
| EXPECT_NE(data, nullptr); |
| |
| if (openvino_graph_builder_test->CreateConstNode( |
| opaque_context, t) != kTfLiteOk) |
| exit(0); |
| } |
| if (inputs.count(t) != 0) { |
| if (data == nullptr) { |
| static int count = 0; |
| if (count == 0) { |
| if (openvino_graph_builder_test->AddInputParams( |
| opaque_tensor, t) != kTfLiteOk) |
| exit(0); |
| compute_inputs_.push_back(t); |
| count++; |
| } |
| } |
| } |
| } |
| if (openvino_graph_builder_test->CreateNodeFromTfLiteOp( |
| registration, node, opaque_context) != kTfLiteOk) |
| exit(0); |
| } |
| |
| EXPECT_EQ(kTfLiteError, |
| openvino_graph_builder_test->UpdateResultNodes( |
| opaque_context, {})); |
| std::shared_ptr<ov::Model> model = std::make_shared<ov::Model>( |
| openvino_graph_builder_test->getResultNodes(), |
| openvino_graph_builder_test->getInputParams()); |
| |
| ov::Core ov_core_(kPluginsXmlPath); |
| std::string deviceStr = "CPU"; |
| ov::InferRequest infer_request_; |
| auto &compiled_model_ = |
| static_cast<UserData *>(user_data)->compiled_model_; |
| compiled_model_ = ov_core_.compile_model(model, deviceStr); |
| |
| infer_request_ = compiled_model_.create_infer_request(); |
| return &compiled_model_; |
| }); |
| |
| TfLiteOperatorSetInvoke(reg_ex, |
| [](TfLiteOpaqueContext *context, |
| TfLiteOpaqueNode *opaque_node) -> TfLiteStatus { |
| return kTfLiteOk; |
| }); |
| |
| TfLiteOperatorSetFree(reg_ex, |
| [](TfLiteOpaqueContext *context, void *data) {}); |
| |
| TfLiteIntArray *execution_plan; |
| TF_LITE_ENSURE_STATUS( |
| TfLiteOpaqueContextGetExecutionPlan(opaque_context, &execution_plan)); |
| TfLiteOpaqueContextReplaceNodeSubsetsWithDelegateKernels( |
| opaque_context, reg_ex, execution_plan, opaque_delegate_); |
| return kTfLiteOk; |
| }; |
| |
| TfLiteModel *model = TfLiteModelCreateFromFile( |
| "external/org_tensorflow/tensorflow/lite/testdata/add.bin"); |
| ASSERT_NE(model, nullptr); |
| |
| TfLiteOpaqueDelegate *opaque_delegate = |
| TfLiteOpaqueDelegateCreate(&opaque_delegate_builder); |
| TfLiteInterpreterOptions *options = TfLiteInterpreterOptionsCreate(); |
| ASSERT_NE(options, nullptr); |
| TfLiteInterpreterOptionsAddDelegate(options, opaque_delegate); |
| TfLiteInterpreter *interpreter = TfLiteInterpreterCreate(model, options); |
| ASSERT_NE(interpreter, nullptr); |
| |
| EXPECT_TRUE(user_data.delegate_prepared_); |
| |
| TfLiteInterpreterOptionsDelete(options); |
| TfLiteInterpreterDelete(interpreter); |
| TfLiteModelDelete(model); |
| TfLiteOpaqueDelegateDelete(opaque_delegate); |
| } |
| |
| TEST_F(OpenVINOGraphBuilderTest, CreateOpClass_Valid) { |
| TfLiteOperator registration; |
| registration.version = 1; |
| registration.builtin_code = kTfLiteBuiltinAdd; |
| registration.node_index = 1; |
| |
| std::shared_ptr<OperationsBase> op_base; |
| auto openvino_graph_builder_test = |
| std::make_unique<OpenVINOGraphBuilder>(std::make_unique<NodeManager>()); |
| |
| EXPECT_EQ(kTfLiteOk, |
| openvino_graph_builder_test->CreateOpClass(®istration, op_base)); |
| } |
| |
| TEST_F(OpenVINOGraphBuilderTest, CreateOpClass_InvalidRegistration) { |
| std::shared_ptr<OperationsBase> op_base; |
| auto openvino_graph_builder_test = |
| std::make_unique<OpenVINOGraphBuilder>(std::make_unique<NodeManager>()); |
| |
| EXPECT_EQ(kTfLiteError, |
| openvino_graph_builder_test->CreateOpClass(nullptr, op_base)); |
| } |
| |
| TEST_F(OpenVINOGraphBuilderTest, CreateNodeFromTfLiteOp_Valid) { |
| TfLiteOpaqueDelegateBuilder opaque_delegate_builder{}; |
| struct UserData { |
| bool delegate_prepared_ = false; |
| ov::CompiledModel compiled_model_; |
| } user_data; |
| |
| opaque_delegate_builder.data = &user_data; |
| opaque_delegate_builder.Prepare = [](TfLiteOpaqueContext *opaque_context, |
| TfLiteOpaqueDelegate *opaque_delegate_, |
| void *data) -> TfLiteStatus { |
| static_cast<UserData *>(data)->delegate_prepared_ = true; |
| auto reg_ex = TfLiteOperatorCreate(kTfLiteBuiltinDelegate, |
| "Test driver Openvino delegate", |
| /*version=*/1, data); |
| TfLiteOperatorSetInitWithData( |
| reg_ex, |
| [](void *user_data, TfLiteOpaqueContext *opaque_context, |
| const char *buffer, size_t length) -> void * { |
| auto openvino_graph_builder_test = |
| std::make_unique<OpenVINOGraphBuilder>( |
| std::make_unique<NodeManager>()); |
| std::vector<int> compute_inputs_ = {}; |
| std::vector<int> outputs_ = {}; |
| const TfLiteOpaqueDelegateParams *params = |
| reinterpret_cast<const TfLiteOpaqueDelegateParams *>(buffer); |
| const std::unordered_set<int> inputs( |
| ¶ms->input_tensors->data[0], |
| ¶ms->input_tensors->data[params->input_tensors->size]); |
| |
| for (int o = 0; o < params->output_tensors->size; o++) { |
| const int output_tensor_idx = params->output_tensors->data[o]; |
| outputs_.push_back(output_tensor_idx); |
| } |
| |
| for (int i = 0; i < params->nodes_to_replace->size; ++i) { |
| const int delegate_node_id = params->nodes_to_replace->data[i]; |
| TfLiteOpaqueNode *node = nullptr; |
| TfLiteOperator *registration = nullptr; |
| TfLiteOpaqueContextGetNodeAndRegistration( |
| opaque_context, delegate_node_id, &node, ®istration); |
| |
| int inputs_size = TfLiteOpaqueNodeNumberOfInputs(node); |
| for (int k = 0; k < inputs_size; k++) { |
| const int *inputs_data; |
| int num_inputs; |
| EXPECT_EQ(kTfLiteOk, TfLiteOpaqueNodeInputs(node, &inputs_data, |
| &num_inputs)); |
| const int t = inputs_data[k]; |
| const void *data = nullptr; |
| auto opaque_tensor = |
| TfLiteOpaqueContextGetOpaqueTensor(opaque_context, t); |
| EXPECT_NE(opaque_tensor, nullptr); |
| auto allocation_type = |
| TfLiteOpaqueTensorGetAllocationType(opaque_tensor); |
| if (allocation_type == kTfLiteMmapRo) { |
| data = TfLiteOpaqueTensorData(opaque_tensor); |
| EXPECT_NE(data, nullptr); |
| |
| if (openvino_graph_builder_test->CreateConstNode( |
| opaque_context, t) != kTfLiteOk) |
| exit(0); |
| } |
| if (inputs.count(t) != 0) { |
| if (data == nullptr) { |
| static int count = 0; |
| if (count == 0) { |
| if (openvino_graph_builder_test->AddInputParams( |
| opaque_tensor, t) != kTfLiteOk) |
| exit(0); |
| compute_inputs_.push_back(t); |
| count++; |
| } |
| } |
| } |
| } |
| EXPECT_EQ(kTfLiteOk, |
| openvino_graph_builder_test->CreateNodeFromTfLiteOp( |
| registration, node, opaque_context)); |
| } |
| |
| openvino_graph_builder_test->UpdateResultNodes(opaque_context, {}); |
| std::shared_ptr<ov::Model> model = std::make_shared<ov::Model>( |
| openvino_graph_builder_test->getResultNodes(), |
| openvino_graph_builder_test->getInputParams()); |
| |
| ov::Core ov_core_(kPluginsXmlPath); |
| std::string deviceStr = "CPU"; |
| ov::InferRequest infer_request_; |
| auto &compiled_model_ = |
| static_cast<UserData *>(user_data)->compiled_model_; |
| compiled_model_ = ov_core_.compile_model(model, deviceStr); |
| |
| infer_request_ = compiled_model_.create_infer_request(); |
| return &compiled_model_; |
| }); |
| |
| TfLiteOperatorSetInvoke(reg_ex, |
| [](TfLiteOpaqueContext *context, |
| TfLiteOpaqueNode *opaque_node) -> TfLiteStatus { |
| return kTfLiteOk; |
| }); |
| |
| TfLiteOperatorSetFree(reg_ex, |
| [](TfLiteOpaqueContext *context, void *data) {}); |
| |
| TfLiteIntArray *execution_plan; |
| TF_LITE_ENSURE_STATUS( |
| TfLiteOpaqueContextGetExecutionPlan(opaque_context, &execution_plan)); |
| TfLiteOpaqueContextReplaceNodeSubsetsWithDelegateKernels( |
| opaque_context, reg_ex, execution_plan, opaque_delegate_); |
| return kTfLiteOk; |
| }; |
| |
| TfLiteModel *model = TfLiteModelCreateFromFile( |
| "external/org_tensorflow/tensorflow/lite/testdata/add.bin"); |
| ASSERT_NE(model, nullptr); |
| |
| TfLiteOpaqueDelegate *opaque_delegate = |
| TfLiteOpaqueDelegateCreate(&opaque_delegate_builder); |
| TfLiteInterpreterOptions *options = TfLiteInterpreterOptionsCreate(); |
| ASSERT_NE(options, nullptr); |
| TfLiteInterpreterOptionsAddDelegate(options, opaque_delegate); |
| TfLiteInterpreter *interpreter = TfLiteInterpreterCreate(model, options); |
| ASSERT_NE(interpreter, nullptr); |
| |
| EXPECT_TRUE(user_data.delegate_prepared_); |
| |
| TfLiteInterpreterOptionsDelete(options); |
| TfLiteInterpreterDelete(interpreter); |
| TfLiteModelDelete(model); |
| TfLiteOpaqueDelegateDelete(opaque_delegate); |
| } |
| |
| TEST_F(OpenVINOGraphBuilderTest, CreateNodeFromTfLiteOp_InvalidRegistration) { |
| TfLiteOpaqueDelegateBuilder opaque_delegate_builder{}; |
| struct UserData { |
| bool delegate_prepared_ = false; |
| ov::CompiledModel compiled_model_; |
| } user_data; |
| |
| opaque_delegate_builder.data = &user_data; |
| opaque_delegate_builder.Prepare = [](TfLiteOpaqueContext *opaque_context, |
| TfLiteOpaqueDelegate *opaque_delegate_, |
| void *data) -> TfLiteStatus { |
| static_cast<UserData *>(data)->delegate_prepared_ = true; |
| auto reg_ex = TfLiteOperatorCreate(kTfLiteBuiltinDelegate, |
| "Test driver Openvino delegate", |
| /*version=*/1, data); |
| TfLiteOperatorSetInitWithData( |
| reg_ex, |
| [](void *user_data, TfLiteOpaqueContext *opaque_context, |
| const char *buffer, size_t length) -> void * { |
| auto openvino_graph_builder_test = |
| std::make_unique<OpenVINOGraphBuilder>( |
| std::make_unique<NodeManager>()); |
| std::vector<int> compute_inputs_ = {}; |
| std::vector<int> outputs_ = {}; |
| const TfLiteOpaqueDelegateParams *params = |
| reinterpret_cast<const TfLiteOpaqueDelegateParams *>(buffer); |
| const std::unordered_set<int> inputs( |
| ¶ms->input_tensors->data[0], |
| ¶ms->input_tensors->data[params->input_tensors->size]); |
| |
| for (int o = 0; o < params->output_tensors->size; o++) { |
| const int output_tensor_idx = params->output_tensors->data[o]; |
| outputs_.push_back(output_tensor_idx); |
| } |
| |
| for (int i = 0; i < params->nodes_to_replace->size; ++i) { |
| const int delegate_node_id = params->nodes_to_replace->data[i]; |
| TfLiteOpaqueNode *node = nullptr; |
| TfLiteOperator *registration = nullptr; |
| TfLiteOpaqueContextGetNodeAndRegistration( |
| opaque_context, delegate_node_id, &node, ®istration); |
| |
| int inputs_size = TfLiteOpaqueNodeNumberOfInputs(node); |
| for (int k = 0; k < inputs_size; k++) { |
| const int *inputs_data; |
| int num_inputs; |
| EXPECT_EQ(kTfLiteOk, TfLiteOpaqueNodeInputs(node, &inputs_data, |
| &num_inputs)); |
| const int t = inputs_data[k]; |
| const void *data = nullptr; |
| auto opaque_tensor = |
| TfLiteOpaqueContextGetOpaqueTensor(opaque_context, t); |
| EXPECT_NE(opaque_tensor, nullptr); |
| |
| auto allocation_type = |
| TfLiteOpaqueTensorGetAllocationType(opaque_tensor); |
| if (allocation_type == kTfLiteMmapRo) { |
| data = TfLiteOpaqueTensorData(opaque_tensor); |
| EXPECT_NE(data, nullptr); |
| |
| if (openvino_graph_builder_test->CreateConstNode( |
| opaque_context, t) != kTfLiteOk) |
| exit(0); |
| } |
| if (inputs.count(t) != 0) { |
| if (data == nullptr) { |
| static int count = 0; |
| if (count == 0) { |
| if (openvino_graph_builder_test->AddInputParams( |
| opaque_tensor, t) != kTfLiteOk) |
| exit(0); |
| compute_inputs_.push_back(t); |
| count++; |
| } |
| } |
| } |
| } |
| EXPECT_EQ(kTfLiteError, |
| openvino_graph_builder_test->CreateNodeFromTfLiteOp( |
| nullptr, node, opaque_context)); |
| } |
| |
| openvino_graph_builder_test->UpdateResultNodes(opaque_context, {}); |
| std::shared_ptr<ov::Model> model = std::make_shared<ov::Model>( |
| openvino_graph_builder_test->getResultNodes(), |
| openvino_graph_builder_test->getInputParams()); |
| |
| ov::Core ov_core_(kPluginsXmlPath); |
| std::string deviceStr = "CPU"; |
| ov::InferRequest infer_request_; |
| auto &compiled_model_ = |
| static_cast<UserData *>(user_data)->compiled_model_; |
| compiled_model_ = ov_core_.compile_model(model, deviceStr); |
| |
| infer_request_ = compiled_model_.create_infer_request(); |
| return &compiled_model_; |
| }); |
| |
| TfLiteOperatorSetInvoke(reg_ex, |
| [](TfLiteOpaqueContext *context, |
| TfLiteOpaqueNode *opaque_node) -> TfLiteStatus { |
| return kTfLiteOk; |
| }); |
| |
| TfLiteOperatorSetFree(reg_ex, |
| [](TfLiteOpaqueContext *context, void *data) {}); |
| |
| TfLiteIntArray *execution_plan; |
| TF_LITE_ENSURE_STATUS( |
| TfLiteOpaqueContextGetExecutionPlan(opaque_context, &execution_plan)); |
| TfLiteOpaqueContextReplaceNodeSubsetsWithDelegateKernels( |
| opaque_context, reg_ex, execution_plan, opaque_delegate_); |
| return kTfLiteOk; |
| }; |
| |
| TfLiteModel *model = TfLiteModelCreateFromFile( |
| "external/org_tensorflow/tensorflow/lite/testdata/add.bin"); |
| ASSERT_NE(model, nullptr); |
| |
| TfLiteOpaqueDelegate *opaque_delegate = |
| TfLiteOpaqueDelegateCreate(&opaque_delegate_builder); |
| TfLiteInterpreterOptions *options = TfLiteInterpreterOptionsCreate(); |
| ASSERT_NE(options, nullptr); |
| TfLiteInterpreterOptionsAddDelegate(options, opaque_delegate); |
| TfLiteInterpreter *interpreter = TfLiteInterpreterCreate(model, options); |
| ASSERT_NE(interpreter, nullptr); |
| |
| EXPECT_TRUE(user_data.delegate_prepared_); |
| |
| TfLiteInterpreterOptionsDelete(options); |
| TfLiteInterpreterDelete(interpreter); |
| TfLiteModelDelete(model); |
| TfLiteOpaqueDelegateDelete(opaque_delegate); |
| } |
| |
| TEST_F(OpenVINOGraphBuilderTest, CreateNodeFromTfLiteOp_InvalidNode) { |
| TfLiteOpaqueDelegateBuilder opaque_delegate_builder{}; |
| struct UserData { |
| bool delegate_prepared_ = false; |
| ov::CompiledModel compiled_model_; |
| } user_data; |
| |
| opaque_delegate_builder.data = &user_data; |
| opaque_delegate_builder.Prepare = [](TfLiteOpaqueContext *opaque_context, |
| TfLiteOpaqueDelegate *opaque_delegate_, |
| void *data) -> TfLiteStatus { |
| static_cast<UserData *>(data)->delegate_prepared_ = true; |
| auto reg_ex = TfLiteOperatorCreate(kTfLiteBuiltinDelegate, |
| "Test driver Openvino delegate", |
| /*version=*/1, data); |
| TfLiteOperatorSetInitWithData( |
| reg_ex, |
| [](void *user_data, TfLiteOpaqueContext *opaque_context, |
| const char *buffer, size_t length) -> void * { |
| auto openvino_graph_builder_test = |
| std::make_unique<OpenVINOGraphBuilder>( |
| std::make_unique<NodeManager>()); |
| std::vector<int> compute_inputs_ = {}; |
| std::vector<int> outputs_ = {}; |
| const TfLiteOpaqueDelegateParams *params = |
| reinterpret_cast<const TfLiteOpaqueDelegateParams *>(buffer); |
| const std::unordered_set<int> inputs( |
| ¶ms->input_tensors->data[0], |
| ¶ms->input_tensors->data[params->input_tensors->size]); |
| |
| for (int o = 0; o < params->output_tensors->size; o++) { |
| const int output_tensor_idx = params->output_tensors->data[o]; |
| outputs_.push_back(output_tensor_idx); |
| } |
| |
| for (int i = 0; i < params->nodes_to_replace->size; ++i) { |
| const int delegate_node_id = params->nodes_to_replace->data[i]; |
| TfLiteOpaqueNode *node = nullptr; |
| TfLiteOperator *registration = nullptr; |
| TfLiteOpaqueContextGetNodeAndRegistration( |
| opaque_context, delegate_node_id, &node, ®istration); |
| |
| int inputs_size = TfLiteOpaqueNodeNumberOfInputs(node); |
| for (int k = 0; k < inputs_size; k++) { |
| const int *inputs_data; |
| int num_inputs; |
| EXPECT_EQ(kTfLiteOk, TfLiteOpaqueNodeInputs(node, &inputs_data, |
| &num_inputs)); |
| const int t = inputs_data[k]; |
| const void *data = nullptr; |
| auto opaque_tensor = |
| TfLiteOpaqueContextGetOpaqueTensor(opaque_context, t); |
| EXPECT_NE(opaque_tensor, nullptr); |
| |
| auto allocation_type = |
| TfLiteOpaqueTensorGetAllocationType(opaque_tensor); |
| if (allocation_type == kTfLiteMmapRo) { |
| data = TfLiteOpaqueTensorData(opaque_tensor); |
| EXPECT_NE(data, nullptr); |
| |
| if (openvino_graph_builder_test->CreateConstNode( |
| opaque_context, t) != kTfLiteOk) |
| exit(0); |
| } |
| if (inputs.count(t) != 0) { |
| if (data == nullptr) { |
| static int count = 0; |
| if (count == 0) { |
| if (openvino_graph_builder_test->AddInputParams( |
| opaque_tensor, t) != kTfLiteOk) |
| exit(0); |
| compute_inputs_.push_back(t); |
| count++; |
| } |
| } |
| } |
| } |
| EXPECT_EQ(kTfLiteError, |
| openvino_graph_builder_test->CreateNodeFromTfLiteOp( |
| registration, nullptr, opaque_context)); |
| } |
| |
| openvino_graph_builder_test->UpdateResultNodes(opaque_context, {}); |
| std::shared_ptr<ov::Model> model = std::make_shared<ov::Model>( |
| openvino_graph_builder_test->getResultNodes(), |
| openvino_graph_builder_test->getInputParams()); |
| |
| ov::Core ov_core_(kPluginsXmlPath); |
| std::string deviceStr = "CPU"; |
| ov::InferRequest infer_request_; |
| auto &compiled_model_ = |
| static_cast<UserData *>(user_data)->compiled_model_; |
| compiled_model_ = ov_core_.compile_model(model, deviceStr); |
| |
| infer_request_ = compiled_model_.create_infer_request(); |
| return &compiled_model_; |
| }); |
| |
| TfLiteOperatorSetInvoke(reg_ex, |
| [](TfLiteOpaqueContext *context, |
| TfLiteOpaqueNode *opaque_node) -> TfLiteStatus { |
| return kTfLiteOk; |
| }); |
| |
| TfLiteOperatorSetFree(reg_ex, |
| [](TfLiteOpaqueContext *context, void *data) {}); |
| |
| TfLiteIntArray *execution_plan; |
| TF_LITE_ENSURE_STATUS( |
| TfLiteOpaqueContextGetExecutionPlan(opaque_context, &execution_plan)); |
| TfLiteOpaqueContextReplaceNodeSubsetsWithDelegateKernels( |
| opaque_context, reg_ex, execution_plan, opaque_delegate_); |
| return kTfLiteOk; |
| }; |
| |
| TfLiteModel *model = TfLiteModelCreateFromFile( |
| "external/org_tensorflow/tensorflow/lite/testdata/add.bin"); |
| ASSERT_NE(model, nullptr); |
| |
| TfLiteOpaqueDelegate *opaque_delegate = |
| TfLiteOpaqueDelegateCreate(&opaque_delegate_builder); |
| TfLiteInterpreterOptions *options = TfLiteInterpreterOptionsCreate(); |
| ASSERT_NE(options, nullptr); |
| TfLiteInterpreterOptionsAddDelegate(options, opaque_delegate); |
| TfLiteInterpreter *interpreter = TfLiteInterpreterCreate(model, options); |
| ASSERT_NE(interpreter, nullptr); |
| |
| EXPECT_TRUE(user_data.delegate_prepared_); |
| |
| TfLiteInterpreterOptionsDelete(options); |
| TfLiteInterpreterDelete(interpreter); |
| TfLiteModelDelete(model); |
| TfLiteOpaqueDelegateDelete(opaque_delegate); |
| } |
| |
| TEST_F(OpenVINOGraphBuilderTest, CreateNodeFromTfLiteOp_InvalidContext) { |
| TfLiteOpaqueDelegateBuilder opaque_delegate_builder{}; |
| struct UserData { |
| bool delegate_prepared_ = false; |
| ov::CompiledModel compiled_model_; |
| } user_data; |
| |
| opaque_delegate_builder.data = &user_data; |
| opaque_delegate_builder.Prepare = [](TfLiteOpaqueContext *opaque_context, |
| TfLiteOpaqueDelegate *opaque_delegate_, |
| void *data) -> TfLiteStatus { |
| static_cast<UserData *>(data)->delegate_prepared_ = true; |
| auto reg_ex = TfLiteOperatorCreate(kTfLiteBuiltinDelegate, |
| "Test driver Openvino delegate", |
| /*version=*/1, data); |
| TfLiteOperatorSetInitWithData( |
| reg_ex, |
| [](void *user_data, TfLiteOpaqueContext *opaque_context, |
| const char *buffer, size_t length) -> void * { |
| auto openvino_graph_builder_test = |
| std::make_unique<OpenVINOGraphBuilder>( |
| std::make_unique<NodeManager>()); |
| std::vector<int> compute_inputs_ = {}; |
| std::vector<int> outputs_ = {}; |
| const TfLiteOpaqueDelegateParams *params = |
| reinterpret_cast<const TfLiteOpaqueDelegateParams *>(buffer); |
| const std::unordered_set<int> inputs( |
| ¶ms->input_tensors->data[0], |
| ¶ms->input_tensors->data[params->input_tensors->size]); |
| |
| for (int o = 0; o < params->output_tensors->size; o++) { |
| const int output_tensor_idx = params->output_tensors->data[o]; |
| outputs_.push_back(output_tensor_idx); |
| } |
| |
| for (int i = 0; i < params->nodes_to_replace->size; ++i) { |
| const int delegate_node_id = params->nodes_to_replace->data[i]; |
| TfLiteOpaqueNode *node = nullptr; |
| TfLiteOperator *registration = nullptr; |
| TfLiteOpaqueContextGetNodeAndRegistration( |
| opaque_context, delegate_node_id, &node, ®istration); |
| |
| int inputs_size = TfLiteOpaqueNodeNumberOfInputs(node); |
| for (int k = 0; k < inputs_size; k++) { |
| const int *inputs_data; |
| int num_inputs; |
| EXPECT_EQ(kTfLiteOk, TfLiteOpaqueNodeInputs(node, &inputs_data, |
| &num_inputs)); |
| const int t = inputs_data[k]; |
| const void *data = nullptr; |
| auto opaque_tensor = |
| TfLiteOpaqueContextGetOpaqueTensor(opaque_context, t); |
| auto allocation_type = |
| TfLiteOpaqueTensorGetAllocationType(opaque_tensor); |
| EXPECT_NE(opaque_tensor, nullptr); |
| |
| if (allocation_type == kTfLiteMmapRo) { |
| data = TfLiteOpaqueTensorData(opaque_tensor); |
| EXPECT_NE(data, nullptr); |
| |
| if (openvino_graph_builder_test->CreateConstNode( |
| opaque_context, t) != kTfLiteOk) |
| exit(0); |
| } |
| if (inputs.count(t) != 0) { |
| if (data == nullptr) { |
| static int count = 0; |
| if (count == 0) { |
| if (openvino_graph_builder_test->AddInputParams( |
| opaque_tensor, t) != kTfLiteOk) |
| exit(0); |
| compute_inputs_.push_back(t); |
| count++; |
| } |
| } |
| } |
| } |
| EXPECT_EQ(kTfLiteError, |
| openvino_graph_builder_test->CreateNodeFromTfLiteOp( |
| registration, node, nullptr)); |
| } |
| |
| openvino_graph_builder_test->UpdateResultNodes(opaque_context, {}); |
| std::shared_ptr<ov::Model> model = std::make_shared<ov::Model>( |
| openvino_graph_builder_test->getResultNodes(), |
| openvino_graph_builder_test->getInputParams()); |
| |
| ov::Core ov_core_(kPluginsXmlPath); |
| std::string deviceStr = "CPU"; |
| ov::InferRequest infer_request_; |
| auto &compiled_model_ = |
| static_cast<UserData *>(user_data)->compiled_model_; |
| compiled_model_ = ov_core_.compile_model(model, deviceStr); |
| |
| infer_request_ = compiled_model_.create_infer_request(); |
| return &compiled_model_; |
| }); |
| |
| TfLiteOperatorSetInvoke(reg_ex, |
| [](TfLiteOpaqueContext *context, |
| TfLiteOpaqueNode *opaque_node) -> TfLiteStatus { |
| return kTfLiteOk; |
| }); |
| |
| TfLiteOperatorSetFree(reg_ex, |
| [](TfLiteOpaqueContext *context, void *data) {}); |
| |
| TfLiteIntArray *execution_plan; |
| TF_LITE_ENSURE_STATUS( |
| TfLiteOpaqueContextGetExecutionPlan(opaque_context, &execution_plan)); |
| TfLiteOpaqueContextReplaceNodeSubsetsWithDelegateKernels( |
| opaque_context, reg_ex, execution_plan, opaque_delegate_); |
| return kTfLiteOk; |
| }; |
| |
| TfLiteModel *model = TfLiteModelCreateFromFile( |
| "external/org_tensorflow/tensorflow/lite/testdata/add.bin"); |
| ASSERT_NE(model, nullptr); |
| |
| TfLiteOpaqueDelegate *opaque_delegate = |
| TfLiteOpaqueDelegateCreate(&opaque_delegate_builder); |
| TfLiteInterpreterOptions *options = TfLiteInterpreterOptionsCreate(); |
| ASSERT_NE(options, nullptr); |
| TfLiteInterpreterOptionsAddDelegate(options, opaque_delegate); |
| TfLiteInterpreter *interpreter = TfLiteInterpreterCreate(model, options); |
| ASSERT_NE(interpreter, nullptr); |
| |
| EXPECT_TRUE(user_data.delegate_prepared_); |
| |
| TfLiteInterpreterOptionsDelete(options); |
| TfLiteInterpreterDelete(interpreter); |
| TfLiteModelDelete(model); |
| TfLiteOpaqueDelegateDelete(opaque_delegate); |
| } |
| |
| } // namespace openvinodelegate |
| } // namespace tflite |
| |
| int main(int argc, char **argv) { |
| testing::InitGoogleTest(&argc, argv); |
| return RUN_ALL_TESTS(); |
| } |