Publishing 2019 R1 content
[platform/upstream/dldt.git] / inference-engine / thirdparty / clDNN / src / eltwise.cpp
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 #include "eltwise_inst.h"
19 #include "primitive_type_base.h"
20 #include "error_handler.h"
21 #include "json_object.h"
22
23 namespace cldnn
24 {
25 primitive_type_id eltwise_type_id()
26 {
27     static primitive_type_base<eltwise> instance;
28     return &instance;
29 }
30
31 layout eltwise_inst::calc_output_layout(eltwise_node const& node)
32 {
33     assert((bool)node.get_primitive()->output_data_type == false
34            && "Output data type forcing is not supported for eltwise_inst_node!");
35
36     auto input_node_layout = node.input().get_non_padded_output_layout();
37
38     auto size = input_node_layout.size;
39     for (size_t i = 1; i < node.inputs_count(); i++)
40     {
41         size = tensor::max(size, node.input(i).get_non_padded_output_layout().size);
42     }
43     auto output_layout = layout(input_node_layout.data_type, input_node_layout.format, size);
44     auto mode = node.get_primitive()->mode;
45     //list of operations supported for integer types
46     if (input_node_layout.data_type == data_types::i8 ||
47         input_node_layout.data_type == data_types::i32 ||
48         input_node_layout.data_type == data_types::i64)
49     {
50         std::vector<eltwise_mode> eltwise_int_modes = { eltwise_mode::sum, eltwise_mode::sub, eltwise_mode::prod, eltwise_mode::div, eltwise_mode::min, eltwise_mode::max, eltwise_mode::mod,
51                                                         eltwise_mode::eq, eltwise_mode::ne, eltwise_mode::lt, eltwise_mode::le, eltwise_mode::gt, eltwise_mode::ge,
52                                                         eltwise_mode::logic_and, eltwise_mode::logic_or, eltwise_mode::logic_xor };
53         if (std::find(eltwise_int_modes.begin(), eltwise_int_modes.end(), mode) == eltwise_int_modes.end())
54             CLDNN_ERROR_MESSAGE(node.id(), "Requested eltwise mode is not supported for integer types.");
55     }
56
57     // Logic and comparison operations should return i8 for any inputs
58     std::vector<eltwise_mode> eltwise_bool_modes = { eltwise_mode::eq, eltwise_mode::ne, eltwise_mode::lt, eltwise_mode::le,
59                                                      eltwise_mode::gt, eltwise_mode::ge,
60                                                      eltwise_mode::logic_and, eltwise_mode::logic_or, eltwise_mode::logic_xor };
61     if (std::find(eltwise_bool_modes.begin(), eltwise_bool_modes.end(), mode) != eltwise_bool_modes.end())
62     {
63         output_layout.data_type = data_types::i8;
64         if (node.get_primitive()->with_activation)
65             CLDNN_ERROR_MESSAGE(node.id(), "Activations are not supported for logical operations.");
66     }
67
68     auto eltw = std::static_pointer_cast<const eltwise>((node.get_primitive()));
69     if (!eltw->stride.empty())
70     {
71         // we can safely use only first stride, since we're using first input, and input / stride should give exact same value for every input
72         input_node_layout.size.spatial[0] /= eltw->stride[0].spatial[0];
73         input_node_layout.size.spatial[1] /= eltw->stride[0].spatial[1];
74         return input_node_layout;
75     }
76     return output_layout;
77 }
78
79 static inline std::string stringify_vector(const std::vector<float>& v)
80 {
81     std::stringstream s;
82
83     s << "{ ";
84
85     for (size_t i = 0; i < v.size(); ++i)
86     {
87         s << v.at(i);
88         if (i + 1 < v.size()) s << ", ";
89     }
90
91     s << " }";
92
93     return s.str();
94 }
95
96 std::string eltwise_inst::to_string(eltwise_node const& node)
97 {
98     auto node_info  = node.desc_to_json();
99     auto desc       = node.get_primitive();
100     auto activation = desc->with_activation ? " true" : "false";
101
102     std::stringstream primitive_description;
103     std::string       str_mode;
104
105     switch(desc->mode)
106     {
107     case eltwise_mode::sum:
108             str_mode = "sum";
109             break;
110     case eltwise_mode::sub:
111             str_mode = "subtract";
112             break;
113     case eltwise_mode::max:
114             str_mode = "max";
115             break;
116     case eltwise_mode::prod:
117             str_mode = "product";
118             break;
119     case eltwise_mode::div:
120             str_mode = "div";
121             break;
122     case eltwise_mode::min:
123             str_mode = "min";
124             break;
125     case eltwise_mode::pow:
126             str_mode = "pow";
127             break;
128     case eltwise_mode::squared_diff:
129             str_mode = "squared_diff";
130             break;
131     case eltwise_mode::mod:
132             str_mode = "mod";
133             break;
134     case eltwise_mode::eq:
135             str_mode = "equal";
136             break;
137     case eltwise_mode::ne:
138             str_mode = "not equal";
139             break;
140     case eltwise_mode::lt:
141             str_mode = "less";
142             break;
143     case eltwise_mode::le:
144             str_mode = "less-or-equal";
145             break;
146     case eltwise_mode::gt:
147             str_mode = "greater";
148             break;
149     case eltwise_mode::ge:
150             str_mode = "greater-or-equal";
151             break;
152     case eltwise_mode::logic_and:
153             str_mode = "and";
154             break;
155     case eltwise_mode::logic_or:
156             str_mode = "or";
157             break;
158     case eltwise_mode::logic_xor:
159             str_mode = "xor";
160             break;
161     default:
162             str_mode = "not supported mode";
163             break;
164     }
165
166     json_composite eltwise_info;
167     for (size_t i = 0; i < node.inputs_count(); i++)
168     {
169         eltwise_info.add("input_"+std::to_string(i), node.input(i).id());
170     }
171     eltwise_info.add("mode", str_mode);
172     if (desc->mode == eltwise_mode::sum)
173     {
174         eltwise_info.add("coefficients", stringify_vector(desc->coefficients));
175     }
176     if (desc->with_activation)
177     {
178         eltwise_info.add("with activation", activation);
179         eltwise_info.add("slope", desc->activation_negative_slope);
180     }
181     node_info->add("eltwise info", eltwise_info);
182     node_info->dump(primitive_description);
183
184     return primitive_description.str();
185 }
186
187 eltwise_inst::typed_primitive_inst(network_impl& network, eltwise_node const& node)
188     :parent(network, node)
189 {
190     check_inputs_count(node);
191     // check for stride
192     auto prim = node.get_primitive();
193     if (!prim->stride.empty())
194     {
195         // number of strides must match number of inputs
196         CLDNN_ERROR_NOT_EQUAL(node.id(), "Eltwise inputs count", node.inputs_count(), "Eltwise strides count", prim->stride.size(), "");
197
198         const auto out_x = node.get_output_layout().size.spatial[0];
199         const auto out_y = node.get_output_layout().size.spatial[1];
200         // check if strides are correctly set. I.e INPUT_SIZE_X / STRIDE_X = OUTPUT_SIZE_X, same for Y dimension
201         for (size_t i = 0; i < node.inputs_count(); i++)
202         {
203             const auto& in_layout = node.input(i).get_output_layout();
204             auto stride = prim->stride[i];
205
206             const auto in_x_div_stride_x = in_layout.size.spatial[0] / stride.spatial[0];
207             if(in_x_div_stride_x != out_x)
208                 CLDNN_ERROR_NOT_EQUAL(node.id(), "Eltwise input_x / stride_x", in_x_div_stride_x, "Eltwise output_x", out_x, "");
209
210             const auto in_y_div_stride_y = in_layout.size.spatial[1] / stride.spatial[1];
211             if(in_y_div_stride_y != out_y)
212                 CLDNN_ERROR_NOT_EQUAL(node.id(), "Eltwise inputyx / stride_y", in_y_div_stride_y, "Eltwise output_y", out_y, "");
213         }
214     }
215     else
216     {
217         std::vector<int32_t> input0_size = node.input().get_output_layout().size.raw.vector();
218         for (size_t i = 1; i < node.inputs_count(); i++)
219         {
220             std::vector<int32_t> input_size = node.input(i).get_output_layout().size.raw.vector();
221             for (size_t d = 0; d < input0_size.size(); d++)
222             {
223                 bool sizes_equal = input0_size[d] == input_size[d];
224                 bool broadcast = (input0_size[d] == 1 || input_size[d] == 1) && (input0_size[d] != 1 || input_size[d] != 1);
225                 CLDNN_ERROR_BOOL(node.id(), "Sizes equal or broadcast is possible", !(sizes_equal || broadcast), "Invalid input shapes");
226             }
227         }
228     }
229 }
230
231 void eltwise_inst::check_inputs_count(eltwise_node const &node)
232 {
233     const size_t inputs_number = node.get_primitive()->input.size();
234     const eltwise_mode mode = node.get_primitive()->mode;
235
236     switch (mode)
237     {
238         case eltwise_mode::sum:
239         case eltwise_mode::sub:
240         case eltwise_mode::div:
241         case eltwise_mode::prod:
242         case eltwise_mode::max:
243         case eltwise_mode::min:
244         case eltwise_mode::mod:
245         case eltwise_mode::logic_and:
246         case eltwise_mode::logic_or:
247         case eltwise_mode::logic_xor:
248             if (inputs_number < 2)
249                 CLDNN_ERROR_MESSAGE(node.id(), "Invalid eltwise inputs number (should be equal at least to 2). Actual: " + std::to_string(inputs_number));
250             break;
251         case eltwise_mode::eq:
252         case eltwise_mode::ne:
253         case eltwise_mode::lt:
254         case eltwise_mode::le:
255         case eltwise_mode::gt:
256         case eltwise_mode::ge:
257         case eltwise_mode::squared_diff:
258         case eltwise_mode::pow:
259             if (inputs_number != 2)
260                 CLDNN_ERROR_MESSAGE(node.id(), "Invalid eltwise inputs number (should be equal to 2). Actual: " + std::to_string(inputs_number));
261             break;
262     }
263 }
264 }