2 // Copyright (c) 2016-2019 Intel Corporation
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
8 // http://www.apache.org/licenses/LICENSE-2.0
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.
17 ///////////////////////////////////////////////////////////////////////////////////////////////////
18 #include "eltwise_inst.h"
19 #include "primitive_type_base.h"
20 #include "error_handler.h"
21 #include "json_object.h"
25 primitive_type_id eltwise_type_id()
27 static primitive_type_base<eltwise> instance;
31 layout eltwise_inst::calc_output_layout(eltwise_node const& node)
33 assert((bool)node.get_primitive()->output_data_type == false
34 && "Output data type forcing is not supported for eltwise_inst_node!");
36 auto input_node_layout = node.input().get_non_padded_output_layout();
38 auto size = input_node_layout.size;
39 for (size_t i = 1; i < node.inputs_count(); i++)
41 size = tensor::max(size, node.input(i).get_non_padded_output_layout().size);
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)
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.");
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())
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.");
68 auto eltw = std::static_pointer_cast<const eltwise>((node.get_primitive()));
69 if (!eltw->stride.empty())
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;
79 static inline std::string stringify_vector(const std::vector<float>& v)
85 for (size_t i = 0; i < v.size(); ++i)
88 if (i + 1 < v.size()) s << ", ";
96 std::string eltwise_inst::to_string(eltwise_node const& node)
98 auto node_info = node.desc_to_json();
99 auto desc = node.get_primitive();
100 auto activation = desc->with_activation ? " true" : "false";
102 std::stringstream primitive_description;
103 std::string str_mode;
107 case eltwise_mode::sum:
110 case eltwise_mode::sub:
111 str_mode = "subtract";
113 case eltwise_mode::max:
116 case eltwise_mode::prod:
117 str_mode = "product";
119 case eltwise_mode::div:
122 case eltwise_mode::min:
125 case eltwise_mode::pow:
128 case eltwise_mode::squared_diff:
129 str_mode = "squared_diff";
131 case eltwise_mode::mod:
134 case eltwise_mode::eq:
137 case eltwise_mode::ne:
138 str_mode = "not equal";
140 case eltwise_mode::lt:
143 case eltwise_mode::le:
144 str_mode = "less-or-equal";
146 case eltwise_mode::gt:
147 str_mode = "greater";
149 case eltwise_mode::ge:
150 str_mode = "greater-or-equal";
152 case eltwise_mode::logic_and:
155 case eltwise_mode::logic_or:
158 case eltwise_mode::logic_xor:
162 str_mode = "not supported mode";
166 json_composite eltwise_info;
167 for (size_t i = 0; i < node.inputs_count(); i++)
169 eltwise_info.add("input_"+std::to_string(i), node.input(i).id());
171 eltwise_info.add("mode", str_mode);
172 if (desc->mode == eltwise_mode::sum)
174 eltwise_info.add("coefficients", stringify_vector(desc->coefficients));
176 if (desc->with_activation)
178 eltwise_info.add("with activation", activation);
179 eltwise_info.add("slope", desc->activation_negative_slope);
181 node_info->add("eltwise info", eltwise_info);
182 node_info->dump(primitive_description);
184 return primitive_description.str();
187 eltwise_inst::typed_primitive_inst(network_impl& network, eltwise_node const& node)
188 :parent(network, node)
190 check_inputs_count(node);
192 auto prim = node.get_primitive();
193 if (!prim->stride.empty())
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(), "");
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++)
203 const auto& in_layout = node.input(i).get_output_layout();
204 auto stride = prim->stride[i];
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, "");
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, "");
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++)
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++)
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");
231 void eltwise_inst::check_inputs_count(eltwise_node const &node)
233 const size_t inputs_number = node.get_primitive()->input.size();
234 const eltwise_mode mode = node.get_primitive()->mode;
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));
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));