xref: /aosp_15_r20/external/ComputeLibrary/src/core/TensorInfo.cpp (revision c217d954acce2dbc11938adb493fc0abd69584f3)
1 /*
2  * Copyright (c) 2016-2023 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/Helpers.h"
28 #include "arm_compute/core/TensorInfo.h"
29 #include "arm_compute/core/Validate.h"
30 #include "src/core/helpers/Utils.h"
31 
32 #include <memory>
33 
34 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(), _dims_state(), _data_type(DataType::UNKNOWN), _format(Format::UNKNOWN), _is_resizable{ true },
38       _valid_region{ Coordinates(), _tensor_shape }, _padding{ 0 }, _quantization_info(), _data_layout(DataLayout::NCHW), _are_values_constant(true), _id(invalid_tensor_id), _lock_paddings(false)
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     _dims_state                    = info.tensor_dims_state();
51     _data_type                     = info.data_type();
52     _format                        = info.format();
53     _is_resizable                  = info.is_resizable();
54     _valid_region                  = info.valid_region();
55     _padding                       = info.padding();
56     _quantization_info             = info.quantization_info();
57     _data_layout                   = info.data_layout();
58     _are_values_constant           = info.are_values_constant();
59     _id                            = info.id();
60     _lock_paddings                 = info.lock_paddings();
61 }
62 
TensorInfo(const TensorInfo & info)63 TensorInfo::TensorInfo(const TensorInfo &info)
64     : TensorInfo()
65 {
66     _total_size                    = info.total_size();
67     _offset_first_element_in_bytes = info.offset_first_element_in_bytes();
68     _strides_in_bytes              = info.strides_in_bytes();
69     _num_channels                  = info.num_channels();
70     _tensor_shape                  = info.tensor_shape();
71     _dims_state                    = info.tensor_dims_state();
72     _data_type                     = info.data_type();
73     _format                        = info.format();
74     _is_resizable                  = info.is_resizable();
75     _valid_region                  = info.valid_region();
76     _padding                       = info.padding();
77     _quantization_info             = info.quantization_info();
78     _data_layout                   = info.data_layout();
79     _are_values_constant           = info.are_values_constant();
80     _id                            = info.id();
81     _lock_paddings                 = false;
82 }
TensorInfo(Format format)83 TensorInfo::TensorInfo(Format format)
84     : TensorInfo(TensorShape(), format)
85 {
86 }
87 
TensorInfo(unsigned int width,unsigned int height,Format format)88 TensorInfo::TensorInfo(unsigned int width, unsigned int height, Format format)
89     : TensorInfo(TensorShape(width, height), format)
90 {
91 }
92 
TensorInfo(const TensorShape & tensor_shape,Format format)93 TensorInfo::TensorInfo(const TensorShape &tensor_shape, Format format)
94     : TensorInfo()
95 {
96     init(tensor_shape, format);
97 }
98 
TensorInfo(size_t num_channels,DataType data_type)99 TensorInfo::TensorInfo(size_t num_channels, DataType data_type)
100     : TensorInfo()
101 {
102     init(TensorShape(), num_channels, data_type);
103 }
104 
TensorInfo(const TensorShape & tensor_shape,size_t num_channels,DataType data_type)105 TensorInfo::TensorInfo(const TensorShape &tensor_shape, size_t num_channels, DataType data_type)
106     : TensorInfo()
107 {
108     init(tensor_shape, num_channels, data_type);
109 }
110 
TensorInfo(const TensorShape & tensor_shape,size_t num_channels,DataType data_type,QuantizationInfo quantization_info)111 TensorInfo::TensorInfo(const TensorShape &tensor_shape, size_t num_channels, DataType data_type, QuantizationInfo quantization_info)
112     : TensorInfo()
113 {
114     init(tensor_shape, num_channels, data_type);
115     _quantization_info = std::move(quantization_info);
116 }
117 
TensorInfo(const TensorShape & tensor_shape,size_t num_channels,DataType data_type,DataLayout data_layout)118 TensorInfo::TensorInfo(const TensorShape &tensor_shape, size_t num_channels, DataType data_type, DataLayout data_layout)
119     : TensorInfo()
120 {
121     init(tensor_shape, num_channels, data_type);
122     _data_layout = data_layout;
123 }
124 
init(Format format)125 void TensorInfo::init(Format format)
126 {
127     init(TensorShape(), format);
128 }
129 
init(const TensorShape & tensor_shape,Format format)130 void TensorInfo::init(const TensorShape &tensor_shape, Format format)
131 {
132     size_t         num_channels = num_channels_from_format(format);
133     const DataType type         = data_type_from_format(format);
134 
135     init(tensor_shape, num_channels, type);
136 
137     _format = format;
138 }
139 
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)140 void TensorInfo::init(const TensorShape &tensor_shape, Format format,
141                       const Strides &strides_in_bytes, size_t offset_first_element_in_bytes,
142                       size_t total_size_in_bytes)
143 {
144     size_t         num_channels = num_channels_from_format(format);
145     const DataType type         = data_type_from_format(format);
146 
147     init(tensor_shape, num_channels, type, strides_in_bytes, offset_first_element_in_bytes, total_size_in_bytes);
148 
149     _format = format;
150 }
151 
init(size_t num_channels,DataType data_type)152 void TensorInfo::init(size_t num_channels, DataType data_type)
153 {
154     init(TensorShape(), num_channels, data_type);
155 }
156 
init(const TensorShape & tensor_shape,size_t num_channels,DataType data_type)157 void TensorInfo::init(const TensorShape &tensor_shape, size_t num_channels, DataType data_type)
158 {
159     ARM_COMPUTE_ERROR_ON(num_channels == 0);
160 
161     _data_type    = data_type;
162     _num_channels = num_channels;
163     _format       = Format::UNKNOWN;
164 
165     set_tensor_shape(tensor_shape);
166 }
167 
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)168 void TensorInfo::init(const TensorShape &tensor_shape, size_t num_channels, DataType data_type,
169                       const Strides &strides_in_bytes, size_t offset_first_element_in_bytes,
170                       size_t total_size_in_bytes)
171 {
172     ARM_COMPUTE_ERROR_ON(num_channels == 0);
173 
174     _data_type                     = data_type;
175     _num_channels                  = num_channels;
176     _format                        = Format::UNKNOWN;
177     _tensor_shape                  = tensor_shape;
178     _offset_first_element_in_bytes = offset_first_element_in_bytes;
179     _strides_in_bytes              = strides_in_bytes;
180     _total_size                    = total_size_in_bytes;
181 
182     _valid_region = ValidRegion{ Coordinates(), _tensor_shape };
183 }
184 
init_auto_padding(const TensorShape & tensor_shape,Format format)185 size_t TensorInfo::init_auto_padding(const TensorShape &tensor_shape, Format format)
186 {
187     const size_t   num_channels = num_channels_from_format(format);
188     const DataType type         = data_type_from_format(format);
189     size_t         total_size   = init_auto_padding(tensor_shape, num_channels, type);
190 
191     _format = format;
192 
193     return total_size;
194 }
195 
init_auto_padding(const TensorShape & tensor_shape,size_t num_channels,DataType data_type)196 size_t TensorInfo::init_auto_padding(const TensorShape &tensor_shape, size_t num_channels, DataType data_type)
197 {
198     ARM_COMPUTE_ERROR_ON(num_channels == 0);
199 
200     _data_type    = data_type;
201     _num_channels = num_channels;
202     _format       = Format::UNKNOWN;
203     _tensor_shape = tensor_shape;
204 
205     _valid_region = ValidRegion{ Coordinates(), _tensor_shape };
206 
207     auto_padding();
208 
209     return _total_size;
210 }
211 
auto_padding()212 bool TensorInfo::auto_padding()
213 {
214     ARM_COMPUTE_ERROR_ON(!_is_resizable);
215 
216     // Some kernels compute 32 elements at the time, worst case scenario they
217     // will read 32 values after the last element
218     const size_t extra_pad_x = _tensor_shape.num_dimensions() < 1 ? 0 : 32;
219     const size_t pad_x       = _tensor_shape.num_dimensions() < 1 ? 0 : 4;
220     const size_t pad_y       = _tensor_shape.num_dimensions() < 2 ? 0 : 4;
221 
222     return extend_padding(PaddingSize(pad_y, pad_x + extra_pad_x, pad_y, pad_x));
223 }
224 
calculate_padding_requirements(const PaddingSize & padding)225 std::tuple<Strides, size_t, size_t> TensorInfo::calculate_padding_requirements(const PaddingSize &padding)
226 {
227     // Calculate resulting stride for the X, Y and Z dimension
228     const size_t stride_x = element_size();
229     const size_t stride_y = (padding.left + _tensor_shape[0] + padding.right) * stride_x;
230     const size_t stride_z = (padding.top + _tensor_shape[1] + padding.bottom) * stride_y;
231 
232     Strides      required_strides;
233     size_t       required_total_size           = 0;
234     const size_t required_offset_first_element = padding.left * stride_x + padding.top * stride_y;
235 
236     switch(_tensor_shape.num_dimensions())
237     {
238         case 0:
239         {
240             if(_tensor_shape.total_size() > 0)
241             {
242                 required_strides    = Strides(stride_x, stride_x);
243                 required_total_size = stride_z;
244             }
245             break;
246         }
247         case 1:
248             required_strides    = compute_strides(*this, stride_x, stride_y);
249             required_total_size = stride_z;
250             break;
251         case 2:
252             required_strides    = compute_strides(*this, stride_x, stride_y);
253             required_total_size = stride_z;
254             break;
255         default:
256         {
257             required_strides = compute_strides(*this, stride_x, stride_y, stride_z);
258 
259             const unsigned int idx_last_dimension = _tensor_shape.num_dimensions() - 1;
260 
261             required_total_size = static_cast<size_t>(_tensor_shape[idx_last_dimension]) * required_strides[idx_last_dimension];
262             break;
263         }
264     }
265 
266     return std::make_tuple(required_strides, required_offset_first_element, required_total_size);
267 }
268 
set_lock_paddings(bool flag)269 ITensorInfo &TensorInfo::set_lock_paddings(bool flag)
270 {
271     _lock_paddings = flag;
272     return *this;
273 }
274 
lock_paddings() const275 bool TensorInfo::lock_paddings() const
276 {
277     return _lock_paddings;
278 }
279 
extend_padding(const PaddingSize & padding)280 bool TensorInfo::extend_padding(const PaddingSize &padding)
281 {
282     ARM_COMPUTE_ERROR_ON(_lock_paddings);
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 
clone() const316 std::unique_ptr<ITensorInfo> TensorInfo::clone() const
317 {
318     return std::make_unique<TensorInfo>(*this);
319 }
320 
set_data_type(DataType data_type)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 
set_num_channels(int num_channels)328 ITensorInfo &TensorInfo::set_num_channels(int num_channels)
329 {
330     _num_channels = num_channels;
331     _format       = Format::UNKNOWN;
332     return *this;
333 }
334 
set_format(Format format)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 
set_tensor_shape(const TensorShape & shape)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                           = static_cast<size_t>(_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 
set_tensor_dims_state(const TensorDimsState & state)374 ITensorInfo &TensorInfo::set_tensor_dims_state(const TensorDimsState &state)
375 {
376     _dims_state = state;
377     return *this;
378 }
379 
set_quantization_info(const QuantizationInfo & quantization_info)380 ITensorInfo &TensorInfo::set_quantization_info(const QuantizationInfo &quantization_info)
381 {
382     _quantization_info = quantization_info;
383     return *this;
384 }
385 
set_data_layout(const DataLayout & data_layout)386 ITensorInfo &TensorInfo::set_data_layout(const DataLayout &data_layout)
387 {
388     _data_layout = data_layout;
389     return *this;
390 }
391 
reset_padding()392 ITensorInfo &TensorInfo::reset_padding()
393 {
394     _padding = PaddingSize();
395     if(((_format != Format::UNKNOWN) || (_data_type != DataType::UNKNOWN)) && _total_size != 0)
396     {
397         std::tie(_strides_in_bytes, _offset_first_element_in_bytes, _total_size) = calculate_padding_requirements(_padding);
398     }
399     return *this;
400 }
401 
offset_element_in_bytes(const Coordinates & pos) const402 int32_t TensorInfo::offset_element_in_bytes(const Coordinates &pos) const
403 {
404     ARM_COMPUTE_ERROR_ON_COORDINATES_DIMENSIONS_GTE(pos, _tensor_shape.num_dimensions());
405 
406     int32_t offset = _offset_first_element_in_bytes;
407 
408     for(size_t i = 0; i < _tensor_shape.num_dimensions(); ++i)
409     {
410         offset += pos[i] * _strides_in_bytes[i];
411     }
412 
413     return offset;
414 }
415 } // namespace arm_compute
416