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