arm_compute v18.05
[platform/upstream/armcl.git] / src / core / Utils.cpp
1 /*
2  * Copyright (c) 2016, 2017, 2018 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/Utils.h"
26
27 #include "arm_compute/core/FixedPoint.h"
28
29 #include "support/ToolchainSupport.h"
30
31 #include <algorithm>
32 #include <cmath>
33 #include <cstdint>
34 #include <fstream>
35 #include <map>
36 #include <string>
37
38 using namespace arm_compute;
39
40 std::string arm_compute::build_information()
41 {
42     static const std::string information =
43 #include "arm_compute_version.embed"
44         ;
45     return information;
46 }
47
48 std::string arm_compute::read_file(const std::string &filename, bool binary)
49 {
50     std::string   out;
51     std::ifstream fs;
52
53     try
54     {
55         fs.exceptions(std::ifstream::failbit | std::ifstream::badbit);
56         std::ios_base::openmode mode = std::ios::in;
57
58         if(binary)
59         {
60             mode |= std::ios::binary;
61         }
62
63         fs.open(filename, mode);
64
65         // Go to the end of the file
66         fs.seekg(0, std::ios::end);
67         // Reserve the memory required to store the file's content
68         out.reserve(fs.tellg());
69         // Go back to the beginning of the file
70         fs.seekg(0, std::ios::beg);
71         // Copy the content of the file
72         out.assign(std::istreambuf_iterator<char>(fs), std::istreambuf_iterator<char>());
73     }
74     catch(const std::ifstream::failure &e)
75     {
76         ARM_COMPUTE_ERROR("Accessing %s: %s", filename.c_str(), e.what());
77     }
78
79     return out;
80 }
81
82 const std::string &arm_compute::string_from_format(Format format)
83 {
84     static std::map<Format, const std::string> formats_map =
85     {
86         { Format::UNKNOWN, "UNKNOWN" },
87         { Format::U8, "U8" },
88         { Format::S16, "S16" },
89         { Format::U16, "U16" },
90         { Format::S32, "S32" },
91         { Format::U32, "U32" },
92         { Format::F16, "F16" },
93         { Format::F32, "F32" },
94         { Format::UV88, "UV88" },
95         { Format::RGB888, "RGB888" },
96         { Format::RGBA8888, "RGBA8888" },
97         { Format::YUV444, "YUV444" },
98         { Format::YUYV422, "YUYV422" },
99         { Format::NV12, "NV12" },
100         { Format::NV21, "NV21" },
101         { Format::IYUV, "IYUV" },
102         { Format::UYVY422, "UYVY422" }
103     };
104
105     return formats_map[format];
106 }
107
108 const std::string &arm_compute::string_from_channel(Channel channel)
109 {
110     static std::map<Channel, const std::string> channels_map =
111     {
112         { Channel::UNKNOWN, "UNKNOWN" },
113         { Channel::R, "R" },
114         { Channel::G, "G" },
115         { Channel::B, "B" },
116         { Channel::A, "A" },
117         { Channel::Y, "Y" },
118         { Channel::U, "U" },
119         { Channel::V, "V" },
120         { Channel::C0, "C0" },
121         { Channel::C1, "C1" },
122         { Channel::C2, "C2" },
123         { Channel::C3, "C3" }
124     };
125
126     return channels_map[channel];
127 }
128
129 const std::string &arm_compute::string_from_data_layout(DataLayout dl)
130 {
131     static std::map<DataLayout, const std::string> dl_map =
132     {
133         { DataLayout::UNKNOWN, "UNKNOWN" },
134         { DataLayout::NCHW, "NCHW" },
135         { DataLayout::NHWC, "NHWC" },
136     };
137
138     return dl_map[dl];
139 }
140
141 const std::string &arm_compute::string_from_data_type(DataType dt)
142 {
143     static std::map<DataType, const std::string> dt_map =
144     {
145         { DataType::UNKNOWN, "UNKNOWN" },
146         { DataType::S8, "S8" },
147         { DataType::U8, "U8" },
148         { DataType::QS8, "QS8" },
149         { DataType::S16, "S16" },
150         { DataType::U16, "U16" },
151         { DataType::QS16, "QS16" },
152         { DataType::S32, "S32" },
153         { DataType::U32, "U32" },
154         { DataType::S64, "S64" },
155         { DataType::U64, "U64" },
156         { DataType::F16, "F16" },
157         { DataType::F32, "F32" },
158         { DataType::F64, "F64" },
159         { DataType::SIZET, "SIZET" },
160         { DataType::QASYMM8, "QASYMM8" },
161     };
162
163     return dt_map[dt];
164 }
165
166 const std::string &arm_compute::string_from_activation_func(ActivationLayerInfo::ActivationFunction act)
167 {
168     static std::map<ActivationLayerInfo::ActivationFunction, const std::string> act_map =
169     {
170         { ActivationLayerInfo::ActivationFunction::ABS, "ABS" },
171         { ActivationLayerInfo::ActivationFunction::LINEAR, "LINEAR" },
172         { ActivationLayerInfo::ActivationFunction::LOGISTIC, "LOGISTIC" },
173         { ActivationLayerInfo::ActivationFunction::RELU, "RELU" },
174         { ActivationLayerInfo::ActivationFunction::BOUNDED_RELU, "BRELU" },
175         { ActivationLayerInfo::ActivationFunction::LU_BOUNDED_RELU, "LU_BRELU" },
176         { ActivationLayerInfo::ActivationFunction::LEAKY_RELU, "LRELU" },
177         { ActivationLayerInfo::ActivationFunction::SOFT_RELU, "SRELU" },
178         { ActivationLayerInfo::ActivationFunction::SQRT, "SQRT" },
179         { ActivationLayerInfo::ActivationFunction::SQUARE, "SQUARE" },
180         { ActivationLayerInfo::ActivationFunction::TANH, "TANH" },
181     };
182
183     return act_map[act];
184 }
185
186 const std::string &arm_compute::string_from_matrix_pattern(MatrixPattern pattern)
187 {
188     static std::map<MatrixPattern, const std::string> pattern_map =
189     {
190         { MatrixPattern::BOX, "BOX" },
191         { MatrixPattern::CROSS, "CROSS" },
192         { MatrixPattern::DISK, "DISK" },
193         { MatrixPattern::OTHER, "OTHER" },
194     };
195
196     return pattern_map[pattern];
197 }
198
199 const std::string &arm_compute::string_from_non_linear_filter_function(NonLinearFilterFunction function)
200 {
201     static std::map<NonLinearFilterFunction, const std::string> func_map =
202     {
203         { NonLinearFilterFunction::MAX, "MAX" },
204         { NonLinearFilterFunction::MEDIAN, "MEDIAN" },
205         { NonLinearFilterFunction::MIN, "MIN" },
206     };
207
208     return func_map[function];
209 }
210
211 const std::string &arm_compute::string_from_interpolation_policy(InterpolationPolicy policy)
212 {
213     static std::map<InterpolationPolicy, const std::string> interpolation_policy_map =
214     {
215         { InterpolationPolicy::AREA, "AREA" },
216         { InterpolationPolicy::BILINEAR, "BILINEAR" },
217         { InterpolationPolicy::NEAREST_NEIGHBOR, "NEAREST_NEIGHBOUR" },
218     };
219
220     return interpolation_policy_map[policy];
221 }
222
223 const std::string &arm_compute::string_from_border_mode(BorderMode border_mode)
224 {
225     static std::map<BorderMode, const std::string> border_mode_map =
226     {
227         { BorderMode::UNDEFINED, "UNDEFINED" },
228         { BorderMode::CONSTANT, "CONSTANT" },
229         { BorderMode::REPLICATE, "REPLICATE" },
230     };
231
232     return border_mode_map[border_mode];
233 }
234
235 const std::string &arm_compute::string_from_norm_type(NormType type)
236 {
237     static std::map<NormType, const std::string> norm_type_map =
238     {
239         { NormType::IN_MAP_1D, "IN_MAP_1D" },
240         { NormType::IN_MAP_2D, "IN_MAP_2D" },
241         { NormType::CROSS_MAP, "CROSS_MAP" },
242     };
243
244     return norm_type_map[type];
245 }
246
247 const std::string &arm_compute::string_from_pooling_type(PoolingType type)
248 {
249     static std::map<PoolingType, const std::string> pool_type_map =
250     {
251         { PoolingType::MAX, "MAX" },
252         { PoolingType::AVG, "AVG" },
253         { PoolingType::L2, "L2" },
254     };
255
256     return pool_type_map[type];
257 }
258
259 std::string arm_compute::lower_string(const std::string &val)
260 {
261     std::string res = val;
262     std::transform(res.begin(), res.end(), res.begin(), ::tolower);
263     return res;
264 }
265
266 PadStrideInfo arm_compute::calculate_same_pad(TensorShape input_shape, TensorShape weights_shape, PadStrideInfo conv_info)
267 {
268     const auto &strides         = conv_info.stride();
269     const int   out_width       = std::ceil(float(input_shape.x()) / float(strides.first));
270     const int   out_height      = std::ceil(float(input_shape.y()) / float(strides.second));
271     const int   pad_width       = ((out_width - 1) * strides.first + weights_shape.x() - input_shape.x());
272     const int   pad_height      = ((out_height - 1) * strides.second + weights_shape.y() - input_shape.y());
273     const int   same_pad_left   = pad_width / 2;
274     const int   same_pad_top    = pad_height / 2;
275     const int   same_pad_right  = pad_width - same_pad_left;
276     const int   same_pad_bottom = pad_height - same_pad_top;
277
278     return PadStrideInfo(strides.first, strides.second, same_pad_left, same_pad_right, same_pad_top, same_pad_bottom, DimensionRoundingType::CEIL);
279 }
280
281 TensorShape arm_compute::deconvolution_output_shape(const std::pair<unsigned int, unsigned int> &out_dims, TensorShape input, TensorShape weights)
282 {
283     TensorShape out_shape(input);
284     out_shape.set(0, out_dims.first);
285     out_shape.set(1, out_dims.second);
286     out_shape.set(2, weights[3]);
287     return out_shape;
288 }
289
290 const std::pair<unsigned int, unsigned int> arm_compute::deconvolution_output_dimensions(
291     unsigned int in_width, unsigned int in_height, unsigned int kernel_width, unsigned int kernel_height, unsigned int padx, unsigned int pady,
292     unsigned int inner_border_right, unsigned int inner_border_top, unsigned int stride_x, unsigned int stride_y)
293 {
294     ARM_COMPUTE_ERROR_ON(in_width < 1 || in_height < 1);
295     ARM_COMPUTE_ERROR_ON(((in_width - 1) * stride_x + kernel_width + inner_border_right) < 2 * padx);
296     ARM_COMPUTE_ERROR_ON(((in_height - 1) * stride_y + kernel_height + inner_border_top) < 2 * pady);
297     const int padx_deconv = (kernel_width - padx - 1);
298     const int pady_deconv = (kernel_height - pady - 1);
299     ARM_COMPUTE_ERROR_ON(padx_deconv < 0);
300     ARM_COMPUTE_ERROR_ON(pady_deconv < 0);
301     const int w = stride_x * (in_width - 1) + kernel_width + inner_border_right - 2 * padx_deconv;
302     const int h = stride_y * (in_height - 1) + kernel_height + inner_border_top - 2 * pady_deconv;
303     return std::make_pair<unsigned int, unsigned int>(w, h);
304 }
305
306 const std::pair<unsigned int, unsigned int> arm_compute::scaled_dimensions(unsigned int width, unsigned int height,
307                                                                            unsigned int kernel_width, unsigned int kernel_height,
308                                                                            const PadStrideInfo &pad_stride_info,
309                                                                            const Size2D        &dilation)
310 {
311     const unsigned int pad_left   = pad_stride_info.pad_left();
312     const unsigned int pad_top    = pad_stride_info.pad_top();
313     const unsigned int pad_right  = pad_stride_info.pad_right();
314     const unsigned int pad_bottom = pad_stride_info.pad_bottom();
315     const unsigned int stride_x   = pad_stride_info.stride().first;
316     const unsigned int stride_y   = pad_stride_info.stride().second;
317     unsigned int       w          = 0;
318     unsigned int       h          = 0;
319     switch(pad_stride_info.round())
320     {
321         case DimensionRoundingType::FLOOR:
322             w = static_cast<unsigned int>(std::floor((static_cast<float>(width + pad_left + pad_right - (dilation.x() * (kernel_width - 1) + 1)) / stride_x) + 1));
323             h = static_cast<unsigned int>(std::floor((static_cast<float>(height + pad_top + pad_bottom - (dilation.y() * (kernel_height - 1) + 1)) / stride_y) + 1));
324             break;
325         case DimensionRoundingType::CEIL:
326             w = static_cast<unsigned int>(std::ceil((static_cast<float>(width + pad_left + pad_right - (dilation.x() * (kernel_width - 1) + 1)) / stride_x) + 1));
327             h = static_cast<unsigned int>(std::ceil((static_cast<float>(height + pad_top + pad_bottom - (dilation.y() * (kernel_height - 1) + 1)) / stride_y) + 1));
328             break;
329         default:
330             ARM_COMPUTE_ERROR("Unsupported rounding type");
331     }
332
333     // Make sure that border operations will start from inside the input and not the padded area
334     if(((w - 1) * stride_x) >= (width + pad_left))
335     {
336         --w;
337     }
338     if(((h - 1) * stride_y) >= (height + pad_top))
339     {
340         --h;
341     }
342     ARM_COMPUTE_ERROR_ON(((w - 1) * stride_x) >= (width + pad_left));
343     ARM_COMPUTE_ERROR_ON(((h - 1) * stride_y) >= (height + pad_top));
344
345     return std::make_pair(w, h);
346 }
347
348 void arm_compute::print_consecutive_elements(std::ostream &s, DataType dt, const uint8_t *ptr, unsigned int n, int stream_width, const std::string &element_delim)
349 {
350     switch(dt)
351     {
352         case DataType::QASYMM8:
353         case DataType::U8:
354             print_consecutive_elements_impl<uint8_t>(s, ptr, n, stream_width, element_delim);
355             break;
356         case DataType::QS8:
357         case DataType::S8:
358             print_consecutive_elements_impl<int8_t>(s, reinterpret_cast<const int8_t *>(ptr), n, stream_width, element_delim);
359             break;
360         case DataType::U16:
361             print_consecutive_elements_impl<uint16_t>(s, reinterpret_cast<const uint16_t *>(ptr), n, stream_width, element_delim);
362             break;
363         case DataType::QS16:
364         case DataType::S16:
365             print_consecutive_elements_impl<int16_t>(s, reinterpret_cast<const int16_t *>(ptr), n, stream_width, element_delim);
366             break;
367         case DataType::U32:
368             print_consecutive_elements_impl<uint32_t>(s, reinterpret_cast<const uint32_t *>(ptr), n, stream_width, element_delim);
369             break;
370         case DataType::S32:
371             print_consecutive_elements_impl<int32_t>(s, reinterpret_cast<const int32_t *>(ptr), n, stream_width, element_delim);
372             break;
373         case DataType::F32:
374             print_consecutive_elements_impl<float>(s, reinterpret_cast<const float *>(ptr), n, stream_width, element_delim);
375             break;
376         case DataType::F16:
377             print_consecutive_elements_impl<half>(s, reinterpret_cast<const half *>(ptr), n, stream_width, element_delim);
378             break;
379         default:
380             ARM_COMPUTE_ERROR("Undefined element size for given data type");
381     }
382 }
383
384 int arm_compute::max_consecutive_elements_display_width(std::ostream &s, DataType dt, const uint8_t *ptr, unsigned int n)
385 {
386     switch(dt)
387     {
388         case DataType::QASYMM8:
389         case DataType::U8:
390             return max_consecutive_elements_display_width_impl<uint8_t>(s, ptr, n);
391         case DataType::QS8:
392         case DataType::S8:
393             return max_consecutive_elements_display_width_impl<int8_t>(s, reinterpret_cast<const int8_t *>(ptr), n);
394         case DataType::U16:
395             return max_consecutive_elements_display_width_impl<uint16_t>(s, reinterpret_cast<const uint16_t *>(ptr), n);
396         case DataType::QS16:
397         case DataType::S16:
398             return max_consecutive_elements_display_width_impl<int16_t>(s, reinterpret_cast<const int16_t *>(ptr), n);
399         case DataType::U32:
400             return max_consecutive_elements_display_width_impl<uint32_t>(s, reinterpret_cast<const uint32_t *>(ptr), n);
401         case DataType::S32:
402             return max_consecutive_elements_display_width_impl<int32_t>(s, reinterpret_cast<const int32_t *>(ptr), n);
403         case DataType::F32:
404             return max_consecutive_elements_display_width_impl<float>(s, reinterpret_cast<const float *>(ptr), n);
405         case DataType::F16:
406             return max_consecutive_elements_display_width_impl<half>(s, reinterpret_cast<const half *>(ptr), n);
407         default:
408             ARM_COMPUTE_ERROR("Undefined element size for given data type");
409     }
410     return 0;
411 }