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