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