• 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 * input_data,const RuntimeShape & output_shape,int8 * output_data)24 inline void AveragePool(const PoolParams& params,
25                         const RuntimeShape& input_shape, const int8* input_data,
26                         const RuntimeShape& output_shape, int8* output_data) {
27   TFLITE_DCHECK_LE(params.quantized_activation_min,
28                    params.quantized_activation_max);
29   TFLITE_DCHECK_EQ(input_shape.DimensionsCount(), 4);
30   TFLITE_DCHECK_EQ(output_shape.DimensionsCount(), 4);
31   const int batches = MatchingDim(input_shape, 0, output_shape, 0);
32   const int depth = MatchingDim(input_shape, 3, output_shape, 3);
33   const int input_height = input_shape.Dims(1);
34   const int input_width = input_shape.Dims(2);
35   const int output_height = output_shape.Dims(1);
36   const int output_width = output_shape.Dims(2);
37   const int stride_height = params.stride_height;
38   const int stride_width = params.stride_width;
39   for (int batch = 0; batch < batches; ++batch) {
40     for (int out_y = 0; out_y < output_height; ++out_y) {
41       for (int out_x = 0; out_x < output_width; ++out_x) {
42         for (int channel = 0; channel < depth; ++channel) {
43           const int in_x_origin =
44               (out_x * stride_width) - params.padding_values.width;
45           const int in_y_origin =
46               (out_y * stride_height) - params.padding_values.height;
47           // Compute the boundaries of the filter region clamped so as to
48           // ensure that the filter window fits in the input array.
49           const int filter_x_start = std::max(0, -in_x_origin);
50           const int filter_x_end =
51               std::min(params.filter_width, input_width - in_x_origin);
52           const int filter_y_start = std::max(0, -in_y_origin);
53           const int filter_y_end =
54               std::min(params.filter_height, input_height - in_y_origin);
55           int32 acc = 0;
56           int filter_count = 0;
57           for (int filter_y = filter_y_start; filter_y < filter_y_end;
58                ++filter_y) {
59             for (int filter_x = filter_x_start; filter_x < filter_x_end;
60                  ++filter_x) {
61               const int in_x = in_x_origin + filter_x;
62               const int in_y = in_y_origin + filter_y;
63               acc +=
64                   input_data[Offset(input_shape, batch, in_y, in_x, channel)];
65               filter_count++;
66             }
67           }
68           // Round to the closest integer value.
69           acc = acc > 0 ? (acc + filter_count / 2) / filter_count
70                         : (acc - filter_count / 2) / filter_count;
71           acc = std::max(acc, params.quantized_activation_min);
72           acc = std::min(acc, params.quantized_activation_max);
73           output_data[Offset(output_shape, batch, out_y, out_x, channel)] =
74               static_cast<int8>(acc);
75         }
76       }
77     }
78   }
79 }
80 
MaxPool(const PoolParams & params,const RuntimeShape & input_shape,const int8 * input_data,const RuntimeShape & output_shape,int8 * output_data)81 inline void MaxPool(const PoolParams& params, const RuntimeShape& input_shape,
82                     const int8* input_data, const RuntimeShape& output_shape,
83                     int8* output_data) {
84   TFLITE_DCHECK_LE(params.quantized_activation_min,
85                    params.quantized_activation_max);
86   TFLITE_DCHECK_GE(params.quantized_activation_min,
87                    std::numeric_limits<int8_t>::min());
88   TFLITE_DCHECK_LE(params.quantized_activation_max,
89                    std::numeric_limits<int8_t>::max());
90   TFLITE_DCHECK_EQ(input_shape.DimensionsCount(), 4);
91   TFLITE_DCHECK_EQ(output_shape.DimensionsCount(), 4);
92   const int batches = MatchingDim(input_shape, 0, output_shape, 0);
93   const int depth = MatchingDim(input_shape, 3, output_shape, 3);
94   const int input_height = input_shape.Dims(1);
95   const int input_width = input_shape.Dims(2);
96   const int output_height = output_shape.Dims(1);
97   const int output_width = output_shape.Dims(2);
98   const int stride_height = params.stride_height;
99   const int stride_width = params.stride_width;
100   for (int batch = 0; batch < batches; ++batch) {
101     for (int out_y = 0; out_y < output_height; ++out_y) {
102       for (int out_x = 0; out_x < output_width; ++out_x) {
103         for (int channel = 0; channel < depth; ++channel) {
104           const int in_x_origin =
105               (out_x * stride_width) - params.padding_values.width;
106           const int in_y_origin =
107               (out_y * stride_height) - params.padding_values.height;
108           // Compute the boundaries of the filter region clamped so as to
109           // ensure that the filter window fits in the input array.
110           const int filter_x_start = std::max(0, -in_x_origin);
111           const int filter_x_end =
112               std::min(params.filter_width, input_width - in_x_origin);
113           const int filter_y_start = std::max(0, -in_y_origin);
114           const int filter_y_end =
115               std::min(params.filter_height, input_height - in_y_origin);
116           int8_t max = std::numeric_limits<int8_t>::lowest();
117           for (int filter_y = filter_y_start; filter_y < filter_y_end;
118                ++filter_y) {
119             for (int filter_x = filter_x_start; filter_x < filter_x_end;
120                  ++filter_x) {
121               const int in_x = in_x_origin + filter_x;
122               const int in_y = in_y_origin + filter_y;
123               max = std::max(
124                   max,
125                   input_data[Offset(input_shape, batch, in_y, in_x, channel)]);
126             }
127           }
128           max = std::max<int8_t>(max, params.quantized_activation_min);
129           max = std::min<int8_t>(max, params.quantized_activation_max);
130           output_data[Offset(output_shape, batch, out_y, out_x, channel)] =
131               static_cast<int8_t>(max);
132         }
133       }
134     }
135   }
136 }
137 
138 }  // namespace reference_integer_ops
139 }  // namespace tflite
140 
141 #endif  // TENSORFLOW_LITE_KERNELS_INTERNAL_REFERENCE_INTEGER_OPS_POOLING_H_
142