chore: import upstream snapshot with attribution
cffconvert / validate (push) Has been skipped
License Check / license-check (push) Failing after 2s

This commit is contained in:
wehub-resource-sync
2026-07-13 12:14:16 +08:00
commit 8a852e4b4e
36502 changed files with 9277225 additions and 0 deletions
+111
View File
@@ -0,0 +1,111 @@
load("@rules_cc//cc:cc_library.bzl", "cc_library")
load(
"//tensorflow:tensorflow.bzl",
"tf_cc_test",
)
load("//tensorflow:tensorflow.default.bzl", "get_compatible_with_portable")
package(
# copybara:uncomment default_applicable_licenses = ["//tensorflow:LICENSE"],
default_visibility = ["//visibility:public"],
licenses = ["notice"],
)
cc_library(
name = "versioning",
hdrs = [
"op_version.h",
],
compatible_with = get_compatible_with_portable(),
deps = [
"//tensorflow/compiler/mlir/lite/tools/versioning",
],
)
cc_library(
name = "op_signature",
srcs = [
"op_signature.cc",
],
hdrs = [
"op_signature.h",
],
compatible_with = get_compatible_with_portable(),
deps = [
"//tensorflow/compiler/mlir/lite/tools/versioning:op_signature",
"//tensorflow/lite:stderr_reporter",
"//tensorflow/lite/core/api",
"//tensorflow/lite/core/c:c_api_types",
"//tensorflow/lite/core/c:common",
"//tensorflow/lite/kernels:kernel_util",
"//tensorflow/lite/kernels/internal:compatibility",
"//tensorflow/lite/schema:schema_fbs",
"//tensorflow/lite/schema:schema_utils",
],
)
tf_cc_test(
name = "op_signature_test",
srcs = [
"op_signature_test.cc",
],
data = [
"//tensorflow/lite:testdata/add.bin",
"//tensorflow/lite:testdata/multi_signatures.bin",
],
deps = [
":op_signature",
"//tensorflow/core/platform:resource_loader",
"//tensorflow/lite:builtin_ops",
"//tensorflow/lite/core:model_builder",
"@com_google_googletest//:gtest_main",
],
)
cc_library(
name = "gpu_compatibility",
srcs = [
"gpu_compatibility.cc",
],
hdrs = [
"gpu_compatibility.h",
],
compatible_with = get_compatible_with_portable(),
deps = [
":op_signature",
"//tensorflow/lite:builtin_op_data",
"//tensorflow/lite:builtin_ops",
"//tensorflow/lite:util",
"//tensorflow/lite/c:c_api_types",
"//tensorflow/lite/c:common",
"//tensorflow/lite/core/c:common",
"//tensorflow/lite/schema:schema_fbs",
"@com_google_absl//absl/status",
"@com_google_absl//absl/strings",
"@com_google_absl//absl/strings:str_format",
],
)
tf_cc_test(
name = "gpu_compatibility_test",
srcs = [
"gpu_compatibility_test.cc",
],
data = [
"//tensorflow/lite:testdata/conv3d_huge_im2col.bin",
"//tensorflow/lite:testdata/conv_huge_im2col.bin",
"//tensorflow/lite:testdata/multi_add_flex.bin",
],
deps = [
":gpu_compatibility",
":op_signature",
"//tensorflow/core/platform:resource_loader",
"//tensorflow/lite/core:model_builder",
"//tensorflow/lite/core/c:common",
"//tensorflow/lite/kernels/internal:types",
"//tensorflow/lite/schema:schema_fbs",
"@com_google_absl//absl/status",
"@com_google_absl//absl/status:status_matchers",
"@com_google_googletest//:gtest_main",
],
)
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,54 @@
/* Copyright 2021 The TensorFlow Authors. All Rights Reserved.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
==============================================================================*/
#ifndef TENSORFLOW_LITE_TOOLS_VERSIONING_GPU_COMPATIBILITY_H_
#define TENSORFLOW_LITE_TOOLS_VERSIONING_GPU_COMPATIBILITY_H_
#include "absl/status/status.h"
#include "tensorflow/lite/core/c/common.h"
#include "tensorflow/lite/schema/schema_generated.h"
#include "tensorflow/lite/tools/versioning/op_signature.h"
namespace tflite {
// Bitwise flags to specify GPU compatibility. Multiple flags can be set.
enum class GpuCompatibilityFlags {
kStandard = 0,
kEnhancedBroadcast = 1 << 0, // Set when backend supports enhanced broadcast.
};
// Check if the given op signature is compatible with GPU delegate.
absl::Status CheckGpuDelegateCompatibility(
const OpSignature& op_sig,
GpuCompatibilityFlags flags = GpuCompatibilityFlags::kStandard);
// Check if the given operator in a TFLite flatbuffer model is compatible with
// GPU delegate.
// WARNING: It's not fully implemented and still under development. Only use the
// function for an experimental feature.
// WARNING: This is an experimental API and subject to change.
absl::Status CheckGpuDelegateCompatibility(const OperatorCode* op_code,
const Operator* op,
const SubGraph* subgraph,
const Model* model);
// Check if the given TfLiteNode op is compatible with GPU delegate.
absl::Status CheckGpuDelegateCompatibility(
const TfLiteContext* context, const TfLiteNode* node,
const TfLiteRegistration* registration,
GpuCompatibilityFlags flags = GpuCompatibilityFlags::kStandard);
} // namespace tflite
#endif // TENSORFLOW_LITE_TOOLS_VERSIONING_GPU_COMPATIBILITY_H_
@@ -0,0 +1,304 @@
/* Copyright 2021 The TensorFlow Authors. All Rights Reserved.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
==============================================================================*/
#include "tensorflow/lite/tools/versioning/gpu_compatibility.h"
#include <memory>
#include <string>
#include <vector>
#include <gmock/gmock.h>
#include <gtest/gtest.h>
#include "absl/status/status.h"
#include "absl/status/status_matchers.h"
#include "tensorflow/core/platform/resource_loader.h"
#include "tensorflow/lite/core/c/builtin_op_data.h"
#include "tensorflow/lite/core/model_builder.h"
#include "tensorflow/lite/kernels/internal/types.h"
#include "tensorflow/lite/schema/schema_generated.h"
#include "tensorflow/lite/tools/versioning/op_signature.h"
namespace tflite {
namespace {
using ::absl_testing::IsOk;
using ::absl_testing::StatusIs;
using ::testing::HasSubstr;
absl::Status CheckGpuDelegateCompatibility(const tflite::Model* model) {
auto subgraphs = model->subgraphs();
for (int i = 0; i < subgraphs->Length(); ++i) {
const SubGraph* subgraph = subgraphs->Get(i);
for (int j = 0; j < subgraph->operators()->Length(); ++j) {
const Operator* op = subgraph->operators()->Get(j);
const OperatorCode* op_code =
model->operator_codes()->Get(op->opcode_index());
auto status = CheckGpuDelegateCompatibility(op_code, op, subgraph, model);
if (!status.ok()) {
return status;
}
}
}
return absl::OkStatus();
}
} // namespace
// FYI, CheckGpuDelegateCompatibility() will be validated by
// third_party/tensorflow/lite/delegates/gpu/common:model_builder_test
TEST(CheckGpuDelegateCompatibility, Conv2DModel) {
const std::string& full_path = tensorflow::GetDataDependencyFilepath(
"tensorflow/lite/testdata/conv_huge_im2col.bin");
auto model = FlatBufferModel::BuildFromFile(full_path.data());
ASSERT_TRUE(model);
EXPECT_TRUE(CheckGpuDelegateCompatibility(model->GetModel()).ok());
}
TEST(CheckGpuDelegateCompatibility, Conv3DModel) {
const std::string& full_path = tensorflow::GetDataDependencyFilepath(
"tensorflow/lite/testdata/conv3d_huge_im2col.bin");
auto model = FlatBufferModel::BuildFromFile(full_path.data());
ASSERT_TRUE(model);
EXPECT_EQ(CheckGpuDelegateCompatibility(model->GetModel()).message(),
"Not supported op CONV_3D");
}
TEST(CheckGpuDelegateCompatibility, FlexModel) {
const std::string& full_path = tensorflow::GetDataDependencyFilepath(
"tensorflow/lite/testdata/multi_add_flex.bin");
auto model = FlatBufferModel::BuildFromFile(full_path.data());
ASSERT_TRUE(model);
EXPECT_EQ(CheckGpuDelegateCompatibility(model->GetModel()).message(),
"Not supported custom op FlexAddV2");
}
TEST(CheckGpuDelegateCompatibility, FCConstInput) {
OpSignature op_sig = OpSignature();
op_sig.op = BuiltinOperator_FULLY_CONNECTED;
auto params = std::make_unique<TfLiteFullyConnectedParams>();
params->weights_format = kTfLiteFullyConnectedWeightsFormatDefault;
op_sig.builtin_data = static_cast<void*>(params.get());
op_sig.inputs = std::vector<OpSignatureTensorSpec>(1);
op_sig.inputs[0] = OpSignatureTensorSpec();
op_sig.inputs[0].is_const = true;
EXPECT_EQ(CheckGpuDelegateCompatibility(op_sig).message(),
"FullyConnected doesn't support constant input.");
}
TEST(CheckGpuDelegateCompatibility, Add1Dto3DBroadcastSuccess) {
OpSignature op_sig = OpSignature();
op_sig.op = BuiltinOperator_ADD;
auto params = std::make_unique<TfLiteAddParams>();
op_sig.builtin_data = static_cast<void*>(params.get());
op_sig.inputs = std::vector<OpSignatureTensorSpec>(2);
op_sig.inputs[0] = OpSignatureTensorSpec();
op_sig.inputs[0].dims = {4, 1, 2};
op_sig.inputs[1] = OpSignatureTensorSpec();
op_sig.inputs[1].dims = {2};
EXPECT_TRUE(CheckGpuDelegateCompatibility(op_sig).message().empty());
}
TEST(CheckGpuDelegateCompatibility, Add2Dto3DBroadcastFail) {
OpSignature op_sig = OpSignature();
op_sig.op = BuiltinOperator_ADD;
auto params = std::make_unique<TfLiteAddParams>();
op_sig.builtin_data = static_cast<void*>(params.get());
op_sig.inputs = std::vector<OpSignatureTensorSpec>(2);
op_sig.inputs[0] = OpSignatureTensorSpec();
op_sig.inputs[0].dims = {1, 100, 256};
op_sig.inputs[1] = OpSignatureTensorSpec();
op_sig.inputs[1].dims = {100, 256};
EXPECT_EQ(CheckGpuDelegateCompatibility(op_sig).message(),
"Doesn't support broadcasting - input0: [1,100,256], input1: "
"[100,256]");
}
TEST(CheckGpuDelegateCompatibility, Add3Dto4DBroadcastFail) {
OpSignature op_sig = OpSignature();
op_sig.op = BuiltinOperator_ADD;
auto params = std::make_unique<TfLiteAddParams>();
op_sig.builtin_data = static_cast<void*>(params.get());
op_sig.inputs = std::vector<OpSignatureTensorSpec>(2);
op_sig.inputs[0] = OpSignatureTensorSpec();
op_sig.inputs[0].dims = {4, 1, 1, 2};
op_sig.inputs[1] = OpSignatureTensorSpec();
// Can't broadcast using batch of 4
op_sig.inputs[1].dims = {1, 1, 2};
EXPECT_EQ(
CheckGpuDelegateCompatibility(op_sig).message(),
"Doesn't support broadcasting - input0: [4,1,1,2], input1: [1,1,2]");
}
TEST(CheckGpuDelegateCompatibility, Add3Dto4DBroadcastSuccess) {
OpSignature op_sig = OpSignature();
op_sig.op = BuiltinOperator_ADD;
auto params = std::make_unique<TfLiteAddParams>();
op_sig.builtin_data = static_cast<void*>(params.get());
op_sig.inputs = std::vector<OpSignatureTensorSpec>(2);
op_sig.inputs[0] = OpSignatureTensorSpec();
op_sig.inputs[0].dims = {1, 128, 513, 3};
op_sig.inputs[1] = OpSignatureTensorSpec();
// Can be broadcasted to {1, 128, 513, 3}
op_sig.inputs[1].dims = {128, 513, 3};
EXPECT_TRUE(CheckGpuDelegateCompatibility(op_sig).message().empty());
}
TEST(CheckGpuDelegateCompatibility, Add2Dto4DBroadcastSuccess) {
OpSignature op_sig = OpSignature();
op_sig.op = BuiltinOperator_ADD;
auto params = std::make_unique<TfLiteAddParams>();
op_sig.builtin_data = static_cast<void*>(params.get());
op_sig.inputs = std::vector<OpSignatureTensorSpec>(2);
op_sig.inputs[0] = OpSignatureTensorSpec();
op_sig.inputs[0].dims = {1, 512, 512, 1};
op_sig.inputs[1] = OpSignatureTensorSpec();
// Can be broadcasted to {1, 1, 1, 1}
op_sig.inputs[1].dims = {1, 1};
EXPECT_TRUE(CheckGpuDelegateCompatibility(op_sig).message().empty());
}
TEST(CheckGpuDelegateCompatibility, Add2Dto4DBroadcastSuccess2) {
OpSignature op_sig = OpSignature();
op_sig.op = BuiltinOperator_ADD;
auto params = std::make_unique<TfLiteAddParams>();
op_sig.builtin_data = static_cast<void*>(params.get());
op_sig.inputs = std::vector<OpSignatureTensorSpec>(2);
op_sig.inputs[0] = OpSignatureTensorSpec();
op_sig.inputs[0].dims = {1, 384, 384, 3};
op_sig.inputs[1] = OpSignatureTensorSpec();
// Can be broadcasted to {1, 1, 1, 1}
op_sig.inputs[1].dims = {1, 1};
EXPECT_TRUE(CheckGpuDelegateCompatibility(op_sig).message().empty());
}
TEST(CheckGpuDelegateCompatibility, Add2Dto4DBroadcastSuccess3) {
OpSignature op_sig = OpSignature();
op_sig.op = BuiltinOperator_ADD;
auto params = std::make_unique<TfLiteAddParams>();
op_sig.builtin_data = static_cast<void*>(params.get());
op_sig.inputs = std::vector<OpSignatureTensorSpec>(2);
op_sig.inputs[0] = OpSignatureTensorSpec();
op_sig.inputs[0].dims = {1, 4, 4, 10};
op_sig.inputs[1] = OpSignatureTensorSpec();
// Can be broadcasted to {1, 1, 1, 10}
op_sig.inputs[1].dims = {1, 10};
EXPECT_TRUE(CheckGpuDelegateCompatibility(op_sig).message().empty());
}
TEST(CheckGpuDelegateCompatibility, BasicLstmUnalignedActivationDepth) {
OpSignature op_sig = OpSignature();
op_sig.op = BuiltinOperator_LSTM;
auto params = std::make_unique<TfLiteLSTMParams>();
params->kernel_type = kTfLiteLSTMBasicKernel;
params->activation = kTfLiteActTanh;
op_sig.builtin_data = static_cast<void*>(params.get());
op_sig.inputs = std::vector<OpSignatureTensorSpec>(5);
op_sig.inputs[0].is_const = false;
op_sig.inputs[0].type = kTfLiteFloat32;
op_sig.inputs[1].is_const = true; // weights
op_sig.inputs[1].type = kTfLiteFloat32;
op_sig.inputs[2].is_const = true; // biases
op_sig.inputs[2].type = kTfLiteFloat32;
op_sig.inputs[3].is_const = false;
op_sig.inputs[3].type = kTfLiteFloat32;
op_sig.inputs[4].is_const = false;
op_sig.inputs[4].type = kTfLiteFloat32;
op_sig.outputs = std::vector<OpSignatureTensorSpec>(4);
op_sig.outputs[3].dims = {2, 5}; // unaligned activation depth = 5
EXPECT_THAT(
CheckGpuDelegateCompatibility(op_sig),
StatusIs(
absl::StatusCode::kUnimplemented,
HasSubstr("BasicLSTM activation depth must be a multiple of 4.")));
}
TEST(CheckGpuDelegateCompatibility, BasicLstmAlignedActivationDepth) {
OpSignature op_sig = OpSignature();
op_sig.op = BuiltinOperator_LSTM;
auto params = std::make_unique<TfLiteLSTMParams>();
params->kernel_type = kTfLiteLSTMBasicKernel;
params->activation = kTfLiteActTanh;
op_sig.builtin_data = static_cast<void*>(params.get());
op_sig.inputs = std::vector<OpSignatureTensorSpec>(5);
op_sig.inputs[0].is_const = false;
op_sig.inputs[0].type = kTfLiteFloat32;
op_sig.inputs[1].is_const = true; // weights
op_sig.inputs[1].type = kTfLiteFloat32;
op_sig.inputs[2].is_const = true; // biases
op_sig.inputs[2].type = kTfLiteFloat32;
op_sig.inputs[3].is_const = false;
op_sig.inputs[3].type = kTfLiteFloat32;
op_sig.inputs[4].is_const = false;
op_sig.inputs[4].type = kTfLiteFloat32;
op_sig.outputs = std::vector<OpSignatureTensorSpec>(4);
op_sig.outputs[3].dims = {2, 8}; // aligned activation depth = 8
EXPECT_THAT(CheckGpuDelegateCompatibility(op_sig), IsOk());
}
TEST(CheckGpuDelegateCompatibility, ResamplerMismatchedBatch) {
OpSignature op_sig = OpSignature();
op_sig.op = BuiltinOperator_CUSTOM;
op_sig.custom_name = "Resampler";
op_sig.inputs = std::vector<OpSignatureTensorSpec>(2);
op_sig.inputs[0].is_const = false;
op_sig.inputs[0].type = kTfLiteFloat32;
op_sig.inputs[0].dims = {2, 4, 4, 3};
op_sig.inputs[1].is_const = false;
op_sig.inputs[1].type = kTfLiteFloat32;
op_sig.inputs[1].dims = {1, 4, 4, 2};
op_sig.outputs = std::vector<OpSignatureTensorSpec>(1);
op_sig.outputs[0].type = kTfLiteFloat32;
op_sig.outputs[0].dims = {2, 4, 4, 3};
EXPECT_THAT(CheckGpuDelegateCompatibility(op_sig),
StatusIs(absl::StatusCode::kInvalidArgument,
HasSubstr("src.b != warp.b")));
}
TEST(CheckGpuDelegateCompatibility, ResamplerInvalidChannels) {
OpSignature op_sig = OpSignature();
op_sig.op = BuiltinOperator_CUSTOM;
op_sig.custom_name = "Resampler";
op_sig.inputs = std::vector<OpSignatureTensorSpec>(2);
op_sig.inputs[0].is_const = false;
op_sig.inputs[0].type = kTfLiteFloat32;
op_sig.inputs[0].dims = {1, 4, 4, 3};
op_sig.inputs[1].is_const = false;
op_sig.inputs[1].type = kTfLiteFloat32;
op_sig.inputs[1].dims = {1, 4, 4, 1};
op_sig.outputs = std::vector<OpSignatureTensorSpec>(1);
op_sig.outputs[0].type = kTfLiteFloat32;
op_sig.outputs[0].dims = {1, 4, 4, 3};
EXPECT_THAT(
CheckGpuDelegateCompatibility(op_sig),
StatusIs(absl::StatusCode::kInvalidArgument, HasSubstr("warp.c < 2")));
}
} // namespace tflite
@@ -0,0 +1,80 @@
/* Copyright 2021 The TensorFlow Authors. All Rights Reserved.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
==============================================================================*/
#include "tensorflow/lite/tools/versioning/op_signature.h"
#include <cstdint>
#include <cstring>
#include <vector>
#include "tensorflow/compiler/mlir/lite/tools/versioning/op_signature.h"
#include "tensorflow/lite/core/c/common.h"
#include "tensorflow/lite/kernels/kernel_util.h"
#include "tensorflow/lite/schema/schema_generated.h"
namespace tflite {
namespace {
std::vector<OpSignatureTensorSpec> GetOpSignatureTensorSpecs(
TfLiteIntArray* tensors, const TfLiteContext* context,
const TfLiteNode* tflite_node) {
std::vector<OpSignatureTensorSpec> tensor_specs;
for (int32_t i = 0; i < tensors->size; ++i) {
int32_t tensor_no = tensors->data[i];
OpSignatureTensorSpec tensor_spec = {kTfLiteNoType};
if (tensor_no >= 0) {
const TfLiteTensor* tfl_tensor;
if (context->tensors != nullptr) {
tfl_tensor = &context->tensors[tensor_no];
} else {
tfl_tensor = context->GetTensor(context, tensor_no);
}
if (tfl_tensor != nullptr) {
tensor_spec.type = tfl_tensor->type;
tensor_spec.is_const = (tfl_tensor->allocation_type == kTfLiteMmapRo);
if (tfl_tensor->dims) {
for (int32_t j = 0; j < tfl_tensor->dims->size; ++j) {
tensor_spec.dims.push_back(tfl_tensor->dims->data[j]);
}
}
tensor_spec.is_shape_dynamic = HasUnspecifiedDimension(tfl_tensor);
}
}
tensor_specs.push_back(tensor_spec);
}
return tensor_specs;
}
} // namespace
OpSignature GetOpSignature(const TfLiteContext* context, const TfLiteNode* node,
const TfLiteRegistration* registration) {
OpSignature op_sig = {
static_cast<BuiltinOperator>(registration->builtin_code)};
op_sig.builtin_data = node->builtin_data;
if (op_sig.op == BuiltinOperator_CUSTOM) {
op_sig.custom_name = registration->custom_name;
op_sig.custom_initial_data = node->custom_initial_data;
}
std::memset(&op_sig.ext_options, 0, sizeof(op_sig.ext_options));
op_sig.inputs = GetOpSignatureTensorSpecs(node->inputs, context, node);
op_sig.outputs = GetOpSignatureTensorSpecs(node->outputs, context, node);
op_sig.version = registration->version;
return op_sig;
}
} // namespace tflite
@@ -0,0 +1,30 @@
/* Copyright 2021 The TensorFlow Authors. All Rights Reserved.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
==============================================================================*/
#ifndef TENSORFLOW_LITE_TOOLS_VERSIONING_OP_SIGNATURE_H_
#define TENSORFLOW_LITE_TOOLS_VERSIONING_OP_SIGNATURE_H_
#include "tensorflow/compiler/mlir/lite/tools/versioning/op_signature.h" // iwyu pragma: export
#include "tensorflow/lite/core/c/common.h"
namespace tflite {
// Generate OpSignature with the given TfLiteContext, TfLiteNode and
// TfLiteRegistration.
// The function can be used by a compatibility checker of a delegate such as
// TFLiteOperationParser::IsSupported() in the GPU delegate.
OpSignature GetOpSignature(const TfLiteContext* context, const TfLiteNode* node,
const TfLiteRegistration* registration);
} // namespace tflite
#endif // TENSORFLOW_LITE_TOOLS_VERSIONING_OP_SIGNATURE_H_
@@ -0,0 +1,224 @@
/* Copyright 2021 The TensorFlow Authors. All Rights Reserved.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
==============================================================================*/
#include "tensorflow/lite/tools/versioning/op_signature.h"
#include <cstdlib>
#include <cstring>
#include <memory>
#include <string>
#include <vector>
#include <gtest/gtest.h>
#include "tensorflow/core/platform/resource_loader.h"
#include "tensorflow/lite/builtin_ops.h"
#include "tensorflow/lite/core/model_builder.h"
namespace tflite {
// StubTfLiteContext is a TfLiteContext which has 3 nodes as the followings.
// dummyAdd -> target op -> dummyAdd
class StubTfLiteContext : public TfLiteContext {
public:
StubTfLiteContext(const int builtin_code, const int op_version,
const int num_inputs)
: TfLiteContext({0}) {
// Stub execution plan
exec_plan_ = TfLiteIntArrayCreate(3);
for (int i = 0; i < 3; ++i) exec_plan_->data[i] = i;
int tensor_no = 0;
std::memset(nodes_, 0, sizeof(nodes_));
std::memset(registrations_, 0, sizeof(registrations_));
// Node 0, dummyAdd
nodes_[0].inputs = TfLiteIntArrayCreate(1);
nodes_[0].inputs->data[0] = tensor_no++;
nodes_[0].outputs = TfLiteIntArrayCreate(1);
nodes_[0].outputs->data[0] = tensor_no;
nodes_[0].builtin_data = nullptr;
// Node 1, target op
nodes_[1].inputs = TfLiteIntArrayCreate(num_inputs);
for (int i = 0; i < num_inputs; i++) {
nodes_[1].inputs->data[i] = tensor_no++;
}
nodes_[1].outputs = TfLiteIntArrayCreate(1);
nodes_[1].outputs->data[0] = tensor_no;
nodes_[1].builtin_data = malloc(1024);
std::memset(nodes_[1].builtin_data, 0, 1024);
// Node 2, dummyAdd
nodes_[2].inputs = TfLiteIntArrayCreate(1);
nodes_[2].inputs->data[0] = tensor_no++;
nodes_[2].outputs = TfLiteIntArrayCreate(1);
nodes_[2].outputs->data[0] = tensor_no++;
nodes_[2].builtin_data = nullptr;
// Creates tensors of 4d float32
tensors_.resize(tensor_no);
for (size_t i = 0; i < tensors_.size(); i++) {
std::memset(&tensors_[i], 0, sizeof(tensors_[i]));
tensors_[i].buffer_handle = kTfLiteNullBufferHandle;
tensors_[i].type = kTfLiteFloat32;
tensors_[i].dims = TfLiteIntArrayCreate(4);
for (int d = 0; d < 4; d++) {
tensors_[i].dims->data[d] = 1;
}
}
tensors = tensors_.data();
tensors_size = tensors_.size();
// Creates registrations
registrations_[0].builtin_code = kTfLiteBuiltinAdd;
registrations_[1].builtin_code = builtin_code;
registrations_[1].version = op_version;
registrations_[2].builtin_code = kTfLiteBuiltinAdd;
this->GetExecutionPlan = StubGetExecutionPlan;
this->GetNodeAndRegistration = StubGetNodeAndRegistration;
}
~StubTfLiteContext() {
for (auto& node : nodes_) {
TfLiteIntArrayFree(node.inputs);
TfLiteIntArrayFree(node.outputs);
if (node.builtin_data) {
free(node.builtin_data);
}
}
for (auto& tensor : tensors_) {
TfLiteIntArrayFree(tensor.dims);
}
TfLiteIntArrayFree(exec_plan_);
}
TfLiteIntArray* exec_plan() const { return exec_plan_; }
TfLiteNode* node() { return &nodes_[1]; }
TfLiteRegistration* registration() { return &registrations_[1]; }
TfLiteNode* node(int node_index) { return &nodes_[node_index]; }
TfLiteRegistration* registration(int reg_index) {
return &registrations_[reg_index];
}
TfLiteTensor* tensor(int tensor_index) { return &tensors_[tensor_index]; }
private:
static TfLiteStatus StubGetExecutionPlan(TfLiteContext* context,
TfLiteIntArray** execution_plan) {
StubTfLiteContext* stub = reinterpret_cast<StubTfLiteContext*>(context);
*execution_plan = stub->exec_plan();
return kTfLiteOk;
}
static TfLiteStatus StubGetNodeAndRegistration(
TfLiteContext* context, int node_index, TfLiteNode** node,
TfLiteRegistration** registration) {
StubTfLiteContext* stub = reinterpret_cast<StubTfLiteContext*>(context);
*node = stub->node(node_index);
*registration = stub->registration(node_index);
return kTfLiteOk;
}
TfLiteIntArray* exec_plan_;
TfLiteNode nodes_[3];
TfLiteRegistration registrations_[3];
std::vector<TfLiteTensor> tensors_;
};
TEST(GetOpSignature, FlatBufferModel) {
const std::string& full_path =
tensorflow::GetDataDependencyFilepath("tensorflow/lite/testdata/add.bin");
auto fb_model = FlatBufferModel::BuildFromFile(full_path.data());
ASSERT_TRUE(fb_model);
auto model = fb_model->GetModel();
auto subgraphs = model->subgraphs();
const SubGraph* subgraph = subgraphs->Get(0);
const Operator* op1 = subgraph->operators()->Get(0);
const OperatorCode* op_code1 =
model->operator_codes()->Get(op1->opcode_index());
OpSignature op_sig = GetOpSignature(op_code1, op1, subgraph, model);
EXPECT_EQ(op_sig.op, BuiltinOperator_ADD);
EXPECT_EQ(op_sig.inputs[0].type, kTfLiteFloat32);
EXPECT_EQ(op_sig.inputs[0].dims.size(), 4);
EXPECT_FALSE(op_sig.inputs[0].is_const);
EXPECT_FALSE(op_sig.inputs[0].is_shape_dynamic);
EXPECT_EQ(op_sig.outputs[0].type, kTfLiteFloat32);
EXPECT_FALSE(op_sig.outputs[0].is_const);
EXPECT_EQ(op_sig.outputs[0].dims.size(), 4);
EXPECT_FALSE(op_sig.outputs[0].is_shape_dynamic);
EXPECT_NE(op_sig.builtin_data, nullptr);
EXPECT_EQ(op_sig.version, 1);
free(op_sig.builtin_data);
const Operator* op2 = subgraph->operators()->Get(1);
const OperatorCode* op_code2 =
model->operator_codes()->Get(op2->opcode_index());
op_sig = GetOpSignature(op_code2, op2, subgraph, model);
EXPECT_EQ(op_sig.op, BuiltinOperator_ADD);
EXPECT_EQ(op_sig.inputs[0].type, kTfLiteFloat32);
EXPECT_EQ(op_sig.inputs[0].dims.size(), 4);
EXPECT_FALSE(op_sig.inputs[0].is_const);
EXPECT_FALSE(op_sig.inputs[0].is_shape_dynamic);
EXPECT_EQ(op_sig.outputs[0].type, kTfLiteFloat32);
EXPECT_FALSE(op_sig.outputs[0].is_const);
EXPECT_EQ(op_sig.outputs[0].dims.size(), 4);
EXPECT_FALSE(op_sig.outputs[0].is_shape_dynamic);
EXPECT_NE(op_sig.builtin_data, nullptr);
EXPECT_EQ(op_sig.version, 1);
free(op_sig.builtin_data);
const std::string& full_path3 = tensorflow::GetDataDependencyFilepath(
"tensorflow/lite/testdata/multi_signatures.bin");
auto fb_model3 = FlatBufferModel::BuildFromFile(full_path3.data());
ASSERT_TRUE(fb_model3);
auto model3 = fb_model3->GetModel();
auto subgraphs3 = model3->subgraphs();
const SubGraph* subgraph3 = subgraphs3->Get(0);
const Operator* op3 = subgraph3->operators()->Get(0);
const OperatorCode* op_code3 =
model3->operator_codes()->Get(op3->opcode_index());
op_sig = GetOpSignature(op_code3, op3, subgraph3, model3);
EXPECT_EQ(op_sig.op, BuiltinOperator_ADD);
EXPECT_EQ(op_sig.inputs[0].type, kTfLiteFloat32);
EXPECT_EQ(op_sig.inputs[0].dims.size(), 1);
EXPECT_FALSE(op_sig.inputs[0].is_const);
EXPECT_TRUE(op_sig.inputs[0].is_shape_dynamic);
EXPECT_EQ(op_sig.outputs[0].type, kTfLiteFloat32);
EXPECT_FALSE(op_sig.outputs[0].is_const);
EXPECT_EQ(op_sig.outputs[0].dims.size(), 1);
EXPECT_TRUE(op_sig.outputs[0].is_shape_dynamic);
EXPECT_NE(op_sig.builtin_data, nullptr);
EXPECT_EQ(op_sig.version, 1);
free(op_sig.builtin_data);
}
TEST(GetOpSignature, TfLiteContext) {
auto context = std::make_unique<StubTfLiteContext>(kTfLiteBuiltinAdd,
/*op_version=*/1,
/*num_inputs=*/4);
OpSignature op_sig =
GetOpSignature(context.get(), context->node(), context->registration());
EXPECT_EQ(op_sig.op, BuiltinOperator_ADD);
EXPECT_EQ(op_sig.inputs[0].type, kTfLiteFloat32);
EXPECT_EQ(op_sig.inputs[0].dims.size(), 4);
EXPECT_FALSE(op_sig.inputs[0].is_const);
EXPECT_FALSE(op_sig.inputs[0].is_shape_dynamic);
EXPECT_EQ(op_sig.outputs[0].type, kTfLiteFloat32);
EXPECT_FALSE(op_sig.outputs[0].is_const);
EXPECT_EQ(op_sig.outputs[0].dims.size(), 4);
EXPECT_FALSE(op_sig.outputs[0].is_shape_dynamic);
EXPECT_NE(op_sig.builtin_data, nullptr);
EXPECT_EQ(op_sig.version, 1);
}
} // namespace tflite
@@ -0,0 +1,20 @@
/* Copyright 2019 The TensorFlow Authors. All Rights Reserved.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
==============================================================================*/
#ifndef TENSORFLOW_LITE_TOOLS_VERSIONING_OP_VERSION_H_
#define TENSORFLOW_LITE_TOOLS_VERSIONING_OP_VERSION_H_
#include "tensorflow/compiler/mlir/lite/tools/versioning/op_version.h"
#endif // TENSORFLOW_LITE_TOOLS_VERSIONING_OP_VERSION_H_