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
+800
View File
@@ -0,0 +1,800 @@
load("@rules_cc//cc:cc_library.bzl", "cc_library")
load("@rules_cc//cc:cc_test.bzl", "cc_test")
load("@xla//third_party/rules_python/python:py_binary.bzl", "py_binary")
load("@xla//third_party/rules_python/python:py_library.bzl", "py_library")
load(
"//tensorflow:tensorflow.bzl",
"tf_cc_binary",
"tf_cc_test",
)
load("//tensorflow:tensorflow.default.bzl", "pybind_extension")
load("//tensorflow/core/platform:build_config_root.bzl", "if_pywrap")
load(
"//tensorflow/lite:build_def.bzl",
"tflite_custom_android_library",
"tflite_custom_cc_library",
)
load("//tensorflow/lite:special_rules.bzl", "tflite_portable_test_suite")
load(
"//tensorflow/lite/testing:build_def.bzl",
"delegate_suffix",
"gen_zip_test",
"gen_zipped_test_file",
"generated_test_models_all",
)
load("//tensorflow/lite/testing:tflite_model_test.bzl", "tflite_model_test")
# copybara:uncomment(oss-unused) load("//tools/build_defs/build_test:build_test.bzl", "build_test")
package(
# copybara:uncomment default_applicable_licenses = ["//tensorflow:LICENSE"],
default_visibility = [
"//visibility:public",
],
licenses = ["notice"],
)
exports_files([
"build_def.bzl",
"generated_examples_zip_test.cc",
"tflite_diff_example_test.cc",
"init_tensorflow.h",
"init_tensorflow.cc",
])
_test_size_override = {
# copybara:comment_begin(oss-only)
"merged_models_with-flex_6": "large",
"merged_models_with-flex_9": "large",
# copybara:comment_end
}
[gen_zip_test(
name = "zip_test_%s%s" % (
test_name,
delegate_suffix(delegate),
),
size = _test_size_override.get(test_name, "medium"),
srcs = ["generated_examples_zip_test.cc"],
args = args + select({
"//tensorflow:android": [],
"//conditions:default": [
"--zip_file_path=$(location :zip_%s%s)" % (
test_name,
delegate_suffix(delegate),
),
# TODO(angerson) We may be able to add an external unzip binary instead
# of relying on an existing one for OSS builds.
#"--unzip_binary_path=/usr/bin/unzip",
],
}),
conversion_mode = conversion_mode,
# copybara:uncomment_begin(no special handling for Android in OSS)
# data = select({
# "//tensorflow:android": [],
# "//conditions:default": [
# ":zip_%s%s" % (
# test_name,
# delegate_suffix(delegate),
# ),
# "//third_party/unzip",
# ],
# }),
# copybara:uncomment_end_and_comment_begin
data = [":zip_%s%s" % (
test_name,
delegate_suffix(delegate),
)],
# copybara:comment_end
delegate = delegate,
tags = tags + [
"gen_zip_test",
"tflite_not_portable_intentional",
],
test_name = test_name,
deps = [
":parse_testdata_lib",
":tflite_driver",
":tflite_driver_delegate_providers",
":util",
"//tensorflow/lite:builtin_op_data",
"//tensorflow/lite:framework",
"//tensorflow/lite:string",
"//tensorflow/lite/kernels:builtin_ops",
"@com_google_absl//absl/status",
"@com_google_absl//absl/strings",
"@com_google_googletest//:gtest",
"@com_googlesource_code_re2//:re2",
] + select({
"//conditions:default": [
"@tsl//tsl/platform:env",
"@tsl//tsl/platform:status",
"@xla//xla/tsl/platform:subprocess",
"@xla//xla/tsl/util:command_line_flags",
],
"//tensorflow:android": [
"//tensorflow/core:portable_tensorflow_lib",
"//tensorflow/core:portable_tensorflow_test_lib",
],
}),
) for conversion_mode, delegate, test_name, tags, args in generated_test_models_all()]
test_suite(
name = "generated_zip_tests",
tags = [
"gen_zip_test",
],
)
py_library(
name = "mlir_convert",
srcs = ["mlir_convert.py"],
data = [
"//tensorflow/compiler/mlir/lite:tf_tfl_translate",
],
strict_deps = True,
deps = [
":zip_test_utils",
"//tensorflow/lite/python:lite",
"//tensorflow/lite/python:test_util",
"//tensorflow/python/platform:resource_loader",
"//tensorflow/python/saved_model:signature_constants",
"//third_party/py/numpy",
],
)
py_library(
name = "op_tests",
srcs = glob(["op_tests/*.py"]),
strict_deps = True,
deps = [
":zip_test_utils",
"//third_party/py/numpy",
"//tensorflow:tensorflow_py",
# copybara:uncomment_begin(b/186563810)
# "//third_party/py/tensorflow_addons",
# copybara:uncomment_end
"//tensorflow/python/framework:test_lib",
"//tensorflow/lite/python:lite",
"//tensorflow/python/ops:array_ops",
"//tensorflow/python/ops:list_ops",
"//tensorflow/python/ops:rnn",
],
)
py_library(
name = "generate_examples_lib",
srcs = ["generate_examples_lib.py"],
strict_deps = True,
deps = [
":op_tests",
":zip_test_utils",
"//tensorflow:tensorflow_py",
],
)
py_library(
name = "zip_test_utils",
srcs = ["zip_test_utils.py"],
strict_deps = True,
deps = [
":generate_examples_report",
"//tensorflow:tensorflow_py",
"//tensorflow/lite/python:lite",
"//tensorflow/lite/tools:flatbuffer_utils",
"//tensorflow/python/framework:convert_to_constants",
"//tensorflow/python/saved_model:signature_constants",
"//third_party/py/numpy",
"@ml_dtypes_py//ml_dtypes",
] + if_pywrap(
if_false = [
":_pywrap_string_util",
],
if_true = [
"//tensorflow/lite/python:pywrap_tflite",
],
),
)
py_binary(
name = "generate_examples",
srcs = ["generate_examples.py"],
strict_deps = True,
deps = [
":generate_examples_lib",
":mlir_convert",
"//tensorflow:tensorflow_py",
] + if_pywrap(
if_true = ["//tensorflow/python:_pywrap_tensorflow"],
),
)
py_library(
name = "generate_examples_report",
srcs = ["generate_examples_report.py"],
strict_deps = True,
)
cc_library(
name = "parse_testdata_lib",
srcs = ["parse_testdata.cc"],
hdrs = ["parse_testdata.h"],
deps = [
":message",
":split",
":test_runner",
"//tensorflow/lite:framework",
"//tensorflow/lite:string",
"//tensorflow/lite/c:c_api_types",
"//tensorflow/lite/c:common",
"//tensorflow/lite/core:framework_stable",
],
)
cc_library(
name = "matchers",
testonly = True,
srcs = ["matchers.h"],
hdrs = ["matchers.h"],
deps = [
"//tensorflow/lite/core/c:common",
"//tensorflow/lite/kernels:kernel_util",
"@com_google_absl//absl/base",
"@com_google_absl//absl/log:absl_check",
"@com_google_absl//absl/strings",
"@com_google_absl//absl/strings:string_view",
"@com_google_absl//absl/types:span",
"@com_google_googletest//:gtest",
],
)
cc_test(
name = "matchers_test",
srcs = ["matchers_test.cc"],
deps = [
":matchers",
"//tensorflow/lite/core/c:c_api_types",
"//tensorflow/lite/core/c:common",
"@com_google_absl//absl/types:span",
"@com_google_googletest//:gtest_main",
],
)
cc_library(
name = "message",
srcs = ["message.cc"],
hdrs = ["message.h"],
deps = [":tokenize"],
)
cc_test(
name = "message_test",
srcs = ["message_test.cc"],
deps = [
":message",
"@com_google_googletest//:gtest_main",
],
)
cc_library(
name = "split",
srcs = ["split.cc"],
hdrs = ["split.h"],
deps = [
"//tensorflow/lite:string",
"//tensorflow/lite/types:half",
"@eigen_archive//:eigen3",
],
)
cc_test(
name = "split_test",
size = "small",
srcs = ["split_test.cc"],
deps = [
":split",
"//tensorflow/lite:string",
"//tensorflow/lite/types:half",
"@com_google_googletest//:gtest_main",
"@eigen_archive//:eigen3",
],
)
cc_library(
name = "join",
hdrs = ["join.h"],
deps = ["//tensorflow/lite:string"],
)
cc_test(
name = "join_test",
size = "small",
srcs = ["join_test.cc"],
deps = [
":join",
"@com_google_googletest//:gtest_main",
],
)
cc_library(
name = "tflite_driver",
srcs = ["tflite_driver.cc"],
hdrs = ["tflite_driver.h"],
deps = [
":join",
":result_expectations",
":split",
":test_runner",
"//tensorflow/lite:builtin_op_data",
"//tensorflow/lite:framework",
"//tensorflow/lite:string",
"//tensorflow/lite:string_util",
"//tensorflow/lite/core:framework",
"//tensorflow/lite/core/api:op_resolver",
"//tensorflow/lite/core/c:c_api_types",
"//tensorflow/lite/core/c:common",
"//tensorflow/lite/core/kernels:builtin_ops",
"//tensorflow/lite/kernels:custom_ops",
"//tensorflow/lite/kernels:reference_ops",
"//tensorflow/lite/kernels:test_delegate_providers_lib",
"//tensorflow/lite/kernels/gradient:gradient_ops",
"//tensorflow/lite/kernels/parse_example",
"//tensorflow/lite/kernels/perception:perception_ops",
"//tensorflow/lite/tools:logging",
"//tensorflow/lite/tools/delegates:delegate_provider_hdr",
"//tensorflow/lite/tools/evaluation:utils",
"//tensorflow/lite/types:half",
"@com_google_absl//absl/strings",
"@eigen_archive//:eigen3",
] + select({
"//tensorflow:ios": [],
"//conditions:default": ["//tensorflow/lite/delegates/flex:delegate"],
}),
)
# A convenient library of tflite delegate execution providers for tests based
# on the `tflite_driver` library.
cc_library(
name = "tflite_driver_delegate_providers",
deps = [
"//tensorflow/lite/tools/delegates:coreml_delegate_provider",
"//tensorflow/lite/tools/delegates:default_execution_provider",
"//tensorflow/lite/tools/delegates:external_delegate_provider",
"//tensorflow/lite/tools/delegates:gpu_delegate_provider",
"//tensorflow/lite/tools/delegates:hexagon_delegate_provider",
"//tensorflow/lite/tools/delegates:nnapi_delegate_provider",
"//tensorflow/lite/tools/delegates:xnnpack_delegate_provider",
],
alwayslink = 1,
)
tf_cc_test(
name = "tflite_driver_test",
size = "small",
srcs = ["tflite_driver_test.cc"],
data = [
"//tensorflow/lite:testdata/add_quantized_int8.bin",
"//tensorflow/lite:testdata/multi_add.bin",
],
tags = [
"tflite_not_portable_android",
"tflite_not_portable_ios",
],
deps = [
":test_runner",
":tflite_driver",
"@com_google_googletest//:gtest_main",
],
)
cc_library(
name = "tokenize",
srcs = ["tokenize.cc"],
hdrs = ["tokenize.h"],
deps = [
"//tensorflow/lite:string",
],
)
cc_test(
name = "tokenize_test",
srcs = ["tokenize_test.cc"],
deps = [
":tokenize",
"@com_google_googletest//:gtest_main",
],
)
cc_library(
name = "test_runner",
hdrs = ["test_runner.h"],
deps = [
"//tensorflow/lite:string",
],
)
cc_library(
name = "util",
hdrs = ["util.h"],
deps = [
"//tensorflow/lite:string",
"//tensorflow/lite/core/api",
"@com_google_absl//absl/flags:flag",
"@com_google_absl//absl/log:flags",
],
)
cc_test(
name = "test_runner_test",
srcs = ["test_runner_test.cc"],
deps = [
":test_runner",
"//tensorflow/lite:string",
"@com_google_googletest//:gtest_main",
],
)
tf_cc_binary(
name = "nnapi_example",
srcs = ["nnapi_example.cc"],
deps = [
":parse_testdata_lib",
":tflite_driver",
],
)
cc_library(
name = "tf_driver",
srcs = ["tf_driver.cc"],
hdrs = ["tf_driver.h"],
deps = [
":join",
":split",
":test_runner",
"//tensorflow/core:protos_all_cc",
"//tensorflow/lite:string",
"//tensorflow/lite:string_util",
"@com_google_absl//absl/container:flat_hash_map",
"@com_google_absl//absl/log:check",
"@com_google_absl//absl/strings",
"@com_google_absl//absl/types:span",
] + select({
"//conditions:default": [
"//tensorflow/core:core_cpu",
"//tensorflow/core:framework",
"//tensorflow/core:lib",
"//tensorflow/core:tensorflow",
],
"//tensorflow:android": [
"//tensorflow/core:portable_tensorflow_lib",
],
"//tensorflow:ios": [
"//tensorflow/core:portable_tensorflow_lib",
],
}),
)
tf_cc_test(
name = "tf_driver_test",
size = "small",
srcs = ["tf_driver_test.cc"],
data = ["//tensorflow/lite:testdata/multi_add.pb"],
tags = [
"tflite_not_portable",
],
deps = [
":tf_driver",
"//tensorflow/core:framework",
"//tensorflow/core:protos_all_cc",
"//tensorflow/lite:string",
"//tensorflow/lite:string_util",
"@com_google_absl//absl/strings",
"@com_google_absl//absl/types:span",
"@com_google_googletest//:gtest_main",
],
)
cc_library(
name = "generate_testspec",
srcs = ["generate_testspec.cc"],
hdrs = ["generate_testspec.h"],
deps = [
":join",
":split",
":test_runner",
":tf_driver",
":tflite_driver",
"//tensorflow/core:protos_all_cc",
"//tensorflow/lite:string",
"@com_google_absl//absl/log:check",
] + select({
"//conditions:default": [
"//tensorflow/core:framework",
],
"//tensorflow:android": [
"//tensorflow/core:portable_tensorflow_lib",
],
"//tensorflow:ios": [
"//tensorflow/core:portable_tensorflow_lib",
],
}),
)
tf_cc_test(
name = "generate_testspec_test",
size = "small",
srcs = ["generate_testspec_test.cc"],
tags = [
"tflite_not_portable",
],
deps = [
":generate_testspec",
"@com_google_googletest//:gtest_main",
],
)
cc_library(
name = "init_tensorflow",
srcs = [
"init_tensorflow.cc",
],
hdrs = [
"init_tensorflow.h",
],
visibility = [
# copybara:uncomment_begin(internal brella benchmark)
# "//learning/brain/mobile/lite/brella_benchmark:__subpackages__",
# copybara:uncomment_end
"//tensorflow/lite/delegates/flex:__subpackages__",
"//tensorflow/lite/tools/benchmark:__subpackages__",
],
deps = select({
"//conditions:default": [
"//tensorflow/core:lib",
],
"//tensorflow:android": [
"//tensorflow/core:portable_tensorflow_lib_lite",
],
"//tensorflow:ios": [
"//tensorflow/core:portable_tensorflow_lib_lite",
],
}),
)
cc_library(
name = "tflite_diff_util",
srcs = ["tflite_diff_util.cc"],
hdrs = ["tflite_diff_util.h"],
deps = [
":generate_testspec",
":parse_testdata_lib",
":test_runner",
":tflite_driver",
"//tensorflow/lite:framework",
"//tensorflow/lite:string",
],
)
cc_library(
name = "tflite_diff_flags",
hdrs = ["tflite_diff_flags.h"],
deps = [
":split",
":tflite_diff_util",
":tflite_driver",
"@com_google_absl//absl/strings",
] + select({
"//conditions:default": [
"//tensorflow/core:framework_internal",
"//tensorflow/core:lib",
],
"//tensorflow:android": [
"//tensorflow/core:portable_tensorflow_lib",
],
"//tensorflow:ios": [
"//tensorflow/core:portable_tensorflow_lib",
],
}),
)
tf_cc_test(
name = "tflite_diff_example_test",
size = "medium",
srcs = ["tflite_diff_example_test.cc"],
args = [
"--tensorflow_model=third_party/tensorflow/lite/testdata/multi_add.pb",
"--tflite_model=third_party/tensorflow/lite/testdata/multi_add.bin",
"--input_layer=a,b,c,d",
"--input_layer_type=float,float,float,float",
"--input_layer_shape=1,3,4,3:1,3,4,3:1,3,4,3:1,3,4,3",
"--output_layer=x,y",
],
data = [
"//tensorflow/lite:testdata/multi_add.bin",
"//tensorflow/lite:testdata/multi_add.pb",
],
tags = [
"no_cuda_on_cpu_tap",
"no_oss", # needs test data
"tflite_not_portable",
],
deps = [
":init_tensorflow",
":tflite_diff_flags",
":tflite_diff_util",
],
)
tf_cc_binary(
name = "tflite_diff",
srcs = ["tflite_diff_example_test.cc"],
deps = [
":init_tensorflow",
":tflite_diff_flags",
":tflite_diff_util",
],
)
tflite_model_test(
name = "tflite_model_example_test",
input_layer = "a,b,c,d",
input_layer_shape = "1,8,8,3:1,8,8,3:1,8,8,3:1,8,8,3",
input_layer_type = "float,float,float,float",
output_layer = "x,y",
tags = [
"no_cuda_on_cpu_tap",
"no_oss", # needs test data
"tflite_not_portable", # TODO(b/134772701): Enable after making this a proper GTest.
],
tensorflow_model_file = "//tensorflow/lite:testdata/multi_add.pb",
)
cc_library(
name = "string_util_lib",
srcs = ["string_util.cc"],
hdrs = ["string_util.h"],
deps = [
"//tensorflow/lite:string",
"//tensorflow/lite:string_util",
"//tensorflow/lite/python/interpreter_wrapper:numpy",
"//tensorflow/lite/python/interpreter_wrapper:python_utils",
"@com_google_absl//absl/strings",
"@xla//third_party/python_runtime:headers",
],
)
cc_library(
name = "result_expectations",
srcs = ["result_expectations.cc"],
hdrs = ["result_expectations.h"],
deps = [
":split",
"//tensorflow/lite:framework",
"//tensorflow/lite:string_util",
"//tensorflow/lite/core/c:c_api_types",
"//tensorflow/lite/core/c:common",
"@com_google_absl//absl/strings",
"@eigen_archive//:eigen3",
],
)
# A selective built tflite for testing.
tflite_custom_cc_library(
name = "test_tflite_lib",
models = [
"//tensorflow/lite:testdata/add.bin",
"//tensorflow/lite:testdata/lstm.bin",
],
)
cc_test(
name = "selective_build_test",
srcs = ["selective_build_test.cc"],
data = [
"//tensorflow/lite:testdata/add.bin",
"//tensorflow/lite:testdata/lstm.bin",
],
tags = [
"no_mac", # b/161990368
"tflite_not_portable",
],
deps = [
":test_tflite_lib",
"//tensorflow/core:tflite_portable_logging",
"//tensorflow/lite:framework",
"//tensorflow/lite/core:cc_api_stable",
"//tensorflow/lite/core/c:common",
"@com_google_absl//absl/log",
"@com_google_googletest//:gtest_main",
],
)
pybind_extension(
name = "_pywrap_string_util",
srcs = [
"string_util_wrapper.cc",
],
hdrs = ["string_util.h"],
additional_stubgen_deps = [
"//third_party/py/numpy:numpy",
],
common_lib_packages = [
"litert/python",
"tensorflow/lite/python",
],
enable_stub_generation = True,
features = ["-use_header_modules"],
pytype_srcs = [
"_pywrap_string_util.pyi",
],
wrap_py_init = True,
deps = [
":string_util_lib",
"//tensorflow/lite/python/interpreter_wrapper:numpy",
"//tensorflow/python/lib/core:pybind11_lib",
"@pybind11",
"@xla//third_party/python_runtime:headers",
],
)
tflite_portable_test_suite()
tflite_custom_android_library(
name = "customized_tflite_for_add_ops",
experimental = True,
models = ["//tensorflow/lite:testdata/add.bin"],
visibility = ["//visibility:public"],
)
edgetpu_ops = [
"add",
"avg_pool",
"concat",
"conv", # high error
"conv_relu",
"conv_relu1",
"conv_relu6",
"depthwiseconv", # high error
"expand_dims",
"fully_connected",
"l2norm", # high error
"maximum",
"max_pool",
"mean",
"minimum",
"mul",
"pad", # high error
"pack",
"relu",
"relu1",
"relu6",
"reshape",
"resize_bilinear",
"resize_nearest_neighbor",
"sigmoid",
"slice",
"softmax",
"space_to_depth",
"split",
"squeeze",
"strided_slice",
"sub",
"sum", # high error
"tanh",
"transpose",
"transpose_conv",
]
# copybara:uncomment_begin(google-only)
# [gen_zipped_test_file(
# name = "zip_%s_edgetpu" % op_name,
# file = "%s_edgetpu.zip" % op_name,
# flags = " --make_edgetpu_tests",
# ) for op_name in edgetpu_ops]
#
# edgetpu_targets = [":zip_%s_edgetpu" % op_name for op_name in edgetpu_ops]
#
# build_test(
# name = "gen_edgetpu_tests",
# targets = edgetpu_targets,
# )
# copybara:uncomment_end
@@ -0,0 +1,16 @@
# 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.
# ==============================================================================
def SerializeAsHexString(arg0: object) -> object: ...
+593
View File
@@ -0,0 +1,593 @@
"""Build rule definitions for TFLite zip tests."""
load(
"//tensorflow:tensorflow.bzl",
"tf_cc_test",
)
# This is the master list of generated examples that will be made into tests. A
# function called make_XXX_tests() must also appear in generate_examples.py.
# Disable a test by adding it to the denylists specified in
# generated_test_models_failing().
def generated_test_models():
return [
# keep sorted
"abs",
"add",
"add_n",
"arg_min_max",
"atan2",
"avg_pool",
"avg_pool3d",
"batch_to_space_nd",
"batchmatmul",
"bitcast",
"bitwise_xor",
"broadcast_args",
"broadcast_gradient_args",
"broadcast_to",
"cast",
"ceil",
"complex_abs",
"concat",
"cond",
"constant",
"control_dep",
"conv",
"conv2d_transpose",
"conv3d",
"conv3d_transpose",
"conv_bias_relu6",
"conv_relu",
"conv_relu1",
"conv_relu6",
"conv_to_depthwiseconv_with_shared_weights",
"conv_with_shared_weights",
"cos",
"cumsum",
# copybara:uncomment(Exclude tests that depend on tensorflow_addons APIs) "dense_image_warp",
"depth_to_space",
"depthwiseconv",
"div",
# copybara:uncomment(b/275574740) "dynamic_rnn",
"dynamic_update_slice",
"einsum",
"elu",
"embedding_lookup",
"equal",
"exp",
"expand_dims",
"expm1",
"eye",
"fill",
"floor",
"floor_div",
"floor_mod",
"fully_connected",
"fully_connected_4bit_hybrid",
"fused_batch_norm",
"gather",
"gather_nd",
"gather_with_constant",
"gelu",
"global_batch_norm",
"greater",
"greater_equal",
"hardswish",
"identify_dilated_conv",
"identify_dilated_conv1d",
"identity",
"imag",
"irfft2d",
"is_finite",
"l2_pool",
"l2norm",
"l2norm_shared_epsilon",
"leaky_relu",
"less",
"less_equal",
"local_response_norm",
"log",
"log_softmax",
"logical_and",
"logical_or",
"logical_xor",
# copybara:uncomment(b/275574740) "lstm",
"matrix_band_part",
"matrix_diag",
"matrix_set_diag",
"max_pool",
"max_pool3d",
"max_pool_with_argmax",
"maximum",
"mean",
"minimum",
"mirror_pad",
"mul",
"multinomial",
"nearest_upsample",
"neg",
"not_equal",
"one_hot",
"pack",
"pad",
"padv2",
"parse_example",
"placeholder_with_default",
"pow",
"prelu",
"random_standard_normal",
"random_uniform",
"range",
"rank",
"real",
"reciprocal",
"reduce_all",
"reduce_any",
"reduce_max",
"reduce_min",
"reduce_prod",
"relu",
"relu1",
"relu6",
"reshape",
"resize_bilinear",
"resize_nearest_neighbor",
"resolve_constant_strided_slice",
"reverse_sequence",
"reverse_v2",
"rfft",
"rfft2d",
"right_shift",
"roll",
"roll_with_constant",
"round",
"rsqrt",
"scatter_nd",
"segment_sum",
"shape",
"shape_to_strided_slice",
"sigmoid",
"sigmoid_grad",
"sign",
"sin",
"slice",
"softmax",
"softplus",
"softsign",
"space_to_batch_nd",
"space_to_depth",
"sparse_to_dense",
"split",
"splitv",
"sqrt",
"square",
"squared_difference",
"squeeze",
"static_hashtable",
# copybara:uncomment(b/275574740) "static_rnn_with_control_flow_v2",
"stft",
"strided_slice",
"strided_slice_1d_exhaustive",
"strided_slice_np_style",
"sub",
"sum",
"tanh",
"tensor_list_concat",
"tensor_list_dynamic_shape",
"tensor_list_get_item",
"tensor_list_length",
"tensor_list_resize",
"tensor_list_set_item",
"tensor_scatter_add",
"tensor_scatter_update",
"tile",
"topk",
"transpose",
"transpose_conv",
# copybara:uncomment(b/275574740) "unfused_gru",
"unique",
"unpack",
"unroll_batch_matmul",
"unsorted_segment_max",
"unsorted_segment_min",
"unsorted_segment_prod",
"unsorted_segment_sum",
"where",
"where_v2",
"while",
"zeros_like",
]
def mlir_generated_test_denylisted_models():
return [
# TODO(b/150647400): This test passes in TF2 with tf.compat.v1 but
# fails in TF1 with tf.compat.v1. Due to the testing environments
# changing on 3/3, this will only be disabled temporarily.
"unidirectional_sequence_lstm",
"unidirectional_sequence_rnn",
]
# List of models that fail generated tests for the conversion mode.
# If you have to disable a test, please add here with a link to the appropriate
# bug or issue.
def generated_test_models_failing(conversion_mode, delegate):
if delegate == "xnnpack":
# TODO(b/179802976): Revisit this list after XNNPack Delegate supports
# dynamic tensors.
return [
"batch_to_space_nd",
"broadcast_gradient_args",
"broadcast_to",
"concat",
"cond",
"conv2d_transpose",
"conv3d_transpose",
"depthwiseconv",
"dynamic_rnn",
"einsum",
"expand_dims",
"eye",
"fill",
"fully_connected",
"fused_batch_norm",
"gather",
"gather_nd",
"global_batch_norm",
"leaky_relu",
"matrix_band_part",
"mean",
"mirror_pad",
"multinomial",
"one_hot",
"pad",
"padv2",
"parse_example",
"pow",
"prelu",
"random_standard_normal",
"random_uniform",
"range",
"reduce_all",
"reduce_any",
"reduce_max",
"reduce_min",
"reduce_prod",
"reshape",
"roll",
"roll_with_constant",
"round",
"scatter_nd",
"segment_sum",
"shape",
"slice",
"space_to_batch_nd",
"squeeze",
"static_hashtable",
"stft",
"strided_slice_1d_exhaustive",
"strided_slice",
"sum",
"tensor_list_dynamic_shape",
"tensor_list_length",
"tensor_list_resize",
"tile",
"topk",
"transpose",
"unique",
"unsorted_segment_max",
"unsorted_segment_min",
"unsorted_segment_prod",
"unsorted_segment_sum",
"where",
"where_v2",
"while",
]
else:
return []
def generated_test_models_successful(conversion_mode, delegate):
"""Returns the list of successful test models.
Args:
conversion_mode: Conversion mode.
delegate: Delegate zip test runs with.
Returns:
List of successful test models for the conversion mode.
"""
return [test_model for test_model in generated_test_models() if test_model not in generated_test_models_failing(conversion_mode, delegate)]
def merged_test_model_name():
"""Returns the name of merged test model.
Returns:
The name of merged test model.
"""
return "merged_models"
def max_number_of_test_models_in_merged_zip():
"""Returns the maximum number of merged test models in a zip file.
Returns:
Maximum number of merged test models in a zip file.
"""
return 5
def number_of_merged_zip_file(conversion_mode, delegate):
"""Returns the number of merged zip file targets.
Returns:
Number of merged zip file targets.
"""
m = max_number_of_test_models_in_merged_zip()
return (len(generated_test_models_successful(conversion_mode, delegate)) + m - 1) // m
def merged_test_models():
"""Generates a list of merged tests with the different converters.
This model list should be referred only if :generate_examples supports
--no_tests_limit and --test_sets flags.
Returns:
List of tuples representing:
(conversion mode, name of group, test tags, test args).
"""
conversion_modes = generated_test_conversion_modes()
options = []
for conversion_mode in conversion_modes:
test = merged_test_model_name()
if conversion_mode:
test += "_%s" % conversion_mode
for delegate in generated_test_delegates():
successful_tests = generated_test_models_successful(conversion_mode, delegate)
if len(successful_tests) > 0:
tags = common_test_tags_for_generated_models(conversion_mode, False)
# Only non-merged tests are executed on TAP.
# Merged test rules are only for running on the real device environment.
if "notap" not in tags:
tags.append("notap")
# Only execute merged tests on real device.
if "no_oss" not in tags:
tags.append("no_oss")
args = common_test_args_for_generated_models(conversion_mode, False)
n = number_of_merged_zip_file(conversion_mode, delegate)
for i in range(n):
test_i = "%s_%d" % (test, i)
options.append((conversion_mode, delegate, test_i, tags, args))
return options
def flags_for_merged_test_models(test_name, conversion_mode, delegate):
"""Returns flags for generating zipped-example data file for merged tests.
Args:
test_name: str. Test name in the form of "<merged_model_name>_[<conversion_mode>_]%d".
conversion_mode: str. Which conversion mode to run with. Comes from the
list above.
delegate: str. Delegate zip test runs with.
Returns:
Flags for generating zipped-example data file for merged tests.
"""
prefix = merged_test_model_name() + "_"
if not test_name.startswith(prefix):
fail(msg = "Invalid test name " + test_name + ": test name should start " +
"with " + prefix + " when using flags of merged test models.")
# Remove prefix and conversion_mode from the test name
# to extract merged test index number.
index_string = test_name[len(prefix):]
if conversion_mode:
index_string = index_string.replace("%s_" % conversion_mode, "")
if delegate:
index_string = index_string.replace("%s_" % delegate, "")
# If the maximum number of test models in a file is 15 and the number of
# successful test models are 62, 5 zip files will be generated.
# To assign the test models fairly among these files, each zip file
# should contain 12 or 13 test models. (62 / 5 = 12 ... 2)
# Each zip file will have 12 test models and the first 2 zip files will have
# 1 more test model each, resulting [13, 13, 12, 12, 12] assignment.
# So Zip file 0, 1, 2, 3, 4 and 5 will have model[0:13], model[13:26],
# model[26,38], model[38,50] and model[50,62], respectively.
zip_index = int(index_string)
num_merged_zips = number_of_merged_zip_file(conversion_mode, delegate)
test_models = generated_test_models_successful(conversion_mode, delegate)
# Each zip file has (models_per_zip) or (models_per_zip+1) test models.
models_per_zip = len(test_models) // num_merged_zips
# First (models_remaining) zip files have (models_per_zip+1) test models each.
models_remaining = len(test_models) % num_merged_zips
if zip_index < models_remaining:
# Zip files [0:models_remaining] have (models_per_zip+1) models.
begin = (models_per_zip + 1) * zip_index
end = begin + (models_per_zip + 1)
else:
# Zip files [models_remaining:] have (models_per_zip) models.
begin = models_per_zip * zip_index + models_remaining
end = begin + models_per_zip
tests_csv = ""
for test_model in test_models[begin:end]:
tests_csv += "%s," % test_model
if tests_csv != "":
tests_csv = tests_csv[:-1] # Remove trailing comma.
return " --no_tests_limit --test_sets=%s" % tests_csv
def mlir_generated_test_models():
"""Returns a list of models to be tested with MLIR-based conversion.
Returns:
List of strings of models.
"""
models = []
denylisted_models = mlir_generated_test_denylisted_models()
for model in generated_test_models():
if model not in denylisted_models:
models.append(model)
return models
def generated_test_conversion_modes():
"""Returns a list of conversion modes."""
return ["with-flex", "forward-compat", "", "mlir-quant"]
def generated_test_delegates():
"""Returns a list of delegates."""
return ["", "xnnpack"]
def delegate_suffix(delegate):
"""Returns the suffix for the delegate. Empty string for default (no delegate)."""
if delegate:
return "_%s" % delegate
return ""
def generated_test_models_all():
"""Generates a list of all tests with the different converters.
Returns:
List of tuples representing:
(conversion mode, delegate to use, name of test, test tags, test args).
"""
conversion_modes = generated_test_conversion_modes()
options = []
for conversion_mode in conversion_modes:
for delegate in generated_test_delegates():
failing_tests = generated_test_models_failing(conversion_mode, delegate)
for test in mlir_generated_test_models():
tags = []
args = []
# Forward-compat coverage testing is largely redundant, and
# contributes to coverage test bloat.
if conversion_mode == "forward-compat":
tags.append("nozapfhahn")
if test in failing_tests:
tags.append("notap")
tags.append("manual")
if conversion_mode:
test += "_%s" % conversion_mode
options.append((conversion_mode, delegate, test, tags, args))
return options
def common_test_args_for_generated_models(conversion_mode, failing):
"""Returns test args for generated model tests.
Args:
conversion_mode: Conversion mode.
failing: True if the generated model test is failing.
Returns:
test args of generated models.
"""
args = []
# Flex conversion shouldn't suffer from the same conversion bugs
# listed for the default TFLite kernel backend.
if conversion_mode == "with-flex":
args.append("--ignore_known_bugs=false")
return args
def common_test_tags_for_generated_models(conversion_mode, failing):
"""Returns test tags for generated model tests.
Args:
conversion_mode: Conversion mode.
failing: True if the generated model test is failing.
Returns:
tags for the failing generated model tests.
"""
tags = []
# Forward-compat coverage testing is largely redundant, and contributes
# to coverage test bloat.
if conversion_mode == "forward-compat":
tags.append("nozapfhahn")
if failing:
return ["notap", "manual"]
return tags
def gen_zip_test(
name,
test_name,
conversion_mode,
tags,
args,
delegate,
**kwargs):
"""Generate a zipped-example test and its dependent zip files.
Args:
name: str. Resulting cc_test target name
test_name: str. Test targets this model. Comes from the list above.
conversion_mode: str. Which conversion mode to run with. Comes from the
list above.
tags: tags for the generated cc_test.
args: the basic cc_test args to be used.
delegate: str. Delegate to use in the zip test.
**kwargs: tf_cc_test kwargs
"""
flags = ""
if conversion_mode == "forward-compat":
flags += " --make_forward_compat_test"
elif conversion_mode == "mlir-quant":
flags += " --mlir_quantizer"
elif conversion_mode == "with-flex":
flags += " --ignore_converter_errors --run_with_flex"
if test_name.startswith(merged_test_model_name() + "_"):
flags += flags_for_merged_test_models(test_name, conversion_mode, delegate)
if delegate == "xnnpack":
# buildifier: disable=list-append
# Error: 'select' value has no field or method 'append'
args += ["--use_xnnpack=true"]
# TODO(b/204360746): XNNPack delegate don't support high dimension.
flags += " --skip_high_dimension_inputs"
zip_name = "zip_%s"
zip_file = "%s.zip"
if delegate:
zip_name = "zip_%s_" + delegate
zip_file = "%s_" + delegate + ".zip"
gen_zipped_test_file(
name = zip_name % test_name,
file = zip_file % test_name,
flags = flags,
)
tf_cc_test(name, tags = tags, args = args, **kwargs)
def gen_zipped_test_file(name, file, flags = ""):
"""Generate a zip file of tests by using :generate_examples.
Args:
name: str. Name of output. We will produce "`file`.files" as a target.
file: str. The name of one of the generated_examples targets, e.g. "transpose"
flags: str. Any additional flags to include
"""
native.genrule(
name = file + ".files",
cmd = (("TF_FLAG_SAVED_MODEL_FINGERPRINTING=0 " +
"$(location //tensorflow/lite/testing:generate_examples) " +
"--enable_tensorflow_metrics_export=false " +
"--zip_to_output {0} {1} $(@D)").format(file, flags)),
outs = [file],
# `exec_tools` is required for PY3 compatibility in place of `tools`.
tools = [
"//tensorflow/lite/testing:generate_examples",
],
)
native.filegroup(
name = name,
srcs = [file],
)
@@ -0,0 +1,153 @@
# 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.
# ==============================================================================
"""Generate a series of TensorFlow graphs that become tflite test cases.
Usage:
generate_examples <output directory>
bazel run //tensorflow/lite/testing:generate_examples
To more easily debug failures use (or override) the --save_graphdefs flag to
place text proto graphdefs into the generated zip files.
"""
import argparse
import os
import sys
import tensorflow as tf
from tensorflow.lite.testing import generate_examples_lib
from tensorflow.lite.testing import mlir_convert
MLIR_CONVERTER_KNOWN_BUGS = {
# We need to support dynamic_rnn case.
r"unidirectional_sequence_rnn.*is_dynamic_rnn=True": "128997102",
r"unidirectional_sequence_lstm.*is_dynamic_rnn=True": "128997102",
# TODO(b/124314620): Test cases work with tf_tfl_translate binary
# but not TFLiteConverter interface.
# Concat & SpaceToDepth with uint8 doesn't work.
r"concat.*type=tf\.uint8": "124314620",
r"space_to_depth.*type=tf\.uint8": "124314620",
r"l2norm.*fully_quantize=True": "134594898",
# Below are not really a converter bug, but our kernels doesn't support
# int64.
r"div.*dtype=tf\.int64": "119126484",
r"floor_div.*dtype=tf\.int64": "119126484",
r"relu.*dtype=tf\.int64": "119126484",
r"squared_difference.*dtype=tf\.int64": "119126484",
# Post-training quantization support missing for below op in mlir.
r"prelu.*fully_quantize=True": "156112683",
# ResizeBilinear op kernel supports only float32 and quantized 8-bit
# integers.
r"resize_bilinear.*dtype=tf\.int32": "156569626",
}
# Disable GPU for now since we are just testing in TF against CPU reference
# value and creating non-device-specific graphs to export.
os.environ["CUDA_VISIBLE_DEVICES"] = "-1"
parser = argparse.ArgumentParser(description="Script to generate TFLite tests.")
parser.add_argument(
"output_path", help="Directory where the outputs will be go.")
parser.add_argument(
"--zip_to_output",
type=str,
help="Particular zip to output.",
required=True)
parser.add_argument(
"--known_bugs_are_errors",
action="store_true",
help=("If a particular model is affected by a known bug,"
" count it as a converter error."))
parser.add_argument(
"--ignore_converter_errors",
action="store_true",
help="Raise an exception if any converter error is encountered.")
parser.add_argument(
"--save_graphdefs",
action="store_true",
help="Include intermediate graphdefs in the output zip files.")
parser.add_argument(
"--run_with_flex",
action="store_true",
help="Whether the TFLite Flex converter is being used.")
parser.add_argument(
"--make_edgetpu_tests",
action="store_true",
help="Whether to generate test cases for edgetpu.")
parser.add_argument(
"--make_tf_ptq_tests",
action="store_true",
help="Whether to generate test cases for TF post-training quantization.")
parser.add_argument(
"--hlo_aware_conversion",
action="store_true",
help="For TF Quantization only: whether conversion for HLO target.")
parser.add_argument(
"--make_forward_compat_test",
action="store_true",
help="Make tests by setting TF forward compatibility horizon to the future")
parser.add_argument(
"--no_tests_limit",
action="store_true",
help="Remove the limit of the number of tests.")
parser.add_argument(
"--test_sets",
type=str,
help=("Comma-separated list of test set names to generate. "
"If not specified, a test set is selected by parsing the name of "
"'zip_to_output' file."))
parser.add_argument(
"--mlir_quantizer",
action="store_true",
help=("Whether the new MLIR quantizer is being used."))
parser.add_argument(
"--skip_high_dimension_inputs",
action="store_true",
help=("Whether to skip generating tests with high dimension input shape."))
def main(unused_args):
options = generate_examples_lib.Options()
options.output_path = FLAGS.output_path
options.zip_to_output = FLAGS.zip_to_output
options.known_bugs_are_errors = FLAGS.known_bugs_are_errors
options.ignore_converter_errors = FLAGS.ignore_converter_errors
options.save_graphdefs = FLAGS.save_graphdefs
options.run_with_flex = FLAGS.run_with_flex
options.make_edgetpu_tests = FLAGS.make_edgetpu_tests
options.make_tf_ptq_tests = FLAGS.make_tf_ptq_tests
options.tflite_convert_function = mlir_convert.mlir_convert
options.known_bugs = MLIR_CONVERTER_KNOWN_BUGS
options.make_forward_compat_test = FLAGS.make_forward_compat_test
options.no_tests_limit = FLAGS.no_tests_limit
options.mlir_quantizer = FLAGS.mlir_quantizer
options.skip_high_dimension_inputs = FLAGS.skip_high_dimension_inputs
if FLAGS.test_sets:
test_sets = FLAGS.test_sets.split(",")
generate_examples_lib.generate_multi_set_examples(options, test_sets)
else:
generate_examples_lib.generate_examples(options)
if __name__ == "__main__":
FLAGS, unparsed = parser.parse_known_args()
tf.compat.v1.app.run(main=main, argv=[sys.argv[0]] + unparsed)
@@ -0,0 +1,380 @@
# 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.
# ==============================================================================
"""Generate a series of TensorFlow graphs that become tflite test cases.
Usage:
generate_examples <output directory>
bazel run //tensorflow/lite/testing:generate_examples
To more easily debug failures use (or override) the --save_graphdefs flag to
place text proto graphdefs into the generated zip files.
"""
import copy
import datetime
import os
import re
import zipfile
import tensorflow as tf
# TODO(aselle): Disable GPU for now
os.environ["CUDA_VISIBLE_DEVICES"] = "-1"
# pylint: disable=g-import-not-at-top
# pylint: disable=g-multiple-import
# pylint: disable=unused-import
from tensorflow.lite.testing.op_tests.abs import make_abs_tests
from tensorflow.lite.testing.op_tests.add_n import make_add_n_tests
from tensorflow.lite.testing.op_tests.arg_min_max import make_arg_min_max_tests
from tensorflow.lite.testing.op_tests.atan2 import make_atan2_tests
from tensorflow.lite.testing.op_tests.batch_to_space_nd import make_batch_to_space_nd_tests
from tensorflow.lite.testing.op_tests.batchmatmul import make_batchmatmul_tests
from tensorflow.lite.testing.op_tests.binary_op import make_add_tests, make_div_tests, make_sub_tests, make_mul_tests, make_pow_tests, make_floor_div_tests, make_floor_mod_tests, make_squared_difference_tests
from tensorflow.lite.testing.op_tests.bitcast import make_bitcast_tests
from tensorflow.lite.testing.op_tests.bitwise_xor import make_bitwise_xor_tests
from tensorflow.lite.testing.op_tests.broadcast_args import make_broadcast_args_tests
from tensorflow.lite.testing.op_tests.broadcast_gradient_args import make_broadcast_gradient_args_tests
from tensorflow.lite.testing.op_tests.broadcast_to import make_broadcast_to_tests
from tensorflow.lite.testing.op_tests.cast import make_cast_tests
from tensorflow.lite.testing.op_tests.ceil import make_ceil_tests
from tensorflow.lite.testing.op_tests.complex_abs import make_complex_abs_tests
from tensorflow.lite.testing.op_tests.concat import make_concat_tests
from tensorflow.lite.testing.op_tests.cond import make_cond_tests
from tensorflow.lite.testing.op_tests.constant import make_constant_tests
from tensorflow.lite.testing.op_tests.control_dep import make_control_dep_tests
from tensorflow.lite.testing.op_tests.conv import make_conv_tests
from tensorflow.lite.testing.op_tests.conv2d_transpose import make_conv2d_transpose_tests
from tensorflow.lite.testing.op_tests.conv3d import make_conv3d_tests
from tensorflow.lite.testing.op_tests.conv3d_transpose import make_conv3d_transpose_tests
from tensorflow.lite.testing.op_tests.conv_activation import make_conv_relu_tests, make_conv_relu1_tests, make_conv_relu6_tests
from tensorflow.lite.testing.op_tests.conv_bias_activation import make_conv_bias_relu6_tests
from tensorflow.lite.testing.op_tests.conv_to_depthwiseconv_with_shared_weights import make_conv_to_depthwiseconv_with_shared_weights_tests
from tensorflow.lite.testing.op_tests.conv_with_shared_weights import make_conv_with_shared_weights_tests
from tensorflow.lite.testing.op_tests.cos import make_cos_tests
from tensorflow.lite.testing.op_tests.cumsum import make_cumsum_tests
# Placeholder for make_dense_image_warp_tests import
from tensorflow.lite.testing.op_tests.depth_to_space import make_depth_to_space_tests
from tensorflow.lite.testing.op_tests.depthwiseconv import make_depthwiseconv_tests
from tensorflow.lite.testing.op_tests.dynamic_rnn import make_dynamic_rnn_tests
from tensorflow.lite.testing.op_tests.dynamic_update_slice import make_dynamic_update_slice_tests
from tensorflow.lite.testing.op_tests.einsum import make_einsum_tests
from tensorflow.lite.testing.op_tests.elementwise import make_sin_tests, make_log_tests, make_sqrt_tests, make_rsqrt_tests, make_square_tests
from tensorflow.lite.testing.op_tests.elu import make_elu_tests
from tensorflow.lite.testing.op_tests.embedding_lookup import make_embedding_lookup_tests
from tensorflow.lite.testing.op_tests.equal import make_equal_tests
from tensorflow.lite.testing.op_tests.exp import make_exp_tests
from tensorflow.lite.testing.op_tests.expand_dims import make_expand_dims_tests
from tensorflow.lite.testing.op_tests.expm1 import make_expm1_tests
from tensorflow.lite.testing.op_tests.eye import make_eye_tests
from tensorflow.lite.testing.op_tests.fill import make_fill_tests, make_fill_16_tests
from tensorflow.lite.testing.op_tests.floor import make_floor_tests
from tensorflow.lite.testing.op_tests.fully_connected import make_fully_connected_tests
from tensorflow.lite.testing.op_tests.fully_connected_4bit_hybrid import make_fully_connected_4bit_hybrid_tests
from tensorflow.lite.testing.op_tests.fused_batch_norm import make_fused_batch_norm_tests
from tensorflow.lite.testing.op_tests.gather import make_gather_tests
from tensorflow.lite.testing.op_tests.gather_nd import make_gather_nd_tests
from tensorflow.lite.testing.op_tests.gather_with_constant import make_gather_with_constant_tests
from tensorflow.lite.testing.op_tests.gelu import make_gelu_tests
from tensorflow.lite.testing.op_tests.global_batch_norm import make_global_batch_norm_tests
from tensorflow.lite.testing.op_tests.greater import make_greater_tests
from tensorflow.lite.testing.op_tests.greater_equal import make_greater_equal_tests
from tensorflow.lite.testing.op_tests.hardswish import make_hardswish_tests
from tensorflow.lite.testing.op_tests.identify_dilated_conv import make_identify_dilated_conv_tests
from tensorflow.lite.testing.op_tests.identify_dilated_conv1d import make_identify_dilated_conv1d_tests
from tensorflow.lite.testing.op_tests.identity import make_identity_tests
from tensorflow.lite.testing.op_tests.imag import make_imag_tests
from tensorflow.lite.testing.op_tests.irfft2d import make_irfft2d_tests
from tensorflow.lite.testing.op_tests.is_finite import make_is_finite_tests
from tensorflow.lite.testing.op_tests.l2norm import make_l2norm_tests
# Note: This is a regression test for a bug (b/122651451) that Toco incorrectly
# erases the reduction indices array while it's shared with other ops.
from tensorflow.lite.testing.op_tests.l2norm_shared_epsilon import make_l2norm_shared_epsilon_tests
from tensorflow.lite.testing.op_tests.leaky_relu import make_leaky_relu_tests
from tensorflow.lite.testing.op_tests.less import make_less_tests
from tensorflow.lite.testing.op_tests.less_equal import make_less_equal_tests
from tensorflow.lite.testing.op_tests.local_response_norm import make_local_response_norm_tests
from tensorflow.lite.testing.op_tests.log_softmax import make_log_softmax_tests
from tensorflow.lite.testing.op_tests.logic import make_logical_or_tests, make_logical_and_tests, make_logical_xor_tests
from tensorflow.lite.testing.op_tests.lstm import make_lstm_tests
from tensorflow.lite.testing.op_tests.matrix_band_part import make_matrix_band_part_tests
from tensorflow.lite.testing.op_tests.matrix_diag import make_matrix_diag_tests
from tensorflow.lite.testing.op_tests.matrix_set_diag import make_matrix_set_diag_tests
from tensorflow.lite.testing.op_tests.max_pool_with_argmax import make_max_pool_with_argmax_tests
from tensorflow.lite.testing.op_tests.maximum import make_maximum_tests
from tensorflow.lite.testing.op_tests.minimum import make_minimum_tests
from tensorflow.lite.testing.op_tests.mirror_pad import make_mirror_pad_tests
from tensorflow.lite.testing.op_tests.multinomial import make_multinomial_tests
from tensorflow.lite.testing.op_tests.nearest_upsample import make_nearest_upsample_tests
from tensorflow.lite.testing.op_tests.neg import make_neg_tests
from tensorflow.lite.testing.op_tests.not_equal import make_not_equal_tests
from tensorflow.lite.testing.op_tests.one_hot import make_one_hot_tests
from tensorflow.lite.testing.op_tests.pack import make_pack_tests
from tensorflow.lite.testing.op_tests.pad import make_pad_tests
from tensorflow.lite.testing.op_tests.padv2 import make_padv2_tests
from tensorflow.lite.testing.op_tests.parse_example import make_parse_example_tests
from tensorflow.lite.testing.op_tests.placeholder_with_default import make_placeholder_with_default_tests
from tensorflow.lite.testing.op_tests.pool import make_l2_pool_tests, make_avg_pool_tests, make_max_pool_tests
from tensorflow.lite.testing.op_tests.pool3d import make_avg_pool3d_tests
from tensorflow.lite.testing.op_tests.pool3d import make_max_pool3d_tests
from tensorflow.lite.testing.op_tests.prelu import make_prelu_tests
from tensorflow.lite.testing.op_tests.random_standard_normal import make_random_standard_normal_tests
from tensorflow.lite.testing.op_tests.random_uniform import make_random_uniform_tests
from tensorflow.lite.testing.op_tests.range import make_range_tests
from tensorflow.lite.testing.op_tests.rank import make_rank_tests
from tensorflow.lite.testing.op_tests.real import make_real_tests
from tensorflow.lite.testing.op_tests.reciprocal import make_reciprocal_tests
from tensorflow.lite.testing.op_tests.reduce import make_mean_tests, make_sum_tests, make_reduce_prod_tests, make_reduce_max_tests, make_reduce_min_tests, make_reduce_any_tests, make_reduce_all_tests
from tensorflow.lite.testing.op_tests.relu import make_relu_tests
from tensorflow.lite.testing.op_tests.relu1 import make_relu1_tests
from tensorflow.lite.testing.op_tests.relu6 import make_relu6_tests
from tensorflow.lite.testing.op_tests.reshape import make_reshape_tests
from tensorflow.lite.testing.op_tests.resize_bilinear import make_resize_bilinear_tests
from tensorflow.lite.testing.op_tests.resize_nearest_neighbor import make_resize_nearest_neighbor_tests
# For verifying https://github.com/tensorflow/tensorflow/issues/23599
from tensorflow.lite.testing.op_tests.resolve_constant_strided_slice import make_resolve_constant_strided_slice_tests
from tensorflow.lite.testing.op_tests.reverse_sequence import make_reverse_sequence_tests
from tensorflow.lite.testing.op_tests.reverse_v2 import make_reverse_v2_tests
from tensorflow.lite.testing.op_tests.rfft import make_rfft_tests
from tensorflow.lite.testing.op_tests.rfft2d import make_rfft2d_tests
from tensorflow.lite.testing.op_tests.right_shift import make_right_shift_tests
from tensorflow.lite.testing.op_tests.roll import make_roll_tests
from tensorflow.lite.testing.op_tests.roll import make_roll_with_constant_tests
from tensorflow.lite.testing.op_tests.round import make_round_tests
from tensorflow.lite.testing.op_tests.scatter_nd import make_scatter_nd_tests
from tensorflow.lite.testing.op_tests.segment_sum import make_segment_sum_tests
from tensorflow.lite.testing.op_tests.shape import make_shape_tests
from tensorflow.lite.testing.op_tests.shape_to_strided_slice import make_shape_to_strided_slice_tests
from tensorflow.lite.testing.op_tests.sigmoid import make_sigmoid_tests
from tensorflow.lite.testing.op_tests.sigmoid_grad import make_sigmoid_grad_tests
from tensorflow.lite.testing.op_tests.sign import make_sign_tests
from tensorflow.lite.testing.op_tests.slice import make_slice_tests
from tensorflow.lite.testing.op_tests.softmax import make_softmax_tests
from tensorflow.lite.testing.op_tests.softplus import make_softplus_tests
from tensorflow.lite.testing.op_tests.softsign import make_softsign_tests
from tensorflow.lite.testing.op_tests.space_to_batch_nd import make_space_to_batch_nd_tests
from tensorflow.lite.testing.op_tests.space_to_depth import make_space_to_depth_tests
from tensorflow.lite.testing.op_tests.sparse_to_dense import make_sparse_to_dense_tests
from tensorflow.lite.testing.op_tests.split import make_split_tests
from tensorflow.lite.testing.op_tests.splitv import make_splitv_tests
from tensorflow.lite.testing.op_tests.squeeze import make_squeeze_tests
from tensorflow.lite.testing.op_tests.squeeze_transpose import make_squeeze_transpose_tests
from tensorflow.lite.testing.op_tests.static_hashtable import make_static_hashtable_tests
from tensorflow.lite.testing.op_tests.static_rnn_with_control_flow_v2 import make_static_rnn_with_control_flow_v2_tests
from tensorflow.lite.testing.op_tests.stft import make_stft_tests
from tensorflow.lite.testing.op_tests.strided_slice import make_strided_slice_tests, make_strided_slice_1d_exhaustive_tests
from tensorflow.lite.testing.op_tests.strided_slice_np_style import make_strided_slice_np_style_tests
from tensorflow.lite.testing.op_tests.tanh import make_tanh_tests
from tensorflow.lite.testing.op_tests.tensor_list_concat import make_tensor_list_concat_tests
from tensorflow.lite.testing.op_tests.tensor_list_dynamic_shape import make_tensor_list_dynamic_shape_tests
from tensorflow.lite.testing.op_tests.tensor_list_get_item import make_tensor_list_get_item_tests
from tensorflow.lite.testing.op_tests.tensor_list_length import make_tensor_list_length_tests
from tensorflow.lite.testing.op_tests.tensor_list_resize import make_tensor_list_resize_tests
from tensorflow.lite.testing.op_tests.tensor_list_set_item import make_tensor_list_set_item_tests
from tensorflow.lite.testing.op_tests.tensor_scatter_add import make_tensor_scatter_add_tests
from tensorflow.lite.testing.op_tests.tensor_scatter_update import make_tensor_scatter_update_tests
from tensorflow.lite.testing.op_tests.tile import make_tile_tests
from tensorflow.lite.testing.op_tests.topk import make_topk_tests
from tensorflow.lite.testing.op_tests.transpose import make_transpose_tests
from tensorflow.lite.testing.op_tests.transpose_conv import make_transpose_conv_tests
from tensorflow.lite.testing.op_tests.unfused_gru import make_unfused_gru_tests
from tensorflow.lite.testing.op_tests.unique import make_unique_tests
from tensorflow.lite.testing.op_tests.unpack import make_unpack_tests
from tensorflow.lite.testing.op_tests.unroll_batch_matmul import make_unroll_batch_matmul_tests
from tensorflow.lite.testing.op_tests.unsorted_segment import make_unsorted_segment_max_tests, make_unsorted_segment_min_tests, make_unsorted_segment_prod_tests, make_unsorted_segment_sum_tests
from tensorflow.lite.testing.op_tests.where import make_where_tests
from tensorflow.lite.testing.op_tests.where_v2 import make_where_v2_tests
from tensorflow.lite.testing.op_tests.while_loop import make_while_tests
from tensorflow.lite.testing.op_tests.zeros_like import make_zeros_like_tests
from tensorflow.lite.testing.zip_test_utils import get_test_function
class MultiGenState:
"""State of multiple set generation process.
This state class stores the information needed when generating the examples
for multiple test set. The stored informations are open archive object to be
shared, information on test target for current iteration of generation,
accumulated generation results.
"""
def __init__(self):
# Open archive.
self.archive = None
# Test name for current generation.
self.test_name = None
# Label base path containing the test name.
# Each of the test data path in the zip archive is derived from this path.
# If this path is "a/b/c/d.zip", an example of generated test data path
# is "a/b/c/d_input_type=tf.float32,input_shape=[2,2].inputs".
# The test runner interpretes the test name of this path as "d".
# Label base path also should finish with ".zip".
self.label_base_path = None
# Zip manifests.
self.zip_manifest = []
# Number of all parameters accumulated.
self.parameter_count = 0
class Options:
"""All options for example generation."""
def __init__(self):
# Directory where the outputs will be go.
self.output_path = None
# Particular zip to output.
self.zip_to_output = None
# If a particular model is affected by a known bug count it as a converter
# error.
self.known_bugs_are_errors = False
# Raise an exception if any converter error is encountered.
self.ignore_converter_errors = False
# Include intermediate graphdefs in the output zip files.
self.save_graphdefs = False
# Whether the TFLite Flex converter is being used.
self.run_with_flex = False
# Whether to generate test cases for edgetpu.
self.make_edgetpu_tests = False
# Whether to generate test cases for TF PTQ.
self.make_tf_ptq_tests = False
# For TF Quantization only: where conversion for HLO target.
self.hlo_aware_conversion = True
# The function to convert a TensorFLow model to TFLite model.
# See the document for `mlir_convert` function for its required signature.
self.tflite_convert_function = None
# A map from regular expression to bug number. Any test failure with label
# matching the expression will be considered due to the corresponding bug.
self.known_bugs = {}
# Make tests by setting TF forward compatibility horizon to the future.
self.make_forward_compat_test = False
# No limitation on the number of tests.
self.no_tests_limit = False
# Do not create conversion report.
self.no_conversion_report = False
# State of multiple test set generation. This stores state values those
# should be kept and updated while generating examples over multiple
# test sets.
# TODO(juhoha): Separate the state from the options.
self.multi_gen_state = None
self.mlir_quantizer = False
# The list of ops' name that should exist in the converted model.
# This feature is currently only supported in MLIR conversion path.
# Example of supported ops' name:
# - "AVERAGE_POOL_2D" for builtin op.
# - "NumericVerify" for custom op.
self.expected_ops_in_converted_model = []
# Whether to skip generating tests with high dimension input shape.
self.skip_high_dimension_inputs = False
# Whether to enable DynamicUpdateSlice op.
self.enable_dynamic_update_slice = False
# Whether to unrolling batch matmul.
self.unfold_batchmatmul = False
# Experimental low bit options
self.experimental_low_bit_qat = False
# Whether to enable experimental unsafe single batch rank reduction.
self.experimental_unsafe_single_batch_rank_reduction = False
def _prepare_dir(options):
def mkdir_if_not_exist(x):
if not os.path.isdir(x):
os.mkdir(x)
if not os.path.isdir(x):
raise RuntimeError("Failed to create dir %r" % x)
opstest_path = os.path.join(options.output_path)
mkdir_if_not_exist(opstest_path)
def generate_examples(options):
"""Generate examples for a test set.
Args:
options: Options containing information to generate examples.
Raises:
RuntimeError: if the test function cannot be found.
"""
_prepare_dir(options)
out = options.zip_to_output
# Some zip filenames contain a postfix identifying the conversion mode. The
# list of valid conversion modes is defined in
# generated_test_conversion_modes() in build_def.bzl.
if options.multi_gen_state:
test_name = options.multi_gen_state.test_name
else:
# Remove suffixes to extract the test name from the output name.
test_name = re.sub(
r"(_(|with-flex|forward-compat|edgetpu|mlir-quant))?(_xnnpack)?\.zip$",
"",
out,
count=1)
test_function_name = "make_%s_tests" % test_name
test_function = get_test_function(test_function_name)
if test_function is None:
raise RuntimeError("Can't find a test function to create %r. Tried %r" %
(out, test_function_name))
if options.make_forward_compat_test:
future_date = datetime.date.today() + datetime.timedelta(days=30)
with tf.compat.forward_compatibility_horizon(future_date.year,
future_date.month,
future_date.day):
test_function(options)
else:
test_function(options)
def generate_multi_set_examples(options, test_sets):
"""Generate examples for test sets.
Args:
options: Options containing information to generate examples.
test_sets: List of the name of test sets to generate examples.
"""
_prepare_dir(options)
multi_gen_state = MultiGenState()
options.multi_gen_state = multi_gen_state
zip_path = os.path.join(options.output_path, options.zip_to_output)
with zipfile.PyZipFile(zip_path, "w") as archive:
multi_gen_state.archive = archive
for test_name in test_sets:
# Some generation function can change the value of the options object.
# To keep the original options for each run, we use shallow copy.
new_options = copy.copy(options)
# Remove suffix and set test_name to run proper test generation function.
multi_gen_state.test_name = re.sub(
r"(_(|with-flex|forward-compat|mlir-quant))?$",
"",
test_name,
count=1)
# Set label base path to write test data files with proper path.
multi_gen_state.label_base_path = os.path.join(
os.path.dirname(zip_path), test_name + ".zip")
generate_examples(new_options)
zipinfo = zipfile.ZipInfo("manifest.txt")
archive.writestr(zipinfo, "".join(multi_gen_state.zip_manifest),
zipfile.ZIP_DEFLATED)
@@ -0,0 +1,133 @@
# Copyright 2017 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.
# ==============================================================================
"""Make HTML tables that report where TF and TFLite failed to convert models.
This is primarily used by generate_examples.py. See it or
`make_report_table` for more details on usage.
"""
import html
import json
import re
FAILED = "FAILED"
SUCCESS = "SUCCESS"
NOTRUN = "NOTRUN"
def make_report_table(fp, title, reports):
"""Make an HTML report of the success/failure reports.
Args:
fp: File-like object in which to put the html.
title: "Title of the zip file this pertains to."
reports: a list of conversion attempts. (report_args, report_vals) i.e.
({"shape": [1,2,3], "type": "tf.float32"},
{"tf": "SUCCESS", "tflite_converter": "FAILURE",
"tf_log": "", "tflite_converter_log": "Unsupported type."})
"""
# sort reports by if TFLite converter failure and then TF failure (reversed)
reports.sort(key=lambda x: x[1]["tflite_converter"], reverse=False)
reports.sort(key=lambda x: x[1]["tf"], reverse=True)
def result_cell(x, row, col):
"""Produce a cell with the condition string `x`."""
s = html.escape(repr(x), quote=True)
color = "#44ff44" if x == SUCCESS else (
"#ff4444" if x == FAILED else "#eeeeee")
handler = "ShowLog(%d, %d)" % (row, col)
fp.write("<td style='background-color: %s' onclick='%s'>%s</td>\n" % (
color, handler, s))
fp.write("""<html>
<head>
<title>tflite report</title>
<style>
body { font-family: Arial; }
th { background-color: #555555; color: #eeeeee; }
td { vertical-align: top; }
td.horiz {width: 50%;}
pre { white-space: pre-wrap; word-break: keep-all; }
table {width: 100%;}
</style>
</head>
""")
# Write the log data to a javascript variable and also make a function
# in javascript to show the log when an item is clicked.
fp.write("<script> \n")
fp.write("""
function ShowLog(row, col) {
var log = document.getElementById("log");
log.innerHTML = "<pre>" + data[row][col] + "</pre>";
}
""")
fp.write("var data = \n")
logs = json.dumps([[escape_and_normalize(x[1]["tf_log"]),
escape_and_normalize(x[1]["tflite_converter_log"])
] for x in reports])
fp.write(logs)
fp.write(";</script>\n")
# Write the main table and use onclick on the items that have log items.
fp.write("""
<body>
<h1>TensorFlow Lite Conversion</h1>
<h2>%s</h2>
""" % title)
# Get a list of keys that are in any of the records.
param_keys = {}
for params, _ in reports:
for k in params.keys():
param_keys[k] = True
fp.write("<table>\n")
fp.write("<tr><td class='horiz'>\n")
fp.write("<div style='height:1000px; overflow:auto'>\n")
fp.write("<table>\n")
fp.write("<tr>\n")
for p in param_keys:
fp.write("<th>%s</th>\n" % html.escape(p, quote=True))
fp.write("<th>TensorFlow</th>\n")
fp.write("<th>TensorFlow Lite Converter</th>\n")
fp.write("</tr>\n")
for idx, (params, vals) in enumerate(reports):
fp.write("<tr>\n")
for p in param_keys:
fp.write(" <td>%s</td>\n" %
html.escape(repr(params.get(p, None)), quote=True))
result_cell(vals["tf"], idx, 0)
result_cell(vals["tflite_converter"], idx, 1)
fp.write("</tr>\n")
fp.write("</table>\n")
fp.write("</div>\n")
fp.write("</td>\n")
fp.write("<td class='horiz' id='log'></td></tr>\n")
fp.write("</table>\n")
fp.write("<script>\n")
fp.write("</script>\n")
fp.write("""
</body>
</html>
""")
def escape_and_normalize(log):
# These logs contain paths like /tmp/tmpgmypg3xa that are inconsistent between
# builds. This replaces these inconsistent paths with a consistent placeholder
# so the output is deterministic.
log = re.sub(r"/tmp/[^ ]+ ", "/NORMALIZED_TMP_FILE_PATH ", log)
log = re.sub(r"/build/work/[^/]+", "/NORMALIZED_BUILD_PATH", log)
return html.escape(log, quote=True)
@@ -0,0 +1,223 @@
/* Copyright 2017 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/testing/generate_testspec.h"
#include <cstdint>
#include <cstdio>
#include <iostream>
#include <random>
#include <utility>
#include <vector>
#include "absl/log/check.h"
#include "tensorflow/core/framework/types.h"
#include "tensorflow/core/framework/types.pb.h"
#include "tensorflow/lite/string_type.h"
#include "tensorflow/lite/testing/join.h"
#include "tensorflow/lite/testing/split.h"
#include "tensorflow/lite/testing/test_runner.h"
#include "tensorflow/lite/testing/tf_driver.h"
#include "tensorflow/lite/testing/tflite_driver.h"
namespace tflite {
namespace testing {
namespace {
// Generates input name / value pairs according to given shape and distribution.
// Fills `out` with a pair of string, which the first element is input name and
// the second element is comma separated values in string.
template <typename T, typename RandomEngine, typename RandomDistribution>
void GenerateCsv(const string& name, const std::vector<int>& shape,
RandomEngine* engine, RandomDistribution distribution,
std::pair<string, string>* out) {
std::vector<T> data =
GenerateRandomTensor<T>(shape, [&]() { return distribution(*engine); });
*out = std::make_pair(name, Join(data.data(), data.size(), ","));
}
// Generates random values for `input_layer` according to given value types and
// shapes.
// Fills `out` with a vector of string pairs, which the first element in the
// pair is the input name from `input_layer` and the second element is comma
// separated values in string.
template <typename RandomEngine>
std::vector<std::pair<string, string>> GenerateInputValues(
RandomEngine* engine, const std::vector<string>& input_layer,
const std::vector<string>& input_layer_type,
const std::vector<string>& input_layer_shape) {
std::vector<std::pair<string, string>> input_values;
input_values.resize(input_layer.size());
for (int i = 0; i < input_layer.size(); i++) {
tensorflow::DataType type;
CHECK(DataTypeFromString(input_layer_type[i], &type));
auto shape = Split<int>(input_layer_shape[i], ",");
const auto& name = input_layer[i];
switch (type) {
case tensorflow::DT_FLOAT:
GenerateCsv<float>(name, shape, engine,
std::uniform_real_distribution<float>(-0.5, 0.5),
&input_values[i]);
break;
case tensorflow::DT_UINT8:
GenerateCsv<uint8_t>(name, shape, engine,
std::uniform_int_distribution<uint32_t>(0, 255),
&input_values[i]);
break;
case tensorflow::DT_INT32:
GenerateCsv<int32_t>(name, shape, engine,
std::uniform_int_distribution<int32_t>(-100, 100),
&input_values[i]);
break;
case tensorflow::DT_INT64:
GenerateCsv<int64_t>(name, shape, engine,
std::uniform_int_distribution<int64_t>(-100, 100),
&input_values[i]);
break;
case tensorflow::DT_BOOL:
GenerateCsv<int>(name, shape, engine,
std::uniform_int_distribution<int>(0, 1),
&input_values[i]);
break;
default:
fprintf(stderr, "Unsupported type %d (%s) when generating testspec.\n",
type, input_layer_type[i].c_str());
input_values.clear();
return input_values;
}
}
return input_values;
}
bool GenerateTestSpecFromRunner(std::iostream& stream, int num_invocations,
const std::vector<string>& input_layer,
const std::vector<string>& input_layer_type,
const std::vector<string>& input_layer_shape,
const std::vector<string>& output_layer,
TestRunner* runner) {
auto input_size = input_layer.size();
if (input_layer_shape.size() != input_size ||
input_layer_type.size() != input_size) {
fprintf(stderr,
"Input size not match. Expected %lu, got %lu input types, %lu "
"input shapes.\n",
input_size, input_layer_type.size(), input_layer_shape.size());
return false;
}
stream << "reshape {\n";
for (int i = 0; i < input_size; i++) {
const auto& name = input_layer[i];
const auto& shape = input_layer_shape[i];
stream << " input { key: \"" << name << "\" value: \"" << shape
<< "\" }\n";
}
stream << "}\n";
// Generate inputs.
std::mt19937 random_engine;
for (int i = 0; i < num_invocations; ++i) {
// Note that the input values are random, so each invocation will have a
// different set.
auto input_values = GenerateInputValues(
&random_engine, input_layer, input_layer_type, input_layer_shape);
if (input_values.empty()) {
std::cerr << "Unable to generate input values for the TensorFlow model. "
"Make sure the correct values are defined for "
"input_layer, input_layer_type, and input_layer_shape."
<< std::endl;
return false;
}
// Run TensorFlow.
runner->Invoke(input_values);
if (!runner->IsValid()) {
std::cerr << runner->GetErrorMessage() << std::endl;
return false;
}
// Write second part of test spec, with inputs and outputs.
stream << "invoke {\n";
for (const auto& entry : input_values) {
stream << " input { key: \"" << entry.first << "\" value: \""
<< entry.second << "\" }\n";
}
for (const auto& name : output_layer) {
stream << " output { key: \"" << name << "\" value: \""
<< runner->ReadOutput(name) << "\" }\n";
if (!runner->IsValid()) {
std::cerr << runner->GetErrorMessage() << std::endl;
return false;
}
}
stream << "}\n";
}
return true;
}
} // namespace
bool GenerateTestSpecFromTensorflowModel(
std::iostream& stream, const string& tensorflow_model_path,
const string& tflite_model_path, int num_invocations,
const std::vector<string>& input_layer,
const std::vector<string>& input_layer_type,
const std::vector<string>& input_layer_shape,
const std::vector<string>& output_layer) {
CHECK_EQ(input_layer.size(), input_layer_type.size());
CHECK_EQ(input_layer.size(), input_layer_shape.size());
// Invoke tensorflow model.
TfDriver runner(input_layer, input_layer_type, input_layer_shape,
output_layer);
if (!runner.IsValid()) {
std::cerr << runner.GetErrorMessage() << std::endl;
return false;
}
runner.LoadModel(tensorflow_model_path);
if (!runner.IsValid()) {
std::cerr << runner.GetErrorMessage() << std::endl;
return false;
}
// Write first part of test spec, defining model and input shapes.
stream << "load_model: " << tflite_model_path << "\n";
return GenerateTestSpecFromRunner(stream, num_invocations, input_layer,
input_layer_type, input_layer_shape,
output_layer, &runner);
}
bool GenerateTestSpecFromTFLiteModel(
std::iostream& stream, const string& tflite_model_path, int num_invocations,
const std::vector<string>& input_layer,
const std::vector<string>& input_layer_type,
const std::vector<string>& input_layer_shape,
const std::vector<string>& output_layer) {
TfLiteDriver runner;
runner.LoadModel(tflite_model_path);
if (!runner.IsValid()) {
std::cerr << runner.GetErrorMessage() << std::endl;
return false;
}
runner.AllocateTensors();
return GenerateTestSpecFromRunner(stream, num_invocations, input_layer,
input_layer_type, input_layer_shape,
output_layer, &runner);
}
} // namespace testing
} // namespace tflite
@@ -0,0 +1,74 @@
/* Copyright 2017 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_TESTING_GENERATE_TESTSPEC_H_
#define TENSORFLOW_LITE_TESTING_GENERATE_TESTSPEC_H_
#include <algorithm>
#include <functional>
#include <iostream>
#include <vector>
#include "tensorflow/lite/string_type.h"
namespace tflite {
namespace testing {
// Generate test spec by executing TensorFlow model on random inputs.
// The test spec can be consumed by ParseAndRunTests.
// See test spec format in parse_testdata.h
//
// Inputs:
// stream: mutable iostream that contains the contents of test spec.
// tensorflow_model_path: path to TensorFlow model.
// tflite_model_path: path to tflite_model_path that the test spec runs
// num_invocations: how many pairs of inputs and outputs will be generated.
// against. input_layer: names of input tensors. Example: input1
// input_layer_type: datatypes of input tensors. Example: float
// input_layer_shape: shapes of input tensors, separated by comma. example:
// 1,3,4 output_layer: names of output tensors. Example: output
bool GenerateTestSpecFromTensorflowModel(
std::iostream& stream, const string& tensorflow_model_path,
const string& tflite_model_path, int num_invocations,
const std::vector<string>& input_layer,
const std::vector<string>& input_layer_type,
const std::vector<string>& input_layer_shape,
const std::vector<string>& output_layer);
// Generate test spec by executing TFLite model on random inputs.
bool GenerateTestSpecFromTFLiteModel(
std::iostream& stream, const string& tflite_model_path, int num_invocations,
const std::vector<string>& input_layer,
const std::vector<string>& input_layer_type,
const std::vector<string>& input_layer_shape,
const std::vector<string>& output_layer);
// Generates random values that are filled into the tensor.
template <typename T, typename RandomFunction>
std::vector<T> GenerateRandomTensor(const std::vector<int>& shape,
RandomFunction random_func) {
int64_t num_elements = 1;
for (const int dim : shape) {
num_elements *= dim;
}
std::vector<T> result(num_elements);
std::generate_n(result.data(), num_elements, random_func);
return result;
}
} // namespace testing
} // namespace tflite
#endif // TENSORFLOW_LITE_TESTING_GENERATE_TESTSPEC_H_
@@ -0,0 +1,56 @@
/* Copyright 2017 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/testing/generate_testspec.h"
#include <random>
#include <set>
#include <gtest/gtest.h>
namespace tflite {
namespace testing {
namespace {
TEST(GenerateRandomTensor, FloatValue) {
std::mt19937 random_engine;
auto random_func = [&]() {
return std::uniform_real_distribution<float>(-0.5, 0.5)(random_engine);
};
std::set<float> values;
float sum_x_square = 0.0f;
float sum_x = 0.0f;
for (int i = 0; i < 100; i++) {
const auto& data = GenerateRandomTensor<float>({1, 3, 4}, random_func);
for (float value : data) {
values.insert(value);
sum_x_square += value * value;
sum_x += value;
}
}
// Eech round, generated tensor has different values.
EXPECT_GT(values.size(), 200);
int num = 1 * 3 * 4 * 100;
float stddev = sum_x_square / num - (sum_x / num) * (sum_x / num);
// Stddev is greater than 1/2 stddev of uniform distribution: (B-A)^2 / 12
float minstddev = 1.0f / 12 / 2;
EXPECT_GT(stddev, minstddev);
}
} // namespace
} // namespace testing
} // namespace tflite
@@ -0,0 +1,396 @@
/* Copyright 2017 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 <cctype>
#include <cstdint>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <fstream>
#include <iterator>
#include <map>
#include <tuple>
#include <utility>
#include <vector>
#include <gtest/gtest.h>
#include "absl/status/status.h"
#include "absl/strings/match.h"
#include "re2/re2.h"
#include "xla/tsl/platform/subprocess.h"
#include "xla/tsl/util/command_line_flags.h"
#include "tensorflow/lite/string_type.h"
#include "tensorflow/lite/testing/parse_testdata.h"
#include "tensorflow/lite/testing/tflite_driver.h"
#include "tensorflow/lite/testing/util.h"
#include "tsl/platform/env.h"
#include "tsl/platform/status.h"
namespace tflite {
namespace testing {
namespace {
bool FLAGS_ignore_known_bugs = true;
// As archive file names are test-specific, no default is possible.
//
// This test supports input as both zip and tar, as a stock android image does
// not have unzip but does have tar.
string* FLAGS_zip_file_path = new string;
string* FLAGS_tar_file_path = new string;
#ifndef __ANDROID__
string* FLAGS_unzip_binary_path = new string("/usr/bin/unzip");
string* FLAGS_tar_binary_path = new string("/bin/tar");
#else
string* FLAGS_unzip_binary_path = new string("/system/bin/unzip");
string* FLAGS_tar_binary_path = new string("/system/bin/tar");
#endif
bool FLAGS_use_nnapi = false;
bool FLAGS_ignore_unsupported_nnapi = false;
} // namespace
// TensorFlow system environment for file system called.
tsl::Env* env = tsl::Env::Default();
// Already known broken tests.
// Key is a substring of the test name and value is pair of a bug number and
// whether this test should be always ignored regardless of `ignore_known_bugs`.
// if `always_ignore` is false, tests are expected to fail when
// --test_arg=--ignore_known_bugs=false
using BrokenTestMap =
std::map</* test_name */ string,
std::pair</* bug_number */ string, /* always_ignore */ bool>>;
// TODO(ahentz): make sure we clean this list up frequently.
const BrokenTestMap& GetKnownBrokenTests() {
static const BrokenTestMap* const kBrokenTests = new BrokenTestMap(
{// TODO(b/194364155): TF and TFLite have different behaviors when output
// nan values in LocalResponseNorm ops.
{R"(^\/local_response_norm.*alpha=-3.*beta=2)", {"194364155", true}},
{R"(^\/local_response_norm.*alpha=(None|2).*beta=2.*bias=-0\.1.*depth_radius=(0|1).*input_shape=\[3,15,14,3\])",
{"194364155", true}},
{R"(^\/static_rnn_with_control_flow_v2.*use_sequence_length=True)",
{"380064373", true}}});
return *kBrokenTests;
}
// Additional list of tests that are expected to fail when
// --test_arg=--ignore_known_bugs=false
// and
// --test_arg=--use_nnapi=true
// Note that issues related to lack of NNAPI support for a particular op are
// handled separately; this list is specifically for broken cases where
// execution produces broken output.
// Key is a substring of the test name and value is a bug number.
const std::map<string, string>& GetKnownBrokenNnapiTests() {
static const std::map<string, string>* const kBrokenNnapiTests =
new std::map<string, string>({
// Certain NNAPI kernels silently fail with int32 types.
{R"(^\/add.*dtype=tf\.int32)", "122987564"},
{R"(^\/concat.*dtype=tf\.int32)", "122987564"},
{R"(^\/mul.*dtype=tf\.int32)", "122987564"},
{R"(^\/space_to_depth.*dtype=tf\.int32)", "122987564"},
// Certain NNAPI fully_connected shape permutations fail.
{R"(^\/fully_connected_constant_filter=True.*shape1=\[3,3\])",
"122987564"},
{R"(^\/fully_connected_constant_filter=True.*shape1=\[4,4\])",
"122987564"},
{R"(^\/fully_connected.*shape1=\[3,3\].*transpose_b=True)",
"122987564"},
{R"(^\/fully_connected.*shape1=\[4,4\].*shape2=\[4,1\])",
"122987564"},
});
return *kBrokenNnapiTests;
}
// List of quantize tests that are probably to fail.
// Quantized tflite models has high diff error with tensorflow models.
// Key is a substring of the test name and value is a bug number.
// TODO(b/134594898): Remove these bugs and corresponding codes or move them to
// kBrokenTests after b/134594898 is fixed.
const std::map<string, string>& GetKnownQuantizeBrokenTests() {
static const std::map<string, string>* const kQuantizeBrokenTests =
new std::map<string, string>({
{R"(^\/conv.*fully_quantize=True)", "134594898"},
{R"(^\/depthwiseconv.*fully_quantize=True)", "134594898"},
{R"(^\/sum.*fully_quantize=True)", "134594898"},
{R"(^\/l2norm.*fully_quantize=True)", "134594898"},
{R"(^\/prelu.*fully_quantize=True)", "156112683"},
});
return *kQuantizeBrokenTests;
}
// Allows test data to be unarchived into a temporary directory and makes
// sure those temporary directories are removed later.
class ArchiveEnvironment : public ::testing::Environment {
public:
~ArchiveEnvironment() override {}
// Delete all temporary directories on teardown.
void TearDown() override {
for (const auto& dir : temporary_directories_) {
int64_t undeleted_dirs, undeleted_files;
TF_CHECK_OK(
env->DeleteRecursively(dir, &undeleted_dirs, &undeleted_files));
}
temporary_directories_.clear();
}
// Unarchive `archive` file into a new temporary directory `out_dir`.
absl::Status UnArchive(const string& zip, const string& tar,
string* out_dir) {
string dir;
TF_CHECK_OK(MakeTemporaryDirectory(&dir));
tsl::SubProcess proc;
if (!zip.empty()) {
string unzip_binary = *FLAGS_unzip_binary_path;
TF_CHECK_OK(env->FileExists(unzip_binary));
TF_CHECK_OK(env->FileExists(zip));
proc.SetProgram(unzip_binary, {"unzip", "-d", dir, zip});
} else {
string tar_binary = *FLAGS_tar_binary_path;
TF_CHECK_OK(env->FileExists(tar_binary));
TF_CHECK_OK(env->FileExists(tar));
// 'o' needs to be explicitly set on Android so that
// untarring works as non-root (otherwise tries to chown
// files, which fails)
proc.SetProgram(tar_binary, {"tar", "xfo", tar, "-C", dir});
}
proc.SetChannelAction(tsl::CHAN_STDOUT, tsl::ACTION_PIPE);
proc.SetChannelAction(tsl::CHAN_STDERR, tsl::ACTION_PIPE);
if (!proc.Start())
return absl::Status(absl::StatusCode::kUnknown, "unzip couldn't start");
string out, err;
int status = proc.Communicate(nullptr, &out, &err);
if (WEXITSTATUS(status) == 0) {
*out_dir = dir;
return absl::OkStatus();
} else {
return absl::Status(absl::StatusCode::kUnknown,
"unzip failed. "
"stdout:\n" +
out + "\nstderr:\n" + err);
}
}
private:
// Make a temporary directory and return its name in `temporary`.
absl::Status MakeTemporaryDirectory(string* temporary) {
if (env->LocalTempFilename(temporary)) {
TF_CHECK_OK(env->CreateDir(*temporary));
temporary_directories_.push_back(*temporary);
return absl::OkStatus();
}
return absl::Status(absl::StatusCode::kUnknown,
"make temporary directory failed");
}
std::vector<string> temporary_directories_;
};
// Return the singleton archive_environment.
ArchiveEnvironment* archive_environment() {
static ArchiveEnvironment* env = new ArchiveEnvironment;
return env;
}
// Read the manifest.txt out of the unarchived archive file. Specifically
// `original_file` is the original zip file for error messages. `dir` is
// the temporary directory where the archive file has been unarchived and
// `test_paths` is the list of test prefixes that were in the manifest.
// Note, it is an error for a manifest to contain no tests.
absl::Status ReadManifest(const string& original_file, const string& dir,
std::vector<string>* test_paths) {
// Read the newline delimited list of entries in the manifest.
std::ifstream manifest_fp(dir + "/manifest.txt");
string manifest((std::istreambuf_iterator<char>(manifest_fp)),
std::istreambuf_iterator<char>());
size_t pos = 0;
int added = 0;
while (true) {
size_t end_pos = manifest.find('\n', pos);
if (end_pos == string::npos) break;
string filename = manifest.substr(pos, end_pos - pos);
test_paths->push_back(dir + "/" + filename);
pos = end_pos + 1;
added += 1;
}
if (!added) {
string message = "Test had no examples: " + original_file;
return absl::Status(absl::StatusCode::kUnknown, message);
}
return absl::OkStatus();
}
// Get a list of tests from either zip or tar file
std::vector<string> UnarchiveAndFindTestNames(const string& zip_file,
const string& tar_file) {
if (zip_file.empty() && tar_file.empty()) {
TF_CHECK_OK(absl::Status(absl::StatusCode::kUnknown,
"Neither zip_file nor tar_file was given"));
}
string decompress_tmp_dir;
TF_CHECK_OK(archive_environment()->UnArchive(zip_file, tar_file,
&decompress_tmp_dir));
std::vector<string> stuff;
if (!zip_file.empty()) {
TF_CHECK_OK(ReadManifest(zip_file, decompress_tmp_dir, &stuff));
} else {
TF_CHECK_OK(ReadManifest(tar_file, decompress_tmp_dir, &stuff));
}
return stuff;
}
class OpsTest : public ::testing::TestWithParam<string> {};
TEST_P(OpsTest, RunZipTests) {
string test_path_and_label = GetParam();
string test_path = test_path_and_label;
string label = test_path_and_label;
size_t end_pos = test_path_and_label.find(' ');
if (end_pos != string::npos) {
test_path = test_path_and_label.substr(0, end_pos);
label = test_path_and_label.substr(end_pos + 1);
}
string tflite_test_case = test_path + "_tests.txt";
string tflite_dir = test_path.substr(0, test_path.find_last_of('/'));
string test_name = label.substr(label.find_last_of('/'));
std::ifstream tflite_stream(tflite_test_case);
ASSERT_TRUE(tflite_stream.is_open()) << tflite_test_case;
tflite::testing::TfLiteDriver test_driver(
FLAGS_use_nnapi ? TfLiteDriver::DelegateType::kNnapi
: TfLiteDriver::DelegateType::kNone);
bool fully_quantize = false;
if (absl::StrContains(label, "fully_quantize=True")) {
// TODO(b/134594898): Tighten this constraint.
test_driver.SetThreshold(0.2, 0.1);
fully_quantize = true;
}
test_driver.SetModelBaseDir(tflite_dir);
auto broken_tests = GetKnownBrokenTests();
if (FLAGS_use_nnapi) {
for (const auto& t : GetKnownBrokenNnapiTests()) {
broken_tests[t.first] =
std::make_pair(t.second, /* always ignore */ false);
}
}
auto quantize_broken_tests = GetKnownQuantizeBrokenTests();
bool result = tflite::testing::ParseAndRunTests(&tflite_stream, &test_driver);
string message = test_driver.GetErrorMessage();
if (fully_quantize) {
if (!result) {
string bug_number;
// See if the tests are potential quantize failures.
for (const auto& p : quantize_broken_tests) {
if (RE2::PartialMatch(test_name, p.first)) {
bug_number = p.second;
break;
}
}
EXPECT_FALSE(bug_number.empty());
}
} else {
string bug_number;
bool always_ignore;
for (const auto& p : broken_tests) {
if (RE2::PartialMatch(test_name, p.first)) {
std::tie(bug_number, always_ignore) = p.second;
break;
}
}
if (bug_number.empty()) {
if (FLAGS_use_nnapi && FLAGS_ignore_unsupported_nnapi && !result) {
EXPECT_EQ(message, string("Failed to invoke interpreter")) << message;
} else {
EXPECT_TRUE(result) << message;
}
} else {
if (FLAGS_ignore_known_bugs) {
EXPECT_FALSE(result) << "Test was expected to fail but is now passing; "
"you can mark http://b/"
<< bug_number << " as fixed! Yay!";
} else {
EXPECT_TRUE(result || always_ignore)
<< message << ": Possibly due to http://b/" << bug_number;
}
}
}
}
struct ZipPathParamName {
template <class ParamType>
string operator()(const ::testing::TestParamInfo<ParamType>& info) const {
string param_name = info.param;
size_t last_slash = param_name.find_last_of("\\/");
if (last_slash != string::npos) {
param_name = param_name.substr(last_slash);
}
for (size_t index = 0; index < param_name.size(); ++index) {
if (!isalnum(param_name[index]) && param_name[index] != '_')
param_name[index] = '_';
}
return param_name;
}
};
INSTANTIATE_TEST_CASE_P(tests, OpsTest,
::testing::ValuesIn(UnarchiveAndFindTestNames(
*FLAGS_zip_file_path, *FLAGS_tar_file_path)),
ZipPathParamName());
} // namespace testing
} // namespace tflite
int main(int argc, char** argv) {
::testing::AddGlobalTestEnvironment(tflite::testing::archive_environment());
std::vector<tsl::Flag> flags = {
tsl::Flag("ignore_known_bugs", &tflite::testing::FLAGS_ignore_known_bugs,
"If a particular model is affected by a known bug, the "
"corresponding test should expect the outputs to not match."),
tsl::Flag("tar_file_path", tflite::testing::FLAGS_tar_file_path,
"Required (or zip_file_path): Location of the test tar file."),
tsl::Flag("zip_file_path", tflite::testing::FLAGS_zip_file_path,
"Required (or tar_file_path): Location of the test zip file."),
tsl::Flag("unzip_binary_path", tflite::testing::FLAGS_unzip_binary_path,
"Location of a suitable unzip binary."),
tsl::Flag("tar_binary_path", tflite::testing::FLAGS_tar_binary_path,
"Location of a suitable tar binary."),
tsl::Flag("use_nnapi", &tflite::testing::FLAGS_use_nnapi,
"Whether to enable the NNAPI delegate"),
tsl::Flag("ignore_unsupported_nnapi",
&tflite::testing::FLAGS_ignore_unsupported_nnapi,
"Don't fail tests just because delegation to NNAPI "
"is not possible")};
bool success = tsl::Flags::Parse(&argc, argv, flags);
if (!success || (argc == 2 && !strcmp(argv[1], "--helpfull"))) {
fprintf(stderr, "%s", tsl::Flags::Usage(argv[0], flags).c_str());
return 1;
}
if (!tflite::testing::TfLiteDriver::InitTestDelegateProviders(
&argc, const_cast<const char**>(argv))) {
return EXIT_FAILURE;
}
::tflite::LogToStderr();
// TODO(mikie): googletest arguments do not work - maybe the tensorflow flags
// parser removes them?
::testing::InitGoogleTest(&argc, argv);
return RUN_ALL_TESTS();
}
@@ -0,0 +1,35 @@
/* Copyright 2018 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/testing/init_tensorflow.h"
#include <cstdlib>
#include "tensorflow/core/platform/init_main.h"
namespace tflite {
void InitTensorFlow() {
static const char* kFakeName = "fake program name";
int argc = 1;
char* fake_name_copy = strdup(kFakeName);
char** argv = &fake_name_copy;
::tensorflow::port::InitMain(kFakeName, &argc, &argv);
free(fake_name_copy);
}
void InitTensorFlow(int argc, char** argv) {
::tensorflow::port::InitMain(argv[0], &argc, &argv);
}
} // namespace tflite
+29
View File
@@ -0,0 +1,29 @@
/* Copyright 2018 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_TESTING_INIT_TENSORFLOW_H_
#define TENSORFLOW_LITE_TESTING_INIT_TENSORFLOW_H_
namespace tflite {
// Initializes tensorflow's libraries. Note that this simulates an empty
// command line, so flags are not initialized.
void InitTensorFlow();
// Initializes tensorflow's libraries with the given command line arguments.
void InitTensorFlow(int argc, char** argv);
} // namespace tflite
#endif // TENSORFLOW_LITE_TESTING_INIT_TENSORFLOW_H_
+90
View File
@@ -0,0 +1,90 @@
/* Copyright 2017 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_TESTING_JOIN_H_
#define TENSORFLOW_LITE_TESTING_JOIN_H_
#include <cstdint>
#include <cstdlib>
#include <iomanip>
#include <sstream>
#include "tensorflow/lite/string_type.h"
namespace tflite {
namespace testing {
// Join a list of data with default precision separated by delimiter.
template <typename T>
string JoinDefault(T* data, size_t len, const string& delimiter) {
if (len == 0 || data == nullptr) {
return "";
}
std::stringstream result;
result << data[0];
for (int i = 1; i < len; i++) {
result << delimiter << data[i];
}
return result.str();
}
// Join a list of data with fixed precision separated by delimiter.
template <typename T>
string Join(T* data, size_t len, const string& delimiter) {
if (len == 0 || data == nullptr) {
return "";
}
std::stringstream result;
result << std::setprecision(9) << data[0];
for (int i = 1; i < len; i++) {
result << std::setprecision(9) << delimiter << data[i];
}
return result.str();
}
// Join a list of uint8 data separated by a delimiter. Cast data to int before
// placing it in the string to prevent values from being treated like chars.
template <>
inline string Join<uint8_t>(uint8_t* data, size_t len,
const string& delimiter) {
if (len == 0 || data == nullptr) {
return "";
}
std::stringstream result;
result << static_cast<int>(data[0]);
for (int i = 1; i < len; i++) {
result << delimiter << static_cast<int>(data[i]);
}
return result.str();
}
// Join a list of int8 data separated by a delimiter. Cast data to int before
// placing it in the string to prevent values from being treated like chars.
template <>
inline string Join<int8_t>(int8_t* data, size_t len, const string& delimiter) {
if (len == 0 || data == nullptr) {
return "";
}
std::stringstream result;
result << static_cast<int>(data[0]);
for (int i = 1; i < len; i++) {
result << delimiter << static_cast<int>(data[i]);
}
return result.str();
}
} // namespace testing
} // namespace tflite
#endif // TENSORFLOW_LITE_TESTING_JOIN_H_
+50
View File
@@ -0,0 +1,50 @@
/* Copyright 2017 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/testing/join.h"
#include <vector>
#include <gmock/gmock.h>
#include <gtest/gtest.h>
namespace tflite {
namespace testing {
namespace {
TEST(JoinTest, JoinInt) {
std::vector<int> data = {1, 2, 3};
EXPECT_EQ(Join(data.data(), data.size(), ","), "1,2,3");
}
TEST(JoinDefaultTest, JoinFloat) {
float data[] = {1.0, -3, 2.3, 1e-5};
EXPECT_EQ(JoinDefault(data, 4, " "), "1 -3 2.3 1e-05");
}
TEST(JoinTest, JoinFloat) {
float data[] = {1.0, -3, 2.3, 1e-5};
EXPECT_EQ(Join(data, 4, " "), "1 -3 2.29999995 9.99999975e-06");
}
TEST(JoinTest, JoinNullData) { EXPECT_THAT(Join<int>(nullptr, 3, ","), ""); }
TEST(JoinTest, JoinZeroData) {
std::vector<int> data;
EXPECT_THAT(Join(data.data(), 0, ","), "");
}
} // namespace
} // namespace testing
} // namespace tflite
+122
View File
@@ -0,0 +1,122 @@
load("@rules_cc//cc:cc_library.bzl", "cc_library")
load("@rules_cc//cc:cc_test.bzl", "cc_test")
load(
"//tensorflow:tensorflow.bzl",
"tf_cc_binary",
"tf_cc_test",
)
package(
# copybara:uncomment default_applicable_licenses = ["//tensorflow:LICENSE"],
default_visibility = [
"//visibility:public",
],
licenses = ["notice"],
)
cc_library(
name = "util",
hdrs = ["util.h"],
deps = [
":input_generator",
"//tensorflow/lite/core/c:common",
"//tensorflow/lite/testing:split",
"//tensorflow/lite/testing:tflite_driver",
] + select({
"//conditions:default": [
"//tensorflow/core:framework_internal",
"//tensorflow/core:lib",
],
"//tensorflow:android": [
"//tensorflow/core:portable_tensorflow_lib",
],
}),
)
tf_cc_test(
name = "util_test",
size = "small",
srcs = ["util_test.cc"],
data = [
":testdata/test_input.csv",
"//tensorflow/lite:testdata/add.bin",
],
deps = [
":util",
"//tensorflow/lite/testing:tflite_driver",
"@com_google_googletest//:gtest_main",
],
)
tf_cc_binary(
name = "tflite_kernel_runner",
srcs = ["tflite_kernel_runner.cc"],
deps = [
":util",
],
)
tf_cc_binary(
name = "generate_diff_report",
srcs = ["generate_diff_report.cc"],
deps = [
":diff_analyzer",
"//tensorflow/core:framework_internal",
],
)
cc_library(
name = "input_generator",
srcs = ["input_generator.cc"],
hdrs = ["input_generator.h"],
deps = [
"//tensorflow/lite:framework",
"//tensorflow/lite:string",
"//tensorflow/lite/core:framework",
"//tensorflow/lite/core/c:c_api_types",
"//tensorflow/lite/core/c:common",
"//tensorflow/lite/core/kernels:builtin_ops",
"//tensorflow/lite/testing:join",
"//tensorflow/lite/testing:split",
],
)
cc_test(
name = "input_generator_test",
size = "small",
srcs = ["input_generator_test.cc"],
data = [
":testdata/test_input.csv",
"//tensorflow/lite:testdata/multi_add.bin",
],
deps = [
":input_generator",
"@com_google_googletest//:gtest_main",
],
)
cc_library(
name = "diff_analyzer",
srcs = ["diff_analyzer.cc"],
hdrs = ["diff_analyzer.h"],
deps = [
"//tensorflow/lite:string",
"//tensorflow/lite/core/c:c_api_types",
"//tensorflow/lite/core/c:common",
"//tensorflow/lite/testing:split",
],
)
tf_cc_test(
name = "diff_analyzer_test",
size = "small",
srcs = ["diff_analyzer_test.cc"],
data = [
":testdata/test_input.csv",
],
deps = [
":diff_analyzer",
"//tensorflow/core:lib",
"@com_google_googletest//:gtest_main",
],
)
@@ -0,0 +1,133 @@
/* 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.
==============================================================================*/
#include "tensorflow/lite/testing/kernel_test/diff_analyzer.h"
#include <algorithm>
#include <cmath>
#include <cstdio>
#include <fstream>
#include <string>
#include <unordered_map>
#include <utility>
#include <vector>
#include "tensorflow/lite/core/c/c_api_types.h"
#include "tensorflow/lite/testing/split.h"
namespace tflite {
namespace testing {
namespace {
float CalculateNormalizedMaxDiff(const std::vector<float>& base,
const std::vector<float>& test) {
float diff = 0;
// For numerical stability in case the tensor is all 0.
float base_max = 1e-6;
for (int i = 0; i < base.size(); i++) {
diff = std::max(diff, std::abs(base[i] - test[i]));
base_max = std::max(base_max, base[i]);
}
return diff / base_max;
}
float CalculateNormalizedL2Norm(const std::vector<float>& base,
const std::vector<float>& test) {
float l2_error = 0;
// For numerical stability in case the tensor is all 0.
float base_max = 1e-6;
for (int i = 0; i < base.size(); i++) {
float diff = base[i] - test[i];
l2_error += diff * diff;
base_max = std::max(base_max, base[i]);
}
l2_error /= base.size();
return std::sqrt(l2_error) / base_max;
}
TfLiteStatus Populate(const string& filename,
std::unordered_map<string, std::vector<float>>* tensors) {
if (filename.empty()) {
fprintf(stderr, "Empty input file name.");
return kTfLiteError;
}
std::ifstream file(filename);
string content;
while (std::getline(file, content, '\n')) {
auto parts = Split<string>(content, ":");
if (parts.size() != 2) {
fprintf(stderr, "Expected <name>:<value>, got %s", content.c_str());
return kTfLiteError;
}
tensors->insert(std::make_pair(parts[0], Split<float>(parts[1], ",")));
}
file.close();
return kTfLiteOk;
}
} // namespace
TfLiteStatus DiffAnalyzer::ReadFiles(const string& base, const string& test) {
TF_LITE_ENSURE_STATUS(Populate(base, &base_tensors_));
TF_LITE_ENSURE_STATUS(Populate(test, &test_tensors_));
if (base_tensors_.size() != test_tensors_.size()) {
fprintf(stderr, "Golden and test tensor dimensions don't match.");
return kTfLiteError;
}
return kTfLiteOk;
}
TfLiteStatus DiffAnalyzer::WriteReport(const string& filename) {
if (filename.empty()) {
fprintf(stderr, "Empty output file name.");
return kTfLiteError;
}
std::ofstream output_file;
output_file.open(filename, std::fstream::out | std::fstream::trunc);
if (!output_file) {
fprintf(stderr, "Failed to open output file %s.", filename.c_str());
return kTfLiteError;
}
output_file << "Normalized L2 Error"
<< ","
<< "Normalized Max Diff"
<< "\n";
for (const auto& item : base_tensors_) {
const auto& name = item.first;
if (!test_tensors_.count(name)) {
fprintf(stderr, "Missing tensor %s in test tensors.", name.c_str());
continue;
}
float l2_error =
CalculateNormalizedL2Norm(base_tensors_[name], test_tensors_[name]);
float max_diff =
CalculateNormalizedMaxDiff(base_tensors_[name], test_tensors_[name]);
output_file << name << ":" << l2_error << "," << max_diff << "\n";
}
output_file.close();
return kTfLiteOk;
}
} // namespace testing
} // namespace tflite
@@ -0,0 +1,49 @@
/* 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_TESTING_KERNEL_TEST_DIFF_ANALYZER_H_
#define TENSORFLOW_LITE_TESTING_KERNEL_TEST_DIFF_ANALYZER_H_
#include <string>
#include <unordered_map>
#include <vector>
#include "tensorflow/lite/core/c/common.h"
#include "tensorflow/lite/string_type.h"
namespace tflite {
namespace testing {
// Reads the baseline and test files with output tensor values, and calculates
// the diff metrics.
class DiffAnalyzer {
public:
DiffAnalyzer() = default;
// Reads base and test tensor values from files.
// Each file have lines in <name>:<values> format, where name is the signature
// output name and value as comma separated value string.
TfLiteStatus ReadFiles(const string& base, const string& test);
// Writes diff report in <name>:<L2 Error>,<Max Diff> format.
TfLiteStatus WriteReport(const string& filename);
private:
// Mappings from signature output names to its values.
std::unordered_map<string, std::vector<float>> base_tensors_;
std::unordered_map<string, std::vector<float>> test_tensors_;
};
} // namespace testing
} // namespace tflite
#endif // TENSORFLOW_LITE_TESTING_KERNEL_TEST_DIFF_ANALYZER_H_
@@ -0,0 +1,48 @@
/* 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.
==============================================================================*/
#include "tensorflow/lite/testing/kernel_test/diff_analyzer.h"
#include <fstream>
#include <string>
#include <gtest/gtest.h>
#include "tensorflow/core/lib/io/path.h"
namespace tflite {
namespace testing {
namespace {
TEST(DiffAnalyzerTest, ZeroDiff) {
DiffAnalyzer diff_analyzer;
string filename =
"tensorflow/lite/testing/kernel_test/testdata/test_input.csv";
ASSERT_EQ(diff_analyzer.ReadFiles(filename, filename), kTfLiteOk);
string output_file =
tensorflow::io::JoinPath(::testing::TempDir(), "diff_report.csv");
ASSERT_EQ(diff_analyzer.WriteReport(output_file), kTfLiteOk);
std::string content;
std::ifstream file(output_file);
std::getline(file, content);
std::getline(file, content);
ASSERT_EQ(content, "a:0,0");
}
} // namespace
} // namespace testing
} // namespace tflite
@@ -0,0 +1,34 @@
/* 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.
==============================================================================*/
#include <string>
#include <vector>
#include "tensorflow/core/util/command_line_flags.h"
#include "tensorflow/lite/testing/kernel_test/diff_analyzer.h"
int main(int argc, char** argv) {
std::string base, test, output;
std::vector<tensorflow::Flag> flag_list = {
tensorflow::Flag("base", &base, "Path to the base serialized tensor."),
tensorflow::Flag("test", &test, "Path to the test serialized tensor."),
tensorflow::Flag("output", &output, "Path to the output file."),
};
tensorflow::Flags::Parse(&argc, argv, flag_list);
tflite::testing::DiffAnalyzer diff_analyzer;
diff_analyzer.ReadFiles(base, test);
diff_analyzer.WriteReport(output);
return 0;
}
@@ -0,0 +1,236 @@
/* 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.
==============================================================================*/
#include "tensorflow/lite/testing/kernel_test/input_generator.h"
#include <cstdint>
#include <cstdio>
#include <cstdlib>
#include <fstream>
#include <functional>
#include <limits>
#include <random>
#include <string>
#include <utility>
#include <vector>
#include "tensorflow/lite/core/c/c_api_types.h"
#include "tensorflow/lite/core/c/common.h"
#include "tensorflow/lite/core/kernels/register.h"
#include "tensorflow/lite/testing/join.h"
#include "tensorflow/lite/testing/split.h"
namespace tflite {
namespace testing {
namespace {
static constexpr char kDefaultServingSignatureDefKey[] = "serving_default";
template <typename T>
std::vector<T> GenerateRandomTensor(TfLiteIntArray* dims,
const std::function<T(int)>& random_func) {
int64_t num_elements = 1;
for (int i = 0; i < dims->size; i++) {
num_elements *= dims->data[i];
}
std::vector<T> result(num_elements);
for (int i = 0; i < num_elements; i++) {
result[i] = random_func(i);
}
return result;
}
template <typename T>
std::vector<T> GenerateUniform(TfLiteIntArray* dims, float min, float max) {
auto random_float = [](float min, float max) {
// TODO(yunluli): Change seed for each invocation if needed.
// Used rand() instead of rand_r() here to make it runnable on android.
return min + (max - min) * static_cast<float>(rand()) / RAND_MAX;
};
std::function<T(int)> random_t = [&](int) {
return static_cast<T>(random_float(min, max));
};
std::vector<T> data = GenerateRandomTensor(dims, random_t);
return data;
}
template <typename T>
std::vector<T> GenerateGaussian(TfLiteIntArray* dims, float min, float max) {
auto random_float = [](float min, float max) {
static std::default_random_engine generator;
// We generate a float number within [0, 1) following a mormal distribution
// with mean = 0.5 and stddev = 1/3, and use it to scale the final random
// number into the desired range.
static std::normal_distribution<double> distribution(0.5, 1.0 / 3);
auto rand_n = distribution(generator);
while (rand_n < 0 || rand_n >= 1) {
rand_n = distribution(generator);
}
return min + (max - min) * static_cast<float>(rand_n);
};
std::function<T(int)> random_t = [&](int) {
return static_cast<T>(random_float(min, max));
};
std::vector<T> data = GenerateRandomTensor(dims, random_t);
return data;
}
} // namespace
TfLiteStatus InputGenerator::LoadModel(const string& model_dir) {
return LoadModel(model_dir, kDefaultServingSignatureDefKey);
}
TfLiteStatus InputGenerator::LoadModel(const string& model_dir,
const string& signature) {
model_ = FlatBufferModel::BuildFromFile(model_dir.c_str());
if (!model_) {
fprintf(stderr, "Cannot load model %s", model_dir.c_str());
return kTfLiteError;
}
::tflite::ops::builtin::BuiltinOpResolver builtin_ops;
InterpreterBuilder(*model_, builtin_ops)(&interpreter_);
if (!interpreter_) {
fprintf(stderr, "Failed to build interpreter.");
return kTfLiteError;
}
signature_runner_ = interpreter_->GetSignatureRunner(signature.c_str());
if (!signature_runner_) {
fprintf(stderr, "Failed to get SignatureRunner.\n");
return kTfLiteError;
}
return kTfLiteOk;
}
TfLiteStatus InputGenerator::ReadInputsFromFile(const string& filename) {
if (filename.empty()) {
fprintf(stderr, "Empty input file name.");
return kTfLiteError;
}
std::ifstream input_file(filename);
string input;
while (std::getline(input_file, input, '\n')) {
std::vector<string> parts = Split<string>(input, ":");
if (parts.size() != 2) {
fprintf(stderr, "Expected <name>:<value>, got %s", input.c_str());
return kTfLiteError;
}
inputs_.push_back(std::make_pair(parts[0], parts[1]));
}
input_file.close();
return kTfLiteOk;
}
TfLiteStatus InputGenerator::WriteInputsToFile(const string& filename) {
if (filename.empty()) {
fprintf(stderr, "Empty input file name.");
return kTfLiteError;
}
std::ofstream output_file;
output_file.open(filename, std::fstream::out | std::fstream::trunc);
if (!output_file) {
fprintf(stderr, "Failed to open output file %s.", filename.c_str());
return kTfLiteError;
}
for (const auto& input : inputs_) {
output_file << input.first << ":" << input.second << "\n";
}
output_file.close();
return kTfLiteOk;
}
// TODO(yunluli): Support more tensor types when needed.
TfLiteStatus InputGenerator::GenerateInput(const string& distribution) {
auto input_tensor_names = signature_runner_->input_names();
for (const char* name : input_tensor_names) {
auto* tensor = signature_runner_->input_tensor(name);
if (distribution == "UNIFORM") {
switch (tensor->type) {
case kTfLiteInt8: {
auto data = GenerateUniform<int8_t>(
tensor->dims, std::numeric_limits<int8_t>::min(),
std::numeric_limits<int8_t>::max());
inputs_.push_back(
std::make_pair(name, Join(data.data(), data.size(), ",")));
break;
}
case kTfLiteUInt8: {
auto data = GenerateUniform<uint8_t>(
tensor->dims, std::numeric_limits<uint8_t>::min(),
std::numeric_limits<uint8_t>::max());
inputs_.push_back(
std::make_pair(name, Join(data.data(), data.size(), ",")));
break;
}
case kTfLiteFloat32: {
auto data = GenerateUniform<float>(tensor->dims, -1, 1);
inputs_.push_back(
std::make_pair(name, Join(data.data(), data.size(), ",")));
break;
}
default:
fprintf(stderr, "Unsupported input tensor type %s.",
TfLiteTypeGetName(tensor->type));
break;
}
} else if (distribution == "GAUSSIAN") {
switch (tensor->type) {
case kTfLiteInt8: {
auto data = GenerateGaussian<int8_t>(
tensor->dims, std::numeric_limits<int8_t>::min(),
std::numeric_limits<int8_t>::max());
inputs_.push_back(
std::make_pair(name, Join(data.data(), data.size(), ",")));
break;
}
case kTfLiteUInt8: {
auto data = GenerateGaussian<uint8_t>(
tensor->dims, std::numeric_limits<uint8_t>::min(),
std::numeric_limits<uint8_t>::max());
inputs_.push_back(
std::make_pair(name, Join(data.data(), data.size(), ",")));
break;
}
case kTfLiteFloat32: {
auto data = GenerateGaussian<float>(tensor->dims, -1, 1);
inputs_.push_back(
std::make_pair(name, Join(data.data(), data.size(), ",")));
break;
}
default:
fprintf(stderr, "Unsupported input tensor type %s.",
TfLiteTypeGetName(tensor->type));
break;
}
} else {
fprintf(stderr, "Unsupported distribution %s.", distribution.c_str());
return kTfLiteError;
}
}
return kTfLiteOk;
}
} // namespace testing
} // namespace tflite
@@ -0,0 +1,58 @@
/* 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_TESTING_KERNEL_TEST_INPUT_GENERATOR_H_
#define TENSORFLOW_LITE_TESTING_KERNEL_TEST_INPUT_GENERATOR_H_
#include <memory>
#include <string>
#include <utility>
#include <vector>
#include "tensorflow/lite/core/c/c_api_types.h"
#include "tensorflow/lite/core/c/common.h"
#include "tensorflow/lite/core/interpreter.h"
#include "tensorflow/lite/core/model.h"
#include "tensorflow/lite/signature_runner.h"
#include "tensorflow/lite/string_type.h"
namespace tflite {
namespace testing {
// Generate random input, or read input from a file for kernel diff test.
// Needs to load the tflite graph to get information like tensor shape and
// data type.
class InputGenerator {
public:
InputGenerator() = default;
TfLiteStatus LoadModel(const string& model_dir);
TfLiteStatus LoadModel(const string& model_dir, const string& signature);
TfLiteStatus ReadInputsFromFile(const string& filename);
TfLiteStatus GenerateInput(const string& distribution);
std::vector<std::pair<string, string>> GetInputs() { return inputs_; }
TfLiteStatus WriteInputsToFile(const string& filename);
private:
std::unique_ptr<FlatBufferModel> model_;
std::unique_ptr<Interpreter> interpreter_;
// Not owned.
SignatureRunner* signature_runner_ = nullptr;
// Mapping from input names to csv string values.
std::vector<std::pair<string, string>> inputs_;
};
} // namespace testing
} // namespace tflite
#endif // TENSORFLOW_LITE_TESTING_KERNEL_TEST_INPUT_GENERATOR_H_
@@ -0,0 +1,83 @@
/* 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.
==============================================================================*/
#include "tensorflow/lite/testing/kernel_test/input_generator.h"
#include <fstream>
#include <string>
#include <utility>
#include <vector>
#include <gtest/gtest.h>
namespace tflite {
namespace testing {
namespace {
TEST(InputGeneratorTest, LoadModel) {
InputGenerator input_generator;
ASSERT_EQ(input_generator.LoadModel(
"tensorflow/lite/testdata/multi_add.bin"),
kTfLiteOk);
}
TEST(InputGeneratorTest, ReadWriteSimpleFile) {
InputGenerator input_generator;
ASSERT_EQ(
input_generator.ReadInputsFromFile("tensorflow/lite/testing/"
"kernel_test/testdata/test_input.csv"),
kTfLiteOk);
std::string content = "1";
for (int i = 0; i < 1 * 8 * 8 * 3 - 1; i++) {
content.append(",1");
}
std::vector<std::pair<string, string>> inputs = {{"a", content}};
ASSERT_EQ(input_generator.GetInputs(), inputs);
auto output_filename = ::testing::TempDir() + "/out.csv";
ASSERT_EQ(input_generator.WriteInputsToFile(output_filename), kTfLiteOk);
std::ifstream in(output_filename);
std::string out;
std::getline(in, out, '\n');
std::string expected_out = "a:";
expected_out.append(content);
ASSERT_EQ(out, expected_out);
}
TEST(InputGeneratorTest, GenerateUniformInput) {
InputGenerator input_generator;
ASSERT_EQ(input_generator.LoadModel(
"tensorflow/lite/testdata/multi_add.bin"),
kTfLiteOk);
input_generator.GenerateInput("UNIFORM");
auto inputs = input_generator.GetInputs();
ASSERT_EQ(inputs.size(), 4);
}
TEST(InputGeneratorTest, GenerateGaussianInput) {
InputGenerator input_generator;
ASSERT_EQ(input_generator.LoadModel(
"tensorflow/lite/testdata/multi_add.bin"),
kTfLiteOk);
input_generator.GenerateInput("GAUSSIAN");
auto inputs = input_generator.GetInputs();
ASSERT_EQ(inputs.size(), 4);
}
} // namespace
} // namespace testing
} // namespace tflite
@@ -0,0 +1 @@
a:1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1
1 a:1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1
@@ -0,0 +1,37 @@
/* 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.
==============================================================================*/
#include <memory>
#include "tensorflow/lite/testing/kernel_test/util.h"
int main(int argc, char** argv) {
tflite::testing::kernel_test::TestOptions options =
tflite::testing::kernel_test::ParseTfliteKernelTestFlags(&argc, argv);
const bool run_reference_kernel = options.kernel_type == "REFERENCE";
const tflite::testing::TfLiteDriver::DelegateType delegate_type =
options.kernel_type == "NNAPI"
? tflite::testing::TfLiteDriver::DelegateType::kNnapi
: tflite::testing::TfLiteDriver::DelegateType::kNone;
auto runner = std::make_unique<tflite::testing::TfLiteDriver>(
delegate_type, run_reference_kernel);
if (tflite::testing::kernel_test::RunKernelTest(options, runner.get()) ==
kTfLiteOk) {
return 0;
}
return -1;
}
+113
View File
@@ -0,0 +1,113 @@
/* 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_TESTING_KERNEL_TEST_UTIL_H_
#define TENSORFLOW_LITE_TESTING_KERNEL_TEST_UTIL_H_
#include <fstream>
#include "tensorflow/core/util/command_line_flags.h"
#include "tensorflow/lite/core/c/common.h"
#include "tensorflow/lite/testing/kernel_test/input_generator.h"
#include "tensorflow/lite/testing/split.h"
#include "tensorflow/lite/testing/tflite_driver.h"
namespace tflite {
namespace testing {
namespace kernel_test {
struct TestOptions {
// Path of tensorflow lite model.
string tflite_model;
// Path of the input file. If empty, generate at runtime.
string read_input_from_file;
// Path to dump the input file.
string dump_input_to_file;
// Path to dump the output.
string dump_output_to_file;
// Input distribution.
string input_distribution;
// Kernel type.
string kernel_type;
};
inline TestOptions ParseTfliteKernelTestFlags(int* argc, char** argv) {
TestOptions options;
std::vector<tensorflow::Flag> flags = {
tensorflow::Flag("tflite_model", &options.tflite_model,
"Path of tensorflow lite model."),
tensorflow::Flag("read_input_from_file", &options.read_input_from_file,
"File to read input data from. If empty, generates "
"input at runtime."),
tensorflow::Flag("dump_input_to_file", &options.dump_input_to_file,
"File to dump randomly generated input."),
tensorflow::Flag("dump_output_to_file", &options.dump_output_to_file,
"File to dump output."),
tensorflow::Flag("input_distribution", &options.input_distribution,
"Input distribution. Default: Gaussian."),
tensorflow::Flag("kernel_type", &options.kernel_type, "Kernel type."),
};
tensorflow::Flags::Parse(argc, argv, flags);
return options;
}
inline TfLiteStatus RunKernelTest(const kernel_test::TestOptions& options,
TestRunner* runner) {
InputGenerator input_generator;
if (options.read_input_from_file.empty()) {
TF_LITE_ENSURE_STATUS(input_generator.LoadModel(options.tflite_model));
TF_LITE_ENSURE_STATUS(
input_generator.GenerateInput(options.input_distribution));
} else {
TF_LITE_ENSURE_STATUS(
input_generator.ReadInputsFromFile(options.read_input_from_file));
}
runner->LoadModel(options.tflite_model);
runner->AllocateTensors();
if (!runner->IsValid()) return kTfLiteError;
auto inputs = input_generator.GetInputs();
runner->Invoke(inputs);
if (!options.dump_input_to_file.empty()) {
TF_LITE_ENSURE_STATUS(
input_generator.WriteInputsToFile(options.dump_input_to_file));
}
if (!options.dump_output_to_file.empty()) {
std::ofstream output_file;
output_file.open(options.dump_output_to_file,
std::fstream::out | std::fstream::trunc);
if (!output_file) {
return kTfLiteError;
}
for (const auto& name : runner->GetOutputNames()) {
output_file << name << ":" << runner->ReadOutput(name) << "\n";
}
output_file.close();
}
return kTfLiteOk;
}
} // namespace kernel_test
} // namespace testing
} // namespace tflite
#endif // TENSORFLOW_LITE_TESTING_KERNEL_TEST_UTIL_H_
@@ -0,0 +1,52 @@
/* 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.
==============================================================================*/
#include "tensorflow/lite/testing/kernel_test/util.h"
#include <fstream>
#include <memory>
#include <string>
#include <gtest/gtest.h>
#include "tensorflow/lite/testing/tflite_driver.h"
namespace tflite {
namespace testing {
namespace kernel_test {
namespace {
TEST(UtilTest, SimpleE2ETest) {
TestOptions options;
options.tflite_model = "tensorflow/lite/testdata/add.bin";
options.read_input_from_file =
"tensorflow/lite/testing/kernel_test/testdata/test_input.csv";
options.dump_output_to_file = ::testing::TempDir() + "/test_out.csv";
options.kernel_type = "REFERENCE";
std::unique_ptr<TestRunner> runner(new TfLiteDriver(
TfLiteDriver::DelegateType::kNone, /*reference_kernel=*/true));
RunKernelTest(options, runner.get());
std::string expected = "x:3";
for (int i = 0; i < 1 * 8 * 8 * 3 - 1; i++) {
expected.append(",3");
}
std::string content;
std::ifstream file(options.dump_output_to_file);
std::getline(file, content);
EXPECT_EQ(content, expected);
}
} // namespace
} // namespace kernel_test
} // namespace testing
} // namespace tflite
+302
View File
@@ -0,0 +1,302 @@
/* Copyright 2024 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_TESTING_MATCHERS_H_
#define TENSORFLOW_LITE_TESTING_MATCHERS_H_
#include <algorithm>
#include <cfloat>
#include <cmath>
#include <cstring>
#include <iomanip>
#include <iostream>
#include <limits>
#include <sstream>
#include <string>
#include <vector>
#include <gtest/gtest.h>
#include "absl/base/casts.h"
#include "absl/log/absl_check.h"
#include "absl/strings/str_cat.h"
#include "absl/strings/str_join.h"
#include "absl/strings/string_view.h"
#include "absl/types/span.h"
#include "tensorflow/lite/core/c/common.h"
#include "tensorflow/lite/kernels/kernel_util.h"
// gMock matchers for TfLiteTensors.
//
// EXPECT_THAT(a, EqualsTensor(b));
// EXPECT_THAT(a, Approximately(EqualsTensor(b)));
// EXPECT_THAT(a, Approximately(EqualsTensor(b), /*margin*/));
// EXPECT_THAT(a, Approximately(EqualsTensor(b), /*margin=*/0, /*fraction*/));
//
// TODO: who/impjdi - Expand to more dtypes than just float.
// TODO: who/impjdi - Add cross-dtype matchers.
inline void PrintTo(const TfLiteTensor& tensor, std::ostream* os) {
*os << "\n" << ::tflite::GetTensorDebugString(&tensor);
}
namespace testing {
namespace tflite {
namespace internal {
enum class FloatComparison { kExact, kApproximate };
struct TensorComparison {
FloatComparison float_comp = FloatComparison::kExact;
bool custom_margin = false;
bool custom_fraction = false;
double margin = 0.0; // only used if custom_margin == true
double fraction = 0.0; // only used if custom_fraction == true
};
class TensorMatcher {
public:
TensorMatcher(const TensorComparison& comp, const TfLiteTensor& expected)
: comp_(comp), expected_(expected) {}
bool MatchAndExplain(const TfLiteTensor& actual,
MatchResultListener* listener) const {
const bool match = Match(actual);
if (listener->IsInterested() && !match) *listener << DescribeDiff(actual);
return match;
}
void DescribeTo(std::ostream* os) const { Describe(os, "is "); }
void DescribeNegationTo(std::ostream* os) const { Describe(os, "is not "); }
void SetCompareApproximately() {
comp_.float_comp = FloatComparison::kApproximate;
}
void SetMargin(double margin) {
ABSL_QCHECK_GE(margin, 0.0) // Crash OK
<< "Using a negative margin for Approximately";
comp_.custom_margin = true;
comp_.margin = margin;
}
void SetFraction(double fraction) {
ABSL_QCHECK(0.0 <= fraction && fraction < 1.0) // Crash OK
<< "Fraction for Approximately must be >= 0.0 and < 1.0";
comp_.custom_fraction = true;
comp_.fraction = fraction;
}
private:
static std::string TensorIndex(int index, const TfLiteIntArray* dims) {
if (!dims->size) return "";
std::vector<int> index_nd(dims->size);
for (int i = dims->size - 1; i >= 0; --i) {
index_nd[i] = index % dims->data[i];
index /= dims->data[i];
}
return absl::StrCat("[", absl::StrJoin(index_nd, "]["), "]");
}
bool CompareFloat(float x, float y) const {
switch (comp_.float_comp) {
case FloatComparison::kExact:
return x == y;
case FloatComparison::kApproximate:
if (x == y) return true;
float fraction, margin;
if (comp_.custom_margin || comp_.custom_fraction) {
fraction = comp_.fraction;
margin = comp_.margin;
} else {
constexpr float kEpsilon = 32 * FLT_EPSILON;
if (std::fabs(x) <= kEpsilon && std::fabs(y) <= kEpsilon) return true;
fraction = kEpsilon;
margin = kEpsilon;
}
if (!std::isfinite(x) || !std::isfinite(y)) return false;
float relative_margin = fraction * std::max(std::fabs(x), std::fabs(y));
return std::fabs(x - y) <= std::max(margin, relative_margin);
}
return false;
}
void Describe(std::ostream* os, absl::string_view prefix) const {
*os << prefix;
if (comp_.float_comp == FloatComparison::kApproximate) {
*os << "approximately ";
if (comp_.custom_margin || comp_.custom_fraction) {
*os << "(";
if (comp_.custom_margin) {
std::stringstream ss;
ss << std::setprecision(std::numeric_limits<double>::digits10 + 2)
<< comp_.margin;
*os << "absolute error of float values <= " << ss.str();
}
if (comp_.custom_margin && comp_.custom_fraction) {
*os << " or ";
}
if (comp_.custom_fraction) {
std::stringstream ss;
ss << std::setprecision(std::numeric_limits<double>::digits10 + 2)
<< comp_.fraction;
*os << "relative error of float values <= " << ss.str();
}
*os << ") ";
}
}
*os << "equal to ";
PrintTo(expected_, os);
}
std::string DescribeDiff(const TfLiteTensor& actual) const {
if (actual.type != expected_.type) {
return absl::StrCat(
"dtypes don't match: ", TfLiteTypeGetName(actual.type), " vs ",
TfLiteTypeGetName(expected_.type));
}
if (!actual.dims) return "actual.dims is null.";
if (!expected_.dims) return "expected.dims is null.";
if (actual.dims->size != expected_.dims->size) {
return absl::StrCat("dims don't match: ", actual.dims->size, "D vs ",
expected_.dims->size, "D");
}
if (int n = actual.dims->size;
std::memcmp(actual.dims->data, expected_.dims->data, n * sizeof(int))) {
return absl::StrCat(
"shapes don't match: ", ::tflite::GetShapeDebugString(actual.dims),
" vs ", ::tflite::GetShapeDebugString(expected_.dims));
}
if (!actual.data.raw) return "actual.data is null.";
if (!expected_.data.raw) return "expected.data is null.";
if (actual.bytes != expected_.bytes) {
return absl::StrCat("bytes don't match: ", actual.bytes, " vs ",
expected_.bytes);
}
std::string error = "\n";
TfLiteIntArray* dims = actual.dims;
int n = ::tflite::NumElements(dims);
constexpr int kMaxMismatches = 20;
for (int i = 0, j = 0; i < n; ++i) {
if (!CompareFloat(actual.data.f[i], expected_.data.f[i])) {
absl::StrAppend(&error, "data", TensorIndex(i, dims),
" don't match: ", actual.data.f[i], " vs ",
expected_.data.f[i], "\n");
++j;
}
if (j == kMaxMismatches) {
absl::StrAppend(&error, "Too many mismatches; stopping after ", j,
".\n");
break;
}
}
return error;
}
bool Match(const TfLiteTensor& actual) const {
if (actual.type != expected_.type) return false;
if (!actual.dims) return false;
if (!expected_.dims) return false;
if (actual.dims->size != expected_.dims->size) return false;
if (int n = actual.dims->size;
std::memcmp(actual.dims->data, expected_.dims->data, n * sizeof(int))) {
return false;
}
if (!actual.data.raw) return false;
if (!expected_.data.raw) return false;
if (actual.bytes != expected_.bytes) return false;
switch (comp_.float_comp) {
case FloatComparison::kExact:
if (int n = actual.bytes;
std::memcmp(actual.data.raw, expected_.data.raw, n)) {
return false;
}
break;
case FloatComparison::kApproximate:
for (int i = 0, n = ::tflite::NumElements(actual.dims); i < n; ++i) {
if (!CompareFloat(actual.data.f[i], expected_.data.f[i])) {
return false;
}
}
break;
};
return true;
}
TensorComparison comp_;
TfLiteTensor expected_;
};
} // namespace internal
// A struct that simplifies the creation and management of constant
// `TfLiteTensor` objects, automatically deallocating the memory (including
// dims) at destruction time.
//
// Example:
// float data[] = {2.71828f, 3.14159f};
// SimpleConstTensor a(TfLiteType::kTfLiteFloat32, {1, 2},
// absl::MakeSpan(data));
struct SimpleConstTensor : public TfLiteTensor {
template <typename T>
SimpleConstTensor(TfLiteType dtype, const std::vector<int>& shape,
absl::Span<T> buf) {
type = dtype;
dims = TfLiteIntArrayCreate(shape.size());
std::memcpy(dims->data, shape.data(), shape.size() * sizeof(int));
data = {.data = buf.data()};
bytes = buf.size() * sizeof(T);
sparsity = nullptr;
}
~SimpleConstTensor() { TfLiteIntArrayFree(dims); }
};
// Delegate pretty print to PrintTo(TfLiteTensor&).
inline void PrintTo(const SimpleConstTensor& tensor,
std::ostream* os) { // NOLINT
PrintTo(absl::implicit_cast<const TfLiteTensor&>(tensor), os);
}
inline PolymorphicMatcher<internal::TensorMatcher> EqualsTensor(
const TfLiteTensor& expected) {
internal::TensorComparison comp;
return MakePolymorphicMatcher(internal::TensorMatcher(comp, expected));
}
template <class InnerTensorMatcherT>
inline InnerTensorMatcherT Approximately(InnerTensorMatcherT m) {
m.mutable_impl().SetCompareApproximately();
return m;
}
template <class InnerTensorMatcherT>
inline InnerTensorMatcherT Approximately(InnerTensorMatcherT m, double margin) {
m.mutable_impl().SetCompareApproximately();
m.mutable_impl().SetMargin(margin);
return m;
}
template <class InnerTensorMatcherT>
inline InnerTensorMatcherT Approximately(InnerTensorMatcherT m, double margin,
double fraction) {
m.mutable_impl().SetCompareApproximately();
m.mutable_impl().SetMargin(margin);
m.mutable_impl().SetFraction(fraction);
return m;
}
} // namespace tflite
} // namespace testing
#endif // TENSORFLOW_LITE_TESTING_MATCHERS_H_
+126
View File
@@ -0,0 +1,126 @@
/* Copyright 2024 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/testing/matchers.h"
#include <vector>
#include <gmock/gmock.h>
#include <gtest/gtest.h>
#include "absl/types/span.h"
#include "tensorflow/lite/core/c/c_api_types.h"
#include "tensorflow/lite/core/c/common.h"
namespace tflite {
namespace {
using ::testing::tflite::Approximately;
using ::testing::tflite::EqualsTensor;
using ::testing::tflite::SimpleConstTensor;
TEST(TensorMatcherTest, ExactlyEqualsSelf) {
float data[] = {2.71828f, 3.14159f};
SimpleConstTensor a(TfLiteType::kTfLiteFloat32, {1, 2}, absl::MakeSpan(data));
EXPECT_THAT(a, EqualsTensor(a));
}
TEST(TensorMatcherTest, ExactlyEqualsSame) {
float a_data[] = {2.71828f, 3.14159f};
SimpleConstTensor a(TfLiteType::kTfLiteFloat32, {1, 2},
absl::MakeSpan(a_data));
float b_data[] = {2.71828f, 3.14159f};
SimpleConstTensor b(TfLiteType::kTfLiteFloat32, {1, 2},
absl::MakeSpan(b_data));
EXPECT_THAT(a, EqualsTensor(b));
}
TEST(TensorMatcherTest, DoesNotExactlyEqualDifferentType) {
float data[] = {2.71828f, 3.14159f};
SimpleConstTensor a(TfLiteType::kTfLiteFloat32, {1, 2}, absl::MakeSpan(data));
SimpleConstTensor b(TfLiteType::kTfLiteInt32, {1, 2}, absl::MakeSpan(data));
EXPECT_THAT(a, Not(EqualsTensor(b)));
}
TEST(TensorMatcherTest, DoesNotExactlyEqualDifferentDims) {
float data[] = {2.71828f, 3.14159f};
SimpleConstTensor a(TfLiteType::kTfLiteFloat32, {1, 2}, absl::MakeSpan(data));
SimpleConstTensor b(TfLiteType::kTfLiteFloat32, {2, 1}, absl::MakeSpan(data));
EXPECT_THAT(a, Not(EqualsTensor(b)));
}
TEST(TensorMatcherTest, DoesNotExactlyEqualDifferentData) {
float a_data[] = {2.71828f, 3.14159f};
SimpleConstTensor a(TfLiteType::kTfLiteFloat32, {1, 2},
absl::MakeSpan(a_data));
float b_data[] = {3.14159f, 2.71828f};
SimpleConstTensor b(TfLiteType::kTfLiteFloat32, {1, 2},
absl::MakeSpan(b_data));
EXPECT_THAT(a, Not(EqualsTensor(b)));
}
TEST(TensorMatcherTest, ApproximatelyEqualsDefaultMargin) {
float a_data[] = {2.71828f, 3.14159f};
SimpleConstTensor a(TfLiteType::kTfLiteFloat32, {1, 2},
absl::MakeSpan(a_data));
float b_data[] = {2.718277f, 3.141593f};
SimpleConstTensor b(TfLiteType::kTfLiteFloat32, {1, 2},
absl::MakeSpan(b_data));
EXPECT_THAT(a, Approximately(EqualsTensor(b)));
}
TEST(TensorMatcherTest, ApproximatelyEqualsWithLooseMargin) {
float a_data[] = {2.71828f, 3.14159f};
SimpleConstTensor a(TfLiteType::kTfLiteFloat32, {1, 2},
absl::MakeSpan(a_data));
float b_data[] = {2.72f, 3.14f};
SimpleConstTensor b(TfLiteType::kTfLiteFloat32, {1, 2},
absl::MakeSpan(b_data));
EXPECT_THAT(a, Approximately(EqualsTensor(b), /*margin=*/0.01));
}
TEST(TensorMatcherTest, DoesNotApproximatelyEqualWithTightMargin) {
float a_data[] = {2.71828f, 3.14159f};
SimpleConstTensor a(TfLiteType::kTfLiteFloat32, {1, 2},
absl::MakeSpan(a_data));
float b_data[] = {2.72f, 3.14f};
SimpleConstTensor b(TfLiteType::kTfLiteFloat32, {1, 2},
absl::MakeSpan(b_data));
EXPECT_THAT(a, Not(Approximately(EqualsTensor(b), /*margin=*/0.001)));
}
TEST(TensorMatcherTest, ApproximatelyEqualsWithLooseFraction) {
float a_data[] = {2.71828f, 3.14159f};
SimpleConstTensor a(TfLiteType::kTfLiteFloat32, {1, 2},
absl::MakeSpan(a_data));
float b_data[] = {2.72f, 3.14f};
SimpleConstTensor b(TfLiteType::kTfLiteFloat32, {1, 2},
absl::MakeSpan(b_data));
EXPECT_THAT(
a, Approximately(EqualsTensor(b), /*margin=*/0.0, /*fraction=*/0.999));
}
TEST(TensorMatcherTest, DoesNotApproximatelyEqualWithTightFraction) {
float a_data[] = {2.71828f, 3.14159f};
SimpleConstTensor a(TfLiteType::kTfLiteFloat32, {1, 2},
absl::MakeSpan(a_data));
float b_data[] = {2.72f, 3.14f};
SimpleConstTensor b(TfLiteType::kTfLiteFloat32, {1, 2},
absl::MakeSpan(b_data));
EXPECT_THAT(a, Not(Approximately(EqualsTensor(b), /*margin=*/0.0,
/*fraction=*/0.0001)));
}
} // namespace
} // namespace tflite
+98
View File
@@ -0,0 +1,98 @@
/* Copyright 2017 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/testing/message.h"
#include <istream>
#include <stack>
#include <string>
#include "tensorflow/lite/testing/tokenize.h"
namespace tflite {
namespace testing {
// A token processor that builds messages and forward calls to the current
// message object. Place a new message at the top of the stack when it start
// and remove it when it is finished.
class MessageStack : public TokenProcessor {
public:
// Start a new MessageStack with the given first_node, which will be used to
// process freestanding fields and submessages.
explicit MessageStack(Message* first_node) {
nodes_.push(first_node);
valid_ = true;
}
void ConsumeToken(std::string* token) override {
if (!valid_) return;
Message* current_node = nodes_.top();
if (*token == "{") {
// This is the beginning of a new message, names after the previous token.
if (previous_token_.empty()) {
valid_ = false;
return;
}
nodes_.push(current_node ? current_node->AddChild(previous_token_)
: nullptr);
previous_token_.clear();
} else if (*token == "}") {
// A message is being completed. There should be no previous token. Note
// that the top-level message never closes, so we should always have at
// least one entry in the stack.
if (nodes_.size() == 1 || !previous_token_.empty()) {
valid_ = false;
return;
}
if (current_node) {
current_node->Finish();
}
nodes_.pop();
} else if (*token == ":") {
// We reached the end of the 'key' portion of a field. Store the token
// until we have the 'value' portion.
if (previous_token_.empty()) {
valid_ = false;
return;
}
} else {
if (previous_token_.empty()) {
previous_token_.swap(*token);
} else {
// This is the 'value' portion of a field. The previous token is the
// 'key'.
if (current_node) {
current_node->SetField(previous_token_, *token);
}
previous_token_.clear();
}
}
}
bool valid() const { return valid_; }
private:
std::stack<Message*> nodes_;
std::string previous_token_;
bool valid_;
};
bool Message::Read(std::istream* input, Message* message) {
MessageStack stack(message);
Tokenize(input, &stack);
return stack.valid();
}
} // namespace testing
} // namespace tflite
+82
View File
@@ -0,0 +1,82 @@
/* Copyright 2017 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_TESTING_MESSAGE_H_
#define TENSORFLOW_LITE_TESTING_MESSAGE_H_
#include <memory>
#include <string>
#include <vector>
namespace tflite {
namespace testing {
// A Message is a textual protobuf-like structure that looks like:
// tag {
// f : "values"
// child {
// a : 1
// }
// }
// This class provides the framework for processing message but does not
// associate any particular behavior to fields and submessage. In order
// to properly parse a stream this class must be derived.
class Message {
public:
// Reads a stream, tokenizes it and create a new message under the given
// top-level message. Returns true if the parsing succeeded.
static bool Read(std::istream* input, Message* message);
Message() {}
virtual ~Message() {}
// Called when a new field is found. For example, when:
// f : "values"
// is found, it triggers:
// SetField("f", "values");
virtual void SetField(const std::string& name, const std::string& value) {}
// Called when a submessage is started. For example, when:
// child {
// is found, it triggers
// AddChild("child");
// If nullptr is returned, the contents of the submessage will be ignored.
// Otherwise, the returned Message will be used to handle new fields and new
// submessages. The caller should not take ownership of the returned pointer.
virtual Message* AddChild(const std::string& name) { return nullptr; }
// Called when a submessage is completed, that is, whenever a '}' is found.
virtual void Finish() {}
protected:
// Takes ownership of the given pointer. Subclasses can use this method if
// they don't want to implement their own ownership semantics.
Message* Store(Message* n) {
children_.emplace_back(n);
return n;
}
// Returns a list of all owned submessages.
const std::vector<std::unique_ptr<Message>>& Children() const {
return children_;
}
private:
std::vector<std::unique_ptr<Message>> children_;
};
} // namespace testing
} // namespace tflite
#endif // TENSORFLOW_LITE_TESTING_MESSAGE_H_
+122
View File
@@ -0,0 +1,122 @@
/* Copyright 2017 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/testing/message.h"
#include <map>
#include <sstream>
#include <string>
#include <gtest/gtest.h>
namespace tflite {
namespace testing {
namespace {
// A hierarchical, key-value store.
class TestMessage : public Message {
public:
TestMessage() {}
explicit TestMessage(const std::string& text_to_parse) {
std::stringstream ss(text_to_parse);
finished_ = Message::Read(&ss, this);
}
void SetField(const std::string& name, const std::string& value) override {
fields_[name] = value;
}
Message* AddChild(const std::string& name) override {
TestMessage* m = new TestMessage;
m->name_ = name;
return Store(m);
}
void Finish() override { finished_ = true; }
int NumChildren() const { return Children().size(); }
const TestMessage* GetChild(int i) const {
return dynamic_cast<TestMessage*>(Children()[i].get());
}
int NumFields() const { return fields_.size(); }
const std::string& GetField(const std::string& key) const {
return fields_.at(key);
}
const std::string& name() const { return name_; }
bool finished() const { return finished_; }
protected:
std::string name_;
std::map<std::string, std::string> fields_;
bool finished_ = false;
};
TEST(MessageTest, Simple) {
TestMessage message("x{a:1 b:2} y{} z{c:3} d:4");
ASSERT_TRUE(message.finished());
ASSERT_EQ(message.NumFields(), 1);
EXPECT_EQ(message.GetField("d"), "4");
ASSERT_EQ(message.NumChildren(), 3);
auto* x = message.GetChild(0);
EXPECT_EQ(x->name(), "x");
ASSERT_EQ(x->NumFields(), 2);
EXPECT_EQ(x->GetField("a"), "1");
EXPECT_EQ(x->GetField("b"), "2");
auto* y = message.GetChild(1);
EXPECT_EQ(y->name(), "y");
ASSERT_EQ(y->NumFields(), 0);
auto* z = message.GetChild(2);
EXPECT_EQ(z->name(), "z");
ASSERT_EQ(z->NumFields(), 1);
EXPECT_EQ(z->GetField("c"), "3");
}
TEST(MessageTest, Unnamed) {
TestMessage message("x{c:3} {} y{d:4}");
ASSERT_FALSE(message.finished());
EXPECT_EQ(message.NumChildren(), 1);
}
TEST(MessageTest, TooManyBraces) {
TestMessage message("x{c:3} } y{d:4}");
ASSERT_FALSE(message.finished());
EXPECT_EQ(message.NumChildren(), 1);
}
TEST(MessageTest, LeftoverToken) {
TestMessage message("x{c:3} z{test} y{d:4}");
ASSERT_FALSE(message.finished());
EXPECT_EQ(message.NumChildren(), 2);
}
TEST(MessageTest, MissingKey) {
TestMessage message("x{c:3} z{:test} y{d:4}");
ASSERT_FALSE(message.finished());
EXPECT_EQ(message.NumChildren(), 2);
}
TEST(MessageTest, MissingValue) {
TestMessage message("x{c:3} z{test:} y{d:4}");
ASSERT_FALSE(message.finished());
EXPECT_EQ(message.NumChildren(), 2);
}
} // namespace
} // namespace testing
} // namespace tflite
+234
View File
@@ -0,0 +1,234 @@
# 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.
# ==============================================================================
"""Converts a model's graph def into a tflite model with MLIR-based conversion."""
import os
import shlex
import subprocess
import tempfile
import numpy as np
from tensorflow.lite.python import lite
from tensorflow.lite.python import test_util as tflite_test_util
from tensorflow.lite.testing import zip_test_utils
from tensorflow.python.platform import resource_loader
from tensorflow.python.saved_model import signature_constants
def mlir_convert(
options,
saved_model_dir,
input_tensors,
output_tensors, # pylint: disable=unused-argument
**kwargs):
"""Convert a saved model into a tflite model with MLIR-based conversion.
Args:
options: A lite.testing.generate_examples_lib.Options instance.
saved_model_dir: Path to the saved model.
input_tensors: List of input tensor tuples `(name, shape, type)`.
output_tensors: List of output tensors (names).
**kwargs: Extra parameters.
Returns:
output tflite model, log_txt from conversion
or None, log_txt if it did not convert properly.
"""
test_params = kwargs.get("test_params", {})
extra_convert_options = kwargs.get("extra_convert_options",
zip_test_utils.ExtraConvertOptions())
tflite_model = None
log = ""
signature_key = signature_constants.DEFAULT_SERVING_SIGNATURE_DEF_KEY
converter = lite.TFLiteConverterV2.from_saved_model(
saved_model_dir, [signature_key])
converter.allow_custom_ops = extra_convert_options.allow_custom_ops
converter.experimental_new_quantizer = options.mlir_quantizer
if options.make_tf_ptq_tests:
if options.hlo_aware_conversion:
tf_quantization_mode = "DEFAULT"
else:
tf_quantization_mode = "LEGACY_INTEGER"
converter._experimental_tf_quantization_mode = tf_quantization_mode # pylint: disable=protected-access
if options.run_with_flex:
converter.target_spec.supported_ops = set(
[lite.OpsSet.TFLITE_BUILTINS, lite.OpsSet.SELECT_TF_OPS])
if options.enable_dynamic_update_slice:
converter._experimental_enable_dynamic_update_slice = True # pylint: disable=protected-access
converter.unfold_batchmatmul = options.unfold_batchmatmul
if test_params.get("dynamic_range_quantize", False):
converter.optimizations = [lite.Optimize.DEFAULT]
if options.experimental_low_bit_qat:
converter._experimental_low_bit_qat = ( # pylint: disable=protected-access
True
)
if options.experimental_unsafe_single_batch_rank_reduction:
converter._experimental_unsafe_single_batch_rank_reduction = ( # pylint: disable=protected-access
True
)
if test_params.get("fully_quantize", False):
converter.optimizations = [lite.Optimize.DEFAULT]
# Read the input range for the representative dataset from parameters.
min_value, max_value = test_params.get("input_range", (-1, 1))
def representative_dataset(input_tensors):
calibration_inputs = {}
for name, shape, dtype in input_tensors:
if shape:
dims = [1 if dim.value is None else dim.value for dim in shape.dims]
calibration_inputs[name] = np.random.uniform(
min_value, max_value, tuple(dims)).astype(dtype.as_numpy_dtype)
return calibration_inputs
def representative_dataset_gen():
for _ in range(100):
yield representative_dataset(input_tensors)
if test_params.get("quant_16x8", False):
converter.target_spec.supported_ops = [
lite.OpsSet
.EXPERIMENTAL_TFLITE_BUILTINS_ACTIVATIONS_INT16_WEIGHTS_INT8
]
else:
converter.target_spec.supported_ops = [
lite.OpsSet.TFLITE_BUILTINS_INT8
]
converter.representative_dataset = representative_dataset_gen
if extra_convert_options.inference_input_type:
converter.inference_input_type = (
extra_convert_options.inference_input_type)
if extra_convert_options.inference_output_type:
converter.inference_output_type = (
extra_convert_options.inference_output_type)
try:
tflite_model = converter.convert()
if options.expected_ops_in_converted_model:
ops_list = tflite_test_util.get_ops_list(tflite_model)
for expected_op in options.expected_ops_in_converted_model:
if expected_op not in ops_list:
# Force the test to fail.
tflite_model = None
raise ValueError(
"{} op not found in the converted model".format(expected_op))
except Exception as e: # pylint: disable=broad-except
log = str(e)
return tflite_model, log
def mlir_convert_file(graph_def_filename,
input_tensors,
output_tensors,
quantization_params=None,
additional_flags=""):
"""Convert a graphdef file into a tflite model with MLIR-based conversion.
NOTE: this currently shells out to the MLIR binary binary, but we would like
convert to Python API tooling in the future.
Args:
graph_def_filename: A GraphDef file.
input_tensors: List of input tensor tuples `(name, shape, type)`. name
should be a string. shape should be a tuple of integers. type should be a
string, for example 'DT_FLOAT'
output_tensors: List of output tensors (names).
quantization_params: parameters `(inference_type, min_values, max_values)`
to quantize the model.
additional_flags: A string of additional command line flags to be passed to
MLIR converter.
Returns:
output tflite model, log_txt from conversion
or None, log_txt if it did not convert properly.
"""
bin_path = resource_loader.get_path_to_datafile(
"../../compiler/mlir/lite/tf_tfl_translate"
)
if not os.path.exists(bin_path):
bin_path = resource_loader.get_path_to_datafile(
"../../../../compiler/mlir/lite/tf_tfl_translate"
)
with tempfile.NamedTemporaryFile() as output_file:
input_shapes = []
for input_tensor in input_tensors:
shape = input_tensor[1]
input_shapes.append(",".join([str(dim) for dim in shape]))
input_shapes_str = ":".join(input_shapes)
input_types = ",".join([x[2] for x in input_tensors])
cmd_list = [
bin_path,
"-tf-input-arrays=" + ",".join([x[0] for x in input_tensors]),
"-tf-input-data-types=" + input_types,
"-tf-input-shapes=" + input_shapes_str,
"-tf-output-arrays=" + ",".join(output_tensors),
]
if quantization_params is not None:
min_vals = ",".join([str(val) for val in quantization_params[1]])
max_vals = ",".join([str(val) for val in quantization_params[2]])
cmd_list.extend([
"-tf-inference-type=" + quantization_params[0],
"-tf-input-min-values=" + min_vals,
"-tf-input-max-values=" + max_vals,
"-emit-quant-adaptor-ops",
])
if additional_flags:
cmd_list.extend(shlex.split(additional_flags))
cmd_list.extend([graph_def_filename, "-o", output_file.name])
try:
with tempfile.NamedTemporaryFile() as stdout_file:
with tempfile.NamedTemporaryFile() as stderr_file:
result = subprocess.run(
cmd_list, stdout=stdout_file, stderr=stderr_file, check=False
)
exit_code = result.returncode
stdout_file.seek(0)
stderr_file.seek(0)
stdout = stdout_file.read().decode("utf-8", errors="replace")
stderr = stderr_file.read().decode("utf-8", errors="replace")
except FileNotFoundError:
exit_code = 127
stdout = ""
stderr = "Command not found: " + bin_path
except PermissionError:
exit_code = 126
stdout = ""
stderr = "Permission denied: " + bin_path
log = (
" ".join(cmd_list)
+ " exited with code %d" % exit_code
+ "\n------------------\n"
+ stdout
+ stderr
)
return (None if exit_code != 0 else output_file.read()), log
+92
View File
@@ -0,0 +1,92 @@
/* Copyright 2017 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.
==============================================================================*/
// NOTE: this is an example driver that converts a tflite model to TensorFlow.
// This is an example that will be integrated more tightly into tflite in
// the future.
//
// Usage: bazel run -c opt \
// tensorflow/lite/nnapi:nnapi_example -- <filename>
//
#include <dirent.h>
#include <cstdio>
#include <cstring>
#include <fstream>
#include <string>
#include "tensorflow/lite/testing/parse_testdata.h"
#include "tensorflow/lite/testing/tflite_driver.h"
std::string dirname(const std::string& s) {
return s.substr(0, s.find_last_of('/'));
}
bool Interpret(const char* examples_filename, bool use_nnapi) {
std::ifstream tflite_stream(examples_filename);
if (!tflite_stream.is_open()) {
fprintf(stderr, "Can't open input file.");
return false;
}
printf("Use nnapi is set to: %d\n", use_nnapi);
tflite::testing::TfLiteDriver test_driver(
use_nnapi ? tflite::testing::TfLiteDriver::DelegateType::kNnapi
: tflite::testing::TfLiteDriver::DelegateType::kNone);
test_driver.SetModelBaseDir(dirname(examples_filename));
if (!tflite::testing::ParseAndRunTests(&tflite_stream, &test_driver)) {
fprintf(stderr, "Results from tflite don't match.");
return false;
}
return true;
}
int main(int argc, char* argv[]) {
bool use_nnapi = true;
if (argc == 4) {
use_nnapi = strcmp(argv[3], "1") == 0 ? true : false;
}
if (argc < 3) {
fprintf(stderr,
"Compiled " __DATE__ __TIME__
"\n"
"Usage!!!: %s <tflite model> <examples to test> "
"{ use nn api i.e. 0,1}\n",
argv[0]);
return 1;
}
std::string base_dir = dirname(argv[1]);
DIR* dir = opendir(base_dir.c_str());
if (dir == nullptr) {
fprintf(stderr, "Can't open dir %s\n", base_dir.c_str());
return 1;
}
while (struct dirent* ent = readdir(dir)) {
std::string name = ent->d_name;
if (name.rfind(".txt") == name.length() - 4) {
printf("%s: ", name.c_str());
if (Interpret((base_dir + "/" + name).c_str(), use_nnapi)) {
printf(" %s\n", "OK");
} else {
printf(" %s\n", "FAIL");
}
}
}
closedir(dir);
return 0;
}
+68
View File
@@ -0,0 +1,68 @@
# 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.
# ==============================================================================
"""Test configs for abs."""
import tensorflow as tf
from tensorflow.lite.testing.zip_test_utils import create_tensor_data
from tensorflow.lite.testing.zip_test_utils import make_zip_of_tests
from tensorflow.lite.testing.zip_test_utils import register_make_test_function
@register_make_test_function()
def make_abs_tests(options):
"""Make a set of tests to do abs."""
# Chose a set of parameters
test_parameters = [{
"input_shape": [[], [1], [2, 3], [1, 1, 1, 1], [1, 3, 4, 3],
[3, 15, 14, 3], [3, 1, 2, 4, 6], [2, 2, 3, 4, 5, 6]],
"dtype": [tf.float32],
"dynamic_range_quantize": [False, True],
"fully_quantize": [False],
"input_range": [(-10, 10), (-10, 0)],
}, {
"input_shape": [[], [1], [2, 3], [1, 1, 1, 1], [1, 3, 4, 3],
[3, 15, 14, 3], [3, 1, 2, 4, 6], [2, 2, 3, 4, 5, 6]],
"dtype": [tf.float32],
"dynamic_range_quantize": [False],
"fully_quantize": [True],
"input_range": [(-10, 10)],
}, {
"input_shape": [[], [1], [2, 3], [1, 1, 1, 1],
[1, 3, 4, 3], [3, 15, 14, 3],
[3, 1, 2, 4, 6], [2, 2, 3, 4, 5, 6]],
"dtype": [tf.int16],
}]
def build_graph(parameters):
input_tensor = tf.compat.v1.placeholder(
dtype=parameters["dtype"],
name="input",
shape=parameters["input_shape"])
out = tf.abs(input_tensor)
return [input_tensor], [out]
def build_inputs(parameters, sess, inputs, outputs):
min_value, max_value = (-10, 10)
if "input_range" in parameters:
min_value, max_value = parameters["input_range"]
input_values = create_tensor_data(
parameters["dtype"],
parameters["input_shape"],
min_value=min_value,
max_value=max_value)
return [input_values], sess.run(
outputs, feed_dict=dict(zip(inputs, [input_values])))
make_zip_of_tests(options, test_parameters, build_graph, build_inputs)
+74
View File
@@ -0,0 +1,74 @@
# 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.
# ==============================================================================
"""Test configs for add_n."""
import tensorflow as tf
from tensorflow.lite.testing.zip_test_utils import create_tensor_data
from tensorflow.lite.testing.zip_test_utils import make_zip_of_tests
from tensorflow.lite.testing.zip_test_utils import register_make_test_function
@register_make_test_function()
def make_add_n_tests(options):
"""Make a set of tests for AddN op."""
test_parameters = [
{
"dtype": [tf.float32, tf.int32],
"input_shape": [[2, 5, 3, 1]],
"num_inputs": [2, 3, 4, 5],
"dynamic_range_quantize": [False],
},
{
"dtype": [tf.float32, tf.int32],
"input_shape": [[5]],
"num_inputs": [2, 3, 4, 5],
"dynamic_range_quantize": [False],
},
{
"dtype": [tf.float32, tf.int32],
"input_shape": [[]],
"num_inputs": [2, 3, 4, 5],
"dynamic_range_quantize": [False],
},
{
"dtype": [tf.float32],
"input_shape": [[]],
"num_inputs": [2, 3, 4, 5],
"dynamic_range_quantize": [True],
},
]
def build_graph(parameters):
"""Builds the graph given the current parameters."""
input_tensors = []
for i in range(parameters["num_inputs"]):
input_tensors.append(
tf.compat.v1.placeholder(
dtype=parameters["dtype"],
name="input_{}".format(i),
shape=parameters["input_shape"]))
out = tf.add_n(input_tensors)
return input_tensors, [out]
def build_inputs(parameters, sess, inputs, outputs):
"""Builds operand inputs for op."""
input_data = []
for _ in range(parameters["num_inputs"]):
input_data.append(
create_tensor_data(parameters["dtype"], parameters["input_shape"]))
return input_data, sess.run(
outputs, feed_dict={i: d for i, d in zip(inputs, input_data)})
make_zip_of_tests(options, test_parameters, build_graph, build_inputs)
@@ -0,0 +1,85 @@
# 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.
# ==============================================================================
"""Test configs for arg_min_max."""
import random
import tensorflow as tf
from tensorflow.lite.testing.zip_test_utils import create_tensor_data
from tensorflow.lite.testing.zip_test_utils import make_zip_of_tests
from tensorflow.lite.testing.zip_test_utils import register_make_test_function
@register_make_test_function()
def make_arg_min_max_tests(options):
"""Make a set of tests to do arg_max."""
test_parameters = [
{
"input_dtype": [tf.float32, tf.int32],
"input_shape": [[], [1, 1, 1, 3], [2, 3, 4, 5], [2, 3, 3], [5, 5],
[10]],
"output_type": [tf.int32, tf.int64],
"is_arg_max": [True],
"is_last_axis": [False],
"dynamic_range_quantize": [False, True],
},
{
"input_dtype": [tf.float32, tf.int32],
"input_shape": [[1], [2], [3], [4], [5], [6], [7], [8], [9], [10],
[2, 10], [3, 4, 50], [2, 3, 5, 100]],
"output_type": [tf.int32, tf.int64],
"is_arg_max": [False, True],
"is_last_axis": [True],
"dynamic_range_quantize": [False, True],
},
{
"input_dtype": [tf.bool],
"input_shape": [[1, 1, 1, 3], [2, 3, 4, 5], [2, 3, 3], [5, 5], [10]],
"output_type": [tf.int32, tf.int64],
"is_arg_max": [True],
"is_last_axis": [False],
},
]
def build_graph(parameters):
"""Build the topk op testing graph."""
input_value = tf.compat.v1.placeholder(
dtype=parameters["input_dtype"],
name="input",
shape=parameters["input_shape"])
if not parameters["is_last_axis"]:
axis = random.randint(0, max(len(parameters["input_shape"]) - 1, 0))
else:
axis = -1
if parameters["is_arg_max"]:
out = tf.math.argmax(
input=input_value, axis=axis, output_type=parameters["output_type"])
else:
out = tf.math.argmin(
input=input_value, axis=axis, output_type=parameters["output_type"])
return [input_value], [out]
def build_inputs(parameters, sess, inputs, outputs):
input_value = create_tensor_data(parameters["input_dtype"],
parameters["input_shape"])
return [input_value], sess.run(
outputs, feed_dict=dict(zip(inputs, [input_value])))
make_zip_of_tests(
options,
test_parameters,
build_graph,
build_inputs,
expected_tf_failures=8)
+52
View File
@@ -0,0 +1,52 @@
# Copyright 2022 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.
# ==============================================================================
"""Test configs for atan2."""
import tensorflow as tf
from tensorflow.lite.testing.zip_test_utils import create_tensor_data
from tensorflow.lite.testing.zip_test_utils import make_zip_of_tests
from tensorflow.lite.testing.zip_test_utils import register_make_test_function
@register_make_test_function()
def make_atan2_tests(options):
"""Make a set of tests to do atan2."""
test_parameters = [{
"input_dtype": [tf.float32, tf.float64],
"input_shape": [[], [1], [1, 2], [5, 6, 7, 8], [3, 4, 5, 6]]
}]
def build_graph(parameters):
"""Build the atan2 op testing graph."""
input_value1 = tf.compat.v1.placeholder(
dtype=parameters["input_dtype"],
name="y",
shape=parameters["input_shape"])
input_value2 = tf.compat.v1.placeholder(
dtype=parameters["input_dtype"],
name="x",
shape=parameters["input_shape"])
out = tf.math.atan2(input_value1, input_value2)
return [input_value1, input_value2], [out]
def build_inputs(parameters, sess, inputs, outputs):
input_value1 = create_tensor_data(parameters["input_dtype"],
parameters["input_shape"])
input_value2 = create_tensor_data(parameters["input_dtype"],
parameters["input_shape"])
return [input_value1, input_value2], sess.run(
outputs, feed_dict=dict(zip(inputs, [input_value1, input_value2])))
make_zip_of_tests(options, test_parameters, build_graph, build_inputs)
@@ -0,0 +1,135 @@
# 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.
# ==============================================================================
"""Test configs for batch_to_space_nd."""
import numpy as np
import tensorflow as tf
from tensorflow.lite.testing.zip_test_utils import create_tensor_data
from tensorflow.lite.testing.zip_test_utils import make_zip_of_tests
from tensorflow.lite.testing.zip_test_utils import register_make_test_function
@register_make_test_function()
def make_batch_to_space_nd_tests(options):
"""Make a set of tests to do batch_to_space_nd."""
test_parameters = [
{
"dtype": [tf.float32, tf.int64, tf.int32],
"input_shape": [[12, 3, 3, 1]],
"block_shape": [[1, 4], [2, 2], [3, 4]],
"crops": [[[0, 0], [0, 0]], [[1, 1], [1, 1]]],
"constant_block_shape": [True, False],
"constant_crops": [True, False],
"dynamic_range_quantize": [False],
},
# Single batch (no-op)
{
"dtype": [tf.float32],
"input_shape": [[1, 3, 3, 1]],
"block_shape": [[1, 1]],
"crops": [[[0, 0], [0, 0]], [[1, 1], [1, 1]]],
"constant_block_shape": [True],
"constant_crops": [True],
"dynamic_range_quantize": [True, False],
},
{
"dtype": [tf.float32],
"input_shape": [[1, 3, 3, 1]],
"block_shape": [[1, 1]],
"crops": [[[0, 0], [0, 0]], [[1, 1], [1, 1]]],
"constant_block_shape": [True],
"constant_crops": [True],
"fully_quantize": [True],
"quant_16x8": [False, True],
},
# 3D use case.
{
"dtype": [tf.float32],
"input_shape": [[1, 3, 3]],
"block_shape": [[1]],
"crops": [[[0, 0]], [[1, 1]]],
"constant_block_shape": [True],
"constant_crops": [True],
"dynamic_range_quantize": [True, False],
},
{
"dtype": [tf.float32],
"input_shape": [[1, 3, 3]],
"block_shape": [[1]],
"crops": [[[0, 0]], [[1, 1]]],
"constant_block_shape": [True],
"constant_crops": [True],
"fully_quantize": [True],
"quant_16x8": [False, True],
},
]
if options.run_with_flex:
# Non-4D use case: 1 batch dimension, 3 spatial dimensions, 2 others.
test_parameters = test_parameters + [{
"dtype": [tf.float32],
"input_shape": [[8, 2, 2, 2, 1, 1]],
"block_shape": [[2, 2, 2]],
"crops": [[[0, 0], [0, 0], [0, 0]]],
"constant_block_shape": [True, False],
"constant_crops": [True, False],
"dynamic_range_quantize": [False],
}]
def build_graph(parameters):
"""Build a batch_to_space graph given `parameters`."""
input_tensor = tf.compat.v1.placeholder(
dtype=parameters["dtype"],
name="input",
shape=parameters["input_shape"])
input_tensors = [input_tensor]
# Get block_shape either as a const or as a placeholder (tensor).
if parameters["constant_block_shape"]:
block_shape = parameters["block_shape"]
else:
shape = [len(parameters["block_shape"])]
block_shape = tf.compat.v1.placeholder(
dtype=tf.int32, name="shape", shape=shape)
input_tensors.append(block_shape)
# Get crops either as a const or as a placeholder (tensor).
if parameters["constant_crops"]:
crops = parameters["crops"]
else:
shape = [len(parameters["crops"]), 2]
crops = tf.compat.v1.placeholder(
dtype=tf.int32, name="crops", shape=shape)
input_tensors.append(crops)
out = tf.batch_to_space(input_tensor, block_shape, crops)
return input_tensors, [out]
def build_inputs(parameters, sess, inputs, outputs):
values = [
create_tensor_data(
parameters["dtype"],
parameters["input_shape"],
min_value=-1.0,
max_value=1.0,
)
]
if not parameters["constant_block_shape"]:
values.append(np.array(parameters["block_shape"]))
if not parameters["constant_crops"]:
values.append(np.array(parameters["crops"]))
return values, sess.run(outputs, feed_dict=dict(zip(inputs, values)))
make_zip_of_tests(options, test_parameters, build_graph, build_inputs)
@@ -0,0 +1,107 @@
# 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.
# ==============================================================================
"""Test configs for batchmatmul."""
import tensorflow as tf
from tensorflow.lite.testing.zip_test_utils import create_tensor_data
from tensorflow.lite.testing.zip_test_utils import make_zip_of_tests
from tensorflow.lite.testing.zip_test_utils import register_make_test_function
@register_make_test_function("make_batchmatmul_tests")
def make_batchmatmul_tests(options):
"""Make a set of tests to do basic batch matrix multiply."""
test_parameters = [
{
"dtype": [tf.float32],
"shapes": [((3, 4, 7), (7, 9), (3, 4, 7), (7, 9)),
((None, 4, 5), (None, 5, 6), (3, 4, 5), (3, 5, 6)),
((None, 1, 3, 4), (None, 4, 2), (2, 1, 3, 4), (5, 4, 2)),
((None, None, None, 3, 4), (None, None, None, 4, 3),
(2, 2, 2, 3, 4), (2, 2, 2, 4, 3))],
"adjoint_b": [False, True],
"adjoint_a": [False, True],
"rhs_constant": [False],
"fully_quantize": [False, True],
},
]
def swap_last_two_dims(*args):
"""Return a tuple with the last two dimensions swapped."""
return args[:-2] + (args[-1],) + (args[-2],)
def build_graph(parameters):
"""Build a simple graph with BatchMatMul."""
placeholder0_shape = parameters["shapes"][0]
adj_a = parameters["adjoint_a"]
adj_b = parameters["adjoint_b"]
rhs_constant = parameters["rhs_constant"]
if adj_a:
placeholder0_shape = swap_last_two_dims(*placeholder0_shape)
input0_tensor = tf.compat.v1.placeholder(
dtype=parameters["dtype"], shape=placeholder0_shape)
if rhs_constant:
if adj_b:
constant1_shape = swap_last_two_dims(*parameters["shapes"][3])
else:
constant1_shape = parameters["shapes"][3]
data = create_tensor_data(
parameters["dtype"], constant1_shape, min_value=-1.0, max_value=1.0)
input1_constant = tf.constant(
data, shape=constant1_shape, dtype=parameters["dtype"])
out = tf.matmul(
input0_tensor, input1_constant, adjoint_a=adj_a, adjoint_b=adj_b)
return [input0_tensor], [out]
else:
if adj_b:
placeholder1_shape = swap_last_two_dims(*parameters["shapes"][1])
else:
placeholder1_shape = parameters["shapes"][1]
input1_tensor = tf.compat.v1.placeholder(
dtype=parameters["dtype"], shape=placeholder1_shape)
out = tf.matmul(
input0_tensor, input1_tensor, adjoint_a=adj_a, adjoint_b=adj_b)
return [input0_tensor, input1_tensor], [out]
def build_inputs(parameters, sess, inputs, outputs):
"""Feed inputs, assign variables, and freeze graph."""
input0_shape = parameters["shapes"][2]
adj_a = parameters["adjoint_a"]
adj_b = parameters["adjoint_b"]
rhs_constant = parameters["rhs_constant"]
if adj_a:
input0_shape = swap_last_two_dims(*input0_shape)
input0_value = create_tensor_data(
parameters["dtype"], input0_shape, min_value=-1.0, max_value=1.0)
if rhs_constant:
output_values = sess.run(
outputs, feed_dict=dict(zip(inputs, [input0_value])))
return [input0_value], output_values
else:
input1_shape = parameters["shapes"][
3] if not adj_b else swap_last_two_dims(*parameters["shapes"][3])
input1_value = create_tensor_data(
parameters["dtype"], input1_shape, min_value=-1.0, max_value=1.0)
output_values = sess.run(
outputs, feed_dict=dict(zip(inputs, [input0_value, input1_value])))
return [input0_value, input1_value], output_values
options.disable_batchmatmul_unfold = True
make_zip_of_tests(
options,
test_parameters,
build_graph,
build_inputs,
expected_tf_failures=0)
@@ -0,0 +1,393 @@
# 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.
# ==============================================================================
"""Test configs for binary_op."""
import tensorflow as tf
from tensorflow.lite.testing.zip_test_utils import create_tensor_data
from tensorflow.lite.testing.zip_test_utils import make_zip_of_tests
from tensorflow.lite.testing.zip_test_utils import register_make_test_function
def make_binary_op_tests(options,
binary_operator,
allow_fully_quantize=False,
expected_tf_failures=0,
test_parameters=None):
"""Make a set of tests to do binary ops with and without broadcast."""
if test_parameters is None:
test_parameters = []
test_parameters = test_parameters + [
# Avoid creating all combinations to keep the test size small.
{
"dtype": [tf.float32, tf.int32],
"input_shape_1": [[1, 3, 4, 3]],
"input_shape_2": [[1, 3, 4, 3]],
"activation": [True],
"fully_quantize": [False],
"dynamic_range_quantize": [False],
},
{
"dtype": [tf.float32],
"input_shape_1": [[5]],
"input_shape_2": [[5]],
"activation": [False, True],
"fully_quantize": [False],
"dynamic_range_quantize": [False],
},
{
"dtype": [tf.float32, tf.int32, tf.int64],
"input_shape_1": [[1, 3, 4, 3]],
"input_shape_2": [[3]],
"activation": [True, False],
"fully_quantize": [False],
"dynamic_range_quantize": [False],
},
{
"dtype": [tf.float32, tf.int32],
"input_shape_1": [[3]],
"input_shape_2": [[1, 3, 4, 3]],
"activation": [True, False],
"fully_quantize": [False],
"dynamic_range_quantize": [False],
},
{
"dtype": [tf.float32],
"input_shape_1": [[]],
"input_shape_2": [[]],
"activation": [False],
"fully_quantize": [False],
"dynamic_range_quantize": [False],
},
{
"dtype": [tf.float32],
"input_shape_1": [[1, 3, 4, 3]],
"input_shape_2": [[1, 3, 4, 3]],
"activation": [False],
"fully_quantize": [True],
"dynamic_range_quantize": [False],
},
{
"dtype": [tf.float32],
"input_shape_1": [[5]],
"input_shape_2": [[5]],
"activation": [False],
"fully_quantize": [True],
"dynamic_range_quantize": [False],
},
{
"dtype": [tf.float32],
"input_shape_1": [[1, 3, 4, 3]],
"input_shape_2": [[3]],
"activation": [False],
"fully_quantize": [True],
"dynamic_range_quantize": [False],
},
{
"dtype": [tf.float32],
"input_shape_1": [[3]],
"input_shape_2": [[1, 3, 4, 3]],
"activation": [False],
"fully_quantize": [True],
"dynamic_range_quantize": [False],
},
{
"dtype": [tf.float32],
"input_shape_1": [[]],
"input_shape_2": [[]],
"activation": [False],
"fully_quantize": [True],
"dynamic_range_quantize": [False],
},
{
"dtype": [tf.float32],
"input_shape_1": [[1, 3, 4, 3]],
"input_shape_2": [[1, 3, 4, 3]],
"activation": [False],
"fully_quantize": [False],
"dynamic_range_quantize": [True],
},
{
"dtype": [tf.float32],
"input_shape_1": [[5]],
"input_shape_2": [[5]],
"activation": [False],
"fully_quantize": [False],
"dynamic_range_quantize": [True],
},
{
"dtype": [tf.float32],
"input_shape_1": [[1, 3, 4, 3]],
"input_shape_2": [[3]],
"activation": [False],
"fully_quantize": [False],
"dynamic_range_quantize": [True],
},
{
"dtype": [tf.float32],
"input_shape_1": [[3]],
"input_shape_2": [[1, 3, 4, 3]],
"activation": [False],
"fully_quantize": [False],
"dynamic_range_quantize": [True],
},
{
"dtype": [tf.float32],
"input_shape_1": [[]],
"input_shape_2": [[]],
"activation": [False],
"fully_quantize": [False],
"dynamic_range_quantize": [True],
},
]
# float64 types are supported via flex only.
if options.run_with_flex:
test_parameters = test_parameters + [
{
"dtype": [tf.float64],
"input_shape_1": [[7]],
"input_shape_2": [[7]],
"activation": [False],
"fully_quantize": [False],
"dynamic_range_quantize": [False],
},
]
if not options.skip_high_dimension_inputs:
test_parameters = test_parameters + [
# High dimension broadcasting support in MLIR converter.
# Note(b/204360746): XNNPack delegate don't support high dimension.
{
"dtype": [tf.float32],
"input_shape_1": [[8, 7, 6, 5, 4, 3, 2, 1],
[8, 7, 6, 5, None, 3, 2, 1], [2, None]],
"input_shape_2": [[4, 3, 2, 1], [None, 3, 2, 1]],
"activation": [False],
"fully_quantize": [False],
"dynamic_range_quantize": [False],
"dynamic_size_value": [4, 1],
}
]
# test_parameters include fully_quantize option only when
# allow_fully_quantize is True.
if not allow_fully_quantize:
test_parameters = [
test_parameter for test_parameter in test_parameters
if True not in test_parameter["fully_quantize"]
]
def populate_dynamic_shape(parameters, input_shape):
return [
parameters["dynamic_size_value"] if x is None else x
for x in input_shape
]
def build_graph(parameters):
"""Builds the graph given the current parameters."""
input1 = tf.compat.v1.placeholder(
dtype=parameters["dtype"],
name="input1",
shape=parameters["input_shape_1"])
input2 = tf.compat.v1.placeholder(
dtype=parameters["dtype"],
name="input2",
shape=parameters["input_shape_2"])
out = binary_operator(input1, input2)
if parameters["activation"] and (parameters["dtype"] != tf.int32 and
parameters["dtype"] != tf.int64):
out = tf.nn.relu(out)
return [input1, input2], [out]
def build_inputs(parameters, sess, inputs, outputs):
"""Builds operand inputs for op."""
input_shape_1 = populate_dynamic_shape(parameters,
parameters["input_shape_1"])
input_shape_2 = populate_dynamic_shape(parameters,
parameters["input_shape_2"])
if allow_fully_quantize:
input1 = create_tensor_data(
parameters["dtype"], input_shape_1, min_value=-1, max_value=1)
input2 = create_tensor_data(
parameters["dtype"], input_shape_2, min_value=-1, max_value=1)
else:
input1 = create_tensor_data(parameters["dtype"], input_shape_1)
input2 = create_tensor_data(parameters["dtype"], input_shape_2)
return [input1, input2], sess.run(
outputs, feed_dict={
inputs[0]: input1,
inputs[1]: input2
})
make_zip_of_tests(
options,
test_parameters,
build_graph,
build_inputs,
expected_tf_failures=expected_tf_failures)
def make_binary_op_tests_func(binary_operator):
"""Return a function that does a test on a binary operator."""
return lambda options: make_binary_op_tests(options, binary_operator)
@register_make_test_function()
def make_add_tests(options):
"""Make zip tests for add op with uint32 and int16 case."""
test_parameters = [
{
"dtype": [tf.uint32],
"input_shape_1": [[1, 3, 3, 3], [1], [3, 3]],
"input_shape_2": [[3], [1]],
"activation": [False],
"fully_quantize": [False],
"dynamic_range_quantize": [False],
},
{
"dtype": [tf.int16],
"input_shape_1": [[1, 3, 3, 3], [1], [3, 3]],
"input_shape_2": [[3], [1]],
"activation": [False],
"fully_quantize": [False],
"dynamic_range_quantize": [False],
},
]
make_binary_op_tests(
options,
tf.add,
allow_fully_quantize=True,
test_parameters=test_parameters)
@register_make_test_function()
def make_div_tests(options):
"""Make zip tests for div op with 5D case."""
test_parameters = [
{
"dtype": [tf.float32],
"input_shape_1": [[1, 3, 3, 3, 3]],
"input_shape_2": [[3]],
"activation": [False],
"fully_quantize": [False],
"dynamic_range_quantize": [False, True],
},
]
make_binary_op_tests(
options, tf.compat.v1.div, test_parameters=test_parameters)
@register_make_test_function()
def make_sub_tests(options):
"""Make zip tests for sub op with additional cases."""
test_parameters = [
{
"dtype": [tf.float32],
"input_shape_1": [[1, 3, 3, 3, 3]],
"input_shape_2": [[3]],
"activation": [False],
"fully_quantize": [False],
"dynamic_range_quantize": [False, True],
},
]
make_binary_op_tests(
options,
tf.subtract,
allow_fully_quantize=True,
test_parameters=test_parameters)
@register_make_test_function()
def make_mul_tests(options):
"""Make zip tests for mul op with additional complex cases."""
test_parameters = [
{
"dtype": [tf.complex64],
"input_shape_1": [[1, 3, 3, 3, 3]],
"input_shape_2": [[3]],
"activation": [False],
"fully_quantize": [False],
"dynamic_range_quantize": [False],
},
{
"dtype": [tf.int16],
"input_shape_1": [[1, 3, 3, 3]],
"input_shape_2": [[3], [1, 3, 3, 3]],
"activation": [False],
"fully_quantize": [False],
"dynamic_range_quantize": [False],
},
{
"dtype": [tf.uint32],
"input_shape_1": [[1, 3, 3, 3]],
"input_shape_2": [[3], [1, 3, 3, 3]],
"activation": [False],
"fully_quantize": [False],
"dynamic_range_quantize": [False],
},
]
make_binary_op_tests(
options,
tf.multiply,
allow_fully_quantize=True,
test_parameters=test_parameters)
@register_make_test_function()
def make_pow_tests(options):
make_binary_op_tests(options, tf.pow, expected_tf_failures=7)
@register_make_test_function()
def make_floor_div_tests(options):
"""Make zip tests for floor_div op with int16 case."""
test_parameters = [
{
"dtype": [tf.int8, tf.int16],
"input_shape_1": [[1, 3, 3, 3, 3]],
"input_shape_2": [[3]],
"activation": [False],
"fully_quantize": [False],
"dynamic_range_quantize": [False],
},
]
make_binary_op_tests(
options, tf.math.floordiv, test_parameters=test_parameters
)
@register_make_test_function()
def make_floor_mod_tests(options):
"""Make zip tests for floor_mod op with int16 case."""
test_parameters = [
{
"dtype": [tf.int8, tf.int16],
"input_shape_1": [[1, 3, 3, 3, 3]],
"input_shape_2": [[3]],
"activation": [False],
"fully_quantize": [False],
"dynamic_range_quantize": [False],
},
]
make_binary_op_tests(
options, tf.math.floormod, test_parameters=test_parameters
)
@register_make_test_function()
def make_squared_difference_tests(options):
make_binary_op_tests(
options, tf.math.squared_difference, allow_fully_quantize=True)
@@ -0,0 +1,86 @@
# 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.
# ==============================================================================
"""Test configs for bitcast."""
import tensorflow as tf
from tensorflow.lite.testing.zip_test_utils import create_tensor_data
from tensorflow.lite.testing.zip_test_utils import make_zip_of_tests
from tensorflow.lite.testing.zip_test_utils import register_make_test_function
@register_make_test_function()
def make_bitcast_tests(options):
"""Generate examples for bitcast."""
test_parameters = [
{
"input_dtype": [tf.int32],
"output_dtype": [tf.uint32],
"input_shape": [[], [1], [1, 2], [3, 4, 5, 6]],
},
{
"input_dtype": [tf.uint32],
"output_dtype": [tf.int32],
"input_shape": [[], [1], [1, 2], [3, 4, 5, 6]],
},
{
"input_dtype": [tf.uint32],
"output_dtype": [tf.int16],
"input_shape": [[], [1], [1, 2], [3, 4, 5, 6]],
},
{
"input_dtype": [tf.int16],
"output_dtype": [tf.uint32],
"input_shape": [[2], [1, 2], [1, 2, 2], [3, 4, 5, 6, 2]],
},
{
"input_dtype": [tf.int32],
"output_dtype": [tf.int16],
"input_shape": [[], [1], [1, 2], [3, 4, 5, 6]],
},
{
"input_dtype": [tf.uint16],
"output_dtype": [tf.uint32],
"input_shape": [[2], [1, 2], [1, 2, 2], [3, 4, 5, 6, 2]],
},
{
"input_dtype": [tf.float32],
"output_dtype": [tf.int16],
"input_shape": [[], [1], [1, 2], [3, 4, 5, 6]],
},
{
"input_dtype": [tf.int16],
"output_dtype": [tf.float32],
"input_shape": [[2], [1, 2], [1, 2, 2], [3, 4, 5, 6, 2]],
}
]
def build_graph(parameters):
"""Build the bitcast testing graph."""
input_value = tf.compat.v1.placeholder(
dtype=parameters["input_dtype"],
name="input",
shape=parameters["input_shape"],
)
out = tf.bitcast(input_value, parameters["output_dtype"])
return [input_value], [out]
def build_inputs(parameters, sess, inputs, outputs):
input_value = create_tensor_data(
parameters["input_dtype"], parameters["input_shape"]
)
return [input_value], sess.run(
outputs, feed_dict=dict(zip(inputs, [input_value]))
)
make_zip_of_tests(options, test_parameters, build_graph, build_inputs)
@@ -0,0 +1,78 @@
# 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.
# ==============================================================================
"""Test configs for bitwise_xor operator."""
import tensorflow as tf
from tensorflow.lite.testing.zip_test_utils import create_tensor_data
from tensorflow.lite.testing.zip_test_utils import make_zip_of_tests
from tensorflow.lite.testing.zip_test_utils import register_make_test_function
@register_make_test_function()
def make_bitwise_xor_tests(options):
"""Generate examples for bitwise_xor."""
test_parameters = [
{
"input_dtype": [
tf.uint8,
tf.int8,
tf.uint16,
tf.int16,
tf.uint32,
tf.int32,
],
"input_shape_pair": [
([], []),
([2, 3, 4], [2, 3, 4]),
([1, 1, 1, 3], [1, 1, 1, 3]),
([5, 5], [1]),
([10], [2, 4, 10]),
([2, 3, 3], [2, 3]), # this test case is intended to fail
],
},
]
def build_graph(parameters):
"""Build the bitwise_xor testing graph."""
input_value1 = tf.compat.v1.placeholder(
dtype=parameters["input_dtype"],
name="input1",
shape=parameters["input_shape_pair"][0],
)
input_value2 = tf.compat.v1.placeholder(
dtype=parameters["input_dtype"],
name="input2",
shape=parameters["input_shape_pair"][1],
)
out = tf.bitwise.bitwise_xor(input_value1, input_value2)
return [input_value1, input_value2], [out]
def build_inputs(parameters, sess, inputs, outputs):
input_value1 = create_tensor_data(
parameters["input_dtype"], parameters["input_shape_pair"][0]
)
input_value2 = create_tensor_data(
parameters["input_dtype"], parameters["input_shape_pair"][1]
)
return [input_value1, input_value2], sess.run(
outputs, feed_dict=dict(zip(inputs, [input_value1, input_value2]))
)
make_zip_of_tests(
options,
test_parameters,
build_graph,
build_inputs,
expected_tf_failures=6,
)
@@ -0,0 +1,62 @@
# 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.
# ==============================================================================
"""Test configs for broadcast_args."""
import numpy as np
import tensorflow as tf
from tensorflow.lite.testing.zip_test_utils import make_zip_of_tests
from tensorflow.lite.testing.zip_test_utils import register_make_test_function
@register_make_test_function("make_broadcast_args_tests")
def make_broadcast_args_tests(options):
"""Make a set of tests to do broadcast_args."""
# Chose a set of parameters
test_parameters = [{
"dtype": [tf.int64, tf.int32],
"input1_shape": [[1], [4], [3, 4], [1, 3, 4]],
"input2_shape": [[6, 4, 3, 4]],
}, {
"dtype": [tf.int64, tf.int32],
"input1_shape": [[1, 4, 0]],
"input2_shape": [[3, 1, 0], [3, 4, 1]],
}]
def build_graph(parameters):
"""Build the graph for broadcast_args tests."""
shape1_tensor = tf.compat.v1.placeholder(
dtype=parameters["dtype"],
name="input1",
shape=[len(parameters["input1_shape"])])
shape2_tensor = tf.compat.v1.placeholder(
dtype=parameters["dtype"],
name="input2",
shape=[len(parameters["input2_shape"])])
out = tf.raw_ops.BroadcastArgs(s0=shape1_tensor, s1=shape2_tensor)
return [shape1_tensor, shape2_tensor], [out]
def build_inputs(parameters, sess, inputs, outputs):
input_values = [
np.array(parameters["input1_shape"]).astype(
parameters["dtype"].as_numpy_dtype),
np.array(parameters["input2_shape"]).astype(
parameters["dtype"].as_numpy_dtype),
]
return input_values, sess.run(
outputs, feed_dict=dict(zip(inputs, input_values)))
make_zip_of_tests(options, test_parameters, build_graph, build_inputs)
@@ -0,0 +1,68 @@
# 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.
# ==============================================================================
"""Test configs for broadcast_gradient_args."""
import numpy as np
import tensorflow as tf
from tensorflow.lite.testing.zip_test_utils import ExtraConvertOptions
from tensorflow.lite.testing.zip_test_utils import make_zip_of_tests
from tensorflow.lite.testing.zip_test_utils import register_make_test_function
@register_make_test_function()
def make_broadcast_gradient_args_tests(options):
"""Make a set of tests to do broadcast_gradient_args."""
test_parameters = [{
'input_case': ['ALL_EQUAL', 'ONE_DIM', 'NON_BROADCASTABLE'],
'dtype': [tf.dtypes.int32, tf.dtypes.int64],
}]
def build_graph(parameters):
"""Build the op testing graph."""
input1 = tf.compat.v1.placeholder(dtype=parameters['dtype'], name='input1')
input2 = tf.compat.v1.placeholder(dtype=parameters['dtype'], name='input2')
output1, output2 = tf.raw_ops.BroadcastGradientArgs(s0=input1, s1=input2)
return [input1, input2], [output1, output2]
def build_inputs(parameters, sess, inputs, outputs):
dtype = parameters['dtype'].as_numpy_dtype()
if parameters['input_case'] == 'ALL_EQUAL':
values = [
np.array([2, 4, 1, 3], dtype=dtype),
np.array([2, 4, 1, 3], dtype=dtype)
]
elif parameters['input_case'] == 'ONE_DIM':
values = [
np.array([2, 4, 1, 3], dtype=dtype),
np.array([2, 1, 1, 3], dtype=dtype)
]
elif parameters['input_case'] == 'NON_BROADCASTABLE':
values = [
np.array([2, 4, 1, 3], dtype=dtype),
np.array([2, 5, 1, 3], dtype=dtype)
]
return values, sess.run(outputs, feed_dict=dict(zip(inputs, values)))
extra_convert_options = ExtraConvertOptions()
extra_convert_options.allow_custom_ops = True
make_zip_of_tests(
options,
test_parameters,
build_graph,
build_inputs,
extra_convert_options,
expected_tf_failures=2)
@@ -0,0 +1,72 @@
# 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.
# ==============================================================================
"""Test configs for broadcast_to."""
import tensorflow as tf
from tensorflow.lite.testing.zip_test_utils import create_tensor_data
from tensorflow.lite.testing.zip_test_utils import make_zip_of_tests
from tensorflow.lite.testing.zip_test_utils import register_make_test_function
@register_make_test_function("make_broadcast_to_tests")
def make_broadcast_to_tests(options):
"""Make a set of tests to do broadcast_to."""
# Chose a set of parameters
test_parameters = [{
"input_dtype": [tf.float32, tf.int32],
"input_shape": [[1, 2], [2, 3, 4], [1], [2, 5, 2, 3, 4]],
"output_shape": [[3, 1, 2], [5, 2, 3, 4], [10, 10],
[1, 2, 1, 2, 5, 2, 3, 4]],
}, {
"input_dtype": [tf.float32, tf.int32],
"input_shape": [[3, 2, 3, 4, 5, 6, 7, 8]],
"output_shape": [[3, 2, 3, 4, 5, 6, 7, 8]],
}, {
"input_dtype": [tf.float32, tf.int32],
"input_shape": [[1, 3, 1, 2, 1, 4, 1, 1]],
"output_shape": [[2, 3, 1, 2, 2, 4, 1, 1]],
}, {
"input_dtype": [tf.float32, tf.int32],
"input_shape": [[2, 1, 1, 2, 1, 4, 1, 1]],
"output_shape": [[2, 3, 2, 2, 2, 4, 1, 1]],
}, {
"input_dtype": [tf.float32, tf.int32],
"input_shape": [[3, 4, 1]],
"output_shape": [[3, 4, 0]],
}]
def build_graph(parameters):
"""Build the graph for cond tests."""
input_tensor = tf.compat.v1.placeholder(
dtype=parameters["input_dtype"],
name="input",
shape=parameters["input_shape"])
out = tf.broadcast_to(input_tensor, shape=parameters["output_shape"])
return [input_tensor], [out]
def build_inputs(parameters, sess, inputs, outputs):
input_values = [
create_tensor_data(parameters["input_dtype"], parameters["input_shape"])
]
return input_values, sess.run(
outputs, feed_dict=dict(zip(inputs, input_values)))
make_zip_of_tests(
options,
test_parameters,
build_graph,
build_inputs,
expected_tf_failures=16)
+148
View File
@@ -0,0 +1,148 @@
# 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.
# ==============================================================================
"""Test configs for cast."""
import tensorflow as tf
from tensorflow.lite.testing.zip_test_utils import create_tensor_data
from tensorflow.lite.testing.zip_test_utils import make_zip_of_tests
from tensorflow.lite.testing.zip_test_utils import register_make_test_function
@register_make_test_function()
def make_cast_tests(options):
"""Generate examples for cast."""
test_parameters = [
{
"input_dtype": [tf.float32],
"output_dtype": [tf.int16],
"input_shape": [[], [1], [1, 2], [5, 6, 7, 8], [3, 4, 5, 6]],
},
{
"input_dtype": [tf.int16],
"output_dtype": [tf.float32],
"input_shape": [[], [1], [1, 2], [5, 6, 7, 8], [3, 4, 5, 6]],
},
{
"input_dtype": [tf.int32],
"output_dtype": [tf.float32],
"input_shape": [[], [1], [1, 2], [5, 6, 7, 8], [3, 4, 5, 6]],
},
{
"input_dtype": [tf.int8],
"output_dtype": [tf.float32],
"input_shape": [[], [1], [1, 2], [5, 6, 7, 8], [3, 4, 5, 6]],
},
{
"input_dtype": [tf.float32],
"output_dtype": [tf.int8],
"input_shape": [[], [1], [1, 2], [5, 6, 7, 8], [3, 4, 5, 6]],
},
{
"input_dtype": [tf.uint16],
"output_dtype": [tf.float32],
"input_shape": [[], [1], [1, 2], [5, 6, 7, 8], [3, 4, 5, 6]],
},
{
"input_dtype": [tf.uint32],
"output_dtype": [tf.int32],
"input_shape": [[], [1], [1, 2], [5, 6, 7, 8], [3, 4, 5, 6]],
},
{
"input_dtype": [tf.uint8],
"output_dtype": [tf.int8],
"input_shape": [[], [1], [1, 2], [5, 6, 7, 8], [3, 4, 5, 6]],
},
{
"input_dtype": [tf.int8],
"output_dtype": [tf.uint8],
"input_shape": [[], [1], [1, 2], [5, 6, 7, 8], [3, 4, 5, 6]],
},
{
"input_dtype": [tf.uint16],
"output_dtype": [tf.int16],
"input_shape": [[], [1], [1, 2], [5, 6, 7, 8], [3, 4, 5, 6]],
},
{
"input_dtype": [tf.int16],
"output_dtype": [tf.uint16],
"input_shape": [[], [1], [1, 2], [5, 6, 7, 8], [3, 4, 5, 6]],
},
{
"input_dtype": [tf.int32],
"output_dtype": [tf.float64],
"input_shape": [[], [1], [1, 2], [5, 6, 7, 8], [3, 4, 5, 6]],
},
{
"input_dtype": [tf.float64],
"output_dtype": [tf.int32],
"input_shape": [[], [1], [1, 2], [5, 6, 7, 8], [3, 4, 5, 6]],
},
{
"input_dtype": [tf.float32],
"output_dtype": [tf.float64],
"input_shape": [[], [1], [1, 2], [5, 6, 7, 8], [3, 4, 5, 6]],
},
{
"input_dtype": [tf.float64],
"output_dtype": [tf.float32],
"input_shape": [[], [1], [1, 2], [5, 6, 7, 8], [3, 4, 5, 6]],
},
{
"input_dtype": [tf.int64],
"output_dtype": [tf.float64],
"input_shape": [[], [1], [1, 2], [5, 6, 7, 8], [3, 4, 5, 6]],
},
{
"input_dtype": [tf.float64],
"output_dtype": [tf.int64],
"input_shape": [[], [1], [1, 2], [5, 6, 7, 8], [3, 4, 5, 6]],
},
{
"input_dtype": [tf.float32],
"output_dtype": [tf.float16],
"input_shape": [[], [1], [1, 2], [5, 6, 7, 8], [3, 4, 5, 6]],
},
{
"input_dtype": [tf.float16],
"output_dtype": [tf.float32],
"input_shape": [[], [1], [1, 2], [5, 6, 7, 8], [3, 4, 5, 6]],
},
{
"input_dtype": [tf.bfloat16],
"output_dtype": [tf.float32],
"input_shape": [[], [1], [1, 2], [5, 6, 7, 8], [3, 4, 5, 6]],
},
{
"input_dtype": [tf.float32],
"output_dtype": [tf.bfloat16],
"input_shape": [[], [1], [1, 2], [5, 6, 7, 8], [3, 4, 5, 6]],
},
]
def build_graph(parameters):
"""Build the cast testing graph."""
input_value = tf.compat.v1.placeholder(
dtype=parameters["input_dtype"],
name="input",
shape=parameters["input_shape"])
out = tf.cast(input_value, parameters["output_dtype"])
return [input_value], [out]
def build_inputs(parameters, sess, inputs, outputs):
input_value = create_tensor_data(parameters["input_dtype"],
parameters["input_shape"])
return [input_value], sess.run(
outputs, feed_dict=dict(zip(inputs, [input_value])))
make_zip_of_tests(options, test_parameters, build_graph, build_inputs)
+45
View File
@@ -0,0 +1,45 @@
# 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.
# ==============================================================================
"""Test configs for ceil."""
import tensorflow as tf
from tensorflow.lite.testing.zip_test_utils import create_tensor_data
from tensorflow.lite.testing.zip_test_utils import make_zip_of_tests
from tensorflow.lite.testing.zip_test_utils import register_make_test_function
@register_make_test_function()
def make_ceil_tests(options):
"""Make a set of tests to do ceil."""
test_parameters = [{
"input_dtype": [tf.float32],
"input_shape": [[], [1], [1, 2], [5, 6, 7, 8], [3, 4, 5, 6]],
}]
def build_graph(parameters):
"""Build the ceil op testing graph."""
input_value = tf.compat.v1.placeholder(
dtype=parameters["input_dtype"],
name="input1",
shape=parameters["input_shape"])
out = tf.math.ceil(input_value)
return [input_value], [out]
def build_inputs(parameters, sess, inputs, outputs):
input_value = create_tensor_data(parameters["input_dtype"],
parameters["input_shape"])
return [input_value], sess.run(outputs, feed_dict={inputs[0]: input_value})
make_zip_of_tests(options, test_parameters, build_graph, build_inputs)
@@ -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.
# ==============================================================================
"""Test configs for complex abs."""
import tensorflow as tf
from tensorflow.lite.testing.zip_test_utils import create_tensor_data
from tensorflow.lite.testing.zip_test_utils import make_zip_of_tests
from tensorflow.lite.testing.zip_test_utils import register_make_test_function
@register_make_test_function()
def make_complex_abs_tests(options):
"""Make a set of tests to do complex abs."""
# Chose a set of parameters
test_parameters = [{
"dtype": [tf.complex64],
"input_shape": [[], [1], [2, 3], [1, 3, 4, 3], [2, 2, 3, 4, 5, 6]],
"Tout": [tf.float32]
}, {
"dtype": [tf.complex128],
"input_shape": [[], [1], [2, 3], [1, 3, 4, 3], [2, 2, 3, 4, 5, 6]],
"Tout": [tf.float64]
}]
def build_graph(parameters):
input_tensor = tf.compat.v1.placeholder(
dtype=parameters["dtype"],
name="input",
shape=parameters["input_shape"])
out = tf.raw_ops.ComplexAbs(x=input_tensor, Tout=parameters["Tout"])
return [input_tensor], [out]
def build_inputs(parameters, sess, inputs, outputs):
input_values = create_tensor_data(
parameters["dtype"].as_numpy_dtype,
parameters["input_shape"],
min_value=-10,
max_value=10)
return [input_values], sess.run(
outputs, feed_dict=dict(zip(inputs, [input_values])))
make_zip_of_tests(options, test_parameters, build_graph, build_inputs)
+106
View File
@@ -0,0 +1,106 @@
# 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.
# ==============================================================================
"""Test configs for concat."""
import tensorflow as tf
from tensorflow.lite.testing.zip_test_utils import create_tensor_data
from tensorflow.lite.testing.zip_test_utils import make_zip_of_tests
from tensorflow.lite.testing.zip_test_utils import register_make_test_function
@register_make_test_function()
def make_concat_tests(options):
"""Make a set of tests to do concatenation."""
test_parameters = [{
"base_shape": [[1, 3, 4, 3], [3, 4]],
"num_tensors": [1, 2, 3, 4, 5, 6],
"axis": [0, 1, 2, 3, -3, -2, -1],
"type": [tf.float32, tf.uint8, tf.int32, tf.int64],
"fully_quantize": [False],
"quant_16x8": [False],
"dynamic_range_quantize": [False],
}, {
"base_shape": [[1, 3, 4, 3], [3, 4], [2, 3, 4, 3]],
"num_tensors": [1, 2, 3, 4, 5, 6],
"axis": [1, 2, 3, -3, -2, -1],
"type": [tf.float32],
"fully_quantize": [True],
"quant_16x8": [False],
"dynamic_range_quantize": [False],
}, {
"base_shape": [[1, 3, 4, 3]],
"num_tensors": [6],
"axis": [-1],
"type": [tf.float32],
"fully_quantize": [True],
"quant_16x8": [True],
"dynamic_range_quantize": [False],
}, {
"base_shape": [[1, 3, 4, 3]],
"num_tensors": [6],
"axis": [1],
"type": [tf.float32],
"fully_quantize": [False],
"quant_16x8": [False],
"dynamic_range_quantize": [True],
}, {
"base_shape": [[1, 3, 4, 3]],
"num_tensors": [6],
"axis": [1],
"type": [tf.bool],
"fully_quantize": [False],
"quant_16x8": [False],
"dynamic_range_quantize": [True],
}]
def get_shape(parameters, delta):
"""Return a tweaked version of 'base_shape'."""
axis = parameters["axis"]
shape = parameters["base_shape"][:]
if axis < 0:
axis += len(shape)
if axis < len(shape):
shape[axis] += delta
return shape
def build_graph(parameters):
all_tensors = []
for n in range(0, parameters["num_tensors"]):
input_tensor = tf.compat.v1.placeholder(
dtype=parameters["type"],
name=("input%d" % n),
shape=get_shape(parameters, n))
all_tensors.append(input_tensor)
out = tf.concat(all_tensors, parameters["axis"])
return all_tensors, [out]
def build_inputs(parameters, sess, inputs, outputs):
all_values = []
for n in range(0, parameters["num_tensors"]):
input_values = create_tensor_data(
parameters["type"],
get_shape(parameters, n),
min_value=-1,
max_value=1)
all_values.append(input_values)
return all_values, sess.run(
outputs, feed_dict=dict(zip(inputs, all_values)))
make_zip_of_tests(
options,
test_parameters,
build_graph,
build_inputs,
expected_tf_failures=75)
+62
View File
@@ -0,0 +1,62 @@
# 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.
# ==============================================================================
"""Test configs for cond."""
import numpy as np
import tensorflow as tf
from tensorflow.lite.testing.zip_test_utils import create_tensor_data
from tensorflow.lite.testing.zip_test_utils import make_zip_of_tests
from tensorflow.lite.testing.zip_test_utils import register_make_test_function
from tensorflow.python.framework import test_util
@register_make_test_function("make_cond_tests")
@test_util.enable_control_flow_v2
def make_cond_tests(options):
"""Make a set of tests to do relu1."""
# Chose a set of parameters
test_parameters = [{
# Note: The `tf.string` test case also serves as a regression test to
# ensure that branch subgraph with dynamically allocated inputs/outputs
# are handled correctly.
"dtype": [tf.float32, tf.string],
"pred": [False, True],
}]
def build_graph(parameters):
"""Build the graph for cond tests."""
input1 = tf.compat.v1.placeholder(dtype=parameters["dtype"], shape=(1,))
input2 = tf.compat.v1.placeholder(dtype=parameters["dtype"], shape=(1,))
# MLIR TFLite converter can't handle scalar inputs. This is a workaround
# to input (1,) tensors and then reshape to scalar.
# TODO(b/129003347): Remove the workaround after scalar inputs are
# supported.
pred = tf.compat.v1.placeholder(dtype=tf.bool, shape=(1,))
pred_scalar = tf.reshape(pred, ())
out = tf.cond(
pred=pred_scalar, true_fn=lambda: input1, false_fn=lambda: input2)
return [input1, input2, pred], [out]
def build_inputs(parameters, sess, inputs, outputs):
input_values = [
create_tensor_data(parameters["dtype"], (1,)),
create_tensor_data(parameters["dtype"], (1,)),
np.array([parameters["pred"]], dtype=np.bool_),
]
return input_values, sess.run(
outputs, feed_dict=dict(zip(inputs, input_values)))
make_zip_of_tests(options, test_parameters, build_graph, build_inputs)
@@ -0,0 +1,66 @@
# 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.
# ==============================================================================
"""Test configs for constant ops."""
import numpy as np
import tensorflow as tf
from tensorflow.lite.testing.zip_test_utils import create_tensor_data
from tensorflow.lite.testing.zip_test_utils import make_zip_of_tests
from tensorflow.lite.testing.zip_test_utils import MAP_TF_TO_NUMPY_TYPE
from tensorflow.lite.testing.zip_test_utils import register_make_test_function
# This function tests various TensorFLow functions that generates Const op,
# including `tf.ones`, `tf.zeros` and random functions.
@register_make_test_function()
def make_constant_tests(options):
"""Make a set of tests to do constant ops."""
test_parameters = [{
"dtype": [tf.float32, tf.int32],
"input_shape": [[], [1], [2], [1, 1, 1, 1], [2, 2, 2, 2]],
"constant_is_also_output": [True, False],
# Models should not be rejected regardless whether it has unread inputs.
"has_unread_input": [True, False],
}]
def build_graph(parameters):
"""Build a constant graph given `parameters`."""
dummy_input = tf.compat.v1.placeholder(
dtype=parameters["dtype"],
name="input1",
shape=parameters["input_shape"])
constant = tf.constant(
create_tensor_data(parameters["dtype"], parameters["input_shape"]))
outputs = [tf.maximum(dummy_input, constant)]
if parameters["constant_is_also_output"]:
outputs.append(constant)
inputs = [dummy_input]
if parameters["has_unread_input"]:
unread_input = tf.compat.v1.placeholder(
dtype=parameters["dtype"],
name="unread_input",
shape=parameters["input_shape"])
inputs.append(unread_input)
return inputs, outputs
def build_inputs(parameters, sess, inputs, outputs):
dummy_input = np.zeros(
parameters["input_shape"],
dtype=MAP_TF_TO_NUMPY_TYPE[parameters["dtype"]])
return [dummy_input], sess.run(outputs, feed_dict={inputs[0]: dummy_input})
make_zip_of_tests(options, test_parameters, build_graph, build_inputs)
@@ -0,0 +1,56 @@
# 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.
# ==============================================================================
"""Test configs for control_dep."""
import tensorflow as tf
from tensorflow.lite.testing.zip_test_utils import create_tensor_data
from tensorflow.lite.testing.zip_test_utils import make_zip_of_tests
from tensorflow.lite.testing.zip_test_utils import register_make_test_function
TEST_INPUT_DEPTH = 3
@register_make_test_function()
def make_control_dep_tests(options):
"""Make a set of tests that use control dependencies."""
test_parameters = [{
"input_shape": [[], [1, 1, 1, 1], [1, 15, 14, 1], [3, 15, 14, 3]],
}]
def build_graph(parameters):
input_tensor = tf.compat.v1.placeholder(
dtype=tf.float32, name="input", shape=parameters["input_shape"])
filter_value = tf.zeros((3, 3, TEST_INPUT_DEPTH, 8), tf.float32)
assert_op = tf.compat.v1.assert_greater_equal(input_tensor,
input_tensor - 1)
with tf.control_dependencies([assert_op]):
out = tf.nn.conv2d(
input=input_tensor,
filters=filter_value,
strides=(1, 1, 1, 1),
padding="SAME")
return [input_tensor], [out]
def build_inputs(parameters, sess, inputs, outputs):
input_values = create_tensor_data(tf.float32, parameters["input_shape"])
return [input_values], sess.run(
outputs, feed_dict=dict(zip(inputs, [input_values])))
make_zip_of_tests(
options,
test_parameters,
build_graph,
build_inputs,
expected_tf_failures=3)
+148
View File
@@ -0,0 +1,148 @@
# 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.
# ==============================================================================
"""Test configs for conv."""
import numpy as np
import tensorflow as tf
from tensorflow.lite.testing.zip_test_utils import create_tensor_data
from tensorflow.lite.testing.zip_test_utils import make_zip_of_tests
from tensorflow.lite.testing.zip_test_utils import register_make_test_function
@register_make_test_function()
def make_conv_tests(options):
"""Make a set of tests to do convolution."""
test_parameters = [
{
"input_shape": [[1, 3, 4, 3], [4, 6, 6, 1]],
"filter_shape": [[1, 1], [2, 3], [3, 3]],
"strides": [[1, 1, 1, 1], [1, 2, 3, 1]],
"dilations": [[1, 1, 1, 1], [1, 3, 2, 1], [1, 2, 2, 1]],
"padding": ["SAME", "VALID"],
"data_format": ["NHWC"], # TODO(aselle): NCHW would be good
"constant_filter": [True, False],
"channel_multiplier": [1, 2],
"fully_quantize": [False],
"quant_16x8": [False],
"dynamic_range_quantize": [False]
},
{
"input_shape": [[1, 3, 4, 3]],
"filter_shape": [[1, 1], [2, 3]],
"strides": [[1, 1, 1, 1]],
"dilations": [[1, 1, 1, 1]],
"padding": ["SAME"],
"data_format": ["NHWC"],
"constant_filter": [True],
"channel_multiplier": [1, 2],
"fully_quantize": [True],
"quant_16x8": [True],
"dynamic_range_quantize": [False],
},
# TODO(b/134702301): The fully_quantize param is just ignored by the MLIR
# testing path now, resulting in duplicate tests. Either ignore these
# tests or handle it properly in the mlir_convert() function.
{
"input_shape": [[1, 3, 4, 3], [4, 6, 6, 1]],
"filter_shape": [[1, 1], [2, 3], [3, 3]],
"strides": [[1, 1, 1, 1], [1, 2, 3, 1]],
"dilations": [[1, 1, 1, 1], [1, 3, 2, 1], [1, 2, 2, 1]],
"padding": ["SAME", "VALID"],
"data_format": ["NHWC"], # TODO(aselle): NCHW would be good
"constant_filter": [True],
"channel_multiplier": [1, 2],
"fully_quantize": [True],
"quant_16x8": [False],
"dynamic_range_quantize": [False]
},
{
"input_shape": [[1, 3, 4, 3]],
"filter_shape": [[1, 1]],
"strides": [[1, 1, 1, 1], [1, 2, 3, 1]],
"dilations": [[1, 1, 1, 1]],
"padding": ["SAME", "VALID"],
"data_format": ["NHWC"],
"constant_filter": [True],
"channel_multiplier": [2],
"fully_quantize": [False],
"quant_16x8": [False],
"dynamic_range_quantize": [True]
},
{
"input_shape": [[1, 3, 4, 3]],
"filter_shape": [[1, 1]],
"strides": [[1, 1, 1, 1], [1, 2, 3, 1]],
"dilations": [[1, 1, 1, 1]],
"padding": [[[0, 0], [1, 1], [1, 1], [0, 0]]],
"data_format": ["NHWC"],
"constant_filter": [True],
"channel_multiplier": [2],
"fully_quantize": [False],
"quant_16x8": [False],
"dynamic_range_quantize": [True]
},
]
def get_tensor_shapes(parameters):
input_shape = parameters["input_shape"]
filter_size = parameters["filter_shape"]
filter_shape = filter_size + [
input_shape[3], parameters["channel_multiplier"]
]
return [input_shape, filter_shape]
def build_graph(parameters):
"""Build a conv graph given `parameters`."""
input_shape, filter_shape = get_tensor_shapes(parameters)
input_tensor = tf.compat.v1.placeholder(
dtype=tf.float32, name="input", shape=input_shape)
# Get filter input either as a placeholder or constants. Also get a list of
# the input tensors that are represented as placeholders.
if parameters["constant_filter"]:
filter_input = create_tensor_data(
np.float32, filter_shape, min_value=-10, max_value=10)
input_tensors = [input_tensor]
else:
filter_input = tf.compat.v1.placeholder(
dtype=tf.float32, name="filter", shape=filter_shape)
input_tensors = [input_tensor, filter_input]
out = tf.nn.conv2d(
input=input_tensor,
filters=filter_input,
strides=parameters["strides"],
dilations=parameters["dilations"],
padding=parameters["padding"],
data_format=parameters["data_format"])
return input_tensors, [out]
def build_inputs(parameters, sess, inputs, outputs):
# Build list of input values either containing 1 tensor (input) or 2 tensors
# (input, filter) based on whether filter is constant or variable input.
input_shape, filter_shape = get_tensor_shapes(parameters)
values = [
create_tensor_data(np.float32, input_shape, min_value=-1, max_value=1)
]
if not parameters["constant_filter"]:
values.append(create_tensor_data(np.float32, filter_shape))
return values, sess.run(outputs, feed_dict=dict(zip(inputs, values)))
make_zip_of_tests(
options,
test_parameters,
build_graph,
build_inputs,
expected_tf_failures=60)
@@ -0,0 +1,79 @@
# 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.
# ==============================================================================
"""Test configs for conv2d_transpose."""
import numpy as np
import tensorflow as tf
from tensorflow.lite.testing.zip_test_utils import create_tensor_data
from tensorflow.lite.testing.zip_test_utils import make_zip_of_tests
from tensorflow.lite.testing.zip_test_utils import register_make_test_function
@register_make_test_function()
def make_conv2d_transpose_tests(options):
"""Make a set of tests to do transpose_conv."""
test_parameters = [{
"input_shape": [[1, 50, 54, 3]],
"filter_shape": [[1, 1, 8, 3], [1, 2, 8, 3], [1, 3, 8, 3], [1, 4, 8, 3]],
"output_shape": [[1, 100, 108, 8]],
"dynamic_output_shape": [True, False],
}, {
"input_shape": [[1, 16, 1, 512]],
"filter_shape": [[4, 1, 512, 512]],
"output_shape": [[1, 32, 1, 512]],
"dynamic_output_shape": [True, False],
}, {
"input_shape": [[1, 128, 128, 1]],
"filter_shape": [[4, 4, 1, 1]],
"output_shape": [[1, 256, 256, 1]],
"dynamic_output_shape": [True, False],
}]
def build_graph(parameters):
"""Build a transpose_conv graph given `parameters`."""
input_tensor = tf.compat.v1.placeholder(
dtype=tf.float32, name="input", shape=parameters["input_shape"])
filter_tensor = tf.compat.v1.placeholder(
dtype=tf.float32, name="filter", shape=parameters["filter_shape"])
input_tensors = [input_tensor, filter_tensor]
if parameters["dynamic_output_shape"]:
output_shape = tf.compat.v1.placeholder(dtype=tf.int32, shape=[4])
input_tensors.append(output_shape)
else:
output_shape = parameters["output_shape"]
out = tf.nn.conv2d_transpose(
input_tensor,
filter_tensor,
output_shape=output_shape,
padding="SAME",
strides=(1, 2, 2, 1))
return input_tensors, [out]
def build_inputs(parameters, sess, inputs, outputs):
values = [
create_tensor_data(np.float32, parameters["input_shape"]),
create_tensor_data(np.float32, parameters["filter_shape"])
]
if parameters["dynamic_output_shape"]:
values.append(np.array(parameters["output_shape"]))
return values, sess.run(outputs, feed_dict=dict(zip(inputs, values)))
make_zip_of_tests(options, test_parameters, build_graph, build_inputs)
@@ -0,0 +1,70 @@
# 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.
# ==============================================================================
"""Test configs for exp."""
import tensorflow as tf
from tensorflow.lite.testing.zip_test_utils import create_tensor_data
from tensorflow.lite.testing.zip_test_utils import make_zip_of_tests
from tensorflow.lite.testing.zip_test_utils import register_make_test_function
@register_make_test_function()
def make_conv3d_tests(options):
"""Make a set of tests to do conv3d."""
test_parameters = [{
"input_dtype": [tf.float32],
"input_shape": [[2, 3, 4, 5, 3], [2, 5, 6, 8, 3]],
"filter_shape": [[2, 2, 2, 3, 2], [1, 2, 2, 3, 2]],
"strides": [(1, 1, 1, 1, 1), (1, 1, 1, 2, 1), (1, 1, 2, 2, 1),
(1, 2, 1, 2, 1), (1, 2, 2, 2, 1)],
"dilations": [(1, 1, 1, 1, 1)],
"padding": ["SAME", "VALID"],
}]
def build_graph(parameters):
"""Build the exp op testing graph."""
input_tensor = tf.compat.v1.placeholder(
dtype=parameters["input_dtype"],
name="input",
shape=parameters["input_shape"])
filter_tensor = tf.compat.v1.placeholder(
dtype=parameters["input_dtype"],
name="filter",
shape=parameters["filter_shape"])
out = tf.nn.conv3d(
input_tensor,
filter_tensor,
strides=parameters["strides"],
dilations=parameters["dilations"],
padding=parameters["padding"])
return [input_tensor, filter_tensor], [out]
def build_inputs(parameters, sess, inputs, outputs):
values = [
create_tensor_data(
parameters["input_dtype"],
parameters["input_shape"],
min_value=-100,
max_value=9),
create_tensor_data(
parameters["input_dtype"],
parameters["filter_shape"],
min_value=-3,
max_value=3)
]
return values, sess.run(outputs, feed_dict=dict(zip(inputs, values)))
make_zip_of_tests(options, test_parameters, build_graph, build_inputs)
@@ -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.
# ==============================================================================
"""Test configs for conv3d_transpose."""
import numpy as np
import tensorflow as tf
from tensorflow.lite.testing.zip_test_utils import create_tensor_data
from tensorflow.lite.testing.zip_test_utils import make_zip_of_tests
from tensorflow.lite.testing.zip_test_utils import register_make_test_function
@register_make_test_function()
def make_conv3d_transpose_tests(options):
"""Make a set of tests to do conv3d_transpose."""
test_parameters = [{
"shape_dtype": [tf.int32, tf.int64],
"input_dtype": [tf.float32],
"input_shape": [[2, 3, 4, 5, 2], [2, 5, 6, 8, 2]],
"filter_shape": [[2, 2, 2, 3, 2], [1, 2, 2, 3, 2]],
"strides": [(1, 1, 1, 1, 1), (1, 1, 1, 2, 1), (1, 1, 2, 2, 1),
(1, 2, 1, 2, 1), (1, 2, 2, 2, 1)],
"dilations": [(1, 1, 1, 1, 1)],
"padding": ["SAME", "VALID"],
}]
def build_graph(parameters):
"""Build the exp op testing graph."""
output_shape = tf.compat.v1.placeholder(
dtype=parameters["shape_dtype"], name="input", shape=[5])
input_tensor = tf.compat.v1.placeholder(
dtype=parameters["input_dtype"],
name="input",
shape=parameters["input_shape"])
filter_tensor = tf.compat.v1.placeholder(
dtype=parameters["input_dtype"],
name="filter",
shape=parameters["filter_shape"])
out = tf.nn.conv3d_transpose(
input_tensor,
filter_tensor,
output_shape,
strides=parameters["strides"],
dilations=parameters["dilations"],
padding=parameters["padding"])
return [input_tensor, filter_tensor, output_shape], [out]
def calculate_output_shape(parameters):
def calculate_shape(idx):
input_size = parameters["input_shape"][idx]
filter_size = parameters["filter_shape"][idx - 1]
stride = parameters["strides"][idx]
if parameters["padding"] == "SAME":
return (input_size - 1) * stride + 1
else:
return (input_size - 1) * stride + filter_size
output_shape_values = [parameters["input_shape"][0]]
output_shape_values.append(calculate_shape(1))
output_shape_values.append(calculate_shape(2))
output_shape_values.append(calculate_shape(3))
output_shape_values.append(parameters["filter_shape"][3])
return np.dtype(
parameters["shape_dtype"].as_numpy_dtype()).type(output_shape_values)
def build_inputs(parameters, sess, inputs, outputs):
values = [
create_tensor_data(
parameters["input_dtype"],
parameters["input_shape"],
min_value=-100,
max_value=9),
create_tensor_data(
parameters["input_dtype"],
parameters["filter_shape"],
min_value=-3,
max_value=3),
calculate_output_shape(parameters)
]
return values, sess.run(outputs, feed_dict=dict(zip(inputs, values)))
make_zip_of_tests(options, test_parameters, build_graph, build_inputs)
@@ -0,0 +1,152 @@
# 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.
# ==============================================================================
"""Test configs for conv with activations."""
import numpy as np
import tensorflow as tf
from tensorflow.lite.testing.zip_test_utils import create_tensor_data
from tensorflow.lite.testing.zip_test_utils import make_zip_of_tests
from tensorflow.lite.testing.zip_test_utils import register_make_test_function
def make_conv_activation_tests(activation_op):
"""Make a set of tests to do convolution with activation."""
def f(options):
"""Actual function that generates examples."""
test_parameters = [
{
"input_shape": [[1, 3, 4, 3], [4, 6, 6, 1]],
"filter_shape": [[1, 1], [2, 3], [3, 3]],
"strides": [[1, 1, 1, 1], [1, 2, 3, 1]],
"dilations": [[1, 1, 1, 1], [1, 3, 2, 1], [1, 2, 2, 1]],
"padding": ["SAME", "VALID"],
"data_format": ["NHWC"], # TODO(aselle): NCHW would be good
"constant_filter": [True, False],
"channel_multiplier": [1, 2],
"fully_quantize": [False],
"quant_16x8": [False],
"dynamic_range_quantize": [False],
},
# TODO(b/134702301): The fully_quantize param is just ignored by the
# MLIR testing path now, resulting in duplicate tests. Either ignore
# these tests or handle it properly in the mlir_convert() function.
{
"input_shape": [[1, 3, 4, 3], [4, 6, 6, 1]],
"filter_shape": [[1, 1], [2, 3]],
"strides": [[1, 1, 1, 1], [1, 2, 3, 1]],
"dilations": [[1, 1, 1, 1], [1, 3, 2, 1]],
"padding": ["SAME", "VALID"],
"data_format": ["NHWC"], # TODO(aselle): NCHW would be good
"constant_filter": [True],
"channel_multiplier": [1, 2],
"fully_quantize": [True],
"quant_16x8": [False, True],
"dynamic_range_quantize": [False],
},
{
"input_shape": [[1, 3, 4, 3]],
"filter_shape": [[1, 1], [2, 3], [3, 3]],
"strides": [[1, 1, 1, 1], [1, 2, 3, 1]],
"dilations": [[1, 1, 1, 1]],
"padding": ["SAME", "VALID"],
"data_format": ["NHWC"],
"constant_filter": [True],
"channel_multiplier": [1, 2],
"fully_quantize": [False],
"quant_16x8": [False],
"dynamic_range_quantize": [True],
},
]
def get_tensor_shapes(parameters):
input_shape = parameters["input_shape"]
filter_size = parameters["filter_shape"]
filter_shape = filter_size + [
input_shape[3], parameters["channel_multiplier"]
]
return [input_shape, filter_shape]
def build_graph(parameters):
"""Build a conv graph given `parameters`."""
input_shape, filter_shape = get_tensor_shapes(parameters)
input_tensor = tf.compat.v1.placeholder(
dtype=tf.float32, name="input", shape=input_shape)
# Get filter input either as a placeholder or constants. Also get a list
# of the input tensors that are represented as placeholders.
if parameters["constant_filter"]:
filter_input = create_tensor_data(
np.float32, filter_shape, min_value=-10, max_value=10)
input_tensors = [input_tensor]
else:
filter_input = tf.compat.v1.placeholder(
dtype=tf.float32, name="filter", shape=filter_shape)
input_tensors = [input_tensor, filter_input]
out = tf.nn.conv2d(
input=input_tensor,
filters=filter_input,
strides=parameters["strides"],
dilations=parameters["dilations"],
padding=parameters["padding"],
data_format=parameters["data_format"])
out = activation_op(out)
return input_tensors, [out]
def build_inputs(parameters, sess, inputs, outputs):
"""Build inputs for conv with activation."""
input_shape, filter_shape = get_tensor_shapes(parameters)
values = [
create_tensor_data(
np.float32, input_shape, min_value=-1, max_value=1)
]
if not parameters["constant_filter"]:
values.append(create_tensor_data(np.float32, filter_shape))
return values, sess.run(outputs, feed_dict=dict(zip(inputs, values)))
make_zip_of_tests(
options,
test_parameters,
build_graph,
build_inputs,
expected_tf_failures=48)
return f
@register_make_test_function()
def make_conv_relu6_tests(options):
"""Make a set of tests to do conv_relu6."""
return make_conv_activation_tests(tf.nn.relu6)(options)
@register_make_test_function()
def make_conv_relu_tests(options):
"""Make a set of tests to do conv_relu."""
return make_conv_activation_tests(tf.nn.relu)(options)
def relu1(input_tensor):
# Note that the following is not supported:
# out = tf.maximum(-1.0, tf.minimum(input_tensor, 1.0))
out = tf.minimum(1.0, tf.maximum(input_tensor, -1.0))
return out
@register_make_test_function()
def make_conv_relu1_tests(options):
"""Make a set of tests to do conv_relu1."""
return make_conv_activation_tests(relu1)(options)
@@ -0,0 +1,145 @@
# 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.
# ==============================================================================
"""Test configs for conv followed with bias Add and activations."""
import numpy as np
import tensorflow as tf
from tensorflow.lite.testing.zip_test_utils import create_tensor_data
from tensorflow.lite.testing.zip_test_utils import make_zip_of_tests
from tensorflow.lite.testing.zip_test_utils import register_make_test_function
def make_conv_bias_activation_tests(activation_op):
"""Make a set of tests to do convolution with activation and bias.
This test will create multiple consecutive convolutions with NCHW layout to
make sure that the tranformations to NHWC works as expected. Note this
doesn't check any performance so manual checking of the generated model is
advised.
Args:
activation_op: The activation op to be used in the test.
Returns:
The function that creates the test.
"""
def create_test(options):
"""Actual function that generates examples."""
test_parameters = [
{
"input_shape": [[1, 3, 4, 3]],
"filter_shape": [[2, 3], [3, 3]],
"filter_2_shape": [[2, 1, 1, 3]],
"strides": [[1, 1, 1, 1]],
"dilations": [[1, 1, 1, 1]],
"data_format": ["NCHW"],
"channel_multiplier": [1, 2],
"fully_quantize": [False],
"dynamic_range_quantize": [False],
},
]
def get_tensor_shapes(parameters):
input_shape = parameters["input_shape"]
filter_size = parameters["filter_shape"]
filter_shape = filter_size + [
input_shape[3], parameters["channel_multiplier"]
]
return [input_shape, filter_shape]
# TF CPU doesn't support cases with NCHW. Instead
# use XLA which doesn't have the same restrictions.
@tf.function(jit_compile=True)
def add_conv(input_tensor, filter_input, parameters):
out = tf.nn.conv2d(
input=input_tensor,
filters=filter_input,
strides=parameters["strides"],
dilations=parameters["dilations"],
padding="VALID",
data_format=parameters["data_format"])
return out
def add_bias_add(data_input, filter_shape):
bias_input = create_tensor_data(np.float32, (filter_shape[-1],))
out = tf.nn.bias_add(data_input, bias_input, data_format="NHWC")
return out
def build_graph(parameters):
"""Build a conv graph given `parameters`."""
input_shape, filter_shape = get_tensor_shapes(parameters)
input_tensor = tf.compat.v1.placeholder(
dtype=tf.float32, name="input", shape=input_shape)
filter_input = create_tensor_data(
np.float32, filter_shape, min_value=-10, max_value=10)
input_tensors = [input_tensor]
if parameters["data_format"] == "NCHW":
out = add_conv(input_tensor, filter_input, parameters)
else:
out = tf.nn.conv2d(
input=input_tensor,
filters=filter_input,
strides=parameters["strides"],
dilations=parameters["dilations"],
padding="VALID",
data_format=parameters["data_format"])
out = add_bias_add(out, filter_shape)
out = activation_op(out)
# Add another conv + bias_add + activation.
# Create constant filter for the second conv2d.
filter_input_2 = create_tensor_data(
np.float32, parameters["filter_2_shape"], min_value=-10, max_value=10)
if parameters["data_format"] == "NCHW":
out = add_conv(out, filter_input_2, parameters)
else:
out = tf.nn.conv2d(
input=out,
filters=filter_input_2,
strides=parameters["strides"],
dilations=parameters["dilations"],
padding="VALID",
data_format=parameters["data_format"])
out = add_bias_add(out, filter_shape)
out = activation_op(out)
return input_tensors, [out]
def build_inputs(parameters, sess, inputs, outputs):
"""Build inputs for conv with activation."""
input_shape, _ = get_tensor_shapes(parameters)
values = [
create_tensor_data(
np.float32, input_shape, min_value=-1, max_value=1)
]
return values, sess.run(outputs, feed_dict=dict(zip(inputs, values)))
make_zip_of_tests(
options,
test_parameters,
build_graph,
build_inputs,
expected_tf_failures=2)
return create_test
@register_make_test_function()
def make_conv_bias_relu6_tests(options):
"""Make a set of tests to do conv_bias_relu6."""
return make_conv_bias_activation_tests(tf.nn.relu6)(options)
@@ -0,0 +1,83 @@
# 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.
# ==============================================================================
"""Test configs for conv."""
import numpy as np
import tensorflow as tf
from tensorflow.lite.testing.zip_test_utils import create_tensor_data
from tensorflow.lite.testing.zip_test_utils import make_zip_of_tests
from tensorflow.lite.testing.zip_test_utils import register_make_test_function
@register_make_test_function()
def make_conv_to_depthwiseconv_with_shared_weights_tests(options):
"""Make a test where 2 Conv ops shared the same constant weight tensor."""
test_parameters = [{
"input_shape": [[1, 10, 10, 1]],
"filter_shape": [[3, 3]],
"strides": [[1, 1, 1, 1]],
"dilations": [[1, 1, 1, 1]],
"padding": ["SAME"],
"data_format": ["NHWC"],
"channel_multiplier": [3],
}]
def get_tensor_shapes(parameters):
input_shape = parameters["input_shape"]
filter_size = parameters["filter_shape"]
filter_shape = filter_size + [
input_shape[3], parameters["channel_multiplier"]
]
return [input_shape, filter_shape]
def build_graph(parameters):
"""Build a conv graph given `parameters`."""
input_shape, filter_shape = get_tensor_shapes(parameters)
input_tensor = tf.compat.v1.placeholder(
dtype=tf.float32, name="input", shape=input_shape)
# Construct a constant weights tensor which will be used by both Conv2D.
filter_tensor = tf.constant(
create_tensor_data(np.float32, filter_shape), dtype=tf.float32)
input_tensors = [input_tensor]
# Construct 2 Conv2D operations which use exactly the same input and
# weights.
result1 = tf.nn.conv2d(
input=input_tensor,
filters=filter_tensor,
strides=parameters["strides"],
dilations=parameters["dilations"],
padding=parameters["padding"],
data_format=parameters["data_format"])
result2 = tf.nn.conv2d(
input=input_tensor,
filters=filter_tensor,
strides=parameters["strides"],
dilations=parameters["dilations"],
padding=parameters["padding"],
data_format=parameters["data_format"])
# Add the 2 results up.
out = result1 + result2
return input_tensors, [out]
def build_inputs(parameters, sess, inputs, outputs):
# Build list of input values either containing 1 tensor (input) or 2 tensors
# (input, filter) based on whether filter is constant or variable input.
input_shape, unused_filter_shape = get_tensor_shapes(parameters)
values = [create_tensor_data(np.float32, input_shape)]
return values, sess.run(outputs, feed_dict=dict(zip(inputs, values)))
make_zip_of_tests(options, test_parameters, build_graph, build_inputs)
@@ -0,0 +1,92 @@
# 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.
# ==============================================================================
"""Test configs for conv_with_shared_weights."""
import numpy as np
import tensorflow as tf
from tensorflow.lite.testing.zip_test_utils import create_tensor_data
from tensorflow.lite.testing.zip_test_utils import make_zip_of_tests
from tensorflow.lite.testing.zip_test_utils import register_make_test_function
@register_make_test_function()
def make_conv_with_shared_weights_tests(options):
"""Make a test where 2 Conv ops shared the same constant weight tensor."""
test_parameters = [{
"input_shape": [[1, 10, 10, 3]],
"filter_shape": [[3, 3]],
"strides": [[1, 1, 1, 1]],
"dilations": [[1, 1, 1, 1]],
"padding": ["SAME"],
"data_format": ["NHWC"],
"channel_multiplier": [1],
"dynamic_range_quantize": [False, True],
}]
def get_tensor_shapes(parameters):
input_shape = parameters["input_shape"]
filter_size = parameters["filter_shape"]
filter_shape = filter_size + [
input_shape[3], parameters["channel_multiplier"]
]
return [input_shape, filter_shape]
def build_graph(parameters):
"""Build a conv graph given `parameters`."""
input_shape, filter_shape = get_tensor_shapes(parameters)
input_tensor = tf.compat.v1.placeholder(
dtype=tf.float32, name="input", shape=input_shape)
input_tensors = [input_tensor]
# Construct a constant weights tensor which will be used by both Conv2D.
filter_tensor = tf.constant(
create_tensor_data(np.float32, filter_shape), dtype=tf.float32)
# Ensure that FuseBinaryIntoFollowingAffine works with an input which
# is shared by multiple affine ops.
conv_input = input_tensor + 0.1
# Construct 2 Conv2D operations which use exactly the same input and
# weights.
result1 = tf.nn.conv2d(
input=conv_input,
filters=filter_tensor,
strides=parameters["strides"],
dilations=parameters["dilations"],
padding=parameters["padding"],
data_format=parameters["data_format"])
result2 = tf.nn.conv2d(
input=conv_input,
filters=filter_tensor,
strides=parameters["strides"],
dilations=parameters["dilations"],
padding=parameters["padding"],
data_format=parameters["data_format"])
# Add MUL ops after Conv2D ops. These MUL ops should be fused into the
# weights of Conv2D.
result1 = result1 * 2
result2 = result2 * 3
# Add the 2 results up.
out = result1 + result2
return input_tensors, [out]
def build_inputs(parameters, sess, inputs, outputs):
# Build list of input values either containing 1 tensor (input) or 2 tensors
# (input, filter) based on whether filter is constant or variable input.
input_shape, unused_filter_shape = get_tensor_shapes(parameters)
values = [create_tensor_data(np.float32, input_shape)]
return values, sess.run(outputs, feed_dict=dict(zip(inputs, values)))
make_zip_of_tests(options, test_parameters, build_graph, build_inputs)
+52
View File
@@ -0,0 +1,52 @@
# 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.
# ==============================================================================
"""Test configs for cos."""
import numpy as np
import tensorflow as tf
from tensorflow.lite.testing.zip_test_utils import create_tensor_data
from tensorflow.lite.testing.zip_test_utils import make_zip_of_tests
from tensorflow.lite.testing.zip_test_utils import register_make_test_function
@register_make_test_function()
def make_cos_tests(options):
"""Make a set of tests to do cos."""
test_parameters = [{
"input_dtype": [tf.float32],
"input_shape": [[], [3], [1, 100], [4, 2, 3], [5, 224, 224, 3]],
}]
def build_graph(parameters):
"""Build the cos op testing graph."""
input_tensor = tf.compat.v1.placeholder(
dtype=parameters["input_dtype"],
name="input",
shape=parameters["input_shape"])
out = tf.cos(input_tensor)
return [input_tensor], [out]
def build_inputs(parameters, sess, inputs, outputs):
values = [
create_tensor_data(
parameters["input_dtype"],
parameters["input_shape"],
min_value=-np.pi,
max_value=np.pi)
]
return values, sess.run(outputs, feed_dict=dict(zip(inputs, values)))
make_zip_of_tests(options, test_parameters, build_graph, build_inputs)
@@ -0,0 +1,49 @@
# 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.
# ==============================================================================
"""Test configs for cumsum."""
import tensorflow as tf
from tensorflow.lite.testing.zip_test_utils import create_tensor_data
from tensorflow.lite.testing.zip_test_utils import make_zip_of_tests
from tensorflow.lite.testing.zip_test_utils import register_make_test_function
@register_make_test_function()
def make_cumsum_tests(options):
"""Make a set of tests to do cumsum."""
test_parameters = [{
"shape": [(3, 6), (8, 9, 7), (2, 4, 3, 5)],
"dtype": [tf.int32, tf.int64, tf.float32],
"axis": [0, 1],
"exclusive": [True, False],
"reverse": [True, False],
}]
def build_graph(parameters):
"""Build the cumsum op testing graph."""
input1 = tf.compat.v1.placeholder(
dtype=parameters["dtype"], shape=parameters["shape"])
out = tf.math.cumsum(
input1,
parameters["axis"],
exclusive=parameters["exclusive"],
reverse=parameters["reverse"])
return [input1], [out]
def build_inputs(parameters, sess, inputs, outputs):
input1 = create_tensor_data(parameters["dtype"], parameters["shape"])
return [input1], sess.run(outputs, feed_dict=dict(zip(inputs, [input1])))
make_zip_of_tests(options, test_parameters, build_graph, build_inputs)
@@ -0,0 +1,60 @@
# 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.
# ==============================================================================
"""Test configs for depth_to_space."""
import tensorflow as tf
from tensorflow.lite.testing.zip_test_utils import create_tensor_data
from tensorflow.lite.testing.zip_test_utils import make_zip_of_tests
from tensorflow.lite.testing.zip_test_utils import register_make_test_function
@register_make_test_function()
def make_depth_to_space_tests(options):
"""Make a set of tests to do depth_to_space."""
test_parameters = [{
"dtype": [tf.int32, tf.uint8, tf.int64],
"input_shape": [[2, 3, 4, 16]],
"block_size": [2, 4],
"fully_quantize": [False],
}, {
"dtype": [tf.float32],
"input_shape": [[2, 3, 4, 16]],
"block_size": [2, 4],
"fully_quantize": [True, False],
}]
def build_graph(parameters):
input_tensor = tf.compat.v1.placeholder(
dtype=parameters["dtype"],
name="input",
shape=parameters["input_shape"])
out = tf.compat.v1.depth_to_space(
input_tensor, block_size=parameters["block_size"])
return [input_tensor], [out]
def build_inputs(parameters, sess, inputs, outputs):
if not parameters["fully_quantize"]:
input_values = create_tensor_data(parameters["dtype"],
parameters["input_shape"])
else:
input_values = create_tensor_data(
parameters["dtype"],
parameters["input_shape"],
min_value=-1,
max_value=1)
return [input_values], sess.run(
outputs, feed_dict=dict(zip(inputs, [input_values])))
make_zip_of_tests(options, test_parameters, build_graph, build_inputs)
@@ -0,0 +1,152 @@
# 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.
# ==============================================================================
"""Test configs for depthwiseconv."""
import numpy as np
import tensorflow as tf
from tensorflow.lite.testing.zip_test_utils import create_tensor_data
from tensorflow.lite.testing.zip_test_utils import make_zip_of_tests
from tensorflow.lite.testing.zip_test_utils import register_make_test_function
@register_make_test_function()
def make_depthwiseconv_tests(options):
"""Make a set of tests to do convolution."""
# Tensorflow only supports equal strides
test_parameters = [
{
"input_shape": [[1, 3, 4, 3], [1, 10, 10, 3]],
"filter_size": [[1, 1], [1, 2], [3, 3]],
"strides": [[1, 1, 1, 1], [1, 3, 3, 1]],
"dilations": [[1, 1, 1, 1], [1, 3, 2, 1], [1, 2, 2, 1]],
"channel_multiplier": [1, 2],
"rate": [[1, 1]],
"padding": ["SAME", "VALID"],
"data_format": ["NHWC"],
"constant_filter": [True, False],
"fully_quantize": [False],
"quant_16x8": [False]
},
{
"input_shape": [[1, 3, 4, 3]],
"filter_size": [[1, 1]],
"strides": [[1, 1, 2, 1]], # TF needs [1, x, x, 1]
"dilations": [[1, 1, 1, 1], [1, 2, 2, 1]],
"channel_multiplier": [2],
"rate": [[2, 2]], # Only [1, 1] is supported
"padding": ["SAME"],
"data_format": ["NHWC"],
"constant_filter": [True, False],
"fully_quantize": [False],
"quant_16x8": [False]
},
{
"input_shape": [[1, 3, 4, 3], [1, 10, 10, 3]],
"filter_size": [[1, 1], [1, 2], [3, 3]],
"strides": [[1, 1, 1, 1], [1, 3, 3, 1]],
"dilations": [[1, 1, 1, 1], [1, 3, 2, 1], [1, 2, 2, 1]],
"channel_multiplier": [1, 2],
"rate": [[1, 1]],
"padding": ["SAME", "VALID"],
"data_format": ["NHWC"],
"constant_filter": [True],
"fully_quantize": [True],
"quant_16x8": [False]
},
{
"input_shape": [[1, 3, 3, 3000]],
"filter_size": [[3, 3]],
"strides": [[1, 1, 1, 1]],
"dilations": [[1, 1, 1, 1]],
"channel_multiplier": [1],
"rate": [[1, 1]],
"padding": ["VALID"],
"data_format": ["NHWC"],
"constant_filter": [True],
"fully_quantize": [True],
"quant_16x8": [False]
},
{
"input_shape": [[1, 3, 4, 3]],
"filter_size": [[1, 2]],
"strides": [[1, 3, 3, 1]],
"dilations": [[1, 3, 2, 1]],
"channel_multiplier": [1],
"rate": [[1, 1]],
"padding": ["SAME", "VALID"],
"data_format": ["NHWC"],
"constant_filter": [True],
"fully_quantize": [True],
"quant_16x8": [True]
},
]
def get_tensor_shapes(parameters):
input_shape = parameters["input_shape"]
filter_size = parameters["filter_size"]
filter_shape = filter_size + [
input_shape[3], parameters["channel_multiplier"]
]
return [input_shape, filter_shape]
def build_graph(parameters):
"""Build a depthwise conv graph given `parameters`."""
input_shape, filter_shape = get_tensor_shapes(parameters)
input_tensor = tf.compat.v1.placeholder(
dtype=tf.float32, name="input", shape=input_shape)
# Get filter input either as a placeholder or constants. Also get a list of
# the input tensors that are represented as placeholders.
if parameters["constant_filter"]:
filter_input = create_tensor_data(np.float32, filter_shape)
input_tensors = [input_tensor]
else:
filter_input = tf.compat.v1.placeholder(
dtype=tf.float32, name="filter", shape=filter_shape)
input_tensors = [input_tensor, filter_input]
out = tf.nn.depthwise_conv2d(
input=input_tensor,
filter=filter_input,
strides=parameters["strides"],
dilations=parameters["rate"],
padding=parameters["padding"],
data_format=parameters["data_format"])
return input_tensors, [out]
def build_inputs(parameters, sess, inputs, outputs):
# pylint: disable=g-doc-return-or-yield, g-doc-args
"""Build list of input values.
It either contains 1 tensor (input) or 2 tensors (input, filter) based on
whether filter is constant or variable input.
"""
input_shape, filter_shape = get_tensor_shapes(parameters)
values = [
create_tensor_data(np.float32, input_shape, min_value=-1, max_value=1)
]
if not parameters["constant_filter"]:
values.append(
create_tensor_data(
np.float32, filter_shape, min_value=-1, max_value=1))
return values, sess.run(outputs, feed_dict=dict(zip(inputs, values)))
make_zip_of_tests(
options,
test_parameters,
build_graph,
build_inputs,
expected_tf_failures=4)
@@ -0,0 +1,75 @@
# 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.
# ==============================================================================
"""Test configs for dynamic_rnn."""
import tensorflow as tf
from tensorflow.lite.testing.zip_test_utils import create_tensor_data
from tensorflow.lite.testing.zip_test_utils import make_zip_of_tests
from tensorflow.lite.testing.zip_test_utils import register_make_test_function
from tensorflow.python.framework import test_util
from tensorflow.python.ops import rnn
@register_make_test_function("make_dynamic_rnn_tests")
@test_util.enable_control_flow_v2
def make_dynamic_rnn_tests(options):
"""Make a set of tests to do basic Lstm cell."""
test_parameters = [
{
"dtype": [tf.float32],
"num_batches": [4, 2],
"time_step_size": [4, 3],
"input_vec_size": [3, 2],
"num_cells": [4, 2],
},
]
def build_graph(parameters):
"""Build a simple graph with BasicLSTMCell."""
num_batches = parameters["num_batches"]
time_step_size = parameters["time_step_size"]
input_vec_size = parameters["input_vec_size"]
num_cells = parameters["num_cells"]
input_shape = (num_batches, time_step_size, input_vec_size)
input_tensor = tf.compat.v1.placeholder(
dtype=parameters["dtype"], shape=input_shape)
lstm_cell = tf.compat.v1.nn.rnn_cell.BasicLSTMCell(
num_cells, activation=tf.nn.relu)
output, _ = rnn.dynamic_rnn(
lstm_cell, input_tensor, dtype=parameters["dtype"])
return [input_tensor], [output]
def build_inputs(parameters, sess, inputs, outputs):
"""Feed inputs, assign variables, and freeze graph."""
sess.run(tf.compat.v1.global_variables_initializer())
num_batches = parameters["num_batches"]
time_step_size = parameters["time_step_size"]
input_vec_size = parameters["input_vec_size"]
input_shape = (num_batches, time_step_size, input_vec_size)
input_value = create_tensor_data(parameters["dtype"], input_shape)
output_values = sess.run(
outputs, feed_dict=dict(zip(inputs, [input_value])))
return [input_value], output_values
make_zip_of_tests(
options,
test_parameters,
build_graph,
build_inputs,
use_frozen_graph=True)
@@ -0,0 +1,84 @@
# Copyright 2022 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.
# ==============================================================================
"""Test configs for tensor_list_set_item."""
import functools
import tensorflow as tf
from tensorflow.lite.python import lite
from tensorflow.lite.testing.zip_test_utils import create_tensor_data
from tensorflow.lite.testing.zip_test_utils import make_zip_of_tests
from tensorflow.lite.testing.zip_test_utils import register_make_test_function
from tensorflow.python.ops import list_ops
def _tflite_convert_verify_op(tflite_convert_function, *args, **kwargs):
"""Verifies that the result of the conversion contains DynamicUpdateSlice op."""
result = tflite_convert_function(*args, **kwargs)
tflite_model_binary = result[0]
if not result[0]:
tf.compat.v1.logging.error(result[1]) # stderr from running tflite_convert.
raise RuntimeError("Failed to build model: \n\n" + result[1])
interpreter = lite.Interpreter(model_content=tflite_model_binary)
interpreter.allocate_tensors()
for op in interpreter._get_ops_details(): # pylint: disable=protected-access
if op["op_name"] == "DYNAMIC_UPDATE_SLICE":
return result
raise RuntimeError(
"Expected to generate DYNAMIC_UPDATE_SLICE op node in graph.")
@register_make_test_function()
def make_dynamic_update_slice_tests(options):
"""Make a set of tests to do TensorListSetItem."""
test_parameters = [
{
"element_dtype": [tf.float32, tf.int32, tf.bool],
"num_elements": [4, 5, 6],
"element_shape": [[], [5], [3, 3]],
"index": [0, 1, 2, 3],
},
]
def build_graph(parameters):
"""Build the TensorListSetItem op testing graph."""
data = tf.compat.v1.placeholder(
dtype=parameters["element_dtype"],
shape=[parameters["num_elements"]] + parameters["element_shape"])
item = tf.compat.v1.placeholder(
dtype=parameters["element_dtype"], shape=parameters["element_shape"])
tensor_list = list_ops.tensor_list_from_tensor(data,
parameters["element_shape"])
tensor_list = list_ops.tensor_list_set_item(tensor_list,
parameters["index"], item)
out = list_ops.tensor_list_stack(
tensor_list,
num_elements=parameters["num_elements"],
element_dtype=parameters["element_dtype"])
return [data, item], [out]
def build_inputs(parameters, sess, inputs, outputs):
data = create_tensor_data(parameters["element_dtype"],
[parameters["num_elements"]] +
parameters["element_shape"])
item = create_tensor_data(parameters["element_dtype"],
parameters["element_shape"])
return [data, item], sess.run(
outputs, feed_dict=dict(zip(inputs, [data, item])))
options.enable_dynamic_update_slice = True
options.tflite_convert_function = functools.partial(
_tflite_convert_verify_op, options.tflite_convert_function)
make_zip_of_tests(options, test_parameters, build_graph, build_inputs)
@@ -0,0 +1,89 @@
# 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.
# ==============================================================================
"""Test configs for einsum."""
import tensorflow as tf
from tensorflow.lite.testing.zip_test_utils import create_tensor_data
from tensorflow.lite.testing.zip_test_utils import make_zip_of_tests
from tensorflow.lite.testing.zip_test_utils import register_make_test_function
from tensorflow.python.framework import test_util
@register_make_test_function("make_einsum_tests")
@test_util.enable_control_flow_v2
def make_einsum_tests(options):
"""Make a set of tests to do basic einsum ops."""
test_parameters = [
{
"dtype": [tf.float32],
"shapes": [
((None, None, 8, 64), (4, None, 8, 64), "BQNH,BTNH->BQNT"),
((1, None, 8, None), (1, None, 8, 64), "BQNT,BTNH->BQNH"),
((None, None, 8, 64), (8, 8, 64), "ABNH,NDH->ABD"),
((None, None, 128), (128, 8, 64), "ABD,DNH->ABNH"),
((3, 4, 5), (3, 5, 6), "ijk,ikm->ijm"),
((3, 4, 5), (5, 6), "ijk,km->ijm"),
((2, 5, 7), (5, 2), "LBH,BL->BH"),
((2, 5, 7), (5, 3, 2), "LBH,BKL->BKH"),
((2, 5, 7, 3), (2, 4, 7, 3), "BFNH,BTNH->BNFT"),
((2, 5, 7, 3), (7, 3, 4), "BFND,NDH->BFH"),
((3, 4, 5), (5, 6, 2), "BFD,DNH->BFNH"),
((7, 11, 13), (7, 11, 13, 5), "BIN,BINJ->BIJ"),
((7, 11, 19), (7, 11, 13, 19), "BIJ,BINJ->BIN"),
((5, 13, 3, 11), (5, 11, 13, 8), "ACBE,AECD->ABCD"),
((5, 11, 7, 3), (5, 8, 7, 3), "AECD,ABCD->ACBE"),
((5, 4, 3), (3, 2, 1), "...ij,j...->i..."),
((5, 4, 3), (3, 2, 1), "...ij,j...->...i"),
((1, 11, 19), (7, 11, 13, 19), "...IJ,...INJ->...IN"),
((1, 11, 19), (7, 11, 13, 19), "...IJ,...INJ->IN..."),
((4, 3, 2, 5), (3, 6, 1), "ij...,jk...->ik..."),
((4, 3, 2, 5), (3, 6, 1), "ij...,jk...->...ik"),
],
},
]
def set_dynamic_shape(shape):
"""Convert dynamic shapes to static shapes."""
return [4 if x is None else x for x in shape]
def build_graph(parameters):
"""Build a simple graph with einsum Op."""
input0_shape = parameters["shapes"][0]
input1_shape = parameters["shapes"][1]
equation = parameters["shapes"][2]
input0_tensor = tf.compat.v1.placeholder(
dtype=parameters["dtype"], shape=input0_shape)
input1_tensor = tf.compat.v1.placeholder(
dtype=parameters["dtype"], shape=input1_shape)
out = tf.einsum(equation, input0_tensor, input1_tensor)
return [input0_tensor, input1_tensor], [out]
def build_inputs(parameters, sess, inputs, outputs):
"""Feed inputs, assign variables, and freeze graph."""
input0_shape = set_dynamic_shape(parameters["shapes"][0])
input1_shape = set_dynamic_shape(parameters["shapes"][1])
input0_value = create_tensor_data(parameters["dtype"], input0_shape)
input1_value = create_tensor_data(parameters["dtype"], input1_shape)
output_values = sess.run(
outputs, feed_dict=dict(zip(inputs, [input0_value, input1_value])))
return [input0_value, input1_value], output_values
make_zip_of_tests(
options,
test_parameters,
build_graph,
build_inputs,
use_frozen_graph=True)
@@ -0,0 +1,114 @@
# 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.
# ==============================================================================
"""Test configs for elementwise ops."""
import tensorflow as tf
from tensorflow.lite.testing.zip_test_utils import create_tensor_data
from tensorflow.lite.testing.zip_test_utils import make_zip_of_tests
from tensorflow.lite.testing.zip_test_utils import register_make_test_function
def _make_elementwise_tests(
op,
allow_fully_quantize=False,
min_value=-100,
max_value=100,
):
"""Make a set of tests to do element-wise operations."""
def f(options):
"""Actual function that generates examples."""
test_parameters = [
{
"input_dtype": [tf.float32],
"input_shape": [[], [1], [1, 2], [5, 6, 7, 8], [3, 4, 5, 6]],
"fully_quantize": [False],
"quant_16x8": [False],
"input_range": [[min_value, max_value]],
},
{
"input_dtype": [tf.float32],
"input_shape": [[], [1], [1, 2], [5, 6, 7, 8], [3, 4, 5, 6]],
"fully_quantize": [True],
"quant_16x8": [False, True],
"input_range": [[min_value, max_value]],
},
]
if not allow_fully_quantize:
test_parameters = [
test_parameter for test_parameter in test_parameters
if True not in test_parameter["fully_quantize"]
]
def build_graph(parameters):
"""Build the unary op testing graph."""
input_value = tf.compat.v1.placeholder(
dtype=parameters["input_dtype"],
name="input1",
shape=parameters["input_shape"])
out = op(input_value)
return [input_value], [out]
def build_inputs(parameters, sess, inputs, outputs):
input_value = create_tensor_data(parameters["input_dtype"],
parameters["input_shape"],
min_value=min_value,
max_value=max_value)
return [input_value], sess.run(
outputs, feed_dict={inputs[0]: input_value})
make_zip_of_tests(options, test_parameters, build_graph, build_inputs)
return f
@register_make_test_function()
def make_sin_tests(options):
"""Make a set of tests to do sin."""
return _make_elementwise_tests(tf.sin)(options)
@register_make_test_function()
def make_log_tests(options):
"""Make a set of tests to do log."""
return _make_elementwise_tests(
tf.math.log,
allow_fully_quantize=True,
min_value=0.1,
max_value=10,
)(options)
@register_make_test_function()
def make_sqrt_tests(options):
"""Make a set of tests to do sqrt."""
return _make_elementwise_tests(tf.sqrt)(options)
@register_make_test_function()
def make_rsqrt_tests(options):
"""Make a set of tests to do 1/sqrt."""
return _make_elementwise_tests(
tf.math.rsqrt,
allow_fully_quantize=True,
min_value=0.1,
max_value=1,
)(options)
@register_make_test_function()
def make_square_tests(options):
"""Make a set of tests to do square."""
return _make_elementwise_tests(tf.square)(options)
+49
View File
@@ -0,0 +1,49 @@
# 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.
# ==============================================================================
"""Test configs for elu."""
import numpy as np
import tensorflow as tf
from tensorflow.lite.testing.zip_test_utils import create_tensor_data
from tensorflow.lite.testing.zip_test_utils import make_zip_of_tests
from tensorflow.lite.testing.zip_test_utils import register_make_test_function
@register_make_test_function()
def make_elu_tests(options):
"""Make a set of tests to do (float) tf.nn.elu."""
test_parameters = [
{
"input_shape": [[], [1], [2, 3], [1, 1, 1, 1], [1, 3, 4, 3],
[3, 15, 14, 3], [3, 1, 2, 4, 6], [2, 2, 3, 4, 5, 6]],
},
]
def build_graph(parameters):
"""Build the graph for the test case."""
input_tensor = tf.compat.v1.placeholder(
dtype=tf.float32, name="input", shape=parameters["input_shape"])
out = tf.nn.elu(input_tensor)
return [input_tensor], [out]
def build_inputs(parameters, sess, inputs, outputs):
"""Build the inputs for the test case."""
input_values = create_tensor_data(
np.float32, parameters["input_shape"], min_value=-4, max_value=10)
return [input_values], sess.run(
outputs, feed_dict=dict(zip(inputs, [input_values])))
make_zip_of_tests(options, test_parameters, build_graph, build_inputs)
@@ -0,0 +1,56 @@
# 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.
# ==============================================================================
"""Test configs for embedding_lookup."""
import tensorflow as tf
from tensorflow.lite.testing.zip_test_utils import create_tensor_data
from tensorflow.lite.testing.zip_test_utils import make_zip_of_tests
from tensorflow.lite.testing.zip_test_utils import register_make_test_function
@register_make_test_function()
def make_embedding_lookup_tests(options):
"""Make a set of tests to do gather."""
test_parameters = [
{
"params_dtype": [tf.float32],
"params_shape": [[10], [10, 10]],
"ids_dtype": [tf.int32],
"ids_shape": [[3], [5]],
},
]
def build_graph(parameters):
"""Build the gather op testing graph."""
params = tf.compat.v1.placeholder(
dtype=parameters["params_dtype"],
name="params",
shape=parameters["params_shape"])
ids = tf.compat.v1.placeholder(
dtype=parameters["ids_dtype"],
name="ids",
shape=parameters["ids_shape"])
out = tf.nn.embedding_lookup(params=params, ids=ids)
return [params, ids], [out]
def build_inputs(parameters, sess, inputs, outputs):
params = create_tensor_data(parameters["params_dtype"],
parameters["params_shape"])
ids = create_tensor_data(parameters["ids_dtype"], parameters["ids_shape"],
0, parameters["params_shape"][0] - 1)
return [params, ids], sess.run(
outputs, feed_dict=dict(zip(inputs, [params, ids])))
make_zip_of_tests(options, test_parameters, build_graph, build_inputs)
+64
View File
@@ -0,0 +1,64 @@
# 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.
# ==============================================================================
"""Test configs for equal."""
import tensorflow as tf
from tensorflow.lite.testing.zip_test_utils import create_tensor_data
from tensorflow.lite.testing.zip_test_utils import make_zip_of_tests
from tensorflow.lite.testing.zip_test_utils import register_make_test_function
@register_make_test_function()
def make_equal_tests(options):
"""Make a set of tests to do equal."""
test_parameters = [{
"input_dtype": [tf.float32, tf.int16, tf.int32, tf.int64, tf.string],
"input_shape_pair": [([], []), ([1, 1, 1, 3], [1, 1, 1, 3]),
([2, 3, 4, 5], [2, 3, 4, 5]), ([2, 3, 3], [2, 3]),
([5, 5], [1]), ([10], [2, 4, 10])],
"fully_quantize": [False],
}, {
"input_dtype": [tf.float32],
"input_shape_pair": [([1, 1, 1, 3], [1, 1, 1, 3]), ([2, 3, 3], [2, 3])],
"fully_quantize": [True],
}]
def build_graph(parameters):
"""Build the equal op testing graph."""
input_value1 = tf.compat.v1.placeholder(
dtype=parameters["input_dtype"],
name="input1",
shape=parameters["input_shape_pair"][0])
input_value2 = tf.compat.v1.placeholder(
dtype=parameters["input_dtype"],
name="input2",
shape=parameters["input_shape_pair"][1])
out = tf.equal(input_value1, input_value2)
return [input_value1, input_value2], [out]
def build_inputs(parameters, sess, inputs, outputs):
input_value1 = create_tensor_data(parameters["input_dtype"],
parameters["input_shape_pair"][0])
input_value2 = create_tensor_data(parameters["input_dtype"],
parameters["input_shape_pair"][1])
return [input_value1, input_value2], sess.run(
outputs, feed_dict=dict(zip(inputs, [input_value1, input_value2])))
make_zip_of_tests(
options,
test_parameters,
build_graph,
build_inputs,
expected_tf_failures=6)
+63
View File
@@ -0,0 +1,63 @@
# 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.
# ==============================================================================
"""Test configs for exp."""
import tensorflow as tf
from tensorflow.lite.testing.zip_test_utils import create_tensor_data
from tensorflow.lite.testing.zip_test_utils import make_zip_of_tests
from tensorflow.lite.testing.zip_test_utils import register_make_test_function
@register_make_test_function()
def make_exp_tests(options):
"""Make a set of tests to do exp."""
test_parameters = [
{
"input_dtype": [tf.float32],
"input_shape": [[], [3], [1, 100], [4, 2, 3], [5, 224, 224, 3]],
"input_range": [(-100, 9)],
},
{
"input_dtype": [tf.float32],
"input_shape": [[], [3], [1, 100], [4, 2, 3], [5, 224, 224, 3]],
"input_range": [(-2, 2)],
"fully_quantize": [True],
"quant_16x8": [False, True],
},
]
def build_graph(parameters):
"""Build the exp op testing graph."""
input_tensor = tf.compat.v1.placeholder(
dtype=parameters["input_dtype"],
name="input",
shape=parameters["input_shape"])
out = tf.exp(input_tensor)
return [input_tensor], [out]
def build_inputs(parameters, sess, inputs, outputs):
min_value, max_value = parameters["input_range"]
values = [
create_tensor_data(
parameters["input_dtype"],
parameters["input_shape"],
min_value=min_value,
max_value=max_value,
)
]
return values, sess.run(outputs, feed_dict=dict(zip(inputs, values)))
make_zip_of_tests(options, test_parameters, build_graph, build_inputs)
@@ -0,0 +1,75 @@
# 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.
# ==============================================================================
"""Test configs for expand_dims."""
import numpy as np
import tensorflow as tf
from tensorflow.lite.testing.zip_test_utils import create_tensor_data
from tensorflow.lite.testing.zip_test_utils import make_zip_of_tests
from tensorflow.lite.testing.zip_test_utils import register_make_test_function
@register_make_test_function()
def make_expand_dims_tests(options):
"""Make a set of tests to do expand_dims."""
test_parameters = [{
"input_type": [tf.float32, tf.int32],
"input_shape": [[5, 4], [1, 5, 4]],
"axis_value": [0, 1, 2, -1, -2, -3],
"constant_axis": [True, False],
"fully_quantize": [False],
}, {
"input_type": [tf.float32],
"input_shape": [[5, 4], [1, 5, 4]],
"axis_value": [0, 1, 2, -1, -2, -3],
"constant_axis": [True],
"fully_quantize": [True],
}]
def build_graph(parameters):
"""Build the where op testing graph."""
inputs = []
input_value = tf.compat.v1.placeholder(
dtype=parameters["input_type"],
name="input",
shape=parameters["input_shape"])
inputs.append(input_value)
if parameters["constant_axis"]:
axis_value = tf.constant(
parameters["axis_value"], dtype=tf.int32, shape=[1])
else:
axis_value = tf.compat.v1.placeholder(
dtype=tf.int32, name="axis", shape=[1])
inputs.append(axis_value)
out = tf.expand_dims(input_value, axis=axis_value)
return inputs, [out]
def build_inputs(parameters, sess, inputs, outputs):
"""Builds the inputs for expand_dims."""
input_values = []
input_values.append(
create_tensor_data(
parameters["input_type"],
parameters["input_shape"],
min_value=-1,
max_value=1))
if not parameters["constant_axis"]:
input_values.append(np.array([parameters["axis_value"]], dtype=np.int32))
return input_values, sess.run(
outputs, feed_dict=dict(zip(inputs, input_values)))
make_zip_of_tests(options, test_parameters, build_graph, build_inputs)
+49
View File
@@ -0,0 +1,49 @@
# 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.
# ==============================================================================
"""Test configs for expm1."""
import numpy as np
import tensorflow as tf
from tensorflow.lite.testing.zip_test_utils import create_tensor_data
from tensorflow.lite.testing.zip_test_utils import make_zip_of_tests
from tensorflow.lite.testing.zip_test_utils import register_make_test_function
@register_make_test_function()
def make_expm1_tests(options):
"""Make a set of tests to do (float) tf.math.expm1."""
test_parameters = [
{
"input_shape": [[], [1], [2, 3], [1, 1, 1, 1], [1, 3, 4, 3],
[3, 15, 14, 3], [3, 1, 2, 4, 6], [2, 2, 3, 4, 5, 6]],
},
]
def build_graph(parameters):
"""Build the graph for the test case."""
input_tensor = tf.compat.v1.placeholder(
dtype=tf.float32, name="input", shape=parameters["input_shape"])
out = tf.math.expm1(input_tensor)
return [input_tensor], [out]
def build_inputs(parameters, sess, inputs, outputs):
"""Build the inputs for the test case."""
input_values = create_tensor_data(
np.float32, parameters["input_shape"], min_value=-4, max_value=10)
return [input_values], sess.run(
outputs, feed_dict=dict(zip(inputs, [input_values])))
make_zip_of_tests(options, test_parameters, build_graph, build_inputs)
+63
View File
@@ -0,0 +1,63 @@
# 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.
# ==============================================================================
"""Test configs for eye."""
import numpy as np
import tensorflow as tf
from tensorflow.lite.testing.zip_test_utils import create_scalar_data
from tensorflow.lite.testing.zip_test_utils import make_zip_of_tests
from tensorflow.lite.testing.zip_test_utils import register_make_test_function
@register_make_test_function()
def make_eye_tests(options):
"""Make a set of tests for tf.eye op."""
test_parameters = [{
"num_rows_shape": [[]],
"num_cols_shape": [[]],
"batch_shape": [[3], [2, 4], [4, 5, 6], None],
"use_num_cols": [True, False],
"dtype": [tf.float32, tf.int32],
}]
def build_graph(parameters):
"""Make a set of tests to do eye."""
input_tensor0 = tf.compat.v1.placeholder(
dtype=tf.int32, name="num_rows", shape=parameters["num_rows_shape"])
input_tensor1 = tf.compat.v1.placeholder(
dtype=tf.int32, name="num_columns", shape=parameters["num_cols_shape"])
if parameters["use_num_cols"]:
outs = tf.eye(
num_rows=input_tensor0,
num_columns=input_tensor1,
batch_shape=parameters["batch_shape"],
dtype=parameters["dtype"])
return [input_tensor0, input_tensor1], [outs]
else:
outs = tf.eye(num_rows=input_tensor0, dtype=parameters["dtype"])
return [input_tensor0], [outs]
def build_inputs(parameters, sess, inputs, outputs):
input_value0 = create_scalar_data(dtype=np.int32, min_value=1)
input_value1 = create_scalar_data(dtype=np.int32, min_value=1)
if parameters["use_num_cols"]:
return [input_value0, input_value1], sess.run(
outputs, feed_dict=dict(zip(inputs, [input_value0, input_value1])))
else:
return [input_value0], sess.run(
outputs, feed_dict=dict(zip(inputs, [input_value0])))
make_zip_of_tests(options, test_parameters, build_graph, build_inputs)
+88
View File
@@ -0,0 +1,88 @@
# 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.
# ==============================================================================
"""Test configs for fill."""
import tensorflow.compat.v2 as tf
from tensorflow.lite.testing.zip_test_utils import create_scalar_data
from tensorflow.lite.testing.zip_test_utils import create_tensor_data
from tensorflow.lite.testing.zip_test_utils import make_zip_of_tests
from tensorflow.lite.testing.zip_test_utils import register_make_test_function
@register_make_test_function()
def make_fill_tests(options):
"""Make a set of tests to do fill."""
test_parameters = [{
"dims_dtype": [tf.int32, tf.int64],
"dims_shape": [[], [1], [3], [3, 3]],
"value_dtype": [tf.int32, tf.int64, tf.float32, tf.bool, tf.string],
}]
def build_graph(parameters):
"""Build the fill op testing graph."""
input1 = tf.compat.v1.placeholder(
dtype=parameters["dims_dtype"],
name="dims",
shape=parameters["dims_shape"])
input2 = tf.compat.v1.placeholder(
dtype=parameters["value_dtype"], name="value", shape=[])
out = tf.fill(input1, input2)
return [input1, input2], [out]
def build_inputs(parameters, sess, inputs, outputs):
input1 = create_tensor_data(parameters["dims_dtype"],
parameters["dims_shape"], 1)
input2 = create_scalar_data(parameters["value_dtype"])
return [input1, input2], sess.run(
outputs, feed_dict=dict(zip(inputs, [input1, input2])))
make_zip_of_tests(
options,
test_parameters,
build_graph,
build_inputs,
expected_tf_failures=20)
@register_make_test_function()
def make_fill_16_tests(options):
"""Make a set of tests to do fill with fp16."""
test_parameters = [{
"dims_dtype": [tf.int32, tf.int64],
"dims_shape": [[], [1], [3], [3, 3]],
}]
def build_graph(parameters):
"""Build the fill op testing graph."""
input1 = tf.compat.v1.placeholder(
dtype=parameters["dims_dtype"],
name="dims",
shape=parameters["dims_shape"])
const_fp16 = tf.constant(1.0, dtype=tf.float16)
out = tf.fill(input1, const_fp16)
return [input1], [out]
def build_inputs(parameters, sess, inputs, outputs):
input1 = create_tensor_data(parameters["dims_dtype"],
parameters["dims_shape"], 1)
return [input1], sess.run(outputs, feed_dict=dict(zip(inputs, [input1])))
make_zip_of_tests(
options,
test_parameters,
build_graph,
build_inputs,
expected_tf_failures=0)
+45
View File
@@ -0,0 +1,45 @@
# 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.
# ==============================================================================
"""Test configs for floor."""
import tensorflow as tf
from tensorflow.lite.testing.zip_test_utils import create_tensor_data
from tensorflow.lite.testing.zip_test_utils import make_zip_of_tests
from tensorflow.lite.testing.zip_test_utils import register_make_test_function
@register_make_test_function()
def make_floor_tests(options):
"""Make a set of tests to do floor."""
test_parameters = [{
"input_dtype": [tf.float32],
"input_shape": [[], [1], [1, 2], [5, 6, 7, 8], [3, 4, 5, 6]],
}]
def build_graph(parameters):
"""Build the floor op testing graph."""
input_value = tf.compat.v1.placeholder(
dtype=parameters["input_dtype"],
name="input1",
shape=parameters["input_shape"])
out = tf.floor(input_value)
return [input_value], [out]
def build_inputs(parameters, sess, inputs, outputs):
input_value = create_tensor_data(parameters["input_dtype"],
parameters["input_shape"])
return [input_value], sess.run(outputs, feed_dict={inputs[0]: input_value})
make_zip_of_tests(options, test_parameters, build_graph, build_inputs)
@@ -0,0 +1,172 @@
# 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.
# ==============================================================================
"""Test configs for fully_connected."""
import numpy as np
import tensorflow as tf
from tensorflow.lite.testing.zip_test_utils import create_tensor_data
from tensorflow.lite.testing.zip_test_utils import make_zip_of_tests
from tensorflow.lite.testing.zip_test_utils import register_make_test_function
@register_make_test_function()
def make_fully_connected_tests(options):
"""Make a set of tests to do fully_connected."""
test_parameters = [{
"shape1": [[3, 3]],
"shape2": [[3, 3]],
"transpose_a": [True, False],
"transpose_b": [True, False],
"constant_filter": [True, False],
"fully_quantize": [False],
"quant_16x8": [False]
}, {
"shape1": [[4, 4], [1, 4], [4]],
"shape2": [[4, 4], [4, 1], [4]],
"transpose_a": [False],
"transpose_b": [False],
"constant_filter": [True, False],
"fully_quantize": [False],
"quant_16x8": [False]
}, {
"shape1": [[40, 37]],
"shape2": [[37, 40]],
"transpose_a": [False],
"transpose_b": [False],
"constant_filter": [True, False],
"fully_quantize": [False],
"quant_16x8": [False]
}, {
"shape1": [[40, 37]],
"shape2": [[40, 37]],
"transpose_a": [False],
"transpose_b": [True],
"constant_filter": [True, False],
"fully_quantize": [False],
"quant_16x8": [False]
}, {
"shape1": [[5, 3]],
"shape2": [[5, 3]],
"transpose_a": [True],
"transpose_b": [False],
"constant_filter": [True, False],
"fully_quantize": [False],
"quant_16x8": [False]
}, {
"shape1": [[1, 3]],
"shape2": [[3, 3]],
"transpose_a": [False],
"transpose_b": [False],
"constant_filter": [True],
"fully_quantize": [True],
"quant_16x8": [False]
}, {
"shape1": [[1, 4], [4]],
"shape2": [[4, 4], [4, 1], [4]],
"transpose_a": [False],
"transpose_b": [False],
"constant_filter": [True],
"fully_quantize": [True],
"quant_16x8": [False]
}, {
"shape1": [[1, 37], [2, 37]],
"shape2": [[37, 40]],
"transpose_a": [False],
"transpose_b": [False],
"constant_filter": [True],
"fully_quantize": [True],
"quant_16x8": [False]
}, {
"shape1": [[1, 3], [2, 3]],
"shape2": [[3, 5], [3, 1]],
"transpose_a": [False],
"transpose_b": [False],
"constant_filter": [True],
"fully_quantize": [True],
"quant_16x8": [False]
}, {
"shape1": [[2, 3]],
"shape2": [[3, 5]],
"transpose_a": [False],
"transpose_b": [False],
"constant_filter": [True],
"fully_quantize": [True],
"quant_16x8": [True]
}, {
"shape1": [[0, 3]],
"shape2": [[3, 3]],
"transpose_a": [False],
"transpose_b": [False],
"constant_filter": [True, False],
"fully_quantize": [False],
"quant_16x8": [False]
}, {
"shape1": [[3, 0]],
"shape2": [[0, 3]],
"transpose_a": [False],
"transpose_b": [False],
"constant_filter": [True, False],
"fully_quantize": [False],
"quant_16x8": [False]
}]
def build_graph(parameters):
"""Build a matmul graph given `parameters`."""
input_tensor1 = tf.compat.v1.placeholder(
dtype=tf.float32, name="input1", shape=parameters["shape1"])
# Get input_tensor2 either as a placeholder or constants. Also get a list of
# the input tensors that are represented as placeholders.
if parameters["constant_filter"]:
input_tensor2 = create_tensor_data(
np.float32, parameters["shape2"], min_value=-1, max_value=1)
input_tensors = [input_tensor1]
else:
input_tensor2 = tf.compat.v1.placeholder(
dtype=tf.float32, name="input2", shape=parameters["shape2"])
input_tensors = [input_tensor1, input_tensor2]
out = tf.matmul(
input_tensor1,
input_tensor2,
transpose_a=parameters["transpose_a"],
transpose_b=parameters["transpose_b"])
return input_tensors, [out]
def build_inputs(parameters, sess, inputs, outputs):
# pylint: disable=g-doc-return-or-yield, g-doc-args
"""Build list of input values.
It either contains 1 tensor (input_values1) or
2 tensors (input_values1, input_values2) based on whether the second input
is a constant or variable input.
"""
values = [
create_tensor_data(
np.float32, shape=parameters["shape1"], min_value=-1, max_value=1)
]
if not parameters["constant_filter"]:
values.append(
create_tensor_data(
np.float32, parameters["shape2"], min_value=-1, max_value=1))
return values, sess.run(outputs, feed_dict=dict(zip(inputs, values)))
make_zip_of_tests(
options,
test_parameters,
build_graph,
build_inputs,
expected_tf_failures=14)
@@ -0,0 +1,90 @@
# 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.
# ==============================================================================
"""Test configs for fully_connected_4bit."""
import numpy as np
import tensorflow as tf
from tensorflow.lite.testing.zip_test_utils import make_zip_of_tests
from tensorflow.lite.testing.zip_test_utils import register_make_test_function
@register_make_test_function()
def make_fully_connected_4bit_hybrid_tests(options):
"""Make a set of tests to do fully_connected."""
test_parameters = [
# Simple 3x3 test.
{
"shape1": [[3, 3]],
"shape2": [[3, 3]],
"dynamic_range_quantize": [True],
},
# Use optimized kernel.
{
"shape1": [[40, 42]],
"shape2": [[42, 40]],
"dynamic_range_quantize": [True],
},
# No optimization.
{
"shape1": [[1, 40]],
"shape2": [[40, 3]],
"dynamic_range_quantize": [True],
},
]
def build_graph(parameters):
"""Build a matmul graph given `parameters`."""
input_tensor1 = tf.compat.v1.placeholder(
dtype=tf.float32, name="input1", shape=parameters["shape1"]
)
# Create a float filter with no quantization loss.
float_data = np.random.uniform(-1, 1, parameters["shape2"])
scale = np.abs(float_data).max() / 7.0
int_data = np.round(float_data / scale)
input_tensor2 = tf.constant(int_data, dtype=tf.float32)
quantized = tf.quantization.fake_quant_with_min_max_vars(
input_tensor2, min=-7, max=7, num_bits=4, narrow_range=True
)
out = tf.matmul(input_tensor1, quantized)
return [input_tensor1], [out]
def create_input_data(parameters):
"""Create a float input with no quantization loss."""
float_data = np.random.random(parameters["shape1"]).astype(np.float32)
# Note that since the default ops dynamically quantize the inputs to four
# bits, but e.g. XNNPACK dynamically quantizes the inputs to 8 bits, we
# generate inputs in {-1, 0, 1} which will be quantized exactly by both
# schemes.
scale = np.abs(float_data).max(axis=1, keepdims=True) / 1.0
return np.round(float_data / scale)
def build_inputs(parameters, sess, inputs, outputs):
# pylint: disable=g-doc-return-or-yield, g-doc-args
"""Build list of input values.
Use the specialized method, as dynamic range quantization will cause
differing outputs from TF, which does not quantize inputs.
"""
values = [create_input_data(parameters)]
return values, sess.run(outputs, feed_dict=dict(zip(inputs, values)))
options.experimental_low_bit_qat = True
make_zip_of_tests(
options,
test_parameters,
build_graph,
build_inputs,
expected_tf_failures=0,
)
@@ -0,0 +1,89 @@
# 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.
# ==============================================================================
"""Test configs for fused_batch_norm."""
import numpy as np
import tensorflow as tf
from tensorflow.lite.testing.zip_test_utils import create_tensor_data
from tensorflow.lite.testing.zip_test_utils import make_zip_of_tests
from tensorflow.lite.testing.zip_test_utils import register_make_test_function
@register_make_test_function()
def make_fused_batch_norm_tests(options):
"""Make a set of tests to do fused_batch_norm."""
test_parameters = [{
"dtype": [tf.float32],
"input_shape": [[1, 1, 6, 2]],
"epsilon": [0.001, 0.1],
"is_training": [False],
}, {
"dtype": [tf.float32],
"input_shape": [[1, 1, 6, 2]],
"epsilon": [0.001, 0.1],
"is_training": [True],
}, {
"dtype": [tf.float32],
"input_shape": [[1, None, 6, 2]],
"epsilon": [0.001, 0.1],
"is_training": [True, False],
}]
def build_graph(parameters):
"""Build the testing graph for fused batch normalization."""
input_shape = parameters["input_shape"]
scale_shape = input_shape[3]
scale = create_tensor_data(parameters["dtype"], scale_shape)
offset = create_tensor_data(parameters["dtype"], scale_shape)
mean = create_tensor_data(parameters["dtype"], scale_shape)
variance = create_tensor_data(parameters["dtype"], scale_shape)
x = tf.compat.v1.placeholder(
dtype=parameters["dtype"], name="x", shape=parameters["input_shape"])
[x_norm, _, _] = tf.compat.v1.nn.fused_batch_norm(
x,
scale,
offset,
mean,
variance,
parameters["epsilon"],
data_format="NHWC",
is_training=parameters["is_training"])
input_tensor = tf.compat.v1.placeholder(
dtype=parameters["dtype"],
name="input",
shape=parameters["input_shape"])
out = tf.add(input_tensor, x_norm)
return [x, input_tensor], [out]
def build_inputs(parameters, sess, inputs, outputs):
# Fill dynamic shape with a random number.
input_shape = parameters["input_shape"]
input_shape = [
np.random.randint(1, 10) if v is None else v for v in input_shape
]
input_values = [
create_tensor_data(parameters["dtype"], input_shape),
create_tensor_data(parameters["dtype"], input_shape)
]
return input_values, sess.run(
outputs, feed_dict=dict(zip(inputs, input_values)))
make_zip_of_tests(options, test_parameters, build_graph, build_inputs)
+128
View File
@@ -0,0 +1,128 @@
# 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.
# ==============================================================================
"""Test configs for gather."""
import tensorflow as tf
from tensorflow.lite.testing.zip_test_utils import create_tensor_data
from tensorflow.lite.testing.zip_test_utils import make_zip_of_tests
from tensorflow.lite.testing.zip_test_utils import register_make_test_function
@register_make_test_function()
def make_gather_tests(options):
"""Make a set of tests to do gather."""
test_parameters = [
{
"params_dtype": [tf.float32, tf.int32, tf.int64, tf.int16],
"params_shape": [[1, 2, 20]],
"indices_dtype": [tf.int32, tf.int64],
"indices_shape": [[3], [5]],
"axis": [-1, 0, 1],
"batch_dims": [0],
"constant_params": [False, True],
},
{
"params_dtype": [tf.string],
"params_shape": [[8]],
"indices_dtype": [tf.int32],
"indices_shape": [[3], [3, 2]],
"axis": [0],
"batch_dims": [0],
"constant_params": [False, True],
},
{
"params_dtype": [tf.float32],
"params_shape": [[1, 2, 20]],
"indices_dtype": [tf.int32, tf.int64],
"indices_shape": [[3], [5]],
"axis": [-1, 0, 1],
"batch_dims": [0],
"constant_params": [False],
# Fix the indice values to prevent representative dataset generator
# from generating invalid values.
"constant_indices": [True],
"fully_quantize": [True],
"input_range": [(-10, 10)],
},
{
# Test with batch_dims.
"params_dtype": [tf.float32, tf.int32],
"params_shape": [[2, 2, 3, 5]],
"indices_dtype": [tf.int32],
"indices_shape": [[2, 2, 2]],
"axis": [0, 2],
"batch_dims": [1, 2],
"constant_params": [False, True],
}
]
def build_graph(parameters):
"""Build the gather op testing graph."""
inputs = []
if parameters["constant_params"]:
params = create_tensor_data(parameters["params_dtype"],
parameters["params_shape"])
else:
params = tf.compat.v1.placeholder(
dtype=parameters["params_dtype"],
name="params",
shape=parameters["params_shape"])
inputs.append(params)
if parameters.get("constant_indices", False):
indices = create_tensor_data(
parameters["indices_dtype"],
parameters["indices_shape"],
min_value=0,
max_value=parameters["params_shape"][0] - 1)
else:
indices = tf.compat.v1.placeholder(
dtype=parameters["indices_dtype"],
name="indices",
shape=parameters["indices_shape"])
inputs.append(indices)
axis = min(len(parameters["params_shape"]), parameters["axis"])
out = tf.gather(
params, indices, axis=axis, batch_dims=parameters["batch_dims"])
return inputs, [out]
def build_inputs(parameters, sess, inputs, outputs):
input_values = []
min_value, max_value = parameters.get("input_range", (-10, 10))
if not parameters["constant_params"]:
params = create_tensor_data(
parameters["params_dtype"],
parameters["params_shape"],
min_value=min_value,
max_value=max_value)
input_values.append(params)
if not parameters.get("constant_indices", False):
indices = create_tensor_data(
parameters["indices_dtype"],
parameters["indices_shape"],
min_value=0,
max_value=parameters["params_shape"][0] - 1)
input_values.append(indices)
return input_values, sess.run(
outputs, feed_dict=dict(zip(inputs, input_values)))
make_zip_of_tests(
options,
test_parameters,
build_graph,
build_inputs,
expected_tf_failures=0)
@@ -0,0 +1,96 @@
# 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.
# ==============================================================================
"""Test configs for gather_nd."""
import tensorflow as tf
from tensorflow.lite.testing.zip_test_utils import create_tensor_data
from tensorflow.lite.testing.zip_test_utils import make_zip_of_tests
from tensorflow.lite.testing.zip_test_utils import register_make_test_function
@register_make_test_function()
def make_gather_nd_tests(options):
"""Make a set of tests to do gather_nd."""
test_parameters = [
{
"params_dtype": [
tf.float32,
tf.int16,
tf.int32,
tf.int64,
tf.string,
tf.bool,
],
"params_shape": [[5, 1]],
"indices_dtype": [tf.int16, tf.int32, tf.int64],
"indices_shape": [[1, 1]],
},
{
"params_dtype": [
tf.float32,
tf.int16,
tf.int32,
tf.int64,
tf.string,
tf.bool,
],
"params_shape": [[5, 5]],
"indices_dtype": [tf.int16, tf.int32, tf.int64],
"indices_shape": [[2, 1], [2, 2]],
},
{
"params_dtype": [
tf.float32,
tf.int16,
tf.int32,
tf.int64,
tf.string,
tf.bool,
],
"params_shape": [[5, 5, 10]],
"indices_dtype": [tf.int16, tf.int32, tf.int64],
"indices_shape": [[3, 1], [2, 2], [2, 3], [2, 1, 3]],
},
{
"params_dtype": [tf.float32, tf.string],
"params_shape": [[1, 0]],
"indices_dtype": [tf.int64],
"indices_shape": [[0, 2]],
},
]
def build_graph(parameters):
"""Build the gather_nd op testing graph."""
params = tf.compat.v1.placeholder(
dtype=parameters["params_dtype"],
name="params",
shape=parameters["params_shape"])
indices = tf.compat.v1.placeholder(
dtype=parameters["indices_dtype"],
name="indices",
shape=parameters["indices_shape"])
out = tf.gather_nd(params, indices)
return [params, indices], [out]
def build_inputs(parameters, sess, inputs, outputs):
params = create_tensor_data(parameters["params_dtype"],
parameters["params_shape"])
indices = create_tensor_data(parameters["indices_dtype"],
parameters["indices_shape"], 0,
parameters["params_shape"][0] - 1)
return [params, indices], sess.run(
outputs, feed_dict=dict(zip(inputs, [params, indices])))
make_zip_of_tests(options, test_parameters, build_graph, build_inputs)
@@ -0,0 +1,50 @@
# 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.
# ==============================================================================
"""Test configs for gather_with_constant."""
import numpy as np
import tensorflow as tf
from tensorflow.lite.testing.zip_test_utils import create_tensor_data
from tensorflow.lite.testing.zip_test_utils import make_zip_of_tests
from tensorflow.lite.testing.zip_test_utils import register_make_test_function
@register_make_test_function()
def make_gather_with_constant_tests(options):
"""Make a set of test which feed a constant to gather."""
test_parameters = [{
"input_shape": [[3]],
"reference_shape": [[2]],
}, {
"input_shape": [[2, 3]],
"reference_shape": [[2, 3]],
}]
def build_graph(parameters):
"""Build a graph where the inputs to Gather are constants."""
reference = tf.compat.v1.placeholder(
dtype=tf.int32, shape=parameters["reference_shape"])
gather_input = tf.constant(
create_tensor_data(tf.int32, parameters["input_shape"]))
gather_indices = tf.constant([0, 1], tf.int32)
out = tf.equal(reference, tf.gather(gather_input, gather_indices))
return [reference], [out]
def build_inputs(parameters, sess, inputs, outputs):
reference_values = np.zeros(parameters["reference_shape"], dtype=np.int32)
return [reference_values], sess.run(
outputs, feed_dict={inputs[0]: reference_values})
make_zip_of_tests(options, test_parameters, build_graph, build_inputs)
+77
View File
@@ -0,0 +1,77 @@
# 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.
# ==============================================================================
"""Test configs for gelu."""
import functools
import tensorflow as tf
from tensorflow.lite.python import lite
from tensorflow.lite.testing.zip_test_utils import create_tensor_data
from tensorflow.lite.testing.zip_test_utils import make_zip_of_tests
from tensorflow.lite.testing.zip_test_utils import register_make_test_function
def _tflite_convert_verify_op(tflite_convert_function, *args, **kwargs):
"""Verifies that the result of the conversion contains Gelu op."""
result = tflite_convert_function(*args, **kwargs)
tflite_model_binary = result[0]
if not result[0]:
tf.compat.v1.logging.error(result[1]) # stderr from running tflite_convert.
raise RuntimeError("Failed to build model: \n\n" + result[1])
interpreter = lite.Interpreter(model_content=tflite_model_binary)
interpreter.allocate_tensors()
for op in interpreter._get_ops_details(): # pylint: disable=protected-access
if op["op_name"] == "GELU":
return result
raise RuntimeError("Expected to generate GELU op node in graph.")
@register_make_test_function()
def make_gelu_tests(options):
"""Makes a set of tests for gelu."""
test_parameters = [{
"input_dtype": [tf.float32],
"input_shape": [[], [1], [2, 3], [1, 1, 1, 1], [1, 3, 4, 3],
[3, 15, 14, 3], [3, 1, 2, 4, 6], [2, 2, 3, 4, 5, 6]],
"fully_quantize": [False, True],
"input_range": [(-10, 10)],
"approximate": [True, False],
}]
def build_graph(parameters):
"""Builds the gelu op testing graph."""
input_tensor = tf.compat.v1.placeholder(
dtype=parameters["input_dtype"],
name="input",
shape=parameters["input_shape"])
out = tf.nn.gelu(input_tensor, approximate=parameters["approximate"])
return [input_tensor], [out]
def build_inputs(parameters, sess, inputs, outputs):
values = [
create_tensor_data(
parameters["input_dtype"],
parameters["input_shape"],
min_value=-8,
max_value=8)
]
return values, sess.run(outputs, feed_dict=dict(zip(inputs, values)))
if not options.run_with_flex:
options.tflite_convert_function = functools.partial(
_tflite_convert_verify_op,
options.tflite_convert_function)
make_zip_of_tests(options, test_parameters, build_graph, build_inputs)
@@ -0,0 +1,61 @@
# 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.
# ==============================================================================
"""Test configs for global_batch_norm."""
import tensorflow as tf
from tensorflow.lite.testing.zip_test_utils import create_tensor_data
from tensorflow.lite.testing.zip_test_utils import make_zip_of_tests
from tensorflow.lite.testing.zip_test_utils import register_make_test_function
@register_make_test_function()
def make_global_batch_norm_tests(options):
"""Make a set of tests to do batch_norm_with_global_normalization."""
test_parameters = [{
"dtype": [tf.float32],
"input_shape": [[1, 1, 6, 2], [3, 4, 5, 4]],
"epsilon": [0.1, 0.0001],
"scale_after": [True, False],
}]
def build_graph(parameters):
"""Build the global batch norm testing graph."""
input_shape = parameters["input_shape"]
scale_shape = input_shape[3]
scale = create_tensor_data(parameters["dtype"], scale_shape)
offset = create_tensor_data(parameters["dtype"], scale_shape)
mean = create_tensor_data(parameters["dtype"], scale_shape)
variance = create_tensor_data(parameters["dtype"], scale_shape)
x = create_tensor_data(parameters["dtype"], parameters["input_shape"])
x_norm = tf.nn.batch_norm_with_global_normalization(
x, mean, variance, scale, offset, parameters["epsilon"],
parameters["scale_after"])
input_tensor = tf.compat.v1.placeholder(
dtype=parameters["dtype"],
name="input",
shape=parameters["input_shape"])
out = tf.add(input_tensor, x_norm)
return [input_tensor], [out]
def build_inputs(parameters, sess, inputs, outputs):
input_value = create_tensor_data(parameters["dtype"],
parameters["input_shape"])
return [input_value], sess.run(
outputs, feed_dict=dict(zip(inputs, [input_value])))
make_zip_of_tests(options, test_parameters, build_graph, build_inputs)
@@ -0,0 +1,64 @@
# 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.
# ==============================================================================
"""Test configs for conv."""
import tensorflow as tf
from tensorflow.lite.testing.zip_test_utils import create_tensor_data
from tensorflow.lite.testing.zip_test_utils import make_zip_of_tests
from tensorflow.lite.testing.zip_test_utils import register_make_test_function
@register_make_test_function()
def make_greater_tests(options):
"""Make a set of tests to do greater."""
test_parameters = [{
"input_dtype": [tf.float32, tf.int32, tf.int64],
"input_shape_pair": [([1, 1, 1, 3], [1, 1, 1, 3]),
([2, 3, 4, 5], [2, 3, 4, 5]), ([2, 3, 3], [2, 3]),
([5, 5], [1]), ([10], [2, 4, 10])],
"fully_quantize": [False],
}, {
"input_dtype": [tf.float32],
"input_shape_pair": [([1, 1, 1, 3], [1, 1, 1, 3]), ([2, 3, 3], [2, 3])],
"fully_quantize": [True],
}]
def build_graph(parameters):
"""Build the greater op testing graph."""
input_value1 = tf.compat.v1.placeholder(
dtype=parameters["input_dtype"],
name="input1",
shape=parameters["input_shape_pair"][0])
input_value2 = tf.compat.v1.placeholder(
dtype=parameters["input_dtype"],
name="input2",
shape=parameters["input_shape_pair"][1])
out = tf.greater(input_value1, input_value2)
return [input_value1, input_value2], [out]
def build_inputs(parameters, sess, inputs, outputs):
input_value1 = create_tensor_data(parameters["input_dtype"],
parameters["input_shape_pair"][0])
input_value2 = create_tensor_data(parameters["input_dtype"],
parameters["input_shape_pair"][1])
return [input_value1, input_value2], sess.run(
outputs, feed_dict=dict(zip(inputs, [input_value1, input_value2])))
make_zip_of_tests(
options,
test_parameters,
build_graph,
build_inputs,
expected_tf_failures=4)
@@ -0,0 +1,64 @@
# 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.
# ==============================================================================
"""Test configs for greater_equal."""
import tensorflow as tf
from tensorflow.lite.testing.zip_test_utils import create_tensor_data
from tensorflow.lite.testing.zip_test_utils import make_zip_of_tests
from tensorflow.lite.testing.zip_test_utils import register_make_test_function
@register_make_test_function()
def make_greater_equal_tests(options):
"""Make a set of tests to do greater_equal."""
test_parameters = [{
"input_dtype": [tf.float32, tf.int16, tf.int32, tf.int64],
"input_shape_pair": [([1, 1, 1, 3], [1, 1, 1, 3]),
([2, 3, 4, 5], [2, 3, 4, 5]), ([2, 3, 3], [2, 3]),
([5, 5], [1]), ([10], [2, 4, 10])],
"fully_quantize": [False],
}, {
"input_dtype": [tf.float32],
"input_shape_pair": [([1, 1, 1, 3], [1, 1, 1, 3]), ([2, 3, 3], [2, 3])],
"fully_quantize": [True],
}]
def build_graph(parameters):
"""Build the greater_equal op testing graph."""
input_value1 = tf.compat.v1.placeholder(
dtype=parameters["input_dtype"],
name="input1",
shape=parameters["input_shape_pair"][0])
input_value2 = tf.compat.v1.placeholder(
dtype=parameters["input_dtype"],
name="input2",
shape=parameters["input_shape_pair"][1])
out = tf.greater_equal(input_value1, input_value2)
return [input_value1, input_value2], [out]
def build_inputs(parameters, sess, inputs, outputs):
input_value1 = create_tensor_data(parameters["input_dtype"],
parameters["input_shape_pair"][0])
input_value2 = create_tensor_data(parameters["input_dtype"],
parameters["input_shape_pair"][1])
return [input_value1, input_value2], sess.run(
outputs, feed_dict=dict(zip(inputs, [input_value1, input_value2])))
make_zip_of_tests(
options,
test_parameters,
build_graph,
build_inputs,
expected_tf_failures=5)
@@ -0,0 +1,80 @@
# 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.
# ==============================================================================
"""Test configs for hardswish."""
import functools
import numpy as np
import tensorflow as tf
from tensorflow.lite.python import lite
from tensorflow.lite.testing.zip_test_utils import create_tensor_data
from tensorflow.lite.testing.zip_test_utils import make_zip_of_tests
from tensorflow.lite.testing.zip_test_utils import register_make_test_function
def _tflite_convert_verify_num_ops(tflite_convert_function, *args, **kwargs):
"""Verifies that the result of the conversion is a single op."""
num_ops = kwargs.pop("num_ops", 2)
result = tflite_convert_function(*args, **kwargs)
tflite_model_binary = result[0]
if not result[0]:
tf.compat.v1.logging.error(result[1]) # stderr from running tflite_convert.
raise RuntimeError("Failed to build model: \n\n" + result[1])
interpreter = lite.Interpreter(model_content=tflite_model_binary)
interpreter.allocate_tensors()
if len(interpreter.get_tensor_details()) != num_ops:
raise RuntimeError(
"Expected to generate two node graph got %s " %
"\n".join(str(x) for x in interpreter.get_tensor_details()))
return result
@register_make_test_function()
def make_hardswish_tests(options):
"""Make a set of tests to do hardswish."""
# Chose a set of parameters
if options.run_with_flex:
# Only Flex is able to execute on the data bigger than four dimension.
test_parameters = [{
"input_shape": [[], [1], [2, 3], [1, 1, 1, 1], [1, 3, 4, 3],
[3, 15, 14, 3], [3, 1, 2, 4, 6], [2, 2, 3, 4, 5, 6]],
}]
else:
test_parameters = [{
"input_shape": [[], [1], [2, 3], [1, 1, 1, 1], [1, 3, 4, 3],
[3, 15, 14, 3]],
}]
def build_graph(parameters):
inp = tf.compat.v1.placeholder(
dtype=tf.float32, name="input", shape=parameters["input_shape"])
out = inp * tf.nn.relu6(inp + np.float32(3)) * np.float32(1. / 6.)
return [inp], [out]
def build_inputs(parameters, sess, inputs, outputs):
input_values = create_tensor_data(
np.float32, parameters["input_shape"], min_value=-10, max_value=10)
return [input_values], sess.run(
outputs, feed_dict=dict(zip(inputs, [input_values])))
# Add additional validation if we are using converter.
# Flex doesn't yet support this.
if not options.run_with_flex:
options.tflite_convert_function = functools.partial(
_tflite_convert_verify_num_ops,
options.tflite_convert_function,
num_ops=2)
make_zip_of_tests(options, test_parameters, build_graph, build_inputs)
@@ -0,0 +1,92 @@
# 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.
# ==============================================================================
"""Test configs for identifying dilated conv."""
import numpy as np
import tensorflow as tf
from tensorflow.lite.testing.zip_test_utils import create_tensor_data
from tensorflow.lite.testing.zip_test_utils import make_zip_of_tests
from tensorflow.lite.testing.zip_test_utils import register_make_test_function
@register_make_test_function()
def make_identify_dilated_conv_tests(options):
"""Make a set of tests to do dilated convolution."""
test_parameters = [
{
"input_shape": [[1, 3, 4, 3], [4, 6, 6, 1]],
"filter_shape": [[1, 1], [2, 3], [3, 3]],
"strides": [[1, 1, 1, 1], [1, 2, 3, 1]],
"dilations": [[1, 3, 2, 1], [1, 2, 2, 1], [1, 2, 1, 1]],
"padding": ["VALID", "SAME"],
"data_format": ["NHWC"],
"constant_filter": [True, False],
"channel_multiplier": [1, 2],
},
]
def get_tensor_shapes(parameters):
input_shape = parameters["input_shape"]
filter_size = parameters["filter_shape"]
filter_shape = filter_size + [
input_shape[3], parameters["channel_multiplier"]
]
return [input_shape, filter_shape]
def build_graph(parameters):
"""Build a conv graph given `parameters`."""
input_shape, filter_shape = get_tensor_shapes(parameters)
input_tensor = tf.compat.v1.placeholder(
dtype=tf.float32, name="input", shape=input_shape)
# Get filter input either as a placeholder or constants. Also get a list of
# the input tensors that are represented as placeholders.
if parameters["constant_filter"]:
filter_input = create_tensor_data(
np.float32, filter_shape, min_value=-10, max_value=10)
input_tensors = [input_tensor]
else:
filter_input = tf.compat.v1.placeholder(
dtype=tf.float32, name="filter", shape=filter_shape)
input_tensors = [input_tensor, filter_input]
# Use `tf.nn.convolution` here since it will create the `batch_to_space` and
# the `space_to_batch` ops respectively.
out = tf.nn.convolution(
input=input_tensor,
filters=filter_input,
strides=parameters["strides"],
dilations=parameters["dilations"],
padding=parameters["padding"],
data_format=parameters["data_format"])
return input_tensors, [out]
def build_inputs(parameters, sess, inputs, outputs):
# Build list of input values either containing 1 tensor (input) or 2 tensors
# (input, filter) based on whether filter is constant or variable input.
input_shape, filter_shape = get_tensor_shapes(parameters)
values = [
create_tensor_data(np.float32, input_shape, min_value=-1, max_value=1)
]
if not parameters["constant_filter"]:
values.append(create_tensor_data(np.float32, filter_shape))
return values, sess.run(outputs, feed_dict=dict(zip(inputs, values)))
make_zip_of_tests(
options,
test_parameters,
build_graph,
build_inputs,
expected_tf_failures=168)
@@ -0,0 +1,75 @@
# 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.
# ==============================================================================
"""Test configs for identifying dilated Conv1D."""
import numpy as np
import tensorflow as tf
from tensorflow.lite.testing.zip_test_utils import create_tensor_data
from tensorflow.lite.testing.zip_test_utils import make_zip_of_tests
from tensorflow.lite.testing.zip_test_utils import register_make_test_function
@register_make_test_function()
def make_identify_dilated_conv1d_tests(options):
"""Make a set of tests to do 1D dilated convolution."""
test_parameters = [
{
"input_shape": [[1, 3, 3], [4, 6, 1]],
"filter_size": [1, 2, 3],
"stride": [1, 2],
"dilations": [1, 2, 3],
"padding": ["VALID", "SAME"],
"num_filters": [1, 2],
},
]
def get_tensor_shapes(parameters):
input_shape = parameters["input_shape"]
filter_size = parameters["filter_size"]
filter_shape = [filter_size, input_shape[2], parameters["num_filters"]]
return [input_shape, filter_shape]
def build_graph(parameters):
"""Build a conv graph given `parameters`."""
input_shape, filter_shape = get_tensor_shapes(parameters)
filter_input = tf.compat.v1.placeholder(
dtype=tf.float32, name="filter", shape=filter_shape)
input_tensor = tf.compat.v1.placeholder(
dtype=tf.float32, name="input", shape=input_shape)
input_tensors = [input_tensor, filter_input]
out = tf.nn.conv1d(
input=input_tensor,
filters=filter_input,
stride=parameters["stride"],
dilations=parameters["dilations"],
padding=parameters["padding"])
return input_tensors, [out]
def build_inputs(parameters, sess, inputs, outputs):
input_shape, filter_shape = get_tensor_shapes(parameters)
values = [
create_tensor_data(np.float32, input_shape, min_value=-1, max_value=1),
create_tensor_data(np.float32, filter_shape)
]
return values, sess.run(outputs, feed_dict=dict(zip(inputs, values)))
make_zip_of_tests(
options,
test_parameters,
build_graph,
build_inputs,
expected_tf_failures=16)
@@ -0,0 +1,73 @@
# 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.
# ==============================================================================
"""Test configs for identity."""
import numpy as np
import tensorflow as tf
from tensorflow.lite.testing.zip_test_utils import create_tensor_data
from tensorflow.lite.testing.zip_test_utils import make_zip_of_tests
from tensorflow.lite.testing.zip_test_utils import register_make_test_function
from tensorflow.python.ops import array_ops
@register_make_test_function()
def make_identity_tests(options):
"""Make a set of tests to do identity."""
# Chose a set of parameters
test_parameters = [{
"input_shape": [[], [1], [3, 3]],
"op_to_use": [
"identity", "identity_n", "snapshot", "identity_n_with_2_inputs"
],
}]
def build_graph(parameters):
"""Make a set of tests to do identity."""
input_tensors = []
input_count = (2 if parameters["op_to_use"] == "identity_n_with_2_inputs"
else 1)
input_tensors = [
tf.compat.v1.placeholder(
dtype=tf.float32, name="input", shape=parameters["input_shape"])
for _ in range(input_count)
]
# We add the Multiply before Identity just as a walk-around to make the test
# pass when input_shape is scalar.
# During graph transformation, converter will replace the Identity op with
# Reshape when input has shape. However, currently converter can't
# distinguish between missing shape and scalar shape. As a result, when
# input has scalar shape, this conversion still fails.
inputs_doubled = [input_tensor * 2.0 for input_tensor in input_tensors]
if parameters["op_to_use"] == "identity":
identity_outputs = [tf.identity(inputs_doubled[0])]
elif parameters["op_to_use"] == "snapshot":
identity_outputs = [array_ops.snapshot(inputs_doubled[0])]
elif parameters["op_to_use"] in ("identity_n", "identity_n_with_2_inputs"):
identity_outputs = tf.identity_n(inputs_doubled)
return input_tensors, identity_outputs
def build_inputs(parameters, sess, inputs, outputs):
input_values = [
create_tensor_data(
np.float32, parameters["input_shape"], min_value=-4, max_value=10)
for _ in range(len(inputs))
]
return input_values, sess.run(
outputs, feed_dict=dict(zip(inputs, input_values)))
make_zip_of_tests(options, test_parameters, build_graph, build_inputs)
+49
View File
@@ -0,0 +1,49 @@
# 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.
# ==============================================================================
"""Test configs for imag op."""
import tensorflow as tf
from tensorflow.lite.testing.zip_test_utils import create_tensor_data
from tensorflow.lite.testing.zip_test_utils import make_zip_of_tests
from tensorflow.lite.testing.zip_test_utils import register_make_test_function
@register_make_test_function()
def make_imag_tests(options):
"""Make a set of tests to do imag op."""
# Chose a set of parameters
test_parameters = [{
"dtype": [tf.complex64, tf.complex128],
"input_shape": [[], [1], [2, 3], [1, 3, 4, 3], [2, 2, 3, 4, 5, 6]],
}]
def build_graph(parameters):
input_tensor = tf.compat.v1.placeholder(
dtype=parameters["dtype"],
name="input",
shape=parameters["input_shape"])
out = tf.math.imag(input_tensor)
return [input_tensor], [out]
def build_inputs(parameters, sess, inputs, outputs):
input_values = create_tensor_data(
parameters["dtype"].as_numpy_dtype,
parameters["input_shape"],
min_value=-10,
max_value=10)
return [input_values], sess.run(
outputs, feed_dict=dict(zip(inputs, [input_values])))
make_zip_of_tests(options, test_parameters, build_graph, build_inputs)
@@ -0,0 +1,64 @@
# 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.
# ==============================================================================
"""Test configs for irfft2d."""
import numpy as np
import tensorflow as tf
from tensorflow.lite.testing.zip_test_utils import create_tensor_data
from tensorflow.lite.testing.zip_test_utils import ExtraConvertOptions
from tensorflow.lite.testing.zip_test_utils import make_zip_of_tests
from tensorflow.lite.testing.zip_test_utils import register_make_test_function
@register_make_test_function()
def make_irfft2d_tests(options):
"""Make a set of tests to do irfft2d."""
test_parameters = [{
"input_dtype": [tf.complex64],
"input_shape": [[4, 3]],
"fft_length": [[4, 4], [2, 2], [2, 4]]
}, {
"input_dtype": [tf.complex64],
"input_shape": [[3, 8, 5]],
"fft_length": [[2, 4], [2, 8], [8, 8]]
}, {
"input_dtype": [tf.complex64],
"input_shape": [[3, 1, 9]],
"fft_length": [[1, 8], [1, 16]]
}]
def build_graph(parameters):
input_value = tf.compat.v1.placeholder(
dtype=parameters["input_dtype"],
name="input",
shape=parameters["input_shape"])
outs = tf.signal.irfft2d(input_value, fft_length=parameters["fft_length"])
return [input_value], [outs]
def build_inputs(parameters, sess, inputs, outputs):
rfft_length = []
rfft_length.append(parameters["input_shape"][-2])
rfft_length.append((parameters["input_shape"][-1] - 1) * 2)
rfft_input = create_tensor_data(np.float32, parameters["input_shape"])
rfft_result = np.fft.rfft2(rfft_input, rfft_length)
return [rfft_result], sess.run(
outputs, feed_dict=dict(zip(inputs, [rfft_result])))
extra_convert_options = ExtraConvertOptions()
extra_convert_options.allow_custom_ops = True
make_zip_of_tests(options, test_parameters, build_graph, build_inputs,
extra_convert_options)
@@ -0,0 +1,62 @@
# 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.
# ==============================================================================
"""Test configs for is_finite."""
import numpy as np
import tensorflow as tf
from tensorflow.lite.testing.zip_test_utils import create_tensor_data
from tensorflow.lite.testing.zip_test_utils import make_zip_of_tests
from tensorflow.lite.testing.zip_test_utils import register_make_test_function
@register_make_test_function()
def make_is_finite_tests(options):
"""Make a set of tests to do is_finite."""
test_parameters = [
{
"input_shape": [[100], [3, 15, 14, 3]],
},
]
def build_graph(parameters):
"""Build the graph for the test case."""
input_tensor = tf.compat.v1.placeholder(
dtype=tf.float32, name="input", shape=parameters["input_shape"])
out = tf.math.is_finite(input_tensor)
return [input_tensor], [out]
def build_inputs(parameters, sess, inputs, outputs):
"""Build the inputs for the test case."""
input_values = create_tensor_data(
np.float32, parameters["input_shape"], min_value=-10, max_value=10)
# Inject NaN and Inf value.
def random_index(shape):
result = []
for dim in shape:
result.append(np.random.randint(low=0, high=dim))
return tuple(result)
input_values[random_index(input_values.shape)] = np.inf
input_values[random_index(input_values.shape)] = -np.inf
input_values[random_index(input_values.shape)] = np.nan
input_values[random_index(input_values.shape)] = tf.float32.max
input_values[random_index(input_values.shape)] = tf.float32.min
return [input_values], sess.run(
outputs, feed_dict=dict(zip(inputs, [input_values])))
make_zip_of_tests(options, test_parameters, build_graph, build_inputs)
@@ -0,0 +1,66 @@
# 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.
# ==============================================================================
"""Test configs for l2norm."""
import numpy as np
import tensorflow as tf
from tensorflow.lite.testing.zip_test_utils import create_tensor_data
from tensorflow.lite.testing.zip_test_utils import make_zip_of_tests
from tensorflow.lite.testing.zip_test_utils import register_make_test_function
@register_make_test_function()
def make_l2norm_tests(options):
"""Make a set of tests to do l2norm."""
# Chose a set of parameters
test_parameters = [{
"input_shape": [[5, 7], [1, 1, 1, 1], [1, 3, 4, 3], [3, 15, 14, 3]],
"dim": [0, 1, 2, 3, [2, 3], -2],
"epsilon": [None, 1e-12, 1e-3],
"fully_quantize": [False],
}, {
"input_shape": [[1, 1, 1, 1], [1, 3, 4, 3], [3, 15, 14, 3]],
"dim": [3],
"epsilon": [None, 1e-12],
"fully_quantize": [True],
}, { # use another group of test so the dim is set to fuse to tfl.l2norm
"input_shape": [[5, 7]],
"dim": [1],
"epsilon": [None, 1e-12],
"fully_quantize": [True],
}]
def build_graph(parameters):
input_tensor = tf.compat.v1.placeholder(
dtype=tf.float32, name="input", shape=parameters["input_shape"])
if parameters["epsilon"]:
out = tf.nn.l2_normalize(
input_tensor, parameters["dim"], epsilon=parameters["epsilon"])
else:
out = tf.nn.l2_normalize(input_tensor, parameters["dim"])
return [input_tensor], [out]
def build_inputs(parameters, sess, inputs, outputs):
input_values = create_tensor_data(
np.float32, parameters["input_shape"], min_value=-1, max_value=1)
return [input_values], sess.run(
outputs, feed_dict=dict(zip(inputs, [input_values])))
make_zip_of_tests(
options,
test_parameters,
build_graph,
build_inputs,
expected_tf_failures=9)
@@ -0,0 +1,49 @@
# 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.
# ==============================================================================
"""Test configs for l2norm_shared_epsilon."""
import numpy as np
import tensorflow as tf
from tensorflow.lite.testing.zip_test_utils import create_tensor_data
from tensorflow.lite.testing.zip_test_utils import make_zip_of_tests
from tensorflow.lite.testing.zip_test_utils import register_make_test_function
@register_make_test_function()
def make_l2norm_shared_epsilon_tests(options):
"""Regression test for a bug (b/122651451)."""
# Chose a set of parameters
test_parameters = [{
"input_shape": [[5, 7]],
"dim": [1],
"epsilon": [1e-8],
}]
def build_graph(parameters):
input_tensor = tf.compat.v1.placeholder(
dtype=tf.float32, name="input", shape=parameters["input_shape"])
epsilon = tf.constant(parameters["epsilon"])
out1 = tf.nn.l2_normalize(input_tensor, parameters["dim"], epsilon=epsilon)
out2 = tf.nn.l2_normalize(input_tensor, parameters["dim"], epsilon=epsilon)
out = out1 + out2
return [input_tensor], [out]
def build_inputs(parameters, sess, inputs, outputs):
input_values = create_tensor_data(
np.float32, parameters["input_shape"], min_value=-4, max_value=10)
return [input_values], sess.run(
outputs, feed_dict=dict(zip(inputs, [input_values])))
make_zip_of_tests(options, test_parameters, build_graph, build_inputs)
@@ -0,0 +1,50 @@
# 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.
# ==============================================================================
"""Test configs for leaky_relu."""
import numpy as np
import tensorflow as tf
from tensorflow.lite.testing.zip_test_utils import create_tensor_data
from tensorflow.lite.testing.zip_test_utils import make_zip_of_tests
from tensorflow.lite.testing.zip_test_utils import register_make_test_function
@register_make_test_function()
def make_leaky_relu_tests(options):
"""Make a set of tests to do LeakyRelu."""
test_parameters = [{
"input_shape": [[], [1], [5], [1, 10, 10, 3], [3, 3, 3, 3]],
"alpha": [0.1, 1.0, 2.0, -0.1, -1.0, -2.0],
"fully_quantize": [False, True],
"input_range": [(-3, 10)],
"quant_16x8": [False, True],
}]
def build_graph(parameters):
"""Build the graph for the test case."""
input_tensor = tf.compat.v1.placeholder(
dtype=tf.float32, name="input", shape=parameters["input_shape"])
out = tf.nn.leaky_relu(input_tensor, alpha=parameters["alpha"])
return [input_tensor], [out]
def build_inputs(parameters, sess, inputs, outputs):
"""Build the inputs for the test case."""
input_values = create_tensor_data(
np.float32, parameters["input_shape"], min_value=-3, max_value=10)
return [input_values], sess.run(
outputs, feed_dict=dict(zip(inputs, [input_values])))
make_zip_of_tests(options, test_parameters, build_graph, build_inputs)
+64
View File
@@ -0,0 +1,64 @@
# 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.
# ==============================================================================
"""Test configs for less."""
import tensorflow as tf
from tensorflow.lite.testing.zip_test_utils import create_tensor_data
from tensorflow.lite.testing.zip_test_utils import make_zip_of_tests
from tensorflow.lite.testing.zip_test_utils import register_make_test_function
@register_make_test_function()
def make_less_tests(options):
"""Make a set of tests to do less."""
test_parameters = [{
"input_dtype": [tf.float32, tf.int16, tf.int32, tf.int64],
"input_shape_pair": [([1, 1, 1, 3], [1, 1, 1, 3]),
([2, 3, 4, 5], [2, 3, 4, 5]), ([2, 3, 3], [2, 3]),
([5, 5], [1]), ([10], [2, 4, 10])],
"fully_quantize": [False],
}, {
"input_dtype": [tf.float32],
"input_shape_pair": [([1, 1, 1, 3], [1, 1, 1, 3]), ([2, 3, 3], [2, 3])],
"fully_quantize": [True],
}]
def build_graph(parameters):
"""Build the less op testing graph."""
input_value1 = tf.compat.v1.placeholder(
dtype=parameters["input_dtype"],
name="input1",
shape=parameters["input_shape_pair"][0])
input_value2 = tf.compat.v1.placeholder(
dtype=parameters["input_dtype"],
name="input2",
shape=parameters["input_shape_pair"][1])
out = tf.less(input_value1, input_value2)
return [input_value1, input_value2], [out]
def build_inputs(parameters, sess, inputs, outputs):
input_value1 = create_tensor_data(parameters["input_dtype"],
parameters["input_shape_pair"][0])
input_value2 = create_tensor_data(parameters["input_dtype"],
parameters["input_shape_pair"][1])
return [input_value1, input_value2], sess.run(
outputs, feed_dict=dict(zip(inputs, [input_value1, input_value2])))
make_zip_of_tests(
options,
test_parameters,
build_graph,
build_inputs,
expected_tf_failures=5)
@@ -0,0 +1,87 @@
# 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.
# ==============================================================================
"""Test configs for less_equal."""
import tensorflow as tf
from tensorflow.lite.testing.zip_test_utils import create_tensor_data
from tensorflow.lite.testing.zip_test_utils import make_zip_of_tests
from tensorflow.lite.testing.zip_test_utils import register_make_test_function
@register_make_test_function()
def make_less_equal_tests(options):
"""Make a set of tests to do less_equal."""
test_parameters = [{
"input_dtype": [tf.float32, tf.int32, tf.int64],
"input_shape_pair": [([1, 1, 1, 3], [1, 1, 1, 3]),
([2, 3, 4, 5], [2, 3, 4, 5]), ([2, 3, 3], [2, 3]),
([5, 5], [1]), ([10], [2, 4, 10])],
"fully_quantize": [False],
}, {
"input_dtype": [tf.float32],
"input_shape_pair": [([1, 1, 1, 3], [1, 1, 1, 3]), ([2, 3, 3], [2, 3])],
"fully_quantize": [True],
}]
# High dimension broadcasting support in MLIR converter.
# Note(b/204360746): XNNPack delegate don't support high dimension.
if not options.skip_high_dimension_inputs:
test_parameters = test_parameters + [
{
"input_dtype": [tf.float32, tf.int32],
"input_shape_pair": [([6, 5, 4, 3, 2, 1], [4, 3, 2, 1]),
([6, 5, 4, 3, 2, 1], [None, 3, 2, 1]),
([6, 5, None, 3, 2, 1], [None, 3, 2, 1])],
"fully_quantize": [False],
"dynamic_size_value": [4, 1],
},
]
def populate_dynamic_shape(parameters, input_shape):
return [
parameters["dynamic_size_value"] if x is None else x
for x in input_shape
]
def build_graph(parameters):
"""Build the less_equal op testing graph."""
input_value1 = tf.compat.v1.placeholder(
dtype=parameters["input_dtype"],
name="input1",
shape=parameters["input_shape_pair"][0])
input_value2 = tf.compat.v1.placeholder(
dtype=parameters["input_dtype"],
name="input2",
shape=parameters["input_shape_pair"][1])
out = tf.less_equal(input_value1, input_value2)
return [input_value1, input_value2], [out]
def build_inputs(parameters, sess, inputs, outputs):
input_shape_1 = populate_dynamic_shape(parameters,
parameters["input_shape_pair"][0])
input_shape_2 = populate_dynamic_shape(parameters,
parameters["input_shape_pair"][1])
input_value1 = create_tensor_data(parameters["input_dtype"], input_shape_1)
input_value2 = create_tensor_data(parameters["input_dtype"], input_shape_2)
return [input_value1, input_value2], sess.run(
outputs, feed_dict=dict(zip(inputs, [input_value1, input_value2])))
make_zip_of_tests(
options,
test_parameters,
build_graph,
build_inputs,
expected_tf_failures=4)
@@ -0,0 +1,53 @@
# 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.
# ==============================================================================
"""Test configs for local_response_norm."""
import numpy as np
import tensorflow as tf
from tensorflow.lite.testing.zip_test_utils import create_tensor_data
from tensorflow.lite.testing.zip_test_utils import make_zip_of_tests
from tensorflow.lite.testing.zip_test_utils import register_make_test_function
@register_make_test_function()
def make_local_response_norm_tests(options):
"""Make a set of tests to do local_response_norm."""
# Chose a set of parameters
test_parameters = [{
"input_shape": [[1, 1, 1, 1], [1, 3, 4, 3], [3, 15, 14, 3]],
"depth_radius": [None, 0, 1, 3, 5],
"bias": [None, 0.3, -0.1],
"alpha": [None, 2, -3],
"beta": [None, 0.25, 2],
}]
def build_graph(parameters):
input_tensor = tf.compat.v1.placeholder(
dtype=tf.float32, name="input", shape=parameters["input_shape"])
out = tf.nn.local_response_normalization(
input_tensor,
depth_radius=parameters["depth_radius"],
bias=parameters["bias"],
alpha=parameters["alpha"],
beta=parameters["beta"])
return [input_tensor], [out]
def build_inputs(parameters, sess, inputs, outputs):
input_values = create_tensor_data(
np.float32, parameters["input_shape"], min_value=-4, max_value=10)
return [input_values], sess.run(
outputs, feed_dict=dict(zip(inputs, [input_values])))
make_zip_of_tests(options, test_parameters, build_graph, build_inputs)

Some files were not shown because too many files have changed in this diff Show More