Files
tensorflow--tensorflow/tensorflow/lite/testing/build_def.bzl
T
wehub-resource-sync 8a852e4b4e
cffconvert / validate (push) Has been skipped
License Check / license-check (push) Failing after 2s
chore: import upstream snapshot with attribution
2026-07-13 12:14:16 +08:00

594 lines
18 KiB
Python

"""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],
)