• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2016-2022 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 
25 #include "arm_compute/core/Helpers.h"
26 
27 #include "arm_compute/core/Utils.h"
28 
29 #include <algorithm>
30 #include <cmath>
31 #include <cstdint>
32 #include <fstream>
33 #include <map>
34 #include <string>
35 
36 namespace arm_compute
37 {
read_file(const std::string & filename,bool binary)38 std::string read_file(const std::string &filename, bool binary)
39 {
40     std::string   out;
41     std::ifstream fs;
42 
43 #ifndef ARM_COMPUTE_EXCEPTIONS_DISABLED
44     try
45     {
46 #endif /* ARM_COMPUTE_EXCEPTIONS_DISABLED */
47         fs.exceptions(std::ifstream::failbit | std::ifstream::badbit);
48         std::ios_base::openmode mode = std::ios::in;
49 
50         if(binary)
51         {
52             mode |= std::ios::binary;
53         }
54 
55         fs.open(filename, mode);
56 
57         // Go to the end of the file
58         fs.seekg(0, std::ios::end);
59         // Reserve the memory required to store the file's content
60         out.reserve(fs.tellg());
61         // Go back to the beginning of the file
62         fs.seekg(0, std::ios::beg);
63         // Copy the content of the file
64         out.assign(std::istreambuf_iterator<char>(fs), std::istreambuf_iterator<char>());
65 #ifndef ARM_COMPUTE_EXCEPTIONS_DISABLED
66     }
67     catch(const std::ifstream::failure &e)
68     {
69         ARM_COMPUTE_ERROR_VAR("Accessing %s: %s", filename.c_str(), e.what());
70     }
71 #endif /* ARM_COMPUTE_EXCEPTIONS_DISABLED */
72 
73     return out;
74 }
75 
string_from_format(Format format)76 const std::string &string_from_format(Format format)
77 {
78     static std::map<Format, const std::string> formats_map =
79     {
80         { Format::UNKNOWN, "UNKNOWN" },
81         { Format::U8, "U8" },
82         { Format::S16, "S16" },
83         { Format::U16, "U16" },
84         { Format::S32, "S32" },
85         { Format::U32, "U32" },
86         { Format::F16, "F16" },
87         { Format::F32, "F32" },
88         { Format::UV88, "UV88" },
89         { Format::RGB888, "RGB888" },
90         { Format::RGBA8888, "RGBA8888" },
91         { Format::YUV444, "YUV444" },
92         { Format::YUYV422, "YUYV422" },
93         { Format::NV12, "NV12" },
94         { Format::NV21, "NV21" },
95         { Format::IYUV, "IYUV" },
96         { Format::UYVY422, "UYVY422" }
97     };
98 
99     return formats_map[format];
100 }
101 
string_from_channel(Channel channel)102 const std::string &string_from_channel(Channel channel)
103 {
104     static std::map<Channel, const std::string> channels_map =
105     {
106         { Channel::UNKNOWN, "UNKNOWN" },
107         { Channel::R, "R" },
108         { Channel::G, "G" },
109         { Channel::B, "B" },
110         { Channel::A, "A" },
111         { Channel::Y, "Y" },
112         { Channel::U, "U" },
113         { Channel::V, "V" },
114         { Channel::C0, "C0" },
115         { Channel::C1, "C1" },
116         { Channel::C2, "C2" },
117         { Channel::C3, "C3" }
118     };
119 
120     return channels_map[channel];
121 }
122 
string_from_data_layout(DataLayout dl)123 const std::string &string_from_data_layout(DataLayout dl)
124 {
125     static std::map<DataLayout, const std::string> dl_map =
126     {
127         { DataLayout::UNKNOWN, "UNKNOWN" },
128         { DataLayout::NCHW, "NCHW" },
129         { DataLayout::NHWC, "NHWC" },
130     };
131 
132     return dl_map[dl];
133 }
134 
string_from_data_type(DataType dt)135 const std::string &string_from_data_type(DataType dt)
136 {
137     static std::map<DataType, const std::string> dt_map =
138     {
139         { DataType::UNKNOWN, "UNKNOWN" },
140         { DataType::S8, "S8" },
141         { DataType::U8, "U8" },
142         { DataType::S16, "S16" },
143         { DataType::U16, "U16" },
144         { DataType::S32, "S32" },
145         { DataType::U32, "U32" },
146         { DataType::S64, "S64" },
147         { DataType::U64, "U64" },
148         { DataType::F16, "F16" },
149         { DataType::F32, "F32" },
150         { DataType::F64, "F64" },
151         { DataType::SIZET, "SIZET" },
152         { DataType::QSYMM8, "QSYMM8" },
153         { DataType::QSYMM8_PER_CHANNEL, "QSYMM8_PER_CHANNEL" },
154         { DataType::QASYMM8, "QASYMM8" },
155         { DataType::QASYMM8_SIGNED, "QASYMM8_SIGNED" },
156         { DataType::QSYMM16, "QSYMM16" },
157         { DataType::QASYMM16, "QASYMM16" },
158     };
159 
160     return dt_map[dt];
161 }
162 
string_from_activation_func(ActivationLayerInfo::ActivationFunction act)163 const std::string &string_from_activation_func(ActivationLayerInfo::ActivationFunction act)
164 {
165     static std::map<ActivationLayerInfo::ActivationFunction, const std::string> act_map =
166     {
167         { ActivationLayerInfo::ActivationFunction::ABS, "ABS" },
168         { ActivationLayerInfo::ActivationFunction::LINEAR, "LINEAR" },
169         { ActivationLayerInfo::ActivationFunction::LOGISTIC, "LOGISTIC" },
170         { ActivationLayerInfo::ActivationFunction::RELU, "RELU" },
171         { ActivationLayerInfo::ActivationFunction::BOUNDED_RELU, "BRELU" },
172         { ActivationLayerInfo::ActivationFunction::LU_BOUNDED_RELU, "LU_BRELU" },
173         { ActivationLayerInfo::ActivationFunction::LEAKY_RELU, "LRELU" },
174         { ActivationLayerInfo::ActivationFunction::SOFT_RELU, "SRELU" },
175         { ActivationLayerInfo::ActivationFunction::ELU, "ELU" },
176         { ActivationLayerInfo::ActivationFunction::SQRT, "SQRT" },
177         { ActivationLayerInfo::ActivationFunction::SQUARE, "SQUARE" },
178         { ActivationLayerInfo::ActivationFunction::TANH, "TANH" },
179         { ActivationLayerInfo::ActivationFunction::IDENTITY, "IDENTITY" },
180         { ActivationLayerInfo::ActivationFunction::HARD_SWISH, "HARD_SWISH" },
181         { ActivationLayerInfo::ActivationFunction::SWISH, "SWISH" },
182         { ActivationLayerInfo::ActivationFunction::GELU, "GELU" }
183 
184     };
185 
186     return act_map[act];
187 }
188 
string_from_interpolation_policy(InterpolationPolicy policy)189 const std::string &string_from_interpolation_policy(InterpolationPolicy policy)
190 {
191     static std::map<InterpolationPolicy, const std::string> interpolation_policy_map =
192     {
193         { InterpolationPolicy::AREA, "AREA" },
194         { InterpolationPolicy::BILINEAR, "BILINEAR" },
195         { InterpolationPolicy::NEAREST_NEIGHBOR, "NEAREST_NEIGHBOUR" },
196     };
197 
198     return interpolation_policy_map[policy];
199 }
200 
string_from_border_mode(BorderMode border_mode)201 const std::string &string_from_border_mode(BorderMode border_mode)
202 {
203     static std::map<BorderMode, const std::string> border_mode_map =
204     {
205         { BorderMode::UNDEFINED, "UNDEFINED" },
206         { BorderMode::CONSTANT, "CONSTANT" },
207         { BorderMode::REPLICATE, "REPLICATE" },
208     };
209 
210     return border_mode_map[border_mode];
211 }
212 
string_from_norm_type(NormType type)213 const std::string &string_from_norm_type(NormType type)
214 {
215     static std::map<NormType, const std::string> norm_type_map =
216     {
217         { NormType::IN_MAP_1D, "IN_MAP_1D" },
218         { NormType::IN_MAP_2D, "IN_MAP_2D" },
219         { NormType::CROSS_MAP, "CROSS_MAP" },
220     };
221 
222     return norm_type_map[type];
223 }
224 
string_from_pooling_type(PoolingType type)225 const std::string &string_from_pooling_type(PoolingType type)
226 {
227     static std::map<PoolingType, const std::string> pool_type_map =
228     {
229         { PoolingType::MAX, "MAX" },
230         { PoolingType::AVG, "AVG" },
231         { PoolingType::L2, "L2" },
232     };
233 
234     return pool_type_map[type];
235 }
236 
is_pool_region_entirely_outside_input(const PoolingLayerInfo & info)237 bool is_pool_region_entirely_outside_input(const PoolingLayerInfo &info)
238 {
239     if(info.is_global_pooling || info.exclude_padding || info.pool_size.x() == 0 || info.pool_size.y() == 0)
240     {
241         return false;
242     }
243     const auto ps                = info.pad_stride_info;
244     const auto pool_le_padding_x = info.pool_size.x() <= std::max({ ps.pad_left(), ps.pad_right() });
245     const auto pool_le_padding_y = info.pool_size.y() <= std::max({ ps.pad_top(), ps.pad_bottom() });
246     return pool_le_padding_x || pool_le_padding_y;
247 }
248 
is_pool_3d_region_entirely_outside_input(const Pooling3dLayerInfo & info)249 bool is_pool_3d_region_entirely_outside_input(const Pooling3dLayerInfo &info)
250 {
251     if(info.is_global_pooling || info.pool_size.x() == 0 || info.pool_size.y() == 0 || info.pool_size.z() == 0)
252     {
253         return false;
254     }
255     const auto ps                = info.padding;
256     const auto pool_le_padding_x = info.pool_size.x() <= std::max({ ps.left, ps.right });
257     const auto pool_le_padding_y = info.pool_size.y() <= std::max({ ps.top, ps.bottom });
258     const auto pool_le_padding_z = info.pool_size.z() <= std::max({ ps.front, ps.back });
259     return pool_le_padding_x || pool_le_padding_y || pool_le_padding_z;
260 }
261 
string_from_gemmlowp_output_stage(GEMMLowpOutputStageType output_stage)262 const std::string &string_from_gemmlowp_output_stage(GEMMLowpOutputStageType output_stage)
263 {
264     static std::map<GEMMLowpOutputStageType, const std::string> output_stage_map =
265     {
266         { GEMMLowpOutputStageType::NONE, "" },
267         { GEMMLowpOutputStageType::QUANTIZE_DOWN, "quantize_down" },
268         { GEMMLowpOutputStageType::QUANTIZE_DOWN_FIXEDPOINT, "quantize_down_fixedpoint" },
269         { GEMMLowpOutputStageType::QUANTIZE_DOWN_FLOAT, "quantize_down_float" }
270     };
271 
272     return output_stage_map[output_stage];
273 }
274 
string_from_pixel_value(const PixelValue & value,const DataType data_type)275 std::string string_from_pixel_value(const PixelValue &value, const DataType data_type)
276 {
277     std::stringstream ss;
278     std::string       converted_string;
279 
280     switch(data_type)
281     {
282         case DataType::U8:
283         case DataType::QASYMM8:
284             // Needs conversion to 32 bit, otherwise interpreted as ASCII values
285             ss << uint32_t(value.get<uint8_t>());
286             converted_string = ss.str();
287             break;
288         case DataType::S8:
289         case DataType::QASYMM8_SIGNED:
290         case DataType::QSYMM8_PER_CHANNEL:
291             // Needs conversion to 32 bit, otherwise interpreted as ASCII values
292             ss << int32_t(value.get<int8_t>());
293             converted_string = ss.str();
294             break;
295         case DataType::U16:
296         case DataType::QASYMM16:
297             ss << value.get<uint16_t>();
298             converted_string = ss.str();
299             break;
300         case DataType::S16:
301         case DataType::QSYMM16:
302             ss << value.get<int16_t>();
303             converted_string = ss.str();
304             break;
305         case DataType::U32:
306             ss << value.get<uint32_t>();
307             converted_string = ss.str();
308             break;
309         case DataType::S32:
310             ss << value.get<int32_t>();
311             converted_string = ss.str();
312             break;
313         case DataType::F32:
314             converted_string = float_to_string_with_full_precision(value.get<float>());
315             break;
316         case DataType::F16:
317             static_assert(sizeof(half) == 2, "Half must be 16 bit");
318             ss << value.get<half>();
319             converted_string = ss.str();
320             break;
321         default:
322             ARM_COMPUTE_ERROR("Not handled");
323     }
324 
325     return converted_string;
326 }
327 
data_type_from_name(const std::string & name)328 DataType data_type_from_name(const std::string &name)
329 {
330     static const std::map<std::string, DataType> data_types =
331     {
332         { "f16", DataType::F16 },
333         { "f32", DataType::F32 },
334         { "qasymm8", DataType::QASYMM8 },
335         { "qasymm8_signed", DataType::QASYMM8_SIGNED },
336     };
337 
338 #ifndef ARM_COMPUTE_EXCEPTIONS_DISABLED
339     try
340     {
341 #endif /* ARM_COMPUTE_EXCEPTIONS_DISABLED */
342         return data_types.at(utility::tolower(name));
343 
344 #ifndef ARM_COMPUTE_EXCEPTIONS_DISABLED
345     }
346     catch(const std::out_of_range &)
347     {
348         ARM_COMPUTE_ERROR_VAR("Invalid data type name: %s", name.c_str());
349     }
350 #endif /* ARM_COMPUTE_EXCEPTIONS_DISABLED */
351 }
352 
lower_string(const std::string & val)353 std::string lower_string(const std::string &val)
354 {
355     std::string res = val;
356     std::transform(res.begin(), res.end(), res.begin(), ::tolower);
357     return res;
358 }
359 
upper_string(const std::string & val)360 std::string upper_string(const std::string &val)
361 {
362     std::string res = val;
363     std::transform(res.begin(), res.end(), res.begin(), ::toupper);
364     return res;
365 }
366 
calculate_same_pad(TensorShape input_shape,TensorShape weights_shape,PadStrideInfo conv_info,DataLayout data_layout,const Size2D & dilation,const DimensionRoundingType & rounding_type)367 PadStrideInfo calculate_same_pad(TensorShape input_shape, TensorShape weights_shape, PadStrideInfo conv_info, DataLayout data_layout, const Size2D &dilation,
368                                  const DimensionRoundingType &rounding_type)
369 {
370     const auto &strides = conv_info.stride();
371     ARM_COMPUTE_ERROR_ON_MSG((strides.first < 1 || strides.second < 1), "Stride values should be greater than or equal to 1.");
372 
373     const unsigned int width_idx     = get_data_layout_dimension_index(data_layout, DataLayoutDimension::WIDTH);
374     const unsigned int height_idx    = get_data_layout_dimension_index(data_layout, DataLayoutDimension::HEIGHT);
375     const unsigned int in_width      = input_shape[width_idx];
376     const unsigned int in_height     = input_shape[height_idx];
377     const unsigned int kernel_width  = weights_shape[width_idx];
378     const unsigned int kernel_height = weights_shape[height_idx];
379 
380     // Calculate output dimensions
381     const auto         is_ceil    = static_cast<unsigned int>(rounding_type == DimensionRoundingType::CEIL);
382     const unsigned int out_width  = ((in_width - is_ceil) + strides.first - 1) / strides.first + is_ceil;
383     const unsigned int out_height = ((in_height - is_ceil) + strides.second - 1) / strides.second + is_ceil;
384 
385     // Calculate effective weights sizes
386     const int real_weight_width  = (kernel_width - 1) * dilation.x() + 1;
387     const int real_weight_height = (kernel_height - 1) * dilation.y() + 1;
388 
389     // Calculate total pad
390     const int pad_width  = std::max(0, static_cast<int>((out_width - 1) * strides.first + real_weight_width - in_width));
391     const int pad_height = std::max(0, static_cast<int>((out_height - 1) * strides.second + real_weight_height - in_height));
392 
393     // Calculate individual paddings
394     const unsigned int pad_left   = pad_width / 2;
395     const unsigned int pad_top    = pad_height / 2;
396     const unsigned int pad_right  = pad_width - pad_left;
397     const unsigned int pad_bottom = pad_height - pad_top;
398 
399     PadStrideInfo same_info(strides.first, strides.second, pad_left, pad_right, pad_top, pad_bottom, rounding_type);
400 
401     // Check for correctness of predicted output shape against the one calculated using the generated info
402     const auto out_dims = scaled_dimensions(in_width, in_height, kernel_width, kernel_height, same_info, dilation);
403     ARM_COMPUTE_ERROR_ON(out_dims.first != out_width || out_dims.second != out_height);
404     ARM_COMPUTE_UNUSED(out_dims);
405 
406     return same_info;
407 }
408 
deconvolution_output_dimensions(unsigned int in_width,unsigned int in_height,unsigned int kernel_width,unsigned int kernel_height,const PadStrideInfo & pad_stride_info)409 std::pair<unsigned int, unsigned int> deconvolution_output_dimensions(unsigned int in_width, unsigned int in_height,
410                                                                       unsigned int kernel_width, unsigned int kernel_height,
411                                                                       const PadStrideInfo &pad_stride_info)
412 {
413     const unsigned int pad_left   = pad_stride_info.pad_left();
414     const unsigned int pad_top    = pad_stride_info.pad_top();
415     const unsigned int pad_right  = pad_stride_info.pad_right();
416     const unsigned int pad_bottom = pad_stride_info.pad_bottom();
417     const unsigned int stride_x   = pad_stride_info.stride().first;
418     const unsigned int stride_y   = pad_stride_info.stride().second;
419 
420     ARM_COMPUTE_ERROR_ON(in_width < 1 || in_height < 1);
421     ARM_COMPUTE_ERROR_ON(((in_width - 1) * stride_x + kernel_width) < (pad_left + pad_right));
422     ARM_COMPUTE_ERROR_ON(((in_height - 1) * stride_y + kernel_height) < (pad_top + pad_bottom));
423     const int w = stride_x * (in_width - 1) + kernel_width - (pad_left + pad_right);
424     const int h = stride_y * (in_height - 1) + kernel_height - (pad_top + pad_bottom);
425 
426     return std::make_pair<unsigned int, unsigned int>(w, h);
427 }
428 
scaled_dimensions(int width,int height,int kernel_width,int kernel_height,const PadStrideInfo & pad_stride_info,const Size2D & dilation)429 std::pair<unsigned int, unsigned int> scaled_dimensions(int width, int height,
430                                                         int kernel_width, int kernel_height,
431                                                         const PadStrideInfo &pad_stride_info,
432                                                         const Size2D        &dilation)
433 {
434     const int dilation_x = dilation.x();
435     const int dilation_y = dilation.y();
436     const int pad_left   = pad_stride_info.pad_left();
437     const int pad_top    = pad_stride_info.pad_top();
438     const int pad_right  = pad_stride_info.pad_right();
439     const int pad_bottom = pad_stride_info.pad_bottom();
440     const int stride_x   = pad_stride_info.stride().first;
441     const int stride_y   = pad_stride_info.stride().second;
442     int       w          = 0;
443     int       h          = 0;
444     switch(pad_stride_info.round())
445     {
446         case DimensionRoundingType::FLOOR:
447             w = static_cast<int>(std::floor((static_cast<float>(width + pad_left + pad_right - (dilation_x * (kernel_width - 1) + 1)) / stride_x) + 1));
448             h = static_cast<int>(std::floor((static_cast<float>(height + pad_top + pad_bottom - (dilation_y * (kernel_height - 1) + 1)) / stride_y) + 1));
449             break;
450         case DimensionRoundingType::CEIL:
451             w = static_cast<int>(std::ceil((static_cast<float>(width + pad_left + pad_right - (dilation_x * (kernel_width - 1) + 1)) / stride_x) + 1));
452             h = static_cast<int>(std::ceil((static_cast<float>(height + pad_top + pad_bottom - (dilation_y * (kernel_height - 1) + 1)) / stride_y) + 1));
453             break;
454         default:
455             ARM_COMPUTE_ERROR("Unsupported rounding type");
456     }
457 
458     w = std::max(1, w);
459     h = std::max(1, h);
460     return std::make_pair(static_cast<unsigned int>(w), static_cast<unsigned int>(h));
461 }
462 
scaled_dimensions_signed(int width,int height,int kernel_width,int kernel_height,const PadStrideInfo & pad_stride_info)463 std::pair<int, int> scaled_dimensions_signed(int width, int height,
464                                              int kernel_width, int kernel_height,
465                                              const PadStrideInfo &pad_stride_info)
466 {
467     const int pad_left   = pad_stride_info.pad_left();
468     const int pad_top    = pad_stride_info.pad_top();
469     const int pad_right  = pad_stride_info.pad_right();
470     const int pad_bottom = pad_stride_info.pad_bottom();
471     const int stride_x   = pad_stride_info.stride().first;
472     const int stride_y   = pad_stride_info.stride().second;
473     int       w          = 0;
474     int       h          = 0;
475     switch(pad_stride_info.round())
476     {
477         case DimensionRoundingType::FLOOR:
478             w = static_cast<int>(std::floor((static_cast<float>(width + pad_left + pad_right - kernel_width) / stride_x) + 1));
479             h = static_cast<int>(std::floor((static_cast<float>(height + pad_top + pad_bottom - kernel_height) / stride_y) + 1));
480             break;
481         case DimensionRoundingType::CEIL:
482             w = static_cast<int>(std::ceil((static_cast<float>(width + pad_left + pad_right - kernel_width) / stride_x) + 1));
483             h = static_cast<int>(std::ceil((static_cast<float>(height + pad_top + pad_bottom - kernel_height) / stride_y) + 1));
484             break;
485         default:
486             ARM_COMPUTE_ERROR("Unsupported rounding type");
487     }
488 
489     return std::make_pair(static_cast<int>(w), static_cast<int>(h));
490 }
491 
scaled_3d_dimensions_signed(int width,int height,int depth,int kernel_width,int kernel_height,int kernel_depth,const Pooling3dLayerInfo & pool3d_info)492 std::tuple<int, int, int> scaled_3d_dimensions_signed(int width, int height, int depth,
493                                                       int kernel_width, int kernel_height, int kernel_depth,
494                                                       const Pooling3dLayerInfo &pool3d_info)
495 {
496     const int pad_left   = pool3d_info.padding.left;
497     const int pad_top    = pool3d_info.padding.top;
498     const int pad_right  = pool3d_info.padding.right;
499     const int pad_bottom = pool3d_info.padding.bottom;
500     const int pad_front  = pool3d_info.padding.front;
501     const int pad_back   = pool3d_info.padding.back;
502     const int stride_x   = pool3d_info.stride.x();
503     const int stride_y   = pool3d_info.stride.y();
504     const int stride_z   = pool3d_info.stride.z();
505     int       w          = 0;
506     int       h          = 0;
507     int       d          = 0;
508 
509     switch(pool3d_info.round_type)
510     {
511         case DimensionRoundingType::FLOOR:
512             w = static_cast<int>(std::floor((static_cast<float>(width + pad_left + pad_right - kernel_width) / stride_x) + 1));
513             h = static_cast<int>(std::floor((static_cast<float>(height + pad_top + pad_bottom - kernel_height) / stride_y) + 1));
514             d = static_cast<int>(std::floor((static_cast<float>(depth + pad_front + pad_back - kernel_depth) / stride_z) + 1));
515             break;
516         case DimensionRoundingType::CEIL:
517             w = static_cast<int>(std::ceil((static_cast<float>(width + pad_left + pad_right - kernel_width) / stride_x) + 1));
518             h = static_cast<int>(std::ceil((static_cast<float>(height + pad_top + pad_bottom - kernel_height) / stride_y) + 1));
519             d = static_cast<int>(std::ceil((static_cast<float>(depth + pad_front + pad_back - kernel_depth) / stride_z) + 1));
520             break;
521         default:
522             ARM_COMPUTE_ERROR("Unsupported rounding type");
523     }
524 
525     return std::make_tuple(static_cast<int>(w), static_cast<int>(h), static_cast<int>(d));
526 }
527 
needs_serialized_reduction(ReductionOperation op,DataType dt,unsigned int axis)528 bool needs_serialized_reduction(ReductionOperation op, DataType dt, unsigned int axis)
529 {
530     const bool is_min_max        = (op == ReductionOperation::MAX || op == ReductionOperation::MIN);
531     const bool is_quantized_type = is_data_type_quantized(dt);
532     const bool is_first_dim      = (axis == 0);
533 
534     return !is_first_dim || is_min_max || is_quantized_type;
535 }
536 
get_softmax_output_quantization_info(DataType input_type,bool is_log)537 QuantizationInfo get_softmax_output_quantization_info(DataType input_type, bool is_log)
538 {
539     // Note: Output quantization info for softmax should always have
540     // * Softmax with QASYMM8: scale = 1/256, offset = 0
541     // * Softmax with QASYMM8_SIGNED: scale = 1/256, offset = -128
542     // * LogSoftmax with QASYMM8: scale = 1/256, offset = 0
543     // * LogSoftmax with QASYMM8_SIGNED: scale = 16/256, offset = 127
544     if(is_data_type_quantized_asymmetric_signed(input_type))
545     {
546         if(is_log)
547         {
548             return QuantizationInfo(16.f / 256, 127);
549         }
550         else
551         {
552             return QuantizationInfo(1.f / 256, -128);
553         }
554     }
555     return QuantizationInfo(1.f / 256, 0);
556 }
557 
get_quantized_activation_min_max(ActivationLayerInfo act_info,DataType data_type,UniformQuantizationInfo oq_info)558 std::pair<int32_t, int32_t> get_quantized_activation_min_max(ActivationLayerInfo act_info, DataType data_type, UniformQuantizationInfo oq_info)
559 {
560     const bool is_qasymm8_signed = is_data_type_quantized_asymmetric_signed(data_type);
561     const auto a                 = act_info.a();
562     const auto b                 = act_info.b();
563     const int  a_int             = is_qasymm8_signed ? quantize_qasymm8_signed(a, oq_info) : quantize_qasymm8(a, oq_info);
564     const int  b_int             = is_qasymm8_signed ? quantize_qasymm8_signed(b, oq_info) : quantize_qasymm8(b, oq_info);
565     const auto type_max_value    = std::get<1>(get_min_max(data_type)).get<int32_t>();
566 
567     const int32_t min_activation = act_info.activation() != ActivationLayerInfo::ActivationFunction::LU_BOUNDED_RELU ? oq_info.offset : b_int;
568     const int32_t max_activation = act_info.activation() == ActivationLayerInfo::ActivationFunction::RELU ? type_max_value : a_int;
569 
570     return std::make_pair(min_activation, max_activation);
571 }
572 
get_padding_info(std::initializer_list<const ITensor * > tensors)573 std::unordered_map<const ITensorInfo *, PaddingSize> get_padding_info(std::initializer_list<const ITensor *> tensors)
574 {
575     std::unordered_map<const ITensorInfo *, PaddingSize> res;
576 
577     for(const ITensor *tensor : tensors)
578     {
579         if(tensor)
580         {
581             res.insert({ tensor->info(), tensor->info()->padding() });
582         }
583     }
584 
585     return res;
586 }
587 
get_padding_info(std::initializer_list<const ITensorInfo * > infos)588 std::unordered_map<const ITensorInfo *, PaddingSize> get_padding_info(std::initializer_list<const ITensorInfo *> infos)
589 {
590     std::unordered_map<const ITensorInfo *, PaddingSize> res;
591 
592     for(const ITensorInfo *info : infos)
593     {
594         if(info)
595         {
596             res.insert({ info, info->padding() });
597         }
598     }
599 
600     return res;
601 }
602 
has_padding_changed(const std::unordered_map<const ITensorInfo *,PaddingSize> & padding_map)603 bool has_padding_changed(const std::unordered_map<const ITensorInfo *, PaddingSize> &padding_map)
604 {
605     return std::find_if(padding_map.begin(), padding_map.end(), [](const std::pair<const ITensorInfo *, PaddingSize> &padding_info)
606     {
607         return (padding_info.first->padding() != padding_info.second);
608     })
609     != padding_map.end();
610 }
611 
612 #ifdef ARM_COMPUTE_ASSERTS_ENABLED
print_consecutive_elements(std::ostream & s,DataType dt,const uint8_t * ptr,unsigned int n,int stream_width,const std::string & element_delim)613 void print_consecutive_elements(std::ostream &s, DataType dt, const uint8_t *ptr, unsigned int n, int stream_width, const std::string &element_delim)
614 {
615     switch(dt)
616     {
617         case DataType::U8:
618         case DataType::QASYMM8:
619             print_consecutive_elements_impl<uint8_t>(s, ptr, n, stream_width, element_delim);
620             break;
621         case DataType::S8:
622         case DataType::QSYMM8:
623         case DataType::QASYMM8_SIGNED:
624         case DataType::QSYMM8_PER_CHANNEL:
625             print_consecutive_elements_impl<int8_t>(s, reinterpret_cast<const int8_t *>(ptr), n, stream_width, element_delim);
626             break;
627         case DataType::U16:
628         case DataType::QASYMM16:
629             print_consecutive_elements_impl<uint16_t>(s, reinterpret_cast<const uint16_t *>(ptr), n, stream_width, element_delim);
630             break;
631         case DataType::S16:
632         case DataType::QSYMM16:
633             print_consecutive_elements_impl<int16_t>(s, reinterpret_cast<const int16_t *>(ptr), n, stream_width, element_delim);
634             break;
635         case DataType::U32:
636             print_consecutive_elements_impl<uint32_t>(s, reinterpret_cast<const uint32_t *>(ptr), n, stream_width, element_delim);
637             break;
638         case DataType::S32:
639             print_consecutive_elements_impl<int32_t>(s, reinterpret_cast<const int32_t *>(ptr), n, stream_width, element_delim);
640             break;
641         case DataType::BFLOAT16:
642             print_consecutive_elements_impl<bfloat16>(s, reinterpret_cast<const bfloat16 *>(ptr), n, stream_width, element_delim);
643             break;
644         case DataType::F16:
645             print_consecutive_elements_impl<half>(s, reinterpret_cast<const half *>(ptr), n, stream_width, element_delim);
646             break;
647         case DataType::F32:
648             print_consecutive_elements_impl<float>(s, reinterpret_cast<const float *>(ptr), n, stream_width, element_delim);
649             break;
650         default:
651             ARM_COMPUTE_ERROR("Undefined element size for given data type");
652     }
653 }
654 
max_consecutive_elements_display_width(std::ostream & s,DataType dt,const uint8_t * ptr,unsigned int n)655 int max_consecutive_elements_display_width(std::ostream &s, DataType dt, const uint8_t *ptr, unsigned int n)
656 {
657     switch(dt)
658     {
659         case DataType::U8:
660         case DataType::QASYMM8:
661             return max_consecutive_elements_display_width_impl<uint8_t>(s, ptr, n);
662         case DataType::S8:
663         case DataType::QSYMM8:
664         case DataType::QASYMM8_SIGNED:
665         case DataType::QSYMM8_PER_CHANNEL:
666             return max_consecutive_elements_display_width_impl<int8_t>(s, reinterpret_cast<const int8_t *>(ptr), n);
667         case DataType::U16:
668         case DataType::QASYMM16:
669             return max_consecutive_elements_display_width_impl<uint16_t>(s, reinterpret_cast<const uint16_t *>(ptr), n);
670         case DataType::S16:
671         case DataType::QSYMM16:
672             return max_consecutive_elements_display_width_impl<int16_t>(s, reinterpret_cast<const int16_t *>(ptr), n);
673         case DataType::U32:
674             return max_consecutive_elements_display_width_impl<uint32_t>(s, reinterpret_cast<const uint32_t *>(ptr), n);
675         case DataType::S32:
676             return max_consecutive_elements_display_width_impl<int32_t>(s, reinterpret_cast<const int32_t *>(ptr), n);
677         case DataType::BFLOAT16:
678             return max_consecutive_elements_display_width_impl<bfloat16>(s, reinterpret_cast<const bfloat16 *>(ptr), n);
679         case DataType::F16:
680             return max_consecutive_elements_display_width_impl<half>(s, reinterpret_cast<const half *>(ptr), n);
681         case DataType::F32:
682             return max_consecutive_elements_display_width_impl<float>(s, reinterpret_cast<const float *>(ptr), n);
683         default:
684             ARM_COMPUTE_ERROR("Undefined element size for given data type");
685     }
686     return 0;
687 }
688 #endif /* ARM_COMPUTE_ASSERTS_ENABLED */
689 
690 } // namespace arm_compute