Publishing 2019 R1 content
[platform/upstream/dldt.git] / inference-engine / thirdparty / clDNN / src / broadcast.cpp
1 // Copyright (c) 2018 Intel Corporation
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
6 //
7 //      http://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
14
15
16 #include "broadcast_inst.h"
17
18 #include "error_handler.h"
19 #include "json_object.h"
20 #include "primitive_type_base.h"
21
22
23 namespace cldnn
24 {
25 primitive_type_id broadcast_type_id()
26 {
27     static primitive_type_base<broadcast> instance;
28     return &instance;
29 }
30
31 layout broadcast_inst::calc_output_layout(broadcast_node const& node)
32 {
33     assert((bool)node.get_primitive()->output_data_type == false
34            && "Output data type forcing is not supported for broadcast_node!");
35     auto input_layout = node.input().get_output_layout();
36     auto desc         = node.get_primitive();
37
38     return {input_layout.data_type, input_layout.format, desc->broadcast_sizes};
39 }
40
41 std::string broadcast_inst::to_string(broadcast_node const& node)
42 {
43     auto desc                  = node.get_primitive();
44     auto node_info             = node.desc_to_json();
45     const auto& broadcast_sizes   = desc->broadcast_sizes;
46     const auto& broadcast_axes = desc->broadcast_axes;
47     auto& input                = node.input();
48
49     std::stringstream primitive_description;
50     std::stringstream ss_broadcast_axes;
51
52     for (size_t i = 0; i < broadcast_axes.size(); ++i)
53     {
54         ss_broadcast_axes << broadcast_axes.at(i);
55         i != (broadcast_axes.size() - 1) ? ss_broadcast_axes << ", " : ss_broadcast_axes << "";
56     }
57
58     json_composite broadcast_info;
59     broadcast_info.add("input id", input.id());
60     broadcast_info.add("broadcast_sizes", broadcast_sizes.to_string());
61     broadcast_info.add("broadcast axes", ss_broadcast_axes.str());
62
63     node_info->add("broadcast info", broadcast_info);
64     node_info->dump(primitive_description);
65
66     return primitive_description.str();
67 }
68
69 broadcast_inst::typed_primitive_inst(network_impl& network, broadcast_node const& node)
70     : parent(network, node)
71 {
72     auto input_layout = node.input().get_output_layout();
73
74     const auto& input_sizes = input_layout.size;
75     const auto& output_sizes = argument.broadcast_sizes;
76
77     std::vector<tensor::value_type> input_dims = {input_sizes.batch[0], input_sizes.feature[0],
78                                                   input_sizes.spatial[1], input_sizes.spatial[0]};
79     std::vector<tensor::value_type> reordered_input_dims(4, 0);
80     std::set<uint16_t> existing;
81
82     const auto& broadcast_axes = node.get_primitive()->broadcast_axes;
83     size_t broadcast_axes_size = broadcast_axes.size();
84     size_t index = 0;
85     size_t input_index = broadcast_axes_size;
86
87     if (broadcast_axes_size > 4)
88     {
89         CLDNN_ERROR_MESSAGE(node.id(), "Incorrect parameters configuration: broadcast_axes size should be less or equal 4.");
90     }
91     for (size_t i = 0; i < broadcast_axes_size; ++i)
92     {
93         if (broadcast_axes.at(i) >= 4)
94         {
95             CLDNN_ERROR_MESSAGE(node.id(), "Incorrect parameters configuration: broadcast_axes index should be within broadcast_sizes range.");
96         }
97         if (existing.find(broadcast_axes.at(i)) != existing.end())
98         {
99             CLDNN_ERROR_MESSAGE(node.id(), "Incorrect parameters configuration: Duplicate axes numbers was found in broadcast_axes.");
100         }
101         existing.insert(broadcast_axes.at(i));
102     }
103     for (size_t i = 0; i < input_index; ++i)
104     {
105         CLDNN_ERROR_NOT_EQUAL(node.id(), "Input size on dimension number " + std::to_string(i), input_dims.at(i), "", 1, "Must be equal 1.");
106     }
107     //bfyx format
108     for (size_t i = 0; i < 4; ++i)
109     {
110         if (std::find(broadcast_axes.begin(), broadcast_axes.end(), i) != broadcast_axes.end())
111         {
112             reordered_input_dims.at(i) = input_dims.at(index);
113             ++index;
114         }
115         else
116         {
117             reordered_input_dims.at(i) = input_dims.at(input_index);
118             ++input_index;
119         }
120     }
121     tensor input_sizes_to_compare(reordered_input_dims.at(0), reordered_input_dims.at(1), reordered_input_dims.at(3), reordered_input_dims.at(2));
122
123     CLDNN_ERROR_TENSOR_SIZES_NOT_DIVIDABLE(node.id(), "Broadcast sizes", output_sizes, "input sizes", input_sizes_to_compare,
124                                            "Invalid broadcast size: not dividable by input size");
125 }
126 }