blob: 60e76bf84ab10d413d6e70e031618373956f7523 [file] [log] [blame]
Anthony Barbier6ff3b192017-09-04 18:44:23 +01001/*
2 * Copyright (c) 2016, 2017 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"
Michel Iwaniec00633802017-10-12 14:14:15 +010029#include "arm_compute/core/TensorInfo.h"
Anthony Barbier6ff3b192017-09-04 18:44:23 +010030#include "arm_compute/core/Validate.h"
Georgios Pinitas283c1792017-11-10 18:14:06 +000031#include "support/ToolchainSupport.h"
Anthony Barbier6ff3b192017-09-04 18:44:23 +010032
33using namespace arm_compute;
34
35TensorInfo::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),
Michel Iwaniec00633802017-10-12 14:14:15 +010037 _is_resizable{ true }, _valid_region{ Coordinates(), _tensor_shape }, _padding{ 0 }, _quantization_info()
Anthony Barbier6ff3b192017-09-04 18:44:23 +010038{
39}
40
41TensorInfo::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();
Georgios Pinitas30902ed2017-11-14 15:32:57 +000055 _quantization_info = info.quantization_info();
Anthony Barbier6ff3b192017-09-04 18:44:23 +010056}
57
58TensorInfo::TensorInfo(Format format)
59 : TensorInfo(TensorShape(), format)
60{
61}
62
63TensorInfo::TensorInfo(unsigned int width, unsigned int height, Format format)
64 : TensorInfo(TensorShape(width, height), format)
65{
66}
67
68TensorInfo::TensorInfo(const TensorShape &tensor_shape, Format format)
69 : TensorInfo()
70{
71 init(tensor_shape, format);
72}
73
74TensorInfo::TensorInfo(size_t num_channels, DataType data_type, size_t fixed_point_position)
75 : TensorInfo()
76{
77 init(TensorShape(), num_channels, data_type, fixed_point_position);
78}
79
80TensorInfo::TensorInfo(const TensorShape &tensor_shape, size_t num_channels, DataType data_type, int fixed_point_position)
81 : TensorInfo()
82{
83 init(tensor_shape, num_channels, data_type, fixed_point_position);
84}
85
Michel Iwaniec00633802017-10-12 14:14:15 +010086TensorInfo::TensorInfo(const TensorShape &tensor_shape, size_t num_channels, DataType data_type, QuantizationInfo quantization_info)
87 : TensorInfo()
88{
89 init(tensor_shape, num_channels, data_type, 0);
90 _quantization_info = quantization_info;
91}
92
Anthony Barbier6ff3b192017-09-04 18:44:23 +010093TensorInfo::TensorInfo(const HOGInfo &hog_info, unsigned int width, unsigned int height)
94 : TensorInfo()
95{
96 init(hog_info, width, height);
97}
98
99void TensorInfo::init(Format format)
100{
101 init(TensorShape(), format);
102}
103
104void TensorInfo::init(const TensorShape &tensor_shape, Format format)
105{
106 size_t num_channels = num_channels_from_format(format);
107 const DataType type = data_type_from_format(format);
108
109 init(tensor_shape, num_channels, type);
110
111 _format = format;
112}
113
114void TensorInfo::init(const TensorShape &tensor_shape, Format format,
115 const Strides &strides_in_bytes, size_t offset_first_element_in_bytes,
116 size_t total_size_in_bytes)
117{
118 size_t num_channels = num_channels_from_format(format);
119 const DataType type = data_type_from_format(format);
120
121 init(tensor_shape, num_channels, type, strides_in_bytes, offset_first_element_in_bytes, total_size_in_bytes);
122
123 _format = format;
124}
125
126void TensorInfo::init(size_t num_channels, DataType data_type, size_t fixed_point_position)
127{
128 init(TensorShape(), num_channels, data_type, fixed_point_position);
129}
130
131void TensorInfo::init(const TensorShape &tensor_shape, size_t num_channels, DataType data_type, int fixed_point_position)
132{
133 ARM_COMPUTE_ERROR_ON(num_channels == 0);
134 ARM_COMPUTE_ERROR_ON(data_type == DataType::QS8 && (fixed_point_position < 1 || fixed_point_position > 6));
135 ARM_COMPUTE_ERROR_ON(data_type == DataType::QS16 && (fixed_point_position < 1 || fixed_point_position > 14));
136
137 _fixed_point_position = fixed_point_position;
138 _data_type = data_type;
139 _num_channels = num_channels;
140 _format = Format::UNKNOWN;
141
142 set_tensor_shape(tensor_shape);
143}
144
145void TensorInfo::init(const TensorShape &tensor_shape, size_t num_channels, DataType data_type,
146 const Strides &strides_in_bytes, size_t offset_first_element_in_bytes,
147 size_t total_size_in_bytes, int fixed_point_position)
148{
149 ARM_COMPUTE_ERROR_ON(num_channels == 0);
150 ARM_COMPUTE_ERROR_ON(data_type == DataType::QS8 && (fixed_point_position < 1 || fixed_point_position > 6));
151 ARM_COMPUTE_ERROR_ON(data_type == DataType::QS16 && (fixed_point_position < 1 || fixed_point_position > 14));
152
153 _fixed_point_position = fixed_point_position;
154 _data_type = data_type;
155 _num_channels = num_channels;
156 _format = Format::UNKNOWN;
157 _tensor_shape = tensor_shape;
158 _offset_first_element_in_bytes = offset_first_element_in_bytes;
159 _strides_in_bytes = strides_in_bytes;
160 _total_size = total_size_in_bytes;
161
162 Coordinates coordinates;
163 coordinates.set_num_dimensions(_tensor_shape.num_dimensions());
164 _valid_region = ValidRegion{ coordinates, _tensor_shape };
165}
166
167void TensorInfo::init(const HOGInfo &hog_info, unsigned int width, unsigned int height)
168{
169 // Number of cells for each block
170 const Size2D num_cells_per_block = hog_info.num_cells_per_block();
171
172 // Tensor Size = (Number of horizontal blocks) * (Number of vertical blocks )
173 const Size2D num_blocks_per_img = hog_info.num_blocks_per_image(Size2D(width, height));
174
175 // Number of tensor channels = (Number of cells per block) * (Number of bins per cell)
176 const size_t num_channels = num_cells_per_block.area() * hog_info.num_bins();
177
178 init(TensorShape(num_blocks_per_img.width, num_blocks_per_img.height), num_channels, DataType::F32);
179}
180
181size_t TensorInfo::init_auto_padding(const TensorShape &tensor_shape, Format format)
182{
183 const size_t num_channels = num_channels_from_format(format);
184 const DataType type = data_type_from_format(format);
185 size_t total_size = init_auto_padding(tensor_shape, num_channels, type);
186
187 _format = format;
188
189 return total_size;
190}
191
192size_t TensorInfo::init_auto_padding(const TensorShape &tensor_shape, size_t num_channels, DataType data_type, int fixed_point_position)
193{
194 ARM_COMPUTE_ERROR_ON(num_channels == 0);
195 ARM_COMPUTE_ERROR_ON(data_type == DataType::QS8 && (fixed_point_position < 1 || fixed_point_position > 6));
196 ARM_COMPUTE_ERROR_ON(data_type == DataType::QS16 && (fixed_point_position < 1 || fixed_point_position > 14));
197
198 _fixed_point_position = fixed_point_position;
199 _data_type = data_type;
200 _num_channels = num_channels;
201 _format = Format::UNKNOWN;
202 _tensor_shape = tensor_shape;
203
204 Coordinates coordinates;
205 coordinates.set_num_dimensions(_tensor_shape.num_dimensions());
206 _valid_region = ValidRegion{ coordinates, _tensor_shape };
207
208 auto_padding();
209
210 return _total_size;
211}
212
213size_t TensorInfo::init_auto_padding(const HOGInfo &hog_info, unsigned int width, unsigned int height)
214{
215 // Number of cells for each block
216 const Size2D num_cells_per_block = hog_info.num_cells_per_block();
217
218 // Tensor Size = (Number of horizontal blocks) * (Number of vertical blocks )
219 const Size2D num_blocks_per_img = hog_info.num_blocks_per_image(Size2D(width, height));
220
221 // Number of tensor channels = (Number of cells per block) * (Number of bins per cell)
222 const size_t num_channels = num_cells_per_block.area() * hog_info.num_bins();
223
224 return init_auto_padding(TensorShape(num_blocks_per_img.width, num_blocks_per_img.height), num_channels, DataType::F32);
225}
226
227bool TensorInfo::auto_padding()
228{
229 ARM_COMPUTE_ERROR_ON(!_is_resizable);
230
231 // Some kernels compute 32 elements at the time, worst case scenario they
232 // will read 32 values after the last element
233 const size_t extra_pad_x = _tensor_shape.num_dimensions() < 1 ? 0 : 32;
234 const size_t pad_x = _tensor_shape.num_dimensions() < 1 ? 0 : 4;
235 const size_t pad_y = _tensor_shape.num_dimensions() < 2 ? 0 : 4;
236
237 return extend_padding(PaddingSize(pad_y, pad_x + extra_pad_x, pad_y, pad_x));
238}
239
240std::tuple<Strides, size_t, size_t> TensorInfo::calculate_padding_requirements(const PaddingSize &padding)
241{
242 // Calculate resulting stride for the X, Y and Z dimension
243 const size_t stride_x = element_size();
244 const size_t stride_y = (padding.left + _tensor_shape[0] + padding.right) * stride_x;
245 const size_t stride_z = (padding.top + _tensor_shape[1] + padding.bottom) * stride_y;
246
247 Strides required_strides;
248 size_t required_total_size = 0;
249 const size_t required_offset_first_element = padding.left * stride_x + padding.top * stride_y;
250
251 switch(_tensor_shape.num_dimensions())
252 {
253 case 0:
254 {
255 if(_tensor_shape.total_size() > 0)
256 {
Gian Marco Iodiceee94f6a2017-09-11 17:38:02 +0100257 required_strides = Strides(stride_x, stride_x);
Anthony Barbier6ff3b192017-09-04 18:44:23 +0100258 required_total_size = stride_z;
259 }
260 break;
261 }
262 case 1:
Gian Marco Iodiceee94f6a2017-09-11 17:38:02 +0100263 required_strides = compute_strides(*this, stride_x, stride_y);
Anthony Barbier6ff3b192017-09-04 18:44:23 +0100264 required_total_size = stride_z;
265 break;
266 case 2:
267 required_strides = compute_strides(*this, stride_x, stride_y);
268 required_total_size = stride_z;
269 break;
270 default:
271 {
272 required_strides = compute_strides(*this, stride_x, stride_y, stride_z);
273
274 const unsigned int idx_last_dimension = _tensor_shape.num_dimensions() - 1;
275
276 required_total_size = _tensor_shape[idx_last_dimension] * required_strides[idx_last_dimension];
277 break;
278 }
279 }
280
281 return std::make_tuple(required_strides, required_offset_first_element, required_total_size);
282}
283
284bool TensorInfo::extend_padding(const PaddingSize &padding)
285{
286 ARM_COMPUTE_ERROR_ON(!_is_resizable);
287
288 bool updated = false;
289
290 if(padding.top > _padding.top)
291 {
292 _padding.top = padding.top;
293 updated = true;
294 }
295
296 if(padding.right > _padding.right)
297 {
298 _padding.right = padding.right;
299 updated = true;
300 }
301
302 if(padding.bottom > _padding.bottom)
303 {
304 _padding.bottom = padding.bottom;
305 updated = true;
306 }
307
308 if(padding.left > _padding.left)
309 {
310 _padding.left = padding.left;
311 updated = true;
312 }
313
314 std::tie(_strides_in_bytes, _offset_first_element_in_bytes, _total_size) = calculate_padding_requirements(_padding);
315
316 return updated;
317}
318
Georgios Pinitas283c1792017-11-10 18:14:06 +0000319std::unique_ptr<ITensorInfo> TensorInfo::clone() const
320{
321 return support::cpp14::make_unique<TensorInfo>(*this);
322}
323
324ITensorInfo &TensorInfo::set_data_type(DataType data_type)
Anthony Barbier6ff3b192017-09-04 18:44:23 +0100325{
326 _data_type = data_type;
327 _format = Format::UNKNOWN;
Georgios Pinitas283c1792017-11-10 18:14:06 +0000328 return *this;
Anthony Barbier6ff3b192017-09-04 18:44:23 +0100329}
330
Georgios Pinitas283c1792017-11-10 18:14:06 +0000331ITensorInfo &TensorInfo::set_num_channels(int num_channels)
Anthony Barbier6ff3b192017-09-04 18:44:23 +0100332{
333 _num_channels = num_channels;
334 _format = Format::UNKNOWN;
Georgios Pinitas283c1792017-11-10 18:14:06 +0000335 return *this;
Anthony Barbier6ff3b192017-09-04 18:44:23 +0100336}
337
Georgios Pinitas283c1792017-11-10 18:14:06 +0000338ITensorInfo &TensorInfo::set_format(Format format)
Anthony Barbier6ff3b192017-09-04 18:44:23 +0100339{
340 _format = format;
341
342 if(_data_type == DataType::UNKNOWN)
343 {
344 _num_channels = num_channels_from_format(format);
345 _data_type = data_type_from_format(format);
346 }
347 else
348 {
349 ARM_COMPUTE_ERROR_ON(num_channels_from_format(format) != _num_channels);
350 ARM_COMPUTE_ERROR_ON(data_type_from_format(format) != _data_type);
351 }
Georgios Pinitas283c1792017-11-10 18:14:06 +0000352 return *this;
Anthony Barbier6ff3b192017-09-04 18:44:23 +0100353}
354
Georgios Pinitas283c1792017-11-10 18:14:06 +0000355ITensorInfo &TensorInfo::set_tensor_shape(TensorShape shape)
Anthony Barbier6ff3b192017-09-04 18:44:23 +0100356{
357 _tensor_shape = shape;
358 _offset_first_element_in_bytes = 0;
359 _strides_in_bytes = compute_strides(*this);
360
361 if(_tensor_shape.num_dimensions() == 0)
362 {
363 _total_size = _strides_in_bytes[0];
364 }
365 else
366 {
367 const unsigned int idx_last_dimension = _tensor_shape.num_dimensions() - 1;
368 _total_size = _tensor_shape[idx_last_dimension] * _strides_in_bytes[idx_last_dimension];
369 }
370
371 Coordinates coordinates;
372 coordinates.set_num_dimensions(_tensor_shape.num_dimensions());
373 _valid_region = ValidRegion{ coordinates, _tensor_shape };
Georgios Pinitas283c1792017-11-10 18:14:06 +0000374 return *this;
Anthony Barbier6ff3b192017-09-04 18:44:23 +0100375}
376
Georgios Pinitas283c1792017-11-10 18:14:06 +0000377ITensorInfo &TensorInfo::set_fixed_point_position(int fixed_point_position)
Anthony Barbier6ff3b192017-09-04 18:44:23 +0100378{
379 ARM_COMPUTE_ERROR_ON(_data_type == DataType::QS8 && (fixed_point_position < 1 || fixed_point_position > 6));
380 ARM_COMPUTE_ERROR_ON(_data_type == DataType::QS16 && (fixed_point_position < 1 || fixed_point_position > 14));
381 _fixed_point_position = fixed_point_position;
Georgios Pinitas283c1792017-11-10 18:14:06 +0000382 return *this;
383}
384
385ITensorInfo &TensorInfo::set_quantization_info(QuantizationInfo quantization_info)
386{
387 _quantization_info = quantization_info;
388 return *this;
Anthony Barbier6ff3b192017-09-04 18:44:23 +0100389}
390
Georgios Pinitas30902ed2017-11-14 15:32:57 +0000391ITensorInfo &TensorInfo::reset_padding()
392{
393 _padding = PaddingSize();
394 if(((_format != Format::UNKNOWN) || (_data_type != DataType::UNKNOWN)) && _total_size != 0)
395 {
396 std::tie(_strides_in_bytes, _offset_first_element_in_bytes, _total_size) = calculate_padding_requirements(_padding);
397 }
398 return *this;
399}
400
Anthony Barbier6ff3b192017-09-04 18:44:23 +0100401size_t TensorInfo::offset_element_in_bytes(const Coordinates &pos) const
402{
403 ARM_COMPUTE_ERROR_ON_COORDINATES_DIMENSIONS_GTE(pos, _tensor_shape.num_dimensions());
404
405 size_t offset = _offset_first_element_in_bytes;
406
407 for(size_t i = 0; i < _tensor_shape.num_dimensions(); ++i)
408 {
409 offset += pos[i] * _strides_in_bytes[i];
410 }
411
412 return offset;
413}