• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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