xref: /aosp_15_r20/external/tensorflow/tensorflow/lite/kernels/internal/reference/integer_ops/pooling.h (revision b6fb3261f9314811a0f4371741dbb8839866f948)
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