/* Copyright 2017 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 "flatbuffers/flatbuffers.h" // from @flatbuffers #include "tensorflow/lite/core/interpreter.h" #include "tensorflow/lite/kernels/test_util.h" #include "tensorflow/lite/schema/schema_generated.h" #include "tensorflow/lite/types/half.h" namespace tflite { namespace { using ::testing::ElementsAreArray; using ::testing::Matcher; template class PadOpModel : public SingleOpModel { public: void SetInput(std::initializer_list data) { PopulateTensor(input_, data); } template void SetQuantizedInput(std::initializer_list data) { QuantizeAndPopulate(input_, data); } template void SetQuantizedPadValue(float data) { QuantizeAndPopulate(constant_values_, {data}); } void SetPaddings(std::initializer_list paddings) { PopulateTensor(paddings_, paddings); } std::vector GetOutput() { return ExtractVector(output_); } std::vector GetOutputShape() { return GetTensorShape(output_); } template std::vector GetDequantizedOutput() { return Dequantize( ExtractVector(output_), GetScale(output_), GetZeroPoint(output_)); } protected: int input_; int output_; int paddings_; int constant_values_; }; // Tests case where paddings is a const tensor. Type T1 is the dtype. Type T2 is // the padding dtype. template class PadV2OpConstModel : public PadOpModel { public: PadV2OpConstModel(const TensorData& input, std::initializer_list paddings_shape, std::initializer_list paddings, T1 constant_values, const TensorData& output) { this->input_ = this->AddInput(input); this->paddings_ = this->AddConstInput(GetTensorType(), paddings, paddings_shape); this->constant_values_ = this->AddConstInput(GetTensorType(), {constant_values}, {1}); this->output_ = this->AddOutput(output); this->SetBuiltinOp(BuiltinOperator_PADV2, BuiltinOptions_PadV2Options, CreatePadV2Options(this->builder_).Union()); this->BuildInterpreter({input.shape}); } PadV2OpConstModel(const TensorData& input, std::initializer_list paddings_shape, std::initializer_list paddings, const TensorData& constant_values, const TensorData& output) { this->input_ = this->AddInput(input); this->paddings_ = this->AddConstInput(GetTensorType(), paddings, paddings_shape); this->constant_values_ = this->AddInput(constant_values); this->output_ = this->AddOutput(output); this->SetBuiltinOp(BuiltinOperator_PADV2, BuiltinOptions_PadV2Options, CreatePadV2Options(this->builder_).Union()); this->BuildInterpreter({input.shape}); } }; // Tests case where paddings is a const tensor. Type T is the padding dtype. // // Example usage is as follows: // PadOpDynamicModel m(input_shape, paddings_shape, paddings_data); // m.SetInput(input_data); // m.Invoke(); template class PadOpConstModel : public PadOpModel { public: PadOpConstModel(const TensorData& input, std::initializer_list paddings_shape, std::initializer_list paddings, const TensorData& output) { this->input_ = this->AddInput(input); this->paddings_ = this->AddConstInput(GetTensorType(), paddings, paddings_shape); this->constant_values_ = this->AddNullInput(); this->output_ = this->AddOutput(output); this->SetBuiltinOp(BuiltinOperator_PAD, BuiltinOptions_PadOptions, CreatePadOptions(this->builder_).Union()); this->BuildInterpreter({input.shape}); } }; // Test case where paddings is a non-const tensor. template class PadV2OpDynamicModel : public PadOpModel { public: PadV2OpDynamicModel(const TensorData& input, std::initializer_list paddings_shape, RegularInputOutput constant_values, const TensorData& output) { this->input_ = this->AddInput(input); this->paddings_ = this->AddInput(GetTensorType()); this->constant_values_ = this->AddConstInput( GetTensorType(), {constant_values}, {1}); this->output_ = this->AddOutput(output); this->SetBuiltinOp(BuiltinOperator_PADV2, BuiltinOptions_PadV2Options, CreatePadV2Options(this->builder_).Union()); this->BuildInterpreter({input.shape, paddings_shape}); } PadV2OpDynamicModel(const TensorData& input, std::initializer_list paddings_shape, const TensorData& constant_values, const TensorData& output) { this->input_ = this->AddInput(input); this->paddings_ = this->AddInput(GetTensorType()); this->constant_values_ = this->AddInput(constant_values); this->output_ = this->AddOutput(output); this->SetBuiltinOp(BuiltinOperator_PADV2, BuiltinOptions_PadV2Options, CreatePadV2Options(this->builder_).Union()); this->BuildInterpreter({input.shape, paddings_shape}); } }; // Test case where paddings is a non-const tensor. // // Example usage is as follows: // PadOpDynamicModel m(input_shape, paddings_shape); // m.SetInput(input_data); // m.SetPaddings(paddings_data); // m.Invoke(); template class PadOpDynamicModel : public PadOpModel { public: PadOpDynamicModel(const TensorData& input, std::initializer_list paddings_shape, const TensorData& output) { this->input_ = this->AddInput(input); this->paddings_ = this->AddInput(GetTensorType()); this->constant_values_ = this->AddNullInput(); this->output_ = this->AddOutput(output); this->SetBuiltinOp(BuiltinOperator_PAD, BuiltinOptions_PadOptions, CreatePadOptions(this->builder_).Union()); this->BuildInterpreter({input.shape, paddings_shape}); } }; class PadOpTest : public ::testing::Test {}; #if GTEST_HAS_DEATH_TEST template void TooFewDimensions() { EXPECT_DEATH(PadOpConstModel( {TensorType_FLOAT32, {1, 2, 3, 4, 5, 6, 7, 8, 9}}, {9, 2}, {1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6, 7, 7, 8, 8, 9, 9}, {TensorType_FLOAT32}), "dims <= reference_ops::PadKernelMaxDimensionCount()"); } TEST_F(PadOpTest, Int32PaddingTooFewDimensions) { TooFewDimensions(); } TEST_F(PadOpTest, Int64PaddingTooFewDimensions) { TooFewDimensions(); } TEST_F(PadOpTest, Int8PaddingTooFewDimensions) { TooFewDimensions(); } TEST_F(PadOpTest, Int16PaddingTooFewDimensions) { TooFewDimensions(); } template void UnequalDimensions() { EXPECT_DEATH(PadOpConstModel( {TensorType_FLOAT32, {1, 1, 2, 1}}, {3, 2}, {1, 1, 2, 2, 3, 3}, {TensorType_FLOAT32}), "3 != 4"); } TEST_F(PadOpTest, Int32PaddingUnequalDimensions) { UnequalDimensions(); } TEST_F(PadOpTest, Int64PaddingUnequalDimensions) { UnequalDimensions(); } TEST_F(PadOpTest, Int8PaddingUnequalDimensions) { UnequalDimensions(); } TEST_F(PadOpTest, Int16PaddingUnequalDimensions) { UnequalDimensions(); } template void InvalidPadValue() { EXPECT_DEATH(PadOpConstModel({TensorType_FLOAT32, {1, 1, 2, 1}}, {4, 2}, {0, 0, 1, -1, 2, -1, 0, 0}, {TensorType_FLOAT32}), "Pad value has to be greater than equal to 0."); } TEST_F(PadOpTest, Int32PaddingInvalidPadValue) { InvalidPadValue(); } TEST_F(PadOpTest, Int64PaddingInvalidPadValue) { InvalidPadValue(); } TEST_F(PadOpTest, Int8PaddingInvalidPadValue) { InvalidPadValue(); } TEST_F(PadOpTest, Int16PaddingInvalidPadValue) { InvalidPadValue(); } TEST_F(PadOpTest, Int64PaddingOverflow) { EXPECT_DEATH(PadOpConstModel( {TensorType_FLOAT32, {1, 1, 2, 1}}, {4, 2}, {std::numeric_limits::min(), 0, 1, -1, 2, -1, 0, 0}, {TensorType_FLOAT32}), "INT64 padding overflow. Only support value between INT32_MIN " "and INT32_MAX."); EXPECT_DEATH(PadOpConstModel( {TensorType_FLOAT32, {1, 1, 2, 1}}, {4, 2}, {0, 0, 1, -1, 2, -1, std::numeric_limits::max(), 0}, {TensorType_FLOAT32}), "INT64 padding overflow. Only support value between INT32_MIN " "and INT32_MAX."); } #endif template void SimpleConstTest() { // Padding is represented as four 2-D lists representing above padding and // below padding (i.e. {{0, 0}, {1, 1}, {1, 1}, {0, 0}}). PadOpConstModel m({TensorType_FLOAT32, {1, 2, 2, 1}}, {4, 2}, {1, 1, 0, 0, 1, 1, 0, 0}, {TensorType_FLOAT32}); m.SetInput({1, 2, 3, 4}); ASSERT_EQ(m.Invoke(), kTfLiteOk); EXPECT_THAT(m.GetOutput(), ElementsAreArray({0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 0, 0, 3, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0})); EXPECT_THAT(m.GetOutputShape(), ElementsAreArray({3, 2, 4, 1})); } TEST_F(PadOpTest, Int32PaddingSimpleConstTest) { SimpleConstTest(); } TEST_F(PadOpTest, Int64PaddingSimpleConstTest) { SimpleConstTest(); } TEST_F(PadOpTest, Int8PaddingSimpleConstTest) { SimpleConstTest(); } TEST_F(PadOpTest, Int16PaddingSimpleConstTest) { SimpleConstTest(); } template void SimpleConstImageStyleTest() { // Padding is represented as four 2-D lists representing above padding and // below padding (i.e. {{0, 0}, {1, 1}, {1, 1}, {0, 0}}). PadOpConstModel m({TensorType_FLOAT32, {1, 2, 2, 1}}, {4, 2}, {0, 0, 1, 1, 1, 1, 0, 0}, {TensorType_FLOAT32}); m.SetInput({1, 2, 3, 4}); ASSERT_EQ(m.Invoke(), kTfLiteOk); EXPECT_THAT(m.GetOutput(), ElementsAreArray({0, 0, 0, 0, 0, 1, 2, 0, 0, 3, 4, 0, 0, 0, 0, 0})); EXPECT_THAT(m.GetOutputShape(), ElementsAreArray({1, 4, 4, 1})); } TEST_F(PadOpTest, Int32PaddingSimpleConstImageStyleTest) { SimpleConstImageStyleTest(); } TEST_F(PadOpTest, Int64PaddingSimpleConstImageStyleTest) { SimpleConstImageStyleTest(); } TEST_F(PadOpTest, Int8PaddingSimpleConstImageStyleTest) { SimpleConstImageStyleTest(); } TEST_F(PadOpTest, Int16PaddingSimpleConstImageStyleTest) { SimpleConstImageStyleTest(); } // Optimized versions may choose to handle zero-sized images differently. template void ZeroHeightConstImageStyleTest() { PadOpConstModel m({TensorType_FLOAT32, {1, 0, 2, 1}}, {4, 2}, {0, 0, 1, 1, 1, 1, 0, 0}, {TensorType_FLOAT32}); // Nothing to SetInput(). ASSERT_EQ(m.Invoke(), kTfLiteOk); EXPECT_THAT(m.GetOutput(), ElementsAreArray({0, 0, 0, 0, 0, 0, 0, 0})); EXPECT_THAT(m.GetOutputShape(), ElementsAreArray({1, 2, 4, 1})); } TEST_F(PadOpTest, Int32PaddingZeroHeightConstImageStyleTest) { ZeroHeightConstImageStyleTest(); } TEST_F(PadOpTest, Int64PaddingZeroHeightConstImageStyleTest) { ZeroHeightConstImageStyleTest(); } TEST_F(PadOpTest, Int8PaddingZeroHeightConstImageStyleTest) { ZeroHeightConstImageStyleTest(); } TEST_F(PadOpTest, Int16PaddingZeroHeightConstImageStyleTest) { ZeroHeightConstImageStyleTest(); } // Optimized versions may choose to handle zero-sized images differently. template void ZeroWidthConstImageStyleTest() { PadOpConstModel m({TensorType_FLOAT32, {1, 2, 0, 1}}, {4, 2}, {0, 0, 1, 1, 1, 1, 0, 0}, {TensorType_FLOAT32}); // Nothing to SetInput(). ASSERT_EQ(m.Invoke(), kTfLiteOk); EXPECT_THAT(m.GetOutput(), ElementsAreArray({0, 0, 0, 0, 0, 0, 0, 0})); EXPECT_THAT(m.GetOutputShape(), ElementsAreArray({1, 4, 2, 1})); } TEST_F(PadOpTest, Int32PaddingZeroWidthConstImageStyleTest) { ZeroWidthConstImageStyleTest(); } TEST_F(PadOpTest, Int64PaddingZeroWidthConstImageStyleTest) { ZeroWidthConstImageStyleTest(); } TEST_F(PadOpTest, Int8PaddingZeroWidthConstImageStyleTest) { ZeroWidthConstImageStyleTest(); } TEST_F(PadOpTest, Int16PaddingZeroWidthConstImageStyleTest) { ZeroWidthConstImageStyleTest(); } template void SimpleConst1DTest() { PadOpConstModel m({TensorType_FLOAT32, {2}}, {1, 2}, {1, 2}, {TensorType_FLOAT32}); m.SetInput({2, 3}); ASSERT_EQ(m.Invoke(), kTfLiteOk); EXPECT_THAT(m.GetOutput(), ElementsAreArray({0, 2, 3, 0, 0})); EXPECT_THAT(m.GetOutputShape(), ElementsAreArray({5})); } TEST_F(PadOpTest, Int32PaddingSimpleConst1DTest) { SimpleConst1DTest(); } TEST_F(PadOpTest, Int64PaddingSimpleConst1DTest) { SimpleConst1DTest(); } TEST_F(PadOpTest, Int8PaddingSimpleConst1DTest) { SimpleConst1DTest(); } TEST_F(PadOpTest, Int16PaddingSimpleConst1DTest) { SimpleConst1DTest(); } template void SimpleConst1DDim0Test() { if (SingleOpModel::GetForceUseNnapi()) { return; } PadOpConstModel m({TensorType_FLOAT32, {0}}, {1, 2}, {1, 2}, {TensorType_FLOAT32}); // NumElements(input) = 0, so there is no input data. ASSERT_EQ(m.Invoke(), kTfLiteOk); EXPECT_THAT(m.GetOutput(), ElementsAreArray({0, 0, 0})); EXPECT_THAT(m.GetOutputShape(), ElementsAreArray({3})); } TEST_F(PadOpTest, Int32PaddingSimpleConst1DDim0Test) { SimpleConst1DDim0Test(); } TEST_F(PadOpTest, Int64PaddingSimpleConst1DDim0Test) { SimpleConst1DDim0Test(); } TEST_F(PadOpTest, Int8PaddingSimpleConst1DDim0Test) { SimpleConst1DDim0Test(); } TEST_F(PadOpTest, Int16PaddingSimpleConst1DDim0Test) { SimpleConst1DDim0Test(); } template void SimpleDynamicTest() { PadOpDynamicModel m({TensorType_FLOAT32, {1, 2, 2, 1}}, {4, 2}, {TensorType_FLOAT32}); m.SetInput({1, 2, 3, 4}); m.SetPaddings({0, 0, 1, 1, 1, 1, 0, 0}); ASSERT_EQ(m.Invoke(), kTfLiteOk); EXPECT_THAT(m.GetOutput(), ElementsAreArray({0, 0, 0, 0, 0, 1, 2, 0, 0, 3, 4, 0, 0, 0, 0, 0})); EXPECT_THAT(m.GetOutputShape(), ElementsAreArray({1, 4, 4, 1})); } TEST_F(PadOpTest, Int32PaddingSimpleDynamicTest) { SimpleDynamicTest(); } TEST_F(PadOpTest, Int64PaddingSimpleDynamicTest) { SimpleDynamicTest(); } TEST_F(PadOpTest, Int8PaddingSimpleDynamicTest) { SimpleDynamicTest(); } TEST_F(PadOpTest, Int16PaddingSimpleDynamicTest) { SimpleDynamicTest(); } template void DynamicUnequalDimensions() { if (SingleOpModel::GetForceUseNnapi()) { return; } PadOpDynamicModel m({TensorType_FLOAT32, {}}, {3, 2}, {TensorType_FLOAT32}); // Skip invoking m.SetInput() since the method doesn't work with dynamic // shapes. m.SetPaddings({0, 0, 1, 1, 1, 1}); ASSERT_NE(m.Invoke(), kTfLiteOk) << "Unequal dimensions."; } TEST_F(PadOpTest, Int32PaddingDynamicUnequalDimensions) { DynamicUnequalDimensions(); } TEST_F(PadOpTest, Int64PaddingDynamicUnequalDimensions) { DynamicUnequalDimensions(); } TEST_F(PadOpTest, Int8PaddingDynamicUnequalDimensions) { DynamicUnequalDimensions(); } TEST_F(PadOpTest, Int16PaddingDynamicUnequalDimensions) { DynamicUnequalDimensions(); } template void AdvancedConstTestV2() { PadOpConstModel m({TensorType_FLOAT32, {1, 2, 3, 1}}, {4, 2}, {1, 0, 0, 2, 0, 3, 0, 0}, {TensorType_FLOAT32}); m.SetInput({1, 2, 3, 4, 5, 6}); ASSERT_EQ(m.Invoke(), kTfLiteOk); EXPECT_THAT( m.GetOutput(), ElementsAreArray({0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 3, 0, 0, 0, 4, 5, 6, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0})); EXPECT_THAT(m.GetOutputShape(), ElementsAreArray({2, 4, 6, 1})); } TEST_F(PadOpTest, Int32PaddingAdvancedConstTest) { AdvancedConstTestV2(); } TEST_F(PadOpTest, Int64PaddingAdvancedConstTest) { AdvancedConstTestV2(); } TEST_F(PadOpTest, Int8PaddingAdvancedConstTest) { AdvancedConstTestV2(); } TEST_F(PadOpTest, Int16PaddingAdvancedConstTest) { AdvancedConstTestV2(); } template void AdvancedConstImageStyleTest() { PadOpConstModel m({TensorType_FLOAT32, {1, 2, 3, 1}}, {4, 2}, {0, 0, 0, 2, 1, 3, 0, 0}, {TensorType_FLOAT32}); m.SetInput({1, 2, 3, 4, 5, 6}); ASSERT_EQ(m.Invoke(), kTfLiteOk); EXPECT_THAT(m.GetOutput(), ElementsAreArray({0, 1, 2, 3, 0, 0, 0, 0, 4, 5, 6, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0})); EXPECT_THAT(m.GetOutputShape(), ElementsAreArray({1, 4, 7, 1})); } TEST_F(PadOpTest, Int32PaddingAdvancedConstImageStyleTest) { AdvancedConstImageStyleTest(); } TEST_F(PadOpTest, Int64PaddingAdvancedConstImageStyleTest) { AdvancedConstImageStyleTest(); } TEST_F(PadOpTest, Int8PaddingAdvancedConstImageStyleTest) { AdvancedConstImageStyleTest(); } TEST_F(PadOpTest, Int16PaddingAdvancedConstImageStyleTest) { AdvancedConstImageStyleTest(); } template void AdvancedDynamicTest() { PadOpDynamicModel m({TensorType_FLOAT32, {1, 2, 3, 1}}, {4, 2}, {TensorType_FLOAT32}); m.SetInput({1, 2, 3, 4, 5, 6}); m.SetPaddings({0, 0, 0, 2, 1, 3, 0, 0}); ASSERT_EQ(m.Invoke(), kTfLiteOk); EXPECT_THAT(m.GetOutput(), ElementsAreArray({0, 1, 2, 3, 0, 0, 0, 0, 4, 5, 6, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0})); EXPECT_THAT(m.GetOutputShape(), ElementsAreArray({1, 4, 7, 1})); } TEST_F(PadOpTest, Int32PaddingAdvancedDynamicTest) { AdvancedDynamicTest(); } TEST_F(PadOpTest, Int64PaddingAdvancedDynamicTest) { AdvancedDynamicTest(); } TEST_F(PadOpTest, Int8PaddingAdvancedDynamicTest) { AdvancedDynamicTest(); } TEST_F(PadOpTest, Int16PaddingAdvancedDynamicTest) { AdvancedDynamicTest(); } std::vector> DequantizedArrayNear( const std::vector& values, const float min, const float max) { const float quantization_tolerance = (max - min) / 255.0; return ArrayFloatNear(values, quantization_tolerance); } class QuantizedPadOpTest : public ::testing::Test {}; #if GTEST_HAS_DEATH_TEST template void ZeroNotInQuantizationRange() { // The test_util and actual quantization code currently ensure that the range // must include zero, but if that ever changes, this test will catch it. EXPECT_DEATH(PadOpConstModel m( {tensor_dtype, {1, 2, 2, 1}, 1.0, 2.0}, {4, 2}, {0, 0, 1, 1, 1, 1, 0, 0}, {tensor_dtype, {}, 1.0, 2.0}), ".*Check failed: f_min <= 0.*"); } TEST_F(QuantizedPadOpTest, UInt8ZeroNotInQuantizationRange) { ZeroNotInQuantizationRange(); } TEST_F(QuantizedPadOpTest, Int8ZeroNotInQuantizationRange) { ZeroNotInQuantizationRange(); } TEST_F(QuantizedPadOpTest, Int16ZeroNotInQuantizationRange) { ZeroNotInQuantizationRange(); } #endif template void SimpleConstTest() { // Padding is represented as four 2-D lists representing above padding and // below padding (i.e. {{0, 0}, {1, 1}, {1, 1}, {0, 0}}). const float kMin = -1.f; const float kMax = tensor_dtype == TensorType_INT16 ? 32767.f / 32768.f : 1.f; PadOpConstModel m({tensor_dtype, {1, 2, 2, 1}, kMin, kMax}, {4, 2}, {0, 0, 1, 1, 1, 1, 0, 0}, {tensor_dtype, {}, kMin, kMax}); m.template SetQuantizedInput({-0.8, 0.2, 0.9, 0.7}); ASSERT_EQ(m.Invoke(), kTfLiteOk); EXPECT_THAT(m.template GetDequantizedOutput(), ElementsAreArray(DequantizedArrayNear( {0, 0, 0, 0, 0, -0.8, 0.2, 0, 0, 0.9, 0.7, 0, 0, 0, 0, 0}, kMin, kMax))); EXPECT_THAT(m.GetOutputShape(), ElementsAreArray({1, 4, 4, 1})); } TEST_F(QuantizedPadOpTest, UInt8SimpleConstTest) { SimpleConstTest(); } TEST_F(QuantizedPadOpTest, Int8SimpleConstTest) { SimpleConstTest(); } TEST_F(QuantizedPadOpTest, Int16SimpleConstTest) { SimpleConstTest(); } template void SimpleDynamicTest() { const float kMin = -1.f; const float kMax = tensor_dtype == TensorType_INT16 ? 32767.f / 32768.f : 1.f; PadOpDynamicModel m({tensor_dtype, {1, 2, 2, 1}, kMin, kMax}, {4, 2}, {tensor_dtype, {}, kMin, kMax}); m.template SetQuantizedInput({-0.8, 0.2, 0.9, 0.7}); m.SetPaddings({0, 0, 1, 1, 1, 1, 0, 0}); ASSERT_EQ(m.Invoke(), kTfLiteOk); EXPECT_THAT(m.template GetDequantizedOutput(), ElementsAreArray(DequantizedArrayNear( {0, 0, 0, 0, 0, -0.8, 0.2, 0, 0, 0.9, 0.7, 0, 0, 0, 0, 0}, kMin, kMax))); EXPECT_THAT(m.GetOutputShape(), ElementsAreArray({1, 4, 4, 1})); } TEST_F(QuantizedPadOpTest, UInt8SimpleDynamicTest) { SimpleDynamicTest(); } TEST_F(QuantizedPadOpTest, Int8SimpleDynamicTest) { SimpleDynamicTest(); } TEST_F(QuantizedPadOpTest, Int16SimpleDynamicTest) { SimpleDynamicTest(); } template void AdvancedConstTest() { const float kMin = -1.f; const float kMax = tensor_dtype == TensorType_INT16 ? 32767.f / 32768.f : 1.f; PadOpConstModel m({tensor_dtype, {1, 2, 3, 1}, kMin, kMax}, {4, 2}, {0, 0, 0, 2, 1, 3, 0, 0}, {tensor_dtype, {}, kMin, kMax}); m.template SetQuantizedInput({-0.8, 0.2, 0.9, 0.7, 0.1, -0.3}); ASSERT_EQ(m.Invoke(), kTfLiteOk); EXPECT_THAT(m.template GetDequantizedOutput(), ElementsAreArray(DequantizedArrayNear( {0, -0.8, 0.2, 0.9, 0, 0, 0, 0, 0.7, 0.1, -0.3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, kMin, kMax))); EXPECT_THAT(m.GetOutputShape(), ElementsAreArray({1, 4, 7, 1})); } TEST_F(QuantizedPadOpTest, UInt8AdvancedConstTest) { AdvancedConstTest(); } TEST_F(QuantizedPadOpTest, Int8AdvancedConstTest) { AdvancedConstTest(); } TEST_F(QuantizedPadOpTest, Int16AdvancedConstTest) { AdvancedConstTest(); } template void AdvancedDynamicTest() { const float kMin = -1.f; const float kMax = tensor_dtype == TensorType_INT16 ? 32767.f / 32768.f : 1.f; PadOpDynamicModel m({tensor_dtype, {1, 2, 3, 1}, kMin, kMax}, {4, 2}, {tensor_dtype, {}, kMin, kMax}); m.template SetQuantizedInput({-0.8, 0.2, 0.9, 0.7, 0.1, -0.3}); m.SetPaddings({0, 0, 0, 2, 1, 3, 0, 0}); ASSERT_EQ(m.Invoke(), kTfLiteOk); EXPECT_THAT(m.template GetDequantizedOutput(), ElementsAreArray(DequantizedArrayNear( {0, -0.8, 0.2, 0.9, 0, 0, 0, 0, 0.7, 0.1, -0.3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, kMin, kMax))); EXPECT_THAT(m.GetOutputShape(), ElementsAreArray({1, 4, 7, 1})); } TEST_F(QuantizedPadOpTest, UInt8AdvancedDynamicTest) { AdvancedDynamicTest(); } TEST_F(QuantizedPadOpTest, Int8AdvancedDynamicTest) { AdvancedDynamicTest(); } TEST_F(QuantizedPadOpTest, Int16AdvancedDynamicTest) { AdvancedDynamicTest(); } class PadV2OpTest : public ::testing::Test {}; #if GTEST_HAS_DEATH_TEST template void TooManyDimensions() { typedef PadV2OpConstModel f; EXPECT_DEATH(f({TensorType_FLOAT32, {1, 2, 3, 4, 5, 6, 7, 8, 9}}, {9, 2}, {1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6, 7, 7, 8, 8, 9, 9}, 0.0, {TensorType_FLOAT32}), "dims <= reference_ops::PadKernelMaxDimensionCount()"); } TEST_F(PadV2OpTest, Int32PaddingTooManyDimensions) { TooManyDimensions(); } TEST_F(PadV2OpTest, Int64PaddingTooManyDimensions) { TooManyDimensions(); } TEST_F(PadV2OpTest, Int8PaddingTooManyDimensions) { TooManyDimensions(); } TEST_F(PadV2OpTest, Int16PaddingTooManyDimensions) { TooManyDimensions(); } template void UnequalDimensionsV2() { typedef PadV2OpConstModel f; EXPECT_DEATH(f({TensorType_FLOAT32, {1, 1, 2, 1}}, {3, 2}, {1, 1, 2, 2, 3, 3}, 0.0, {TensorType_FLOAT32}), "3 != 4"); } TEST_F(PadV2OpTest, Int32PaddingUnequalDimensions) { UnequalDimensionsV2(); } TEST_F(PadV2OpTest, Int64PaddingUnequalDimensions) { UnequalDimensionsV2(); } TEST_F(PadV2OpTest, Int8PaddingUnequalDimensions) { UnequalDimensionsV2(); } TEST_F(PadV2OpTest, Int16PaddingUnequalDimensions) { UnequalDimensionsV2(); } template void InvalidPadValueV2() { typedef PadV2OpConstModel f; EXPECT_DEATH(f({TensorType_FLOAT32, {1, 1, 2, 1}}, {4, 2}, {0, 0, 1, -1, 2, -1, 0, 0}, 0.0, {TensorType_FLOAT32}), "Pad value has to be greater than equal to 0."); } TEST_F(PadV2OpTest, Int32PaddingInvalidPadValue) { InvalidPadValueV2(); } TEST_F(PadV2OpTest, Int64PaddingInvalidPadValue) { InvalidPadValueV2(); } TEST_F(PadV2OpTest, Int8PaddingInvalidPadValue) { InvalidPadValueV2(); } TEST_F(PadV2OpTest, Int16PaddingInvalidPadValue) { InvalidPadValueV2(); } TEST_F(PadV2OpTest, Int64PaddingOverflow) { EXPECT_DEATH(PadOpConstModel( {TensorType_FLOAT32, {1, 1, 2, 1}}, {4, 2}, {std::numeric_limits::min(), 0, 1, -1, 2, -1, 0, 0}, {TensorType_FLOAT32}), "INT64 padding overflow. Only support value between INT32_MIN " "and INT32_MAX."); } TEST_F(PadV2OpTest, UnsupportedPaddingType) { EXPECT_DEATH( PadOpConstModel({TensorType_FLOAT32, {1, 1, 2, 1}}, {4, 2}, {0, 0, 1, 1, 2, 1, 0, 0}, {TensorType_FLOAT32}), "Padding type FLOAT32 is currently not supported by Pad."); } #endif template void SimpleConstTestUint8() { // Padding is represented as four 2-D lists representing above padding and // below padding (i.e. {{0, 0}, {1, 1}, {1, 1}, {0, 0}}). PadV2OpConstModel m( {TensorType_FLOAT32, {1, 2, 2, 1}}, {4, 2}, {0, 0, 1, 1, 1, 1, 0, 0}, 0.0, {TensorType_FLOAT32}); m.SetInput({1, 2, 3, 4}); ASSERT_EQ(m.Invoke(), kTfLiteOk); EXPECT_THAT(m.GetOutput(), ElementsAreArray({0, 0, 0, 0, 0, 1, 2, 0, 0, 3, 4, 0, 0, 0, 0, 0})); EXPECT_THAT(m.GetOutputShape(), ElementsAreArray({1, 4, 4, 1})); } TEST_F(PadV2OpTest, Int32PaddingSimpleConstTestUint8) { SimpleConstTestUint8(); } TEST_F(PadV2OpTest, Int64PaddingSimpleConstTestUint8) { SimpleConstTestUint8(); } TEST_F(PadV2OpTest, Int8PaddingSimpleConstTestUint8) { SimpleConstTestUint8(); } TEST_F(PadV2OpTest, Int16PaddingSimpleConstTestUint8) { SimpleConstTestUint8(); } template void SimpleConstTestInt8() { // Padding is represented as four 2-D lists representing above padding and // below padding (i.e. {{0, 0}, {1, 1}, {1, 1}, {0, 0}}). PadV2OpConstModel m( {TensorType_FLOAT32, {1, 2, 2, 1}}, {4, 2}, {0, 0, 1, 1, 1, 1, 0, 0}, 0.0, {TensorType_FLOAT32}); m.SetInput({1, 2, 3, 4}); ASSERT_EQ(m.Invoke(), kTfLiteOk); EXPECT_THAT(m.GetOutput(), ElementsAreArray({0, 0, 0, 0, 0, 1, 2, 0, 0, 3, 4, 0, 0, 0, 0, 0})); EXPECT_THAT(m.GetOutputShape(), ElementsAreArray({1, 4, 4, 1})); } TEST_F(PadV2OpTest, Int32PaddingSimpleConstTestInt8) { SimpleConstTestInt8(); } TEST_F(PadV2OpTest, Int64PaddingSimpleConstTestInt8) { SimpleConstTestInt8(); } TEST_F(PadV2OpTest, Int8PaddingSimpleConstTestInt8) { SimpleConstTestInt8(); } TEST_F(PadV2OpTest, Int16PaddingSimpleConstTestInt8) { SimpleConstTestInt8(); } template void SimpleConstFloat32ValuedTestUint8() { // Padding is represented as four 2-D lists representing above padding and // below padding (i.e. {{0, 0}, {1, 1}, {1, 1}, {0, 0}}). PadV2OpConstModel m( {TensorType_FLOAT32, {1, 2, 2, 1}}, {4, 2}, {0, 0, 1, 1, 1, 1, 0, 0}, 5, {TensorType_FLOAT32}); m.SetInput({1, 2, 3, 4}); ASSERT_EQ(m.Invoke(), kTfLiteOk); EXPECT_THAT(m.GetOutput(), ElementsAreArray({5, 5, 5, 5, 5, 1, 2, 5, 5, 3, 4, 5, 5, 5, 5, 5})); EXPECT_THAT(m.GetOutputShape(), ElementsAreArray({1, 4, 4, 1})); } TEST_F(PadV2OpTest, Int32PaddingSimpleConstFloat32ValuedTestUint8) { SimpleConstFloat32ValuedTestUint8(); } TEST_F(PadV2OpTest, Int64PaddingSimpleConstFloat32ValuedTestUint8) { SimpleConstFloat32ValuedTestUint8(); } TEST_F(PadV2OpTest, Int8PaddingSimpleConstFloat32ValuedTestUint8) { SimpleConstFloat32ValuedTestUint8(); } TEST_F(PadV2OpTest, Int16PaddingSimpleConstFloat32ValuedTestUint8) { SimpleConstFloat32ValuedTestUint8(); } template void SimpleConstFloat32ValuedTestInt8() { // Padding is represented as four 2-D lists representing above padding and // below padding (i.e. {{0, 0}, {1, 1}, {1, 1}, {0, 0}}). PadV2OpConstModel m( {TensorType_FLOAT32, {1, 2, 2, 1}}, {4, 2}, {0, 0, 1, 1, 1, 1, 0, 0}, 5, {TensorType_FLOAT32}); m.SetInput({1, 2, 3, 4}); ASSERT_EQ(m.Invoke(), kTfLiteOk); EXPECT_THAT(m.GetOutput(), ElementsAreArray({5, 5, 5, 5, 5, 1, 2, 5, 5, 3, 4, 5, 5, 5, 5, 5})); EXPECT_THAT(m.GetOutputShape(), ElementsAreArray({1, 4, 4, 1})); } TEST_F(PadV2OpTest, Int32PaddingSimpleConstFloat32ValuedTestInt8) { SimpleConstFloat32ValuedTestInt8(); } TEST_F(PadV2OpTest, Int64PaddingSimpleConstFloat32ValuedTestInt8) { SimpleConstFloat32ValuedTestInt8(); } TEST_F(PadV2OpTest, Int8PaddingSimpleConstFloat32ValuedTestInt8) { SimpleConstFloat32ValuedTestInt8(); } TEST_F(PadV2OpTest, Int16PaddingSimpleConstFloat32ValuedTestInt8) { SimpleConstFloat32ValuedTestInt8(); } template void SimpleConstFloat16ValuedTest() { PadV2OpConstModel m( {TensorType_FLOAT16, {1, 2, 2, 1}}, {4, 2}, {0, 0, 1, 1, 1, 1, 0, 0}, half{4.0f}, {TensorType_FLOAT16}); m.SetInput({half{1.5f}, half{2.5f}, half{3.5f}, half{4.5f}}); ASSERT_EQ(m.Invoke(), kTfLiteOk); EXPECT_THAT(m.GetOutput(), ElementsAreArray(ArrayFloatNear( {half{4}, half{4}, half{4}, half{4}, half{4}, half{1.5f}, half{2.5f}, half{4}, half{4}, half{3.5f}, half{4.5f}, half{4}, half{4}, half{4}, half{4}, half{4}}))); EXPECT_THAT(m.GetOutputShape(), ElementsAreArray({1, 4, 4, 1})); } TEST_F(PadV2OpTest, Int32PaddingSimpleConstFloat16) { SimpleConstFloat16ValuedTest(); } TEST_F(PadV2OpTest, Int64PaddingSimpleConstFloat16) { SimpleConstFloat16ValuedTest(); } TEST_F(PadV2OpTest, Int8PaddingSimpleConstFloat16) { SimpleConstFloat16ValuedTest(); } TEST_F(PadV2OpTest, Int16PaddingSimpleConstFloat16) { SimpleConstFloat16ValuedTest(); } template void SimpleConstBFloat16ValuedTest() { PadV2OpConstModel m( {TensorType_BFLOAT16, {1, 2, 2, 1}}, {4, 2}, {0, 0, 1, 1, 1, 1, 0, 0}, Eigen::bfloat16{6.0f}, {TensorType_BFLOAT16}); m.SetInput({Eigen::bfloat16{1.0f}, Eigen::bfloat16{2.0f}, Eigen::bfloat16{3.0f}, Eigen::bfloat16{4.0}}); ASSERT_EQ(m.Invoke(), kTfLiteOk); EXPECT_THAT(m.GetOutput(), ElementsAreArray({6, 6, 6, 6, 6, 1, 2, 6, 6, 3, 4, 6, 6, 6, 6, 6})); EXPECT_THAT(m.GetOutputShape(), ElementsAreArray({1, 4, 4, 1})); } TEST_F(PadV2OpTest, Int32PaddingSimpleConstBFloat16) { SimpleConstBFloat16ValuedTest(); } TEST_F(PadV2OpTest, Int64PaddingSimpleConstBFloat16) { SimpleConstBFloat16ValuedTest(); } TEST_F(PadV2OpTest, Int8PaddingSimpleConstBFloat16) { SimpleConstBFloat16ValuedTest(); } TEST_F(PadV2OpTest, Int16PaddingSimpleConstBFloat16) { SimpleConstBFloat16ValuedTest(); } template void SimpleConstBoolValuedTest() { PadV2OpConstModel m( {TensorType_BOOL, {1, 2, 2, 1}}, {4, 2}, {false, false, true, true, true, true, false, false}, true, {TensorType_BOOL}); m.SetInput({true, true, false, false}); ASSERT_EQ(m.Invoke(), kTfLiteOk); EXPECT_THAT( m.GetOutput(), ElementsAreArray({true, true, true, true, true, true, true, true, true, false, false, true, true, true, true, true})); EXPECT_THAT(m.GetOutputShape(), ElementsAreArray({1, 4, 4, 1})); } TEST_F(PadV2OpTest, Int32PaddingSimpleConstBool) { SimpleConstBoolValuedTest(); } TEST_F(PadV2OpTest, Int64PaddingSimpleConstBool) { SimpleConstBoolValuedTest(); } TEST_F(PadV2OpTest, Int8PaddingSimpleConstBool) { SimpleConstBoolValuedTest(); } TEST_F(PadV2OpTest, Int16PaddingSimpleConstBool) { SimpleConstBoolValuedTest(); } template void Simple4DConstFloat32ValuedTest() { // Padding is represented as four 2-D lists representing above padding and // below padding (i.e. {{0, 0}, {1, 1}, {1, 1}, {0, 0}}). PadV2OpConstModel m( {TensorType_FLOAT32, {1, 1, 2, 1}}, {4, 2}, {0, 1, 0, 0, 0, 0, 0, 1}, 5, {TensorType_FLOAT32}); m.SetInput({3, 3}); ASSERT_EQ(m.Invoke(), kTfLiteOk); EXPECT_THAT(m.GetOutput(), ElementsAreArray({3, 5, 3, 5, 5, 5, 5, 5})); EXPECT_THAT(m.GetOutputShape(), ElementsAreArray({2, 1, 2, 2})); } TEST_F(PadV2OpTest, Int32PaddingSimple4DConstFloat32ValuedTest) { Simple4DConstFloat32ValuedTest(); } TEST_F(PadV2OpTest, Int64PaddingSimple4DConstFloat32ValuedTest) { Simple4DConstFloat32ValuedTest(); } TEST_F(PadV2OpTest, Int8PaddingSimple4DConstFloat32ValuedTest) { Simple4DConstFloat32ValuedTest(); } TEST_F(PadV2OpTest, Int16PaddingSimple4DConstFloat32ValuedTest) { Simple4DConstFloat32ValuedTest(); } template void Simple4DConstFloat16ValuedTest() { PadV2OpConstModel m( {TensorType_FLOAT16, {1, 1, 2, 1}}, {4, 2}, {0, 1, 0, 0, 0, 0, 0, 1}, half{7.0f}, {TensorType_FLOAT16}); m.SetInput({half{3.0f}, half{6.0f}}); ASSERT_EQ(m.Invoke(), kTfLiteOk); EXPECT_THAT(m.GetOutput(), ElementsAreArray(ArrayFloatNear( {half{3.0f}, half{7.0f}, half{6.0f}, half{7.0f}, half{7.0f}, half{7.0f}, half{7.0f}, half{7.0f}}))); EXPECT_THAT(m.GetOutputShape(), ElementsAreArray({2, 1, 2, 2})); } TEST_F(PadV2OpTest, Int32PaddingSimple4DConstFloat16ValuedTest) { Simple4DConstFloat16ValuedTest(); } TEST_F(PadV2OpTest, Int64PaddingSimple4DConstFloat16ValuedTest) { Simple4DConstFloat16ValuedTest(); } TEST_F(PadV2OpTest, Int8PaddingSimple4DConstFloat16ValuedTest) { Simple4DConstFloat16ValuedTest(); } TEST_F(PadV2OpTest, Int16PaddingSimple4DConstFloat16ValuedTest) { Simple4DConstFloat16ValuedTest(); } template void Simple4DConstBFloat16ValuedTest() { PadV2OpConstModel m( {TensorType_BFLOAT16, {1, 1, 2, 1}}, {4, 2}, {0, 1, 0, 0, 0, 0, 0, 1}, Eigen::bfloat16{5.0}, {TensorType_BFLOAT16}); m.SetInput({Eigen::bfloat16{3.2f}, Eigen::bfloat16{6.4f}}); ASSERT_EQ(m.Invoke(), kTfLiteOk); EXPECT_THAT( m.GetOutput(), ElementsAreArray(ArrayFloatNear( {Eigen::bfloat16{3.2f}, Eigen::bfloat16{5.0f}, Eigen::bfloat16{6.4f}, Eigen::bfloat16{5.0f}, Eigen::bfloat16{5.0f}, Eigen::bfloat16{5.0f}, Eigen::bfloat16{5.0f}, Eigen::bfloat16{5.0f}}))); EXPECT_THAT(m.GetOutputShape(), ElementsAreArray({2, 1, 2, 2})); } TEST_F(PadV2OpTest, Int32PaddingSimple4DConstBFloat16ValuedTest) { Simple4DConstBFloat16ValuedTest(); } TEST_F(PadV2OpTest, Int64PaddingSimple4DConstBFloat16ValuedTest) { Simple4DConstBFloat16ValuedTest(); } TEST_F(PadV2OpTest, Int8PaddingSimple4DConstBFloat16ValuedTest) { Simple4DConstBFloat16ValuedTest(); } TEST_F(PadV2OpTest, Int16PaddingSimple4DConstBFloat16ValuedTest) { Simple4DConstBFloat16ValuedTest(); } template void SimpleConstInt32ValuedTest() { // Padding is represented as four 2-D lists representing above padding and // below padding (i.e. {{0, 0}, {1, 1}, {1, 1}, {0, 0}}). PadV2OpConstModel m( {TensorType_INT32, {1, 2, 2, 1}}, {4, 2}, {0, 0, 1, 1, 1, 1, 0, 0}, 5, {TensorType_INT32}); m.SetInput({1, 2, 3, 4}); ASSERT_EQ(m.Invoke(), kTfLiteOk); EXPECT_THAT(m.GetOutput(), ElementsAreArray({5, 5, 5, 5, 5, 1, 2, 5, 5, 3, 4, 5, 5, 5, 5, 5})); EXPECT_THAT(m.GetOutputShape(), ElementsAreArray({1, 4, 4, 1})); } TEST_F(PadV2OpTest, Int32PaddingSimpleConstInt32ValuedTest) { SimpleConstInt32ValuedTest(); } TEST_F(PadV2OpTest, Int64PaddingSimpleConstInt32ValuedTest) { SimpleConstInt32ValuedTest(); } TEST_F(PadV2OpTest, Int8PaddingSimpleConstInt32ValuedTest) { SimpleConstInt32ValuedTest(); } TEST_F(PadV2OpTest, Int16PaddingSimpleConstInt32ValuedTest) { SimpleConstInt32ValuedTest(); } template void SimpleDynamicTestV2() { PadV2OpDynamicModel m( {TensorType_FLOAT32, {1, 2, 2, 1}}, {4, 2}, 0.0, {TensorType_FLOAT32}); m.SetInput({1, 2, 3, 4}); m.SetPaddings({0, 0, 1, 1, 1, 1, 0, 0}); ASSERT_EQ(m.Invoke(), kTfLiteOk); EXPECT_THAT(m.GetOutput(), ElementsAreArray({0, 0, 0, 0, 0, 1, 2, 0, 0, 3, 4, 0, 0, 0, 0, 0})); EXPECT_THAT(m.GetOutputShape(), ElementsAreArray({1, 4, 4, 1})); } TEST_F(PadV2OpTest, Int32PaddingSimpleDynamicTest) { SimpleDynamicTestV2(); } TEST_F(PadV2OpTest, Int64PaddingSimpleDynamicTest) { SimpleDynamicTestV2(); } TEST_F(PadV2OpTest, Int8PaddingSimpleDynamicTest) { SimpleDynamicTestV2(); } TEST_F(PadV2OpTest, Int16PaddingSimpleDynamicTest) { SimpleDynamicTestV2(); } template void SimpleDynamicTestV2Float16() { PadV2OpDynamicModel m( {TensorType_FLOAT16, {1, 2, 2, 1}}, {4, 2}, half{0.0f}, {TensorType_FLOAT16}); m.SetInput({half{1.0f}, half{2.0f}, half{3.0f}, half{4.0f}}); m.SetPaddings({0, 0, 1, 1, 1, 1, 0, 0}); ASSERT_EQ(m.Invoke(), kTfLiteOk); EXPECT_THAT(m.GetOutput(), ElementsAreArray(ArrayFloatNear( {half{0.0f}, half{0.0f}, half{0.0f}, half{0.0f}, half{0.0f}, half{1.0f}, half{2.0f}, half{0.0f}, half{0.0f}, half{3.0f}, half{4.0f}, half{0.0f}, half{0.0f}, half{0.0f}, half{0.0f}, half{0.0f}}))); EXPECT_THAT(m.GetOutputShape(), ElementsAreArray({1, 4, 4, 1})); } TEST_F(PadV2OpTest, Int32PaddingSimpleDynamicTestFloat16) { SimpleDynamicTestV2Float16(); } TEST_F(PadV2OpTest, Int64PaddingSimpleDynamicTestFloat16) { SimpleDynamicTestV2Float16(); } TEST_F(PadV2OpTest, Int8PaddingSimpleDynamicTestFloat16) { SimpleDynamicTestV2Float16(); } TEST_F(PadV2OpTest, Int16PaddingSimpleDynamicTestFloat16) { SimpleDynamicTestV2Float16(); } template void SimpleDynamicTestV2BFloat16() { PadV2OpDynamicModel m( {TensorType_BFLOAT16, {1, 2, 2, 1}}, {4, 2}, Eigen::bfloat16{2.0}, {TensorType_BFLOAT16}); m.SetInput({Eigen::bfloat16{5.0f}, Eigen::bfloat16{6.0f}, Eigen::bfloat16{7.0f}, Eigen::bfloat16{8.0f}}); m.SetPaddings({0, 0, 1, 1, 1, 1, 0, 0}); ASSERT_EQ(m.Invoke(), kTfLiteOk); EXPECT_THAT(m.GetOutput(), ElementsAreArray({2, 2, 2, 2, 2, 5, 6, 2, 2, 7, 8, 2, 2, 2, 2, 2})); EXPECT_THAT(m.GetOutputShape(), ElementsAreArray({1, 4, 4, 1})); } TEST_F(PadV2OpTest, Int32PaddingSimpleDynamicTestBFloat16) { SimpleDynamicTestV2BFloat16(); } TEST_F(PadV2OpTest, Int64PaddingSimpleDynamicTestBFloat16) { SimpleDynamicTestV2BFloat16(); } TEST_F(PadV2OpTest, Int8PaddingSimpleDynamicTestBFloat16) { SimpleDynamicTestV2BFloat16(); } TEST_F(PadV2OpTest, Int16PaddingSimpleDynamicTestBFloat16) { SimpleDynamicTestV2BFloat16(); } template void SimpleDynamicTestBoolV2() { PadV2OpDynamicModel m( {TensorType_BOOL, {1, 2, 2, 1}}, {4, 2}, false, {TensorType_BOOL}); m.SetInput({true, false, true, false}); m.SetPaddings({0, 0, 1, 1, 1, 1, 0, 0}); ASSERT_EQ(m.Invoke(), kTfLiteOk); EXPECT_THAT(m.GetOutput(), ElementsAreArray({false, false, false, false, false, true, false, false, false, true, false, false, false, false, false, false})); EXPECT_THAT(m.GetOutputShape(), ElementsAreArray({1, 4, 4, 1})); } TEST_F(PadV2OpTest, Int32PaddingSimpleDynamicTestBoolV2) { SimpleDynamicTestBoolV2(); } TEST_F(PadV2OpTest, Int64PaddingSimpleDynamicTestBoolV2) { SimpleDynamicTestBoolV2(); } TEST_F(PadV2OpTest, Int8PaddingSimpleDynamicTestBoolV2) { SimpleDynamicTestBoolV2(); } TEST_F(PadV2OpTest, Int16PaddingSimpleDynamicTestBoolV2) { SimpleDynamicTestBoolV2(); } template void PadV2OpDynamicUnequalDimensions() { if (SingleOpModel::GetForceUseNnapi()) { return; } PadV2OpDynamicModel m( {TensorType_FLOAT32, {}}, {4, 2}, 0.0, {TensorType_FLOAT32}); // Skip invoking m.SetInput() since the method doesn't work with dynamic // shapes. m.SetPaddings({0, 0, 1, 1, 1, 1, 0, 0}); ASSERT_NE(m.Invoke(), kTfLiteOk) << "Unequal dimensions"; } TEST_F(PadV2OpTest, Int32PaddingDynamicUnequalDimensions) { PadV2OpDynamicUnequalDimensions(); } TEST_F(PadV2OpTest, Int64PaddingDynamicUnequalDimensions) { PadV2OpDynamicUnequalDimensions(); } TEST_F(PadV2OpTest, Int8PaddingDynamicUnequalDimensions) { PadV2OpDynamicUnequalDimensions(); } TEST_F(PadV2OpTest, Int16PaddingDynamicUnequalDimensions) { PadV2OpDynamicUnequalDimensions(); } template void SimpleDynamicValuedTest() { PadV2OpDynamicModel m( {TensorType_FLOAT32, {1, 2, 2, 1}}, {4, 2}, 5, {TensorType_FLOAT32}); m.SetInput({1, 2, 3, 4}); m.SetPaddings({0, 0, 1, 1, 1, 1, 0, 0}); ASSERT_EQ(m.Invoke(), kTfLiteOk); EXPECT_THAT(m.GetOutput(), ElementsAreArray({5, 5, 5, 5, 5, 1, 2, 5, 5, 3, 4, 5, 5, 5, 5, 5})); EXPECT_THAT(m.GetOutputShape(), ElementsAreArray({1, 4, 4, 1})); } TEST_F(PadV2OpTest, Int32PaddingSimpleDynamicValuedTest) { SimpleDynamicValuedTest(); } TEST_F(PadV2OpTest, Int64PaddingSimpleDynamicValuedTest) { SimpleDynamicValuedTest(); } TEST_F(PadV2OpTest, Int8PaddingSimpleDynamicValuedTest) { SimpleDynamicValuedTest(); } TEST_F(PadV2OpTest, Int16PaddingSimpleDynamicValuedTest) { SimpleDynamicValuedTest(); } template void SimpleTensorWithDim0Test() { PadV2OpDynamicModel m( {TensorType_FLOAT32, {1, 2, 2, 0}}, {4, 2}, 5, {TensorType_FLOAT32}); // NumElements(input) = 0, so there is no input data. m.SetPaddings({0, 0, 1, 1, 0, 0, 1, 1}); ASSERT_EQ(m.Invoke(), kTfLiteOk); EXPECT_THAT(m.GetOutput(), ElementsAreArray({5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5})); EXPECT_THAT(m.GetOutputShape(), ElementsAreArray({1, 4, 2, 2})); m.SetPaddings({0, 0, 1, 1, 1, 1, 0, 0}); ASSERT_EQ(m.Invoke(), kTfLiteOk); // Since NumElements(output) = 0 in this case, there is no data. EXPECT_THAT(m.GetOutputShape(), ElementsAreArray({1, 4, 4, 0})); } TEST_F(PadV2OpTest, Int32PaddingSimpleTensorWithDim0Test) { SimpleTensorWithDim0Test(); } TEST_F(PadV2OpTest, Int64PaddingSimpleTensorWithDim0Test) { SimpleTensorWithDim0Test(); } TEST_F(PadV2OpTest, Int8PaddingSimpleTensorWithDim0Test) { SimpleTensorWithDim0Test(); } TEST_F(PadV2OpTest, Int16PaddingSimpleTensorWithDim0Test) { SimpleTensorWithDim0Test(); } template void Simple5DConstFloat32ValuedTest() { PadV2OpConstModel m( {TensorType_FLOAT32, {1, 1, 2, 1, 1}}, {5, 2}, {0, 1, 0, 0, 1, 1, 0, 0, 0, 1}, 5, {TensorType_FLOAT32}); m.SetInput({3, 3}); ASSERT_EQ(m.Invoke(), kTfLiteOk); EXPECT_THAT(m.GetOutputShape(), ElementsAreArray({2, 1, 4, 1, 2})); EXPECT_THAT(m.GetOutput(), ElementsAreArray({5, 5, 3, 5, 3, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5})); } TEST_F(PadV2OpTest, Int32PaddingSimple5DConstFloat32ValuedTest) { Simple5DConstFloat32ValuedTest(); } TEST_F(PadV2OpTest, Int64PaddingSimple5DConstFloat32ValuedTest) { Simple5DConstFloat32ValuedTest(); } TEST_F(PadV2OpTest, Int8PaddingSimple5DConstFloat32ValuedTest) { Simple5DConstFloat32ValuedTest(); } TEST_F(PadV2OpTest, Int16PaddingSimple5DConstFloat32ValuedTest) { Simple5DConstFloat32ValuedTest(); } template void Simple5DConstInt32ValuedTest() { PadV2OpConstModel m( {TensorType_INT32, {1, 2, 2, 1, 1}}, {5, 2}, {0, 0, 1, 1, 1, 1, 0, 0, 1, 1}, 5, {TensorType_INT32}); m.SetInput({1, 2, 3, 4}); ASSERT_EQ(m.Invoke(), kTfLiteOk); EXPECT_THAT(m.GetOutputShape(), ElementsAreArray({1, 4, 4, 1, 3})); EXPECT_THAT( m.GetOutput(), ElementsAreArray({5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 1, 5, 5, 2, 5, 5, 5, 5, 5, 5, 5, 5, 3, 5, 5, 4, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5})); } TEST_F(PadV2OpTest, Int32PaddingSimple5DConstInt32ValuedTest) { Simple5DConstInt32ValuedTest(); } TEST_F(PadV2OpTest, Int64PaddingSimple5DConstInt32ValuedTest) { Simple5DConstInt32ValuedTest(); } TEST_F(PadV2OpTest, Int8PaddingSimple5DConstInt32ValuedTest) { Simple5DConstInt32ValuedTest(); } TEST_F(PadV2OpTest, Int16PaddingSimple5DConstInt32ValuedTest) { Simple5DConstInt32ValuedTest(); } template void Simple5DDynamicValuedTest() { PadV2OpDynamicModel m( {TensorType_FLOAT32, {1, 2, 2, 1, 1}}, {5, 2}, 5, {TensorType_FLOAT32}); m.SetInput({1, 2, 3, 4}); m.SetPaddings({0, 0, 1, 1, 1, 1, 0, 0, 1, 1}); ASSERT_EQ(m.Invoke(), kTfLiteOk); EXPECT_THAT(m.GetOutputShape(), ElementsAreArray({1, 4, 4, 1, 3})); EXPECT_THAT( m.GetOutput(), ElementsAreArray({5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 1, 5, 5, 2, 5, 5, 5, 5, 5, 5, 5, 5, 3, 5, 5, 4, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5})); } TEST_F(PadV2OpTest, Int32PaddingSimple5DDynamicValuedTest) { Simple5DDynamicValuedTest(); } TEST_F(PadV2OpTest, Int64PaddingSimple5DDynamicValuedTest) { Simple5DDynamicValuedTest(); } TEST_F(PadV2OpTest, Int8PaddingSimple5DDynamicValuedTest) { Simple5DDynamicValuedTest(); } TEST_F(PadV2OpTest, Int16PaddingSimple5DDynamicValuedTest) { Simple5DDynamicValuedTest(); } template void AdvancedConstTest() { PadV2OpConstModel m( {TensorType_FLOAT32, {1, 2, 3, 1}}, {4, 2}, {0, 0, 0, 2, 1, 3, 0, 0}, 0, {TensorType_FLOAT32}); m.SetInput({1, 2, 3, 4, 5, 6}); ASSERT_EQ(m.Invoke(), kTfLiteOk); EXPECT_THAT(m.GetOutput(), ElementsAreArray({0, 1, 2, 3, 0, 0, 0, 0, 4, 5, 6, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0})); EXPECT_THAT(m.GetOutputShape(), ElementsAreArray({1, 4, 7, 1})); } TEST_F(PadV2OpTest, Int32PaddingAdvancedConstTest) { AdvancedConstTest(); } TEST_F(PadV2OpTest, Int64PaddingAdvancedConstTest) { AdvancedConstTest(); } TEST_F(PadV2OpTest, Int8PaddingAdvancedConstTest) { AdvancedConstTest(); } TEST_F(PadV2OpTest, Int16PaddingAdvancedConstTest) { AdvancedConstTest(); } template void AdvancedDynamicTestV2() { PadV2OpDynamicModel m( {TensorType_FLOAT32, {1, 2, 3, 1}}, {4, 2}, 0, {TensorType_FLOAT32}); m.SetInput({1, 2, 3, 4, 5, 6}); m.SetPaddings({0, 0, 0, 2, 1, 3, 0, 0}); ASSERT_EQ(m.Invoke(), kTfLiteOk); EXPECT_THAT(m.GetOutput(), ElementsAreArray({0, 1, 2, 3, 0, 0, 0, 0, 4, 5, 6, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0})); EXPECT_THAT(m.GetOutputShape(), ElementsAreArray({1, 4, 7, 1})); } TEST_F(PadV2OpTest, Int32PaddingAdvancedDynamicTest) { AdvancedDynamicTestV2(); } TEST_F(PadV2OpTest, Int64PaddingAdvancedDynamicTest) { AdvancedDynamicTestV2(); } TEST_F(PadV2OpTest, Int8PaddingAdvancedDynamicTest) { AdvancedDynamicTestV2(); } TEST_F(PadV2OpTest, Int16PaddingAdvancedDynamicTest) { AdvancedDynamicTestV2(); } class QuantizedPadV2OpTest : public ::testing::Test { protected: std::vector> DequantizedArrayNear( const std::vector& values, const float min, const float max) { const float quantization_tolerance = (max - min) / 255.0; return ArrayFloatNear(values, quantization_tolerance); } }; #if GTEST_HAS_DEATH_TEST template void ZeroNotInQuantizationRangeV2() { // The test_util and actual quantization code currently ensure that the range // must include zero, but if that ever changes, this test will catch it. typedef PadV2OpConstModel f; EXPECT_DEATH(f({tensor_dtype, {1, 2, 2, 1}, 1.0, 2.0}, {4, 2}, {0, 0, 1, 1, 1, 1, 0, 0}, 0, {tensor_dtype, {}, 1.0, 2.0}), ".*Check failed: f_min <= 0.*"); } TEST_F(QuantizedPadV2OpTest, UInt8ZeroNotInQuantizationRange) { ZeroNotInQuantizationRangeV2(); } TEST_F(QuantizedPadV2OpTest, Int8ZeroNotInQuantizationRange) { ZeroNotInQuantizationRangeV2(); } #endif template void SimpleConstTestV2() { // Padding is represented as four 2-D lists representing above padding and // below padding (i.e. {{0, 0}, {1, 1}, {1, 1}, {0, 0}}). PadV2OpConstModel m( {tensor_dtype, {1, 2, 2, 1}, -1.0, 1.0}, {4, 2}, {0, 0, 1, 1, 1, 1, 0, 0}, {tensor_dtype, {1}, -1.0, 1.0}, {tensor_dtype, {}, -1.0, 1.0}); m.template SetQuantizedInput({-0.8, 0.2, 0.9, 0.7}); m.template SetQuantizedPadValue(0); ASSERT_EQ(m.Invoke(), kTfLiteOk); EXPECT_THAT(m.template GetDequantizedOutput(), ElementsAreArray(DequantizedArrayNear( {0, 0, 0, 0, 0, -0.8, 0.2, 0, 0, 0.9, 0.7, 0, 0, 0, 0, 0}, -1.0, 1.0))); EXPECT_THAT(m.GetOutputShape(), ElementsAreArray({1, 4, 4, 1})); } TEST_F(QuantizedPadV2OpTest, UInt8SimpleConstTest) { SimpleConstTestV2(); } TEST_F(QuantizedPadV2OpTest, Int8SimpleConstTest) { SimpleConstTestV2(); } template void SimpleDynamicTestV2() { PadV2OpDynamicModel m( {tensor_dtype, {1, 2, 2, 1}, -1.0, 1.0}, {4, 2}, {tensor_dtype, {1}, -1.0, 1.0}, {tensor_dtype, {}, -1.0, 1.0}); m.template SetQuantizedInput({-0.8, 0.2, 0.9, 0.7}); m.template SetQuantizedPadValue(0); m.SetPaddings({0, 0, 1, 1, 1, 1, 0, 0}); ASSERT_EQ(m.Invoke(), kTfLiteOk); EXPECT_THAT(m.template GetDequantizedOutput(), ElementsAreArray(DequantizedArrayNear( {0, 0, 0, 0, 0, -0.8, 0.2, 0, 0, 0.9, 0.7, 0, 0, 0, 0, 0}, -1.0, 1.0))); EXPECT_THAT(m.GetOutputShape(), ElementsAreArray({1, 4, 4, 1})); } TEST_F(QuantizedPadV2OpTest, UInt8SimpleDynamicTest) { SimpleDynamicTestV2(); } TEST_F(QuantizedPadV2OpTest, Int8SimpleDynamicTest) { SimpleDynamicTestV2(); } template void AdvancedConstTestV2() { PadV2OpConstModel m( {tensor_dtype, {1, 2, 3, 1}, -1.0, 1.0}, {4, 2}, {0, 0, 0, 2, 1, 3, 0, 0}, {tensor_dtype, {1}, -1.0, 1.0}, {tensor_dtype, {}, -1.0, 1.0}); m.template SetQuantizedInput({-0.8, 0.2, 0.9, 0.7, 0.1, -0.3}); m.template SetQuantizedPadValue(0); ASSERT_EQ(m.Invoke(), kTfLiteOk); EXPECT_THAT(m.template GetDequantizedOutput(), ElementsAreArray(DequantizedArrayNear( {0, -0.8, 0.2, 0.9, 0, 0, 0, 0, 0.7, 0.1, -0.3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, -1.0, 1.0))); EXPECT_THAT(m.GetOutputShape(), ElementsAreArray({1, 4, 7, 1})); } TEST_F(QuantizedPadV2OpTest, UInt8AdvancedConstTest) { AdvancedConstTestV2(); } TEST_F(QuantizedPadV2OpTest, Int8AdvancedConstTest) { AdvancedConstTestV2(); } template void AdvancedDynamicTestV2() { PadV2OpDynamicModel m( {tensor_dtype, {1, 2, 3, 1}, -1.0, 1.0}, {4, 2}, {tensor_dtype, {1}, -1.0, 1.0}, {tensor_dtype, {}, -1.0, 1.0}); m.template SetQuantizedInput({-0.8, 0.2, 0.9, 0.7, 0.1, -0.3}); m.template SetQuantizedPadValue(0); m.SetPaddings({0, 0, 0, 2, 1, 3, 0, 0}); ASSERT_EQ(m.Invoke(), kTfLiteOk); EXPECT_THAT(m.template GetDequantizedOutput(), ElementsAreArray(DequantizedArrayNear( {0, -0.8, 0.2, 0.9, 0, 0, 0, 0, 0.7, 0.1, -0.3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, -1.0, 1.0))); EXPECT_THAT(m.GetOutputShape(), ElementsAreArray({1, 4, 7, 1})); } TEST_F(QuantizedPadV2OpTest, UInt8AdvancedDynamicTest) { AdvancedDynamicTestV2(); } TEST_F(QuantizedPadV2OpTest, Int8AdvancedDynamicTest) { AdvancedDynamicTestV2(); } template void SimpleConstValuedTest() { // Padding is represented as four 2-D lists representing above padding and // below padding (i.e. {{0, 0}, {1, 1}, {1, 1}, {0, 0}}). PadV2OpConstModel m( {tensor_dtype, {1, 2, 2, 1}, -1.0, 1.0}, {4, 2}, {0, 0, 1, 1, 1, 1, 0, 0}, {tensor_dtype, {1}, -1.0, 1.0}, {tensor_dtype, {}, -1.0, 1.0}); m.template SetQuantizedInput({-0.8, 0.2, 0.9, 0.7}); m.template SetQuantizedPadValue(-0.5); ASSERT_EQ(m.Invoke(), kTfLiteOk); EXPECT_THAT(m.template GetDequantizedOutput(), ElementsAreArray(DequantizedArrayNear( {-0.5, -0.5, -0.5, -0.5, -0.5, -0.8, 0.2, -0.5, -0.5, 0.9, 0.7, -0.5, -0.5, -0.5, -0.5, -0.5}, -1.0, 1.0))); EXPECT_THAT(m.GetOutputShape(), ElementsAreArray({1, 4, 4, 1})); } TEST_F(QuantizedPadV2OpTest, UInt8SimpleConstValuedTest) { SimpleConstValuedTest(); } TEST_F(QuantizedPadV2OpTest, Int8SimpleConstValuedTest) { SimpleConstValuedTest(); } template void SimpleDynamicValuedTest() { PadV2OpDynamicModel m( {tensor_dtype, {1, 2, 2, 1}, -1.0, 1.0}, {4, 2}, {tensor_dtype, {1}, -1.0, 1.0}, {tensor_dtype, {}, -1.0, 1.0}); m.template SetQuantizedInput({-0.8, 0.2, 0.9, 0.7}); m.template SetQuantizedPadValue(-0.5); m.SetPaddings({0, 0, 1, 1, 1, 1, 0, 0}); ASSERT_EQ(m.Invoke(), kTfLiteOk); EXPECT_THAT(m.template GetDequantizedOutput(), ElementsAreArray(DequantizedArrayNear( {-0.5, -0.5, -0.5, -0.5, -0.5, -0.8, 0.2, -0.5, -0.5, 0.9, 0.7, -0.5, -0.5, -0.5, -0.5, -0.5}, -1.0, 1.0))); EXPECT_THAT(m.GetOutputShape(), ElementsAreArray({1, 4, 4, 1})); } TEST_F(QuantizedPadV2OpTest, UInt8SimpleDynamicValuedTest) { SimpleDynamicValuedTest(); } TEST_F(QuantizedPadV2OpTest, Int8SimpleDynamicValuedTest) { SimpleDynamicValuedTest(); } template void AdvancedConstValuedTest() { PadV2OpConstModel m( {tensor_dtype, {1, 2, 3, 1}, -1.0, 1.0}, {4, 2}, {0, 0, 0, 2, 1, 3, 0, 0}, {tensor_dtype, {1}, -1.0, 1.0}, {tensor_dtype, {}, -1.0, 1.0}); m.template SetQuantizedInput({-0.8, 0.2, 0.9, 0.7, 0.1, -0.3}); m.template SetQuantizedPadValue(-0.5); ASSERT_EQ(m.Invoke(), kTfLiteOk); EXPECT_THAT(m.template GetDequantizedOutput(), ElementsAreArray(DequantizedArrayNear( {-0.5, -0.8, 0.2, 0.9, -0.5, -0.5, -0.5, -0.5, 0.7, 0.1, -0.3, -0.5, -0.5, -0.5, -0.5, -0.5, -0.5, -0.5, -0.5, -0.5, -0.5, -0.5, -0.5, -0.5, -0.5, -0.5, -0.5, -0.5}, -1.0, 1.0))); EXPECT_THAT(m.GetOutputShape(), ElementsAreArray({1, 4, 7, 1})); } TEST_F(QuantizedPadV2OpTest, UInt8AdvancedConstValuedTest) { AdvancedConstValuedTest(); } TEST_F(QuantizedPadV2OpTest, Int8AdvancedConstValuedTest) { AdvancedConstValuedTest(); } template void AdvancedDynamicValuedTest() { PadV2OpDynamicModel m( {tensor_dtype, {1, 2, 3, 1}, -1.0, 1.0}, {4, 2}, {tensor_dtype, {1}, -1.0, 1.0}, {tensor_dtype, {}, -1.0, 1.0}); m.template SetQuantizedInput({-0.8, 0.2, 0.9, 0.7, 0.1, -0.3}); m.template SetQuantizedPadValue(-0.5); m.SetPaddings({0, 0, 0, 2, 1, 3, 0, 0}); ASSERT_EQ(m.Invoke(), kTfLiteOk); EXPECT_THAT(m.template GetDequantizedOutput(), ElementsAreArray(DequantizedArrayNear( {-0.5, -0.8, 0.2, 0.9, -0.5, -0.5, -0.5, -0.5, 0.7, 0.1, -0.3, -0.5, -0.5, -0.5, -0.5, -0.5, -0.5, -0.5, -0.5, -0.5, -0.5, -0.5, -0.5, -0.5, -0.5, -0.5, -0.5, -0.5}, -1.0, 1.0))); EXPECT_THAT(m.GetOutputShape(), ElementsAreArray({1, 4, 7, 1})); } TEST_F(QuantizedPadV2OpTest, UInt8AdvancedDynamicValuedTest) { AdvancedDynamicValuedTest(); } TEST_F(QuantizedPadV2OpTest, Int8AdvancedDynamicValuedTest) { AdvancedDynamicValuedTest(); } } // namespace } // namespace tflite