From 04237f354f67fa6a898b10a5b08bbb41ece6c7da Mon Sep 17 00:00:00 2001 From: Thibaut Goetghebuer-Planchon Date: Wed, 23 Sep 2020 11:21:59 +0100 Subject: [PATCH 1/3] Add int16x8 support for REDUCE_MIN and REDUCE_MAX operators --- tensorflow/lite/kernels/reduce.cc | 11 +- tensorflow/lite/kernels/reduce_test.cc | 436 ++++++++++-------- tensorflow/lite/kernels/register.cc | 4 +- tensorflow/lite/kernels/register_ref.cc | 4 +- tensorflow/lite/toco/tflite/op_version.cc | 2 + .../lite/tools/versioning/op_version.cc | 4 +- .../lite/tools/versioning/op_version_test.cc | 8 + .../lite/tools/versioning/runtime_version.cc | 2 + 8 files changed, 260 insertions(+), 211 deletions(-) diff --git a/tensorflow/lite/kernels/reduce.cc b/tensorflow/lite/kernels/reduce.cc index c3debef0f86..458c2273215 100644 --- a/tensorflow/lite/kernels/reduce.cc +++ b/tensorflow/lite/kernels/reduce.cc @@ -223,6 +223,11 @@ TfLiteStatus PrepareSimple(TfLiteContext* context, TfLiteNode* node) { TF_LITE_ENSURE_TYPES_EQ(context, op_context.axis->type, kTfLiteInt32); TF_LITE_ENSURE_OK(context, InitializeTemporaries(context, node, &op_context)); + if (op_context.input->type == kTfLiteInt16) { + TF_LITE_ENSURE_EQ(context, op_context.input->params.zero_point, 0); + TF_LITE_ENSURE_EQ(context, op_context.output->params.zero_point, 0); + } + TfLiteTensor* resolved_axis; TF_LITE_ENSURE_OK( context, GetTemporarySafe(context, node, /*index=*/1, &resolved_axis)); @@ -535,7 +540,8 @@ TfLiteStatus EvalLogic(TfLiteContext* context, TfLiteNode* node, if (input->dims->data[i] == 0) return kTfLiteOk; } - if (input->type == kTfLiteUInt8 || input->type == kTfLiteInt8) { + if (input->type == kTfLiteUInt8 || input->type == kTfLiteInt8 || + input->type == kTfLiteInt16) { TF_LITE_ENSURE_EQ(context, input->params.scale, op_context->output->params.scale); TF_LITE_ENSURE_EQ(context, input->params.zero_point, @@ -635,6 +641,9 @@ TfLiteStatus EvalGeneric(TfLiteContext* context, TfLiteNode* node) { case kTfLiteInt8: return EvalType(context, node, &op_context, reduce_type); break; + case kTfLiteInt16: + return EvalType(context, node, &op_context, reduce_type); + break; case kTfLiteBool: return EvalType(context, node, &op_context, reduce_type); break; diff --git a/tensorflow/lite/kernels/reduce_test.cc b/tensorflow/lite/kernels/reduce_test.cc index 2e724189fde..6296e722a2a 100644 --- a/tensorflow/lite/kernels/reduce_test.cc +++ b/tensorflow/lite/kernels/reduce_test.cc @@ -998,148 +998,162 @@ TEST(DynamicFloatMaxOpTest, Scale) { EXPECT_THAT(m.GetOutput(), ElementsAreArray(ArrayFloatNear({9.527}))); } -TEST(ConstUint8MaxOpTest, NotKeepDims) { - float kQuantizedTolerance = GetTolerance(-1.0, 1.0); +template +void ConstMaxOpTestNotKeepDims() { + const float kMin = -1; + const float kMax = + std::numeric_limits::max() / + static_cast(std::numeric_limits::max() + 1); + const float kQuantizedTolerance = GetTolerance(-1.0, 1.0); std::vector data = {0.4, 0.2, 0.3, 0.4, 0.5, 0.6}; - MaxOpConstModel m({TensorType_UINT8, {1, 3, 2}, -1.0, 1.0}, - {TensorType_UINT8, {2}, -1.0, 1.0}, {1}, {1}, false); - m.QuantizeAndPopulate(m.Input(), data); + MaxOpConstModel m({tensor_type, {1, 3, 2}, 1.0 * kMin, 1.0 * kMax}, + {tensor_type, {2}, 1.0 * kMin, 1.0 * kMax}, {1}, {1}, + false); + m.QuantizeAndPopulate(m.Input(), data); m.Invoke(); EXPECT_THAT(m.GetOutputShape(), ElementsAreArray({1, 2})); - EXPECT_THAT(m.GetDequantizedOutput(), - ElementsAreArray( - ArrayFloatNear({0.501961, 0.603922}, kQuantizedTolerance))); + EXPECT_THAT( + m.GetDequantizedOutput(), + ElementsAreArray(ArrayFloatNear({0.5, 0.6}, kQuantizedTolerance))); +} + +TEST(ConstUint8MaxOpTest, NotKeepDims) { + ConstMaxOpTestNotKeepDims(); } TEST(ConstInt8MaxOpTest, NotKeepDims) { - float kQuantizedTolerance = GetTolerance(-1.0, 1.0); + ConstMaxOpTestNotKeepDims(); +} + +TEST(ConstInt16MaxOpTest, NotKeepDims) { + ConstMaxOpTestNotKeepDims(); +} + +template +void ConstMaxOpTestKeepDims() { + const float kMin = -1; + const float kMax = + std::numeric_limits::max() / + static_cast(std::numeric_limits::max() + 1); + const float kQuantizedTolerance = GetTolerance(-1.0, 1.0); std::vector data = {0.4, 0.2, 0.3, 0.4, 0.5, 0.6}; - MaxOpConstModel m({TensorType_INT8, {1, 3, 2}, -1.0, 1.0}, - {TensorType_INT8, {2}, -1.0, 1.0}, {1}, {1}, false); - m.QuantizeAndPopulate(m.Input(), data); + MaxOpConstModel m({tensor_type, {3, 2}, 1.0 * kMin, 1.0 * kMax}, + {tensor_type, {3}, 1.0 * kMin, 1.0 * kMax}, {1}, {1}, true); + m.QuantizeAndPopulate(m.Input(), data); m.Invoke(); - EXPECT_THAT(m.GetOutputShape(), ElementsAreArray({1, 2})); - EXPECT_THAT(m.GetDequantizedOutput(), - ElementsAreArray( - ArrayFloatNear({0.501961, 0.603922}, kQuantizedTolerance))); + EXPECT_THAT(m.GetOutputShape(), ElementsAreArray({3, 1})); + EXPECT_THAT( + m.GetDequantizedOutput(), + ElementsAreArray(ArrayFloatNear({0.4, 0.4, 0.6}, kQuantizedTolerance))); } TEST(ConstUint8MaxOpTest, KeepDims) { - float kQuantizedTolerance = GetTolerance(-1.0, 1.0); - std::vector data = {0.4, 0.2, 0.3, 0.4, 0.5, 0.6}; - MaxOpConstModel m({TensorType_UINT8, {3, 2}, -1.0, 1.0}, - {TensorType_UINT8, {3}, -1.0, 1.0}, {1}, {1}, true); - m.QuantizeAndPopulate(m.Input(), data); - m.Invoke(); - EXPECT_THAT(m.GetOutputShape(), ElementsAreArray({3, 1})); - EXPECT_THAT(m.GetDequantizedOutput(), - ElementsAreArray( - ArrayFloatNear({0.4, 0.4, 0.603922}, kQuantizedTolerance))); + ConstMaxOpTestKeepDims(); } TEST(ConstInt8MaxOpTest, KeepDims) { - float kQuantizedTolerance = GetTolerance(-1.0, 1.0); - std::vector data = {0.4, 0.2, 0.3, 0.4, 0.5, 0.6}; - MaxOpConstModel m({TensorType_INT8, {3, 2}, -1.0, 1.0}, - {TensorType_INT8, {3}, -1.0, 1.0}, {1}, {1}, true); - m.QuantizeAndPopulate(m.Input(), data); + ConstMaxOpTestKeepDims(); +} + +TEST(ConstInt16MaxOpTest, KeepDims) { + ConstMaxOpTestKeepDims(); +} + +template +void DynamicMaxOpTestNotKeepDims() { + const float kMin = -1; + const float kMax = + std::numeric_limits::max() / + static_cast(std::numeric_limits::max() + 1); + const float kQuantizedTolerance = GetTolerance(-5.0, 5.0); + std::vector data = {1.3, -4.8, -3.6, 0.24}; + MaxOpDynamicModel m({tensor_type, {2, 2}, 5.0 * kMin, 5.0 * kMax}, + {tensor_type, {2}, 5.0 * kMin, 5.0 * kMax}, + {TensorType_INT32, {1}}, false); + std::vector axis = {1}; + m.SetAxis(axis); + m.QuantizeAndPopulate(m.Input(), data); m.Invoke(); - EXPECT_THAT(m.GetOutputShape(), ElementsAreArray({3, 1})); - EXPECT_THAT(m.GetDequantizedOutput(), - ElementsAreArray( - ArrayFloatNear({0.4, 0.4, 0.603922}, kQuantizedTolerance))); + EXPECT_THAT(m.GetOutputShape(), ElementsAreArray({2})); + EXPECT_THAT( + m.GetDequantizedOutput(), + ElementsAreArray(ArrayFloatNear({1.3, 0.24}, kQuantizedTolerance))); } TEST(DynamicUint8MaxOpTest, NotKeepDims) { - float kQuantizedTolerance = GetTolerance(-5.0, 2.0); - std::vector data = {1.3, -4.8, -3.6, 0.24}; - MaxOpDynamicModel m({TensorType_UINT8, {2, 2}, -5.0, 2.0}, - {TensorType_UINT8, {2}, -5.0, 2.0}, - {TensorType_INT32, {1}}, false); - std::vector axis = {1}; - m.SetAxis(axis); - m.QuantizeAndPopulate(m.Input(), data); - m.Invoke(); - EXPECT_THAT(m.GetOutputShape(), ElementsAreArray({2})); - EXPECT_THAT(m.GetDequantizedOutput(), - ElementsAreArray( - ArrayFloatNear({1.2902, 0.247059}, kQuantizedTolerance))); + DynamicMaxOpTestNotKeepDims(); } TEST(DynamicInt8MaxOpTest, NotKeepDims) { - float kQuantizedTolerance = GetTolerance(-5.0, 2.0); - std::vector data = {1.3, -4.8, -3.6, 0.24}; - MaxOpDynamicModel m({TensorType_INT8, {2, 2}, -5.0, 2.0}, - {TensorType_INT8, {2}, -5.0, 2.0}, - {TensorType_INT32, {1}}, false); - std::vector axis = {1}; + DynamicMaxOpTestNotKeepDims(); +} + +TEST(DynamicInt16MaxOpTest, NotKeepDims) { + DynamicMaxOpTestNotKeepDims(); +} + +template +void DynamicMaxOpTestKeepDims() { + const float kMin = -1; + const float kMax = + std::numeric_limits::max() / + static_cast(std::numeric_limits::max() + 1); + const float kQuantizedTolerance = GetTolerance(-12.0, 12.0); + std::vector data = {11.14, -0.14, 7.423, 0.879}; + MaxOpDynamicModel m({tensor_type, {2, 2}, 12.0 * kMin, 12.0 * kMax}, + {tensor_type, {2}, 12.0 * kMin, 12.0 * kMax}, + {TensorType_INT32, {1}}, true); + std::vector axis = {0}; m.SetAxis(axis); - m.QuantizeAndPopulate(m.Input(), data); + m.QuantizeAndPopulate(m.Input(), data); m.Invoke(); - EXPECT_THAT(m.GetOutputShape(), ElementsAreArray({2})); - EXPECT_THAT(m.GetDequantizedOutput(), - ElementsAreArray( - ArrayFloatNear({1.2902, 0.247059}, kQuantizedTolerance))); + EXPECT_THAT(m.GetOutputShape(), ElementsAreArray({1, 2})); + EXPECT_THAT( + m.GetDequantizedOutput(), + ElementsAreArray(ArrayFloatNear({11.14, 0.879}, kQuantizedTolerance))); } TEST(DynamicUint8MaxOpTest, KeepDims) { - float kQuantizedTolerance = GetTolerance(-10.0, 12.0); - std::vector data = {11.14, -0.14, 7.423, 0.879}; - MaxOpDynamicModel m({TensorType_UINT8, {2, 2}, -10.0, 12.0}, - {TensorType_UINT8, {2}, -10.0, 12.0}, - {TensorType_INT32, {1}}, true); - std::vector axis = {0}; - m.SetAxis(axis); - m.QuantizeAndPopulate(m.Input(), data); - m.Invoke(); - EXPECT_THAT(m.GetOutputShape(), ElementsAreArray({1, 2})); - EXPECT_THAT(m.GetDequantizedOutput(), - ElementsAreArray( - ArrayFloatNear({11.1294, 0.862745}, kQuantizedTolerance))); + DynamicMaxOpTestKeepDims(); } TEST(DynamicInt8MaxOpTest, KeepDims) { - float kQuantizedTolerance = GetTolerance(-10.0, 12.0); - std::vector data = {11.14, -0.14, 7.423, 0.879}; - MaxOpDynamicModel m({TensorType_INT8, {2, 2}, -10.0, 12.0}, - {TensorType_INT8, {2}, -10.0, 12.0}, + DynamicMaxOpTestKeepDims(); +} + +TEST(DynamicInt16MaxOpTest, KeepDims) { + DynamicMaxOpTestKeepDims(); +} + +template +void DynamicMaxOpTestScalar() { + const float kMin = -1; + const float kMax = + std::numeric_limits::max() / + static_cast(std::numeric_limits::max() + 1); + const float kQuantizedTolerance = GetTolerance(-12.0, 12.0); + std::vector data = {11.14}; + MaxOpDynamicModel m({tensor_type, {}, 12.0 * kMin, 12.0 * kMax}, + {tensor_type, {}, 12.0 * kMin, 12.0 * kMax}, {TensorType_INT32, {1}}, true); std::vector axis = {0}; - m.SetAxis(axis); - m.QuantizeAndPopulate(m.Input(), data); + m.QuantizeAndPopulate(m.Input(), data); m.Invoke(); - EXPECT_THAT(m.GetOutputShape(), ElementsAreArray({1, 2})); - EXPECT_THAT(m.GetDequantizedOutput(), - ElementsAreArray( - ArrayFloatNear({11.1294, 0.862745}, kQuantizedTolerance))); + EXPECT_THAT(m.GetOutputShape(), IsEmpty()); + EXPECT_THAT(m.GetDequantizedOutput(), + ElementsAreArray(ArrayFloatNear({11.14}, kQuantizedTolerance))); } TEST(DynamicUint8MaxOpTest, Scalar) { - float kQuantizedTolerance = GetTolerance(-10.0, 12.0); - std::vector data = {11.14}; - MaxOpDynamicModel m({TensorType_UINT8, {}, -10.0, 12.0}, - {TensorType_UINT8, {}, -10.0, 12.0}, - {TensorType_INT32, {1}}, true); - std::vector axis = {0}; - m.QuantizeAndPopulate(m.Input(), data); - m.Invoke(); - EXPECT_THAT(m.GetOutputShape(), IsEmpty()); - EXPECT_THAT(m.GetDequantizedOutput(), - ElementsAreArray(ArrayFloatNear({11.1294}, kQuantizedTolerance))); + DynamicMaxOpTestScalar(); } TEST(DynamicInt8MaxOpTest, Scalar) { - float kQuantizedTolerance = GetTolerance(-10.0, 12.0); - std::vector data = {11.14}; - MaxOpDynamicModel m({TensorType_INT8, {}, -10.0, 12.0}, - {TensorType_INT8, {}, -10.0, 12.0}, - {TensorType_INT32, {1}}, true); - std::vector axis = {0}; - m.QuantizeAndPopulate(m.Input(), data); - m.Invoke(); - EXPECT_THAT(m.GetOutputShape(), IsEmpty()); - EXPECT_THAT(m.GetDequantizedOutput(), - ElementsAreArray(ArrayFloatNear({11.1294}, kQuantizedTolerance))); + DynamicMaxOpTestScalar(); +} + +TEST(DynamicInt16MaxOpTest, Scalar) { + DynamicMaxOpTestScalar(); } // Tests for reduce_min @@ -1221,148 +1235,162 @@ TEST(DynamicFloatMinOpTest, Scalar) { EXPECT_THAT(m.GetOutput(), ElementsAreArray(ArrayFloatNear({9.527}))); } -TEST(ConstUint8MinOpTest, NotKeepDims) { - float kQuantizedTolerance = GetTolerance(-1.0, 1.0); +template +void ConstMinOpTestNotKeepDims() { + const float kMin = -1; + const float kMax = + std::numeric_limits::max() / + static_cast(std::numeric_limits::max() + 1); + const float kQuantizedTolerance = GetTolerance(-1.0, 1.0); std::vector data = {0.4, 0.2, 0.3, 0.4, 0.5, 0.6}; - MinOpConstModel m({TensorType_UINT8, {1, 3, 2}, -1.0, 1.0}, - {TensorType_UINT8, {2}, -1.0, 1.0}, {1}, {1}, false); - m.QuantizeAndPopulate(m.Input(), data); + MinOpConstModel m({tensor_type, {1, 3, 2}, 1.0 * kMin, 1.0 * kMax}, + {tensor_type, {2}, 1.0 * kMin, 1.0 * kMax}, {1}, {1}, + false); + m.QuantizeAndPopulate(m.Input(), data); m.Invoke(); EXPECT_THAT(m.GetOutputShape(), ElementsAreArray({1, 2})); EXPECT_THAT( - m.GetDequantizedOutput(), - ElementsAreArray(ArrayFloatNear({0.294117, 0.2}, kQuantizedTolerance))); + m.GetDequantizedOutput(), + ElementsAreArray(ArrayFloatNear({0.3, 0.2}, kQuantizedTolerance))); +} + +TEST(ConstUint8MinOpTest, NotKeepDims) { + ConstMinOpTestNotKeepDims(); } TEST(ConstInt8MinOpTest, NotKeepDims) { - float kQuantizedTolerance = GetTolerance(-1.0, 1.0); + ConstMinOpTestNotKeepDims(); +} + +TEST(ConstInt16MinOpTest, NotKeepDims) { + ConstMinOpTestNotKeepDims(); +} + +template +void ConstMinOpTestKeepDims() { + const float kMin = -1; + const float kMax = + std::numeric_limits::max() / + static_cast(std::numeric_limits::max() + 1); + const float kQuantizedTolerance = GetTolerance(-1.0, 1.0); std::vector data = {0.4, 0.2, 0.3, 0.4, 0.5, 0.6}; - MinOpConstModel m({TensorType_INT8, {1, 3, 2}, -1.0, 1.0}, - {TensorType_INT8, {2}, -1.0, 1.0}, {1}, {1}, false); - m.QuantizeAndPopulate(m.Input(), data); + MinOpConstModel m({tensor_type, {3, 2}, 1.0 * kMin, 1.0 * kMax}, + {tensor_type, {3}, 1.0 * kMin, 1.0 * kMax}, {1}, {1}, true); + m.QuantizeAndPopulate(m.Input(), data); m.Invoke(); - EXPECT_THAT(m.GetOutputShape(), ElementsAreArray({1, 2})); + EXPECT_THAT(m.GetOutputShape(), ElementsAreArray({3, 1})); EXPECT_THAT( - m.GetDequantizedOutput(), - ElementsAreArray(ArrayFloatNear({0.294117, 0.2}, kQuantizedTolerance))); + m.GetDequantizedOutput(), + ElementsAreArray(ArrayFloatNear({0.2, 0.3, 0.5}, kQuantizedTolerance))); } TEST(ConstUint8MinOpTest, KeepDims) { - float kQuantizedTolerance = GetTolerance(-1.0, 1.0); - std::vector data = {0.4, 0.2, 0.3, 0.4, 0.5, 0.6}; - MinOpConstModel m({TensorType_UINT8, {3, 2}, -1.0, 1.0}, - {TensorType_UINT8, {3}, -1.0, 1.0}, {1}, {1}, true); - m.QuantizeAndPopulate(m.Input(), data); - m.Invoke(); - EXPECT_THAT(m.GetOutputShape(), ElementsAreArray({3, 1})); - EXPECT_THAT( - m.GetDequantizedOutput(), - ElementsAreArray(ArrayFloatNear({0.2, 0.3, 0.5}, kQuantizedTolerance))); + ConstMinOpTestKeepDims(); } TEST(ConstInt8MinOpTest, KeepDims) { - float kQuantizedTolerance = GetTolerance(-1.0, 1.0); - std::vector data = {0.4, 0.2, 0.3, 0.4, 0.5, 0.6}; - MinOpConstModel m({TensorType_INT8, {3, 2}, -1.0, 1.0}, - {TensorType_INT8, {3}, -1.0, 1.0}, {1}, {1}, true); - m.QuantizeAndPopulate(m.Input(), data); + ConstMinOpTestKeepDims(); +} + +TEST(ConstInt16MinOpTest, KeepDims) { + ConstMinOpTestKeepDims(); +} + +template +void DynamicMinOpTestNotKeepDims() { + const float kMin = -1; + const float kMax = + std::numeric_limits::max() / + static_cast(std::numeric_limits::max() + 1); + const float kQuantizedTolerance = GetTolerance(-5.0, 5.0); + std::vector data = {1.3, -4.8, -3.6, 0.24}; + MinOpDynamicModel m({tensor_type, {2, 2}, 5.0 * kMin, 5.0 * kMax}, + {tensor_type, {2}, 5.0 * kMin, 5.0 * kMax}, + {TensorType_INT32, {1}}, false); + std::vector axis = {1}; + m.SetAxis(axis); + m.QuantizeAndPopulate(m.Input(), data); m.Invoke(); - EXPECT_THAT(m.GetOutputShape(), ElementsAreArray({3, 1})); + EXPECT_THAT(m.GetOutputShape(), ElementsAreArray({2})); EXPECT_THAT( - m.GetDequantizedOutput(), - ElementsAreArray(ArrayFloatNear({0.2, 0.3, 0.5}, kQuantizedTolerance))); + m.GetDequantizedOutput(), + ElementsAreArray(ArrayFloatNear({-4.8, -3.6}, kQuantizedTolerance))); } TEST(DynamicUint8MinOpTest, NotKeepDims) { - float kQuantizedTolerance = GetTolerance(-5.0, 2.0); - std::vector data = {1.3, -4.8, -3.6, 0.24}; - MinOpDynamicModel m({TensorType_UINT8, {2, 2}, -5.0, 2.0}, - {TensorType_UINT8, {2}, -5.0, 2.0}, - {TensorType_INT32, {1}}, false); - std::vector axis = {1}; - m.SetAxis(axis); - m.QuantizeAndPopulate(m.Input(), data); - m.Invoke(); - EXPECT_THAT(m.GetOutputShape(), ElementsAreArray({2})); - EXPECT_THAT( - m.GetDequantizedOutput(), - ElementsAreArray(ArrayFloatNear({-4.807843, -3.6}, kQuantizedTolerance))); + DynamicMinOpTestNotKeepDims(); } TEST(DynamicInt8MinOpTest, NotKeepDims) { - float kQuantizedTolerance = GetTolerance(-5.0, 2.0); - std::vector data = {1.3, -4.8, -3.6, 0.24}; - MinOpDynamicModel m({TensorType_INT8, {2, 2}, -5.0, 2.0}, - {TensorType_INT8, {2}, -5.0, 2.0}, - {TensorType_INT32, {1}}, false); - std::vector axis = {1}; + DynamicMinOpTestNotKeepDims(); +} + +TEST(DynamicInt16MinOpTest, NotKeepDims) { + DynamicMinOpTestNotKeepDims(); +} + +template +void DynamicMinOpTestKeepDims() { + const float kMin = -1; + const float kMax = + std::numeric_limits::max() / + static_cast(std::numeric_limits::max() + 1); + const float kQuantizedTolerance = GetTolerance(-12.0, 12.0); + std::vector data = {11.14, -0.14, 7.423, 0.879}; + MinOpDynamicModel m({tensor_type, {2, 2}, 12.0 * kMin, 12.0 * kMax}, + {tensor_type, {2}, 12.0 * kMin, 12.0 * kMax}, + {TensorType_INT32, {1}}, true); + std::vector axis = {0}; m.SetAxis(axis); - m.QuantizeAndPopulate(m.Input(), data); + m.QuantizeAndPopulate(m.Input(), data); m.Invoke(); - EXPECT_THAT(m.GetOutputShape(), ElementsAreArray({2})); + EXPECT_THAT(m.GetOutputShape(), ElementsAreArray({1, 2})); EXPECT_THAT( - m.GetDequantizedOutput(), - ElementsAreArray(ArrayFloatNear({-4.807843, -3.6}, kQuantizedTolerance))); + m.GetDequantizedOutput(), + ElementsAreArray(ArrayFloatNear({7.423, -0.14}, kQuantizedTolerance))); } TEST(DynamicUint8MinOpTest, KeepDims) { - float kQuantizedTolerance = GetTolerance(-10.0, 12.0); - std::vector data = {11.14, -0.14, 7.423, 0.879}; - MinOpDynamicModel m({TensorType_UINT8, {2, 2}, -10.0, 12.0}, - {TensorType_UINT8, {2}, -10.0, 12.0}, - {TensorType_INT32, {1}}, true); - std::vector axis = {0}; - m.SetAxis(axis); - m.QuantizeAndPopulate(m.Input(), data); - m.Invoke(); - EXPECT_THAT(m.GetOutputShape(), ElementsAreArray({1, 2})); - EXPECT_THAT(m.GetDequantizedOutput(), - ElementsAreArray( - ArrayFloatNear({7.427451, -0.164706}, kQuantizedTolerance))); + DynamicMinOpTestKeepDims(); } TEST(DynamicInt8MinOpTest, KeepDims) { - float kQuantizedTolerance = GetTolerance(-10.0, 12.0); - std::vector data = {11.14, -0.14, 7.423, 0.879}; - MinOpDynamicModel m({TensorType_INT8, {2, 2}, -10.0, 12.0}, - {TensorType_INT8, {2}, -10.0, 12.0}, + DynamicMinOpTestKeepDims(); +} + +TEST(DynamicInt16MinOpTest, KeepDims) { + DynamicMinOpTestKeepDims(); +} + +template +void DynamicMinOpTestScalar() { + const float kMin = -1; + const float kMax = + std::numeric_limits::max() / + static_cast(std::numeric_limits::max() + 1); + const float kQuantizedTolerance = GetTolerance(-12.0, 12.0); + std::vector data = {11.14}; + MinOpDynamicModel m({tensor_type, {}, 12.0 * kMin, 12.0 * kMax}, + {tensor_type, {}, 12.0 * kMin, 12.0 * kMax}, {TensorType_INT32, {1}}, true); std::vector axis = {0}; - m.SetAxis(axis); - m.QuantizeAndPopulate(m.Input(), data); + m.QuantizeAndPopulate(m.Input(), data); m.Invoke(); - EXPECT_THAT(m.GetOutputShape(), ElementsAreArray({1, 2})); - EXPECT_THAT(m.GetDequantizedOutput(), - ElementsAreArray( - ArrayFloatNear({7.427451, -0.164706}, kQuantizedTolerance))); + EXPECT_THAT(m.GetOutputShape(), IsEmpty()); + EXPECT_THAT(m.GetDequantizedOutput(), + ElementsAreArray(ArrayFloatNear({11.14}, kQuantizedTolerance))); } TEST(DynamicUint8MinOpTest, Scalar) { - float kQuantizedTolerance = GetTolerance(-10.0, 12.0); - std::vector data = {11.14}; - MinOpDynamicModel m({TensorType_UINT8, {}, -10.0, 12.0}, - {TensorType_UINT8, {}, -10.0, 12.0}, - {TensorType_INT32, {1}}, true); - std::vector axis = {0}; - m.QuantizeAndPopulate(m.Input(), data); - m.Invoke(); - EXPECT_THAT(m.GetOutputShape(), IsEmpty()); - EXPECT_THAT(m.GetDequantizedOutput(), - ElementsAreArray(ArrayFloatNear({11.1294}, kQuantizedTolerance))); + DynamicMinOpTestScalar(); } TEST(DynamicInt8MinOpTest, Scalar) { - float kQuantizedTolerance = GetTolerance(-10.0, 12.0); - std::vector data = {11.14}; - MinOpDynamicModel m({TensorType_INT8, {}, -10.0, 12.0}, - {TensorType_INT8, {}, -10.0, 12.0}, - {TensorType_INT32, {1}}, true); - std::vector axis = {0}; - m.QuantizeAndPopulate(m.Input(), data); - m.Invoke(); - EXPECT_THAT(m.GetOutputShape(), IsEmpty()); - EXPECT_THAT(m.GetDequantizedOutput(), - ElementsAreArray(ArrayFloatNear({11.1294}, kQuantizedTolerance))); + DynamicMinOpTestScalar(); +} + +TEST(DynamicInt16MinOpTest, Scalar) { + DynamicMinOpTestScalar(); } // Tests for reduce_any diff --git a/tensorflow/lite/kernels/register.cc b/tensorflow/lite/kernels/register.cc index 6e15f553fdb..06f3309d63c 100644 --- a/tensorflow/lite/kernels/register.cc +++ b/tensorflow/lite/kernels/register.cc @@ -218,10 +218,10 @@ BuiltinOpResolver::BuiltinOpResolver() { AddBuiltin(BuiltinOperator_REDUCE_PROD, Register_REDUCE_PROD()); AddBuiltin(BuiltinOperator_REDUCE_MAX, Register_REDUCE_MAX(), /* min_version = */ 1, - /* max_version = */ 2); + /* max_version = */ 3); AddBuiltin(BuiltinOperator_REDUCE_MIN, Register_REDUCE_MIN(), /* min_version = */ 1, - /* max_version = */ 2); + /* max_version = */ 3); AddBuiltin(BuiltinOperator_REDUCE_ANY, Register_REDUCE_ANY()); AddBuiltin(BuiltinOperator_EXPAND_DIMS, Register_EXPAND_DIMS()); AddBuiltin(BuiltinOperator_SPARSE_TO_DENSE, Register_SPARSE_TO_DENSE(), diff --git a/tensorflow/lite/kernels/register_ref.cc b/tensorflow/lite/kernels/register_ref.cc index c8fb46adb96..40d8731256c 100644 --- a/tensorflow/lite/kernels/register_ref.cc +++ b/tensorflow/lite/kernels/register_ref.cc @@ -374,10 +374,10 @@ BuiltinRefOpResolver::BuiltinRefOpResolver() { AddBuiltin(BuiltinOperator_REDUCE_PROD, Register_REDUCE_PROD()); AddBuiltin(BuiltinOperator_REDUCE_MAX, Register_REDUCE_MAX(), /* min_version = */ 1, - /* max_version = */ 2); + /* max_version = */ 3); AddBuiltin(BuiltinOperator_REDUCE_MIN, Register_REDUCE_MIN(), /* min_version = */ 1, - /* max_version = */ 2); + /* max_version = */ 3); AddBuiltin(BuiltinOperator_REDUCE_ANY, Register_REDUCE_ANY()); AddBuiltin(BuiltinOperator_EXPAND_DIMS, Register_EXPAND_DIMS()); AddBuiltin(BuiltinOperator_SPARSE_TO_DENSE, Register_SPARSE_TO_DENSE(), diff --git a/tensorflow/lite/toco/tflite/op_version.cc b/tensorflow/lite/toco/tflite/op_version.cc index 72fc4eea1e7..46f817b1650 100644 --- a/tensorflow/lite/toco/tflite/op_version.cc +++ b/tensorflow/lite/toco/tflite/op_version.cc @@ -139,8 +139,10 @@ std::string GetMinimumRuntimeVersionForModel(const Model& model) { {{OperatorType::kSum, 2}, "1.15.0"}, {{OperatorType::kReduceMax, 1}, "1.11.0"}, {{OperatorType::kReduceMax, 2}, "1.14.0"}, + {{OperatorType::kReduceMax, 3}, kPendingReleaseOpVersion}, {{OperatorType::kReduceMin, 1}, "1.11.0"}, {{OperatorType::kReduceMin, 2}, "1.14.0"}, + {{OperatorType::kReduceMin, 3}, kPendingReleaseOpVersion}, {{OperatorType::kReduceProd, 1}, "1.11.0"}, {{OperatorType::kAny, 1}, "1.11.0"}, {{OperatorType::kRelu6, 1}, "1.5.0"}, diff --git a/tensorflow/lite/tools/versioning/op_version.cc b/tensorflow/lite/tools/versioning/op_version.cc index a15fc27d43a..d365af1c228 100644 --- a/tensorflow/lite/tools/versioning/op_version.cc +++ b/tensorflow/lite/tools/versioning/op_version.cc @@ -547,6 +547,8 @@ int GetBuiltinOperatorVersion(const OpSignature& op_sig) { case BuiltinOperator_MEAN: case BuiltinOperator_PAD: case BuiltinOperator_PADV2: + case BuiltinOperator_REDUCE_MAX: + case BuiltinOperator_REDUCE_MIN: // In case of int16 inputs, the version is 3. if (op_sig.input_types.at(0) == TensorType_INT16) { return 3; @@ -573,8 +575,6 @@ int GetBuiltinOperatorVersion(const OpSignature& op_sig) { case BuiltinOperator_SPACE_TO_DEPTH: case BuiltinOperator_SPLIT_V: case BuiltinOperator_SUM: - case BuiltinOperator_REDUCE_MAX: - case BuiltinOperator_REDUCE_MIN: case BuiltinOperator_RELU6: case BuiltinOperator_LOG_SOFTMAX: case BuiltinOperator_TOPK_V2: diff --git a/tensorflow/lite/tools/versioning/op_version_test.cc b/tensorflow/lite/tools/versioning/op_version_test.cc index f954ea6b6d2..f3f23e80cb1 100644 --- a/tensorflow/lite/tools/versioning/op_version_test.cc +++ b/tensorflow/lite/tools/versioning/op_version_test.cc @@ -306,6 +306,14 @@ TEST(OpVersionTest, VersioningSumTest) { SimpleVersioningTest(BuiltinOperator_SUM); } +TEST(OpVersionTest, VersioningReduceMinTest) { + SimpleVersioningTestExtended(BuiltinOperator_REDUCE_MIN); +} + +TEST(OpVersionTest, VersioningReduceMaxTest) { + SimpleVersioningTestExtended(BuiltinOperator_REDUCE_MAX); +} + TEST(OpVersionTest, VersioningAddTest) { SimpleVersioningTest(BuiltinOperator_ADD); } diff --git a/tensorflow/lite/tools/versioning/runtime_version.cc b/tensorflow/lite/tools/versioning/runtime_version.cc index cac6779c48a..17bf5713ccf 100644 --- a/tensorflow/lite/tools/versioning/runtime_version.cc +++ b/tensorflow/lite/tools/versioning/runtime_version.cc @@ -180,8 +180,10 @@ std::string FindMinimumRuntimeVersionForOp(tflite::BuiltinOperator op_code, {{BuiltinOperator_SUM, 2}, "1.15.0"}, {{BuiltinOperator_REDUCE_MAX, 1}, "1.11.0"}, {{BuiltinOperator_REDUCE_MAX, 2}, "1.14.0"}, + {{BuiltinOperator_REDUCE_MAX, 3}, kPendingReleaseVersion}, {{BuiltinOperator_REDUCE_MIN, 1}, "1.11.0"}, {{BuiltinOperator_REDUCE_MIN, 2}, "1.14.0"}, + {{BuiltinOperator_REDUCE_MIN, 3}, kPendingReleaseVersion}, {{BuiltinOperator_REDUCE_PROD, 1}, "1.11.0"}, {{BuiltinOperator_REDUCE_ANY, 1}, "1.11.0"}, {{BuiltinOperator_RELU6, 1}, "1.5.0"}, From 43b1e7396c8c911525be29c8602336e406fee121 Mon Sep 17 00:00:00 2001 From: Thibaut Goetghebuer-Planchon Date: Wed, 23 Sep 2020 11:23:56 +0100 Subject: [PATCH 2/3] Use Register_*_REF for reduce operators in BuiltinRefOpResolver --- tensorflow/lite/kernels/register_ref.cc | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/tensorflow/lite/kernels/register_ref.cc b/tensorflow/lite/kernels/register_ref.cc index 40d8731256c..8edbfc7f343 100644 --- a/tensorflow/lite/kernels/register_ref.cc +++ b/tensorflow/lite/kernels/register_ref.cc @@ -101,11 +101,11 @@ TfLiteRegistration* Register_LESS_EQUAL(); TfLiteRegistration* Register_FLOOR_REF(); TfLiteRegistration* Register_TILE(); TfLiteRegistration* Register_NEG(); -TfLiteRegistration* Register_SUM(); -TfLiteRegistration* Register_REDUCE_PROD(); -TfLiteRegistration* Register_REDUCE_MAX(); -TfLiteRegistration* Register_REDUCE_MIN(); -TfLiteRegistration* Register_REDUCE_ANY(); +TfLiteRegistration* Register_SUM_REF(); +TfLiteRegistration* Register_REDUCE_PROD_REF(); +TfLiteRegistration* Register_REDUCE_MAX_REF(); +TfLiteRegistration* Register_REDUCE_MIN_REF(); +TfLiteRegistration* Register_REDUCE_ANY_REF(); TfLiteRegistration* Register_SELECT(); TfLiteRegistration* Register_SLICE_REF(); TfLiteRegistration* Register_SIN(); @@ -368,17 +368,17 @@ BuiltinRefOpResolver::BuiltinRefOpResolver() { AddBuiltin(BuiltinOperator_TILE, Register_TILE(), /* min_version = */ 1, /* max_version = */ 2); - AddBuiltin(BuiltinOperator_SUM, Register_SUM(), + AddBuiltin(BuiltinOperator_SUM, Register_SUM_REF(), /* min_version = */ 1, /* max_version = */ 2); - AddBuiltin(BuiltinOperator_REDUCE_PROD, Register_REDUCE_PROD()); - AddBuiltin(BuiltinOperator_REDUCE_MAX, Register_REDUCE_MAX(), + AddBuiltin(BuiltinOperator_REDUCE_PROD, Register_REDUCE_PROD_REF()); + AddBuiltin(BuiltinOperator_REDUCE_MAX, Register_REDUCE_MAX_REF(), /* min_version = */ 1, /* max_version = */ 3); - AddBuiltin(BuiltinOperator_REDUCE_MIN, Register_REDUCE_MIN(), + AddBuiltin(BuiltinOperator_REDUCE_MIN, Register_REDUCE_MIN_REF(), /* min_version = */ 1, /* max_version = */ 3); - AddBuiltin(BuiltinOperator_REDUCE_ANY, Register_REDUCE_ANY()); + AddBuiltin(BuiltinOperator_REDUCE_ANY, Register_REDUCE_ANY_REF()); AddBuiltin(BuiltinOperator_EXPAND_DIMS, Register_EXPAND_DIMS()); AddBuiltin(BuiltinOperator_SPARSE_TO_DENSE, Register_SPARSE_TO_DENSE(), /* min_version = */ 1, From 5f1adf36f5752e18dae49bb77db88918abc4abdc Mon Sep 17 00:00:00 2001 From: Thibaut Goetghebuer-Planchon Date: Wed, 7 Oct 2020 08:45:30 +0100 Subject: [PATCH 3/3] Remove unnecessary version increment of kReduceMin and kReduceMax in deprecated file --- tensorflow/lite/toco/tflite/op_version.cc | 2 -- 1 file changed, 2 deletions(-) diff --git a/tensorflow/lite/toco/tflite/op_version.cc b/tensorflow/lite/toco/tflite/op_version.cc index 46f817b1650..72fc4eea1e7 100644 --- a/tensorflow/lite/toco/tflite/op_version.cc +++ b/tensorflow/lite/toco/tflite/op_version.cc @@ -139,10 +139,8 @@ std::string GetMinimumRuntimeVersionForModel(const Model& model) { {{OperatorType::kSum, 2}, "1.15.0"}, {{OperatorType::kReduceMax, 1}, "1.11.0"}, {{OperatorType::kReduceMax, 2}, "1.14.0"}, - {{OperatorType::kReduceMax, 3}, kPendingReleaseOpVersion}, {{OperatorType::kReduceMin, 1}, "1.11.0"}, {{OperatorType::kReduceMin, 2}, "1.14.0"}, - {{OperatorType::kReduceMin, 3}, kPendingReleaseOpVersion}, {{OperatorType::kReduceProd, 1}, "1.11.0"}, {{OperatorType::kAny, 1}, "1.11.0"}, {{OperatorType::kRelu6, 1}, "1.5.0"},