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
@@ -0,0 +1,99 @@
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",
srcs = [
"op_version.cc",
"runtime_version.cc",
],
hdrs = [
"op_version.h",
"runtime_version.h",
],
compatible_with = get_compatible_with_portable(),
deps = [
":op_signature",
"//tensorflow/compiler/mlir/lite/core/c:tflite_common",
"//tensorflow/compiler/mlir/lite/kernels/internal:compatibility_macros",
"//tensorflow/compiler/mlir/lite/schema:schema_fbs",
"//tensorflow/compiler/mlir/lite/schema:schema_fbs_with_mutable",
"//tensorflow/compiler/mlir/lite/schema:schema_utils",
"@com_google_absl//absl/log",
"@com_google_absl//absl/strings",
"@flatbuffers",
],
)
tf_cc_test(
name = "op_version_test",
srcs = [
"op_version_test.cc",
],
deps = [
":op_signature",
":versioning",
"//tensorflow/compiler/mlir/lite/core/c:tflite_common",
"//tensorflow/compiler/mlir/lite/schema:schema_fbs",
"//tensorflow/compiler/mlir/lite/schema:schema_fbs_with_mutable",
"@com_google_googletest//:gtest_main",
],
)
tf_cc_test(
name = "runtime_version_test",
srcs = [
"runtime_version_test.cc",
],
deps = [
":versioning",
"@com_google_googletest//:gtest_main",
],
)
cc_library(
name = "op_signature",
srcs = [
"op_signature.cc",
],
hdrs = [
"op_signature.h",
],
compatible_with = get_compatible_with_portable(),
deps = [
"//tensorflow/compiler/mlir/lite/core/api:flatbuffer_conversions",
"//tensorflow/compiler/mlir/lite/core/c:tflite_common",
"//tensorflow/compiler/mlir/lite/schema:schema_fbs",
"//tensorflow/compiler/mlir/lite/schema:schema_utils",
"@flatbuffers//:runtime_cc",
],
)
tf_cc_test(
name = "op_signature_test",
srcs = [
"op_signature_test.cc",
],
data = [
"//tensorflow/compiler/mlir/lite:testdata/add.bin",
"//tensorflow/compiler/mlir/lite:testdata/multi_signatures.bin",
],
deps = [
":op_signature",
"//tensorflow/compiler/mlir/lite/core:absl_error_model_builder",
"//tensorflow/compiler/mlir/lite/core/c:tflite_common",
"//tensorflow/compiler/mlir/lite/schema:schema_fbs",
"//tensorflow/core/platform:resource_loader",
"@com_google_googletest//:gtest_main",
],
)
@@ -0,0 +1,272 @@
/* 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/compiler/mlir/lite/tools/versioning/op_signature.h"
#include <cstdint>
#include <cstdlib>
#include <cstring>
#include <vector>
#include "flatbuffers/vector.h" // from @flatbuffers
#include "tensorflow/compiler/mlir/lite/core/api/flatbuffer_conversions.h"
#include "tensorflow/compiler/mlir/lite/core/c/tflite_types.h"
#include "tensorflow/compiler/mlir/lite/schema/schema_generated.h"
#include "tensorflow/compiler/mlir/lite/schema/schema_utils.h"
namespace tflite {
namespace {
using tflite_file::flatbuffer_conversions::BuiltinDataAllocator;
using tflite_file::flatbuffer_conversions::ConvertTensorType;
using tflite_file::flatbuffer_conversions::ParseOpData;
// A BuiltinDataAllocator which just uses malloc()/free().
class MallocDataAllocator : public BuiltinDataAllocator {
public:
void* Allocate(size_t size, size_t alignment_hint) override {
return malloc(size);
}
void Deallocate(void* data) override { free(data); }
};
// Get the number of dimensions of a tensor with idx of an operator op.
inline int GetNumDims(const SubGraph* subgraph, const Operator* op, int idx) {
const flatbuffers::Vector<int32_t>* ret =
subgraph->tensors()->Get(op->inputs()->Get(idx))->shape();
if (ret) {
return ret->size();
} else {
return 0;
}
}
std::vector<OpSignatureTensorSpec> GetOpSignatureTensorSpecs(
const flatbuffers::Vector<int32_t>* tensors, const SubGraph* subgraph,
const Model* model) {
std::vector<OpSignatureTensorSpec> tensor_specs;
if (!tensors) {
return tensor_specs;
}
for (size_t i = 0; i < tensors->size(); ++i) {
int32_t tensor_no = tensors->Get(i);
OpSignatureTensorSpec tensor_spec = {kTfLiteNoType};
if (tensor_no >= 0) {
if (subgraph->tensors() &&
static_cast<size_t>(tensor_no) < subgraph->tensors()->size()) {
auto* fb_tensor = subgraph->tensors()->Get(tensor_no);
ConvertTensorType(fb_tensor->type(), &tensor_spec.type).IgnoreError();
auto buffer_idx = fb_tensor->buffer();
// Check if the tensor is a constant tensor.
if (buffer_idx != 0 && buffer_idx < model->buffers()->size()) {
auto* buffer = model->buffers()->Get(buffer_idx);
if (buffer->data() && !buffer->data()->empty()) {
tensor_spec.is_const = true;
}
}
const flatbuffers::Vector<int32_t>* shape_vec = fb_tensor->shape();
if (shape_vec) {
for (size_t j = 0; j < shape_vec->size(); ++j) {
tensor_spec.dims.push_back(shape_vec->Get(j));
}
}
const flatbuffers::Vector<int32_t>* shape_signature_vec =
fb_tensor->shape_signature();
tensor_spec.is_shape_dynamic = false;
if (shape_signature_vec) {
for (size_t j = 0; j < shape_signature_vec->size(); ++j) {
if (shape_signature_vec->Get(j) == -1) {
tensor_spec.is_shape_dynamic = true;
break;
}
}
}
}
}
tensor_specs.push_back(tensor_spec);
}
return tensor_specs;
}
bool IsTensorSizeEqual(size_t tensor_a_size, int tensor_b_size) {
return tensor_b_size >= 0 &&
static_cast<size_t>(tensor_b_size) == tensor_a_size;
}
} // namespace
OpSignature GetOpSignature(const OperatorCode* op_code, const Operator* op,
const SubGraph* subgraph, const Model* model) {
auto builtin_code = GetBuiltinCode(op_code);
OpSignature op_sig = {builtin_code};
std::memset(&op_sig.ext_options, 0, sizeof(op_sig.ext_options));
if (builtin_code != BuiltinOperator_CUSTOM) {
MallocDataAllocator allocator;
ParseOpData(op, builtin_code, &allocator, &op_sig.builtin_data)
.IgnoreError();
} else {
op_sig.custom_name = op_code->custom_code()->str();
}
switch (builtin_code) {
case BuiltinOperator_DEPTHWISE_CONV_2D: {
const Tensor* filter_tensor =
subgraph->tensors()->Get(op->inputs()->Get(1));
const QuantizationParameters* filter_quant =
filter_tensor->quantization();
int num_channels = filter_tensor->shape()->Get(3);
if (filter_quant && num_channels > 0 && filter_quant->scale() &&
filter_quant->scale()->size() == static_cast<size_t>(num_channels)) {
op_sig.ext_options.depthwise_conv_2d.is_per_channel_quantized = true;
}
} break;
case BuiltinOperator_FULLY_CONNECTED: {
const Tensor* weight_tensor =
subgraph->tensors()->Get(op->inputs()->Get(1));
op_sig.ext_options.fully_connected.sparse_weight =
(weight_tensor->sparsity() != nullptr);
const QuantizationParameters* weight_quant =
weight_tensor->quantization();
if (weight_quant && weight_quant->scale() &&
!weight_quant->scale()->empty() && weight_tensor->shape() &&
!weight_tensor->shape()->empty()) {
op_sig.ext_options.fully_connected.is_per_channel_quantized =
IsTensorSizeEqual(weight_quant->scale()->size(),
weight_tensor->shape()->Get(0));
}
} break;
case BuiltinOperator_MUL: {
if (op->inputs()->size() < 2 || op->outputs()->empty()) {
break;
}
const Tensor* input1_tensor =
subgraph->tensors()->Get(op->inputs()->Get(0));
const Tensor* input2_tensor =
subgraph->tensors()->Get(op->inputs()->Get(1));
const Tensor* output_tensor =
subgraph->tensors()->Get(op->outputs()->Get(0));
const QuantizationParameters* input1_quant =
input1_tensor->quantization();
const QuantizationParameters* input2_qunt = input2_tensor->quantization();
const QuantizationParameters* output_quant =
output_tensor->quantization();
if (input1_quant && input1_quant->scale() &&
!input1_quant->scale()->empty() && input2_qunt &&
input2_qunt->scale() && !input2_qunt->scale()->empty() &&
output_quant && output_quant->scale() &&
!output_quant->scale()->empty()) {
op_sig.ext_options.mul.input1_scale = input1_quant->scale()->Get(0);
op_sig.ext_options.mul.input2_scale = input2_qunt->scale()->Get(0);
op_sig.ext_options.mul.output_scale = output_quant->scale()->Get(0);
}
if (input1_quant || input2_qunt) {
op_sig.ext_options.mul.input_quantized = true;
}
} break;
case BuiltinOperator_CONV_2D: {
const Tensor* input_tensor =
subgraph->tensors()->Get(op->inputs()->Get(0));
const Tensor* filter_tensor =
subgraph->tensors()->Get(op->inputs()->Get(1));
const QuantizationParameters* filter_quant =
filter_tensor->quantization();
int num_filters = filter_tensor->shape()->Get(0);
if (filter_quant && num_filters > 0 && filter_quant->scale() &&
filter_quant->scale()->size() == static_cast<size_t>(num_filters)) {
op_sig.ext_options.conv_2d.is_per_channel_quantized = true;
}
if (input_tensor->shape() && !input_tensor->shape()->empty()) {
int num_input_channels = input_tensor->shape()->Get(3);
int num_filter_input_channels = filter_tensor->shape()->Get(3);
op_sig.ext_options.conv_2d.is_grouped_convolution =
num_input_channels != num_filter_input_channels;
} else {
op_sig.ext_options.conv_2d.is_grouped_convolution = false;
}
} break;
case BuiltinOperator_STRIDED_SLICE: {
op_sig.ext_options.strided_slice.num_dims = GetNumDims(subgraph, op, 0);
} break;
case BuiltinOperator_ABS: {
if (subgraph->tensors()->Get(op->inputs()->Get(0))->quantization()) {
op_sig.ext_options.abs.input_quantized = true;
}
} break;
case BuiltinOperator_DEQUANTIZE: {
const Tensor* input_tensor =
subgraph->tensors()->Get(op->inputs()->Get(0));
const QuantizationParameters* input_quant = input_tensor->quantization();
if (input_quant && input_quant->scale() &&
input_quant->scale()->size() > 1 &&
IsTensorSizeEqual(
input_quant->scale()->size(),
input_tensor->shape()->Get(input_quant->quantized_dimension()))) {
op_sig.ext_options.dequantize.is_per_channel_quantized = true;
}
} break;
case BuiltinOperator_QUANTIZE: {
const Tensor* output_tensor =
subgraph->tensors()->Get(op->outputs()->Get(0));
const QuantizationParameters* output_quant =
output_tensor->quantization();
if (output_quant && output_quant->scale() &&
output_quant->scale()->size() > 1 &&
IsTensorSizeEqual(output_quant->scale()->size(),
output_tensor->shape()->Get(
output_quant->quantized_dimension()))) {
op_sig.ext_options.quantize.is_per_channel_quantized = true;
}
} break;
case BuiltinOperator_ADD: {
if (subgraph->tensors()->Get(op->inputs()->Get(0))->quantization()) {
op_sig.ext_options.add.input_quantized = true;
}
} break;
case BuiltinOperator_EMBEDDING_LOOKUP: {
const Tensor* table_tensor =
subgraph->tensors()->Get(op->inputs()->Get(1));
const QuantizationParameters* table_quant = table_tensor->quantization();
if (table_quant && table_quant->scale() &&
!table_quant->scale()->empty() && table_tensor->shape() &&
!table_tensor->shape()->empty()) {
op_sig.ext_options.embedding_lookup.is_per_channel_quantized =
table_quant->scale()->size() > 1 &&
IsTensorSizeEqual(table_quant->scale()->size(),
table_tensor->shape()->Get(0));
}
} break;
default:
break;
}
op_sig.inputs = GetOpSignatureTensorSpecs(op->inputs(), subgraph, model);
op_sig.outputs = GetOpSignatureTensorSpecs(op->outputs(), subgraph, model);
op_sig.version = op_code->version();
return op_sig;
}
} // namespace tflite
@@ -0,0 +1,96 @@
/* 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_COMPILER_MLIR_LITE_TOOLS_VERSIONING_OP_SIGNATURE_H_
#define TENSORFLOW_COMPILER_MLIR_LITE_TOOLS_VERSIONING_OP_SIGNATURE_H_
#include <cstdint>
#include <string>
#include <vector>
#include "tensorflow/compiler/mlir/lite/core/c/tflite_types.h"
#include "tensorflow/compiler/mlir/lite/schema/schema_generated.h"
namespace tflite {
// OpSignature contains operator parameters for version functions.
typedef struct {
TfLiteType type;
std::vector<int32_t> dims;
bool is_const;
bool is_shape_dynamic;
} OpSignatureTensorSpec;
typedef struct {
BuiltinOperator op;
std::vector<OpSignatureTensorSpec> inputs;
std::vector<OpSignatureTensorSpec> outputs;
void* builtin_data;
int version;
const void* custom_initial_data;
std::string custom_name;
union {
struct {
bool is_per_channel_quantized;
bool is_grouped_convolution;
} conv_2d;
struct {
bool is_per_channel_quantized;
} depthwise_conv_2d;
struct {
// TODO(b/156530611): Make this global when more ops support sparse
// computation.
bool sparse_weight;
bool is_per_channel_quantized;
} fully_connected;
struct {
float input1_scale;
float input2_scale;
float output_scale;
bool input_quantized;
} mul;
struct {
int32_t num_dims;
} strided_slice;
struct {
bool input_quantized;
} abs;
struct {
bool is_per_channel_quantized;
} dequantize;
struct {
bool is_per_channel_quantized;
} quantize;
struct {
bool input_quantized;
} add;
struct {
bool is_per_channel_quantized;
} embedding_lookup;
} ext_options;
} OpSignature;
// Generate OpSignature with the given OperatorCode, Operator and Tensors (from
// SubGraph). The OpSignature will be used by GetBuiltinOperatorVersion() and
// mostly input and output tensor types are enough to figure out op version.
// But some ops (DEPTHWISE_CONV_2D, FULLY_CONNECTED, ...) require to pass their
// options to decide op version.
//
// WARNING: The caller is responsible to free the allocated
// OpSignature.builtin_data memory.
OpSignature GetOpSignature(const OperatorCode* op_code, const Operator* op,
const SubGraph* subgraph, const Model* model);
} // namespace tflite
#endif // TENSORFLOW_COMPILER_MLIR_LITE_TOOLS_VERSIONING_OP_SIGNATURE_H_
@@ -0,0 +1,99 @@
/* 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/compiler/mlir/lite/tools/versioning/op_signature.h"
#include <cstdlib>
#include <memory>
#include <string>
#include <vector>
#include <gtest/gtest.h>
#include "tensorflow/compiler/mlir/lite/core/absl_error_model_builder.h"
#include "tensorflow/compiler/mlir/lite/core/c/tflite_types.h"
#include "tensorflow/compiler/mlir/lite/schema/schema_generated.h"
#include "tensorflow/core/platform/resource_loader.h"
namespace tflite {
TEST(GetOpSignature, FlatBufferModel) {
const std::string& full_path = tensorflow::GetDataDependencyFilepath(
"tensorflow/compiler/mlir/lite/testdata/add.bin");
auto fb_model =
mlir::TFL::FlatBufferModelAbslError::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/compiler/mlir/lite/testdata/multi_signatures.bin");
auto fb_model3 =
mlir::TFL::FlatBufferModelAbslError::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);
}
} // namespace tflite
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,33 @@
/* 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_COMPILER_MLIR_LITE_TOOLS_VERSIONING_OP_VERSION_H_
#define TENSORFLOW_COMPILER_MLIR_LITE_TOOLS_VERSIONING_OP_VERSION_H_
#include <cstdint>
#include "tensorflow/compiler/mlir/lite/schema/mutable/schema_generated.h" // IWYU pragma: keep
#include "tensorflow/compiler/mlir/lite/tools/versioning/op_signature.h"
namespace tflite {
// Returns version of builtin ops by the given signature.
int GetBuiltinOperatorVersion(const OpSignature& op_sig);
// Update operator's version of the given TFL flatbuffer model.
void UpdateOpVersion(uint8_t* model_buffer_pointer);
} // namespace tflite
#endif // TENSORFLOW_COMPILER_MLIR_LITE_TOOLS_VERSIONING_OP_VERSION_H_
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,544 @@
/* Copyright 2023 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/compiler/mlir/lite/tools/versioning/runtime_version.h"
#include <cstdint>
#include <cstring>
#include <map>
#include <string>
#include <utility>
#include <vector>
#include "absl/log/log.h"
#include "absl/strings/numbers.h"
#include "absl/strings/str_split.h"
#include "tensorflow/compiler/mlir/lite/schema/mutable/schema_generated.h"
#include "tensorflow/compiler/mlir/lite/schema/schema_utils.h"
namespace tflite {
bool CompareRuntimeVersion(const std::string& v1, const std::string& v2) {
const std::vector<std::string> vec1 = absl::StrSplit(v1, '.');
const std::vector<std::string> vec2 = absl::StrSplit(v2, '.');
int i = 0;
while (i < vec1.size() && i < vec2.size()) {
int v1_val, v2_val;
if (absl::SimpleAtoi(vec1[i], &v1_val) &&
absl::SimpleAtoi(vec2[i], &v2_val)) {
if (v1_val != v2_val) return v1_val < v2_val;
}
++i;
}
// If there are remaining items in v2 not being compared, then v1 should
// precede v2.
return i < vec2.size();
}
std::string FindMinimumRuntimeVersionForOp(tflite::BuiltinOperator op_code,
int op_version) {
// A map from the version key of an op to its minimum runtime version.
// For example, {{kAveragePool, 1}, "1.5.0"}, means the 1st version of
// AveragePool requires a minimum TF Lite runtime version '1.5.0`.
// NOTE: When adding a new op version pair, associate it with the current
// runtime version defined in tensorflow/core/public/version.h.
static const std::map<std::pair<BuiltinOperator, int>, std::string>*
op_version_map =
new std::map<std::pair<BuiltinOperator, int>, std::string>({
{{BuiltinOperator_AVERAGE_POOL_2D, 1}, "1.5.0"},
{{BuiltinOperator_AVERAGE_POOL_2D, 2}, "1.14.0"},
{{BuiltinOperator_AVERAGE_POOL_2D, 3}, "2.3.0"},
{{BuiltinOperator_BATCH_MATMUL, 1}, "2.3.0"},
{{BuiltinOperator_BATCH_MATMUL, 2}, "2.3.0"},
{{BuiltinOperator_BATCH_MATMUL, 3}, "2.4.0"},
{{BuiltinOperator_BATCH_MATMUL, 4}, "2.5.0"},
// The version one of broadcast to op won't be not supported since
// the version one was rollbacked and the builtin op code number
// has been changed because of builtin op code shortage problem.
{{BuiltinOperator_BROADCAST_TO, 2}, "2.5.0"},
{{BuiltinOperator_BROADCAST_TO, 3}, "2.5.0"},
{{BuiltinOperator_CONV_2D, 1}, "1.5.0"},
{{BuiltinOperator_CONV_2D, 2}, "1.14.0"},
{{BuiltinOperator_CONV_2D, 3}, "1.14.0"},
{{BuiltinOperator_CONV_2D, 4}, "2.3.0"},
{{BuiltinOperator_CONV_2D, 5}, "2.4.0"},
{{BuiltinOperator_CONV_2D, 6}, "2.9.0"},
{{BuiltinOperator_CONV_2D, 7}, "2.11.0"},
{{BuiltinOperator_CONV_2D, 8}, "2.15.0"},
{{BuiltinOperator_DEPTHWISE_CONV_2D, 1}, "1.5.0"},
{{BuiltinOperator_DEPTHWISE_CONV_2D, 2}, "1.12.0"},
{{BuiltinOperator_DEPTHWISE_CONV_2D, 3}, "1.14.0"},
{{BuiltinOperator_DEPTHWISE_CONV_2D, 4}, "2.2.0"},
{{BuiltinOperator_DEPTHWISE_CONV_2D, 5}, "2.3.0"},
{{BuiltinOperator_DEPTHWISE_CONV_2D, 6}, "2.3.0"},
{{BuiltinOperator_DEPTHWISE_CONV_2D, 7}, "2.11.0"},
{{BuiltinOperator_ADD, 1}, "1.5.0"},
{{BuiltinOperator_ADD, 2}, "1.14.0"},
{{BuiltinOperator_ADD, 3}, "2.4.0"},
{{BuiltinOperator_ADD, 4}, "2.6.0"},
{{BuiltinOperator_ADD, 5}, "2.13.0"},
{{BuiltinOperator_ADD, 6}, "2.23.0"},
{{BuiltinOperator_ADD_N, 1}, "1.14.0"},
{{BuiltinOperator_SPACE_TO_BATCH_ND, 1}, "1.6.0"},
{{BuiltinOperator_SPACE_TO_BATCH_ND, 2}, "1.14.0"},
{{BuiltinOperator_SPACE_TO_BATCH_ND, 3}, "2.3.0"},
{{BuiltinOperator_SPACE_TO_BATCH_ND, 4}, "2.12.0"},
{{BuiltinOperator_SUB, 1}, "1.6.0"},
{{BuiltinOperator_SUB, 2}, "1.14.0"},
{{BuiltinOperator_SUB, 3}, "2.3.0"},
{{BuiltinOperator_SUB, 4}, "2.4.0"},
{{BuiltinOperator_SUB, 5}, "2.4.0"},
{{BuiltinOperator_DENSIFY, 1}, "2.2.0"},
{{BuiltinOperator_DIV, 1}, "1.6.0"},
{{BuiltinOperator_DIV, 2}, "2.3.0"},
{{BuiltinOperator_BATCH_TO_SPACE_ND, 1}, "1.6.0"},
{{BuiltinOperator_BATCH_TO_SPACE_ND, 2}, "1.14.0"},
{{BuiltinOperator_BATCH_TO_SPACE_ND, 3}, "2.3.0"},
{{BuiltinOperator_BATCH_TO_SPACE_ND, 4}, "2.12.0"},
{{BuiltinOperator_CAST, 1}, "1.5.0"},
{{BuiltinOperator_CAST, 2}, "2.7.0"},
{{BuiltinOperator_CAST, 3}, "2.8.0"},
{{BuiltinOperator_CAST, 4}, "2.9.0"},
{{BuiltinOperator_CAST, 5}, "2.12.0"},
{{BuiltinOperator_CAST, 6}, "2.15.0"},
{{BuiltinOperator_CAST, 7}, "2.17.0"},
{{BuiltinOperator_CAST, 8}, "2.21.0"},
{{BuiltinOperator_CONCATENATION, 1}, "1.5.0"},
{{BuiltinOperator_CONCATENATION, 2}, "1.14.0"},
{{BuiltinOperator_CONCATENATION, 3}, "2.3.0"},
{{BuiltinOperator_CONCATENATION, 4}, "2.14.0"},
{{BuiltinOperator_CONCATENATION, 5}, "2.21.0"},
{{BuiltinOperator_CONCATENATION, 6}, "2.23.0"},
{{BuiltinOperator_DEPTH_TO_SPACE, 1}, "2.1.0"},
{{BuiltinOperator_DEPTH_TO_SPACE, 2}, "2.5.0"},
{{BuiltinOperator_EMBEDDING_LOOKUP, 1}, "1.13.0"},
{{BuiltinOperator_EMBEDDING_LOOKUP, 2}, "1.14.0"},
{{BuiltinOperator_EMBEDDING_LOOKUP, 3}, "1.14.0"},
{{BuiltinOperator_EMBEDDING_LOOKUP, 4}, "2.18.0"},
{{BuiltinOperator_EMBEDDING_LOOKUP, 5}, "2.21.0"},
{{BuiltinOperator_EMBEDDING_LOOKUP_SPARSE, 1}, "1.5.0"},
{{BuiltinOperator_FAKE_QUANT, 1}, "1.5.0"},
{{BuiltinOperator_FAKE_QUANT, 2}, "1.10.0"},
{{BuiltinOperator_FULLY_CONNECTED, 1}, "1.5.0"},
{{BuiltinOperator_FULLY_CONNECTED, 2}, "1.10.0"},
{{BuiltinOperator_FULLY_CONNECTED, 3}, "1.14.0"},
{{BuiltinOperator_FULLY_CONNECTED, 4}, "1.14.0"},
{{BuiltinOperator_FULLY_CONNECTED, 5}, "2.0.0"},
{{BuiltinOperator_FULLY_CONNECTED, 6}, "2.1.0"},
{{BuiltinOperator_FULLY_CONNECTED, 7}, "2.3.0"},
{{BuiltinOperator_FULLY_CONNECTED, 8}, "2.3.0"},
{{BuiltinOperator_FULLY_CONNECTED, 9}, "2.3.0"},
{{BuiltinOperator_FULLY_CONNECTED, 10}, "2.11.0"},
{{BuiltinOperator_FULLY_CONNECTED, 11}, "2.15.0"},
{{BuiltinOperator_FULLY_CONNECTED, 12}, "2.17.0"},
{{BuiltinOperator_FULLY_CONNECTED, 13}, "2.18.0"},
{{BuiltinOperator_FULLY_CONNECTED, 14}, "2.21.0"},
{{BuiltinOperator_GATHER, 1}, "1.6.0"},
{{BuiltinOperator_GATHER, 2}, "1.14.0"},
{{BuiltinOperator_GATHER, 3}, "1.15.0"},
{{BuiltinOperator_GATHER, 4}, "2.4.0"},
{{BuiltinOperator_GATHER, 5}, "2.5.0"},
{{BuiltinOperator_GATHER, 6}, "2.13.0"},
{{BuiltinOperator_GATHER, 7}, "2.15.0"},
{{BuiltinOperator_GATHER_ND, 1}, "1.14.0"},
{{BuiltinOperator_GATHER_ND, 2}, "2.3.0"},
{{BuiltinOperator_GATHER_ND, 3}, "2.5.0"},
{{BuiltinOperator_GATHER_ND, 4}, "2.13.0"},
{{BuiltinOperator_GATHER_ND, 5}, "2.16.0"},
{{BuiltinOperator_HASHTABLE_LOOKUP, 1}, "1.5.0"},
{{BuiltinOperator_SVDF, 1}, "1.5.0"},
{{BuiltinOperator_SVDF, 2}, "1.14.0"},
{{BuiltinOperator_SVDF, 3}, "2.2.0"},
{{BuiltinOperator_SVDF, 4}, "2.3.0"},
{{BuiltinOperator_L2_NORMALIZATION, 1}, "1.5.0"},
{{BuiltinOperator_L2_NORMALIZATION, 2}, "1.14.0"},
{{BuiltinOperator_L2_POOL_2D, 1}, "1.5.0"},
{{BuiltinOperator_LOCAL_RESPONSE_NORMALIZATION, 1}, "1.5.0"},
{{BuiltinOperator_MAX_POOL_2D, 1}, "1.5.0"},
{{BuiltinOperator_MAX_POOL_2D, 2}, "1.14.0"},
{{BuiltinOperator_MAX_POOL_2D, 3}, "2.3.0"},
{{BuiltinOperator_MAXIMUM, 1}, "1.14.0"},
{{BuiltinOperator_MAXIMUM, 2}, "1.14.0"},
{{BuiltinOperator_MAXIMUM, 3}, "2.3.0"},
{{BuiltinOperator_MAXIMUM, 4}, "2.3.0"},
{{BuiltinOperator_MINIMUM, 1}, "1.14.0"},
{{BuiltinOperator_MINIMUM, 2}, "1.14.0"},
{{BuiltinOperator_MINIMUM, 3}, "2.3.0"},
{{BuiltinOperator_MINIMUM, 4}, "2.3.0"},
{{BuiltinOperator_MUL, 1}, "1.5.0"},
{{BuiltinOperator_MUL, 2}, "1.14.0"},
{{BuiltinOperator_MUL, 3}, "1.15.0"},
{{BuiltinOperator_MUL, 4}, "2.3.0"},
{{BuiltinOperator_MUL, 5}, "2.6.0"},
{{BuiltinOperator_MUL, 6}, "2.11.0"},
{{BuiltinOperator_MUL, 7}, "2.13.0"},
{{BuiltinOperator_MUL, 8}, "2.23.0"},
{{BuiltinOperator_NON_MAX_SUPPRESSION_V4, 1}, "2.1.0"},
{{BuiltinOperator_NON_MAX_SUPPRESSION_V5, 1}, "2.1.0"},
{{BuiltinOperator_PAD, 1}, "1.5.0"},
{{BuiltinOperator_PAD, 2}, "1.14.0"},
{{BuiltinOperator_PAD, 3}, "2.4.0"},
{{BuiltinOperator_PAD, 4}, "2.6.0"},
{{BuiltinOperator_PAD, 5}, "2.20.0"},
{{BuiltinOperator_TILE, 1}, "1.10.1"},
{{BuiltinOperator_TILE, 2}, "2.2.0"},
{{BuiltinOperator_TILE, 3}, "2.8.0"},
{{BuiltinOperator_PADV2, 1}, "1.9.0"},
{{BuiltinOperator_PADV2, 2}, "1.14.0"},
{{BuiltinOperator_PADV2, 3}, "2.4.0"},
{{BuiltinOperator_PADV2, 4}, "2.6.0"},
{{BuiltinOperator_PADV2, 5}, "2.20.0"},
{{BuiltinOperator_RESHAPE, 1}, "1.5.0"},
{{BuiltinOperator_SOFTMAX, 1}, "1.5.0"},
{{BuiltinOperator_SOFTMAX, 2}, "1.14.0"},
{{BuiltinOperator_SOFTMAX, 3}, "2.3.0"},
{{BuiltinOperator_SOFTMAX, 4}, "2.23.0"},
{{BuiltinOperator_SPACE_TO_DEPTH, 1}, "1.5.0"},
{{BuiltinOperator_SPACE_TO_DEPTH, 2}, "1.14.0"},
{{BuiltinOperator_TRANSPOSE, 1}, "1.6.0"},
{{BuiltinOperator_TRANSPOSE, 2}, "1.14.0"},
{{BuiltinOperator_TRANSPOSE, 3}, "1.15.0"},
{{BuiltinOperator_TRANSPOSE, 4}, "2.3.0"},
{{BuiltinOperator_TRANSPOSE, 5}, "2.4.0"},
{{BuiltinOperator_TRANSPOSE, 6}, "2.12.0"},
{{BuiltinOperator_TRANSPOSE, 7}, "2.14.4"},
{{BuiltinOperator_TRANSPOSE, 8}, "2.22.0"},
{{BuiltinOperator_TRANSPOSE, 9}, "2.23.0"},
{{BuiltinOperator_LSTM, 1}, "1.7.0"},
{{BuiltinOperator_LSTM, 2}, "1.10.0"},
{{BuiltinOperator_LSTM, 3}, "1.14.0"},
{{BuiltinOperator_LSTM, 4}, "2.3.0"},
{{BuiltinOperator_UNIDIRECTIONAL_SEQUENCE_LSTM, 1}, "1.13.1"},
{{BuiltinOperator_UNIDIRECTIONAL_SEQUENCE_LSTM, 2}, "1.14.0"},
{{BuiltinOperator_UNIDIRECTIONAL_SEQUENCE_LSTM, 3}, "2.3.0"},
{{BuiltinOperator_UNIDIRECTIONAL_SEQUENCE_LSTM, 4}, "2.12.0"},
{{BuiltinOperator_BIDIRECTIONAL_SEQUENCE_LSTM, 1}, "1.14.0"},
{{BuiltinOperator_BIDIRECTIONAL_SEQUENCE_LSTM, 2}, "1.14.0"},
{{BuiltinOperator_BIDIRECTIONAL_SEQUENCE_LSTM, 3}, "1.14.0"},
{{BuiltinOperator_BIDIRECTIONAL_SEQUENCE_RNN, 1}, "1.14.0"},
{{BuiltinOperator_BIDIRECTIONAL_SEQUENCE_RNN, 2}, "1.14.0"},
{{BuiltinOperator_BIDIRECTIONAL_SEQUENCE_RNN, 3}, "2.3.0"},
{{BuiltinOperator_MEAN, 1}, "1.6.0"},
{{BuiltinOperator_MEAN, 2}, "1.14.0"},
{{BuiltinOperator_MEAN, 3}, "2.4.0"},
{{BuiltinOperator_SUM, 1}, "1.10.0"},
{{BuiltinOperator_SUM, 2}, "1.15.0"},
{{BuiltinOperator_REDUCE_MAX, 1}, "1.11.0"},
{{BuiltinOperator_REDUCE_MAX, 2}, "1.14.0"},
{{BuiltinOperator_REDUCE_MAX, 3}, "2.5.0"},
{{BuiltinOperator_REDUCE_MIN, 1}, "1.11.0"},
{{BuiltinOperator_REDUCE_MIN, 2}, "1.14.0"},
{{BuiltinOperator_REDUCE_MIN, 3}, "2.5.0"},
{{BuiltinOperator_REDUCE_PROD, 1}, "1.11.0"},
{{BuiltinOperator_REDUCE_PROD, 2}, "2.6.0"},
{{BuiltinOperator_REDUCE_ANY, 1}, "1.11.0"},
{{BuiltinOperator_RELU6, 1}, "1.5.0"},
{{BuiltinOperator_RELU6, 2}, "1.14.0"},
{{BuiltinOperator_RELU6, 3}, "2.5.0"},
{{BuiltinOperator_RESIZE_BILINEAR, 1}, "1.7.0"},
{{BuiltinOperator_RESIZE_BILINEAR, 2}, "1.14.0"},
{{BuiltinOperator_RESIZE_BILINEAR, 3}, "2.2.0"},
{{BuiltinOperator_RESIZE_BILINEAR, 4}, "2.5.0"},
{{BuiltinOperator_RESIZE_NEAREST_NEIGHBOR, 1}, "1.13.1"},
{{BuiltinOperator_RESIZE_NEAREST_NEIGHBOR, 2}, "1.14.0"},
{{BuiltinOperator_RESIZE_NEAREST_NEIGHBOR, 3}, "2.3.0"},
{{BuiltinOperator_RESIZE_NEAREST_NEIGHBOR, 4}, "2.4.0"},
{{BuiltinOperator_RNN, 1}, "1.5.0"},
{{BuiltinOperator_RNN, 2}, "1.14.0"},
{{BuiltinOperator_RNN, 3}, "2.3.0"},
{{BuiltinOperator_SKIP_GRAM, 1}, "1.5.0"},
{{BuiltinOperator_SQUEEZE, 1}, "1.6.0"},
{{BuiltinOperator_SQUEEZE, 2}, "2.5.0"},
{{BuiltinOperator_SPLIT, 1}, "1.5.0"},
{{BuiltinOperator_SPLIT, 2}, "1.14.0"},
{{BuiltinOperator_SPLIT, 3}, "1.14.0"},
{{BuiltinOperator_SPLIT, 4}, "2.3.0"},
{{BuiltinOperator_SPLIT_V, 1}, "1.13.1"},
{{BuiltinOperator_SPLIT_V, 2}, "2.3.0"},
{{BuiltinOperator_STRIDED_SLICE, 1}, "1.6.0"},
{{BuiltinOperator_STRIDED_SLICE, 2}, "1.14.0"},
{{BuiltinOperator_STRIDED_SLICE, 3}, "2.1.0"},
{{BuiltinOperator_STRIDED_SLICE, 4}, "2.2.0"},
{{BuiltinOperator_STRIDED_SLICE, 5}, "2.5.0"},
{{BuiltinOperator_STRIDED_SLICE, 6}, "2.6.0"},
{{BuiltinOperator_STRIDED_SLICE, 7}, "2.14.0"},
{{BuiltinOperator_STRIDED_SLICE, 8}, "2.14.0"},
{{BuiltinOperator_TOPK_V2, 1}, "1.7.0"},
{{BuiltinOperator_TOPK_V2, 2}, "1.14.0"},
{{BuiltinOperator_TOPK_V2, 3}, "2.13.0"},
{{BuiltinOperator_ARG_MAX, 1}, "1.9.0"},
{{BuiltinOperator_ARG_MAX, 2}, "1.14.0"},
{{BuiltinOperator_ARG_MAX, 3}, "2.9.0"},
{{BuiltinOperator_ARG_MIN, 1}, "1.9.0"},
{{BuiltinOperator_ARG_MIN, 2}, "1.14.0"},
{{BuiltinOperator_ARG_MIN, 3}, "2.9.0"},
{{BuiltinOperator_TRANSPOSE_CONV, 1}, "1.9.0"},
{{BuiltinOperator_TRANSPOSE_CONV, 2}, "2.2.0"},
{{BuiltinOperator_TRANSPOSE_CONV, 3}, "2.3.0"},
{{BuiltinOperator_TRANSPOSE_CONV, 4}, "2.13.0"},
{{BuiltinOperator_TRANSPOSE_CONV, 5}, "2.15.0"},
{{BuiltinOperator_SPARSE_TO_DENSE, 1}, "1.9.0"},
{{BuiltinOperator_SPARSE_TO_DENSE, 2}, "1.14.0"},
{{BuiltinOperator_SPARSE_TO_DENSE, 3}, "1.15.0"},
{{BuiltinOperator_EXPAND_DIMS, 1}, "1.10.0"},
{{BuiltinOperator_PACK, 1}, "1.11.0"},
{{BuiltinOperator_PACK, 2}, "1.14.0"},
{{BuiltinOperator_PACK, 3}, "2.3.0"},
{{BuiltinOperator_PACK, 4}, "2.13.0"},
{{BuiltinOperator_SHAPE, 1}, "1.10.0"},
{{BuiltinOperator_SLICE, 1}, "1.14.0"},
{{BuiltinOperator_SLICE, 2}, "1.14.0"},
{{BuiltinOperator_SLICE, 3}, "1.14.0"},
{{BuiltinOperator_SLICE, 4}, "2.4.0"},
{{BuiltinOperator_SLICE, 5}, "2.5.0"},
{{BuiltinOperator_SLICE, 6}, "2.14.0"},
{{BuiltinOperator_SLICE, 7}, "2.21.0"},
{{BuiltinOperator_SLICE, 8}, "2.23.0"},
{{BuiltinOperator_TANH, 1}, "1.14.0"},
{{BuiltinOperator_TANH, 2}, "1.14.0"},
{{BuiltinOperator_TANH, 3}, "2.3.0"},
{{BuiltinOperator_ONE_HOT, 1}, "1.11.0"},
{{BuiltinOperator_UNPACK, 1}, "1.11.0"},
{{BuiltinOperator_UNPACK, 2}, "1.14.0"},
{{BuiltinOperator_UNPACK, 3}, "2.2.0"},
{{BuiltinOperator_UNPACK, 4}, "2.3.0"},
{{BuiltinOperator_UNPACK, 5}, "2.22.0"},
{{BuiltinOperator_LEAKY_RELU, 1}, "1.13.1"},
{{BuiltinOperator_LEAKY_RELU, 2}, "2.3.0"},
{{BuiltinOperator_LOGISTIC, 1}, "1.14.0"},
{{BuiltinOperator_LOGISTIC, 2}, "1.14.0"},
{{BuiltinOperator_LOGISTIC, 3}, "2.3.0"},
{{BuiltinOperator_LOG_SOFTMAX, 1}, "1.14.0"},
{{BuiltinOperator_LOG_SOFTMAX, 2}, "1.14.0"},
{{BuiltinOperator_LSH_PROJECTION, 1}, "1.5.0"},
{{BuiltinOperator_SQUARED_DIFFERENCE, 1}, "1.13.1"},
{{BuiltinOperator_SQUARED_DIFFERENCE, 2}, "2.5.0"},
{{BuiltinOperator_MIRROR_PAD, 1}, "1.13.1"},
{{BuiltinOperator_MIRROR_PAD, 2}, "2.3.0"},
{{BuiltinOperator_MIRROR_PAD, 3}, "2.12.0"},
{{BuiltinOperator_UNIQUE, 1}, "1.14.0"},
{{BuiltinOperator_UNIDIRECTIONAL_SEQUENCE_RNN, 1}, "1.14.0"},
{{BuiltinOperator_UNIDIRECTIONAL_SEQUENCE_RNN, 2}, "1.14.0"},
{{BuiltinOperator_UNIDIRECTIONAL_SEQUENCE_RNN, 3}, "2.3.0"},
{{BuiltinOperator_WHERE, 1}, "1.14.0"},
{{BuiltinOperator_DEQUANTIZE, 1}, "1.13.1"},
{{BuiltinOperator_DEQUANTIZE, 2}, "1.14.0"},
{{BuiltinOperator_DEQUANTIZE, 3}, "1.15.0"},
{{BuiltinOperator_DEQUANTIZE, 4}, "2.2.0"},
{{BuiltinOperator_DEQUANTIZE, 5}, "2.7.0"},
{{BuiltinOperator_DEQUANTIZE, 6}, "2.18.0"},
{{BuiltinOperator_DEQUANTIZE, 7}, "2.21.0"},
{{BuiltinOperator_DEQUANTIZE, 8}, "2.22.0"},
{{BuiltinOperator_REVERSE_SEQUENCE, 1}, "1.14.0"},
{{BuiltinOperator_EQUAL, 1}, "1.14.0"},
{{BuiltinOperator_EQUAL, 2}, "1.14.0"},
{{BuiltinOperator_EQUAL, 3}, "2.3.0"},
{{BuiltinOperator_EQUAL, 4}, "2.13.0"},
{{BuiltinOperator_EQUAL, 5}, "2.21.0"},
{{BuiltinOperator_NOT_EQUAL, 1}, "1.14.0"},
{{BuiltinOperator_NOT_EQUAL, 2}, "1.14.0"},
{{BuiltinOperator_NOT_EQUAL, 3}, "2.3.0"},
{{BuiltinOperator_NOT_EQUAL, 4}, "2.21.0"},
{{BuiltinOperator_GREATER, 1}, "1.14.0"},
{{BuiltinOperator_GREATER, 2}, "1.14.0"},
{{BuiltinOperator_GREATER_EQUAL, 1}, "1.14.0"},
{{BuiltinOperator_GREATER_EQUAL, 2}, "1.14.0"},
{{BuiltinOperator_GREATER_EQUAL, 3}, "2.13.0"},
{{BuiltinOperator_LESS, 1}, "1.14.0"},
{{BuiltinOperator_LESS, 2}, "1.14.0"},
{{BuiltinOperator_LESS, 3}, "2.13.0"},
{{BuiltinOperator_LESS_EQUAL, 1}, "1.14.0"},
{{BuiltinOperator_LESS_EQUAL, 2}, "1.14.0"},
{{BuiltinOperator_SCATTER_ND, 1}, "2.1.0"},
{{BuiltinOperator_SEGMENT_SUM, 1}, "2.2.0"},
{{BuiltinOperator_SELECT, 1}, "1.14.0"},
{{BuiltinOperator_SELECT, 2}, "1.14.0"},
{{BuiltinOperator_SELECT, 3}, "2.12.0"},
{{BuiltinOperator_SELECT, 4}, "2.12.0"},
{{BuiltinOperator_SELECT_V2, 1}, "2.2.0"},
{{BuiltinOperator_SELECT_V2, 2}, "2.12.0"},
{{BuiltinOperator_IF, 1}, "1.15.0"},
{{BuiltinOperator_FLOOR_DIV, 1}, "1.14.0"},
{{BuiltinOperator_FLOOR_DIV, 2}, "1.14.0"},
{{BuiltinOperator_FLOOR_DIV, 3}, "2.13.0"},
{{BuiltinOperator_FLOOR, 1}, "1.9.0"},
{{BuiltinOperator_CEIL, 1}, "1.14.0"},
{{BuiltinOperator_MATRIX_DIAG, 1}, "1.14.0"},
{{BuiltinOperator_MATRIX_SET_DIAG, 1}, "1.14.0"},
{{BuiltinOperator_ELU, 1}, "1.14.0"},
{{BuiltinOperator_QUANTIZE, 1}, "1.14.0"},
{{BuiltinOperator_QUANTIZE, 2}, "1.15.0"},
{{BuiltinOperator_QUANTIZE, 3}, "2.7.0"},
{{BuiltinOperator_QUANTIZE, 4}, "2.21.0"},
{{BuiltinOperator_QUANTIZE, 5}, "2.21.0"},
{{BuiltinOperator_QUANTIZE, 6}, "2.21.0"},
{{BuiltinOperator_ROUND, 1}, "1.14.0"},
{{BuiltinOperator_RELU, 1}, "1.5.0"},
{{BuiltinOperator_RELU, 2}, "2.1.0"},
{{BuiltinOperator_RELU, 3}, "2.5.0"},
{{BuiltinOperator_RELU_N1_TO_1, 1}, "1.5.0"},
{{BuiltinOperator_RELU_0_TO_1, 1}, "2.10.0"},
{{BuiltinOperator_PRELU, 1}, "1.8.0"},
{{BuiltinOperator_EXP, 1}, "1.7.0"},
{{BuiltinOperator_EXP, 2}, "2.12.0"},
{{BuiltinOperator_COS, 1}, "1.14.0"},
{{BuiltinOperator_COS, 2}, "2.23.0"},
{{BuiltinOperator_NEG, 1}, "1.9.0"},
{{BuiltinOperator_POW, 1}, "1.10.0"},
{{BuiltinOperator_LOGICAL_OR, 1}, "1.11.0"},
{{BuiltinOperator_LOGICAL_AND, 1}, "1.11.0"},
{{BuiltinOperator_LOGICAL_NOT, 1}, "1.11.0"},
{{BuiltinOperator_FLOOR_MOD, 1}, "1.13.0"},
{{BuiltinOperator_FLOOR_MOD, 2}, "2.13.0"},
{{BuiltinOperator_RANGE, 1}, "1.13.0"},
{{BuiltinOperator_RANGE, 2}, "2.14.0"},
{{BuiltinOperator_SIN, 1}, "1.9.0"},
{{BuiltinOperator_SIN, 2}, "2.23.0"},
{{BuiltinOperator_LOG, 1}, "1.14.0"},
{{BuiltinOperator_LOG, 2}, "2.15.0"},
{{BuiltinOperator_SQRT, 1}, "1.10.0"},
{{BuiltinOperator_SQRT, 2}, "2.21.0"},
{{BuiltinOperator_RSQRT, 1}, "1.10.0"},
{{BuiltinOperator_RSQRT, 2}, "2.5.0"},
{{BuiltinOperator_RSQRT, 3}, "2.15.0"},
{{BuiltinOperator_SQUARE, 1}, "1.12.0"},
{{BuiltinOperator_ZEROS_LIKE, 1}, "1.12.0"},
{{BuiltinOperator_ABS, 1}, "1.13.0"},
{{BuiltinOperator_ABS, 2}, "2.4.0"},
{{BuiltinOperator_ABS, 3}, "2.5.0"},
{{BuiltinOperator_ABS, 4}, "2.6.0"},
{{BuiltinOperator_ABS, 5}, "2.12.0"},
{{BuiltinOperator_HARD_SWISH, 1}, "1.15.0"},
{{BuiltinOperator_FILL, 1}, "1.13.0"},
{{BuiltinOperator_FILL, 2}, "2.3.0"},
{{BuiltinOperator_FILL, 3}, "2.5.0"},
{{BuiltinOperator_FILL, 4}, "2.12.0"},
{{BuiltinOperator_REVERSE_V2, 1}, "1.14.0"},
{{BuiltinOperator_REVERSE_V2, 2}, "2.2.0"},
{{BuiltinOperator_REVERSE_V2, 3}, "2.5.0"},
{{BuiltinOperator_RANK, 1}, "1.14.0"},
{{BuiltinOperator_WHILE, 1}, "1.15.0"},
{{BuiltinOperator_CUMSUM, 1}, "2.4.0"},
{{BuiltinOperator_CALL_ONCE, 1}, "2.5.0"},
{{BuiltinOperator_RFFT2D, 1}, "2.5.0"},
{{BuiltinOperator_CONV_3D, 1}, "2.5.0"},
{{BuiltinOperator_IMAG, 1}, "2.5.0"},
{{BuiltinOperator_REAL, 1}, "2.5.0"},
{{BuiltinOperator_COMPLEX_ABS, 1}, "2.5.0"},
{{BuiltinOperator_HASHTABLE, 1}, "2.5.0"},
{{BuiltinOperator_HASHTABLE_FIND, 1}, "2.5.0"},
{{BuiltinOperator_HASHTABLE_IMPORT, 1}, "2.5.0"},
{{BuiltinOperator_HASHTABLE_SIZE, 1}, "2.5.0"},
{{BuiltinOperator_REDUCE_ALL, 1}, "2.6.0"},
{{BuiltinOperator_CONV_3D_TRANSPOSE, 1}, "2.6.0"},
{{BuiltinOperator_VAR_HANDLE, 1}, "2.6.0"},
{{BuiltinOperator_READ_VARIABLE, 1}, "2.6.0"},
{{BuiltinOperator_ASSIGN_VARIABLE, 1}, "2.6.0"},
{{BuiltinOperator_BROADCAST_ARGS, 1}, "2.6.0"},
{{BuiltinOperator_RANDOM_STANDARD_NORMAL, 1}, "2.8.0"},
{{BuiltinOperator_BUCKETIZE, 1}, "2.8.0"},
{{BuiltinOperator_WHERE, 2}, "2.8.0"},
{{BuiltinOperator_RANDOM_UNIFORM, 1}, "2.8.0"},
{{BuiltinOperator_MULTINOMIAL, 1}, "2.8.0"},
{{BuiltinOperator_GELU, 1}, "2.9.0"},
{{BuiltinOperator_GELU, 2}, "2.9.0"},
{{BuiltinOperator_GELU, 3}, "2.23.0"},
{{BuiltinOperator_DYNAMIC_UPDATE_SLICE, 1}, "2.9.0"},
{{BuiltinOperator_DYNAMIC_UPDATE_SLICE, 2}, "2.17.0"},
{{BuiltinOperator_DYNAMIC_UPDATE_SLICE, 3}, "2.19.0"},
{{BuiltinOperator_DYNAMIC_UPDATE_SLICE, 4}, "2.20.0"},
{{BuiltinOperator_DYNAMIC_UPDATE_SLICE, 5}, "2.21.0"},
{{BuiltinOperator_DYNAMIC_UPDATE_SLICE, 6}, "2.22.0"},
{{BuiltinOperator_UNSORTED_SEGMENT_PROD, 1}, "2.10.0"},
{{BuiltinOperator_UNSORTED_SEGMENT_MAX, 1}, "2.10.0"},
{{BuiltinOperator_UNSORTED_SEGMENT_MIN, 1}, "2.11.0"},
{{BuiltinOperator_UNSORTED_SEGMENT_SUM, 1}, "2.10.0"},
{{BuiltinOperator_ATAN2, 1}, "2.10.0"},
{{BuiltinOperator_SIGN, 1}, "2.11.0"},
{{BuiltinOperator_SIGN, 2}, "2.12.0"},
{{BuiltinOperator_BITCAST, 1}, "2.13.0"},
{{BuiltinOperator_BITWISE_XOR, 1}, "2.13.0"},
{{BuiltinOperator_RIGHT_SHIFT, 1}, "2.13.0"},
{{BuiltinOperator_STABLEHLO_SCATTER, 1}, "2.15.0"},
{{BuiltinOperator_DILATE, 1}, "2.15.0"},
{{BuiltinOperator_STABLEHLO_RNG_BIT_GENERATOR, 1}, "2.15.0"},
{{BuiltinOperator_REDUCE_WINDOW, 1}, "2.15.0"},
{{BuiltinOperator_STABLEHLO_GATHER, 1}, "2.16.0"},
{{BuiltinOperator_STABLEHLO_ADD, 1}, "2.16.0"},
{{BuiltinOperator_STABLEHLO_MULTIPLY, 1}, "2.16.0"},
{{BuiltinOperator_STABLEHLO_REDUCE_WINDOW, 1}, "2.16.0"},
{{BuiltinOperator_STABLEHLO_MAXIMUM, 1}, "2.16.0"},
{{BuiltinOperator_STABLEHLO_MINIMUM, 1}, "2.16.0"},
{{BuiltinOperator_STABLEHLO_PAD, 1}, "2.16.0"},
{{BuiltinOperator_STABLEHLO_COMPOSITE, 1}, "2.17.0"},
{{BuiltinOperator_STABLEHLO_AND, 1}, "2.17.0"},
{{BuiltinOperator_STABLEHLO_SHIFT_LEFT, 1}, "2.17.0"},
{{BuiltinOperator_STABLEHLO_CBRT, 1}, "2.17.0"},
{{BuiltinOperator_STABLEHLO_CASE, 1}, "2.17.0"},
});
std::pair<BuiltinOperator, int> version_key = {op_code, op_version};
auto it = op_version_map->find(version_key);
if (it == op_version_map->end()) {
return std::string();
}
return it->second;
}
void UpdateMinimumRuntimeVersionForModel(uint8_t* model_buffer_pointer) {
auto model = GetMutableModel(model_buffer_pointer);
std::string model_min_version;
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());
std::string runtime_version = FindMinimumRuntimeVersionForOp(
GetBuiltinCode(op_code), op_code->version());
// If we didn't find the current op version in the map, skip comparison.
if (runtime_version.empty()) {
continue;
}
if (CompareRuntimeVersion(model_min_version, runtime_version)) {
// Current min model runtime version should be bumped if we see a
// higher op version.
model_min_version = runtime_version;
}
}
}
// The size of the `min_runtime_version` metadata buffer is 16 bytes. If the
// generated `model_min_version` is equal or longer than 16 bytes, print a
// warning message and return.
if (model_min_version.size() >= 16) {
LOG(WARNING) << "Skip writing minimum runtime version string since it's "
<< "longer than 16 bytes.";
return;
}
// Copy over the bytes from `model_min_version` into the buffer.
for (int i = 0; i < model->metadata()->size(); ++i) {
if (model->metadata()->Get(i)->name()->str() == "min_runtime_version") {
auto buffer = model->metadata()->Get(i)->buffer();
auto buffer_data =
model->mutable_buffers()->GetMutableObject(buffer)->mutable_data();
memset(buffer_data->data(), 0, buffer_data->size());
memcpy(buffer_data->data(), model_min_version.data(),
model_min_version.size());
break;
}
}
}
} // namespace tflite
@@ -0,0 +1,40 @@
/* Copyright 2020 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_COMPILER_MLIR_LITE_TOOLS_VERSIONING_RUNTIME_VERSION_H_
#define TENSORFLOW_COMPILER_MLIR_LITE_TOOLS_VERSIONING_RUNTIME_VERSION_H_
#include <cstdint>
#include <string>
#include "flatbuffers/flatbuffers.h" // from @flatbuffers // IWYU pragma: keep
#include "tensorflow/compiler/mlir/lite/schema/mutable/schema_generated.h"
namespace tflite {
// Update minimum runtime version of the given TFL flatbuffer model.
void UpdateMinimumRuntimeVersionForModel(uint8_t* model_buffer_pointer);
// Find the minimum runtime version of a given op version. Return an empty
// string the version is not registered.
std::string FindMinimumRuntimeVersionForOp(tflite::BuiltinOperator op_code,
int op_version);
// Returns true if the first version string precedes the second.
// For example, '1.9' should precede '1.14', also '1.14' should precede
// '1.14.1'. If two version string is equal, then false will be returned.
bool CompareRuntimeVersion(const std::string&, const std::string&);
} // namespace tflite
#endif // TENSORFLOW_COMPILER_MLIR_LITE_TOOLS_VERSIONING_RUNTIME_VERSION_H_
@@ -0,0 +1,35 @@
/* Copyright 2025 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/compiler/mlir/lite/tools/versioning/runtime_version.h"
#include <string>
#include <gtest/gtest.h>
namespace tflite {
TEST(OpVersionTest, CompareRuntimeVersion) {
EXPECT_TRUE(CompareRuntimeVersion("1.9", "1.13"));
EXPECT_FALSE(CompareRuntimeVersion("1.13", "1.13"));
EXPECT_TRUE(CompareRuntimeVersion("1.14", "1.14.1"));
EXPECT_FALSE(CompareRuntimeVersion("1.14.1", "1.14"));
EXPECT_FALSE(CompareRuntimeVersion("1.14.1", "1.9"));
EXPECT_FALSE(CompareRuntimeVersion("1.0.9", "1.0.8"));
EXPECT_FALSE(CompareRuntimeVersion("2.1.0", "1.2.0"));
EXPECT_TRUE(CompareRuntimeVersion("", "1.13"));
EXPECT_FALSE(CompareRuntimeVersion("", ""));
}
} // namespace tflite