blob: 4f755ce2c4329033405c57608156e7594307ca3e [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"
Georgios Pinitasdc460f12017-08-24 19:02:44 +010028
29namespace arm_compute
30{
31namespace test
32{
33namespace validation
34{
35namespace reference
36{
37namespace
38{
39TensorShape calculate_output_shape(TensorShape shape, PoolingLayerInfo info)
40{
41 TensorShape dst_shape = shape;
42 const std::pair<unsigned int, unsigned int> scaled_dims = arm_compute::scaled_dimensions(shape.x(),
43 shape.y(),
44 info.pool_size(),
45 info.pool_size(),
46 info.pad_stride_info());
47 dst_shape.set(0, scaled_dims.first);
48 dst_shape.set(1, scaled_dims.second);
49
50 return dst_shape;
51}
52} // namespace
53
54template <typename T, typename std::enable_if<is_floating_point<T>::value, int>::type>
55SimpleTensor<T> pooling_layer(const SimpleTensor<T> &src, PoolingLayerInfo info)
56{
Georgios Pinitasadaae7e2017-10-30 15:56:32 +000057 const int pool_size = info.pool_size();
58 PoolingType type = info.pool_type();
59 int pool_stride_x = info.pad_stride_info().stride().first;
60 int pool_stride_y = info.pad_stride_info().stride().second;
61 int pad_x = info.pad_stride_info().pad().first;
62 int pad_y = info.pad_stride_info().pad().second;
63 bool exclude_padding = info.exclude_padding();
Georgios Pinitasdc460f12017-08-24 19:02:44 +010064
65 const auto w_src = static_cast<int>(src.shape()[0]);
66 const auto h_src = static_cast<int>(src.shape()[1]);
67 const int upper_dims = src.shape().total_size() / (w_src * h_src);
68
69 // Create reference
70 SimpleTensor<T> dst{ calculate_output_shape(src.shape(), info), src.data_type(), 1, src.fixed_point_position() };
71
72 const auto w_dst = static_cast<int>(dst.shape()[0]);
73 const auto h_dst = static_cast<int>(dst.shape()[1]);
74
75 if(type == PoolingType::MAX)
76 {
77 for(int r = 0; r < upper_dims; ++r)
78 {
79 for(int h = 0; h < h_dst; ++h)
80 {
81 for(int w = 0; w < w_dst; ++w)
82 {
83 int wstart = w * pool_stride_x - pad_x;
84 int hstart = h * pool_stride_y - pad_y;
85 int wend = std::min(wstart + pool_size, w_src);
86 int hend = std::min(hstart + pool_size, h_src);
87 wstart = std::max(wstart, 0);
88 hstart = std::max(hstart, 0);
89
90 T max_val = std::numeric_limits<T>::lowest();
91 for(int y = hstart; y < hend; ++y)
92 {
93 for(int x = wstart; x < wend; ++x)
94 {
95 const T val = src[r * h_src * w_src + y * w_src + x];
96 if(val > max_val)
97 {
98 max_val = val;
99 }
100 }
101 }
102
103 dst[r * h_dst * w_dst + h * w_dst + w] = max_val;
104 }
105 }
106 }
107 }
Georgios Pinitascdf51452017-08-31 14:21:36 +0100108 else // Average or l2 pooling
Georgios Pinitasdc460f12017-08-24 19:02:44 +0100109 {
110 for(int r = 0; r < upper_dims; ++r)
111 {
112 for(int h = 0; h < h_dst; ++h)
113 {
114 for(int w = 0; w < w_dst; ++w)
115 {
116 T avg_val(0);
117 int wstart = w * pool_stride_x - pad_x;
118 int hstart = h * pool_stride_y - pad_y;
119 int wend = std::min(wstart + pool_size, w_src + pad_x);
120 int hend = std::min(hstart + pool_size, h_src + pad_y);
121 int pool = (hend - hstart) * (wend - wstart);
122 wstart = std::max(wstart, 0);
123 hstart = std::max(hstart, 0);
124 wend = std::min(wend, w_src);
125 hend = std::min(hend, h_src);
Georgios Pinitasadaae7e2017-10-30 15:56:32 +0000126 // Exclude padding pixels from the average
127 if(exclude_padding)
128 {
129 pool = (hend - hstart) * (wend - wstart);
130 }
Georgios Pinitasdc460f12017-08-24 19:02:44 +0100131
Georgios Pinitascdf51452017-08-31 14:21:36 +0100132 if(type == PoolingType::AVG)
Georgios Pinitasdc460f12017-08-24 19:02:44 +0100133 {
Georgios Pinitascdf51452017-08-31 14:21:36 +0100134 for(int y = hstart; y < hend; ++y)
Georgios Pinitasdc460f12017-08-24 19:02:44 +0100135 {
Georgios Pinitascdf51452017-08-31 14:21:36 +0100136 for(int x = wstart; x < wend; ++x)
137 {
138 avg_val += src[r * h_src * w_src + y * w_src + x];
139 }
Georgios Pinitasdc460f12017-08-24 19:02:44 +0100140 }
Georgios Pinitascdf51452017-08-31 14:21:36 +0100141 dst[r * h_dst * w_dst + h * w_dst + w] = avg_val / pool;
Georgios Pinitasdc460f12017-08-24 19:02:44 +0100142 }
Georgios Pinitascdf51452017-08-31 14:21:36 +0100143 else
144 {
145 for(int y = hstart; y < hend; ++y)
146 {
147 for(int x = wstart; x < wend; ++x)
148 {
149 const T val = src[r * h_src * w_src + y * w_src + x];
150 avg_val += val * val;
151 }
152 }
153 dst[r * h_dst * w_dst + h * w_dst + w] = std::sqrt(avg_val / pool);
154 }
Georgios Pinitasdc460f12017-08-24 19:02:44 +0100155 }
156 }
157 }
158 }
159
160 return dst;
161}
162
163template <typename T, typename std::enable_if<std::is_integral<T>::value, int>::type>
164SimpleTensor<T> pooling_layer(const SimpleTensor<T> &src, PoolingLayerInfo info)
165{
Georgios Pinitasadaae7e2017-10-30 15:56:32 +0000166 const int pool_size = info.pool_size();
167 PoolingType type = info.pool_type();
168 int pool_stride_x = info.pad_stride_info().stride().first;
169 int pool_stride_y = info.pad_stride_info().stride().second;
170 int pad_x = info.pad_stride_info().pad().first;
171 int pad_y = info.pad_stride_info().pad().second;
172 bool exclude_padding = info.exclude_padding();
Georgios Pinitasdc460f12017-08-24 19:02:44 +0100173
174 const auto w_src = static_cast<int>(src.shape()[0]);
175 const auto h_src = static_cast<int>(src.shape()[1]);
176 const int upper_dims = src.shape().total_size() / (w_src * h_src);
177
178 // Create reference
179 SimpleTensor<T> dst{ calculate_output_shape(src.shape(), info), src.data_type(), 1, src.fixed_point_position() };
180
181 const auto w_dst = static_cast<int>(dst.shape()[0]);
182 const auto h_dst = static_cast<int>(dst.shape()[1]);
183
184 if(type == PoolingType::MAX)
185 {
186 for(int r = 0; r < upper_dims; ++r)
187 {
188 for(int h = 0; h < h_dst; ++h)
189 {
190 for(int w = 0; w < w_dst; ++w)
191 {
192 int wstart = w * pool_stride_x - pad_x;
193 int hstart = h * pool_stride_y - pad_y;
194 int wend = std::min(wstart + pool_size, w_src);
195 int hend = std::min(hstart + pool_size, h_src);
196 wstart = std::max(wstart, 0);
197 hstart = std::max(hstart, 0);
198
199 T max_val = std::numeric_limits<T>::lowest();
200 for(int y = hstart; y < hend; ++y)
201 {
202 for(int x = wstart; x < wend; ++x)
203 {
204 const T val = src[r * h_src * w_src + y * w_src + x];
205 if(val > max_val)
206 {
207 max_val = val;
208 }
209 }
210 }
211
212 dst[r * h_dst * w_dst + h * w_dst + w] = max_val;
213 }
214 }
215 }
216 }
Georgios Pinitascdf51452017-08-31 14:21:36 +0100217 else // Average or l2 pooling
Georgios Pinitasdc460f12017-08-24 19:02:44 +0100218 {
219 for(int r = 0; r < upper_dims; ++r)
220 {
221 for(int h = 0; h < h_dst; ++h)
222 {
223 for(int w = 0; w < w_dst; ++w)
224 {
225 int wstart = w * pool_stride_x - pad_x;
226 int hstart = h * pool_stride_y - pad_y;
227 int wend = std::min(wstart + pool_size, w_src + pad_x);
228 int hend = std::min(hstart + pool_size, h_src + pad_y);
229 int pool = (hend - hstart) * (wend - wstart);
230 wstart = std::max(wstart, 0);
231 hstart = std::max(hstart, 0);
232 wend = std::min(wend, w_src);
233 hend = std::min(hend, h_src);
Georgios Pinitasadaae7e2017-10-30 15:56:32 +0000234 // Exclude padding pixels from the average
235 if(exclude_padding)
236 {
237 pool = (hend - hstart) * (wend - wstart);
238 }
Georgios Pinitasdc460f12017-08-24 19:02:44 +0100239
240 using namespace fixed_point_arithmetic;
241
242 const int fixed_point_position = src.fixed_point_position();
Georgios Pinitascdf51452017-08-31 14:21:36 +0100243 const fixed_point<T> const_1(1, fixed_point_position);
Georgios Pinitasdc460f12017-08-24 19:02:44 +0100244 const fixed_point<T> invpool_fp(1.f / static_cast<float>(pool), fixed_point_position);
245 fixed_point<T> avg_val(0, fixed_point_position, true);
246
Georgios Pinitascdf51452017-08-31 14:21:36 +0100247 if(type == PoolingType::AVG)
Georgios Pinitasdc460f12017-08-24 19:02:44 +0100248 {
Georgios Pinitascdf51452017-08-31 14:21:36 +0100249 for(int y = hstart; y < hend; ++y)
Georgios Pinitasdc460f12017-08-24 19:02:44 +0100250 {
Georgios Pinitascdf51452017-08-31 14:21:36 +0100251 for(int x = wstart; x < wend; ++x)
252 {
253 const fixed_point<T> in_fp(src[r * h_src * w_src + y * w_src + x], fixed_point_position, true);
254 avg_val = add(avg_val, in_fp);
255 }
Georgios Pinitasdc460f12017-08-24 19:02:44 +0100256 }
Georgios Pinitascdf51452017-08-31 14:21:36 +0100257 dst[r * h_dst * w_dst + h * w_dst + w] = mul(avg_val, invpool_fp).raw();
Georgios Pinitasdc460f12017-08-24 19:02:44 +0100258 }
Georgios Pinitascdf51452017-08-31 14:21:36 +0100259 else
260 {
261 for(int y = hstart; y < hend; ++y)
262 {
263 for(int x = wstart; x < wend; ++x)
264 {
265 const fixed_point<T> in_fp(src[r * h_src * w_src + y * w_src + x], fixed_point_position, true);
266 avg_val = add(avg_val, mul(in_fp, in_fp));
267 }
268 }
269 auto res = div(const_1, (inv_sqrt(mul(avg_val, invpool_fp))));
270 dst[r * h_dst * w_dst + h * w_dst + w] = res.raw();
271 }
Georgios Pinitasdc460f12017-08-24 19:02:44 +0100272 }
273 }
274 }
275 }
276
277 return dst;
278}
279
280template SimpleTensor<float> pooling_layer(const SimpleTensor<float> &src, PoolingLayerInfo info);
Georgios Pinitas583137c2017-08-31 18:12:42 +0100281template SimpleTensor<half> pooling_layer(const SimpleTensor<half> &src, PoolingLayerInfo info);
Georgios Pinitasdc460f12017-08-24 19:02:44 +0100282template SimpleTensor<qint8_t> pooling_layer(const SimpleTensor<qint8_t> &src, PoolingLayerInfo info);
283template SimpleTensor<qint16_t> pooling_layer(const SimpleTensor<qint16_t> &src, PoolingLayerInfo info);
284} // namespace reference
285} // namespace validation
286} // namespace test
287} // namespace arm_compute