Publishing 2019 R2 content (#223)
[platform/upstream/dldt.git] / inference-engine / thirdparty / clDNN / api / CPP / tensor.hpp
1 /*
2 // Copyright (c) 2016-2019 Intel Corporation
3 //
4 // Licensed under the Apache License, Version 2.0 (the "License");
5 // you may not use this file except in compliance with the License.
6 // You may obtain a copy of the License at
7 //
8 //      http://www.apache.org/licenses/LICENSE-2.0
9 //
10 // Unless required by applicable law or agreed to in writing, software
11 // distributed under the License is distributed on an "AS IS" BASIS,
12 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 // See the License for the specific language governing permissions and
14 // limitations under the License.
15 */
16
17 ///////////////////////////////////////////////////////////////////////////////////////////////////
18 #pragma once
19 #include "cldnn_defs.h"
20 #include "compounds.h"
21 #include "meta_utils.hpp"
22
23 #include <map>
24 #include <list>
25 #include <cstdint>
26 #include <iostream>
27 #include <numeric>
28 #include <algorithm>
29 #include <sstream>
30 #include <vector>
31 #include <string>
32 #include <utility>
33 #include <functional>
34
35 namespace cldnn {
36 /// @addtogroup cpp_api C++ API
37 /// @{
38
39 /// @addtogroup cpp_memory Memory description and management
40 /// @{
41
42 /// @brief Format information helper class.
43 struct format_traits {
44     /// @brief Number of batch dimensions in a format.
45     size_t batch_num;
46     /// @brief Number of feature map/channel dimensions in a format.
47     size_t feature_num;
48     /// @brief Number of spatial (x,y) dimensions in a format.
49     size_t spatial_num;
50     /// @brief Number of local (x,y) dimensions in a format.
51     size_t local_num;
52     /// @brief Dimensions changing order from rare to often.
53     std::string order;
54     /// @brief Dimensions order for internal storage.
55     std::string internal_order;
56     /// @brief Block sizes as a vector of pairs of dimension number and block size ordered from rare to often.
57     std::vector<std::pair<size_t, int>> block_sizes;
58     /// @brief Characters representing batch dimensions in an order.
59     static const char* batch_chars() { return "bn"; }
60     /// @brief Characters representing feature map/channel dimensions in an order.
61     static const char* feature_chars() { return "fioc"; }
62     /// @brief Characters representing spatial dimensions in an order.
63     static const char* spatial_chars() { return "xyzhsw"; }
64     /// @brief Characters representing local dimensions in an order.
65     static const char* local_chars() { return "kl"; }
66     /// @brief Checks if @p c represents batch dimension.
67     static bool is_batch_char(char c) { return std::string(batch_chars()).find_first_of(c) != std::string::npos; }
68     /// @brief Checks if @p c represents feature map/channel dimension.
69     static bool is_feature_char(char c) { return std::string(feature_chars()).find_first_of(c) != std::string::npos; }
70     /// @brief Checks if @p c represents spatial dimension.
71     static bool is_spatial_char(char c) { return std::string(spatial_chars()).find_first_of(c) != std::string::npos; }
72     /// @brief Checks if @p c represents local dimensions.
73     static bool is_local_char(char c) { return std::string(local_chars()).find_first_of(c) != std::string::npos; }
74 };
75
76 /// @brief Represents memory formats (orders).
77 /// @n In CNN most of data is described as 4 dimensional blocks. In Intel(R) clDNN library we describe memory with 4 letters
78 /// - b - number of blocks in batch. For weights formats: output features - conv, neurons - inner product
79 /// - f - number of feature maps, features or channels. For weights formats: input features - conv, inputs, inner product
80 /// - x - spatial, width
81 /// - y - spatial, height
82 /// /n
83 /// For explanation how each format type is implemented in memory we will use naming shown bellow (b=2,f=3,y=3,x=3):
84 /// \image html layout_memory_representation.jpg
85 struct format {
86     enum type : int32_t {
87         // Data formats
88         yxfb                 = cldnn_format_yxfb,                  ///< batch first, feature and than spatials \n \image html yxfb.jpg
89         byxf                 = cldnn_format_byxf,                  ///< used in bitmaps, input from user i.e b images of RGB format \n \image html byxf.jpg
90         bfyx                 = cldnn_format_bfyx,                  ///< the most common format for activations in clDNN. \n \image html bfyx.jpg
91         fyxb                 = cldnn_format_fyxb,                  ///< format not used inside clDNN, but supported in reorder as extension
92                                                                    ///< for user provided formats.
93         bfyx_f16             = cldnn_format_bfyx_f16,              ///< format used for blocked convolution
94         bs_xs_xsv8_bsv8      = cldnn_format_bs_xs_xsv8_bsv8,       ///< format used only for fully connected weights: bs - batch slice,
95                                                                    ///< xs - x slice, bsv8 - 8 values of single slice.
96         bs_xs_xsv8_bsv16     = cldnn_format_bs_xs_xsv8_bsv16,      ///< format used only for fully connected weights: bs - batch slice,
97                                                                    ///< xs - x slice, bsv16 - 16 values of single slice.
98         bs_x_bsv16           = cldnn_format_bs_x_bsv16,            ///< format used only for fully connected weights fp16 batch=1 : bs - batch slice
99                                                                    ///< (responses slice), bsv16 - 16 values of single batch slice, x - flattened plane of (fyx)
100                                                                    ///< \n \image html bs_x_bsv16.jpg
101         bf8_xy16             = cldnn_format_bf8_xy16,              ///< format used only for convolution 1x1 input, xy aligned to 16, f aligned to 8
102                                                                    ///< \n \image html bf8_xy16.jpg
103         b_fs_yx_32fp         = cldnn_format_b_fs_yx_32fp,          ///< format for data for binary convolutions
104                                                                    ///< \n \image html image_2d_weights_c1_b_fyx.jpg
105         winograd_2x3_s1_data = cldnn_format_winograd_2x3_s1_data,  ///< format used for input for winograd convolution, F(2,3) -- filter 3x3 with stride 1
106         byxf_af32            = cldnn_format_byxf_af32,             ///< format for input for primitives using MMAD
107         byx8_f4              = cldnn_format_byx8_f4,               ///< format for input for MMAD convolutions
108         fs_bs_yx_bsv4_fsv32  = cldnn_format_fs_bs_yx_bs4_fs32,     ///< format for batched input for primitives using MMAD
109         b_fs_yx_fsv4         = cldnn_format_b_fs_yx_fsv4,          ///< format for input for IMAD convolutions
110         bfzyx                = cldnn_format_bfzyx,                 ///< format for 5d data tensors
111         bfwzyx               = cldnn_format_bfwzyx,                ///  batch, feature, 4D spatial
112         fs_b_yx_fsv32        = cldnn_format_fs_b_yx_fsv32,         ///< format for input for fp16 primitives
113
114         // Weights formats
115         o_i_yx_i16_o16                         = cldnn_format_o_i_yx_i16_o16,                      ///< format used for blocked convolution
116         oiyx_o16                               = cldnn_format_oiyx_o16,                            ///< format used only for convolution weights:
117                                                                                                    ///< os - output feature maps slice, i - input feature maps,
118                                                                                                    ///< yx - spatials, sv16 - 16 values of single slice.
119         os_iyx_osv16                           = cldnn_format_os_iyx_osv16,                        ///< format used only for convolution weights:
120                                                                                                    ///< os - output feature maps slice, i - input feature maps,
121                                                                                                    ///< yx - spatials, sv16 - 16 values of single slice.
122         os_iyx_osv32                           = cldnn_format_os_iyx_osv32,                        ///< format used only for convolution weights:
123                                                                                                    ///< os - output feature maps slice, i - input feature maps,
124                                                                                                    ///< yx - spatials, sv32 - 32 values of single slice.
125         os_iyx_osv64                           = cldnn_format_os_iyx_osv64,                        ///< format used only for convolution weights:
126                                                                                                    ///< os - output feature maps slice, i - input feature maps,
127                                                                                                    ///< yx - spatials, sv64 - 64 values of single slice.
128         image_2d_weights_c4_fyx_b              = cldnn_format_image_2d_weights_c4_fyx_b,           ///< image format for weights, width size is f*y*x/4
129                                                                                                    ///< (4-channels filled with fyx data), height is b
130                                                                                                    ///< \n \image html image_2d_weights_c4_fyx_b.jpg
131         image_2d_weights_c1_b_fyx              = cldnn_format_image_2d_weights_c1_b_fyx,           ///< image format for weights, width size is b,
132                                                                                                    ///< height is f*y*x, single channel
133         winograd_2x3_s1_weights                = cldnn_format_winograd_2x3_s1_weights,             ///< format used for weights for winograd non-fused
134                                                                                                    ///< convolution, F(2,3) -- filter 3x3 with stride 1
135         winograd_2x3_s1_fused_weights          = cldnn_format_winograd_2x3_s1_fused_weights,       ///< format used for weights for winograd fused
136                                                                                                    ///< convolution, F(2,3) -- filter 3x3 with stride 1
137         winograd_6x3_s1_fused_weights          = cldnn_format_winograd_6x3_s1_fused_weights,       ///< format used for weights for winograd fused
138                                                                                                    ///< convolution, F(6,3) -- filter 3x3 with stride 1
139         image_2d_weights_winograd_6x3_s1_fbxyb = cldnn_format_image_2d_weights_winograd_6x3_s1_fbxyb,  ///< image format used for weights for winograd fused
140                                                                                                        ///< convolution, F(6,3) -- filter 3x3 with stride 1
141         image_2d_weights_winograd_6x3_s1_xfbyb = cldnn_format_image_2d_weights_winograd_6x3_s1_xfbyb,  ///< image format used for weights for winograd fused
142                                                                                                        ///< convolution, F(6,3) -- filter 3x3 with stride 1
143         os_is_yx_isa8_osv8_isv4                = cldnn_format_os_is_yx_isa8_osv8_isv4,                 ///< format for weights for MMAD convolution
144         os_is_yx_isa8_osv8_isv4_swizzled_by_4  = cldnn_format_os_is_yx_isa8_osv8_isv4_swizzled_by_4,   ///< format for weights for MMAD convolution
145         is_o_yx_isv32                          = cldnn_format_is_o_yx_isv32,                           ///< format for weights for 1x1 MMAD convolutions
146         is_o32_yx_isv32_swizzled_by_4          = cldnn_format_is_o32_yx_isv32_swizzled_by_4,           ///< format for weights for 1x1 MMAD convolutions
147         os_is_y_x8_osv8_isv4                   = cldnn_format_os_is_y_x8_osv8_isv4,                    ///< format for weights for 1x1 MMAD convolutions
148         os_is_y_x8_osv8_isv4_swizzled_by_4     = cldnn_format_os_is_y_x8_osv8_isv4_swizzled_by_4,      ///< format for weights for 1x1 MMAD convolutions
149         os_is_yx_osv16_isv4                    = cldnn_format_os_is_yx_osv16_isv4,                     ///< format for weights for IMAD convolutions
150         bf_lyx_yx                              = cldnn_bf_lyx_yx,                                      ///< format for local convolution weights
151         os_is_yx_osv32_isv32p                  = cldnn_format_os_is_yx_osv32_isv32p,                   ///< format for weights for binary convolutions
152
153         format_num = cldnn_format_format_num,  ///< number of format types
154         any        = cldnn_format_any
155     };
156
157     /// @brief Get format traits for particular @p format::type
158     static const format_traits& traits(type fmt) {
159         static const std::map<type, format_traits> traits {
160                 { yxfb,                 { 1, 1, 2, 0, "yxfb",   "bfxy?",  {}}},
161                 { byxf,                 { 1, 1, 2, 0, "byxf",   "bfxy?",  {}}},
162                 { bfyx,                 { 1, 1, 2, 0, "bfyx",   "bfxy?",  {}}},
163                 { fyxb,                 { 1, 1, 2, 0, "fyxb",   "bfxy?",  {}}},
164                 { bfyx_f16,             { 1, 1, 2, 0, "bfyx",   "bfxy",   {{1, 16}}}},
165                 { bs_xs_xsv8_bsv8,      { 1, 1, 1, 0, "bx",     "b?x??",  {{2, 8}, {0, 8}}}},
166                 { bs_xs_xsv8_bsv16,     { 1, 1, 1, 0, "bx",     "b?x??",  {{2, 8}, {0, 16}}}},
167                 { bs_x_bsv16,           { 1, 1, 1, 0, "bx",     "b?x??",  {{0, 16}}}},
168                 { bf8_xy16,             { 1, 1, 2, 0, "bfyx",   "bfxy?",  {{1, 8}}}},
169                 { winograd_2x3_s1_data, { 1, 1, 2, 0, "bxyf",   "bfxy?",  {}}},
170                 { byxf_af32,            { 1, 1, 2, 0, "byxf",   "bfxy?",  {}}},
171                 { byx8_f4 ,             { 1, 1, 2, 0, "byxf",   "bfxy?",  {}}},
172                 { fs_bs_yx_bsv4_fsv32,  { 1, 1, 2, 0, "fbyx",   "bfxy?",  {{0, 4}, {1, 32}}}},
173                 { b_fs_yx_fsv4,         { 1, 1, 1, 0, "bfyx",   "bfxy?",  {{1, 4}}}},
174                 { bfzyx,                { 1, 1, 3, 0, "bfzyx",  "bfxyz",  {}}},
175                 { bfwzyx,               { 1, 1, 4, 0, "bfwzyx", "bfxyzw", {}}},
176                 { fs_b_yx_fsv32,        { 1, 1, 2, 0, "fbyx",   "bfxy?",  {{1, 32}}}},
177                 { b_fs_yx_32fp,         { 1, 1, 2, 0, "bfyx",   "bfxy?",  {}}},
178
179                 { o_i_yx_i16_o16,                         { 1, 1, 2, 0, "bfyx",   "bfxy",    {{1, 16}, {0, 16}}}},
180                 { oiyx_o16,                               { 1, 1, 2, 0, "bfyx",   "bfxy",    {{0, 16}}}},
181                 { os_iyx_osv16,                           { 1, 1, 2, 0, "bfyx",   "bfxy?",   {{0, 16}}}},
182                 { os_iyx_osv32,                           { 1, 1, 2, 0, "bfyx",   "bfxy?",   {{0, 32}}}},
183                 { os_iyx_osv64,                           { 1, 1, 2, 0, "bfyx",   "bfxy?",   {{0, 64}}}},
184                 { winograd_2x3_s1_weights,                { 1, 1, 2, 0, "bfyx",   "bfxy?",   {}}},
185                 { winograd_2x3_s1_fused_weights,          { 1, 1, 2, 0, "xyfb",   "bfxy?",   {}}},
186                 { winograd_6x3_s1_fused_weights,          { 1, 1, 2, 0, "xyfb",   "bfxy?",   {}}},
187                 { image_2d_weights_winograd_6x3_s1_fbxyb, { 1, 1, 2, 0, "xyfb",   "bfxy?",   {}}},
188                 { image_2d_weights_winograd_6x3_s1_xfbyb, { 1, 1, 2, 0, "xyfb",   "bfxy?",   {}}},
189                 { image_2d_weights_c4_fyx_b,              { 1, 1, 2, 0, "bfyx",   "bfxy?",   {}}},
190                 { image_2d_weights_c1_b_fyx,              { 1, 1, 2, 0, "bfyx",   "bfxy?",   {}}},
191                 { os_is_yx_isa8_osv8_isv4,                { 1, 1, 2, 0, "bfyx",   "bfxy?",   {}}},
192                 { os_is_yx_isa8_osv8_isv4_swizzled_by_4,  { 1, 1, 2, 0, "bfyx",   "bfxy?",   {}}},
193                 { is_o_yx_isv32,                          { 1, 1, 2, 0, "byxf",   "bfxy?",   {{1, 32}}}},
194                 { is_o32_yx_isv32_swizzled_by_4,          { 1, 1, 2, 0, "byxf",   "bfxy?",   {}}},
195                 { os_is_y_x8_osv8_isv4,                   { 1, 1, 2, 0, "byxf",   "bfxy?",   {}}},
196                 { os_is_y_x8_osv8_isv4_swizzled_by_4,     { 1, 1, 2, 0, "byxf",   "bfxy?",   {}}},
197                 { bf_lyx_yx,                              { 1, 1, 2, 2, "bfklyx", "bfxy??lk", {}}},
198                 { os_is_yx_osv16_isv4,                    { 1, 1, 1, 0, "bfxy",   "bfxy?",   {{0, 16}, {1, 4}}}},
199                 { os_is_yx_osv32_isv32p,                  { 1, 1, 1, 0, "bfxy",   "bfxy?",   {}}},
200         };
201         return traits.at(fmt);
202     }
203
204     /// @brief Returns number of batch dimensions for a @p format.
205     static size_t batch_num(type fmt) { return traits(fmt).batch_num; }
206     /// @brief Returns number of feature dimensions for a @p format.
207     static size_t feature_num(type fmt) { return traits(fmt).feature_num; }
208     /// @brief Returns number of spatial dimensions for a @p format.
209     static size_t spatial_num(type fmt) { return traits(fmt).spatial_num; }
210     /// @brief Returns number of local dimensions for a @p format.
211     static size_t local_num(type fmt) { return traits(fmt).local_num; }
212     /// @brief Returns an order of dimensions for a @ format.
213     static const std::string& order(type fmt) { return traits(fmt).order; }
214     /// @brief Returns an internal orders of dimensions for a @p format.
215     static const std::string& internal_order(type fmt) { return traits(fmt).internal_order; }
216     /// @brief Returns block sizes for @p format.
217     static const std::vector<std::pair<size_t, int>>& block_sizes(type fmt) { return traits(fmt).block_sizes; }
218     /// @brief Returns number of dimensions contained within a @p format
219     static size_t dimension(type fmt) { return order(fmt).size(); }
220     /// @brief Checks if @p format is a winograd format
221     static bool is_winograd(type fmt) {
222         return (fmt == winograd_2x3_s1_data ||
223                 fmt == winograd_2x3_s1_weights ||
224                 fmt == winograd_2x3_s1_fused_weights ||
225                 fmt == winograd_6x3_s1_fused_weights ||
226                 fmt == image_2d_weights_winograd_6x3_s1_fbxyb ||
227                 fmt == image_2d_weights_winograd_6x3_s1_xfbyb); }
228     /// @brief Checks if @p format is of image2d type
229     static bool is_image_2d(type fmt) {
230         return (fmt == image_2d_weights_c4_fyx_b ||
231                 fmt == image_2d_weights_c1_b_fyx ||
232                 fmt == image_2d_weights_winograd_6x3_s1_fbxyb ||
233                 fmt == image_2d_weights_winograd_6x3_s1_xfbyb); }
234     /// @brief Checks if @p format is of image type
235     static bool is_image(type fmt) { return (is_image_2d(fmt)); }
236     /// @brief Checks if @p format is blocked format
237     static bool is_blocked(type fmt) { return !(block_sizes(fmt).empty()); }
238
239     /// @brief Returns number of batch dimensions.
240     size_t batch_num() const { return traits(value).batch_num; }
241     /// @brief Returns number of feature dimensions.
242     size_t feature_num() const { return traits(value).feature_num; }
243     /// @brief Returns number of spatial dimensions.
244     size_t spatial_num() const { return traits(value).spatial_num; }
245     /// @brief Returns number of local dimensions.
246     size_t local_num() const { return traits(value).local_num; }
247     /// @brief Returns an order of dimensions in form of string.
248     const std::string& order() const { return traits(value).order; }
249     /// @brief Returns an internal orders of dimensions form of string.
250     const std::string& internal_order() const { return traits(value).internal_order; }
251     /// @brief Returns block sizes as vector of pairs of dimension and block size for that dimension.
252     const std::vector<std::pair<size_t, int>>& block_sizes() const { return traits(value).block_sizes; }
253     /// @brief Returns number of dimensions contained within this format
254     size_t dimension() const { return order(value).size(); }
255     /// @brief Checks if @p format is a winograd format
256     bool is_winograd() const { return is_winograd(value); }
257     /// @brief Checks if @p format is of image 2d type
258     bool is_image_2d() const { return is_image_2d(value); }
259     /// @brief Checks if @p format is of image type
260     bool is_image() const { return is_image(value); }
261     /// @brief Checks if @p format is blocked format
262     bool is_blocked() { return is_blocked(value); }
263
264     /// @brief Transforms dimension from internal order to external order
265     size_t internal_to_external(size_t idx) const {
266         auto index = order().find_first_of(internal_order()[idx]);
267         if (index == std::string::npos)
268             throw std::invalid_argument("Internal dimension index does not map to external index.");
269         return index;
270     }
271
272     type value;
273     /// @brief Implicit conversion from format::type.
274     constexpr format(type t) : value(t) {}
275     /// @brief Implicit conversion to format::type.
276     constexpr operator type() const { return value; }
277     /// @brief Conversion from C API @ref ::cldnn_format_type.
278     constexpr explicit format(cldnn_format_type t) : value(static_cast<type>(t)) {}
279     /// @brief Conversion to C API @ref ::cldnn_format_type.
280     constexpr explicit operator cldnn_format_type() const { return static_cast<cldnn_format_type>(value); }
281 };
282
283 struct tensor;
284
285 /// @brief Helper structs used in tensor constructor with dim_vec_kinds
286 namespace details {
287 /// @brief enum class that represent dimension kinds
288 enum class dim_vec_kind {
289     batch,
290     feature,
291     spatial,
292     local
293 };
294
295 /// @brief template class with max_dimensionalities and dimension offset for dimension kinds
296 template <dim_vec_kind Kind>
297 struct dim_vec_limits {
298     static_assert(meta::always_false_ty_val<dim_vec_kind, Kind>::value, "Limits are undefined for selected value of dim_vec_kind.");
299 };
300
301 template <>
302 struct dim_vec_limits<dim_vec_kind::batch> {
303     static constexpr int32_t max_dimentionality = CLDNN_TENSOR_BATCH_DIM_MAX;
304     static constexpr int32_t dim_offset = 0;
305 };
306
307 template <>
308 struct dim_vec_limits<dim_vec_kind::feature> {
309     static constexpr int32_t max_dimentionality = CLDNN_TENSOR_FEATURE_DIM_MAX;
310     static constexpr int32_t dim_offset = CLDNN_TENSOR_BATCH_DIM_MAX;
311 };
312
313 template <>
314 struct dim_vec_limits<dim_vec_kind::spatial> {
315     static constexpr int32_t max_dimentionality = CLDNN_TENSOR_SPATIAL_DIM_MAX;
316     static constexpr int32_t dim_offset = CLDNN_TENSOR_BATCH_DIM_MAX + CLDNN_TENSOR_FEATURE_DIM_MAX;
317 };
318
319 template <>
320 struct dim_vec_limits<dim_vec_kind::local> {
321     static constexpr int32_t max_dimentionality = CLDNN_TENSOR_LOCAL_DIM_MAX;
322     static constexpr int32_t dim_offset = CLDNN_TENSOR_BATCH_DIM_MAX + CLDNN_TENSOR_FEATURE_DIM_MAX + CLDNN_TENSOR_SPATIAL_DIM_MAX;
323 };
324
325 /// @brief Template class used in tensor constructor using dim_vec_kinds
326 template <dim_vec_kind Kind>
327 class dim_vec_kind_init {
328 public:
329     static constexpr auto _max_dimensionality = dim_vec_limits<Kind>::max_dimentionality;
330     static constexpr auto _dimOffset = dim_vec_limits<Kind>::dim_offset;
331
332     template <typename... DimTys>
333     explicit dim_vec_kind_init(DimTys&&... values)
334         : _sizes{int32_t(std::forward<DimTys>(values))...}, _dimSize(sizeof...(DimTys)) {
335     }
336
337     void init_tensor_values(cldnn::tensor& t);
338
339     int32_t _sizes[_max_dimensionality];
340     int32_t _dimSize;
341 };
342 }  // namespace details
343
344 template <typename... InitTys>
345 details::dim_vec_kind_init<details::dim_vec_kind::batch> batch(InitTys&&... inits) {
346     return details::dim_vec_kind_init<details::dim_vec_kind::batch>(std::forward<InitTys>(inits)...);
347 }
348
349 template <typename... InitTys>
350 details::dim_vec_kind_init<details::dim_vec_kind::feature> feature(InitTys&&... inits) {
351     return details::dim_vec_kind_init<details::dim_vec_kind::feature>(std::forward<InitTys>(inits)...);
352 }
353
354 template <typename... InitTys>
355 details::dim_vec_kind_init<details::dim_vec_kind::spatial> spatial(InitTys&&... inits) {
356     return details::dim_vec_kind_init<details::dim_vec_kind::spatial>(std::forward<InitTys>(inits)...);
357 }
358
359 template <typename... InitTys>
360 details::dim_vec_kind_init<details::dim_vec_kind::local> local(InitTys&&... inits) {
361     return details::dim_vec_kind_init<details::dim_vec_kind::local>(std::forward<InitTys>(inits)...);
362 }
363
364 /// @brief N-dimensional vector. Mostly used to represent memory size.
365 struct tensor {
366     friend class details::dim_vec_kind_init<details::dim_vec_kind::batch>;
367     friend class details::dim_vec_kind_init<details::dim_vec_kind::feature>;
368     friend class details::dim_vec_kind_init<details::dim_vec_kind::spatial>;
369     friend class details::dim_vec_kind_init<details::dim_vec_kind::local>;
370
371     typedef int32_t value_type;  ///< Values type stored in tensor.
372     // TODO find the way to prevent direct change of following fields.
373     mutable_array_ref<value_type> raw;      ///< Raw representation of all dimensions.
374     mutable_array_ref<value_type> batch;    ///< Batch dimensions.
375     mutable_array_ref<value_type> feature;  ///< Feature maps.
376     mutable_array_ref<value_type> spatial;  ///< Spatial dimensions.
377     mutable_array_ref<value_type> local;    ///< Local dimensions.
378
379 private:
380     value_type _sizes[CLDNN_TENSOR_DIM_MAX];
381     value_type _dimOffset;
382     value_type _dimSize;
383
384 public:
385     explicit tensor(value_type default_size = 0) :
386         raw(_sizes, CLDNN_TENSOR_DIM_MAX),
387         batch(_sizes, CLDNN_TENSOR_BATCH_DIM_MAX),
388         feature(_sizes + CLDNN_TENSOR_BATCH_DIM_MAX, CLDNN_TENSOR_FEATURE_DIM_MAX),
389         spatial(_sizes + CLDNN_TENSOR_BATCH_DIM_MAX + CLDNN_TENSOR_FEATURE_DIM_MAX, CLDNN_TENSOR_SPATIAL_DIM_MAX),
390         local(_sizes + CLDNN_TENSOR_BATCH_DIM_MAX + CLDNN_TENSOR_FEATURE_DIM_MAX + CLDNN_TENSOR_SPATIAL_DIM_MAX, CLDNN_TENSOR_LOCAL_DIM_MAX) {
391         std::fill_n(_sizes, CLDNN_TENSOR_DIM_MAX, default_size);
392     }
393
394     /// @brief Constructs tensor.
395     /// @param[in] kind_inits Dimensions defined using dim_vec_kind. If dimension is not provided it is set to 1.
396     /// @details Example:
397     /*! @code
398     *
399     tensor my_tensor(batch(2), spatial(5, 6));   // y=6, x=5, b=2, f - not set
400     cout << my_tensor.batch[0] << endl;           // 2
401     cout << my_tensor.feature[0] << endl;         // 1 - default_size
402     cout << "x=" << my_tensor.spatial[0] << endl; // x=5
403     cout << "y=" << my_tensor.spatial[1] << endl; // y=6
404     *
405     * @endcode
406     */
407     template <typename... KindInitTys,
408               typename = typename std::enable_if<
409                   meta::all<
410                       meta::is_any_of<KindInitTys,
411                                       cldnn::details::dim_vec_kind_init<cldnn::details::dim_vec_kind::batch>,
412                                       cldnn::details::dim_vec_kind_init<cldnn::details::dim_vec_kind::feature>,
413                                       cldnn::details::dim_vec_kind_init<details::dim_vec_kind::spatial>>::value...>::value,
414                   void>::type>
415     explicit tensor(KindInitTys&&... kind_inits)
416         : tensor(1) {
417         assign_inits(std::forward<KindInitTys>(kind_inits)...);
418     }
419
420     /// @brief Constructs @p tensor.
421     /// @details Example:
422     /*! @code
423      *
424        tensor my_tensor( 2, 3, 4, 5 );   // b=2, f=3, x=4, y=5
425        cout << my_tensor.batch[0] << endl;           // 2
426        cout << my_tensor.feature[0] << endl;         // 3
427        cout << "x=" << my_tensor.spatial[0] << endl; // x=4
428        cout << "y=" << my_tensor.spatial[1] << endl; // y=5
429      *
430      * @endcode
431      */
432     tensor(value_type batch_num, value_type feature_num, value_type width, value_type height)
433         : tensor(1) {
434         _sizes[0] = batch_num;
435         _sizes[CLDNN_TENSOR_BATCH_DIM_MAX] = feature_num;
436         _sizes[CLDNN_TENSOR_BATCH_DIM_MAX + CLDNN_TENSOR_FEATURE_DIM_MAX] = width;
437         _sizes[CLDNN_TENSOR_BATCH_DIM_MAX + CLDNN_TENSOR_FEATURE_DIM_MAX + 1] = height;
438         if (batch_num == 0 && feature_num == 0 && width == 0 && height == 0)
439             _sizes[CLDNN_TENSOR_BATCH_DIM_MAX + CLDNN_TENSOR_FEATURE_DIM_MAX + 2] = 0;
440     }
441
442     /// @brief Constructs @p tensor.
443     /// @details Example:
444     /*! @code
445     *
446     tensor my_tensor( 2, 3, 4, 5, 6 );   // b=2, f=3, x=4, y=5, z =6
447     cout << my_tensor.batch[0] << endl;           // 2
448     cout << my_tensor.feature[0] << endl;         // 3
449     cout << "x=" << my_tensor.spatial[0] << endl; // x=4
450     cout << "y=" << my_tensor.spatial[1] << endl; // y=5
451     cout << "z=" << my_tensor.spatial[2] << endl; // z=6
452     *
453     * @endcode
454     */
455     tensor(value_type batch_num, value_type feature_num, value_type width, value_type height, value_type depth)
456         : tensor(1) {
457         _sizes[0] = batch_num;
458         _sizes[CLDNN_TENSOR_BATCH_DIM_MAX] = feature_num;
459         _sizes[CLDNN_TENSOR_BATCH_DIM_MAX + CLDNN_TENSOR_FEATURE_DIM_MAX] = width;
460         _sizes[CLDNN_TENSOR_BATCH_DIM_MAX + CLDNN_TENSOR_FEATURE_DIM_MAX + 1] = height;
461         _sizes[CLDNN_TENSOR_BATCH_DIM_MAX + CLDNN_TENSOR_FEATURE_DIM_MAX + 2] = depth;
462     }
463
464     /// @brief Constructs @p tensor.
465     /// @details Example:
466     /*! @code
467     *
468     tensor my_tensor( 2, 3, 4, 5, 6, 7 );   // b=2, f=3, x=4, y=5, lx= 6, ly =7
469     cout << my_tensor.batch[0] << endl;           // 2
470     cout << my_tensor.feature[0] << endl;         // 3
471     cout << "x=" << my_tensor.spatial[0] << endl; // x=4
472     cout << "y=" << my_tensor.spatial[1] << endl; // y=5
473         cout << "local x=" << my_tensor.local[0] << endl; // local x=6
474         cout << "loxal y=" << my_tensor.local[1] << endl; // local y=7
475     *
476     * @endcode
477     */
478     tensor(value_type batch_num, value_type feature_num, value_type width,
479            value_type height, value_type local_x, value_type local_y)
480         : tensor(1) {
481         _sizes[0] = batch_num;
482         _sizes[CLDNN_TENSOR_BATCH_DIM_MAX] = feature_num;
483         _sizes[CLDNN_TENSOR_BATCH_DIM_MAX + CLDNN_TENSOR_FEATURE_DIM_MAX] = width;
484         _sizes[CLDNN_TENSOR_BATCH_DIM_MAX + CLDNN_TENSOR_FEATURE_DIM_MAX + 1] = height;
485         _sizes[CLDNN_TENSOR_BATCH_DIM_MAX + CLDNN_TENSOR_FEATURE_DIM_MAX + CLDNN_TENSOR_SPATIAL_DIM_MAX] = local_x;
486         _sizes[CLDNN_TENSOR_BATCH_DIM_MAX + CLDNN_TENSOR_FEATURE_DIM_MAX + CLDNN_TENSOR_SPATIAL_DIM_MAX + 1] = local_y;
487     }
488
489     /// @brief Constructs @p tensor using vector of sizes.
490     /// @param[in] sizes dimensions need to be provided in the following order {batch, feature, spatial_x, spatial_y [, spatial_z] }.
491     /// @param[in] default_size default_size for tensor dimensions.
492     /// @details Example:
493     /*! @code
494      *
495        tensor my_tensor = { 2, 3, 4, 5 };   // b=2, f=3, x=4, y=5
496        cout << my_tensor.batch[0] << endl;           // 2
497        cout << my_tensor.feature[0] << endl;         // 3
498        cout << "x=" << my_tensor.spatial[0] << endl; // x=4
499        cout << "y=" << my_tensor.spatial[1] << endl; // y=5
500      *
501      * @endcode
502      */
503     explicit tensor(const std::vector<value_type>& sizes, value_type default_size = 1)
504         : tensor(default_size) {
505         int max_size = std::min(static_cast<int>(sizes.size()), CLDNN_TENSOR_DIM_MAX);
506         for (int i = 0; i < max_size; i++)
507             _sizes[i] = sizes[i];
508     }
509
510     tensor(format fmt, const std::vector<value_type>& sizes, value_type default_size = 1)
511         : tensor(default_size) {
512         auto in_order = fmt.order();
513         auto out_order = fmt.internal_order();
514         if (in_order.size() != sizes.size())
515             throw std::invalid_argument("The count of values passed to initialize tensor does not match passed format.");
516
517         for (size_t out_idx = 0; out_idx < out_order.size(); ++out_idx) {
518             auto channel = out_order[out_idx];
519             if (channel == '?')
520                 continue;
521
522             auto in_idx = in_order.find(channel);
523             if (in_idx == in_order.npos)
524                 throw std::runtime_error("Internal order of a format contains channel which does not appear in external order.");
525
526             _sizes[out_idx] = sizes[in_idx];
527         }
528     }
529
530     /// @brief Implicit conversion form C API :: cldnn_tensor.
531     explicit tensor(const cldnn_tensor& other)
532         : tensor(0) {
533         std::copy_n(other.sizes, CLDNN_TENSOR_DIM_MAX, _sizes);
534     }
535
536     /// @brief Implicit conversion to C API ::cldnn_tensor.
537     operator cldnn_tensor() const {
538         cldnn_tensor result;
539         result.batch_num = batch.size();
540         result.feature_num = feature.size();
541         result.spatial_num = spatial.size();
542         result.local_num = local.size();
543         std::copy_n(_sizes, CLDNN_TENSOR_DIM_MAX, result.sizes);
544         return result;
545     }
546
547     /// @brief Copy construction.
548     tensor(const tensor& other)
549         : tensor(0) {
550         std::copy_n(other._sizes, CLDNN_TENSOR_DIM_MAX, _sizes);
551     }
552
553     /// @brief Copy assignment.
554     tensor& operator=(const tensor& other) {
555         if (this == &other)
556             return *this;
557         std::copy_n(other._sizes, CLDNN_TENSOR_DIM_MAX, _sizes);
558         return *this;
559     }
560
561     friend bool operator==(const tensor& lhs, const tensor& rhs) {
562         return lhs.raw.size() == rhs.raw.size() && std::equal(lhs.raw.begin(), lhs.raw.end(), rhs.raw.begin());
563     }
564
565     friend bool operator!=(const tensor& lhs, const tensor& rhs) {
566         return !(lhs == rhs);
567     }
568
569     friend bool operator<(const tensor& lhs, const tensor& rhs) {
570         if (lhs.raw.size() != rhs.raw.size())
571             return lhs.raw.size() < rhs.raw.size();
572         for (size_t i = 0; i < lhs.raw.size(); ++i) {
573             if (lhs.raw[i] < rhs.raw[i])
574                 return true;
575             if (rhs.raw[i] < lhs.raw[i])
576                 return false;
577         }
578
579         return false;
580     }
581
582     friend std::ostream& operator<<(std::ostream& os, const tensor& tensor) {
583         os << tensor.to_string();
584         return os;
585     }
586
587     std::string to_string() const {
588         std::stringstream out;
589         const char* delim = "";
590
591         out << "[b:";
592         for (size_t i = 0; i < batch.size(); ++i) {
593             out << delim << batch[i];
594             delim = ",";
595         }
596         delim = "";
597
598         out << ", f:";
599         for (size_t i = 0; i < feature.size(); ++i) {
600             out << delim << feature[i];
601             delim = ",";
602         }
603
604         std::vector<std::string> spatial_dim_names = {", x", ", y", ", z", ", w"};
605         for (size_t i = 0; i < spatial.size(); ++i) {
606             out << spatial_dim_names[i] << ":" << spatial[i];
607         }
608         out << "]";
609
610         return out.str();
611     }
612
613     /// @brief Returns a tensor with all negated elements.
614     tensor negate() const {
615         auto result = *this;
616         for (size_t i = 0; i < CLDNN_TENSOR_DIM_MAX; i++) {
617             result._sizes[i] = -_sizes[i];
618         }
619         return result;
620     }
621
622     /// @brief Returns a tensor with all elements multilied to @p multiplier.
623     tensor mul(value_type multiplier) const {
624         auto result = *this;
625         for (size_t i = 0; i < CLDNN_TENSOR_DIM_MAX; i++) {
626             result._sizes[i] *= multiplier;
627         }
628         return result;
629     }
630
631     /// @brief Returns a tensor with all elements divided by @p divider.
632     tensor div(value_type divider) const {
633         auto result = *this;
634         for (size_t i = 0; i < CLDNN_TENSOR_DIM_MAX; i++) {
635             result._sizes[i] /= divider;
636         }
637         return result;
638     }
639
640     /// @brief Returns a tensor with all elements added by appropriate elements of @p rhs
641     tensor add(const tensor& rhs) const {
642         auto result = *this;
643         for (size_t i = 0; i < CLDNN_TENSOR_DIM_MAX; i++) {
644             result._sizes[i] += rhs._sizes[i];
645         }
646         return result;
647     }
648
649     /// @brief Returns a tensor with all elements subtracted by appropriate elements of @p rhs
650     tensor sub(const tensor& rhs) const {
651         return add(rhs.negate());
652     }
653
654     /// @brief Assign and add
655     tensor& operator+=(const tensor& rhs) {
656         for (size_t i = 0; i < CLDNN_TENSOR_DIM_MAX; i++)
657             _sizes[i] += rhs._sizes[i];
658         return *this;
659     }
660
661     /// @brief Assign and subtract
662     tensor& operator-=(const tensor& rhs) {
663         for (size_t i = 0; i < CLDNN_TENSOR_DIM_MAX; i++)
664             _sizes[i] -= rhs._sizes[i];
665         return *this;
666     }
667
668     /// @brief Returns a vector of tensors values, ordered regarding to @p format.
669     std::vector<value_type> sizes(cldnn::format fmt) const {
670         auto output_order = fmt.order();
671         auto internal_order = fmt.internal_order();
672         std::vector<value_type> sizes(output_order.size(), 0);
673
674         for (size_t i = 0; i < sizes.size(); ++i) {
675             auto c = output_order[i];
676             auto pos = internal_order.find(c);
677             if (pos == internal_order.npos)
678                 throw std::domain_error(std::string("Unknown coord type: ") + c);
679
680             sizes[i] = _sizes[pos];
681         }
682
683         return sizes;
684     }
685
686     /// @brief Returns a vector of tensors values, ordered batch, feature, spatial_x, spatial_y.
687     std::vector<value_type> sizes() const {
688         std::vector<value_type> sizes(sizeof(_sizes) / sizeof(_sizes[0]), 0);
689         for (size_t i = 0; i < sizes.size(); ++i)
690             sizes[i] = _sizes[i];
691         return sizes;
692     }
693
694     /// @brief Returns tensor elements count calculated as multiplication of all elements.
695     size_t count() const {
696         return std::accumulate(
697             raw.begin(),
698             raw.end(),
699             static_cast<size_t>(1),
700             std::multiplies<size_t>());
701     }
702
703     /// @brief Returns new tensor based on current but transformed to new @p format.
704     /// @param[in] new_fmt Format of new tensor.
705     /// @param[in] default_size Default element values for positions not defined by current format.
706     /// @details Example:
707     /*!
708      * @code
709        tensor my_tensor({ 2, 3, 4, 5 });
710        auto my_sizes = my_tensor.sizes();
711        cout << "dims_num=" << my_sizes.size() << endl; // dims_num=2
712        cout << "b=" << my_sizes[0] << endl;            // b=2
713        cout << "f=" << my_sizes[1] << endl;            // f=3
714        cout << "x=" << my_sizes[2] << endl;            // x=5
715        cout << "y=" << my_sizes[3] << endl;            // y=4
716        auto new_tensor = my_tensor.transform(format::yxfb, 10);
717        auto new_sizes = new_tensor.sizes();
718        cout << "new_num=" << new_sizes.size() << endl;   // new_num=4
719        for(auto dim : new_sizes) cout << " " << dim;     //  5 4 3 2
720        cout << endl;
721        * @endcode
722      */
723     tensor transform(cldnn::format new_fmt, value_type default_size) const {
724         cldnn::format format = cldnn::format::bfwzyx;
725         auto val_order = format.internal_order();
726         auto new_order = new_fmt.internal_order();
727         std::vector<value_type> old_sizes = sizes();
728         std::vector<value_type> new_sizes(old_sizes.size(), default_size);
729         auto tmp = 1;
730         auto tmp_z = 1;
731         auto tmp_w = 1;
732         for (size_t i = 0; i < format.order().size(); i++) {
733             auto c = val_order[i];
734             // skip f and y, z for the formats that do not have it
735             if (((new_fmt == format::bs_xs_xsv8_bsv8) ||
736                  (new_fmt == format::bs_xs_xsv8_bsv16) ||
737                  (new_fmt == format::bs_x_bsv16)) &&
738                 ((c == 'f') ||
739                  (c == 'y') ||
740                  (c == 'z') ||
741                  (c == 'w'))) {
742                 if (new_order[i] == '?')
743                     new_sizes[i] = default_size;
744
745                 tmp *= old_sizes[i];
746                 continue;
747             }
748
749             // skip z for the formats that do not have it
750             if (((new_fmt != format::bfzyx && new_fmt != format::bfwzyx)) && (c == 'z')) {
751                 if (new_order[i] == '?')
752                     new_sizes[i] = default_size;
753
754                 tmp_z *= old_sizes[i];
755                 continue;
756             }
757
758             if (new_fmt != format::bfwzyx && c == 'w') {
759                 if (new_order[i] == '?')
760                     new_sizes[i] = default_size;
761
762                 if (new_fmt == format::bfzyx)
763                     tmp_w *= old_sizes[i];
764                 else
765                     tmp_z *= old_sizes[i];
766                 continue;
767             }
768
769             auto new_pos = new_order.find(c);
770             if (new_pos == std::string::npos)
771                 throw std::invalid_argument("cannot convert to new format");
772             new_sizes[new_pos] = old_sizes[i];
773         }
774
775         // in case of formats with smaller number of dimensions than input, flatten is performed below
776         if (tmp != 1 || tmp_z != 1 || tmp_w != 1) {
777             for (size_t i = 0; i < format.order().size(); i++) {
778                 auto c = val_order[i];
779                 if (c == 'x') {
780                     auto new_pos = new_order.find(c);
781                     new_sizes[new_pos] *= tmp;
782                 }
783                 if (c == 'y') {
784                     auto new_pos = new_order.find(c);
785                     if (new_pos != std::string::npos)
786                         new_sizes[new_pos] *= tmp_z;
787                 }
788                 if (c == 'z') {
789                     auto new_pos = new_order.find(c);
790                     if (new_pos != std::string::npos)
791                         new_sizes[new_pos] *= tmp_w;
792                 }
793             }
794         }
795
796         tensor sizes { new_sizes };
797         return sizes;
798     }
799
800     /// @brief Calculates linear offset for given @p coord within current tensor.
801     /// @param coord The coordinate within current tensor.
802     size_t get_linear_offset(const tensor& coord, cldnn::format fmt) const {
803         auto my_sizes = this->sizes(fmt);
804         auto adjusted_coords = coord.sizes(fmt);
805
806         // Extend N-dimensional format with B blocked dimensions to (N+B) sizes
807         for (const auto& block : fmt.block_sizes()) {
808             auto block_axis = block.first;
809             auto block_size = block.second;
810             auto external_axis = fmt.internal_to_external(block_axis);
811
812             my_sizes.push_back(block_size);
813             my_sizes[external_axis] = ceil_div(my_sizes[external_axis], block_size);
814
815             adjusted_coords.push_back(adjusted_coords[external_axis] % block_size);
816             adjusted_coords[external_axis] /= block_size;
817         }
818
819         if (fmt == cldnn::format::byxf_af32 && !(is_aligned_to(my_sizes[3], 32))) {
820             my_sizes[3] = align_to(my_sizes[3], 32);
821         } else if (fmt == cldnn::format::byx8_f4 && (!(is_aligned_to(my_sizes[3], 4)) || !(is_aligned_to(my_sizes[2], 8)))) {
822             my_sizes[3] = align_to(my_sizes[3], 4);
823             my_sizes[2] = align_to(my_sizes[2], 8);
824         } else if (fmt == cldnn::format::bf8_xy16) {
825             // Special case of blocked format, where xy is treated as one flattened dimension
826             auto flat_xy = adjusted_coords[3] + adjusted_coords[2] * my_sizes[3];
827
828             my_sizes.push_back(16);
829             my_sizes[3] = ceil_div(my_sizes[2] * my_sizes[3], 16);
830             my_sizes[2] = 1;
831
832             adjusted_coords.push_back(flat_xy % 16);
833             adjusted_coords[3] = flat_xy / 16;
834             adjusted_coords[2] = 0;
835         } else if (fmt == cldnn::format::os_is_yx_isa8_osv8_isv4 &&  // TODO Fix offsets calculation for formats below
836                    !(is_aligned_to(my_sizes[0], 8)) &&
837                    !(is_aligned_to(my_sizes[1], 32))) {
838             my_sizes[0] = align_to(my_sizes[0], 8);
839             my_sizes[1] = align_to(my_sizes[1], 32);
840             adjusted_coords[0] = align_to(adjusted_coords[0], 8);
841             adjusted_coords[1] = align_to(adjusted_coords[1], 32);
842         } else if (fmt == cldnn::format::os_is_yx_isa8_osv8_isv4_swizzled_by_4 && !(is_aligned_to(my_sizes[0], 32)) && !(is_aligned_to(my_sizes[1], 32))) {
843             my_sizes[0] = align_to(my_sizes[0], 32);
844             my_sizes[1] = align_to(my_sizes[1], 32);
845             adjusted_coords[0] = align_to(adjusted_coords[0], 32);
846             adjusted_coords[1] = align_to(adjusted_coords[1], 32);
847         } else if (fmt == cldnn::format::is_o32_yx_isv32_swizzled_by_4 && (!is_aligned_to(my_sizes[1], 32) || !is_aligned_to(my_sizes[0], 32))) {
848             my_sizes[0] = align_to(my_sizes[0], 32);
849             my_sizes[3] = align_to(my_sizes[3], 32);
850             adjusted_coords[0] = align_to(adjusted_coords[0], 32);
851             adjusted_coords[3] = align_to(adjusted_coords[3], 32);
852         } else if (fmt == cldnn::format::os_is_y_x8_osv8_isv4 || fmt == cldnn::format::os_is_yx_isa8_osv8_isv4_swizzled_by_4) {
853             my_sizes[1] = align_to(my_sizes[1], 4);
854             my_sizes[0] = align_to(my_sizes[0], 8);
855             my_sizes[2] = align_to(my_sizes[2], 8);
856         }
857
858         assert(my_sizes.size() == adjusted_coords.size());
859         assert(adjusted_coords.size() > 0);
860
861         size_t offset = adjusted_coords[0];
862         for (size_t i = 1; i < adjusted_coords.size(); i++) {
863             offset = offset * my_sizes[i] + adjusted_coords[i];
864         }
865         return offset;
866     }
867
868     /// @brief Returns a tensor containing values maximum from @p lhs and @p rhs.
869     static tensor max(tensor const& lhs, tensor const& rhs) {
870         auto ret = lhs;
871         for (size_t i = 0; i < CLDNN_TENSOR_DIM_MAX; ++i)
872             ret._sizes[i] = std::max(ret._sizes[i], rhs._sizes[i]);
873
874         return ret;
875     }
876
877     /// @brief Returns a tensor containing values minimum from @p lhs and @p rhs.
878     static tensor min(tensor const& lhs, tensor const& rhs) {
879         auto ret = lhs;
880         for (size_t i = 0; i < CLDNN_TENSOR_DIM_MAX; ++i)
881             ret._sizes[i] = std::min(ret._sizes[i], rhs._sizes[i]);
882
883         return ret;
884     }
885
886 private:
887     /// @brief Helper functions for tensor constructor using dim_vec_kinds
888     template <typename KindInitT>
889     void assign_inits(KindInitT&& init) {
890         init.init_tensor_values(*this);
891     }
892
893     template <typename KindInitT, typename... KindInitTys>
894     void assign_inits(KindInitT&& init, KindInitTys&&... kind_inits) {
895         init.init_tensor_values(*this);
896         assign_inits(std::forward<KindInitTys>(kind_inits)...);
897     }
898 };
899
900 #define TensorValue(val) static_cast<cldnn::tensor::value_type>(val)
901
902 template <details::dim_vec_kind Kind>
903 inline void details::dim_vec_kind_init<Kind>::init_tensor_values(cldnn::tensor& t) {
904     for (size_t i = _dimOffset; i < (size_t)(_dimOffset + _dimSize); i++)
905         t._sizes[i] = _sizes[i - _dimOffset];
906 }
907
908 /// @brief Adds two @p tensors
909 inline tensor operator+(const tensor& lhs, const tensor& rhs) { return lhs.add(rhs); }
910 /// @brief Subtracts two @p tensors
911 inline tensor operator-(const tensor& lhs, const tensor& rhs) { return lhs.sub(rhs); }
912 /// @brief Multiplies a @p tensor to a @p scalar
913 inline tensor operator*(const tensor& lhs, tensor::value_type rhs) { return lhs.mul(rhs); }
914 /// @brief Divides a @p tensor by a @p scalar
915 inline tensor operator/(const tensor& lhs, tensor::value_type rhs) { return lhs.div(rhs); }
916
917 ///
918 /// \brief Converts C API tensor_array to std::vector<tensor>
919 ///
920 inline std::vector<tensor> tensor_arr_to_vector(const cldnn_tensor_arr& arr) {
921     std::vector<tensor> result(arr.size);
922     for (size_t i = 0; i < arr.size; i++)
923         result[i] = (tensor) arr.data[i];
924
925     return result;
926 }
927
928 ///
929 /// \brief Converts std::vector<tensor> to std::vector of C API tensor
930 ///
931 inline std::vector<cldnn_tensor> tensor_vector_to_cldnn_vector(const std::vector<tensor>& stor) {
932     return std::vector<cldnn_tensor>(stor.begin(), stor.end());
933 }
934
935 /// @}
936 /// @}
937 }  // namespace cldnn