1 /*
2 * Licensed to the Apache Software Foundation (ASF) under one
3 * or more contributor license agreements. See the NOTICE file
4 * distributed with this work for additional information
5 * regarding copyright ownership. The ASF licenses this file
6 * to you under the Apache License, Version 2.0 (the
7 * "License"); you may not use this file except in compliance
8 * with the License. You may obtain a copy of the License at
9 *
10 * http://www.apache.org/licenses/LICENSE-2.0
11 *
12 * Unless required by applicable law or agreed to in writing,
13 * software distributed under the License is distributed on an
14 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15 * KIND, either express or implied. See the License for the
16 * specific language governing permissions and limitations
17 * under the License.
18 */
19
20 /*!
21 * \file np_elemwise_binary_op_extended.cc
22 * \brief CPU Implementation of extended functions for elementwise numpy binary broadcast operator.
23 */
24
25 #include <dmlc/strtonum.h>
26 #include "../../common/utils.h"
27 #include "./np_elemwise_broadcast_op.h"
28
29 namespace mxnet {
30 namespace op {
31
32 #define MXNET_OPERATOR_REGISTER_NP_BINARY_SCALAR(name) \
33 NNVM_REGISTER_OP(name) \
34 .set_num_inputs(1) \
35 .set_num_outputs(1) \
36 .set_attr_parser(ParamParser<NumpyBinaryScalarParam>) \
37 .set_attr<mxnet::FInferShape>("FInferShape", ElemwiseShape<1, 1>) \
38 .set_attr<nnvm::FInferType>("FInferType", NumpyBinaryScalarType) \
39 .set_attr<FResourceRequest>("FResourceRequest", \
40 [](const NodeAttrs& attrs) { \
41 return std::vector<ResourceRequest>{ResourceRequest::kTempSpace}; \
42 }) \
43 .add_argument("data", "NDArray-or-Symbol", "source input") \
44 .add_arguments(NumpyBinaryScalarParam::__FIELDS__())
45
46 MXNET_OPERATOR_REGISTER_BINARY_BROADCAST(_npi_copysign)
47 .describe(R"code()code" ADD_FILELINE)
48 .set_attr<FCompute>("FCompute<cpu>", BinaryBroadcastCompute<cpu, mshadow_op::copysign>)
49 .set_attr<nnvm::FGradient>("FGradient", ElemwiseGradUseIn{"_backward_npi_copysign"});
50
51 NNVM_REGISTER_OP(_backward_npi_copysign)
52 .set_num_inputs(3)
53 .set_num_outputs(2)
54 .set_attr<nnvm::TIsBackward>("TIsBackward", true)
55 .set_attr<nnvm::FInplaceOption>("FInplaceOption",
__anon03a3cbee0102(const NodeAttrs& attrs)56 [](const NodeAttrs& attrs){
57 return std::vector<std::pair<int, int> >{{0, 1}};
58 })
59 .set_attr<FResourceRequest>("FResourceRequest",
__anon03a3cbee0202(const NodeAttrs& attrs) 60 [](const NodeAttrs& attrs) {
61 return std::vector<ResourceRequest>{ResourceRequest::kTempSpace};
62 })
63 .set_attr<FCompute>("FCompute<cpu>", BinaryBroadcastBackwardUseIn<cpu, mshadow_op::copysign_grad,
64 mshadow_op::copysign_rgrad>);
65
66 NNVM_REGISTER_OP(_npi_lcm)
67 .set_num_inputs(2)
68 .set_num_outputs(1)
69 .set_attr<nnvm::FListInputNames>("FListInputNames",
__anon03a3cbee0302(const NodeAttrs& attrs) 70 [](const NodeAttrs& attrs) {
71 return std::vector<std::string>{"lhs", "rhs"};
72 })
73 .set_attr<mxnet::FInferShape>("FInferShape", BinaryBroadcastShape)
74 .set_attr<nnvm::FInferType>("FInferType", ElemwiseIntType<2, 1>)
75 .set_attr<nnvm::FInplaceOption>("FInplaceOption",
__anon03a3cbee0402(const NodeAttrs& attrs)76 [](const NodeAttrs& attrs){
77 return std::vector<std::pair<int, int> >{{0, 0}, {1, 0}};
78 })
79 .set_attr<nnvm::FGradient>("FGradient", MakeZeroGradNodes)
80 .set_attr<FCompute>("FCompute<cpu>", BinaryBroadcastIntCompute<cpu, mshadow_op::lcm>)
81 .add_argument("lhs", "NDArray-or-Symbol", "First input to the function")
82 .add_argument("rhs", "NDArray-or-Symbol", "Second input to the function");
83
84 NNVM_REGISTER_OP(_npi_lcm_scalar)
85 .set_num_inputs(1)
86 .set_num_outputs(1)
87 .set_attr_parser(ParamParser<NumpyBinaryScalarParam>)
88 .set_attr<mxnet::FInferShape>("FInferShape", ElemwiseShape<1, 1>)
89 .set_attr<nnvm::FInferType>("FInferType", ElemwiseIntType<1, 1>)
90 .set_attr<nnvm::FInplaceOption>("FInplaceOption",
__anon03a3cbee0502(const NodeAttrs& attrs)91 [](const NodeAttrs& attrs){
92 return std::vector<std::pair<int, int> >{{0, 0}};
93 })
94 .set_attr<nnvm::FGradient>("FGradient", MakeZeroGradNodes)
95 .add_argument("data", "NDArray-or-Symbol", "source input")
96 .add_arguments(NumpyBinaryScalarParam::__FIELDS__())
97 .set_attr<FCompute>("FCompute<cpu>", BinaryScalarOp::Compute<cpu, mshadow_op::lcm>);
98
99 NNVM_REGISTER_OP(_npi_bitwise_and)
100 .set_num_inputs(2)
101 .set_num_outputs(1)
102 .set_attr<nnvm::FListInputNames>("FListInputNames",
__anon03a3cbee0602(const NodeAttrs& attrs) 103 [](const NodeAttrs& attrs) {
104 return std::vector<std::string>{"lhs", "rhs"};
105 })
106 .set_attr<mxnet::FInferShape>("FInferShape", BinaryBroadcastShape)
107 .set_attr<nnvm::FInferType>("FInferType", ElemwiseIntType<2, 1>)
108 .set_attr<nnvm::FInplaceOption>("FInplaceOption",
__anon03a3cbee0702(const NodeAttrs& attrs)109 [](const NodeAttrs& attrs){
110 return std::vector<std::pair<int, int> >{{0, 0}, {1, 0}};
111 })
112 .set_attr<nnvm::FGradient>("FGradient", MakeZeroGradNodes)
113 .set_attr<FCompute>("FCompute<cpu>", BinaryBroadcastIntCompute<cpu, mshadow_op::bitwise_and>)
114 .add_argument("lhs", "NDArray-or-Symbol", "First input to the function")
115 .add_argument("rhs", "NDArray-or-Symbol", "Second input to the function");
116
117 NNVM_REGISTER_OP(_npi_bitwise_and_scalar)
118 .set_num_inputs(1)
119 .set_num_outputs(1)
120 .set_attr_parser(ParamParser<NumpyBinaryScalarParam>)
121 .set_attr<mxnet::FInferShape>("FInferShape", ElemwiseShape<1, 1>)
122 .set_attr<nnvm::FInferType>("FInferType", ElemwiseIntType<1, 1>)
123 .set_attr<nnvm::FInplaceOption>("FInplaceOption",
__anon03a3cbee0802(const NodeAttrs& attrs)124 [](const NodeAttrs& attrs){
125 return std::vector<std::pair<int, int> >{{0, 0}};
126 })
127 .set_attr<nnvm::FGradient>("FGradient", MakeZeroGradNodes)
128 .add_argument("data", "NDArray-or-Symbol", "source input")
129 .add_arguments(NumpyBinaryScalarParam::__FIELDS__())
130 .set_attr<FCompute>("FCompute<cpu>", BinaryScalarOp::ComputeInt<cpu, mshadow_op::bitwise_and>);
131
132 NNVM_REGISTER_OP(_npi_bitwise_xor)
133 .set_num_inputs(2)
134 .set_num_outputs(1)
135 .set_attr<nnvm::FListInputNames>("FListInputNames",
__anon03a3cbee0902(const NodeAttrs& attrs) 136 [](const NodeAttrs& attrs) {
137 return std::vector<std::string>{"lhs", "rhs"};
138 })
139 .set_attr<mxnet::FInferShape>("FInferShape", BinaryBroadcastShape)
140 .set_attr<nnvm::FInferType>("FInferType", ElemwiseIntType<2, 1>)
141 .set_attr<nnvm::FInplaceOption>("FInplaceOption",
__anon03a3cbee0a02(const NodeAttrs& attrs)142 [](const NodeAttrs& attrs){
143 return std::vector<std::pair<int, int> >{{0, 0}, {1, 0}};
144 })
145 .set_attr<nnvm::FGradient>("FGradient", MakeZeroGradNodes)
146 .set_attr<FCompute>("FCompute<cpu>", BinaryBroadcastIntCompute<cpu, mshadow_op::bitwise_xor>)
147 .add_argument("lhs", "NDArray-or-Symbol", "First input to the function")
148 .add_argument("rhs", "NDArray-or-Symbol", "Second input to the function");
149
150 NNVM_REGISTER_OP(_npi_bitwise_or)
151 .set_num_inputs(2)
152 .set_num_outputs(1)
153 .set_attr<nnvm::FListInputNames>("FListInputNames",
__anon03a3cbee0b02(const NodeAttrs& attrs) 154 [](const NodeAttrs& attrs) {
155 return std::vector<std::string>{"lhs", "rhs"};
156 })
157 .set_attr<mxnet::FInferShape>("FInferShape", BinaryBroadcastShape)
158 .set_attr<nnvm::FInferType>("FInferType", ElemwiseIntType<2, 1>)
159 .set_attr<nnvm::FInplaceOption>("FInplaceOption",
__anon03a3cbee0c02(const NodeAttrs& attrs)160 [](const NodeAttrs& attrs){
161 return std::vector<std::pair<int, int> >{{0, 0}, {1, 0}};
162 })
163 .set_attr<nnvm::FGradient>("FGradient", MakeZeroGradNodes)
164 .set_attr<FCompute>("FCompute<cpu>", BinaryBroadcastIntCompute<cpu, mshadow_op::bitwise_or>)
165 .add_argument("lhs", "NDArray-or-Symbol", "First input to the function")
166 .add_argument("rhs", "NDArray-or-Symbol", "Second input to the function");
167
168 NNVM_REGISTER_OP(_npi_bitwise_xor_scalar)
169 .set_num_inputs(1)
170 .set_num_outputs(1)
171 .set_attr_parser(ParamParser<NumpyBinaryScalarParam>)
172 .set_attr<mxnet::FInferShape>("FInferShape", ElemwiseShape<1, 1>)
173 .set_attr<nnvm::FInferType>("FInferType", ElemwiseIntType<1, 1>)
174 .set_attr<nnvm::FInplaceOption>("FInplaceOption",
__anon03a3cbee0d02(const NodeAttrs& attrs)175 [](const NodeAttrs& attrs){
176 return std::vector<std::pair<int, int> >{{0, 0}};
177 })
178 .set_attr<nnvm::FGradient>("FGradient", MakeZeroGradNodes)
179 .add_argument("data", "NDArray-or-Symbol", "source input")
180 .add_arguments(NumpyBinaryScalarParam::__FIELDS__())
181 .set_attr<FCompute>("FCompute<cpu>", BinaryScalarOp::ComputeInt<cpu, mshadow_op::bitwise_xor>);
182
183 NNVM_REGISTER_OP(_npi_bitwise_or_scalar)
184 .set_num_inputs(1)
185 .set_num_outputs(1)
186 .set_attr_parser(ParamParser<NumpyBinaryScalarParam>)
187 .set_attr<mxnet::FInferShape>("FInferShape", ElemwiseShape<1, 1>)
188 .set_attr<nnvm::FInferType>("FInferType", ElemwiseIntType<1, 1>)
189 .set_attr<nnvm::FInplaceOption>("FInplaceOption",
__anon03a3cbee0e02(const NodeAttrs& attrs)190 [](const NodeAttrs& attrs){
191 return std::vector<std::pair<int, int> >{{0, 0}};
192 })
193 .set_attr<nnvm::FGradient>("FGradient", MakeZeroGradNodes)
194 .add_argument("data", "NDArray-or-Symbol", "source input")
195 .add_arguments(NumpyBinaryScalarParam::__FIELDS__())
196 .set_attr<FCompute>("FCompute<cpu>", BinaryScalarOp::ComputeInt<cpu, mshadow_op::bitwise_or>);
197
198 MXNET_OPERATOR_REGISTER_NP_BINARY_SCALAR(_npi_copysign_scalar)
199 .set_attr<FCompute>("FCompute<cpu>", BinaryScalarOp::Compute<cpu, mshadow_op::copysign>)
200 .set_attr<nnvm::FGradient>("FGradient", ElemwiseGradUseIn{"_backward_npi_copysign_scalar"});
201
202 MXNET_OPERATOR_REGISTER_NP_BINARY_SCALAR(_npi_rcopysign_scalar)
203 .set_attr<FCompute>("FCompute<cpu>", BinaryScalarOp::Compute<cpu, mshadow_op::rcopysign>)
204 .set_attr<nnvm::FGradient>("FGradient", ElemwiseGradUseIn{"_backward_npi_rcopysign_scalar"});
205
206 MXNET_OPERATOR_REGISTER_NP_BINARY_SCALAR(_backward_npi_copysign_scalar)
207 .set_attr<FCompute>("FCompute<cpu>",
208 BinaryScalarOp::Backward<cpu, mshadow_op::copysign_grad>);
209
210 MXNET_OPERATOR_REGISTER_NP_BINARY_SCALAR(_backward_npi_rcopysign_scalar)
211 .set_attr<FCompute>("FCompute<cpu>",
212 BinaryScalarOp::Backward<cpu, mshadow_op::rcopysign_grad>);
213
Arctan2OpType(const nnvm::NodeAttrs & attrs,std::vector<int> * in_attrs,std::vector<int> * out_attrs)214 inline bool Arctan2OpType(const nnvm::NodeAttrs& attrs,
215 std::vector<int>* in_attrs,
216 std::vector<int>* out_attrs) {
217 CHECK_EQ(in_attrs->size(), 2U);
218 CHECK_EQ(out_attrs->size(), 1U);
219
220 TYPE_ASSIGN_CHECK(*out_attrs, 0, in_attrs->at(0));
221 TYPE_ASSIGN_CHECK(*out_attrs, 0, in_attrs->at(1));
222 TYPE_ASSIGN_CHECK(*in_attrs, 0, out_attrs->at(0));
223 TYPE_ASSIGN_CHECK(*in_attrs, 1, out_attrs->at(0));
224 // check if it is float16, float32 or float64. If not, raise error.
225 CHECK(common::is_float(in_attrs->at(0))) << "Do not support `int` as input.\n";
226 return out_attrs->at(0) != -1;
227 }
228
229 NNVM_REGISTER_OP(_npi_arctan2)
230 .set_num_inputs(2)
231 .set_num_outputs(1)
232 .set_attr<nnvm::FListInputNames>("FListInputNames",
__anon03a3cbee0f02(const NodeAttrs& attrs) 233 [](const NodeAttrs& attrs) {
234 return std::vector<std::string>{"x1", "x2"};
235 })
236 .set_attr<mxnet::FInferShape>("FInferShape", BinaryBroadcastShape)
237 .set_attr<nnvm::FInferType>("FInferType", Arctan2OpType)
238 .set_attr<FCompute>("FCompute<cpu>", BinaryBroadcastCompute<cpu, mshadow_op::arctan2>)
239 .set_attr<nnvm::FGradient>("FGradient", ElemwiseGradUseIn{"_backward_npi_arctan2"})
240 .set_attr<nnvm::FInplaceOption>("FInplaceOption",
__anon03a3cbee1002(const NodeAttrs& attrs) 241 [](const NodeAttrs& attrs) {
242 return std::vector<std::pair<int, int> >{{0, 0}};
243 })
244 .add_argument("x1", "NDArray-or-Symbol", "The input array")
245 .add_argument("x2", "NDArray-or-Symbol", "The input array");
246
247 NNVM_REGISTER_OP(_backward_npi_arctan2)
248 .set_num_inputs(3)
249 .set_num_outputs(2)
250 .set_attr<nnvm::TIsBackward>("TIsBackward", true)
251 .set_attr<FResourceRequest>("FResourceRequest",
__anon03a3cbee1102(const NodeAttrs& attrs) 252 [](const NodeAttrs& attrs) {
253 return std::vector<ResourceRequest>{ResourceRequest::kTempSpace};
254 })
255 .set_attr<FCompute>("FCompute<cpu>", BinaryBroadcastBackwardUseIn<cpu, mshadow_op::arctan2_grad,
256 mshadow_op::arctan2_rgrad>);
257
258 MXNET_OPERATOR_REGISTER_NP_BINARY_SCALAR(_npi_arctan2_scalar)
259 .set_attr<FCompute>("FCompute<cpu>", BinaryScalarOp::Compute<cpu, mshadow_op::arctan2>)
260 .set_attr<nnvm::FGradient>("FGradient", ElemwiseGradUseIn{"_backward_npi_arctan2_scalar"});
261
262 MXNET_OPERATOR_REGISTER_NP_BINARY_SCALAR(_npi_rarctan2_scalar)
263 .set_attr<FCompute>("FCompute<cpu>", BinaryScalarOp::Compute<cpu, mshadow_op::rarctan2>)
264 .set_attr<nnvm::FGradient>("FGradient", ElemwiseGradUseIn{"_backward_npi_rarctan2_scalar"});
265
266 MXNET_OPERATOR_REGISTER_BINARY(_backward_npi_arctan2_scalar)
267 .add_arguments(NumpyBinaryScalarParam::__FIELDS__())
268 .set_attr_parser(ParamParser<NumpyBinaryScalarParam>)
269 .set_attr<FCompute>("FCompute<cpu>",
270 BinaryScalarOp::Backward<cpu, mshadow_op::arctan2_grad>);
271
272 MXNET_OPERATOR_REGISTER_BINARY(_backward_npi_rarctan2_scalar)
273 .add_arguments(NumpyBinaryScalarParam::__FIELDS__())
274 .set_attr_parser(ParamParser<NumpyBinaryScalarParam>)
275 .set_attr<FCompute>("FCompute<cpu>",
276 BinaryScalarOp::Backward<cpu, mshadow_op::arctan2_rgrad>);
277
HypotOpType(const nnvm::NodeAttrs & attrs,std::vector<int> * in_attrs,std::vector<int> * out_attrs)278 bool HypotOpType(const nnvm::NodeAttrs& attrs,
279 std::vector<int>* in_attrs,
280 std::vector<int>* out_attrs) {
281 CHECK_EQ(in_attrs->size(), 2U);
282 CHECK_EQ(out_attrs->size(), 1U);
283
284 TYPE_ASSIGN_CHECK(*out_attrs, 0, in_attrs->at(0));
285 TYPE_ASSIGN_CHECK(*out_attrs, 0, in_attrs->at(1));
286 TYPE_ASSIGN_CHECK(*in_attrs, 0, out_attrs->at(0));
287 TYPE_ASSIGN_CHECK(*in_attrs, 1, out_attrs->at(0));
288
289 CHECK(common::is_float(in_attrs->at(0))) << "Do not support `int` as input.\n";
290 return out_attrs->at(0) != -1;
291 }
292
293 // rigister hypot that do not support int here
294 NNVM_REGISTER_OP(_npi_hypot)
295 .set_num_inputs(2)
296 .set_num_outputs(1)
297 .set_attr<nnvm::FListInputNames>("FListInputNames",
__anon03a3cbee1202(const NodeAttrs& attrs) 298 [](const NodeAttrs& attrs) {
299 return std::vector<std::string>{"x1", "x2"};
300 })
301 .set_attr<mxnet::FInferShape>("FInferShape", BinaryBroadcastShape)
302 .set_attr<nnvm::FInferType>("FInferType", HypotOpType)
303 .set_attr<FCompute>("FCompute<cpu>", BinaryBroadcastCompute<cpu, mshadow_op::hypot>)
304 .set_attr<nnvm::FGradient>("FGradient", ElemwiseGradUseIn{"_backward_npi_hypot"})
305 .set_attr<nnvm::FInplaceOption>("FInplaceOption",
__anon03a3cbee1302(const NodeAttrs& attrs) 306 [](const NodeAttrs& attrs) {
307 return std::vector<std::pair<int, int> >{{0, 0}, {1, 0}};
308 })
309 .add_argument("x1", "NDArray-or-Symbol", "The input array")
310 .add_argument("x2", "NDArray-or-Symbol", "The input array");
311
312 NNVM_REGISTER_OP(_backward_npi_hypot)
313 .set_num_inputs(3)
314 .set_num_outputs(2)
315 .set_attr<nnvm::TIsBackward>("TIsBackward", true)
316 .set_attr<nnvm::FInplaceOption>("FInplaceOption",
__anon03a3cbee1402(const NodeAttrs& attrs) 317 [](const NodeAttrs& attrs) {
318 return std::vector<std::pair<int, int> > {{0, 1}};
319 })
320 .set_attr<FResourceRequest>("FResourceRequest",
__anon03a3cbee1502(const NodeAttrs& attrs) 321 [](const NodeAttrs& attrs) {
322 return std::vector<ResourceRequest>{ResourceRequest::kTempSpace};
323 })
324 .set_attr<FCompute>("FCompute<cpu>", BinaryBroadcastBackwardUseIn<cpu, mshadow_op::hypot_grad_left,
325 mshadow_op::hypot_grad_right>);
326
327 MXNET_OPERATOR_REGISTER_BINARY_BROADCAST(_npi_ldexp)
328 .set_attr<FCompute>("FCompute<cpu>", BinaryBroadcastCompute<cpu, mshadow_op::ldexp>)
329 .set_attr<nnvm::FGradient>("FGradient", ElemwiseGradUseIn{"_backward_npi_ldexp"});
330
331 MXNET_OPERATOR_REGISTER_NP_BINARY_SCALAR(_npi_ldexp_scalar)
332 .set_attr<FCompute>("FCompute<cpu>", BinaryScalarOp::Compute<cpu, mshadow_op::ldexp>)
333 .set_attr<nnvm::FGradient>("FGradient", ElemwiseGradUseIn{"_backward_npi_ldexp_scalar"});
334
335 MXNET_OPERATOR_REGISTER_NP_BINARY_SCALAR(_npi_rldexp_scalar)
336 .set_attr<FCompute>("FCompute<cpu>", BinaryScalarOp::Compute<cpu, mshadow_op::rldexp>)
337 .set_attr<nnvm::FGradient>("FGradient", ElemwiseGradUseIn{"_backward_npi_rldexp_scalar"});
338
339 NNVM_REGISTER_OP(_backward_npi_ldexp)
340 .set_num_inputs(3)
341 .set_num_outputs(2)
342 .set_attr<nnvm::TIsBackward>("TIsBackward", true)
343 .set_attr<nnvm::FInplaceOption>("FInplaceOption",
__anon03a3cbee1602(const NodeAttrs& attrs)344 [](const NodeAttrs& attrs){
345 return std::vector<std::pair<int, int> >{{0, 1}};
346 })
347 .set_attr<FResourceRequest>("FResourceRequest",
__anon03a3cbee1702(const NodeAttrs& attrs) 348 [](const NodeAttrs& attrs) {
349 return std::vector<ResourceRequest>{ResourceRequest::kTempSpace};
350 })
351 .set_attr<FCompute>("FCompute<cpu>", BinaryBroadcastBackwardUseIn<cpu, mshadow_op::ldexp_grad,
352 mshadow_op::ldexp_rgrad>);
353
354 MXNET_OPERATOR_REGISTER_BINARY(_backward_npi_ldexp_scalar)
355 .add_arguments(NumpyBinaryScalarParam::__FIELDS__())
356 .set_attr_parser(ParamParser<NumpyBinaryScalarParam>)
357 .set_attr<FCompute>("FCompute<cpu>", BinaryScalarOp::Backward<cpu, mshadow_op::ldexp_grad>);
358
359 MXNET_OPERATOR_REGISTER_BINARY(_backward_npi_rldexp_scalar)
360 .add_arguments(NumpyBinaryScalarParam::__FIELDS__())
361 .set_attr_parser(ParamParser<NumpyBinaryScalarParam>)
362 .set_attr<FCompute>("FCompute<cpu>", BinaryScalarOp::Backward<cpu, mshadow_op::rldexp_grad>);
363
364 } // namespace op
365 } // namespace mxnet
366