Merge pull request #39543 from wwwind:op_tests_16x8
PiperOrigin-RevId: 320661178
This commit is contained in:
commit
3adc7cf2c9
tensorflow/lite
@ -33,6 +33,7 @@ def make_concat_tests(options):
|
||||
"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]],
|
||||
@ -40,6 +41,15 @@ def make_concat_tests(options):
|
||||
"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]],
|
||||
@ -47,6 +57,7 @@ def make_concat_tests(options):
|
||||
"axis": [1],
|
||||
"type": [tf.float32],
|
||||
"fully_quantize": [False],
|
||||
"quant_16x8": [False],
|
||||
"dynamic_range_quantize": [True],
|
||||
}]
|
||||
|
||||
|
@ -39,6 +39,20 @@ def make_conv_tests(options):
|
||||
"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
|
||||
@ -54,7 +68,8 @@ def make_conv_tests(options):
|
||||
"constant_filter": [True],
|
||||
"channel_multiplier": [1, 2],
|
||||
"fully_quantize": [True],
|
||||
"dynamic_range_quantize": [False],
|
||||
"quant_16x8": [False],
|
||||
"dynamic_range_quantize": [False]
|
||||
},
|
||||
{
|
||||
"input_shape": [[1, 3, 4, 3]],
|
||||
@ -66,7 +81,8 @@ def make_conv_tests(options):
|
||||
"constant_filter": [True],
|
||||
"channel_multiplier": [2],
|
||||
"fully_quantize": [False],
|
||||
"dynamic_range_quantize": [True],
|
||||
"quant_16x8": [False],
|
||||
"dynamic_range_quantize": [True]
|
||||
},
|
||||
]
|
||||
|
||||
|
@ -40,7 +40,8 @@ def make_depthwiseconv_tests(options):
|
||||
"padding": ["SAME", "VALID"],
|
||||
"data_format": ["NHWC"],
|
||||
"constant_filter": [True, False],
|
||||
"fully_quantize": [False]
|
||||
"fully_quantize": [False],
|
||||
"quant_16x8": [False]
|
||||
},
|
||||
{
|
||||
"input_shape": [[1, 3, 4, 3]],
|
||||
@ -52,7 +53,8 @@ def make_depthwiseconv_tests(options):
|
||||
"padding": ["SAME"],
|
||||
"data_format": ["NHWC"],
|
||||
"constant_filter": [True, False],
|
||||
"fully_quantize": [False]
|
||||
"fully_quantize": [False],
|
||||
"quant_16x8": [False]
|
||||
},
|
||||
{
|
||||
"input_shape": [[1, 3, 4, 3], [1, 10, 10, 3]],
|
||||
@ -64,7 +66,21 @@ def make_depthwiseconv_tests(options):
|
||||
"padding": ["SAME", "VALID"],
|
||||
"data_format": ["NHWC"],
|
||||
"constant_filter": [True],
|
||||
"fully_quantize": [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]
|
||||
},
|
||||
]
|
||||
|
||||
|
@ -35,6 +35,7 @@ def make_fully_connected_tests(options):
|
||||
"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]],
|
||||
@ -42,6 +43,7 @@ def make_fully_connected_tests(options):
|
||||
"transpose_b": [False],
|
||||
"constant_filter": [True, False],
|
||||
"fully_quantize": [False],
|
||||
"quant_16x8": [False]
|
||||
}, {
|
||||
"shape1": [[40, 37]],
|
||||
"shape2": [[37, 40]],
|
||||
@ -49,6 +51,7 @@ def make_fully_connected_tests(options):
|
||||
"transpose_b": [False],
|
||||
"constant_filter": [True, False],
|
||||
"fully_quantize": [False],
|
||||
"quant_16x8": [False]
|
||||
}, {
|
||||
"shape1": [[40, 37]],
|
||||
"shape2": [[40, 37]],
|
||||
@ -56,6 +59,7 @@ def make_fully_connected_tests(options):
|
||||
"transpose_b": [True],
|
||||
"constant_filter": [True, False],
|
||||
"fully_quantize": [False],
|
||||
"quant_16x8": [False]
|
||||
}, {
|
||||
"shape1": [[5, 3]],
|
||||
"shape2": [[5, 3]],
|
||||
@ -63,6 +67,7 @@ def make_fully_connected_tests(options):
|
||||
"transpose_b": [False],
|
||||
"constant_filter": [True, False],
|
||||
"fully_quantize": [False],
|
||||
"quant_16x8": [False]
|
||||
}, {
|
||||
"shape1": [[1, 3]],
|
||||
"shape2": [[3, 3]],
|
||||
@ -70,6 +75,7 @@ def make_fully_connected_tests(options):
|
||||
"transpose_b": [False],
|
||||
"constant_filter": [True],
|
||||
"fully_quantize": [True],
|
||||
"quant_16x8": [False]
|
||||
}, {
|
||||
"shape1": [[1, 4], [4]],
|
||||
"shape2": [[4, 4], [4, 1], [4]],
|
||||
@ -77,6 +83,7 @@ def make_fully_connected_tests(options):
|
||||
"transpose_b": [False],
|
||||
"constant_filter": [True],
|
||||
"fully_quantize": [True],
|
||||
"quant_16x8": [False]
|
||||
}, {
|
||||
"shape1": [[1, 37], [2, 37]],
|
||||
"shape2": [[37, 40]],
|
||||
@ -84,6 +91,7 @@ def make_fully_connected_tests(options):
|
||||
"transpose_b": [False],
|
||||
"constant_filter": [True],
|
||||
"fully_quantize": [True],
|
||||
"quant_16x8": [False]
|
||||
}, {
|
||||
"shape1": [[1, 3], [2, 3]],
|
||||
"shape2": [[3, 5], [3, 1]],
|
||||
@ -91,6 +99,15 @@ def make_fully_connected_tests(options):
|
||||
"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]
|
||||
}]
|
||||
|
||||
def build_graph(parameters):
|
||||
|
@ -55,6 +55,7 @@ def make_pool_tests(pool_op_in, allow_fully_quantize=False):
|
||||
"padding": ["SAME", "VALID"],
|
||||
"data_format": ["NHWC"], # TODO(aselle): NCHW would be good
|
||||
"fully_quantize": [False],
|
||||
"quant_16x8": [False]
|
||||
},
|
||||
{
|
||||
"ksize": [[2, 1, 1, 2], [1, 1, 1, 1], [1, 1, 2, 1], [1, 10, 11, 1]],
|
||||
@ -65,6 +66,16 @@ def make_pool_tests(pool_op_in, allow_fully_quantize=False):
|
||||
"padding": ["SAME", "VALID"],
|
||||
"data_format": ["NHWC"], # TODO(aselle): NCHW would be good
|
||||
"fully_quantize": [True],
|
||||
"quant_16x8": [False]
|
||||
},
|
||||
{
|
||||
"ksize": [[1, 1, 1, 1]],
|
||||
"strides": [[1, 1, 1, 1]],
|
||||
"input_shape": [[1, 1, 1, 1]],
|
||||
"padding": ["SAME", "VALID"],
|
||||
"data_format": ["NHWC"],
|
||||
"fully_quantize": [True],
|
||||
"quant_16x8": [True]
|
||||
}
|
||||
]
|
||||
# test_parameters include fully_quantize option only when
|
||||
|
@ -93,6 +93,15 @@ inline std::vector<int8_t> Split(const string& s, const string& delimiter) {
|
||||
return fields;
|
||||
}
|
||||
|
||||
template <>
|
||||
inline std::vector<int16_t> Split(const string& s, const string& delimiter) {
|
||||
std::vector<int16_t> fields;
|
||||
for (const auto& p : SplitToPos(s, delimiter)) {
|
||||
fields.push_back(strtol(s.data() + p.first, nullptr, 10));
|
||||
}
|
||||
return fields;
|
||||
}
|
||||
|
||||
template <>
|
||||
inline std::vector<bool> Split(const string& s, const string& delimiter) {
|
||||
std::vector<bool> fields;
|
||||
|
@ -78,7 +78,7 @@ unique_void_ptr make_type_erased_array(size_t size) {
|
||||
}
|
||||
|
||||
bool IsQuantized(const TfLiteTensor& tensor) {
|
||||
if (tensor.type != kTfLiteInt8) return false;
|
||||
if (tensor.type != kTfLiteInt8 && tensor.type != kTfLiteInt16) return false;
|
||||
|
||||
if (tensor.quantization.params != nullptr) {
|
||||
auto* quantization =
|
||||
@ -263,13 +263,22 @@ bool TfLiteDriver::DataExpectation::QuantizedCheck(bool verbose,
|
||||
const int32_t zero_point = quantization->zero_point->data[0];
|
||||
|
||||
bool good_result = true;
|
||||
for (int i = 0; i < tensor.bytes; i++) {
|
||||
const int32_t computed = tensor.data.int8[i];
|
||||
int int_size = tensor.type == kTfLiteInt8 ? 1 : 2;
|
||||
for (int i = 0; i < tensor.bytes / int_size; i++) {
|
||||
int32_t computed =
|
||||
tensor.type == kTfLiteInt8 ? tensor.data.int8[i] : tensor.data.i16[i];
|
||||
const float dequantized =
|
||||
static_cast<float>(scale * (computed - zero_point));
|
||||
int error_multiplier = quantization_error_multiplier_;
|
||||
// If we are doing int16 symmetric quantization of activations, we need to
|
||||
// bump up the potential error. Since the weights are quantized to 8 bits
|
||||
// and the activations are 16bits, the output is could be getting
|
||||
// effectively 8bit error instead of 16bit error. So we need to multiply the
|
||||
// error mulitplier by 255 (the difference in number of values between a
|
||||
// 16bit and 8bit number)
|
||||
if (tensor.type == kTfLiteInt16) error_multiplier *= 255;
|
||||
const float reference = Value<float>(data_.get(), i);
|
||||
if (std::abs(dequantized - reference) >
|
||||
quantization_error_multiplier_ * scale) {
|
||||
if (std::abs(dequantized - reference) > error_multiplier * scale) {
|
||||
if (verbose) {
|
||||
std::cerr << " index " << i << ": got " << dequantized
|
||||
<< ", but expected " << reference << std::endl;
|
||||
@ -297,6 +306,8 @@ bool TfLiteDriver::DataExpectation::Check(bool verbose,
|
||||
return TypedCheck<uint8_t, float>(verbose, tensor);
|
||||
case kTfLiteInt8:
|
||||
return TypedCheck<int8_t, float>(verbose, tensor);
|
||||
case kTfLiteInt16:
|
||||
return TypedCheck<int16_t, float>(verbose, tensor);
|
||||
case kTfLiteBool:
|
||||
return TypedCheck<bool, float>(verbose, tensor);
|
||||
case kTfLiteString:
|
||||
@ -433,6 +444,12 @@ void TfLiteDriver::SetInput(int id, const string& csv_values) {
|
||||
SetTensorData(values, tensor->data.raw);
|
||||
break;
|
||||
}
|
||||
case kTfLiteInt16: {
|
||||
const auto& values = testing::Split<int16_t>(csv_values, ",");
|
||||
if (!CheckSizes<int16_t>(tensor->bytes, values.size())) return;
|
||||
SetTensorData(values, tensor->data.raw);
|
||||
break;
|
||||
}
|
||||
case kTfLiteBool: {
|
||||
const auto& values = testing::Split<bool>(csv_values, ",");
|
||||
if (!CheckSizes<bool>(tensor->bytes, values.size())) return;
|
||||
@ -498,6 +515,9 @@ void TfLiteDriver::SetExpectation(int id, const string& csv_values) {
|
||||
case kTfLiteInt8:
|
||||
expected_output_[id]->SetData<int8_t>(csv_values);
|
||||
break;
|
||||
case kTfLiteInt16:
|
||||
expected_output_[id]->SetData<int16_t>(csv_values);
|
||||
break;
|
||||
case kTfLiteBool:
|
||||
expected_output_[id]->SetData<bool>(csv_values);
|
||||
break;
|
||||
@ -589,6 +609,8 @@ string TfLiteDriver::ReadOutput(int id) {
|
||||
return Join(tensor->data.uint8, num_elements, ",");
|
||||
case kTfLiteInt8:
|
||||
return Join(tensor->data.int8, num_elements, ",");
|
||||
case kTfLiteInt16:
|
||||
return Join(tensor->data.i16, num_elements, ",");
|
||||
case kTfLiteBool:
|
||||
return JoinDefault(tensor->data.b, num_elements, ",");
|
||||
default:
|
||||
|
@ -134,9 +134,16 @@ def toco_convert(options, graph_def, input_tensors, output_tensors, **kwargs):
|
||||
for _ in range(100):
|
||||
yield representative_dataset(input_tensors)
|
||||
|
||||
converter.target_spec.supported_ops = [
|
||||
tf.lite.OpsSet.TFLITE_BUILTINS_INT8
|
||||
]
|
||||
if test_params.get("quant_16x8", False):
|
||||
converter.target_spec.supported_ops = [
|
||||
tf.lite.OpsSet.\
|
||||
EXPERIMENTAL_TFLITE_BUILTINS_ACTIVATIONS_INT16_WEIGHTS_INT8
|
||||
]
|
||||
else:
|
||||
converter.target_spec.supported_ops = [
|
||||
tf.lite.OpsSet.TFLITE_BUILTINS_INT8
|
||||
]
|
||||
|
||||
converter.representative_dataset = representative_dataset_gen
|
||||
if extra_toco_options.inference_input_type:
|
||||
converter.inference_input_type = (
|
||||
@ -145,7 +152,10 @@ def toco_convert(options, graph_def, input_tensors, output_tensors, **kwargs):
|
||||
converter.inference_output_type = (
|
||||
extra_toco_options.inference_output_type)
|
||||
else:
|
||||
converter.inference_output_type = tf.int8
|
||||
if test_params.get("quant_16x8", False):
|
||||
converter.inference_output_type = tf.int16
|
||||
else:
|
||||
converter.inference_output_type = tf.int8
|
||||
|
||||
try:
|
||||
tflite_model = converter.convert()
|
||||
|
@ -328,11 +328,13 @@ def make_zip_of_tests(options,
|
||||
# Only count parameters when fully_quantize is True.
|
||||
parameter_count = 0
|
||||
for parameters in test_parameters:
|
||||
if True in parameters.get("fully_quantize", []):
|
||||
if True in parameters.get("fully_quantize",
|
||||
[]) and False in parameters.get(
|
||||
"quant_16x8", [False]):
|
||||
parameter_count += functools.reduce(operator.mul, [
|
||||
len(values)
|
||||
for key, values in parameters.items()
|
||||
if key != "fully_quantize"
|
||||
if key != "fully_quantize" and key != "quant_16x8"
|
||||
])
|
||||
|
||||
label_base_path = zip_path
|
||||
@ -354,8 +356,8 @@ def make_zip_of_tests(options,
|
||||
|
||||
param_dict = dict(zip(keys, curr))
|
||||
|
||||
if options.make_edgetpu_tests and not param_dict.get(
|
||||
"fully_quantize", False):
|
||||
if options.make_edgetpu_tests and (not param_dict.get(
|
||||
"fully_quantize", False) or param_dict.get("quant_16x8", False)):
|
||||
continue
|
||||
|
||||
def generate_inputs_outputs(tflite_model_binary,
|
||||
|
@ -107,10 +107,10 @@ TfLiteStatus GetQuantizationParams(TensorT* tensor, TensorType activations_type,
|
||||
std::numeric_limits<int8_t>::min(), std::numeric_limits<int8_t>::max(),
|
||||
quantization_params);
|
||||
} else if (activations_type == TensorType_INT16) {
|
||||
const float quantized_range = 32767.0;
|
||||
const int half_quantized_range = 32767;
|
||||
GetSymmetricQuantizationParams(tensor->quantization->min[0],
|
||||
tensor->quantization->max[0],
|
||||
quantized_range, quantization_params);
|
||||
half_quantized_range, quantization_params);
|
||||
} else {
|
||||
TF_LITE_REPORT_ERROR(
|
||||
error_reporter,
|
||||
|
Loading…
Reference in New Issue
Block a user