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