• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /* Copyright 2019 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 <algorithm>
16 #include <cmath>
17 #include <cstdlib>
18 #include <functional>
19 #include <iterator>
20 #include <limits>
21 #include <random>
22 #include <string>
23 #include <vector>
24 
25 #include <gtest/gtest.h>
26 #include "tensorflow/lite/kernels/internal/optimized/integer_ops/pooling.h"
27 #include "tensorflow/lite/kernels/internal/reference/integer_ops/pooling.h"
28 #include "tensorflow/lite/kernels/internal/test_util.h"
29 
30 namespace tflite {
31 namespace {
32 
33 // Runs the reference and optimized AveragePool functions and asserts the values
34 // are the same.
RunOneAveragePoolTest(const PoolParams & params,const RuntimeShape & input_shape,const int8 * input_data,const RuntimeShape & output_shape)35 void RunOneAveragePoolTest(const PoolParams& params,
36                            const RuntimeShape& input_shape,
37                            const int8* input_data,
38                            const RuntimeShape& output_shape) {
39   const int buffer_size = output_shape.FlatSize();
40   std::vector<int8> optimized_averagePool_output(buffer_size);
41   std::vector<int8> reference_averagePool_output(buffer_size);
42 
43   reference_integer_ops::AveragePool(params, input_shape, input_data,
44                                      output_shape,
45                                      reference_averagePool_output.data());
46   optimized_integer_ops::AveragePool(params, input_shape, input_data,
47                                      output_shape,
48                                      optimized_averagePool_output.data());
49 
50   for (int i = 0; i < buffer_size; i++) {
51     EXPECT_TRUE(reference_averagePool_output[i] ==
52                 optimized_averagePool_output[i]);
53   }
54 }
55 
56 // Creates random input shape (batch, height, width, depth), then computes
57 // output shape based on value of `padding_same`:
58 // `padding_same` == true, calculate output with padding == "SAME"
59 // `padding_same` == false, calculate output with padding == "VALID"
60 // With input/output shapes computed, fills the input data and calls the
61 // test function.
CreateDataAndRunAveragePool(bool padding_same)62 void CreateDataAndRunAveragePool(bool padding_same) {
63   const int batch = UniformRandomInt(1, 2);
64   const int input_depth = UniformRandomInt(1, 700);
65   const int output_depth = input_depth;
66   const int input_width_offset = UniformRandomInt(1, 30);
67   const int input_height_offset = UniformRandomInt(1, 30);
68   const int stride_width = UniformRandomInt(1, 10);
69   const int stride_height = UniformRandomInt(1, 10);
70   const int filter_width = UniformRandomInt(1, 10);
71   const int filter_height = UniformRandomInt(1, 10);
72   const int input_width = input_width_offset + filter_width;
73   const int input_height = input_height_offset + filter_height;
74   const int output_width =
75       padding_same ? (input_width + stride_width - 1) / stride_width
76                    : (input_width - filter_width + stride_width) / stride_width;
77   const int output_height =
78       padding_same
79           ? (input_height + stride_height - 1) / stride_height
80           : (input_height - filter_height + stride_height) / stride_height;
81 
82   auto input_shape =
83       RuntimeShape({batch, input_height, input_width, input_depth});
84   auto output_shape =
85       RuntimeShape({batch, output_height, output_width, output_depth});
86   const int buffer_size = input_shape.FlatSize();
87   std::vector<int8> input_data(buffer_size);
88   FillRandom(&input_data);
89 
90   PoolParams params;
91   params.stride_height = stride_height;
92   params.stride_width = stride_width;
93   params.filter_height = filter_height;
94   params.filter_width = filter_width;
95   params.quantized_activation_min =
96       static_cast<int8_t>(std::numeric_limits<int8_t>::lowest());
97   params.quantized_activation_max =
98       static_cast<int8_t>(std::numeric_limits<int8_t>::max());
99   auto compute_padding = [](int stride, int in_size, int filter_size,
100                             int out_size) {
101     int padding = ((out_size - 1) * stride + filter_size - in_size) / 2;
102     return padding > 0 ? padding : 0;
103   };
104   params.padding_values.width =
105       compute_padding(stride_width, input_width, filter_width, output_width);
106   params.padding_values.height = compute_padding(stride_height, input_height,
107                                                  filter_height, output_height);
108   RunOneAveragePoolTest(params, input_shape, input_data.data(), output_shape);
109 }
110 
TEST(TestAveragePool,SymmetricQuantAveragePool)111 TEST(TestAveragePool, SymmetricQuantAveragePool) {
112   const int kTestsToRun = 10;
113   for (int i = 0; i < kTestsToRun; i++) {
114     CreateDataAndRunAveragePool(/*padding_same=*/true);
115     CreateDataAndRunAveragePool(/*padding_same=*/false);
116   }
117 }
118 
119 // Creates random input shape (batch, height, width, depth), then computes
120 // output shape based on value of `padding_same`:
121 // `padding_same` == true, calculate output with padding == "SAME"
122 // `padding_same` == false, calculate output with padding == "VALID"
123 // With input/output shapes computed, fills the input data and calls the
124 // test function.
CreateExtremalDataAndRunAveragePool(bool padding_same)125 void CreateExtremalDataAndRunAveragePool(bool padding_same) {
126   const int batch = UniformRandomInt(1, 2);
127   const int input_depth = UniformRandomInt(1, 700);
128   const int output_depth = input_depth;
129   const int input_width_offset = UniformRandomInt(1, 30);
130   const int input_height_offset = UniformRandomInt(1, 30);
131   const int stride_width = UniformRandomInt(1, 128);
132   const int stride_height = UniformRandomInt(1, 128);
133   const int filter_width = UniformRandomInt(1, 28);
134   const int filter_height = UniformRandomInt(1, 28);
135   if (filter_width * filter_height > 64) {
136     std::cout << "should test 32 version" << std::endl;
137   }
138   const int input_width = input_width_offset + filter_width;
139   const int input_height = input_height_offset + filter_height;
140   const int output_width =
141       padding_same ? (input_width + stride_width - 1) / stride_width
142                    : (input_width - filter_width + stride_width) / stride_width;
143   const int output_height =
144       padding_same
145           ? (input_height + stride_height - 1) / stride_height
146           : (input_height - filter_height + stride_height) / stride_height;
147 
148   auto input_shape =
149       RuntimeShape({batch, input_height, input_width, input_depth});
150   auto output_shape =
151       RuntimeShape({batch, output_height, output_width, output_depth});
152 
153   PoolParams params;
154   params.stride_height = stride_height;
155   params.stride_width = stride_width;
156   params.filter_height = filter_height;
157   params.filter_width = filter_width;
158   params.quantized_activation_min =
159       static_cast<int8_t>(std::numeric_limits<int8_t>::lowest());
160   params.quantized_activation_max =
161       static_cast<int8_t>(std::numeric_limits<int8_t>::max());
162   auto compute_padding = [](int stride, int in_size, int filter_size,
163                             int out_size) {
164     int padding = ((out_size - 1) * stride + filter_size - in_size) / 2;
165     return padding > 0 ? padding : 0;
166   };
167   params.padding_values.width =
168       compute_padding(stride_width, input_width, filter_width, output_width);
169   params.padding_values.height = compute_padding(stride_height, input_height,
170                                                  filter_height, output_height);
171 
172   const int buffer_size = input_shape.FlatSize();
173   std::vector<int8> input_data(buffer_size);
174 
175   // Test small values
176   int8 min = std::numeric_limits<int8>::min();
177   int8 max = std::numeric_limits<int8>::min() + 10;
178   FillRandom(&input_data, min, max);
179   RunOneAveragePoolTest(params, input_shape, input_data.data(), output_shape);
180 
181   // Test large values
182   min = std::numeric_limits<int8>::max() - 10;
183   max = std::numeric_limits<int8>::max();
184   FillRandom(&input_data, min, max);
185   RunOneAveragePoolTest(params, input_shape, input_data.data(), output_shape);
186 }
187 
TEST(TestAveragePool,SymmetricQuantExtremalAveragePool)188 TEST(TestAveragePool, SymmetricQuantExtremalAveragePool) {
189   CreateExtremalDataAndRunAveragePool(/*padding_same=*/true);
190   CreateExtremalDataAndRunAveragePool(/*padding_same=*/false);
191 }
192 
193 }  // namespace
194 }  // namespace tflite
195