• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /* Copyright 2017 The TensorFlow Authors. All Rights Reserved.
2 
3 Licensed under the Apache License, Version 2.0 (the "License");
4 you may not use this file except in compliance with the License.
5 You may obtain a copy of the License at
6 
7     http://www.apache.org/licenses/LICENSE-2.0
8 
9 Unless required by applicable law or agreed to in writing, software
10 distributed under the License is distributed on an "AS IS" BASIS,
11 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 See the License for the specific language governing permissions and
13 limitations under the License.
14 ==============================================================================*/
15 #include <cstdint>
16 #include <initializer_list>
17 #include <vector>
18 
19 #include <gmock/gmock.h>
20 #include <gtest/gtest.h>
21 #include "flatbuffers/flatbuffers.h"  // from @flatbuffers
22 #include "tensorflow/lite/interpreter.h"
23 #include "tensorflow/lite/kernels/test_util.h"
24 #include "tensorflow/lite/schema/schema_generated.h"
25 
26 namespace tflite {
27 namespace {
28 
29 using ::testing::ElementsAreArray;
30 using ::testing::Matcher;
31 
32 template <typename RegularInputOutput>
33 class PadOpModel : public SingleOpModel {
34  public:
SetInput(std::initializer_list<RegularInputOutput> data)35   void SetInput(std::initializer_list<RegularInputOutput> data) {
36     PopulateTensor<RegularInputOutput>(input_, data);
37   }
38 
39   template <typename QuantizedInputOutput>
SetQuantizedInput(std::initializer_list<float> data)40   void SetQuantizedInput(std::initializer_list<float> data) {
41     QuantizeAndPopulate<QuantizedInputOutput>(input_, data);
42   }
43 
44   template <typename QuantizedInputOutput>
SetQuantizedPadValue(float data)45   void SetQuantizedPadValue(float data) {
46     QuantizeAndPopulate<QuantizedInputOutput>(constant_values_, {data});
47   }
48 
SetPaddings(std::initializer_list<int> paddings)49   void SetPaddings(std::initializer_list<int> paddings) {
50     PopulateTensor<int>(paddings_, paddings);
51   }
52 
GetOutput()53   std::vector<RegularInputOutput> GetOutput() {
54     return ExtractVector<RegularInputOutput>(output_);
55   }
GetOutputShape()56   std::vector<int> GetOutputShape() { return GetTensorShape(output_); }
57 
58   template <typename QuantizedInputOutput>
GetDequantizedOutput()59   std::vector<float> GetDequantizedOutput() {
60     return Dequantize<QuantizedInputOutput>(
61         ExtractVector<QuantizedInputOutput>(output_), GetScale(output_),
62         GetZeroPoint(output_));
63   }
64 
65  protected:
66   int input_;
67   int output_;
68   int paddings_;
69   int constant_values_;
70 };
71 
72 // Tests case where paddings is a const tensor. Type T is the dtype.
73 template <typename T1>
74 class PadV2OpConstModel : public PadOpModel<T1> {
75  public:
PadV2OpConstModel(const TensorData & input,std::initializer_list<int> paddings_shape,std::initializer_list<int> paddings,T1 constant_values,const TensorData & output)76   PadV2OpConstModel(const TensorData& input,
77                     std::initializer_list<int> paddings_shape,
78                     std::initializer_list<int> paddings, T1 constant_values,
79                     const TensorData& output) {
80     this->input_ = this->AddInput(input);
81     this->paddings_ =
82         this->AddConstInput(TensorType_INT32, paddings, paddings_shape);
83     this->constant_values_ =
84         this->AddConstInput(GetTensorType<T1>(), {constant_values}, {1});
85 
86     this->output_ = this->AddOutput(output);
87 
88     this->SetBuiltinOp(BuiltinOperator_PADV2, BuiltinOptions_PadV2Options,
89                        CreatePadV2Options(this->builder_).Union());
90     this->BuildInterpreter({input.shape});
91   }
92 
PadV2OpConstModel(const TensorData & input,std::initializer_list<int> paddings_shape,std::initializer_list<int> paddings,const TensorData & constant_values,const TensorData & output)93   PadV2OpConstModel(const TensorData& input,
94                     std::initializer_list<int> paddings_shape,
95                     std::initializer_list<int> paddings,
96                     const TensorData& constant_values,
97                     const TensorData& output) {
98     this->input_ = this->AddInput(input);
99     this->paddings_ =
100         this->AddConstInput(TensorType_INT32, paddings, paddings_shape);
101     this->constant_values_ = this->AddInput(constant_values);
102 
103     this->output_ = this->AddOutput(output);
104 
105     this->SetBuiltinOp(BuiltinOperator_PADV2, BuiltinOptions_PadV2Options,
106                        CreatePadV2Options(this->builder_).Union());
107     this->BuildInterpreter({input.shape});
108   }
109 };
110 
111 // Tests case where paddings is a const tensor.
112 //
113 // Example usage is as follows:
114 //    PadOpDynamicModel m(input_shape, paddings_shape, paddings_data);
115 //    m.SetInput(input_data);
116 //    m.Invoke();
117 class PadOpConstModel : public PadOpModel<float> {
118  public:
PadOpConstModel(const TensorData & input,std::initializer_list<int> paddings_shape,std::initializer_list<int> paddings,const TensorData & output)119   PadOpConstModel(const TensorData& input,
120                   std::initializer_list<int> paddings_shape,
121                   std::initializer_list<int> paddings,
122                   const TensorData& output) {
123     this->input_ = AddInput(input);
124     paddings_ = AddConstInput(TensorType_INT32, paddings, paddings_shape);
125     constant_values_ = AddNullInput();
126     output_ = AddOutput(output);
127 
128     SetBuiltinOp(BuiltinOperator_PAD, BuiltinOptions_PadOptions,
129                  CreatePadOptions(builder_).Union());
130     BuildInterpreter({input.shape});
131   }
132 };
133 
134 // Test case where paddings is a non-const tensor.
135 template <typename RegularInputOutput>
136 class PadV2OpDynamicModel : public PadOpModel<RegularInputOutput> {
137  public:
PadV2OpDynamicModel(const TensorData & input,std::initializer_list<int> paddings_shape,RegularInputOutput constant_values,const TensorData & output)138   PadV2OpDynamicModel(const TensorData& input,
139                       std::initializer_list<int> paddings_shape,
140                       RegularInputOutput constant_values,
141                       const TensorData& output) {
142     this->input_ = this->AddInput(input);
143     this->paddings_ = this->AddInput(TensorType_INT32);
144     this->constant_values_ = this->AddConstInput(
145         GetTensorType<RegularInputOutput>(), {constant_values}, {1});
146     this->output_ = this->AddOutput(output);
147 
148     this->SetBuiltinOp(BuiltinOperator_PADV2, BuiltinOptions_PadV2Options,
149                        CreatePadV2Options(this->builder_).Union());
150     this->BuildInterpreter({input.shape, paddings_shape});
151   }
PadV2OpDynamicModel(const TensorData & input,std::initializer_list<int> paddings_shape,const TensorData & constant_values,const TensorData & output)152   PadV2OpDynamicModel(const TensorData& input,
153                       std::initializer_list<int> paddings_shape,
154                       const TensorData& constant_values,
155                       const TensorData& output) {
156     this->input_ = this->AddInput(input);
157     this->paddings_ = this->AddInput(TensorType_INT32);
158     this->constant_values_ = this->AddInput(constant_values);
159     this->output_ = this->AddOutput(output);
160 
161     this->SetBuiltinOp(BuiltinOperator_PADV2, BuiltinOptions_PadV2Options,
162                        CreatePadV2Options(this->builder_).Union());
163     this->BuildInterpreter({input.shape, paddings_shape});
164   }
165 };
166 
167 // Test case where paddings is a non-const tensor.
168 //
169 // Example usage is as follows:
170 //    PadOpDynamicModel m(input_shape, paddings_shape);
171 //    m.SetInput(input_data);
172 //    m.SetPaddings(paddings_data);
173 //    m.Invoke();
174 class PadOpDynamicModel : public PadOpModel<float> {
175  public:
PadOpDynamicModel(const TensorData & input,std::initializer_list<int> paddings_shape,const TensorData & output)176   PadOpDynamicModel(const TensorData& input,
177                     std::initializer_list<int> paddings_shape,
178                     const TensorData& output) {
179     this->input_ = this->AddInput(input);
180     this->paddings_ = this->AddInput(TensorType_INT32);
181     this->constant_values_ = this->AddNullInput();
182     this->output_ = this->AddOutput(output);
183 
184     this->SetBuiltinOp(BuiltinOperator_PAD, BuiltinOptions_PadOptions,
185                        CreatePadOptions(this->builder_).Union());
186     this->BuildInterpreter({input.shape, paddings_shape});
187   }
188 };
189 
190 #ifdef GTEST_HAS_DEATH_TEST
TEST(PadOpTest,TooManyDimensions)191 TEST(PadOpTest, TooManyDimensions) {
192   EXPECT_DEATH(
193       PadOpConstModel({TensorType_FLOAT32, {1, 2, 3, 4, 5, 6, 7, 8, 9}}, {9, 2},
194                       {1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6, 7, 7, 8, 8, 9, 9},
195                       {TensorType_FLOAT32}),
196       "dims <= reference_ops::PadKernelMaxDimensionCount()");
197 }
198 
TEST(PadOpTest,UnequalDimensions)199 TEST(PadOpTest, UnequalDimensions) {
200   EXPECT_DEATH(PadOpConstModel({TensorType_FLOAT32, {1, 1, 2, 1}}, {3, 2},
201                                {1, 1, 2, 2, 3, 3}, {TensorType_FLOAT32}),
202                "3 != 4");
203 }
204 
TEST(PadOpTest,InvalidPadValue)205 TEST(PadOpTest, InvalidPadValue) {
206   EXPECT_DEATH(
207       PadOpConstModel({TensorType_FLOAT32, {1, 1, 2, 1}}, {4, 2},
208                       {0, 0, 1, -1, 2, -1, 0, 0}, {TensorType_FLOAT32}),
209       "Pad value has to be greater than equal to 0.");
210 }
211 #endif
212 
TEST(PadOpTest,SimpleConstTest)213 TEST(PadOpTest, SimpleConstTest) {
214   // Padding is represented as four 2-D lists representing above padding and
215   // below padding (i.e. {{0, 0}, {1, 1}, {1, 1}, {0, 0}}).
216   PadOpConstModel m({TensorType_FLOAT32, {1, 2, 2, 1}}, {4, 2},
217                     {1, 1, 0, 0, 1, 1, 0, 0}, {TensorType_FLOAT32});
218   m.SetInput({1, 2, 3, 4});
219   ASSERT_EQ(m.Invoke(), kTfLiteOk);
220   EXPECT_THAT(m.GetOutput(),
221               ElementsAreArray({0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 0,
222                                 0, 3, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0}));
223   EXPECT_THAT(m.GetOutputShape(), ElementsAreArray({3, 2, 4, 1}));
224 }
225 
TEST(PadOpTest,SimpleConstImageStyleTest)226 TEST(PadOpTest, SimpleConstImageStyleTest) {
227   // Padding is represented as four 2-D lists representing above padding and
228   // below padding (i.e. {{0, 0}, {1, 1}, {1, 1}, {0, 0}}).
229   PadOpConstModel m({TensorType_FLOAT32, {1, 2, 2, 1}}, {4, 2},
230                     {0, 0, 1, 1, 1, 1, 0, 0}, {TensorType_FLOAT32});
231   m.SetInput({1, 2, 3, 4});
232   ASSERT_EQ(m.Invoke(), kTfLiteOk);
233   EXPECT_THAT(m.GetOutput(), ElementsAreArray({0, 0, 0, 0, 0, 1, 2, 0, 0, 3, 4,
234                                                0, 0, 0, 0, 0}));
235   EXPECT_THAT(m.GetOutputShape(), ElementsAreArray({1, 4, 4, 1}));
236 }
237 
238 // Optimized versions may choose to handle zero-sized images differently.
TEST(PadOpTest,ZeroHeightConstImageStyleTest)239 TEST(PadOpTest, ZeroHeightConstImageStyleTest) {
240   PadOpConstModel m({TensorType_FLOAT32, {1, 0, 2, 1}}, {4, 2},
241                     {0, 0, 1, 1, 1, 1, 0, 0}, {TensorType_FLOAT32});
242   // Nothing to SetInput().
243   ASSERT_EQ(m.Invoke(), kTfLiteOk);
244   EXPECT_THAT(m.GetOutput(), ElementsAreArray({0, 0, 0, 0, 0, 0, 0, 0}));
245   EXPECT_THAT(m.GetOutputShape(), ElementsAreArray({1, 2, 4, 1}));
246 }
247 
248 // Optimized versions may choose to handle zero-sized images differently.
TEST(PadOpTest,ZeroWidthConstImageStyleTest)249 TEST(PadOpTest, ZeroWidthConstImageStyleTest) {
250   PadOpConstModel m({TensorType_FLOAT32, {1, 2, 0, 1}}, {4, 2},
251                     {0, 0, 1, 1, 1, 1, 0, 0}, {TensorType_FLOAT32});
252   // Nothing to SetInput().
253   ASSERT_EQ(m.Invoke(), kTfLiteOk);
254   EXPECT_THAT(m.GetOutput(), ElementsAreArray({0, 0, 0, 0, 0, 0, 0, 0}));
255   EXPECT_THAT(m.GetOutputShape(), ElementsAreArray({1, 4, 2, 1}));
256 }
257 
TEST(PadOpTest,SimpleConst1DTest)258 TEST(PadOpTest, SimpleConst1DTest) {
259   PadOpConstModel m({TensorType_FLOAT32, {2}}, {1, 2}, {1, 2},
260                     {TensorType_FLOAT32});
261   m.SetInput({2, 3});
262   ASSERT_EQ(m.Invoke(), kTfLiteOk);
263   EXPECT_THAT(m.GetOutput(), ElementsAreArray({0, 2, 3, 0, 0}));
264   EXPECT_THAT(m.GetOutputShape(), ElementsAreArray({5}));
265 }
266 
TEST(PadOpTest,SimpleConst1DDim0Test)267 TEST(PadOpTest, SimpleConst1DDim0Test) {
268   if (SingleOpModel::GetForceUseNnapi()) {
269     return;
270   }
271   PadOpConstModel m({TensorType_FLOAT32, {0}}, {1, 2}, {1, 2},
272                     {TensorType_FLOAT32});
273   // NumElements(input) = 0, so there is no input data.
274   ASSERT_EQ(m.Invoke(), kTfLiteOk);
275   EXPECT_THAT(m.GetOutput(), ElementsAreArray({0, 0, 0}));
276   EXPECT_THAT(m.GetOutputShape(), ElementsAreArray({3}));
277 }
278 
TEST(PadOpTest,SimpleDynamicTest)279 TEST(PadOpTest, SimpleDynamicTest) {
280   PadOpDynamicModel m({TensorType_FLOAT32, {1, 2, 2, 1}}, {4, 2},
281                       {TensorType_FLOAT32});
282   m.SetInput({1, 2, 3, 4});
283   m.SetPaddings({0, 0, 1, 1, 1, 1, 0, 0});
284   ASSERT_EQ(m.Invoke(), kTfLiteOk);
285   EXPECT_THAT(m.GetOutput(), ElementsAreArray({0, 0, 0, 0, 0, 1, 2, 0, 0, 3, 4,
286                                                0, 0, 0, 0, 0}));
287   EXPECT_THAT(m.GetOutputShape(), ElementsAreArray({1, 4, 4, 1}));
288 }
289 
TEST(PadOpTest,DynamicUnequalDimensions)290 TEST(PadOpTest, DynamicUnequalDimensions) {
291   if (SingleOpModel::GetForceUseNnapi()) {
292     return;
293   }
294   PadOpDynamicModel m({TensorType_FLOAT32, {}}, {3, 2}, {TensorType_FLOAT32});
295   // Skip invoking m.SetInput() since the method doesn't work with dynamic
296   // shapes.
297   m.SetPaddings({0, 0, 1, 1, 1, 1});
298   ASSERT_NE(m.Invoke(), kTfLiteOk) << "Unequal dimensions.";
299 }
300 
TEST(PadOpTest,AdvancedConstTest)301 TEST(PadOpTest, AdvancedConstTest) {
302   PadOpConstModel m({TensorType_FLOAT32, {1, 2, 3, 1}}, {4, 2},
303                     {1, 0, 0, 2, 0, 3, 0, 0}, {TensorType_FLOAT32});
304   m.SetInput({1, 2, 3, 4, 5, 6});
305   ASSERT_EQ(m.Invoke(), kTfLiteOk);
306   EXPECT_THAT(
307       m.GetOutput(),
308       ElementsAreArray({0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
309                         0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 3, 0, 0, 0, 4, 5,
310                         6, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}));
311   EXPECT_THAT(m.GetOutputShape(), ElementsAreArray({2, 4, 6, 1}));
312 }
313 
TEST(PadOpTest,AdvancedConstImageStyleTest)314 TEST(PadOpTest, AdvancedConstImageStyleTest) {
315   PadOpConstModel m({TensorType_FLOAT32, {1, 2, 3, 1}}, {4, 2},
316                     {0, 0, 0, 2, 1, 3, 0, 0}, {TensorType_FLOAT32});
317   m.SetInput({1, 2, 3, 4, 5, 6});
318   ASSERT_EQ(m.Invoke(), kTfLiteOk);
319   EXPECT_THAT(m.GetOutput(),
320               ElementsAreArray({0, 1, 2, 3, 0, 0, 0, 0, 4, 5, 6, 0, 0, 0,
321                                 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}));
322   EXPECT_THAT(m.GetOutputShape(), ElementsAreArray({1, 4, 7, 1}));
323 }
324 
TEST(PadOpTest,AdvancedDynamicTest)325 TEST(PadOpTest, AdvancedDynamicTest) {
326   PadOpDynamicModel m({TensorType_FLOAT32, {1, 2, 3, 1}}, {4, 2},
327                       {TensorType_FLOAT32});
328   m.SetInput({1, 2, 3, 4, 5, 6});
329   m.SetPaddings({0, 0, 0, 2, 1, 3, 0, 0});
330   ASSERT_EQ(m.Invoke(), kTfLiteOk);
331   EXPECT_THAT(m.GetOutput(),
332               ElementsAreArray({0, 1, 2, 3, 0, 0, 0, 0, 4, 5, 6, 0, 0, 0,
333                                 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}));
334   EXPECT_THAT(m.GetOutputShape(), ElementsAreArray({1, 4, 7, 1}));
335 }
336 
DequantizedArrayNear(const std::vector<float> & values,const float min,const float max)337 std::vector<Matcher<float>> DequantizedArrayNear(
338     const std::vector<float>& values, const float min, const float max) {
339   const float quantization_tolerance = (max - min) / 255.0;
340   return ArrayFloatNear(values, quantization_tolerance);
341 }
342 
343 class QuantizedPadOpTest : public ::testing::Test {};
344 
345 #ifdef GTEST_HAS_DEATH_TEST
346 template <typename integer_type, TensorType tensor_dtype>
ZeroNotInQuantizationRange()347 void ZeroNotInQuantizationRange() {
348   // The test_util and actual quantization code currently ensure that the range
349   // must include zero, but if that ever changes, this test will catch it.
350   EXPECT_DEATH(
351       PadOpConstModel m({tensor_dtype, {1, 2, 2, 1}, 1.0, 2.0}, {4, 2},
352                         {0, 0, 1, 1, 1, 1, 0, 0}, {tensor_dtype, {}, 1.0, 2.0}),
353       ".*Check failed: f_min <= 0.*");
354 }
355 
TEST_F(QuantizedPadOpTest,UInt8ZeroNotInQuantizationRange)356 TEST_F(QuantizedPadOpTest, UInt8ZeroNotInQuantizationRange) {
357   ZeroNotInQuantizationRange<uint8_t, TensorType_UINT8>();
358 }
TEST_F(QuantizedPadOpTest,Int8ZeroNotInQuantizationRange)359 TEST_F(QuantizedPadOpTest, Int8ZeroNotInQuantizationRange) {
360   ZeroNotInQuantizationRange<int8_t, TensorType_INT8>();
361 }
TEST_F(QuantizedPadOpTest,Int16ZeroNotInQuantizationRange)362 TEST_F(QuantizedPadOpTest, Int16ZeroNotInQuantizationRange) {
363   ZeroNotInQuantizationRange<int16_t, TensorType_INT16>();
364 }
365 #endif
366 
367 template <typename integer_type, TensorType tensor_dtype>
SimpleConstTest()368 void SimpleConstTest() {
369   // Padding is represented as four 2-D lists representing above padding and
370   // below padding (i.e. {{0, 0}, {1, 1}, {1, 1}, {0, 0}}).
371 
372   const float kMin = -1.f;
373   const float kMax = tensor_dtype == TensorType_INT16 ? 32767.f / 32768.f : 1.f;
374 
375   PadOpConstModel m({tensor_dtype, {1, 2, 2, 1}, kMin, kMax}, {4, 2},
376                     {0, 0, 1, 1, 1, 1, 0, 0}, {tensor_dtype, {}, kMin, kMax});
377   m.template SetQuantizedInput<integer_type>({-0.8, 0.2, 0.9, 0.7});
378   ASSERT_EQ(m.Invoke(), kTfLiteOk);
379   EXPECT_THAT(m.template GetDequantizedOutput<integer_type>(),
380               ElementsAreArray(DequantizedArrayNear(
381                   {0, 0, 0, 0, 0, -0.8, 0.2, 0, 0, 0.9, 0.7, 0, 0, 0, 0, 0},
382                   kMin, kMax)));
383   EXPECT_THAT(m.GetOutputShape(), ElementsAreArray({1, 4, 4, 1}));
384 }
385 
TEST_F(QuantizedPadOpTest,UInt8SimpleConstTest)386 TEST_F(QuantizedPadOpTest, UInt8SimpleConstTest) {
387   SimpleConstTest<uint8_t, TensorType_UINT8>();
388 }
TEST_F(QuantizedPadOpTest,Int8SimpleConstTest)389 TEST_F(QuantizedPadOpTest, Int8SimpleConstTest) {
390   SimpleConstTest<int8_t, TensorType_INT8>();
391 }
TEST_F(QuantizedPadOpTest,Int16SimpleConstTest)392 TEST_F(QuantizedPadOpTest, Int16SimpleConstTest) {
393   SimpleConstTest<int16_t, TensorType_INT16>();
394 }
395 
396 template <typename integer_type, TensorType tensor_dtype>
SimpleDynamicTest()397 void SimpleDynamicTest() {
398   const float kMin = -1.f;
399   const float kMax = tensor_dtype == TensorType_INT16 ? 32767.f / 32768.f : 1.f;
400 
401   PadOpDynamicModel m({tensor_dtype, {1, 2, 2, 1}, kMin, kMax}, {4, 2},
402                       {tensor_dtype, {}, kMin, kMax});
403   m.template SetQuantizedInput<integer_type>({-0.8, 0.2, 0.9, 0.7});
404   m.SetPaddings({0, 0, 1, 1, 1, 1, 0, 0});
405   ASSERT_EQ(m.Invoke(), kTfLiteOk);
406   EXPECT_THAT(m.template GetDequantizedOutput<integer_type>(),
407               ElementsAreArray(DequantizedArrayNear(
408                   {0, 0, 0, 0, 0, -0.8, 0.2, 0, 0, 0.9, 0.7, 0, 0, 0, 0, 0},
409                   kMin, kMax)));
410   EXPECT_THAT(m.GetOutputShape(), ElementsAreArray({1, 4, 4, 1}));
411 }
412 
TEST_F(QuantizedPadOpTest,UInt8SimpleDynamicTest)413 TEST_F(QuantizedPadOpTest, UInt8SimpleDynamicTest) {
414   SimpleDynamicTest<uint8_t, TensorType_UINT8>();
415 }
TEST_F(QuantizedPadOpTest,Int8SimpleDynamicTest)416 TEST_F(QuantizedPadOpTest, Int8SimpleDynamicTest) {
417   SimpleDynamicTest<int8_t, TensorType_INT8>();
418 }
TEST_F(QuantizedPadOpTest,Int16SimpleDynamicTest)419 TEST_F(QuantizedPadOpTest, Int16SimpleDynamicTest) {
420   SimpleDynamicTest<int16_t, TensorType_INT16>();
421 }
422 
423 template <typename integer_type, TensorType tensor_dtype>
AdvancedConstTest()424 void AdvancedConstTest() {
425   const float kMin = -1.f;
426   const float kMax = tensor_dtype == TensorType_INT16 ? 32767.f / 32768.f : 1.f;
427 
428   PadOpConstModel m({tensor_dtype, {1, 2, 3, 1}, kMin, kMax}, {4, 2},
429                     {0, 0, 0, 2, 1, 3, 0, 0}, {tensor_dtype, {}, kMin, kMax});
430   m.template SetQuantizedInput<integer_type>({-0.8, 0.2, 0.9, 0.7, 0.1, -0.3});
431   ASSERT_EQ(m.Invoke(), kTfLiteOk);
432   EXPECT_THAT(m.template GetDequantizedOutput<integer_type>(),
433               ElementsAreArray(DequantizedArrayNear(
434                   {0, -0.8, 0.2, 0.9, 0, 0, 0, 0, 0.7, 0.1, -0.3, 0, 0, 0,
435                    0, 0,    0,   0,   0, 0, 0, 0, 0,   0,   0,    0, 0, 0},
436                   kMin, kMax)));
437   EXPECT_THAT(m.GetOutputShape(), ElementsAreArray({1, 4, 7, 1}));
438 }
439 
TEST_F(QuantizedPadOpTest,UInt8AdvancedConstTest)440 TEST_F(QuantizedPadOpTest, UInt8AdvancedConstTest) {
441   AdvancedConstTest<uint8_t, TensorType_UINT8>();
442 }
TEST_F(QuantizedPadOpTest,Int8AdvancedConstTest)443 TEST_F(QuantizedPadOpTest, Int8AdvancedConstTest) {
444   AdvancedConstTest<int8_t, TensorType_INT8>();
445 }
TEST_F(QuantizedPadOpTest,Int16AdvancedConstTest)446 TEST_F(QuantizedPadOpTest, Int16AdvancedConstTest) {
447   AdvancedConstTest<int16_t, TensorType_INT16>();
448 }
449 
450 template <typename integer_type, TensorType tensor_dtype>
AdvancedDynamicTest()451 void AdvancedDynamicTest() {
452   const float kMin = -1.f;
453   const float kMax = tensor_dtype == TensorType_INT16 ? 32767.f / 32768.f : 1.f;
454 
455   PadOpDynamicModel m({tensor_dtype, {1, 2, 3, 1}, kMin, kMax}, {4, 2},
456                       {tensor_dtype, {}, kMin, kMax});
457   m.template SetQuantizedInput<integer_type>({-0.8, 0.2, 0.9, 0.7, 0.1, -0.3});
458   m.SetPaddings({0, 0, 0, 2, 1, 3, 0, 0});
459   ASSERT_EQ(m.Invoke(), kTfLiteOk);
460   EXPECT_THAT(m.template GetDequantizedOutput<integer_type>(),
461               ElementsAreArray(DequantizedArrayNear(
462                   {0, -0.8, 0.2, 0.9, 0, 0, 0, 0, 0.7, 0.1, -0.3, 0, 0, 0,
463                    0, 0,    0,   0,   0, 0, 0, 0, 0,   0,   0,    0, 0, 0},
464                   kMin, kMax)));
465   EXPECT_THAT(m.GetOutputShape(), ElementsAreArray({1, 4, 7, 1}));
466 }
467 
TEST_F(QuantizedPadOpTest,UInt8AdvancedDynamicTest)468 TEST_F(QuantizedPadOpTest, UInt8AdvancedDynamicTest) {
469   AdvancedDynamicTest<uint8_t, TensorType_UINT8>();
470 }
TEST_F(QuantizedPadOpTest,Int8AdvancedDynamicTest)471 TEST_F(QuantizedPadOpTest, Int8AdvancedDynamicTest) {
472   AdvancedDynamicTest<int8_t, TensorType_INT8>();
473 }
TEST_F(QuantizedPadOpTest,Int16AdvancedDynamicTest)474 TEST_F(QuantizedPadOpTest, Int16AdvancedDynamicTest) {
475   AdvancedDynamicTest<int16_t, TensorType_INT16>();
476 }
477 
478 #ifdef GTEST_HAS_DEATH_TEST
TEST(PadV2OpTest,TooManyDimensions)479 TEST(PadV2OpTest, TooManyDimensions) {
480   typedef PadV2OpConstModel<float> f;
481   EXPECT_DEATH(f({TensorType_FLOAT32, {1, 2, 3, 4, 5, 6, 7, 8, 9}}, {9, 2},
482                  {1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6, 7, 7, 8, 8, 9, 9}, 0.0,
483                  {TensorType_FLOAT32}),
484                "dims <= reference_ops::PadKernelMaxDimensionCount()");
485 }
486 
TEST(PadV2OpTest,UnequalDimensions)487 TEST(PadV2OpTest, UnequalDimensions) {
488   typedef PadV2OpConstModel<float> f;
489   EXPECT_DEATH(f({TensorType_FLOAT32, {1, 1, 2, 1}}, {3, 2}, {1, 1, 2, 2, 3, 3},
490                  0.0, {TensorType_FLOAT32}),
491                "3 != 4");
492 }
493 
TEST(PadV2OpTest,InvalidPadValue)494 TEST(PadV2OpTest, InvalidPadValue) {
495   typedef PadV2OpConstModel<float> f;
496   EXPECT_DEATH(f({TensorType_FLOAT32, {1, 1, 2, 1}}, {4, 2},
497                  {0, 0, 1, -1, 2, -1, 0, 0}, 0.0, {TensorType_FLOAT32}),
498                "Pad value has to be greater than equal to 0.");
499 }
500 #endif
501 
TEST(PadV2OpTest,SimpleConstTestUint8)502 TEST(PadV2OpTest, SimpleConstTestUint8) {
503   // Padding is represented as four 2-D lists representing above padding and
504   // below padding (i.e. {{0, 0}, {1, 1}, {1, 1}, {0, 0}}).
505   PadV2OpConstModel<float> m({TensorType_FLOAT32, {1, 2, 2, 1}}, {4, 2},
506                              {0, 0, 1, 1, 1, 1, 0, 0}, 0.0,
507                              {TensorType_FLOAT32});
508   m.SetInput({1, 2, 3, 4});
509   ASSERT_EQ(m.Invoke(), kTfLiteOk);
510   EXPECT_THAT(m.GetOutput(), ElementsAreArray({0, 0, 0, 0, 0, 1, 2, 0, 0, 3, 4,
511                                                0, 0, 0, 0, 0}));
512   EXPECT_THAT(m.GetOutputShape(), ElementsAreArray({1, 4, 4, 1}));
513 }
514 
TEST(PadV2OpTest,SimpleConstTestInt8)515 TEST(PadV2OpTest, SimpleConstTestInt8) {
516   // Padding is represented as four 2-D lists representing above padding and
517   // below padding (i.e. {{0, 0}, {1, 1}, {1, 1}, {0, 0}}).
518   PadV2OpConstModel<float> m({TensorType_FLOAT32, {1, 2, 2, 1}}, {4, 2},
519                              {0, 0, 1, 1, 1, 1, 0, 0}, 0.0,
520                              {TensorType_FLOAT32});
521   m.SetInput({1, 2, 3, 4});
522   ASSERT_EQ(m.Invoke(), kTfLiteOk);
523   EXPECT_THAT(m.GetOutput(), ElementsAreArray({0, 0, 0, 0, 0, 1, 2, 0, 0, 3, 4,
524                                                0, 0, 0, 0, 0}));
525   EXPECT_THAT(m.GetOutputShape(), ElementsAreArray({1, 4, 4, 1}));
526 }
527 
TEST(PadV2OpTest,SimpleConstFloat32ValuedTestUint8)528 TEST(PadV2OpTest, SimpleConstFloat32ValuedTestUint8) {
529   // Padding is represented as four 2-D lists representing above padding and
530   // below padding (i.e. {{0, 0}, {1, 1}, {1, 1}, {0, 0}}).
531   PadV2OpConstModel<float> m({TensorType_FLOAT32, {1, 2, 2, 1}}, {4, 2},
532                              {0, 0, 1, 1, 1, 1, 0, 0}, 5, {TensorType_FLOAT32});
533   m.SetInput({1, 2, 3, 4});
534   ASSERT_EQ(m.Invoke(), kTfLiteOk);
535   EXPECT_THAT(m.GetOutput(), ElementsAreArray({5, 5, 5, 5, 5, 1, 2, 5, 5, 3, 4,
536                                                5, 5, 5, 5, 5}));
537   EXPECT_THAT(m.GetOutputShape(), ElementsAreArray({1, 4, 4, 1}));
538 }
539 
TEST(PadV2OpTest,SimpleConstFloat32ValuedTestInt8)540 TEST(PadV2OpTest, SimpleConstFloat32ValuedTestInt8) {
541   // Padding is represented as four 2-D lists representing above padding and
542   // below padding (i.e. {{0, 0}, {1, 1}, {1, 1}, {0, 0}}).
543   PadV2OpConstModel<float> m({TensorType_FLOAT32, {1, 2, 2, 1}}, {4, 2},
544                              {0, 0, 1, 1, 1, 1, 0, 0}, 5, {TensorType_FLOAT32});
545   m.SetInput({1, 2, 3, 4});
546   ASSERT_EQ(m.Invoke(), kTfLiteOk);
547   EXPECT_THAT(m.GetOutput(), ElementsAreArray({5, 5, 5, 5, 5, 1, 2, 5, 5, 3, 4,
548                                                5, 5, 5, 5, 5}));
549   EXPECT_THAT(m.GetOutputShape(), ElementsAreArray({1, 4, 4, 1}));
550 }
551 
TEST(PadV2OpTest,Simple4DConstFloat32ValuedTest)552 TEST(PadV2OpTest, Simple4DConstFloat32ValuedTest) {
553   // Padding is represented as four 2-D lists representing above padding and
554   // below padding (i.e. {{0, 0}, {1, 1}, {1, 1}, {0, 0}}).
555   PadV2OpConstModel<float> m({TensorType_FLOAT32, {1, 1, 2, 1}}, {4, 2},
556                              {0, 1, 0, 0, 0, 0, 0, 1}, 5, {TensorType_FLOAT32});
557   m.SetInput({3, 3});
558   ASSERT_EQ(m.Invoke(), kTfLiteOk);
559   EXPECT_THAT(m.GetOutput(), ElementsAreArray({3, 5, 3, 5, 5, 5, 5, 5}));
560   EXPECT_THAT(m.GetOutputShape(), ElementsAreArray({2, 1, 2, 2}));
561 }
562 
TEST(PadV2OpTest,SimpleConstInt32ValuedTest)563 TEST(PadV2OpTest, SimpleConstInt32ValuedTest) {
564   // Padding is represented as four 2-D lists representing above padding and
565   // below padding (i.e. {{0, 0}, {1, 1}, {1, 1}, {0, 0}}).
566   PadV2OpConstModel<int32_t> m({TensorType_INT32, {1, 2, 2, 1}}, {4, 2},
567                                {0, 0, 1, 1, 1, 1, 0, 0}, 5, {TensorType_INT32});
568   m.SetInput({1, 2, 3, 4});
569   ASSERT_EQ(m.Invoke(), kTfLiteOk);
570   EXPECT_THAT(m.GetOutput(), ElementsAreArray({5, 5, 5, 5, 5, 1, 2, 5, 5, 3, 4,
571                                                5, 5, 5, 5, 5}));
572   EXPECT_THAT(m.GetOutputShape(), ElementsAreArray({1, 4, 4, 1}));
573 }
574 
TEST(PadV2OpTest,SimpleDynamicTest)575 TEST(PadV2OpTest, SimpleDynamicTest) {
576   PadV2OpDynamicModel<float> m({TensorType_FLOAT32, {1, 2, 2, 1}}, {4, 2}, 0.0,
577                                {TensorType_FLOAT32});
578   m.SetInput({1, 2, 3, 4});
579   m.SetPaddings({0, 0, 1, 1, 1, 1, 0, 0});
580   ASSERT_EQ(m.Invoke(), kTfLiteOk);
581   EXPECT_THAT(m.GetOutput(), ElementsAreArray({0, 0, 0, 0, 0, 1, 2, 0, 0, 3, 4,
582                                                0, 0, 0, 0, 0}));
583   EXPECT_THAT(m.GetOutputShape(), ElementsAreArray({1, 4, 4, 1}));
584 }
585 
TEST(PadV2OpTest,DynamicUnequalDimensions)586 TEST(PadV2OpTest, DynamicUnequalDimensions) {
587   if (SingleOpModel::GetForceUseNnapi()) {
588     return;
589   }
590   PadV2OpDynamicModel<float> m({TensorType_FLOAT32, {}}, {4, 2}, 0.0,
591                                {TensorType_FLOAT32});
592   // Skip invoking m.SetInput() since the method doesn't work with dynamic
593   // shapes.
594   m.SetPaddings({0, 0, 1, 1, 1, 1, 0, 0});
595   ASSERT_NE(m.Invoke(), kTfLiteOk) << "Unequal dimensions";
596 }
597 
TEST(PadV2OpTest,SimpleDynamicValuedTest)598 TEST(PadV2OpTest, SimpleDynamicValuedTest) {
599   PadV2OpDynamicModel<float> m({TensorType_FLOAT32, {1, 2, 2, 1}}, {4, 2}, 5,
600                                {TensorType_FLOAT32});
601   m.SetInput({1, 2, 3, 4});
602   m.SetPaddings({0, 0, 1, 1, 1, 1, 0, 0});
603   ASSERT_EQ(m.Invoke(), kTfLiteOk);
604   EXPECT_THAT(m.GetOutput(), ElementsAreArray({5, 5, 5, 5, 5, 1, 2, 5, 5, 3, 4,
605                                                5, 5, 5, 5, 5}));
606   EXPECT_THAT(m.GetOutputShape(), ElementsAreArray({1, 4, 4, 1}));
607 }
608 
TEST(PadV2OpTest,SimpleTensorWithDim0Test)609 TEST(PadV2OpTest, SimpleTensorWithDim0Test) {
610   PadV2OpDynamicModel<float> m({TensorType_FLOAT32, {1, 2, 2, 0}}, {4, 2}, 5,
611                                {TensorType_FLOAT32});
612   // NumElements(input) = 0, so there is no input data.
613   m.SetPaddings({0, 0, 1, 1, 0, 0, 1, 1});
614   ASSERT_EQ(m.Invoke(), kTfLiteOk);
615   EXPECT_THAT(m.GetOutput(), ElementsAreArray({5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
616                                                5, 5, 5, 5, 5}));
617   EXPECT_THAT(m.GetOutputShape(), ElementsAreArray({1, 4, 2, 2}));
618 
619   m.SetPaddings({0, 0, 1, 1, 1, 1, 0, 0});
620   ASSERT_EQ(m.Invoke(), kTfLiteOk);
621   // Since NumElements(output) = 0 in this case, there is no data.
622   EXPECT_THAT(m.GetOutputShape(), ElementsAreArray({1, 4, 4, 0}));
623 }
624 
TEST(PadV2OpTest,Simple5DConstFloat32ValuedTest)625 TEST(PadV2OpTest, Simple5DConstFloat32ValuedTest) {
626   PadV2OpConstModel<float> m({TensorType_FLOAT32, {1, 1, 2, 1, 1}}, {5, 2},
627                              {0, 1, 0, 0, 1, 1, 0, 0, 0, 1}, 5,
628                              {TensorType_FLOAT32});
629   m.SetInput({3, 3});
630   ASSERT_EQ(m.Invoke(), kTfLiteOk);
631   EXPECT_THAT(m.GetOutputShape(), ElementsAreArray({2, 1, 4, 1, 2}));
632   EXPECT_THAT(m.GetOutput(), ElementsAreArray({5, 5, 3, 5, 3, 5, 5, 5, 5, 5, 5,
633                                                5, 5, 5, 5, 5}));
634 }
635 
TEST(PadV2OpTest,Simple5DConstInt32ValuedTest)636 TEST(PadV2OpTest, Simple5DConstInt32ValuedTest) {
637   PadV2OpConstModel<int32_t> m({TensorType_INT32, {1, 2, 2, 1, 1}}, {5, 2},
638                                {0, 0, 1, 1, 1, 1, 0, 0, 1, 1}, 5,
639                                {TensorType_INT32});
640   m.SetInput({1, 2, 3, 4});
641   ASSERT_EQ(m.Invoke(), kTfLiteOk);
642   EXPECT_THAT(m.GetOutputShape(), ElementsAreArray({1, 4, 4, 1, 3}));
643   EXPECT_THAT(
644       m.GetOutput(),
645       ElementsAreArray({5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
646                         1, 5, 5, 2, 5, 5, 5, 5, 5, 5, 5, 5, 3, 5, 5, 4,
647                         5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5}));
648 }
649 
TEST(PadV2OpTest,Simple5DDynamicValuedTest)650 TEST(PadV2OpTest, Simple5DDynamicValuedTest) {
651   PadV2OpDynamicModel<float> m({TensorType_FLOAT32, {1, 2, 2, 1, 1}}, {5, 2}, 5,
652                                {TensorType_FLOAT32});
653   m.SetInput({1, 2, 3, 4});
654   m.SetPaddings({0, 0, 1, 1, 1, 1, 0, 0, 1, 1});
655   ASSERT_EQ(m.Invoke(), kTfLiteOk);
656   EXPECT_THAT(m.GetOutputShape(), ElementsAreArray({1, 4, 4, 1, 3}));
657   EXPECT_THAT(
658       m.GetOutput(),
659       ElementsAreArray({5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
660                         1, 5, 5, 2, 5, 5, 5, 5, 5, 5, 5, 5, 3, 5, 5, 4,
661                         5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5}));
662 }
663 
TEST(PadV2OpTest,AdvancedConstTest)664 TEST(PadV2OpTest, AdvancedConstTest) {
665   PadV2OpConstModel<float> m({TensorType_FLOAT32, {1, 2, 3, 1}}, {4, 2},
666                              {0, 0, 0, 2, 1, 3, 0, 0}, 0, {TensorType_FLOAT32});
667   m.SetInput({1, 2, 3, 4, 5, 6});
668   ASSERT_EQ(m.Invoke(), kTfLiteOk);
669   EXPECT_THAT(m.GetOutput(),
670               ElementsAreArray({0, 1, 2, 3, 0, 0, 0, 0, 4, 5, 6, 0, 0, 0,
671                                 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}));
672   EXPECT_THAT(m.GetOutputShape(), ElementsAreArray({1, 4, 7, 1}));
673 }
674 
TEST(PadV2OpTest,AdvancedDynamicTest)675 TEST(PadV2OpTest, AdvancedDynamicTest) {
676   PadV2OpDynamicModel<float> m({TensorType_FLOAT32, {1, 2, 3, 1}}, {4, 2}, 0,
677                                {TensorType_FLOAT32});
678   m.SetInput({1, 2, 3, 4, 5, 6});
679   m.SetPaddings({0, 0, 0, 2, 1, 3, 0, 0});
680   ASSERT_EQ(m.Invoke(), kTfLiteOk);
681   EXPECT_THAT(m.GetOutput(),
682               ElementsAreArray({0, 1, 2, 3, 0, 0, 0, 0, 4, 5, 6, 0, 0, 0,
683                                 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}));
684   EXPECT_THAT(m.GetOutputShape(), ElementsAreArray({1, 4, 7, 1}));
685 }
686 
687 class QuantizedPadV2OpTest : public ::testing::Test {
688  protected:
DequantizedArrayNear(const std::vector<float> & values,const float min,const float max)689   std::vector<Matcher<float>> DequantizedArrayNear(
690       const std::vector<float>& values, const float min, const float max) {
691     const float quantization_tolerance = (max - min) / 255.0;
692     return ArrayFloatNear(values, quantization_tolerance);
693   }
694 };
695 
696 #ifdef GTEST_HAS_DEATH_TEST
697 template <TensorType tensor_dtype>
ZeroNotInQuantizationRangeV2()698 void ZeroNotInQuantizationRangeV2() {
699   // The test_util and actual quantization code currently ensure that the range
700   // must include zero, but if that ever changes, this test will catch it.
701   typedef PadV2OpConstModel<float> f;
702   EXPECT_DEATH(f({tensor_dtype, {1, 2, 2, 1}, 1.0, 2.0}, {4, 2},
703                  {0, 0, 1, 1, 1, 1, 0, 0}, 0, {tensor_dtype, {}, 1.0, 2.0}),
704                ".*Check failed: f_min <= 0.*");
705 }
706 
TEST_F(QuantizedPadV2OpTest,UInt8ZeroNotInQuantizationRange)707 TEST_F(QuantizedPadV2OpTest, UInt8ZeroNotInQuantizationRange) {
708   ZeroNotInQuantizationRangeV2<TensorType_UINT8>();
709 }
TEST_F(QuantizedPadV2OpTest,Int8ZeroNotInQuantizationRange)710 TEST_F(QuantizedPadV2OpTest, Int8ZeroNotInQuantizationRange) {
711   ZeroNotInQuantizationRangeV2<TensorType_INT8>();
712 }
713 #endif
714 
715 template <typename integer_type, TensorType tensor_dtype>
SimpleConstTestV2()716 void SimpleConstTestV2() {
717   // Padding is represented as four 2-D lists representing above padding and
718   // below padding (i.e. {{0, 0}, {1, 1}, {1, 1}, {0, 0}}).
719   PadV2OpConstModel<integer_type> m(
720       {tensor_dtype, {1, 2, 2, 1}, -1.0, 1.0}, {4, 2}, {0, 0, 1, 1, 1, 1, 0, 0},
721       {tensor_dtype, {1}, -1.0, 1.0}, {tensor_dtype, {}, -1.0, 1.0});
722   m.template SetQuantizedInput<integer_type>({-0.8, 0.2, 0.9, 0.7});
723   m.template SetQuantizedPadValue<integer_type>(0);
724   ASSERT_EQ(m.Invoke(), kTfLiteOk);
725   EXPECT_THAT(m.template GetDequantizedOutput<integer_type>(),
726               ElementsAreArray(DequantizedArrayNear(
727                   {0, 0, 0, 0, 0, -0.8, 0.2, 0, 0, 0.9, 0.7, 0, 0, 0, 0, 0},
728                   -1.0, 1.0)));
729   EXPECT_THAT(m.GetOutputShape(), ElementsAreArray({1, 4, 4, 1}));
730 }
731 
TEST_F(QuantizedPadV2OpTest,UInt8SimpleConstTest)732 TEST_F(QuantizedPadV2OpTest, UInt8SimpleConstTest) {
733   SimpleConstTestV2<uint8_t, TensorType_UINT8>();
734 }
TEST_F(QuantizedPadV2OpTest,Int8SimpleConstTest)735 TEST_F(QuantizedPadV2OpTest, Int8SimpleConstTest) {
736   SimpleConstTestV2<int8_t, TensorType_INT8>();
737 }
738 
739 template <typename integer_type, TensorType tensor_dtype>
SimpleDynamicTestV2()740 void SimpleDynamicTestV2() {
741   PadV2OpDynamicModel<integer_type> m({tensor_dtype, {1, 2, 2, 1}, -1.0, 1.0},
742                                       {4, 2}, {tensor_dtype, {1}, -1.0, 1.0},
743                                       {tensor_dtype, {}, -1.0, 1.0});
744   m.template SetQuantizedInput<integer_type>({-0.8, 0.2, 0.9, 0.7});
745   m.template SetQuantizedPadValue<integer_type>(0);
746   m.SetPaddings({0, 0, 1, 1, 1, 1, 0, 0});
747   ASSERT_EQ(m.Invoke(), kTfLiteOk);
748   EXPECT_THAT(m.template GetDequantizedOutput<integer_type>(),
749               ElementsAreArray(DequantizedArrayNear(
750                   {0, 0, 0, 0, 0, -0.8, 0.2, 0, 0, 0.9, 0.7, 0, 0, 0, 0, 0},
751                   -1.0, 1.0)));
752   EXPECT_THAT(m.GetOutputShape(), ElementsAreArray({1, 4, 4, 1}));
753 }
754 
TEST_F(QuantizedPadV2OpTest,UInt8SimpleDynamicTest)755 TEST_F(QuantizedPadV2OpTest, UInt8SimpleDynamicTest) {
756   SimpleDynamicTestV2<uint8_t, TensorType_UINT8>();
757 }
TEST_F(QuantizedPadV2OpTest,Int8SimpleDynamicTest)758 TEST_F(QuantizedPadV2OpTest, Int8SimpleDynamicTest) {
759   SimpleDynamicTestV2<int8_t, TensorType_INT8>();
760 }
761 
762 template <typename integer_type, TensorType tensor_dtype>
AdvancedConstTestV2()763 void AdvancedConstTestV2() {
764   PadV2OpConstModel<integer_type> m(
765       {tensor_dtype, {1, 2, 3, 1}, -1.0, 1.0}, {4, 2}, {0, 0, 0, 2, 1, 3, 0, 0},
766       {tensor_dtype, {1}, -1.0, 1.0}, {tensor_dtype, {}, -1.0, 1.0});
767   m.template SetQuantizedInput<integer_type>({-0.8, 0.2, 0.9, 0.7, 0.1, -0.3});
768   m.template SetQuantizedPadValue<integer_type>(0);
769   ASSERT_EQ(m.Invoke(), kTfLiteOk);
770   EXPECT_THAT(m.template GetDequantizedOutput<integer_type>(),
771               ElementsAreArray(DequantizedArrayNear(
772                   {0, -0.8, 0.2, 0.9, 0, 0, 0, 0, 0.7, 0.1, -0.3, 0, 0, 0,
773                    0, 0,    0,   0,   0, 0, 0, 0, 0,   0,   0,    0, 0, 0},
774                   -1.0, 1.0)));
775   EXPECT_THAT(m.GetOutputShape(), ElementsAreArray({1, 4, 7, 1}));
776 }
777 
TEST_F(QuantizedPadV2OpTest,UInt8AdvancedConstTest)778 TEST_F(QuantizedPadV2OpTest, UInt8AdvancedConstTest) {
779   AdvancedConstTestV2<uint8_t, TensorType_UINT8>();
780 }
TEST_F(QuantizedPadV2OpTest,Int8AdvancedConstTest)781 TEST_F(QuantizedPadV2OpTest, Int8AdvancedConstTest) {
782   AdvancedConstTestV2<int8_t, TensorType_INT8>();
783 }
784 
785 template <typename integer_type, TensorType tensor_dtype>
AdvancedDynamicTestV2()786 void AdvancedDynamicTestV2() {
787   PadV2OpDynamicModel<integer_type> m({tensor_dtype, {1, 2, 3, 1}, -1.0, 1.0},
788                                       {4, 2}, {tensor_dtype, {1}, -1.0, 1.0},
789                                       {tensor_dtype, {}, -1.0, 1.0});
790   m.template SetQuantizedInput<integer_type>({-0.8, 0.2, 0.9, 0.7, 0.1, -0.3});
791   m.template SetQuantizedPadValue<integer_type>(0);
792   m.SetPaddings({0, 0, 0, 2, 1, 3, 0, 0});
793   ASSERT_EQ(m.Invoke(), kTfLiteOk);
794   EXPECT_THAT(m.template GetDequantizedOutput<integer_type>(),
795               ElementsAreArray(DequantizedArrayNear(
796                   {0, -0.8, 0.2, 0.9, 0, 0, 0, 0, 0.7, 0.1, -0.3, 0, 0, 0,
797                    0, 0,    0,   0,   0, 0, 0, 0, 0,   0,   0,    0, 0, 0},
798                   -1.0, 1.0)));
799   EXPECT_THAT(m.GetOutputShape(), ElementsAreArray({1, 4, 7, 1}));
800 }
801 
TEST_F(QuantizedPadV2OpTest,UInt8AdvancedDynamicTest)802 TEST_F(QuantizedPadV2OpTest, UInt8AdvancedDynamicTest) {
803   AdvancedDynamicTestV2<uint8_t, TensorType_UINT8>();
804 }
TEST_F(QuantizedPadV2OpTest,Int8AdvancedDynamicTest)805 TEST_F(QuantizedPadV2OpTest, Int8AdvancedDynamicTest) {
806   AdvancedDynamicTestV2<int8_t, TensorType_INT8>();
807 }
808 
809 template <typename integer_type, TensorType tensor_dtype>
SimpleConstValuedTest()810 void SimpleConstValuedTest() {
811   // Padding is represented as four 2-D lists representing above padding and
812   // below padding (i.e. {{0, 0}, {1, 1}, {1, 1}, {0, 0}}).
813   PadV2OpConstModel<integer_type> m(
814       {tensor_dtype, {1, 2, 2, 1}, -1.0, 1.0}, {4, 2}, {0, 0, 1, 1, 1, 1, 0, 0},
815       {tensor_dtype, {1}, -1.0, 1.0}, {tensor_dtype, {}, -1.0, 1.0});
816   m.template SetQuantizedInput<integer_type>({-0.8, 0.2, 0.9, 0.7});
817   m.template SetQuantizedPadValue<integer_type>(-0.5);
818   ASSERT_EQ(m.Invoke(), kTfLiteOk);
819   EXPECT_THAT(m.template GetDequantizedOutput<integer_type>(),
820               ElementsAreArray(DequantizedArrayNear(
821                   {-0.5, -0.5, -0.5, -0.5, -0.5, -0.8, 0.2, -0.5, -0.5, 0.9,
822                    0.7, -0.5, -0.5, -0.5, -0.5, -0.5},
823                   -1.0, 1.0)));
824   EXPECT_THAT(m.GetOutputShape(), ElementsAreArray({1, 4, 4, 1}));
825 }
826 
TEST_F(QuantizedPadV2OpTest,UInt8SimpleConstValuedTest)827 TEST_F(QuantizedPadV2OpTest, UInt8SimpleConstValuedTest) {
828   SimpleConstValuedTest<uint8_t, TensorType_UINT8>();
829 }
TEST_F(QuantizedPadV2OpTest,Int8SimpleConstValuedTest)830 TEST_F(QuantizedPadV2OpTest, Int8SimpleConstValuedTest) {
831   SimpleConstValuedTest<int8_t, TensorType_INT8>();
832 }
833 
834 template <typename integer_type, TensorType tensor_dtype>
SimpleDynamicValuedTest()835 void SimpleDynamicValuedTest() {
836   PadV2OpDynamicModel<integer_type> m({tensor_dtype, {1, 2, 2, 1}, -1.0, 1.0},
837                                       {4, 2}, {tensor_dtype, {1}, -1.0, 1.0},
838                                       {tensor_dtype, {}, -1.0, 1.0});
839   m.template SetQuantizedInput<integer_type>({-0.8, 0.2, 0.9, 0.7});
840   m.template SetQuantizedPadValue<integer_type>(-0.5);
841   m.SetPaddings({0, 0, 1, 1, 1, 1, 0, 0});
842   ASSERT_EQ(m.Invoke(), kTfLiteOk);
843   EXPECT_THAT(m.template GetDequantizedOutput<integer_type>(),
844               ElementsAreArray(DequantizedArrayNear(
845                   {-0.5, -0.5, -0.5, -0.5, -0.5, -0.8, 0.2, -0.5, -0.5, 0.9,
846                    0.7, -0.5, -0.5, -0.5, -0.5, -0.5},
847                   -1.0, 1.0)));
848   EXPECT_THAT(m.GetOutputShape(), ElementsAreArray({1, 4, 4, 1}));
849 }
850 
TEST_F(QuantizedPadV2OpTest,UInt8SimpleDynamicValuedTest)851 TEST_F(QuantizedPadV2OpTest, UInt8SimpleDynamicValuedTest) {
852   SimpleDynamicValuedTest<uint8_t, TensorType_UINT8>();
853 }
TEST_F(QuantizedPadV2OpTest,Int8SimpleDynamicValuedTest)854 TEST_F(QuantizedPadV2OpTest, Int8SimpleDynamicValuedTest) {
855   SimpleDynamicValuedTest<int8_t, TensorType_INT8>();
856 }
857 
858 template <typename integer_type, TensorType tensor_dtype>
AdvancedConstValuedTest()859 void AdvancedConstValuedTest() {
860   PadV2OpConstModel<integer_type> m(
861       {tensor_dtype, {1, 2, 3, 1}, -1.0, 1.0}, {4, 2}, {0, 0, 0, 2, 1, 3, 0, 0},
862       {tensor_dtype, {1}, -1.0, 1.0}, {tensor_dtype, {}, -1.0, 1.0});
863   m.template SetQuantizedInput<integer_type>({-0.8, 0.2, 0.9, 0.7, 0.1, -0.3});
864   m.template SetQuantizedPadValue<integer_type>(-0.5);
865   ASSERT_EQ(m.Invoke(), kTfLiteOk);
866   EXPECT_THAT(m.template GetDequantizedOutput<integer_type>(),
867               ElementsAreArray(DequantizedArrayNear(
868                   {-0.5, -0.8, 0.2,  0.9,  -0.5, -0.5, -0.5, -0.5, 0.7,  0.1,
869                    -0.3, -0.5, -0.5, -0.5, -0.5, -0.5, -0.5, -0.5, -0.5, -0.5,
870                    -0.5, -0.5, -0.5, -0.5, -0.5, -0.5, -0.5, -0.5},
871                   -1.0, 1.0)));
872   EXPECT_THAT(m.GetOutputShape(), ElementsAreArray({1, 4, 7, 1}));
873 }
874 
TEST_F(QuantizedPadV2OpTest,UInt8AdvancedConstValuedTest)875 TEST_F(QuantizedPadV2OpTest, UInt8AdvancedConstValuedTest) {
876   AdvancedConstValuedTest<uint8_t, TensorType_UINT8>();
877 }
TEST_F(QuantizedPadV2OpTest,Int8AdvancedConstValuedTest)878 TEST_F(QuantizedPadV2OpTest, Int8AdvancedConstValuedTest) {
879   AdvancedConstValuedTest<int8_t, TensorType_INT8>();
880 }
881 
882 template <typename integer_type, TensorType tensor_dtype>
AdvancedDynamicValuedTest()883 void AdvancedDynamicValuedTest() {
884   PadV2OpDynamicModel<integer_type> m({tensor_dtype, {1, 2, 3, 1}, -1.0, 1.0},
885                                       {4, 2}, {tensor_dtype, {1}, -1.0, 1.0},
886                                       {tensor_dtype, {}, -1.0, 1.0});
887   m.template SetQuantizedInput<integer_type>({-0.8, 0.2, 0.9, 0.7, 0.1, -0.3});
888   m.template SetQuantizedPadValue<integer_type>(-0.5);
889   m.SetPaddings({0, 0, 0, 2, 1, 3, 0, 0});
890   ASSERT_EQ(m.Invoke(), kTfLiteOk);
891   EXPECT_THAT(m.template GetDequantizedOutput<integer_type>(),
892               ElementsAreArray(DequantizedArrayNear(
893                   {-0.5, -0.8, 0.2,  0.9,  -0.5, -0.5, -0.5, -0.5, 0.7,  0.1,
894                    -0.3, -0.5, -0.5, -0.5, -0.5, -0.5, -0.5, -0.5, -0.5, -0.5,
895                    -0.5, -0.5, -0.5, -0.5, -0.5, -0.5, -0.5, -0.5},
896                   -1.0, 1.0)));
897   EXPECT_THAT(m.GetOutputShape(), ElementsAreArray({1, 4, 7, 1}));
898 }
899 
TEST_F(QuantizedPadV2OpTest,UInt8AdvancedDynamicValuedTest)900 TEST_F(QuantizedPadV2OpTest, UInt8AdvancedDynamicValuedTest) {
901   AdvancedDynamicValuedTest<uint8_t, TensorType_UINT8>();
902 }
TEST_F(QuantizedPadV2OpTest,Int8AdvancedDynamicValuedTest)903 TEST_F(QuantizedPadV2OpTest, Int8AdvancedDynamicValuedTest) {
904   AdvancedDynamicValuedTest<int8_t, TensorType_INT8>();
905 }
906 
907 }  // namespace
908 }  // namespace tflite
909