Merge pull request from wwwind:op_tests_16x8

PiperOrigin-RevId: 320661178
This commit is contained in:
TensorFlower Gardener 2020-07-10 13:14:01 -07:00
commit 3adc7cf2c9
10 changed files with 134 additions and 20 deletions

View File

@ -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],
}]

View File

@ -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]
},
]

View File

@ -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]
},
]

View File

@ -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):

View File

@ -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

View File

@ -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;

View File

@ -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:

View File

@ -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()

View File

@ -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,

View File

@ -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,