blob: 1a7dd4cbb70304f098ea8ccd87221a5618509fa9 [file] [log] [blame]
Georgios Pinitasdc460f12017-08-24 19:02:44 +01001/*
2 * Copyright (c) 2017 ARM Limited.
3 *
4 * SPDX-License-Identifier: MIT
5 *
6 * Permission is hereby granted, free of charge, to any person obtaining a copy
7 * of this software and associated documentation files (the "Software"), to
8 * deal in the Software without restriction, including without limitation the
9 * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
10 * sell copies of the Software, and to permit persons to whom the Software is
11 * furnished to do so, subject to the following conditions:
12 *
13 * The above copyright notice and this permission notice shall be included in all
14 * copies or substantial portions of the Software.
15 *
16 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
22 * SOFTWARE.
23 */
24#include "PoolingLayer.h"
25
Georgios Pinitas583137c2017-08-31 18:12:42 +010026#include "arm_compute/core/Types.h"
Moritz Pflanzera09de0c2017-09-01 20:41:12 +010027#include "tests/validation/FixedPoint.h"
Anton Lokhmotovaf6204c2017-11-08 09:34:19 +000028#include "tests/validation/Helpers.h"
Georgios Pinitasdc460f12017-08-24 19:02:44 +010029
30namespace arm_compute
31{
32namespace test
33{
34namespace validation
35{
36namespace reference
37{
38namespace
39{
40TensorShape calculate_output_shape(TensorShape shape, PoolingLayerInfo info)
41{
42 TensorShape dst_shape = shape;
Georgios Pinitas4c2dd542017-11-13 12:58:41 +000043 const int pool_size = info.is_global_pooling() ? shape.x() : info.pool_size();
Georgios Pinitasdc460f12017-08-24 19:02:44 +010044 const std::pair<unsigned int, unsigned int> scaled_dims = arm_compute::scaled_dimensions(shape.x(),
45 shape.y(),
Georgios Pinitas4c2dd542017-11-13 12:58:41 +000046 pool_size,
47 pool_size,
Georgios Pinitasdc460f12017-08-24 19:02:44 +010048 info.pad_stride_info());
49 dst_shape.set(0, scaled_dims.first);
50 dst_shape.set(1, scaled_dims.second);
51
52 return dst_shape;
53}
54} // namespace
55
56template <typename T, typename std::enable_if<is_floating_point<T>::value, int>::type>
57SimpleTensor<T> pooling_layer(const SimpleTensor<T> &src, PoolingLayerInfo info)
58{
Georgios Pinitas4c2dd542017-11-13 12:58:41 +000059 ARM_COMPUTE_ERROR_ON(info.is_global_pooling() && (src.shape().x() != src.shape().y()));
60
61 const int pool_size = info.is_global_pooling() ? src.shape().x() : info.pool_size();
Georgios Pinitasadaae7e2017-10-30 15:56:32 +000062 PoolingType type = info.pool_type();
63 int pool_stride_x = info.pad_stride_info().stride().first;
64 int pool_stride_y = info.pad_stride_info().stride().second;
65 int pad_x = info.pad_stride_info().pad().first;
66 int pad_y = info.pad_stride_info().pad().second;
67 bool exclude_padding = info.exclude_padding();
Georgios Pinitasdc460f12017-08-24 19:02:44 +010068
69 const auto w_src = static_cast<int>(src.shape()[0]);
70 const auto h_src = static_cast<int>(src.shape()[1]);
71 const int upper_dims = src.shape().total_size() / (w_src * h_src);
72
73 // Create reference
74 SimpleTensor<T> dst{ calculate_output_shape(src.shape(), info), src.data_type(), 1, src.fixed_point_position() };
75
76 const auto w_dst = static_cast<int>(dst.shape()[0]);
77 const auto h_dst = static_cast<int>(dst.shape()[1]);
78
79 if(type == PoolingType::MAX)
80 {
81 for(int r = 0; r < upper_dims; ++r)
82 {
83 for(int h = 0; h < h_dst; ++h)
84 {
85 for(int w = 0; w < w_dst; ++w)
86 {
87 int wstart = w * pool_stride_x - pad_x;
88 int hstart = h * pool_stride_y - pad_y;
89 int wend = std::min(wstart + pool_size, w_src);
90 int hend = std::min(hstart + pool_size, h_src);
91 wstart = std::max(wstart, 0);
92 hstart = std::max(hstart, 0);
93
94 T max_val = std::numeric_limits<T>::lowest();
95 for(int y = hstart; y < hend; ++y)
96 {
97 for(int x = wstart; x < wend; ++x)
98 {
99 const T val = src[r * h_src * w_src + y * w_src + x];
100 if(val > max_val)
101 {
102 max_val = val;
103 }
104 }
105 }
106
107 dst[r * h_dst * w_dst + h * w_dst + w] = max_val;
108 }
109 }
110 }
111 }
Georgios Pinitascdf51452017-08-31 14:21:36 +0100112 else // Average or l2 pooling
Georgios Pinitasdc460f12017-08-24 19:02:44 +0100113 {
114 for(int r = 0; r < upper_dims; ++r)
115 {
116 for(int h = 0; h < h_dst; ++h)
117 {
118 for(int w = 0; w < w_dst; ++w)
119 {
120 T avg_val(0);
121 int wstart = w * pool_stride_x - pad_x;
122 int hstart = h * pool_stride_y - pad_y;
123 int wend = std::min(wstart + pool_size, w_src + pad_x);
124 int hend = std::min(hstart + pool_size, h_src + pad_y);
125 int pool = (hend - hstart) * (wend - wstart);
126 wstart = std::max(wstart, 0);
127 hstart = std::max(hstart, 0);
128 wend = std::min(wend, w_src);
129 hend = std::min(hend, h_src);
Georgios Pinitasadaae7e2017-10-30 15:56:32 +0000130 // Exclude padding pixels from the average
131 if(exclude_padding)
132 {
133 pool = (hend - hstart) * (wend - wstart);
134 }
Georgios Pinitasdc460f12017-08-24 19:02:44 +0100135
Georgios Pinitascdf51452017-08-31 14:21:36 +0100136 if(type == PoolingType::AVG)
Georgios Pinitasdc460f12017-08-24 19:02:44 +0100137 {
Georgios Pinitascdf51452017-08-31 14:21:36 +0100138 for(int y = hstart; y < hend; ++y)
Georgios Pinitasdc460f12017-08-24 19:02:44 +0100139 {
Georgios Pinitascdf51452017-08-31 14:21:36 +0100140 for(int x = wstart; x < wend; ++x)
141 {
142 avg_val += src[r * h_src * w_src + y * w_src + x];
143 }
Georgios Pinitasdc460f12017-08-24 19:02:44 +0100144 }
Georgios Pinitascdf51452017-08-31 14:21:36 +0100145 dst[r * h_dst * w_dst + h * w_dst + w] = avg_val / pool;
Georgios Pinitasdc460f12017-08-24 19:02:44 +0100146 }
Georgios Pinitascdf51452017-08-31 14:21:36 +0100147 else
148 {
149 for(int y = hstart; y < hend; ++y)
150 {
151 for(int x = wstart; x < wend; ++x)
152 {
153 const T val = src[r * h_src * w_src + y * w_src + x];
154 avg_val += val * val;
155 }
156 }
157 dst[r * h_dst * w_dst + h * w_dst + w] = std::sqrt(avg_val / pool);
158 }
Georgios Pinitasdc460f12017-08-24 19:02:44 +0100159 }
160 }
161 }
162 }
163
164 return dst;
165}
166
167template <typename T, typename std::enable_if<std::is_integral<T>::value, int>::type>
168SimpleTensor<T> pooling_layer(const SimpleTensor<T> &src, PoolingLayerInfo info)
169{
Georgios Pinitas4c2dd542017-11-13 12:58:41 +0000170 ARM_COMPUTE_ERROR_ON(info.is_global_pooling() && (src.shape().x() != src.shape().y()));
171
172 const int pool_size = info.is_global_pooling() ? src.shape().x() : info.pool_size();
Georgios Pinitasadaae7e2017-10-30 15:56:32 +0000173 PoolingType type = info.pool_type();
174 int pool_stride_x = info.pad_stride_info().stride().first;
175 int pool_stride_y = info.pad_stride_info().stride().second;
176 int pad_x = info.pad_stride_info().pad().first;
177 int pad_y = info.pad_stride_info().pad().second;
178 bool exclude_padding = info.exclude_padding();
Georgios Pinitasdc460f12017-08-24 19:02:44 +0100179
180 const auto w_src = static_cast<int>(src.shape()[0]);
181 const auto h_src = static_cast<int>(src.shape()[1]);
182 const int upper_dims = src.shape().total_size() / (w_src * h_src);
183
184 // Create reference
185 SimpleTensor<T> dst{ calculate_output_shape(src.shape(), info), src.data_type(), 1, src.fixed_point_position() };
186
187 const auto w_dst = static_cast<int>(dst.shape()[0]);
188 const auto h_dst = static_cast<int>(dst.shape()[1]);
189
190 if(type == PoolingType::MAX)
191 {
192 for(int r = 0; r < upper_dims; ++r)
193 {
194 for(int h = 0; h < h_dst; ++h)
195 {
196 for(int w = 0; w < w_dst; ++w)
197 {
198 int wstart = w * pool_stride_x - pad_x;
199 int hstart = h * pool_stride_y - pad_y;
200 int wend = std::min(wstart + pool_size, w_src);
201 int hend = std::min(hstart + pool_size, h_src);
202 wstart = std::max(wstart, 0);
203 hstart = std::max(hstart, 0);
204
205 T max_val = std::numeric_limits<T>::lowest();
206 for(int y = hstart; y < hend; ++y)
207 {
208 for(int x = wstart; x < wend; ++x)
209 {
210 const T val = src[r * h_src * w_src + y * w_src + x];
211 if(val > max_val)
212 {
213 max_val = val;
214 }
215 }
216 }
217
218 dst[r * h_dst * w_dst + h * w_dst + w] = max_val;
219 }
220 }
221 }
222 }
Georgios Pinitascdf51452017-08-31 14:21:36 +0100223 else // Average or l2 pooling
Georgios Pinitasdc460f12017-08-24 19:02:44 +0100224 {
225 for(int r = 0; r < upper_dims; ++r)
226 {
227 for(int h = 0; h < h_dst; ++h)
228 {
229 for(int w = 0; w < w_dst; ++w)
230 {
231 int wstart = w * pool_stride_x - pad_x;
232 int hstart = h * pool_stride_y - pad_y;
233 int wend = std::min(wstart + pool_size, w_src + pad_x);
234 int hend = std::min(hstart + pool_size, h_src + pad_y);
235 int pool = (hend - hstart) * (wend - wstart);
236 wstart = std::max(wstart, 0);
237 hstart = std::max(hstart, 0);
238 wend = std::min(wend, w_src);
239 hend = std::min(hend, h_src);
Georgios Pinitasadaae7e2017-10-30 15:56:32 +0000240 // Exclude padding pixels from the average
241 if(exclude_padding)
242 {
243 pool = (hend - hstart) * (wend - wstart);
244 }
Georgios Pinitasdc460f12017-08-24 19:02:44 +0100245
246 using namespace fixed_point_arithmetic;
247
248 const int fixed_point_position = src.fixed_point_position();
Georgios Pinitascdf51452017-08-31 14:21:36 +0100249 const fixed_point<T> const_1(1, fixed_point_position);
Georgios Pinitasdc460f12017-08-24 19:02:44 +0100250 const fixed_point<T> invpool_fp(1.f / static_cast<float>(pool), fixed_point_position);
251 fixed_point<T> avg_val(0, fixed_point_position, true);
252
Georgios Pinitascdf51452017-08-31 14:21:36 +0100253 if(type == PoolingType::AVG)
Georgios Pinitasdc460f12017-08-24 19:02:44 +0100254 {
Georgios Pinitascdf51452017-08-31 14:21:36 +0100255 for(int y = hstart; y < hend; ++y)
Georgios Pinitasdc460f12017-08-24 19:02:44 +0100256 {
Georgios Pinitascdf51452017-08-31 14:21:36 +0100257 for(int x = wstart; x < wend; ++x)
258 {
259 const fixed_point<T> in_fp(src[r * h_src * w_src + y * w_src + x], fixed_point_position, true);
260 avg_val = add(avg_val, in_fp);
261 }
Georgios Pinitasdc460f12017-08-24 19:02:44 +0100262 }
Georgios Pinitascdf51452017-08-31 14:21:36 +0100263 dst[r * h_dst * w_dst + h * w_dst + w] = mul(avg_val, invpool_fp).raw();
Georgios Pinitasdc460f12017-08-24 19:02:44 +0100264 }
Georgios Pinitascdf51452017-08-31 14:21:36 +0100265 else
266 {
267 for(int y = hstart; y < hend; ++y)
268 {
269 for(int x = wstart; x < wend; ++x)
270 {
271 const fixed_point<T> in_fp(src[r * h_src * w_src + y * w_src + x], fixed_point_position, true);
272 avg_val = add(avg_val, mul(in_fp, in_fp));
273 }
274 }
275 auto res = div(const_1, (inv_sqrt(mul(avg_val, invpool_fp))));
276 dst[r * h_dst * w_dst + h * w_dst + w] = res.raw();
277 }
Georgios Pinitasdc460f12017-08-24 19:02:44 +0100278 }
279 }
280 }
281 }
282
283 return dst;
284}
285
Anton Lokhmotovaf6204c2017-11-08 09:34:19 +0000286template <>
287SimpleTensor<uint8_t> pooling_layer<uint8_t>(const SimpleTensor<uint8_t> &src, PoolingLayerInfo info)
288{
289 SimpleTensor<float> src_tmp = convert_from_asymmetric(src);
290 SimpleTensor<float> dst_tmp = pooling_layer<float>(src_tmp, info);
291 SimpleTensor<uint8_t> dst = convert_to_asymmetric(dst_tmp, src.quantization_info());
292 return dst;
293}
294
Georgios Pinitasdc460f12017-08-24 19:02:44 +0100295template SimpleTensor<float> pooling_layer(const SimpleTensor<float> &src, PoolingLayerInfo info);
Georgios Pinitas583137c2017-08-31 18:12:42 +0100296template SimpleTensor<half> pooling_layer(const SimpleTensor<half> &src, PoolingLayerInfo info);
Georgios Pinitasdc460f12017-08-24 19:02:44 +0100297template SimpleTensor<qint8_t> pooling_layer(const SimpleTensor<qint8_t> &src, PoolingLayerInfo info);
298template SimpleTensor<qint16_t> pooling_layer(const SimpleTensor<qint16_t> &src, PoolingLayerInfo info);
299} // namespace reference
300} // namespace validation
301} // namespace test
302} // namespace arm_compute