1 /* Copyright 2018 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 #ifndef TENSORFLOW_LITE_KERNELS_INTERNAL_REFERENCE_INTEGER_OPS_POOLING_H_
16 #define TENSORFLOW_LITE_KERNELS_INTERNAL_REFERENCE_INTEGER_OPS_POOLING_H_
17
18 #include <algorithm>
19 #include <limits>
20
21 #include "tensorflow/lite/kernels/internal/common.h"
22
23 namespace tflite {
24 namespace reference_integer_ops {
25
AveragePool(const PoolParams & params,const RuntimeShape & input_shape,const int8_t * input_data,const RuntimeShape & output_shape,int8_t * output_data)26 inline bool AveragePool(const PoolParams& params,
27 const RuntimeShape& input_shape,
28 const int8_t* input_data,
29 const RuntimeShape& output_shape, int8_t* output_data) {
30 TFLITE_DCHECK_LE(params.quantized_activation_min,
31 params.quantized_activation_max);
32 TFLITE_DCHECK_EQ(input_shape.DimensionsCount(), 4);
33 TFLITE_DCHECK_EQ(output_shape.DimensionsCount(), 4);
34 const int batches = MatchingDim(input_shape, 0, output_shape, 0);
35 const int depth = MatchingDim(input_shape, 3, output_shape, 3);
36 const int input_height = input_shape.Dims(1);
37 const int input_width = input_shape.Dims(2);
38 const int output_height = output_shape.Dims(1);
39 const int output_width = output_shape.Dims(2);
40 const int stride_height = params.stride_height;
41 const int stride_width = params.stride_width;
42 for (int batch = 0; batch < batches; ++batch) {
43 for (int out_y = 0; out_y < output_height; ++out_y) {
44 for (int out_x = 0; out_x < output_width; ++out_x) {
45 for (int channel = 0; channel < depth; ++channel) {
46 const int in_x_origin =
47 (out_x * stride_width) - params.padding_values.width;
48 const int in_y_origin =
49 (out_y * stride_height) - params.padding_values.height;
50 // Compute the boundaries of the filter region clamped so as to
51 // ensure that the filter window fits in the input array.
52 const int filter_x_start = std::max(0, -in_x_origin);
53 const int filter_x_end =
54 std::min(params.filter_width, input_width - in_x_origin);
55 const int filter_y_start = std::max(0, -in_y_origin);
56 const int filter_y_end =
57 std::min(params.filter_height, input_height - in_y_origin);
58 int32_t acc = 0;
59 int filter_count = 0;
60 for (int filter_y = filter_y_start; filter_y < filter_y_end;
61 ++filter_y) {
62 for (int filter_x = filter_x_start; filter_x < filter_x_end;
63 ++filter_x) {
64 const int in_x = in_x_origin + filter_x;
65 const int in_y = in_y_origin + filter_y;
66 acc +=
67 input_data[Offset(input_shape, batch, in_y, in_x, channel)];
68 filter_count++;
69 }
70 }
71 if (filter_count == 0) return false;
72 // Round to the closest integer value.
73 acc = acc > 0 ? (acc + filter_count / 2) / filter_count
74 : (acc - filter_count / 2) / filter_count;
75 acc = std::max(acc, params.quantized_activation_min);
76 acc = std::min(acc, params.quantized_activation_max);
77 output_data[Offset(output_shape, batch, out_y, out_x, channel)] =
78 static_cast<int8_t>(acc);
79 }
80 }
81 }
82 }
83 return true;
84 }
85
MaxPool(const PoolParams & params,const RuntimeShape & input_shape,const int8_t * input_data,const RuntimeShape & output_shape,int8_t * output_data)86 inline void MaxPool(const PoolParams& params, const RuntimeShape& input_shape,
87 const int8_t* input_data, const RuntimeShape& output_shape,
88 int8_t* output_data) {
89 TFLITE_DCHECK_LE(params.quantized_activation_min,
90 params.quantized_activation_max);
91 TFLITE_DCHECK_GE(params.quantized_activation_min,
92 std::numeric_limits<int8_t>::min());
93 TFLITE_DCHECK_LE(params.quantized_activation_max,
94 std::numeric_limits<int8_t>::max());
95 TFLITE_DCHECK_EQ(input_shape.DimensionsCount(), 4);
96 TFLITE_DCHECK_EQ(output_shape.DimensionsCount(), 4);
97 const int batches = MatchingDim(input_shape, 0, output_shape, 0);
98 const int depth = MatchingDim(input_shape, 3, output_shape, 3);
99 const int input_height = input_shape.Dims(1);
100 const int input_width = input_shape.Dims(2);
101 const int output_height = output_shape.Dims(1);
102 const int output_width = output_shape.Dims(2);
103 const int stride_height = params.stride_height;
104 const int stride_width = params.stride_width;
105 for (int batch = 0; batch < batches; ++batch) {
106 for (int out_y = 0; out_y < output_height; ++out_y) {
107 for (int out_x = 0; out_x < output_width; ++out_x) {
108 for (int channel = 0; channel < depth; ++channel) {
109 const int in_x_origin =
110 (out_x * stride_width) - params.padding_values.width;
111 const int in_y_origin =
112 (out_y * stride_height) - params.padding_values.height;
113 // Compute the boundaries of the filter region clamped so as to
114 // ensure that the filter window fits in the input array.
115 const int filter_x_start = std::max(0, -in_x_origin);
116 const int filter_x_end =
117 std::min(params.filter_width, input_width - in_x_origin);
118 const int filter_y_start = std::max(0, -in_y_origin);
119 const int filter_y_end =
120 std::min(params.filter_height, input_height - in_y_origin);
121 int8_t max = std::numeric_limits<int8_t>::lowest();
122 for (int filter_y = filter_y_start; filter_y < filter_y_end;
123 ++filter_y) {
124 for (int filter_x = filter_x_start; filter_x < filter_x_end;
125 ++filter_x) {
126 const int in_x = in_x_origin + filter_x;
127 const int in_y = in_y_origin + filter_y;
128 max = std::max(
129 max,
130 input_data[Offset(input_shape, batch, in_y, in_x, channel)]);
131 }
132 }
133 max = std::max<int8_t>(max, params.quantized_activation_min);
134 max = std::min<int8_t>(max, params.quantized_activation_max);
135 output_data[Offset(output_shape, batch, out_y, out_x, channel)] =
136 static_cast<int8_t>(max);
137 }
138 }
139 }
140 }
141 }
142
AveragePool(const PoolParams & params,const RuntimeShape & input_shape,const int16_t * input_data,const RuntimeShape & output_shape,int16_t * output_data)143 inline bool AveragePool(const PoolParams& params,
144 const RuntimeShape& input_shape,
145 const int16_t* input_data,
146 const RuntimeShape& output_shape,
147 int16_t* output_data) {
148 TFLITE_DCHECK_LE(params.quantized_activation_min,
149 params.quantized_activation_max);
150 TFLITE_DCHECK_EQ(input_shape.DimensionsCount(), 4);
151 TFLITE_DCHECK_EQ(output_shape.DimensionsCount(), 4);
152 const int batches = MatchingDim(input_shape, 0, output_shape, 0);
153 const int depth = MatchingDim(input_shape, 3, output_shape, 3);
154 const int input_height = input_shape.Dims(1);
155 const int input_width = input_shape.Dims(2);
156 const int output_height = output_shape.Dims(1);
157 const int output_width = output_shape.Dims(2);
158 const int stride_height = params.stride_height;
159 const int stride_width = params.stride_width;
160 for (int batch = 0; batch < batches; ++batch) {
161 for (int out_y = 0; out_y < output_height; ++out_y) {
162 for (int out_x = 0; out_x < output_width; ++out_x) {
163 for (int channel = 0; channel < depth; ++channel) {
164 const int in_x_origin =
165 (out_x * stride_width) - params.padding_values.width;
166 const int in_y_origin =
167 (out_y * stride_height) - params.padding_values.height;
168 // Compute the boundaries of the filter region clamped so as to
169 // ensure that the filter window fits in the input array.
170 const int filter_x_start = std::max(0, -in_x_origin);
171 const int filter_x_end =
172 std::min(params.filter_width, input_width - in_x_origin);
173 const int filter_y_start = std::max(0, -in_y_origin);
174 const int filter_y_end =
175 std::min(params.filter_height, input_height - in_y_origin);
176 int32_t acc = 0;
177 int filter_count = 0;
178 for (int filter_y = filter_y_start; filter_y < filter_y_end;
179 ++filter_y) {
180 for (int filter_x = filter_x_start; filter_x < filter_x_end;
181 ++filter_x) {
182 const int in_x = in_x_origin + filter_x;
183 const int in_y = in_y_origin + filter_y;
184 acc +=
185 input_data[Offset(input_shape, batch, in_y, in_x, channel)];
186 filter_count++;
187 }
188 }
189 if (filter_count == 0) return false;
190 // Round to the closest integer value.
191 acc = acc > 0 ? (acc + filter_count / 2) / filter_count
192 : (acc - filter_count / 2) / filter_count;
193 acc = std::max(acc, params.quantized_activation_min);
194 acc = std::min(acc, params.quantized_activation_max);
195 output_data[Offset(output_shape, batch, out_y, out_x, channel)] =
196 static_cast<int16_t>(acc);
197 }
198 }
199 }
200 }
201 return true;
202 }
203
MaxPool(const PoolParams & params,const RuntimeShape & input_shape,const int16_t * input_data,const RuntimeShape & output_shape,int16_t * output_data)204 inline void MaxPool(const PoolParams& params, const RuntimeShape& input_shape,
205 const int16_t* input_data, const RuntimeShape& output_shape,
206 int16_t* output_data) {
207 TFLITE_DCHECK_LE(params.quantized_activation_min,
208 params.quantized_activation_max);
209 TFLITE_DCHECK_GE(params.quantized_activation_min,
210 std::numeric_limits<int16_t>::min());
211 TFLITE_DCHECK_LE(params.quantized_activation_max,
212 std::numeric_limits<int16_t>::max());
213 TFLITE_DCHECK_EQ(input_shape.DimensionsCount(), 4);
214 TFLITE_DCHECK_EQ(output_shape.DimensionsCount(), 4);
215 const int batches = MatchingDim(input_shape, 0, output_shape, 0);
216 const int depth = MatchingDim(input_shape, 3, output_shape, 3);
217 const int input_height = input_shape.Dims(1);
218 const int input_width = input_shape.Dims(2);
219 const int output_height = output_shape.Dims(1);
220 const int output_width = output_shape.Dims(2);
221 const int stride_height = params.stride_height;
222 const int stride_width = params.stride_width;
223 for (int batch = 0; batch < batches; ++batch) {
224 for (int out_y = 0; out_y < output_height; ++out_y) {
225 for (int out_x = 0; out_x < output_width; ++out_x) {
226 for (int channel = 0; channel < depth; ++channel) {
227 const int in_x_origin =
228 (out_x * stride_width) - params.padding_values.width;
229 const int in_y_origin =
230 (out_y * stride_height) - params.padding_values.height;
231 // Compute the boundaries of the filter region clamped so as to
232 // ensure that the filter window fits in the input array.
233 const int filter_x_start = std::max(0, -in_x_origin);
234 const int filter_x_end =
235 std::min(params.filter_width, input_width - in_x_origin);
236 const int filter_y_start = std::max(0, -in_y_origin);
237 const int filter_y_end =
238 std::min(params.filter_height, input_height - in_y_origin);
239 int16_t max = std::numeric_limits<int16_t>::lowest();
240 for (int filter_y = filter_y_start; filter_y < filter_y_end;
241 ++filter_y) {
242 for (int filter_x = filter_x_start; filter_x < filter_x_end;
243 ++filter_x) {
244 const int in_x = in_x_origin + filter_x;
245 const int in_y = in_y_origin + filter_y;
246 max = std::max(
247 max,
248 input_data[Offset(input_shape, batch, in_y, in_x, channel)]);
249 }
250 }
251 max = std::max<int16_t>(max, params.quantized_activation_min);
252 max = std::min<int16_t>(max, params.quantized_activation_max);
253 output_data[Offset(output_shape, batch, out_y, out_x, channel)] =
254 static_cast<int16_t>(max);
255 }
256 }
257 }
258 }
259 }
260
261 } // namespace reference_integer_ops
262 } // namespace tflite
263
264 #endif // TENSORFLOW_LITE_KERNELS_INTERNAL_REFERENCE_INTEGER_OPS_POOLING_H_
265