/* 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 #include #include #include #include #include #include #include #include "flatbuffers/flatbuffers.h" // from @flatbuffers #include "tensorflow/lite/kernels/reduce_test_common.h" #include "tensorflow/lite/kernels/test_util.h" #include "tensorflow/lite/schema/schema_generated.h" namespace tflite { namespace { using ::testing::ElementsAre; using ::testing::ElementsAreArray; using ::testing::IsEmpty; using MeanOpConstModel = BaseConstOpModel; using MeanOpDynamicModel = BaseDynamicOpModel; using SumOpConstModel = BaseConstOpModel; using SumOpDynamicModel = BaseDynamicOpModel; template using ProdOpFullyConstModel = BaseFullyConstOpModel; using ProdOpConstModel = BaseConstOpModel; using ProdOpDynamicModel = BaseDynamicOpModel; using MaxOpConstModel = BaseConstOpModel; using MaxOpDynamicModel = BaseDynamicOpModel; using MinOpConstModel = BaseConstOpModel; using MinOpDynamicModel = BaseDynamicOpModel; using AnyOpConstModel = BaseConstOpModel; using AnyOpDynamicModel = BaseDynamicOpModel; using AllOpConstModel = BaseConstOpModel; using AllOpDynamicModel = BaseDynamicOpModel; // for quantized Add, the error shouldn't exceed step template float GetTolerance(float min, float max) { float kQuantizedStep = (max - min) / (std::numeric_limits::max() - std::numeric_limits::min()); return kQuantizedStep; } using BoolReductions = ::testing::Types; using NonBoolReductions = ::testing::Types; using DynamicBoolReductions = ::testing::Types; using DynamicNonBoolReductions = ::testing::Types; template class ReductionIsCopyTest : public testing::Test {}; template class ReductionIsCopyTestBool : public testing::Test {}; template class DynamicReductionIsCopyTest : public testing::Test {}; template class DynamicReductionIsCopyTestBool : public testing::Test {}; TYPED_TEST_SUITE(ReductionIsCopyTest, NonBoolReductions); TYPED_TEST_SUITE(ReductionIsCopyTestBool, BoolReductions); TYPED_TEST_SUITE(DynamicReductionIsCopyTest, DynamicNonBoolReductions); TYPED_TEST_SUITE(DynamicReductionIsCopyTestBool, DynamicBoolReductions); // Test reductions which are copies. TYPED_TEST(ReductionIsCopyTest, ReduceIsCopy) { std::vector data = {1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0, 9.0, 10.0, 11.0, 12.0, 13.0, 14.0, 15.0, 16.0, 17.0, 18.0, 19.0, 20.0, 21.0, 22.0, 23.0, 24.0}; TypeParam m({TensorType_FLOAT32, {4, 3, 2}}, {TensorType_FLOAT32, {4, 3, 2}}, {0}, {}, false); m.SetInput(data); ASSERT_EQ(m.Invoke(), kTfLiteOk); EXPECT_THAT(m.GetOutputShape(), ElementsAreArray({4, 3, 2})); EXPECT_THAT(m.template GetOutput(), ElementsAreArray(ArrayFloatNear(data))); } TYPED_TEST(ReductionIsCopyTestBool, ReduceIsCopyBool) { std::vector data = {false, false, false, false, false, false, false, true, false, false, false, true}; TypeParam m({TensorType_BOOL, {2, 3, 2}}, {TensorType_BOOL, {2, 3, 2}}, {0}, {}, false); m.SetInput(data); ASSERT_EQ(m.Invoke(), kTfLiteOk); EXPECT_THAT(m.GetOutputShape(), ElementsAreArray({2, 3, 2})); EXPECT_THAT(m.template GetOutput(), ElementsAreArray(data)); } TYPED_TEST(DynamicReductionIsCopyTest, ReduceIsCopy) { std::vector data = {1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0, 9.0, 10.0, 11.0, 12.0, 13.0, 14.0, 15.0, 16.0, 17.0, 18.0, 19.0, 20.0, 21.0, 22.0, 23.0, 24.0}; TypeParam m({TensorType_FLOAT32, {4, 3, 2}}, {TensorType_FLOAT32, {4, 3, 2}}, {TensorType_INT32, {0}}, false); m.SetInput(data); ASSERT_EQ(m.Invoke(), kTfLiteOk); EXPECT_THAT(m.GetOutputShape(), ElementsAreArray({4, 3, 2})); EXPECT_THAT(m.template GetOutput(), ElementsAreArray(ArrayFloatNear(data))); } TYPED_TEST(DynamicReductionIsCopyTestBool, ReduceIsCopy) { std::vector data = {false, false, false, false, false, false, false, true, false, false, false, true}; TypeParam m({TensorType_BOOL, {2, 3, 2}}, {TensorType_BOOL, {2, 3, 2}}, {TensorType_INT32, {0}}, false); m.SetInput(data); ASSERT_EQ(m.Invoke(), kTfLiteOk); EXPECT_THAT(m.GetOutputShape(), ElementsAreArray({2, 3, 2})); EXPECT_THAT(m.template GetOutput(), ElementsAreArray(data)); } TEST(ConstFloatMeanOpTest, FoldFirstDim) { int count = 1 * 2 * 2 * 3; std::vector data(count); std::iota(data.begin(), data.end(), 0); SumOpConstModel m({TensorType_FLOAT32, {1, 2, 2, 3}}, {TensorType_FLOAT32, {2, 2}}, {2}, {3, 0}, false); m.SetInput(data); ASSERT_EQ(m.Invoke(), kTfLiteOk); EXPECT_THAT(m.GetOutputShape(), ElementsAreArray({2, 2})); EXPECT_THAT(m.GetOutput(), ElementsAreArray(ArrayFloatNear({3, 12, 21, 30}))); } TEST(ConstFloatMeanOpTest, Flatten2ReduceDims) { std::vector data = {1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0, 9.0, 10.0, 11.0, 12.0, 13.0, 14.0, 15.0, 16.0, 17.0, 18.0, 19.0, 20.0, 21.0, 22.0, 23.0, 24.0}; MeanOpConstModel m({TensorType_FLOAT32, {4, 3, 2}}, {TensorType_FLOAT32, {2}}, {2}, {2, 1}, false); m.SetInput(data); ASSERT_EQ(m.Invoke(), kTfLiteOk); EXPECT_THAT(m.GetOutputShape(), ElementsAreArray({4})); EXPECT_THAT(m.GetOutput(), ElementsAreArray(ArrayFloatNear({3.5, 9.5, 15.5, 21.5}))); } TEST(ConstFloatMeanOpTest, Flatten2NonReduceDims) { std::vector data = {1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0, 9.0, 10.0, 11.0, 12.0, 13.0, 14.0, 15.0, 16.0, 17.0, 18.0, 19.0, 20.0, 21.0, 22.0, 23.0, 24.0}; MeanOpConstModel m({TensorType_FLOAT32, {4, 3, 2}}, {TensorType_FLOAT32, {2}}, {1}, {2}, false); m.SetInput(data); ASSERT_EQ(m.Invoke(), kTfLiteOk); EXPECT_THAT(m.GetOutputShape(), ElementsAreArray({4, 3})); EXPECT_THAT( m.GetOutput(), ElementsAreArray(ArrayFloatNear({1.5, 3.5, 5.5, 7.5, 9.5, 11.5, 13.5, 15.5, 17.5, 19.5, 21.5, 23.5}))); } TEST(ConstFloatMeanOpTest, Flatten2MiddleDims) { std::vector data = {1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0, 9.0, 10.0, 11.0, 12.0, 13.0, 14.0, 15.0, 16.0, 17.0, 18.0, 19.0, 20.0, 21.0, 22.0, 23.0, 24.0}; MeanOpConstModel m({TensorType_FLOAT32, {2, 2, 3, 2}}, {TensorType_FLOAT32, {2}}, {2}, {2, 1}, false); m.SetInput(data); ASSERT_EQ(m.Invoke(), kTfLiteOk); EXPECT_THAT(m.GetOutputShape(), ElementsAreArray({2, 2})); EXPECT_THAT(m.GetOutput(), ElementsAreArray(ArrayFloatNear({6, 7, 18, 19}))); } // Tests for reduce_mean TEST(ConstFloatMeanOpTest, NotKeepDims) { std::vector data = {1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0, 9.0, 10.0, 11.0, 12.0, 13.0, 14.0, 15.0, 16.0, 17.0, 18.0, 19.0, 20.0, 21.0, 22.0, 23.0, 24.0}; MeanOpConstModel m({TensorType_FLOAT32, {4, 3, 2}}, {TensorType_FLOAT32, {2}}, {4}, {1, 0, -3, -3}, false); m.SetInput(data); ASSERT_EQ(m.Invoke(), kTfLiteOk); EXPECT_THAT(m.GetOutputShape(), ElementsAreArray({2})); EXPECT_THAT(m.GetOutput(), ElementsAreArray(ArrayFloatNear({12, 13}))); } TEST(ConstFloatMeanOpTest, KeepDims) { std::vector data = {1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0, 9.0, 10.0, 11.0, 12.0, 13.0, 14.0, 15.0, 16.0, 17.0, 18.0, 19.0, 20.0, 21.0, 22.0, 23.0, 24.0}; MeanOpConstModel m({TensorType_FLOAT32, {4, 3, 2}}, {TensorType_FLOAT32, {3}}, {2}, {0, 2}, true); m.SetInput(data); ASSERT_EQ(m.Invoke(), kTfLiteOk); EXPECT_THAT(m.GetOutputShape(), ElementsAreArray({1, 3, 1})); EXPECT_THAT(m.GetOutput(), ElementsAreArray(ArrayFloatNear({10.5, 12.5, 14.5}))); } TEST(ConstFloatMeanOpTest, ZeroInputDim) { if (SingleOpModel::GetForceUseNnapi()) { return; } MeanOpConstModel m({TensorType_FLOAT32, {4, 0, 2}}, {TensorType_FLOAT32, {3}}, {2}, {0, 2}, true); ASSERT_EQ(m.Invoke(), kTfLiteOk); EXPECT_THAT(m.GetOutputShape(), ElementsAreArray({1, 0, 1})); } // Uses a set of reduction conditions that trigger the specialized 4D version // of Mean. TEST(ConstFloatMeanOpTest, KeepDims4DMean) { std::vector data = {1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0, 9.0, 10.0, 11.0, 12.0, 13.0, 14.0, 15.0, 16.0, 17.0, 18.0, 19.0, 20.0, 21.0, 22.0, 23.0, 24.0}; MeanOpConstModel m({TensorType_FLOAT32, {2, 2, 3, 2}}, {TensorType_FLOAT32, {3}}, {2}, {1, 2}, true); m.SetInput(data); ASSERT_EQ(m.Invoke(), kTfLiteOk); EXPECT_THAT(m.GetOutputShape(), ElementsAreArray({2, 1, 1, 2})); EXPECT_THAT(m.GetOutput(), ElementsAreArray(ArrayFloatNear({6, 7, 18, 19}))); } TEST(ConstFloatMeanOpTest, KeepDims4DMeanUInt8) { float kQuantizedTolerance = GetTolerance(-1.0, 1.0); std::vector data = {0.1, 0.2, 0.3, 0.4, 0.1, 0.2, 0.3, 0.4, 0.1, 0.2, 0.3, 0.4}; MeanOpConstModel m({TensorType_UINT8, {1, 2, 2, 3}, -1.0, 1.0}, {TensorType_UINT8, {2}, -1.0, 1.0}, {2}, {1, 2}, true); m.QuantizeAndPopulate(m.Input(), data); ASSERT_EQ(m.Invoke(), kTfLiteOk); EXPECT_THAT(m.GetOutputShape(), ElementsAreArray({1, 1, 1, 3})); EXPECT_THAT(m.GetDequantizedOutput(), ElementsAreArray(ArrayFloatNear({0.25098, 0.25098, 0.25098}, kQuantizedTolerance))); } TEST(ConstFloatMeanOpTest, KeepDims4DMeanLargeDepthUInt8) { float kQuantizedTolerance = GetTolerance(-5.0, 5.0); std::vector data = { 0.1, 0.2, 0.3, 0.4, 0.2, 0.3, 0.4, 0.5, 0.1, 0.1, 0.1, 0.1, 0.4, 0.2, 0.2, 0.2, 0.9, 0.9, 0.9, 0.9, 0.2, 0.3, 0.7, 0.7, 0.1, 0.1, 0.3, 0.3, 0.1, 0.2, 0.3, 0.4, 0.1, 0.2, 0.3, 0.4, 0.1, 0.2, 0.3, 0.4, 0.2, 0.3, 0.4, 0.5, 0.1, 0.1, 0.1, 0.1, 0.4, 0.2, 0.2, 0.2, 0.9, 0.9, 0.9, 0.9, 0.2, 0.3, 0.7, 0.7, 0.1, 0.1, 0.3, 0.3, 0.1, 0.2, 0.3, 0.4, 0.1, 0.2, 0.3, 0.4}; MeanOpConstModel m({TensorType_UINT8, {1, 2, 2, 18}, -1.0, 1.0}, {TensorType_UINT8, {2}, -1.0, 1.0}, {2}, {1, 2}, true); m.QuantizeAndPopulate(m.Input(), data); ASSERT_EQ(m.Invoke(), kTfLiteOk); EXPECT_THAT(m.GetOutputShape(), ElementsAreArray({1, 1, 1, 18})); EXPECT_THAT(m.GetDequantizedOutput(), ElementsAreArray(ArrayFloatNear( {0.5, 0.55, 0.25, 0.35, 0.45, 0.5, 0.25, 0.3, 0.2, 0.2, 0.1, 0.15, 0.35, 0.3, 0.15, 0.2, 0.6, 0.65}, kQuantizedTolerance))); } TEST(ConstFloatMeanOpTest, KeepDims4DMeanQuantized) { float kQuantizedTolerance = GetTolerance(-5.0, 5.0); std::vector data = {0.1, 0.2, 0.3, 0.4, 0.1, 0.2, 0.3, 0.4, 0.1, 0.2, 0.3, 0.4}; MeanOpConstModel m({TensorType_UINT8, {1, 2, 3, 2}, 0.0, 1.0}, {TensorType_UINT8, {3}, -5.0, 5.0}, {2}, {1, 2}, true); m.QuantizeAndPopulate(m.Input(), data); ASSERT_EQ(m.Invoke(), kTfLiteOk); EXPECT_THAT(m.GetOutputShape(), ElementsAreArray({1, 1, 1, 2})); EXPECT_THAT(m.GetDequantizedOutput(), ElementsAreArray( ArrayFloatNear({0.235294, 0.313726}, kQuantizedTolerance))); } TEST(ConstFloatMeanOpTest, Scalar) { std::vector data = {3.27}; MeanOpConstModel m({TensorType_FLOAT32, {}}, {TensorType_FLOAT32, {}}, {}, {0}, true); m.SetInput(data); ASSERT_EQ(m.Invoke(), kTfLiteOk); EXPECT_THAT(m.GetOutputShape(), IsEmpty()); EXPECT_THAT(m.GetOutput(), ElementsAreArray(ArrayFloatNear({3.27}))); } TEST(ConstFloatMeanOpTest, ScalarAxis) { std::vector data = {4., 2.}; MeanOpConstModel m({TensorType_FLOAT32, {2}}, {TensorType_FLOAT32, {1}}, {}, {0}, true); m.SetInput(data); ASSERT_EQ(m.Invoke(), kTfLiteOk); EXPECT_THAT(m.GetOutputShape(), ElementsAreArray({1})); EXPECT_THAT(m.GetOutput(), ElementsAreArray(ArrayFloatNear({3.}))); } TEST(ConstFloatMeanOpTest, UseOptimzedFloatMean) { std::vector data = {0.1, 0.2, 0.3, 0.4, 0.1, 0.2, 0.3, 0.4, 0.1, 0.2, 0.3, 0.4}; MeanOpConstModel m({TensorType_FLOAT32, {2, 3, 2}}, {TensorType_FLOAT32, {2}}, {2}, {1, 2}, false); m.SetInput(data); ASSERT_EQ(m.Invoke(), kTfLiteOk); EXPECT_THAT(m.GetOutputShape(), ElementsAreArray({2})); EXPECT_THAT(m.GetOutput(), ElementsAreArray(ArrayFloatNear({0.216667, 0.283333}))); } TEST(DynamicFloatMeanOpTest, NotKeepDims) { std::vector data = {1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0, 9.0, 10.0, 11.0, 12.0, 13.0, 14.0, 15.0, 16.0, 17.0, 18.0, 19.0, 20.0, 21.0, 22.0, 23.0, 24.0}; MeanOpDynamicModel m({TensorType_FLOAT32, {4, 3, 2}}, {TensorType_FLOAT32, {2}}, {TensorType_INT32, {4}}, false); std::vector axis = {1, 0, -3, -3}; m.SetAxis(axis); m.SetInput(data); ASSERT_EQ(m.Invoke(), kTfLiteOk); EXPECT_THAT(m.GetOutputShape(), ElementsAreArray({2})); EXPECT_THAT(m.GetOutput(), ElementsAreArray(ArrayFloatNear({12, 13}))); } TEST(DynamicFloatMeanOpTest, ReduceOnLastDimNotKeepDims) { std::vector data = {1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0, 9.0, 10.0, 11.0, 12.0, 13.0, 14.0, 15.0, 16.0, 17.0, 18.0, 19.0, 20.0, 21.0, 22.0, 23.0, 24.0}; MeanOpDynamicModel m({TensorType_FLOAT32, {4, 3, 2}}, {TensorType_FLOAT32, {2}}, {TensorType_INT32, {1}}, false); std::vector axis = {2}; m.SetAxis(axis); m.SetInput(data); ASSERT_EQ(m.Invoke(), kTfLiteOk); EXPECT_THAT(m.GetOutputShape(), ElementsAreArray({4, 3})); EXPECT_THAT( m.GetOutput(), ElementsAreArray(ArrayFloatNear({1.5, 3.5, 5.5, 7.5, 9.5, 11.5, 13.5, 15.5, 17.5, 19.5, 21.5, 23.5}))); } TEST(DynamicFloatMeanOpTest, KeepDims) { std::vector data = {1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0, 9.0, 10.0, 11.0, 12.0, 13.0, 14.0, 15.0, 16.0, 17.0, 18.0, 19.0, 20.0, 21.0, 22.0, 23.0, 24.0}; MeanOpDynamicModel m({TensorType_FLOAT32, {4, 3, 2}}, {TensorType_FLOAT32, {3}}, {TensorType_INT32, {2}}, true); std::vector axis = {0, 2}; m.SetAxis(axis); m.SetInput(data); ASSERT_EQ(m.Invoke(), kTfLiteOk); EXPECT_THAT(m.GetOutputShape(), ElementsAreArray({1, 3, 1})); EXPECT_THAT(m.GetOutput(), ElementsAreArray(ArrayFloatNear({10.5, 12.5, 14.5}))); } TEST(DynamicFloatMeanOpTest, Scale) { std::vector data = {9.527}; MeanOpDynamicModel m({TensorType_FLOAT32, {1}}, {TensorType_FLOAT32, {1}}, {TensorType_INT32, {1}}, true); std::vector axis = {0}; m.SetAxis(axis); m.SetInput(data); ASSERT_EQ(m.Invoke(), kTfLiteOk); EXPECT_THAT(m.GetOutputShape(), ElementsAreArray({1})); EXPECT_THAT(m.GetOutput(), ElementsAreArray(ArrayFloatNear({9.527}))); } TEST(ConstUint8MeanOpTest, NotKeepDims) { float kQuantizedTolerance = GetTolerance(-1.0, 1.0); std::vector data = {0.4, 0.2, 0.3, 0.4, 0.5, 0.6}; MeanOpConstModel 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); ASSERT_EQ(m.Invoke(), kTfLiteOk); EXPECT_THAT(m.GetOutputShape(), ElementsAreArray({1, 2})); EXPECT_THAT( m.GetDequantizedOutput(), ElementsAreArray(ArrayFloatNear({0.4, 0.4}, kQuantizedTolerance))); } TEST(ConstUint8MeanOpTest, KeepDims) { float kQuantizedTolerance = GetTolerance(-1.0, 1.0); std::vector data = {0.4, 0.2, 0.3, 0.4, 0.5, 0.6}; MeanOpConstModel m({TensorType_UINT8, {3, 2}, -1.0, 1.0}, {TensorType_UINT8, {3}, -1.0, 1.0}, {1}, {1}, true); m.QuantizeAndPopulate(m.Input(), data); ASSERT_EQ(m.Invoke(), kTfLiteOk); EXPECT_THAT(m.GetOutputShape(), ElementsAreArray({3, 1})); EXPECT_THAT( m.GetDequantizedOutput(), ElementsAreArray(ArrayFloatNear({0.3, 0.35, 0.55}, kQuantizedTolerance))); } TEST(ConstUint8MeanOpTest, Rounding) { std::vector data = {0.4, 0.2, 0.3, 0.4, 0.5, 0.6}; MeanOpConstModel m({TensorType_UINT8, {3, 2}, -1.0, 1.0}, {TensorType_UINT8, {3}, -1.1, 1.1}, {1}, {1}, true); m.QuantizeAndPopulate(m.Input(), data); ASSERT_EQ(m.Invoke(), kTfLiteOk); EXPECT_THAT(m.GetOutputShape(), ElementsAreArray({3, 1})); // Different quantization algorithms in TFLite and NNAPI can give slightly // different results. EXPECT_THAT(m.GetOutput(), testing::AnyOf(ElementsAreArray({163, 168, 192}), ElementsAreArray({163, 169, 192}))); } TEST(ConstInt8MeanOpTest, Rounding) { std::vector data = {0.4, 0.2, 0.3, 0.4, 0.5, 0.6}; MeanOpConstModel m({TensorType_INT8, {3, 2}, -1.0, 1.0}, {TensorType_INT8, {3}, -1.1, 1.1}, {1}, {1}, true); m.QuantizeAndPopulate(m.Input(), data); ASSERT_EQ(m.Invoke(), kTfLiteOk); EXPECT_THAT(m.GetOutputShape(), ElementsAreArray({3, 1})); // Different quantization algorithms in TFLite and NNAPI can give slightly // different results. EXPECT_THAT(m.GetOutput(), testing::AnyOf(ElementsAreArray({34, 39, 63}), ElementsAreArray({34, 40, 63}))); } template void MeanOpConstModelTest() { float kQuantizedTolerance = GetTolerance(-255.0, 255.0); std::vector data = {105.0, 71.0, 233.0, 92.0, 227.0, 11.0, 14.0, 43.0}; MeanOpConstModel m({tensor_dtype, {1, 1, 2, 4}, -255.0, 255.0}, {tensor_dtype, {1, 2, 4}, -255, 255.0}, {1}, {1}, false); m.QuantizeAndPopulate(m.Input(), data); ASSERT_EQ(m.Invoke(), kTfLiteOk); EXPECT_THAT(m.GetOutputShape(), ElementsAreArray({1, 2, 4})); EXPECT_THAT(m.GetDequantizedOutput(), ElementsAreArray(ArrayFloatNear(data, kQuantizedTolerance))); } class ConstMeanOpTestSameScale : public ::testing::Test {}; TEST_F(ConstMeanOpTestSameScale, NonSpecialAxisSameScaleInt8) { MeanOpConstModelTest(); } TEST_F(ConstMeanOpTestSameScale, NonSpecialAxisSameScaleInt16) { MeanOpConstModelTest(); } template void ConstMeanOpTestNonSameScale() { float kQuantizedTolerance = GetTolerance(-5.0, 5.0); std::vector data = {0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.7, 0.8}; MeanOpConstModel m({tensor_dtype, {1, 1, 2, 4}, -1.0, 1.0}, {tensor_dtype, {1, 2}, -5.0, 5.0}, {2}, {1, 3}, false); m.QuantizeAndPopulate(m.Input(), data); ASSERT_EQ(m.Invoke(), kTfLiteOk); EXPECT_THAT(m.GetOutputShape(), ElementsAreArray({1, 2})); EXPECT_THAT( m.GetDequantizedOutput(), ElementsAreArray(ArrayFloatNear({0.25, 0.65}, kQuantizedTolerance))); } class ConstMeanOpTestNonSameScale : public ::testing::Test {}; TEST_F(ConstMeanOpTestNonSameScale, NonSpecialAxisNonSameScaleInt8) { MeanOpConstModelTest(); } TEST_F(ConstMeanOpTestNonSameScale, NonSpecialAxisNonSameScaleInt16) { MeanOpConstModelTest(); } template void MeanOpTestQuantizedSameScale() { float kQuantizedTolerance = GetTolerance(-5.0, 5.0); std::vector data = {0.1, 0.2, 0.3, 0.4, 0.2, 0.3, 0.4, 0.5, 0.1, 0.1, 0.1, 0.1, 0.4, 0.2, 0.2, 0.2, 0.9, 0.9, 0.9, 0.9, 0.2, 0.3, 0.7, 0.7, 0.1, 0.1, 0.3, 0.3, 0.1, 0.2, 0.3, 0.4, 0.1, 0.2, 0.3, 0.4}; MeanOpConstModel m({tensor_dtype, {1, 2, 2, 9}, -1.0, 1.0}, {tensor_dtype, {2}, -1.0, 1.0}, {2}, {1, 2}, true); m.QuantizeAndPopulate(m.Input(), data); ASSERT_EQ(m.Invoke(), kTfLiteOk); EXPECT_THAT(m.GetOutputShape(), ElementsAreArray({1, 1, 1, 9})); EXPECT_THAT(m.GetDequantizedOutput(), ElementsAreArray(ArrayFloatNear( {0.35, 0.325, 0.2, 0.35, 0.375, 0.325, 0.225, 0.45, 0.425}, kQuantizedTolerance))); } class MeanOpTestQuantizedSameScale : public ::testing::Test {}; TEST_F(MeanOpTestQuantizedSameScale, QuantizedSameScaleInt8) { MeanOpConstModelTest(); } TEST_F(MeanOpTestQuantizedSameScale, QuantizedSameScaleInt16) { MeanOpConstModelTest(); } template void MeanOpTestQuantizedDifferentScale() { float kQuantizedTolerance = GetTolerance(-5.0, 5.0); std::vector data = {0.1, 0.2, 0.3, 0.4, 0.2, 0.3, 0.4, 0.5, 0.1, 0.1, 0.1, 0.1, 0.4, 0.2, 0.2, 0.2, 0.9, 0.9, 0.9, 0.9, 0.2, 0.3, 0.7, 0.7, 0.1, 0.1, 0.3, 0.3, 0.1, 0.2, 0.3, 0.4, 0.1, 0.2, 0.3, 0.4}; MeanOpConstModel m({tensor_dtype, {1, 2, 2, 9}, -1.0, 1.0}, {tensor_dtype, {2}, -4.0, 4.0}, {2}, {1, 2}, true); m.QuantizeAndPopulate(m.Input(), data); ASSERT_EQ(m.Invoke(), kTfLiteOk); EXPECT_THAT(m.GetOutputShape(), ElementsAreArray({1, 1, 1, 9})); EXPECT_THAT(m.GetDequantizedOutput(), ElementsAreArray(ArrayFloatNear( {0.35, 0.325, 0.2, 0.35, 0.375, 0.325, 0.225, 0.45, 0.425}, kQuantizedTolerance))); } class MeanOpTestQuantizedDifferentScale : public ::testing::Test {}; TEST_F(MeanOpTestQuantizedDifferentScale, QuantizedDifferentScaleInt8) { MeanOpConstModelTest(); } TEST_F(MeanOpTestQuantizedDifferentScale, QuantizedDifferentScaleInt16) { MeanOpConstModelTest(); } TEST(ConstFloatMeanOpTest, KeepDims4DMeanLargeDepthInt8) { float kQuantizedTolerance = GetTolerance(-5.0, 5.0); std::vector data = { 0.1, 0.2, 0.3, 0.4, 0.2, 0.3, 0.4, 0.5, 0.1, 0.1, 0.1, 0.1, 0.4, 0.2, 0.2, 0.2, 0.9, 0.9, 0.9, 0.9, 0.2, 0.3, 0.7, 0.7, 0.1, 0.1, 0.3, 0.3, 0.1, 0.2, 0.3, 0.4, 0.1, 0.2, 0.3, 0.4, 0.1, 0.2, 0.3, 0.4, 0.2, 0.3, 0.4, 0.5, 0.1, 0.1, 0.1, 0.1, 0.4, 0.2, 0.2, 0.2, 0.9, 0.9, 0.9, 0.9, 0.2, 0.3, 0.7, 0.7, 0.1, 0.1, 0.3, 0.3, 0.1, 0.2, 0.3, 0.4, 0.1, 0.2, 0.3, 0.4}; MeanOpConstModel m({TensorType_INT8, {1, 2, 2, 18}, -1.0, 1.0}, {TensorType_INT8, {2}, -1.0, 1.0}, {2}, {1, 2}, true); m.QuantizeAndPopulate(m.Input(), data); ASSERT_EQ(m.Invoke(), kTfLiteOk); EXPECT_THAT(m.GetOutputShape(), ElementsAreArray({1, 1, 1, 18})); EXPECT_THAT(m.GetDequantizedOutput(), ElementsAreArray(ArrayFloatNear( {0.5, 0.55, 0.25, 0.35, 0.45, 0.5, 0.25, 0.3, 0.2, 0.2, 0.1, 0.15, 0.35, 0.3, 0.15, 0.2, 0.6, 0.65}, kQuantizedTolerance))); } TEST(DynamicUint8MeanOpTest, NotKeepDims) { float kQuantizedTolerance = GetTolerance(-5.0, 2.0); std::vector data = {1.3, -4.8, -3.6, 0.24}; MeanOpDynamicModel 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); ASSERT_EQ(m.Invoke(), kTfLiteOk); EXPECT_THAT(m.GetOutputShape(), ElementsAreArray({2})); EXPECT_THAT( m.GetDequantizedOutput(), ElementsAreArray(ArrayFloatNear({-1.75, -1.68}, kQuantizedTolerance))); } TEST(DynamicUint8MeanOpTest, KeepDims) { float kQuantizedTolerance = GetTolerance(-10.0, 12.0); std::vector data = {11.14, -0.14, 7.423, 0.879}; MeanOpDynamicModel 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); ASSERT_EQ(m.Invoke(), kTfLiteOk); EXPECT_THAT(m.GetOutputShape(), ElementsAreArray({1, 2})); EXPECT_THAT( m.GetDequantizedOutput(), ElementsAreArray(ArrayFloatNear({9.2815, 0.3695}, kQuantizedTolerance))); } TEST(DynamicUint8MeanOpTest, QuantizedScalar) { float kQuantizedTolerance = GetTolerance(-10.0, 12.0); std::vector data = {0.643}; MeanOpDynamicModel m({TensorType_UINT8, {}, 0.0, 1.0}, {TensorType_UINT8, {}, -10.0, 12.0}, {TensorType_INT32, {1}}, true); std::vector axis = {0}; m.QuantizeAndPopulate(m.Input(), data); ASSERT_EQ(m.Invoke(), kTfLiteOk); EXPECT_THAT(m.GetOutputShape(), IsEmpty()); EXPECT_THAT(m.GetDequantizedOutput(), ElementsAreArray(ArrayFloatNear({0.643}, kQuantizedTolerance))); } TEST(ConstUint8MeanOpTest, QuantizedKeepDims) { float kQuantizedTolerance = GetTolerance(-5.0, 5.0); std::vector data = {0.4, 0.2, 0.3, 0.4, 0.5, 0.6}; MeanOpConstModel m({TensorType_UINT8, {3, 2}, 0.0, 1.0}, {TensorType_UINT8, {3}, -5.0, 5.0}, {1}, {1}, true); m.QuantizeAndPopulate(m.Input(), data); ASSERT_EQ(m.Invoke(), kTfLiteOk); EXPECT_THAT(m.GetOutputShape(), ElementsAreArray({3, 1})); EXPECT_THAT( m.GetDequantizedOutput(), ElementsAreArray(ArrayFloatNear({0.3, 0.35, 0.55}, kQuantizedTolerance))); } // Tests for reduce_sum TEST(ConstFloatSumOpTest, Size1) { std::vector data = {1.0}; SumOpConstModel m({TensorType_FLOAT32, {1}}, {TensorType_FLOAT32, {1}}, {1}, {0}, false); m.SetInput(data); ASSERT_EQ(m.Invoke(), kTfLiteOk); EXPECT_THAT(m.GetOutputShape(), IsEmpty()); EXPECT_THAT(m.GetOutput(), ElementsAreArray(ArrayFloatNear({1}))); } TEST(ConstFloatSumOpTest, Size1Dims) { std::vector data = {1.0, 2.0}; SumOpConstModel m({TensorType_FLOAT32, {2}}, {TensorType_FLOAT32, {1}}, {1}, {0}, false); m.SetInput(data); ASSERT_EQ(m.Invoke(), kTfLiteOk); EXPECT_THAT(m.GetOutputShape(), IsEmpty()); EXPECT_THAT(m.GetOutput(), ElementsAreArray(ArrayFloatNear({3}))); } TEST(ConstFloatSumOpTest, Size1Contiguous) { std::vector data = {1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0}; SumOpConstModel m({TensorType_FLOAT32, {8, 1}}, {TensorType_FLOAT32, {8}}, {1}, {1}, false); m.SetInput(data); ASSERT_EQ(m.Invoke(), kTfLiteOk); EXPECT_THAT(m.GetOutputShape(), ElementsAreArray({8})); EXPECT_THAT(m.GetOutput(), ElementsAreArray(ArrayFloatNear(data))); } TEST(ConstFloatSumOpTest, Size1DisContiguous) { std::vector data = {1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0}; SumOpConstModel m({TensorType_FLOAT32, {1, 8}}, {TensorType_FLOAT32, {1}}, {1}, {1}, false); m.SetInput(data); ASSERT_EQ(m.Invoke(), kTfLiteOk); EXPECT_THAT(m.GetOutputShape(), ElementsAreArray({1})); EXPECT_THAT(m.GetOutput(), ElementsAreArray(ArrayFloatNear({36}))); } TEST(ConstFloatSumOpTest, RedundantDimension) { std::vector data = {1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0}; SumOpConstModel m({TensorType_FLOAT32, {1, 2, 4}}, {TensorType_FLOAT32, {2}}, {1}, {1}, false); m.SetInput(data); ASSERT_EQ(m.Invoke(), kTfLiteOk); EXPECT_THAT(m.GetOutputShape(), ElementsAreArray({1, 4})); EXPECT_THAT(m.GetOutput(), ElementsAreArray(ArrayFloatNear({6, 8, 10, 12}))); } TEST(ConstFloatSumOpTest, AllSize1) { std::vector data = {1.0}; SumOpConstModel m({TensorType_FLOAT32, {1, 1, 1}}, {TensorType_FLOAT32, {1}}, {1}, {1}, false); m.SetInput(data); ASSERT_EQ(m.Invoke(), kTfLiteOk); EXPECT_THAT(m.GetOutputShape(), ElementsAreArray({1, 1})); EXPECT_THAT(m.GetOutput(), ElementsAreArray(ArrayFloatNear({1}))); } TEST(ConstFloatSumOpTest, NotKeepDims) { std::vector data = {1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0, 9.0, 10.0, 11.0, 12.0, 13.0, 14.0, 15.0, 16.0, 17.0, 18.0, 19.0, 20.0, 21.0, 22.0, 23.0, 24.0}; SumOpConstModel m({TensorType_FLOAT32, {4, 3, 2}}, {TensorType_FLOAT32, {2}}, {4}, {1, 0, -3, -3}, false); m.SetInput(data); ASSERT_EQ(m.Invoke(), kTfLiteOk); EXPECT_THAT(m.GetOutputShape(), ElementsAreArray({2})); EXPECT_THAT(m.GetOutput(), ElementsAreArray(ArrayFloatNear({144, 156}))); } TEST(ConstFloatSumOpTest, KeepDims) { std::vector data = {1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0, 9.0, 10.0, 11.0, 12.0, 13.0, 14.0, 15.0, 16.0, 17.0, 18.0, 19.0, 20.0, 21.0, 22.0, 23.0, 24.0}; SumOpConstModel m({TensorType_FLOAT32, {4, 3, 2}}, {TensorType_FLOAT32, {3}}, {2}, {0, 2}, true); m.SetInput(data); ASSERT_EQ(m.Invoke(), kTfLiteOk); EXPECT_THAT(m.GetOutputShape(), ElementsAreArray({1, 3, 1})); EXPECT_THAT(m.GetOutput(), ElementsAreArray(ArrayFloatNear({84, 100, 116}))); } TEST(ConstFloatSumOpTest, ZeroInputDim) { if (SingleOpModel::GetForceUseNnapi()) { return; } SumOpConstModel m({TensorType_FLOAT32, {4, 0, 2}}, {TensorType_FLOAT32, {3}}, {2}, {0, 2}, true); ASSERT_EQ(m.Invoke(), kTfLiteOk); EXPECT_THAT(m.GetOutputShape(), ElementsAreArray({1, 0, 1})); } TEST(DynamicFloatSumOpTest, NotKeepDims) { std::vector data = {1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0, 9.0, 10.0, 11.0, 12.0, 13.0, 14.0, 15.0, 16.0, 17.0, 18.0, 19.0, 20.0, 21.0, 22.0, 23.0, 24.0}; SumOpDynamicModel m({TensorType_FLOAT32, {4, 3, 2}}, {TensorType_FLOAT32, {2}}, {TensorType_INT32, {4}}, false); std::vector axis = {1, 0, -3, -3}; m.SetAxis(axis); m.SetInput(data); ASSERT_EQ(m.Invoke(), kTfLiteOk); EXPECT_THAT(m.GetOutputShape(), ElementsAreArray({2})); EXPECT_THAT(m.GetOutput(), ElementsAreArray(ArrayFloatNear({144, 156}))); } TEST(ConstFloatSumOpTest, Scalar) { std::vector data = {17.}; SumOpConstModel m({TensorType_FLOAT32, {}}, {TensorType_FLOAT32, {}}, {}, {0}, false); m.SetInput(data); ASSERT_EQ(m.Invoke(), kTfLiteOk); EXPECT_THAT(m.GetOutputShape(), IsEmpty()); EXPECT_THAT(m.GetOutput(), ElementsAreArray(ArrayFloatNear({17.}))); } TEST(ConstFloatSumOpTest, ScalarAxis) { std::vector data = {17., 21., 4.}; SumOpConstModel m({TensorType_FLOAT32, {3}}, {TensorType_FLOAT32, {1}}, {}, {0}, true); m.SetInput(data); ASSERT_EQ(m.Invoke(), kTfLiteOk); EXPECT_THAT(m.GetOutputShape(), ElementsAreArray({1})); EXPECT_THAT(m.GetOutput(), ElementsAreArray(ArrayFloatNear({42.}))); } TEST(DynamicFloatSumOpTest, KeepDims) { std::vector data = {1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0, 9.0, 10.0, 11.0, 12.0, 13.0, 14.0, 15.0, 16.0, 17.0, 18.0, 19.0, 20.0, 21.0, 22.0, 23.0, 24.0}; SumOpDynamicModel m({TensorType_FLOAT32, {4, 3, 2}}, {TensorType_FLOAT32, {3}}, {TensorType_INT32, {2}}, true); std::vector axis = {0, 2}; m.SetAxis(axis); m.SetInput(data); ASSERT_EQ(m.Invoke(), kTfLiteOk); EXPECT_THAT(m.GetOutputShape(), ElementsAreArray({1, 3, 1})); EXPECT_THAT(m.GetOutput(), ElementsAreArray(ArrayFloatNear({84, 100, 116}))); } TEST(DynamicFloatSumOpTest, Scale) { std::vector data = {9.527}; SumOpDynamicModel m({TensorType_FLOAT32, {1}}, {TensorType_FLOAT32, {1}}, {TensorType_INT32, {1}}, true); std::vector axis = {0}; m.SetAxis(axis); m.SetInput(data); ASSERT_EQ(m.Invoke(), kTfLiteOk); EXPECT_THAT(m.GetOutputShape(), ElementsAreArray({1})); EXPECT_THAT(m.GetOutput(), ElementsAreArray(ArrayFloatNear({9.527}))); } TEST(ConstUint8SumOpTest, NotKeepDims) { float kQuantizedTolerance = GetTolerance(-1.0, 1.0); std::vector data = {0.4, 0.2, 0.3, 0.4, 0.5, 0.6}; SumOpConstModel 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); ASSERT_EQ(m.Invoke(), kTfLiteOk); EXPECT_THAT(m.GetOutputShape(), ElementsAreArray({1, 2})); EXPECT_THAT( m.GetDequantizedOutput(), // 0.4 + 0.3 + 0.5 = 1.0 (clamped) // 0.2 + 0.4 + 0.6 = 1.0 (clamped) ElementsAreArray(ArrayFloatNear({1.0, 1.0}, kQuantizedTolerance))); } TEST(ConstUint8SumOpTest, NotKeepDimsRescaling) { float kQuantizedTolerance = GetTolerance(0.0, 2.0); std::vector data = {0.4, 0.2, 0.3, 0.4, 0.5, 0.6}; SumOpConstModel m({TensorType_UINT8, {1, 3, 2}, 0.0, 1.0}, {TensorType_UINT8, {2}, 0.0, 2.0}, {1}, {1}, false); m.QuantizeAndPopulate(m.Input(), data); ASSERT_EQ(m.Invoke(), kTfLiteOk); EXPECT_THAT(m.GetOutputShape(), ElementsAreArray({1, 2})); EXPECT_THAT( m.GetDequantizedOutput(), ElementsAreArray(ArrayFloatNear({1.2, 1.2}, kQuantizedTolerance))); } TEST(ConstUint8SumOpTest, OffsetZeroPoint) { float kQuantizedTolerance = GetTolerance(0.0, 2.0); std::vector data = {0.4, 0.2, 0.3, 0.4, 0.5, 0.6, 0.3, 0.1, 0.5, 0.2, 0.4, 0.6}; SumOpConstModel m({TensorType_UINT8, {1, 3, 2, 2}, -0.1, 1.0}, {TensorType_UINT8, {2}, 0.0, 2.0}, {1}, {-1}, false); m.QuantizeAndPopulate(m.Input(), data); ASSERT_EQ(m.Invoke(), kTfLiteOk); EXPECT_THAT(m.GetOutputShape(), ElementsAreArray({1, 3, 2})); EXPECT_THAT(m.GetDequantizedOutput(), ElementsAreArray(ArrayFloatNear( { 0.6, 0.7, 1.1, 0.4, 0.7, 1.0, }, kQuantizedTolerance))); } TEST(ConstUint8SumOpTest, KeepDims) { float kQuantizedTolerance = GetTolerance(-1.0, 1.0); std::vector data = {0.4, 0.2, 0.3, 0.4, 0.5, 0.6}; SumOpConstModel m({TensorType_UINT8, {3, 2}, -1.0, 1.0}, {TensorType_UINT8, {3}, -1.0, 1.0}, {1}, {1}, true); m.QuantizeAndPopulate(m.Input(), data); ASSERT_EQ(m.Invoke(), kTfLiteOk); EXPECT_THAT(m.GetOutputShape(), ElementsAreArray({3, 1})); EXPECT_THAT( m.GetDequantizedOutput(), // 0.4 + 0.2 = 0.6 // 0.3 + 0.4 = 0.7 // 0.5 + 0.6 = 1.0 (clamped) ElementsAreArray(ArrayFloatNear({0.6, 0.7, 1.0}, kQuantizedTolerance))); } TEST(DynamicUint8SumOpTest, NotKeepDims) { float kQuantizedTolerance = GetTolerance(-5.0, 2.0); std::vector data = {1.3, -4.8, -3.6, 0.24}; SumOpDynamicModel 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); ASSERT_EQ(m.Invoke(), kTfLiteOk); EXPECT_THAT(m.GetOutputShape(), ElementsAreArray({2})); EXPECT_THAT( m.GetDequantizedOutput(), // 1.3 + -4.8 = -3.5 // -3.6 + 0.24 = -3.36 ElementsAreArray(ArrayFloatNear({-3.5, -3.36}, kQuantizedTolerance))); } TEST(DynamicUint8SumOpTest, KeepDims) { float kQuantizedTolerance = GetTolerance(-10.0, 12.0); std::vector data = {11.14, -0.14, 7.423, 0.879}; SumOpDynamicModel 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); ASSERT_EQ(m.Invoke(), kTfLiteOk); EXPECT_THAT(m.GetOutputShape(), ElementsAreArray({1, 2})); EXPECT_THAT( m.GetDequantizedOutput(), // 11.14 + 7.423 = 12.0 (clamped) // -0.14 + 0.879 = 0.739 ElementsAreArray(ArrayFloatNear({12.0, 0.739}, kQuantizedTolerance))); } TEST(ConstInt8SumOpTest, Rescale) { const std::vector data = {0.4, 0.2, 0.3, 0.4, 0.5, 0.3}; SumOpConstModel m({TensorType_INT8, {1, 3, 2}, -1.0, 1.0}, {TensorType_INT8, {2}, -5.0, 5.0}, {1}, {1}, false); // Expect the sum to be 0.4 + 0.3 + 0.5 = 1.2 and 0.2 + 0.4 + 0.3 = 0.9. const std::vector expected_sum = {1.2, 0.9}; const float kQuantizedTolerance = GetTolerance(-5.0, 5.0); m.QuantizeAndPopulate(m.Input(), data); ASSERT_EQ(m.Invoke(), kTfLiteOk); EXPECT_THAT(m.GetOutputShape(), ElementsAreArray({1, 2})); EXPECT_THAT( m.GetDequantizedOutput(), ElementsAreArray(ArrayFloatNear(expected_sum, kQuantizedTolerance))); } TEST(ConstInt16SumOpTest, Rescale) { const std::vector data = {0.4, 0.2, 0.3, 0.4, 0.5, 0.3}; BaseConstOpModel m( {TensorType_INT16, {1, 3, 2}, -1.0, 1.0}, {TensorType_INT16, {2}, -2.0, 2.0}, {1}, {1}, false); // Expect the sum to be 0.4 + 0.3 + 0.5 = 1.2 and 0.2 + 0.4 + 0.3 = 0.9. const std::vector expected_sum = {1.2, 0.9}; const float kQuantizedTolerance = GetTolerance(-5.0, 5.0); m.QuantizeAndPopulate(m.Input(), data); ASSERT_EQ(m.Invoke(), kTfLiteOk); EXPECT_THAT(m.GetOutputShape(), ElementsAreArray({1, 2})); EXPECT_THAT( m.GetDequantizedOutput(), ElementsAreArray(ArrayFloatNear(expected_sum, kQuantizedTolerance))); } // Tests for reduce_prod TEST(FullyConstFloatProdOpTest, SmallInput) { const std::vector data = {2, 3, 4}; ProdOpFullyConstModel m({TensorType_INT32, {3}}, data, {TensorType_INT32, {1}}, {1}, {0}, false); ASSERT_EQ(m.Invoke(), kTfLiteOk); EXPECT_THAT(m.GetOutput(), ElementsAreArray({24})); EXPECT_EQ(m.GetOutputTensor(0)->allocation_type, kTfLitePersistentRo); } TEST(FullyConstFloatProdOpTest, LargeInput) { const std::vector data = {1, 2, 3, 4, 5, 6, 7, 8, 9}; ProdOpFullyConstModel m({TensorType_INT32, {9}}, data, {TensorType_INT32, {1}}, {1}, {0}, false); ASSERT_EQ(m.Invoke(), kTfLiteOk); EXPECT_THAT(m.GetOutput(), ElementsAreArray({362880})); EXPECT_EQ(m.GetOutputTensor(0)->allocation_type, kTfLitePersistentRo); } TEST(ConstFloatProdOpTest, AllInputsAreConstantLargeOutput) { const std::vector data = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18}; ProdOpFullyConstModel m({TensorType_INT32, {2, 1, 3, 3}}, data, {TensorType_INT32, {1}}, {1}, {1}, false); ASSERT_EQ(m.Invoke(), kTfLiteOk); EXPECT_THAT(m.GetOutputShape(), ElementsAreArray({2, 3, 3})); EXPECT_THAT(m.GetOutput(), ElementsAreArray(data)); EXPECT_EQ(m.GetOutputTensor(0)->allocation_type, kTfLiteArenaRw); } TEST(ConstFloatProdOpTest, NotKeepDimsLarge) { const std::vector data = { 1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0, 9.0, 10.0, 11.0, 12.0, 13.0, 14.0, 15.0, 16.0, 17.0, 18.0, 19.0, 20.0, 21.0, 22.0, 23.0, 24.0}; ProdOpConstModel m({TensorType_FLOAT32, {4, 3, 2}}, {TensorType_FLOAT32, {2}}, {4}, {1, 0, -3, -3}, false); m.SetInput(data); ASSERT_EQ(m.Invoke(), kTfLiteOk); EXPECT_THAT(m.GetOutputShape(), ElementsAreArray({2})); EXPECT_THAT( m.GetOutput(), ElementsAreArray(ArrayFloatNear({3.162341376e+11, 1.9619905536e+12}))); } template void ConstIntProdOpTestNotKeepDimsLarge() { const float input_min = (tensor_type == TensorType_INT16) ? -24.0 : 0.0; const float input_max = 24.0; const float output_min = (tensor_type == TensorType_INT16) ? -1.9619905536e+12 : 0.0; const float output_max = 1.9619905536e+12; const std::vector data = { 1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0, 9.0, 10.0, 11.0, 12.0, 13.0, 14.0, 15.0, 16.0, 17.0, 18.0, 19.0, 20.0, 21.0, 22.0, 23.0, 24.0}; ProdOpConstModel m({tensor_type, {4, 3, 2}, input_min, input_max}, {tensor_type, {2}, output_min, output_max}, {4}, {1, 0, -3, -3}, false); m.QuantizeAndPopulate(m.Input(), data); ASSERT_EQ(m.Invoke(), kTfLiteOk); const int reduced_axis_size = 12; const float kQuantizedStep = GetTolerance(output_min, output_max); const float kQuantizedTolerance = reduced_axis_size * 2 * kQuantizedStep; EXPECT_THAT(m.GetOutputShape(), ElementsAreArray({2})); EXPECT_THAT(m.GetDequantizedOutput(), ElementsAreArray(ArrayFloatNear( {3.162341376e+11, 1.9619905536e+12}, kQuantizedTolerance))); } template void ConstIntProdOpTestDisContigReduction() { const float input_min = (tensor_type == TensorType_INT16) ? -12.0 : 0.0; const float input_max = 12.0; const float output_min = (tensor_type == TensorType_INT16) ? -57600 : 0.0; const float output_max = 57600; const std::vector data = { 1.0, 2.0, 3.0, 4.0, 8.0, 7.0, 6.0, 5.0, 10.0, 9.0, 11.0, 12.0, 1.0, 2.0, 3.0, 4.0, 8.0, 7.0, 6.0, 5.0, 10.0, 9.0, 11.0, 12.0}; ProdOpConstModel m({tensor_type, {3, 2, 2, 2}, input_min, input_max}, {tensor_type, {2}, output_min, output_max}, {2}, {1, 0}, false); m.QuantizeAndPopulate(m.Input(), data); ASSERT_EQ(m.Invoke(), kTfLiteOk); const int reduced_axis_size = 6; const float kQuantizedStep = GetTolerance(output_min, output_max); const float kQuantizedTolerance = reduced_axis_size * 2 * kQuantizedStep; EXPECT_THAT(m.GetOutputShape(), ElementsAreArray({2, 2})); EXPECT_THAT(m.GetDequantizedOutput(), ElementsAreArray(ArrayFloatNear( {6404.31, 15875.7, 39208.7, 57602.2}, kQuantizedTolerance))); } template void ConstIntProdOpTestContigReduction() { const float input_min = (tensor_type == TensorType_INT16) ? -12.0 : 0.0; const float input_max = 12.0; const float output_min = (tensor_type == TensorType_INT16) ? -11880 : 0.0; const float output_max = 11880; const std::vector data = { 1.0, 8.0, 13.0, 4.0, 8.0, 7.0, 6.0, 5.0, 10.0, 9.0, 11.0, 12.0, 1.0, 6.0, 9.0, 4.0, 8.0, 7.0, 6.0, 5.0, 10.0, 9.0, 11.0, 12.0}; ProdOpConstModel m({tensor_type, {3, 2, 2, 2}, input_min, input_max}, {tensor_type, {2}, output_min, output_max}, {2}, {2, 3}, false); m.QuantizeAndPopulate(m.Input(), data); ASSERT_EQ(m.Invoke(), kTfLiteOk); const int reduced_axis_size = 4; const float kQuantizedStep = GetTolerance(output_min, output_max); const float kQuantizedTolerance = reduced_axis_size * 2 * kQuantizedStep; EXPECT_THAT(m.GetOutputShape(), ElementsAreArray({3, 2})); EXPECT_THAT(m.GetDequantizedOutput(), ElementsAreArray(ArrayFloatNear( {383.951, 1680.1, 11879.3, 216.086, 1680.1, 11879.3}, kQuantizedTolerance))); } TEST(ConstInt8ProdOpTest, NotKeepDimsLarge) { ConstIntProdOpTestNotKeepDimsLarge(); } TEST(ConstInt16ProdOpTest, NotKeepDimsLarge) { ConstIntProdOpTestNotKeepDimsLarge(); } TEST(ConstInt8ProdOpTest, DisContigProdOpTest) { ConstIntProdOpTestDisContigReduction(); } TEST(ConstInt16ProdOpTest, DisContigProdOpTest) { ConstIntProdOpTestDisContigReduction(); } TEST(ConstInt8ProdOpTest, ContigProdOpTest) { ConstIntProdOpTestContigReduction(); } TEST(ConstInt16ProdOpTest, ContigProdOpTest) { ConstIntProdOpTestContigReduction(); } TEST(ConstFloatProdOpTest, NotKeepDimsSmall) { const std::vector data = { -1.3, -1.2, -1.1, -1.0, -0.9, -0.8, -0.7, -0.6, -0.5, -0.4, -0.3, -0.2, -0.2, 0.3, 0.4, 0.5, 0.6, 0.7, 0.8, 0.9, 1.0, 1.1, 1.2, 1.3}; ProdOpConstModel m({TensorType_FLOAT32, {4, 3, 2}}, {TensorType_FLOAT32, {2}}, {4}, {1, 0, -3, -3}, false); m.SetInput(data); ASSERT_EQ(m.Invoke(), kTfLiteOk); EXPECT_THAT(m.GetOutputShape(), ElementsAreArray({2})); EXPECT_THAT(m.GetOutput(), ElementsAreArray(ArrayFloatNear({-0.0062270208, 0.0062270208}))); } template void ConstIntProdOpTestNotKeepDimsSmall() { const std::vector data = { -1.3, -1.2, -1.1, -1.0, -0.9, -0.8, -0.7, -0.6, -0.5, -0.4, -0.3, -0.2, -0.2, 0.3, 0.4, 0.5, 0.6, 0.7, 0.8, 0.9, 1.0, 1.1, 1.2, 1.3}; ProdOpConstModel m({tensor_type, {4, 3, 2}, -1.3, 1.3}, {tensor_type, {2}, -0.0062270208, 0.0062270208}, {4}, {1, 0, -3, -3}, false); m.QuantizeAndPopulate(m.Input(), data); ASSERT_EQ(m.Invoke(), kTfLiteOk); const int reduced_axis_size = 12; const float kQuantizedStep = GetTolerance(-0.0062270208, 0.0062270208); const float kQuantizedTolerance = reduced_axis_size * 2 * kQuantizedStep; EXPECT_THAT(m.GetOutputShape(), ElementsAreArray({2})); EXPECT_THAT(m.GetDequantizedOutput(), ElementsAreArray(ArrayFloatNear({-0.0062270208, 0.0062270208}, kQuantizedTolerance))); } TEST(ConstInt8ProdOpTest, NotKeepDimsSmall) { ConstIntProdOpTestNotKeepDimsSmall(); } TEST(ConstInt16ProdOpTest, NotKeepDimsSmall) { ConstIntProdOpTestNotKeepDimsSmall(); } TEST(ConstFloatProdOpTest, KeepDims) { std::vector data = {1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0, 9.0, 10.0, 11.0, 12.0, 13.0, 14.0, 15.0, 16.0, 17.0, 18.0, 19.0, 20.0, 21.0, 22.0, 23.0, 24.0}; ProdOpConstModel m({TensorType_FLOAT32, {4, 3, 2}}, {TensorType_FLOAT32, {3}}, {2}, {0, 2}, true); m.SetInput(data); ASSERT_EQ(m.Invoke(), kTfLiteOk); EXPECT_THAT(m.GetOutputShape(), ElementsAreArray({1, 3, 1})); EXPECT_THAT(m.GetOutput(), ElementsAreArray( ArrayFloatNear({7.74592e+06, 1.197504e+08, 6.6889152e+08}))); } TEST(ConstFloatProdOpTest, ZeroInputDim) { if (SingleOpModel::GetForceUseNnapi()) { return; } ProdOpConstModel m({TensorType_FLOAT32, {4, 0, 2}}, {TensorType_FLOAT32, {3}}, {2}, {0, 2}, true); ASSERT_EQ(m.Invoke(), kTfLiteOk); EXPECT_THAT(m.GetOutputShape(), ElementsAreArray({1, 0, 1})); } TEST(ConstInt8ProdOpTest, ZeroInputDim) { if (SingleOpModel::GetForceUseNnapi()) { return; } ProdOpConstModel m({TensorType_INT8, {4, 0, 2}, 0.0, 1.0}, {TensorType_INT8, {3}, 0.0, 1.0}, {2}, {0, 2}, true); ASSERT_EQ(m.Invoke(), kTfLiteOk); EXPECT_THAT(m.GetOutputShape(), ElementsAreArray({1, 0, 1})); } TEST(DynamicFloatProdOpTest, NotKeepDims) { std::vector data = {1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0, 9.0, 10.0, 11.0, 12.0, 13.0, 14.0, 15.0, 16.0, 17.0, 18.0, 19.0, 20.0, 21.0, 22.0, 23.0, 24.0}; ProdOpDynamicModel m({TensorType_FLOAT32, {4, 3, 2}}, {TensorType_FLOAT32, {2}}, {TensorType_INT32, {4}}, false); std::vector axis = {1, 0, -3, -3}; m.SetAxis(axis); m.SetInput(data); ASSERT_EQ(m.Invoke(), kTfLiteOk); EXPECT_THAT(m.GetOutputShape(), ElementsAreArray({2})); EXPECT_THAT( m.GetOutput(), ElementsAreArray(ArrayFloatNear({3.16234143225e+11, 1.9619905536e+12}))); } TEST(DynamicFloatProdOpTest, KeepDims) { std::vector data = {1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0, 9.0, 10.0, 11.0, 12.0, 13.0, 14.0, 15.0, 16.0, 17.0, 18.0, 19.0, 20.0, 21.0, 22.0, 23.0, 24.0}; ProdOpDynamicModel m({TensorType_FLOAT32, {4, 3, 2}}, {TensorType_FLOAT32, {3}}, {TensorType_INT32, {2}}, true); std::vector axis = {0, 2}; m.SetAxis(axis); m.SetInput(data); ASSERT_EQ(m.Invoke(), kTfLiteOk); EXPECT_THAT(m.GetOutputShape(), ElementsAreArray({1, 3, 1})); EXPECT_THAT(m.GetOutput(), ElementsAreArray( ArrayFloatNear({7.74592e+06, 1.197504e+08, 6.6889152e+08}))); } template void DynamicIntProdOpTestKeepDims() { const float input_min = (tensor_type == TensorType_INT16) ? -24.0 : 0.0; const float input_max = 24.0; const float output_min = (tensor_type == TensorType_INT16) ? -6.6889152e+08 : 0.0; const float output_max = 6.6889152e+08; const std::vector data = { 1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0, 9.0, 10.0, 11.0, 12.0, 13.0, 14.0, 15.0, 16.0, 17.0, 18.0, 19.0, 20.0, 21.0, 22.0, 23.0, 24.0}; ProdOpDynamicModel m({tensor_type, {4, 3, 2}, input_min, input_max}, {tensor_type, {3}, output_min, output_max}, {TensorType_INT32, {2}}, true); std::vector axis = {0, 2}; m.SetAxis(axis); m.QuantizeAndPopulate(m.Input(), data); ASSERT_EQ(m.Invoke(), kTfLiteOk); const int reduced_axis_size = 8; const float kQuantizedStep = GetTolerance(output_min, output_max); const float kQuantizedTolerance = reduced_axis_size * 2 * kQuantizedStep; EXPECT_THAT(m.GetOutputShape(), ElementsAreArray({1, 3, 1})); EXPECT_THAT( m.GetDequantizedOutput(), ElementsAreArray(ArrayFloatNear( {7.74592e+06, 1.197504e+08, 6.6889152e+08}, kQuantizedTolerance))); } TEST(DynamicInt8ProdOpTest, KeepDims) { DynamicIntProdOpTestKeepDims(); } TEST(DynamicInt16ProdOpTest, KeepDims) { DynamicIntProdOpTestKeepDims(); } TEST(DynamicFloatProdOpTest, Scale) { std::vector data = {9.527}; ProdOpDynamicModel m({TensorType_FLOAT32, {1}}, {TensorType_FLOAT32, {1}}, {TensorType_INT32, {1}}, true); std::vector axis = {0}; m.SetAxis(axis); m.SetInput(data); ASSERT_EQ(m.Invoke(), kTfLiteOk); EXPECT_THAT(m.GetOutputShape(), ElementsAreArray({1})); EXPECT_THAT(m.GetOutput(), ElementsAreArray(ArrayFloatNear({9.527}))); } // Tests for reduce_max TEST(ConstFloatMaxOpTest, NotKeepDims) { std::vector data = {1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0, 9.0, 10.0, 11.0, 12.0, 13.0, 14.0, 15.0, 16.0, 17.0, 18.0, 19.0, 20.0, 21.0, 22.0, 23.0, 24.0}; MaxOpConstModel m({TensorType_FLOAT32, {4, 3, 2}}, {TensorType_FLOAT32, {2}}, {4}, {1, 0, -3, -3}, false); m.SetInput(data); ASSERT_EQ(m.Invoke(), kTfLiteOk); EXPECT_THAT(m.GetOutputShape(), ElementsAreArray({2})); EXPECT_THAT(m.GetOutput(), ElementsAreArray(ArrayFloatNear({23, 24}))); } TEST(ConstFloatMaxOpTest, KeepDims) { std::vector data = {1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0, 9.0, 10.0, 11.0, 12.0, 13.0, 14.0, 15.0, 16.0, 17.0, 18.0, 19.0, 20.0, 21.0, 22.0, 23.0, 24.0}; MaxOpConstModel m({TensorType_FLOAT32, {4, 3, 2}}, {TensorType_FLOAT32, {3}}, {2}, {0, 2}, true); m.SetInput(data); ASSERT_EQ(m.Invoke(), kTfLiteOk); EXPECT_THAT(m.GetOutputShape(), ElementsAreArray({1, 3, 1})); EXPECT_THAT(m.GetOutput(), ElementsAreArray(ArrayFloatNear({20, 22, 24}))); } TEST(ConstFloatMaxOpTest, ZeroInputDim) { if (SingleOpModel::GetForceUseNnapi()) { return; } MaxOpConstModel m({TensorType_FLOAT32, {4, 0, 2}}, {TensorType_FLOAT32, {3}}, {2}, {0, 2}, true); ASSERT_EQ(m.Invoke(), kTfLiteOk); EXPECT_THAT(m.GetOutputShape(), ElementsAreArray({1, 0, 1})); } TEST(DynamicFloatMaxOpTest, NotKeepDims) { std::vector data = {1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0, 9.0, 10.0, 11.0, 12.0, 13.0, 14.0, 15.0, 16.0, 17.0, 18.0, 19.0, 20.0, 21.0, 22.0, 23.0, 24.0}; MaxOpDynamicModel m({TensorType_FLOAT32, {4, 3, 2}}, {TensorType_FLOAT32, {2}}, {TensorType_INT32, {4}}, false); std::vector axis = {1, 0, -3, -3}; m.SetAxis(axis); m.SetInput(data); ASSERT_EQ(m.Invoke(), kTfLiteOk); EXPECT_THAT(m.GetOutputShape(), ElementsAreArray({2})); EXPECT_THAT(m.GetOutput(), ElementsAreArray(ArrayFloatNear({23, 24}))); } TEST(DynamicFloatMaxOpTest, KeepDims) { std::vector data = {1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0, 9.0, 10.0, 11.0, 12.0, 13.0, 14.0, 15.0, 16.0, 17.0, 18.0, 19.0, 20.0, 21.0, 22.0, 23.0, 24.0}; MaxOpDynamicModel m({TensorType_FLOAT32, {4, 3, 2}}, {TensorType_FLOAT32, {3}}, {TensorType_INT32, {2}}, true); std::vector axis = {0, 2}; m.SetAxis(axis); m.SetInput(data); ASSERT_EQ(m.Invoke(), kTfLiteOk); EXPECT_THAT(m.GetOutputShape(), ElementsAreArray({1, 3, 1})); EXPECT_THAT(m.GetOutput(), ElementsAreArray(ArrayFloatNear({20, 22, 24}))); } TEST(DynamicFloatMaxOpTest, Scale) { std::vector data = {9.527}; MaxOpDynamicModel m({TensorType_FLOAT32, {1}}, {TensorType_FLOAT32, {1}}, {TensorType_INT32, {1}}, true); std::vector axis = {0}; m.SetAxis(axis); m.SetInput(data); ASSERT_EQ(m.Invoke(), kTfLiteOk); EXPECT_THAT(m.GetOutputShape(), ElementsAreArray({1})); EXPECT_THAT(m.GetOutput(), ElementsAreArray(ArrayFloatNear({9.527}))); } 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({tensor_type, {1, 3, 2}, 1.0f * kMin, 1.0f * kMax}, {tensor_type, {2}, 1.0f * kMin, 1.0f * kMax}, {1}, {1}, false); m.QuantizeAndPopulate(m.Input(), data); ASSERT_EQ(m.Invoke(), kTfLiteOk); EXPECT_THAT(m.GetOutputShape(), ElementsAreArray({1, 2})); EXPECT_THAT( m.GetDequantizedOutput(), ElementsAreArray(ArrayFloatNear({0.5, 0.6}, kQuantizedTolerance))); } TEST(ConstUint8MaxOpTest, NotKeepDims) { ConstMaxOpTestNotKeepDims(); } TEST(ConstInt8MaxOpTest, NotKeepDims) { 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({tensor_type, {3, 2}, 1.0f * kMin, 1.0f * kMax}, {tensor_type, {3}, 1.0f * kMin, 1.0f * kMax}, {1}, {1}, true); m.QuantizeAndPopulate(m.Input(), data); ASSERT_EQ(m.Invoke(), kTfLiteOk); EXPECT_THAT(m.GetOutputShape(), ElementsAreArray({3, 1})); EXPECT_THAT( m.GetDequantizedOutput(), ElementsAreArray(ArrayFloatNear({0.4, 0.4, 0.6}, kQuantizedTolerance))); } TEST(ConstUint8MaxOpTest, KeepDims) { ConstMaxOpTestKeepDims(); } TEST(ConstInt8MaxOpTest, KeepDims) { 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.0f * kMin, 5.0f * kMax}, {tensor_type, {2}, 5.0f * kMin, 5.0f * kMax}, {TensorType_INT32, {1}}, false); std::vector axis = {1}; m.SetAxis(axis); m.QuantizeAndPopulate(m.Input(), data); ASSERT_EQ(m.Invoke(), kTfLiteOk); EXPECT_THAT(m.GetOutputShape(), ElementsAreArray({2})); EXPECT_THAT( m.GetDequantizedOutput(), ElementsAreArray(ArrayFloatNear({1.3, 0.24}, kQuantizedTolerance))); } TEST(DynamicUint8MaxOpTest, NotKeepDims) { DynamicMaxOpTestNotKeepDims(); } TEST(DynamicInt8MaxOpTest, NotKeepDims) { 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.0f * kMin, 12.0f * kMax}, {tensor_type, {2}, 12.0f * kMin, 12.0f * kMax}, {TensorType_INT32, {1}}, true); std::vector axis = {0}; m.SetAxis(axis); m.QuantizeAndPopulate(m.Input(), data); ASSERT_EQ(m.Invoke(), kTfLiteOk); EXPECT_THAT(m.GetOutputShape(), ElementsAreArray({1, 2})); EXPECT_THAT( m.GetDequantizedOutput(), ElementsAreArray(ArrayFloatNear({11.14, 0.879}, kQuantizedTolerance))); } TEST(DynamicUint8MaxOpTest, KeepDims) { DynamicMaxOpTestKeepDims(); } TEST(DynamicInt8MaxOpTest, KeepDims) { 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.0f * kMin, 12.0f * kMax}, {tensor_type, {}, 12.0f * kMin, 12.0f * kMax}, {TensorType_INT32, {1}}, true); std::vector axis = {0}; m.QuantizeAndPopulate(m.Input(), data); ASSERT_EQ(m.Invoke(), kTfLiteOk); EXPECT_THAT(m.GetOutputShape(), IsEmpty()); EXPECT_THAT(m.GetDequantizedOutput(), ElementsAreArray(ArrayFloatNear({11.14}, kQuantizedTolerance))); } TEST(DynamicUint8MaxOpTest, Scalar) { DynamicMaxOpTestScalar(); } TEST(DynamicInt8MaxOpTest, Scalar) { DynamicMaxOpTestScalar(); } TEST(DynamicInt16MaxOpTest, Scalar) { DynamicMaxOpTestScalar(); } // Tests for reduce_min TEST(ConstFloatMinOpTest, DiscontiguousReduction) { int count = 3 * 3 * 2 * 4; std::vector data(count); std::iota(data.begin(), data.end(), 0); MinOpConstModel m({TensorType_FLOAT32, {3, 3, 2, 4}}, {TensorType_FLOAT32, {4}}, {1}, {1}, true); m.SetInput(data); ASSERT_EQ(m.Invoke(), kTfLiteOk); EXPECT_THAT(m.GetOutputShape(), ElementsAreArray({3, 1, 2, 4})); EXPECT_THAT(m.GetOutput(), ElementsAreArray(ArrayFloatNear( {0, 1, 2, 3, 4, 5, 6, 7, 24, 25, 26, 27, 28, 29, 30, 31, 48, 49, 50, 51, 52, 53, 54, 55}))); } TEST(ConstFloatMinOpTest, NotKeepDims) { std::vector data = {1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0, 9.0, 10.0, 11.0, 12.0, 13.0, 14.0, 15.0, 16.0, 17.0, 18.0, 19.0, 20.0, 21.0, 22.0, 23.0, 24.0}; MinOpConstModel m({TensorType_FLOAT32, {4, 3, 2}}, {TensorType_FLOAT32, {2}}, {4}, {1, 0, -3, -3}, false); m.SetInput(data); ASSERT_EQ(m.Invoke(), kTfLiteOk); EXPECT_THAT(m.GetOutputShape(), ElementsAreArray({2})); EXPECT_THAT(m.GetOutput(), ElementsAreArray(ArrayFloatNear({1, 2}))); } TEST(ConstFloatMinOpTest, KeepDims) { std::vector data = {1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0, 9.0, 10.0, 11.0, 12.0, 13.0, 14.0, 15.0, 16.0, 17.0, 18.0, 19.0, 20.0, 21.0, 22.0, 23.0, 24.0}; MinOpConstModel m({TensorType_FLOAT32, {4, 3, 2}}, {TensorType_FLOAT32, {3}}, {2}, {0, 2}, true); m.SetInput(data); ASSERT_EQ(m.Invoke(), kTfLiteOk); EXPECT_THAT(m.GetOutputShape(), ElementsAreArray({1, 3, 1})); EXPECT_THAT(m.GetOutput(), ElementsAreArray(ArrayFloatNear({1, 3, 5}))); } TEST(ConstFloatMinOpTest, ZeroInputDim) { if (SingleOpModel::GetForceUseNnapi()) { return; } MinOpConstModel m({TensorType_FLOAT32, {4, 0, 2}}, {TensorType_FLOAT32, {3}}, {2}, {0, 2}, true); ASSERT_EQ(m.Invoke(), kTfLiteOk); EXPECT_THAT(m.GetOutputShape(), ElementsAreArray({1, 0, 1})); } TEST(DynamicFloatMinOpTest, NotKeepDims) { std::vector data = {1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0, 9.0, 10.0, 11.0, 12.0, 13.0, 14.0, 15.0, 16.0, 17.0, 18.0, 19.0, 20.0, 21.0, 22.0, 23.0, 24.0}; MinOpDynamicModel m({TensorType_FLOAT32, {4, 3, 2}}, {TensorType_FLOAT32, {2}}, {TensorType_INT32, {4}}, false); std::vector axis = {1, 0, -3, -3}; m.SetAxis(axis); m.SetInput(data); ASSERT_EQ(m.Invoke(), kTfLiteOk); EXPECT_THAT(m.GetOutputShape(), ElementsAreArray({2})); EXPECT_THAT(m.GetOutput(), ElementsAreArray(ArrayFloatNear({1, 2}))); } TEST(DynamicFloatMinOpTest, KeepDims) { std::vector data = {1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0, 9.0, 10.0, 11.0, 12.0, 13.0, 14.0, 15.0, 16.0, 17.0, 18.0, 19.0, 20.0, 21.0, 22.0, 23.0, 24.0}; MinOpDynamicModel m({TensorType_FLOAT32, {4, 3, 2}}, {TensorType_FLOAT32, {3}}, {TensorType_INT32, {2}}, true); std::vector axis = {0, 2}; m.SetAxis(axis); m.SetInput(data); ASSERT_EQ(m.Invoke(), kTfLiteOk); EXPECT_THAT(m.GetOutputShape(), ElementsAreArray({1, 3, 1})); EXPECT_THAT(m.GetOutput(), ElementsAreArray(ArrayFloatNear({1, 3, 5}))); } TEST(DynamicFloatMinOpTest, Scalar) { std::vector data = {9.527}; MinOpDynamicModel m({TensorType_FLOAT32, {1}}, {TensorType_FLOAT32, {1}}, {TensorType_INT32, {1}}, true); std::vector axis = {0}; m.SetAxis(axis); m.SetInput(data); ASSERT_EQ(m.Invoke(), kTfLiteOk); EXPECT_THAT(m.GetOutputShape(), ElementsAreArray({1})); EXPECT_THAT(m.GetOutput(), ElementsAreArray(ArrayFloatNear({9.527}))); } 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({tensor_type, {1, 3, 2}, 1.0f * kMin, 1.0f * kMax}, {tensor_type, {2}, 1.0f * kMin, 1.0f * kMax}, {1}, {1}, false); m.QuantizeAndPopulate(m.Input(), data); ASSERT_EQ(m.Invoke(), kTfLiteOk); EXPECT_THAT(m.GetOutputShape(), ElementsAreArray({1, 2})); EXPECT_THAT( m.GetDequantizedOutput(), ElementsAreArray(ArrayFloatNear({0.3, 0.2}, kQuantizedTolerance))); } TEST(ConstUint8MinOpTest, NotKeepDims) { ConstMinOpTestNotKeepDims(); } TEST(ConstInt8MinOpTest, NotKeepDims) { 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({tensor_type, {3, 2}, 1.0f * kMin, 1.0f * kMax}, {tensor_type, {3}, 1.0f * kMin, 1.0f * kMax}, {1}, {1}, true); m.QuantizeAndPopulate(m.Input(), data); ASSERT_EQ(m.Invoke(), kTfLiteOk); EXPECT_THAT(m.GetOutputShape(), ElementsAreArray({3, 1})); EXPECT_THAT( m.GetDequantizedOutput(), ElementsAreArray(ArrayFloatNear({0.2, 0.3, 0.5}, kQuantizedTolerance))); } TEST(ConstUint8MinOpTest, KeepDims) { ConstMinOpTestKeepDims(); } TEST(ConstInt8MinOpTest, KeepDims) { 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.0f * kMin, 5.0f * kMax}, {tensor_type, {2}, 5.0f * kMin, 5.0f * kMax}, {TensorType_INT32, {1}}, false); std::vector axis = {1}; m.SetAxis(axis); m.QuantizeAndPopulate(m.Input(), data); ASSERT_EQ(m.Invoke(), kTfLiteOk); EXPECT_THAT(m.GetOutputShape(), ElementsAreArray({2})); EXPECT_THAT( m.GetDequantizedOutput(), ElementsAreArray(ArrayFloatNear({-4.8, -3.6}, kQuantizedTolerance))); } TEST(DynamicUint8MinOpTest, NotKeepDims) { DynamicMinOpTestNotKeepDims(); } TEST(DynamicInt8MinOpTest, NotKeepDims) { 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.0f * kMin, 12.0f * kMax}, {tensor_type, {2}, 12.0f * kMin, 12.0f * kMax}, {TensorType_INT32, {1}}, true); std::vector axis = {0}; m.SetAxis(axis); m.QuantizeAndPopulate(m.Input(), data); ASSERT_EQ(m.Invoke(), kTfLiteOk); EXPECT_THAT(m.GetOutputShape(), ElementsAreArray({1, 2})); EXPECT_THAT( m.GetDequantizedOutput(), ElementsAreArray(ArrayFloatNear({7.423, -0.14}, kQuantizedTolerance))); } TEST(DynamicUint8MinOpTest, KeepDims) { DynamicMinOpTestKeepDims(); } TEST(DynamicInt8MinOpTest, KeepDims) { 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.0f * kMin, 12.0f * kMax}, {tensor_type, {}, 12.0f * kMin, 12.0f * kMax}, {TensorType_INT32, {1}}, true); std::vector axis = {0}; m.QuantizeAndPopulate(m.Input(), data); ASSERT_EQ(m.Invoke(), kTfLiteOk); EXPECT_THAT(m.GetOutputShape(), IsEmpty()); EXPECT_THAT(m.GetDequantizedOutput(), ElementsAreArray(ArrayFloatNear({11.14}, kQuantizedTolerance))); } TEST(DynamicUint8MinOpTest, Scalar) { DynamicMinOpTestScalar(); } TEST(DynamicInt8MinOpTest, Scalar) { DynamicMinOpTestScalar(); } TEST(DynamicInt16MinOpTest, Scalar) { DynamicMinOpTestScalar(); } // Tests for reduce_any TEST(ConstAnyOpTest, NotKeepDims) { std::vector data = {false, false, false, false, false, false, false, true, false, false, false, true}; AnyOpConstModel m({TensorType_BOOL, {2, 3, 2}}, {TensorType_BOOL, {2}}, {4}, {1, 0, -3, -3}, false); m.SetInput(data); ASSERT_EQ(m.Invoke(), kTfLiteOk); EXPECT_THAT(m.GetOutputShape(), ElementsAreArray({2})); EXPECT_THAT(m.GetOutput(), ElementsAreArray({false, true})); } TEST(ConstAnyOpTest, KeepDims) { std::vector data = {false, false, false, false, false, false, false, true, false, false, false, true}; AnyOpConstModel m({TensorType_BOOL, {2, 3, 2}}, {TensorType_BOOL, {3}}, {2}, {0, 2}, true); m.SetInput(data); ASSERT_EQ(m.Invoke(), kTfLiteOk); EXPECT_THAT(m.GetOutputShape(), ElementsAreArray({1, 3, 1})); EXPECT_THAT(m.GetOutput(), ElementsAreArray({true, false, true})); } TEST(ConstAnyOpTest, ZeroInputDim) { if (SingleOpModel::GetForceUseNnapi()) { return; } AnyOpConstModel m({TensorType_BOOL, {2, 0, 2}}, {TensorType_BOOL, {3}}, {2}, {0, 2}, true); ASSERT_EQ(m.Invoke(), kTfLiteOk); EXPECT_THAT(m.GetOutputShape(), ElementsAreArray({1, 0, 1})); } TEST(DynamicAnyOpTest, NotKeepDims) { std::vector data = {false, false, false, false, false, false, false, true, false, false, false, true}; AnyOpDynamicModel m({TensorType_BOOL, {2, 3, 2}}, {TensorType_BOOL, {2}}, {TensorType_INT32, {4}}, false); std::vector axis = {1, 0, -3, -3}; m.SetAxis(axis); m.SetInput(data); ASSERT_EQ(m.Invoke(), kTfLiteOk); EXPECT_THAT(m.GetOutputShape(), ElementsAreArray({2})); EXPECT_THAT(m.GetOutput(), ElementsAreArray({false, true})); } TEST(DynamicAnyOpTest, KeepDims) { std::vector data = {false, false, false, false, false, false, false, true, false, false, false, true}; AnyOpDynamicModel m({TensorType_BOOL, {2, 3, 2}}, {TensorType_BOOL, {3}}, {TensorType_INT32, {2}}, true); std::vector axis = {0, 2}; m.SetAxis(axis); m.SetInput(data); ASSERT_EQ(m.Invoke(), kTfLiteOk); EXPECT_THAT(m.GetOutputShape(), ElementsAreArray({1, 3, 1})); EXPECT_THAT(m.GetOutput(), ElementsAreArray({true, false, true})); } TEST(DynamicAnyOpTest, Scalar) { std::vector data = {false}; AnyOpDynamicModel m({TensorType_BOOL, {1}}, {TensorType_BOOL, {1}}, {TensorType_INT32, {1}}, true); std::vector axis = {0}; m.SetAxis(axis); m.SetInput(data); ASSERT_EQ(m.Invoke(), kTfLiteOk); EXPECT_THAT(m.GetOutputShape(), ElementsAreArray({1})); EXPECT_THAT(m.GetOutput(), ElementsAreArray({false})); } // Tests for reduce_all TEST(ConstAllOpTest, NotKeepDims) { std::vector data = {true, true, true, true, true, false, true, true, true, true, true, true}; AllOpConstModel m({TensorType_BOOL, {2, 3, 2}}, {TensorType_BOOL, {2}}, {4}, {1, 0, -3, -3}, false); m.SetInput(data); ASSERT_EQ(m.Invoke(), kTfLiteOk); EXPECT_THAT(m.GetOutputShape(), ElementsAreArray({2})); EXPECT_THAT(m.GetOutput(), ElementsAreArray({true, false})); } TEST(ConstAllOpTest, KeepDims) { std::vector data = {true, true, true, true, true, false, true, true, true, true, true, true}; AllOpConstModel m({TensorType_BOOL, {2, 3, 2}}, {TensorType_BOOL, {3}}, {2}, {0, 2}, true); m.SetInput(data); ASSERT_EQ(m.Invoke(), kTfLiteOk); EXPECT_THAT(m.GetOutputShape(), ElementsAreArray({1, 3, 1})); EXPECT_THAT(m.GetOutput(), ElementsAreArray({true, true, false})); } TEST(ConstAllOpTest, ZeroInputDim) { if (SingleOpModel::GetForceUseNnapi()) { return; } AllOpConstModel m({TensorType_BOOL, {2, 0, 2}}, {TensorType_BOOL, {3}}, {2}, {0, 2}, true); ASSERT_EQ(m.Invoke(), kTfLiteOk); EXPECT_THAT(m.GetOutputShape(), ElementsAreArray({1, 0, 1})); } TEST(DynamicAllOpTest, NotKeepDims) { std::vector data = {true, true, true, true, true, false, true, true, true, true, true, true}; AllOpDynamicModel m({TensorType_BOOL, {2, 3, 2}}, {TensorType_BOOL, {2}}, {TensorType_INT32, {4}}, false); std::vector axis = {1, 0, -3, -3}; m.SetAxis(axis); m.SetInput(data); ASSERT_EQ(m.Invoke(), kTfLiteOk); EXPECT_THAT(m.GetOutputShape(), ElementsAreArray({2})); EXPECT_THAT(m.GetOutput(), ElementsAreArray({true, false})); } TEST(DynamicAllOpTest, KeepDims) { std::vector data = {true, true, true, true, true, false, true, true, true, true, true, true}; AllOpDynamicModel m({TensorType_BOOL, {2, 3, 2}}, {TensorType_BOOL, {3}}, {TensorType_INT32, {2}}, true); std::vector axis = {0, 2}; m.SetAxis(axis); m.SetInput(data); ASSERT_EQ(m.Invoke(), kTfLiteOk); EXPECT_THAT(m.GetOutputShape(), ElementsAreArray({1, 3, 1})); EXPECT_THAT(m.GetOutput(), ElementsAreArray({true, true, false})); } TEST(DynamicAllOpTest, Scalar) { std::vector data = {false}; AllOpDynamicModel m({TensorType_BOOL, {1}}, {TensorType_BOOL, {1}}, {TensorType_INT32, {1}}, true); std::vector axis = {0}; m.SetAxis(axis); m.SetInput(data); ASSERT_EQ(m.Invoke(), kTfLiteOk); EXPECT_THAT(m.GetOutputShape(), ElementsAreArray({1})); EXPECT_THAT(m.GetOutput(), ElementsAreArray({false})); } TEST(ConstInt32MinOpTest, EmptyInputButScalarOutput) { MinOpConstModel m({TensorType_INT32, {0}}, {TensorType_INT32, {}}, {1}, {0}, false); ASSERT_EQ(m.Invoke(), kTfLiteOk); EXPECT_THAT(m.GetOutputShape(), IsEmpty()); EXPECT_THAT(m.GetOutput(), ElementsAreArray({2147483647})); } TEST(ConstInt32MaxOpTest, EmptyInputButScalarOutput) { MaxOpConstModel m({TensorType_INT32, {0}}, {TensorType_INT32, {}}, {1}, {0}, false); ASSERT_EQ(m.Invoke(), kTfLiteOk); EXPECT_TRUE(m.GetOutputShape().empty()); EXPECT_THAT(m.GetOutput(), ElementsAreArray({-2147483648})); } TEST(ConstInt32ProdOpTest, EmptyInputButScalarOutput) { ProdOpConstModel m({TensorType_INT32, {0}}, {TensorType_INT32, {}}, {1}, {0}, false); ASSERT_EQ(m.Invoke(), kTfLiteOk); EXPECT_TRUE(m.GetOutputShape().empty()); EXPECT_THAT(m.GetOutput(), ElementsAreArray({1})); } TEST(ConstInt32SumOpTest, EmptyInputButScalarOutput) { SumOpConstModel m({TensorType_INT32, {0}}, {TensorType_INT32, {}}, {1}, {0}, false); ASSERT_EQ(m.Invoke(), kTfLiteOk); EXPECT_TRUE(m.GetOutputShape().empty()); EXPECT_THAT(m.GetOutput(), ElementsAreArray({0})); } TEST(ConstInt32MeanOpTest, EmptyInputButScalarOutput) { MeanOpConstModel m({TensorType_INT32, {0}}, {TensorType_INT32, {}}, {1}, {0}, false); ASSERT_EQ(m.Invoke(), kTfLiteOk); EXPECT_TRUE(m.GetOutputShape().empty()); EXPECT_THAT(m.GetOutput(), ElementsAreArray({std::numeric_limits::quiet_NaN()})); } TEST(ConstFloatMinOpTest, EmptyInputButScalarOutput) { if (SingleOpModel::GetForceUseNnapi()) { return; } MinOpConstModel m({TensorType_FLOAT32, {0}}, {TensorType_FLOAT32, {}}, {1}, {0}, false); ASSERT_EQ(m.Invoke(), kTfLiteOk); EXPECT_TRUE(m.GetOutputShape().empty()); EXPECT_THAT(m.GetOutput(), ElementsAre(testing::Ge(std::numeric_limits::max()))); } TEST(ConstFloatMaxOpTest, EmptyInputButScalarOutput) { if (SingleOpModel::GetForceUseNnapi()) { return; } MaxOpConstModel m({TensorType_FLOAT32, {0}}, {TensorType_FLOAT32, {}}, {1}, {0}, false); ASSERT_EQ(m.Invoke(), kTfLiteOk); EXPECT_TRUE(m.GetOutputShape().empty()); EXPECT_THAT(m.GetOutput(), ElementsAre(testing::Le(-std::numeric_limits::max()))); } TEST(ConstFloatProdOpTest, EmptyInputButScalarOutput) { ProdOpConstModel m({TensorType_FLOAT32, {0}}, {TensorType_FLOAT32, {}}, {1}, {0}, false); ASSERT_EQ(m.Invoke(), kTfLiteOk); EXPECT_TRUE(m.GetOutputShape().empty()); EXPECT_THAT(m.GetOutput(), ElementsAreArray(ArrayFloatNear({1.0}))); } TEST(ConstFloatSumOpTest, EmptyInputButScalarOutput) { SumOpConstModel m({TensorType_FLOAT32, {0}}, {TensorType_FLOAT32, {}}, {1}, {0}, false); ASSERT_EQ(m.Invoke(), kTfLiteOk); EXPECT_TRUE(m.GetOutputShape().empty()); EXPECT_THAT(m.GetOutput(), ElementsAreArray(ArrayFloatNear({0.0}))); } TEST(ConstFloatMeanOpTest, EmptyInputButScalarOutput) { if (SingleOpModel::GetForceUseNnapi()) { return; } MeanOpConstModel m({TensorType_FLOAT32, {0}}, {TensorType_FLOAT32, {}}, {1}, {0}, false); ASSERT_EQ(m.Invoke(), kTfLiteOk); EXPECT_TRUE(m.GetOutputShape().empty()); EXPECT_THAT(m.GetOutput(), ElementsAre(testing::IsNan())); } TEST(ConstAllOpTest, EmptyInputButScalarOutputKeepDim) { AllOpConstModel m({TensorType_BOOL, {0}}, {TensorType_BOOL, {}}, {1}, {0}, true); ASSERT_EQ(m.Invoke(), kTfLiteOk); EXPECT_THAT(m.GetOutputShape(), ElementsAreArray({1})); EXPECT_THAT(m.GetOutput(), ElementsAreArray({true})); } TEST(ConstAnyOpTest, EmptyInputButScalarOutputKeepDim) { if (SingleOpModel::GetForceUseNnapi()) { return; } AnyOpConstModel m({TensorType_BOOL, {0}}, {TensorType_BOOL, {}}, {1}, {0}, true); ASSERT_EQ(m.Invoke(), kTfLiteOk); EXPECT_THAT(m.GetOutputShape(), ElementsAreArray({1})); EXPECT_THAT(m.GetOutput(), ElementsAreArray({false})); } TEST(ConstFloatProdOpTest, EmptyAxis) { const std::vector data = {1.0, 2.0, 3.0, 4.0}; ProdOpConstModel m({TensorType_FLOAT32, {4}}, {TensorType_FLOAT32, {1}}, {TensorType_INT32, {}}, {}, false); m.SetInput(data); EXPECT_EQ(m.Invoke(), kTfLiteOk); } TEST(ConstInt8MeanOpTest, AxisCountExceedsMaxLimitNoCrash) { std::vector data = {1.0, 2.0}; MeanOpConstModel m({TensorType_INT8, {1, 2}, -10.0, 10.0}, {TensorType_INT8, {1}, -10.0, 10.0}, {5}, {0, 0, 0, 0, 0}, false); m.QuantizeAndPopulate(m.Input(), data); EXPECT_EQ(m.Invoke(), kTfLiteOk); } } // namespace } // namespace tflite