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