arm_compute v17.04
[platform/upstream/armcl.git] / src / core / TensorInfo.cpp
1 /*
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"
29 #include "arm_compute/core/Validate.h"
30
31 using namespace arm_compute;
32
33 TensorInfo::TensorInfo()
34     : _total_size(0), _fixed_point_pos(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 },
35       _valid_region{ Coordinates(), _tensor_shape }, _padding{ 0 }
36 {
37 }
38
39 TensorInfo::TensorInfo(unsigned int width, unsigned int height, Format format)
40     : TensorInfo(TensorShape(width, height), format)
41 {
42 }
43
44 TensorInfo::TensorInfo(const TensorShape &tensor_shape, Format format)
45     : TensorInfo()
46 {
47     init(tensor_shape, format);
48 }
49
50 TensorInfo::TensorInfo(const TensorShape &tensor_shape, size_t num_channels, DataType data_type, size_t fixed_point_pos)
51     : TensorInfo()
52 {
53     init(tensor_shape, num_channels, data_type, fixed_point_pos);
54 }
55
56 TensorInfo::TensorInfo(const HOGInfo &hog_info, unsigned int width, unsigned int height)
57     : TensorInfo()
58 {
59     init(hog_info, width, height);
60 }
61
62 void TensorInfo::init(const TensorShape &tensor_shape, Format format)
63 {
64     size_t         num_channels = num_channels_from_format(format);
65     const DataType type         = data_type_from_format(format);
66
67     init(tensor_shape, num_channels, type);
68
69     _format = format;
70 }
71
72 void TensorInfo::init(const TensorShape &tensor_shape, Format format,
73                       const Strides &strides_in_bytes, size_t offset_first_element_in_bytes,
74                       size_t total_size_in_bytes)
75 {
76     size_t         num_channels = num_channels_from_format(format);
77     const DataType type         = data_type_from_format(format);
78
79     init(tensor_shape, num_channels, type, strides_in_bytes, offset_first_element_in_bytes, total_size_in_bytes);
80
81     _format = format;
82 }
83
84 void TensorInfo::init(const TensorShape &tensor_shape, size_t num_channels, DataType data_type, size_t fixed_point_pos)
85 {
86     ARM_COMPUTE_ERROR_ON(0 == num_channels);
87
88     _fixed_point_pos               = fixed_point_pos;
89     _data_type                     = data_type;
90     _num_channels                  = num_channels;
91     _format                        = Format::UNKNOWN;
92     _tensor_shape                  = tensor_shape;
93     _offset_first_element_in_bytes = 0;
94     _strides_in_bytes              = compute_strides(*this);
95
96     const unsigned int idx_last_dimension = _tensor_shape.num_dimensions() - 1;
97     _total_size                           = _tensor_shape[idx_last_dimension] * _strides_in_bytes[idx_last_dimension];
98
99     Coordinates coordinates;
100     coordinates.set_num_dimensions(_tensor_shape.num_dimensions());
101     _valid_region = ValidRegion{ coordinates, _tensor_shape };
102 }
103
104 void TensorInfo::init(const TensorShape &tensor_shape, size_t num_channels, DataType data_type,
105                       const Strides &strides_in_bytes, size_t offset_first_element_in_bytes,
106                       size_t total_size_in_bytes, size_t fixed_point_pos)
107 {
108     ARM_COMPUTE_ERROR_ON(0 == num_channels);
109
110     _fixed_point_pos               = fixed_point_pos;
111     _data_type                     = data_type;
112     _num_channels                  = num_channels;
113     _format                        = Format::UNKNOWN;
114     _tensor_shape                  = tensor_shape;
115     _offset_first_element_in_bytes = offset_first_element_in_bytes;
116     _strides_in_bytes              = strides_in_bytes;
117     _total_size                    = total_size_in_bytes;
118
119     Coordinates coordinates;
120     coordinates.set_num_dimensions(_tensor_shape.num_dimensions());
121     _valid_region = ValidRegion{ coordinates, _tensor_shape };
122 }
123
124 void TensorInfo::init(const HOGInfo &hog_info, unsigned int width, unsigned int height)
125 {
126     // Number of cells for each block
127     const Size2D num_cells_per_block = hog_info.num_cells_per_block();
128
129     // Tensor Size = (Number of horizontal blocks) * (Number of vertical blocks )
130     const Size2D num_blocks_per_img = hog_info.num_blocks_per_image(Size2D(width, height));
131
132     // Number of tensor channels = (Number of cells per block) * (Number of bins per cell)
133     const size_t num_channels = num_cells_per_block.area() * hog_info.num_bins();
134
135     init(TensorShape(num_blocks_per_img.width, num_blocks_per_img.height), num_channels, DataType::F32);
136 }
137
138 size_t TensorInfo::init_auto_padding(const TensorShape &tensor_shape, Format format)
139 {
140     const size_t   num_channels = num_channels_from_format(format);
141     const DataType type         = data_type_from_format(format);
142     size_t         total_size   = init_auto_padding(tensor_shape, num_channels, type);
143
144     _format = format;
145
146     return total_size;
147 }
148
149 size_t TensorInfo::init_auto_padding(const TensorShape &tensor_shape, size_t num_channels, DataType data_type, size_t fixed_point_pos)
150 {
151     ARM_COMPUTE_ERROR_ON(0 == num_channels);
152
153     _fixed_point_pos = fixed_point_pos;
154     _data_type       = data_type;
155     _num_channels    = num_channels;
156     _format          = Format::UNKNOWN;
157     _tensor_shape    = tensor_shape;
158
159     Coordinates coordinates;
160     coordinates.set_num_dimensions(_tensor_shape.num_dimensions());
161     _valid_region = ValidRegion{ coordinates, _tensor_shape };
162
163     auto_padding();
164
165     return _total_size;
166 }
167
168 size_t TensorInfo::init_auto_padding(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 blocks) * (Number of vertical blocks )
174     const Size2D num_blocks_per_img = hog_info.num_blocks_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     return init_auto_padding(TensorShape(num_blocks_per_img.width, num_blocks_per_img.height), num_channels, DataType::F32);
180 }
181
182 bool TensorInfo::auto_padding()
183 {
184     ARM_COMPUTE_ERROR_ON(!_is_resizable);
185
186     /* Some kernels compute 32 elements at the time, worst case scenario they will read 32 values after the last element */
187     const size_t extra_pad_x = 32;
188     const size_t pad_x       = 4;
189     const size_t pad_y       = (_tensor_shape.num_dimensions() == 1 ? 0 : 4); // Skip pad_y if the tensor has just 1 dimension
190
191     return extend_padding(PaddingSize(pad_y, pad_x + extra_pad_x, pad_y, pad_x));
192 }
193
194 std::tuple<Strides, size_t, size_t> TensorInfo::calculate_padding_requirements(const PaddingSize &padding)
195 {
196     // Calculate resulting stride for the X, Y and Z dimension
197     const size_t stride_x = element_size();
198     const size_t stride_y = (padding.left + _tensor_shape[0] + padding.right) * stride_x;
199     const size_t stride_z = _tensor_shape.num_dimensions() == 1 ? 0 : (padding.top + _tensor_shape[1] + padding.bottom) * stride_y;
200
201     Strides      required_strides;
202     size_t       required_total_size           = 0;
203     const size_t required_offset_first_element = padding.left * stride_x + padding.top * stride_y;
204
205     switch(_tensor_shape.num_dimensions())
206     {
207         case 1:
208             required_strides    = compute_strides(*this, stride_x);
209             required_total_size = stride_y;
210             break;
211         case 2:
212             required_strides    = compute_strides(*this, stride_x, stride_y);
213             required_total_size = stride_z;
214             break;
215         default:
216         {
217             required_strides = compute_strides(*this, stride_x, stride_y, stride_z);
218
219             const unsigned int idx_last_dimension = _tensor_shape.num_dimensions() - 1;
220
221             required_total_size = _tensor_shape[idx_last_dimension] * required_strides[idx_last_dimension];
222             break;
223         }
224     }
225
226     return std::make_tuple(required_strides, required_offset_first_element, required_total_size);
227 }
228
229 bool TensorInfo::extend_padding(const PaddingSize &padding)
230 {
231     ARM_COMPUTE_ERROR_ON(!_is_resizable);
232
233     bool updated = false;
234
235     if(padding.top > _padding.top)
236     {
237         _padding.top = padding.top;
238         updated      = true;
239     }
240
241     if(padding.right > _padding.right)
242     {
243         _padding.right = padding.right;
244         updated        = true;
245     }
246
247     if(padding.bottom > _padding.bottom)
248     {
249         _padding.bottom = padding.bottom;
250         updated         = true;
251     }
252
253     if(padding.left > _padding.left)
254     {
255         _padding.left = padding.left;
256         updated       = true;
257     }
258
259     std::tie(_strides_in_bytes, _offset_first_element_in_bytes, _total_size) = calculate_padding_requirements(_padding);
260
261     return updated;
262 }
263
264 void TensorInfo::set_format(Format format)
265 {
266     ARM_COMPUTE_ERROR_ON(num_channels_from_format(format) != _num_channels);
267     ARM_COMPUTE_ERROR_ON(data_type_from_format(format) != _data_type);
268
269     _format = format;
270 }
271
272 size_t TensorInfo::offset_element_in_bytes(const Coordinates &pos) const
273 {
274     ARM_COMPUTE_ERROR_ON_COORDINATES_DIMENSIONS_GTE(pos, _tensor_shape.num_dimensions());
275
276     size_t offset = _offset_first_element_in_bytes;
277
278     for(size_t i = 0; i < _tensor_shape.num_dimensions(); ++i)
279     {
280         offset += pos[i] * _strides_in_bytes[i];
281     }
282
283     return offset;
284 }