arm_compute v18.05
[platform/upstream/armcl.git] / src / core / TensorInfo.cpp
1 /*
2  * Copyright (c) 2016-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 #include "arm_compute/core/TensorInfo.h"
25
26 #include "arm_compute/core/Error.h"
27 #include "arm_compute/core/HOGInfo.h"
28 #include "arm_compute/core/Helpers.h"
29 #include "arm_compute/core/TensorInfo.h"
30 #include "arm_compute/core/Validate.h"
31 #include "support/ToolchainSupport.h"
32
33 using namespace arm_compute;
34
35 TensorInfo::TensorInfo()
36     : _total_size(0), _fixed_point_position(0), _offset_first_element_in_bytes(0), _strides_in_bytes(), _num_channels(0), _tensor_shape(), _data_type(DataType::UNKNOWN), _format(Format::UNKNOWN),
37       _is_resizable{ true }, _valid_region{ Coordinates(), _tensor_shape }, _padding{ 0 }, _quantization_info(), _data_layout(DataLayout::NCHW)
38 {
39 }
40
41 TensorInfo::TensorInfo(const ITensorInfo &info)
42     : TensorInfo()
43 {
44     _total_size                    = info.total_size();
45     _fixed_point_position          = info.fixed_point_position();
46     _offset_first_element_in_bytes = info.offset_first_element_in_bytes();
47     _strides_in_bytes              = info.strides_in_bytes();
48     _num_channels                  = info.num_channels();
49     _tensor_shape                  = info.tensor_shape();
50     _data_type                     = info.data_type();
51     _format                        = info.format();
52     _is_resizable                  = info.is_resizable();
53     _valid_region                  = info.valid_region();
54     _padding                       = info.padding();
55     _quantization_info             = info.quantization_info();
56     _data_layout                   = info.data_layout();
57 }
58
59 TensorInfo::TensorInfo(Format format)
60     : TensorInfo(TensorShape(), format)
61 {
62 }
63
64 TensorInfo::TensorInfo(unsigned int width, unsigned int height, Format format)
65     : TensorInfo(TensorShape(width, height), format)
66 {
67 }
68
69 TensorInfo::TensorInfo(const TensorShape &tensor_shape, Format format)
70     : TensorInfo()
71 {
72     init(tensor_shape, format);
73 }
74
75 TensorInfo::TensorInfo(size_t num_channels, DataType data_type, size_t fixed_point_position)
76     : TensorInfo()
77 {
78     init(TensorShape(), num_channels, data_type, fixed_point_position);
79 }
80
81 TensorInfo::TensorInfo(const TensorShape &tensor_shape, size_t num_channels, DataType data_type, int fixed_point_position)
82     : TensorInfo()
83 {
84     init(tensor_shape, num_channels, data_type, fixed_point_position);
85 }
86
87 TensorInfo::TensorInfo(const TensorShape &tensor_shape, size_t num_channels, DataType data_type, QuantizationInfo quantization_info)
88     : TensorInfo()
89 {
90     init(tensor_shape, num_channels, data_type, 0);
91     _quantization_info = quantization_info;
92 }
93
94 TensorInfo::TensorInfo(const HOGInfo &hog_info, unsigned int width, unsigned int height)
95     : TensorInfo()
96 {
97     init(hog_info, width, height);
98 }
99
100 void TensorInfo::init(Format format)
101 {
102     init(TensorShape(), format);
103 }
104
105 void TensorInfo::init(const TensorShape &tensor_shape, Format format)
106 {
107     size_t         num_channels = num_channels_from_format(format);
108     const DataType type         = data_type_from_format(format);
109
110     init(tensor_shape, num_channels, type);
111
112     _format = format;
113 }
114
115 void TensorInfo::init(const TensorShape &tensor_shape, Format format,
116                       const Strides &strides_in_bytes, size_t offset_first_element_in_bytes,
117                       size_t total_size_in_bytes)
118 {
119     size_t         num_channels = num_channels_from_format(format);
120     const DataType type         = data_type_from_format(format);
121
122     init(tensor_shape, num_channels, type, strides_in_bytes, offset_first_element_in_bytes, total_size_in_bytes);
123
124     _format = format;
125 }
126
127 void TensorInfo::init(size_t num_channels, DataType data_type, size_t fixed_point_position)
128 {
129     init(TensorShape(), num_channels, data_type, fixed_point_position);
130 }
131
132 void TensorInfo::init(const TensorShape &tensor_shape, size_t num_channels, DataType data_type, int fixed_point_position)
133 {
134     ARM_COMPUTE_ERROR_ON(num_channels == 0);
135     ARM_COMPUTE_ERROR_ON(data_type == DataType::QS8 && (fixed_point_position < 1 || fixed_point_position > 6));
136     ARM_COMPUTE_ERROR_ON(data_type == DataType::QS16 && (fixed_point_position < 1 || fixed_point_position > 14));
137
138     _fixed_point_position = fixed_point_position;
139     _data_type            = data_type;
140     _num_channels         = num_channels;
141     _format               = Format::UNKNOWN;
142
143     set_tensor_shape(tensor_shape);
144 }
145
146 void TensorInfo::init(const TensorShape &tensor_shape, size_t num_channels, DataType data_type,
147                       const Strides &strides_in_bytes, size_t offset_first_element_in_bytes,
148                       size_t total_size_in_bytes, int fixed_point_position)
149 {
150     ARM_COMPUTE_ERROR_ON(num_channels == 0);
151     ARM_COMPUTE_ERROR_ON(data_type == DataType::QS8 && (fixed_point_position < 1 || fixed_point_position > 6));
152     ARM_COMPUTE_ERROR_ON(data_type == DataType::QS16 && (fixed_point_position < 1 || fixed_point_position > 14));
153
154     _fixed_point_position          = fixed_point_position;
155     _data_type                     = data_type;
156     _num_channels                  = num_channels;
157     _format                        = Format::UNKNOWN;
158     _tensor_shape                  = tensor_shape;
159     _offset_first_element_in_bytes = offset_first_element_in_bytes;
160     _strides_in_bytes              = strides_in_bytes;
161     _total_size                    = total_size_in_bytes;
162
163     _valid_region = ValidRegion{ Coordinates(), _tensor_shape };
164 }
165
166 void TensorInfo::init(const HOGInfo &hog_info, unsigned int width, unsigned int height)
167 {
168     // Number of cells for each block
169     const Size2D num_cells_per_block = hog_info.num_cells_per_block();
170
171     // Tensor Size = (Number of horizontal block positions) * (Number of vertical block positions)
172     const Size2D num_block_positions_per_img = hog_info.num_block_positions_per_image(Size2D(width, height));
173
174     // Number of tensor channels = (Number of cells per block) * (Number of bins per cell)
175     const size_t num_channels = num_cells_per_block.area() * hog_info.num_bins();
176
177     init(TensorShape(num_block_positions_per_img.width, num_block_positions_per_img.height), num_channels, DataType::F32);
178 }
179
180 size_t TensorInfo::init_auto_padding(const TensorShape &tensor_shape, Format format)
181 {
182     const size_t   num_channels = num_channels_from_format(format);
183     const DataType type         = data_type_from_format(format);
184     size_t         total_size   = init_auto_padding(tensor_shape, num_channels, type);
185
186     _format = format;
187
188     return total_size;
189 }
190
191 size_t TensorInfo::init_auto_padding(const TensorShape &tensor_shape, size_t num_channels, DataType data_type, int fixed_point_position)
192 {
193     ARM_COMPUTE_ERROR_ON(num_channels == 0);
194     ARM_COMPUTE_ERROR_ON(data_type == DataType::QS8 && (fixed_point_position < 1 || fixed_point_position > 6));
195     ARM_COMPUTE_ERROR_ON(data_type == DataType::QS16 && (fixed_point_position < 1 || fixed_point_position > 14));
196
197     _fixed_point_position = fixed_point_position;
198     _data_type            = data_type;
199     _num_channels         = num_channels;
200     _format               = Format::UNKNOWN;
201     _tensor_shape         = tensor_shape;
202
203     _valid_region = ValidRegion{ Coordinates(), _tensor_shape };
204
205     auto_padding();
206
207     return _total_size;
208 }
209
210 size_t TensorInfo::init_auto_padding(const HOGInfo &hog_info, unsigned int width, unsigned int height)
211 {
212     // Number of cells for each block
213     const Size2D num_cells_per_block = hog_info.num_cells_per_block();
214
215     // Tensor Size = (Number of horizontal block positions) * (Number of vertical block positions)
216     const Size2D num_block_positions_per_img = hog_info.num_block_positions_per_image(Size2D(width, height));
217
218     // Number of tensor channels = (Number of cells per block) * (Number of bins per cell)
219     const size_t num_channels = num_cells_per_block.area() * hog_info.num_bins();
220
221     return init_auto_padding(TensorShape(num_block_positions_per_img.width, num_block_positions_per_img.height), num_channels, DataType::F32);
222 }
223
224 bool TensorInfo::auto_padding()
225 {
226     ARM_COMPUTE_ERROR_ON(!_is_resizable);
227
228     // Some kernels compute 32 elements at the time, worst case scenario they
229     // will read 32 values after the last element
230     const size_t extra_pad_x = _tensor_shape.num_dimensions() < 1 ? 0 : 32;
231     const size_t pad_x       = _tensor_shape.num_dimensions() < 1 ? 0 : 4;
232     const size_t pad_y       = _tensor_shape.num_dimensions() < 2 ? 0 : 4;
233
234     return extend_padding(PaddingSize(pad_y, pad_x + extra_pad_x, pad_y, pad_x));
235 }
236
237 std::tuple<Strides, size_t, size_t> TensorInfo::calculate_padding_requirements(const PaddingSize &padding)
238 {
239     // Calculate resulting stride for the X, Y and Z dimension
240     const size_t stride_x = element_size();
241     const size_t stride_y = (padding.left + _tensor_shape[0] + padding.right) * stride_x;
242     const size_t stride_z = (padding.top + _tensor_shape[1] + padding.bottom) * stride_y;
243
244     Strides      required_strides;
245     size_t       required_total_size           = 0;
246     const size_t required_offset_first_element = padding.left * stride_x + padding.top * stride_y;
247
248     switch(_tensor_shape.num_dimensions())
249     {
250         case 0:
251         {
252             if(_tensor_shape.total_size() > 0)
253             {
254                 required_strides    = Strides(stride_x, stride_x);
255                 required_total_size = stride_z;
256             }
257             break;
258         }
259         case 1:
260             required_strides    = compute_strides(*this, stride_x, stride_y);
261             required_total_size = stride_z;
262             break;
263         case 2:
264             required_strides    = compute_strides(*this, stride_x, stride_y);
265             required_total_size = stride_z;
266             break;
267         default:
268         {
269             required_strides = compute_strides(*this, stride_x, stride_y, stride_z);
270
271             const unsigned int idx_last_dimension = _tensor_shape.num_dimensions() - 1;
272
273             required_total_size = _tensor_shape[idx_last_dimension] * required_strides[idx_last_dimension];
274             break;
275         }
276     }
277
278     return std::make_tuple(required_strides, required_offset_first_element, required_total_size);
279 }
280
281 bool TensorInfo::extend_padding(const PaddingSize &padding)
282 {
283     ARM_COMPUTE_ERROR_ON(!_is_resizable);
284
285     bool updated = false;
286
287     if(padding.top > _padding.top)
288     {
289         _padding.top = padding.top;
290         updated      = true;
291     }
292
293     if(padding.right > _padding.right)
294     {
295         _padding.right = padding.right;
296         updated        = true;
297     }
298
299     if(padding.bottom > _padding.bottom)
300     {
301         _padding.bottom = padding.bottom;
302         updated         = true;
303     }
304
305     if(padding.left > _padding.left)
306     {
307         _padding.left = padding.left;
308         updated       = true;
309     }
310
311     std::tie(_strides_in_bytes, _offset_first_element_in_bytes, _total_size) = calculate_padding_requirements(_padding);
312
313     return updated;
314 }
315
316 std::unique_ptr<ITensorInfo> TensorInfo::clone() const
317 {
318     return support::cpp14::make_unique<TensorInfo>(*this);
319 }
320
321 ITensorInfo &TensorInfo::set_data_type(DataType data_type)
322 {
323     _data_type = data_type;
324     _format    = Format::UNKNOWN;
325     return set_tensor_shape(tensor_shape()); // Force total size and strides to update
326 }
327
328 ITensorInfo &TensorInfo::set_num_channels(int num_channels)
329 {
330     _num_channels = num_channels;
331     _format       = Format::UNKNOWN;
332     return *this;
333 }
334
335 ITensorInfo &TensorInfo::set_format(Format format)
336 {
337     _format = format;
338
339     if(_data_type == DataType::UNKNOWN)
340     {
341         _num_channels = num_channels_from_format(format);
342         _data_type    = data_type_from_format(format);
343     }
344     else
345     {
346         ARM_COMPUTE_ERROR_ON(num_channels_from_format(format) != _num_channels);
347         ARM_COMPUTE_ERROR_ON(data_type_from_format(format) != _data_type);
348     }
349     return *this;
350 }
351
352 ITensorInfo &TensorInfo::set_tensor_shape(const TensorShape &shape)
353 {
354     _tensor_shape                  = shape;
355     _offset_first_element_in_bytes = 0;
356     _strides_in_bytes              = compute_strides(*this);
357
358     if(_tensor_shape.num_dimensions() == 0)
359     {
360         _total_size = _strides_in_bytes[0];
361     }
362     else
363     {
364         const unsigned int idx_last_dimension = _tensor_shape.num_dimensions() - 1;
365         _total_size                           = _tensor_shape[idx_last_dimension] * _strides_in_bytes[idx_last_dimension];
366     }
367
368     std::tie(_strides_in_bytes, _offset_first_element_in_bytes, _total_size) = calculate_padding_requirements(_padding);
369
370     _valid_region = ValidRegion{ Coordinates(), _tensor_shape };
371     return *this;
372 }
373
374 ITensorInfo &TensorInfo::set_fixed_point_position(int fixed_point_position)
375 {
376     ARM_COMPUTE_ERROR_ON(_data_type == DataType::QS8 && (fixed_point_position < 1 || fixed_point_position > 6));
377     ARM_COMPUTE_ERROR_ON(_data_type == DataType::QS16 && (fixed_point_position < 1 || fixed_point_position > 14));
378     _fixed_point_position = fixed_point_position;
379     return *this;
380 }
381
382 ITensorInfo &TensorInfo::set_quantization_info(const QuantizationInfo &quantization_info)
383 {
384     _quantization_info = quantization_info;
385     return *this;
386 }
387
388 ITensorInfo &TensorInfo::set_data_layout(const DataLayout &data_layout)
389 {
390     _data_layout = data_layout;
391     return *this;
392 }
393
394 ITensorInfo &TensorInfo::reset_padding()
395 {
396     _padding = PaddingSize();
397     if(((_format != Format::UNKNOWN) || (_data_type != DataType::UNKNOWN)) && _total_size != 0)
398     {
399         std::tie(_strides_in_bytes, _offset_first_element_in_bytes, _total_size) = calculate_padding_requirements(_padding);
400     }
401     return *this;
402 }
403
404 size_t TensorInfo::offset_element_in_bytes(const Coordinates &pos) const
405 {
406     ARM_COMPUTE_ERROR_ON_COORDINATES_DIMENSIONS_GTE(pos, _tensor_shape.num_dimensions());
407
408     size_t offset = _offset_first_element_in_bytes;
409
410     for(size_t i = 0; i < _tensor_shape.num_dimensions(); ++i)
411     {
412         offset += pos[i] * _strides_in_bytes[i];
413     }
414
415     return offset;
416 }