You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@mxnet.apache.org by jx...@apache.org on 2018/03/22 06:23:30 UTC
[incubator-mxnet] branch master updated: Add quadratic op for the
tutorial of adding ops in backend (#10091)
This is an automated email from the ASF dual-hosted git repository.
jxie pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/incubator-mxnet.git
The following commit(s) were added to refs/heads/master by this push:
new 1e4bd20 Add quadratic op for the tutorial of adding ops in backend (#10091)
1e4bd20 is described below
commit 1e4bd20e873278be9890d6878c08942b4d4d2280
Author: reminisce <wu...@gmail.com>
AuthorDate: Wed Mar 21 23:23:26 2018 -0700
Add quadratic op for the tutorial of adding ops in backend (#10091)
* Add quadratic op for add op tutorial
* Fix unit test
* Fix unit test tolerance
* Move the op to contrib
* Fix lint
* Fix test
---
src/operator/contrib/quadratic_op-inl.h | 144 ++++++++++++++++++++++++++++++++
src/operator/contrib/quadratic_op.cc | 68 +++++++++++++++
src/operator/contrib/quadratic_op.cu | 36 ++++++++
tests/python/unittest/test_operator.py | 23 +++++
4 files changed, 271 insertions(+)
diff --git a/src/operator/contrib/quadratic_op-inl.h b/src/operator/contrib/quadratic_op-inl.h
new file mode 100644
index 0000000..8d73a42
--- /dev/null
+++ b/src/operator/contrib/quadratic_op-inl.h
@@ -0,0 +1,144 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+/*!
+ * \file quad_function-inl.h
+ * \brief Operator implementing quadratic function.
+ * For using as an exmaple in the tutorial of adding operators
+ * in MXNet backend.
+ */
+#ifndef MXNET_OPERATOR_CONTRIB_QUADRATIC_OP_INL_H_
+#define MXNET_OPERATOR_CONTRIB_QUADRATIC_OP_INL_H_
+
+#include <mxnet/operator_util.h>
+#include <vector>
+#include "../mshadow_op.h"
+#include "../mxnet_op.h"
+#include "../operator_common.h"
+#include "../elemwise_op_common.h"
+
+namespace mxnet {
+namespace op {
+
+struct QuadraticParam : public dmlc::Parameter<QuadraticParam> {
+ float a, b, c;
+ DMLC_DECLARE_PARAMETER(QuadraticParam) {
+ DMLC_DECLARE_FIELD(a)
+ .set_default(0.0)
+ .describe("Coefficient of the quadratic term in the quadratic function.");
+ DMLC_DECLARE_FIELD(b)
+ .set_default(0.0)
+ .describe("Coefficient of the linear term in the quadratic function.");
+ DMLC_DECLARE_FIELD(c)
+ .set_default(0.0)
+ .describe("Constant term in the quadratic function.");
+ }
+};
+
+inline bool QuadraticOpShape(const nnvm::NodeAttrs& attrs,
+ std::vector<TShape>* in_attrs,
+ std::vector<TShape>* out_attrs) {
+ CHECK_EQ(in_attrs->size(), 1U);
+ CHECK_EQ(out_attrs->size(), 1U);
+
+ SHAPE_ASSIGN_CHECK(*out_attrs, 0, in_attrs->at(0));
+ SHAPE_ASSIGN_CHECK(*in_attrs, 0, out_attrs->at(0));
+ return out_attrs->at(0).ndim() != 0U && out_attrs->at(0).Size() != 0U;
+}
+
+inline bool QuadraticOpType(const nnvm::NodeAttrs& attrs,
+ std::vector<int>* in_attrs,
+ std::vector<int>* out_attrs) {
+ CHECK_EQ(in_attrs->size(), 1U);
+ CHECK_EQ(out_attrs->size(), 1U);
+
+ TYPE_ASSIGN_CHECK(*out_attrs, 0, in_attrs->at(0));
+ TYPE_ASSIGN_CHECK(*in_attrs, 0, out_attrs->at(0));
+ return out_attrs->at(0) != -1;
+}
+
+template<int req>
+struct quadratic_forward {
+ template<typename DType>
+ MSHADOW_XINLINE static void Map(int i, DType* out_data, const DType* in_data,
+ const float a, const float b, const float c) {
+ KERNEL_ASSIGN(out_data[i], req, in_data[i] * (a * in_data[i] + b) + c);
+ }
+};
+
+template<int req>
+struct quadratic_backward {
+ template<typename DType>
+ MSHADOW_XINLINE static void Map(int i, DType* in_grad, const DType* out_grad,
+ const DType* in_data, const float a, const float b) {
+ KERNEL_ASSIGN(in_grad[i], req, out_grad[i] * (2 * a * in_data[i] + b));
+ }
+};
+
+template<typename xpu>
+void QuadraticOpForward(const nnvm::NodeAttrs& attrs,
+ const OpContext& ctx,
+ const std::vector<TBlob>& inputs,
+ const std::vector<OpReqType>& req,
+ const std::vector<TBlob>& outputs) {
+ CHECK_EQ(inputs.size(), 1U);
+ CHECK_EQ(outputs.size(), 1U);
+ CHECK_EQ(req.size(), 1U);
+ mshadow::Stream<xpu> *s = ctx.get_stream<xpu>();
+ const TBlob& in_data = inputs[0];
+ const TBlob& out_data = outputs[0];
+ const QuadraticParam& param = nnvm::get<QuadraticParam>(attrs.parsed);
+ using namespace mxnet_op;
+ MSHADOW_TYPE_SWITCH(out_data.type_flag_, DType, {
+ MXNET_ASSIGN_REQ_SWITCH(req[0], req_type, {
+ Kernel<quadratic_forward<req_type>, xpu>::Launch(
+ s, out_data.Size(), out_data.dptr<DType>(), in_data.dptr<DType>(),
+ param.a, param.b, param.c);
+ });
+ });
+}
+
+template<typename xpu>
+void QuadraticOpBackward(const nnvm::NodeAttrs& attrs,
+ const OpContext& ctx,
+ const std::vector<TBlob>& inputs,
+ const std::vector<OpReqType>& req,
+ const std::vector<TBlob>& outputs) {
+ CHECK_EQ(inputs.size(), 2U);
+ CHECK_EQ(outputs.size(), 1U);
+ CHECK_EQ(req.size(), 1U);
+ mshadow::Stream<xpu> *s = ctx.get_stream<xpu>();
+ const TBlob& out_grad = inputs[0];
+ const TBlob& in_data = inputs[1];
+ const TBlob& in_grad = outputs[0];
+ const QuadraticParam& param = nnvm::get<QuadraticParam>(attrs.parsed);
+ using namespace mxnet_op;
+ MSHADOW_TYPE_SWITCH(out_grad.type_flag_, DType, {
+ MXNET_ASSIGN_REQ_SWITCH(req[0], req_type, {
+ Kernel<quadratic_backward<req_type>, xpu>::Launch(
+ s, in_grad.Size(), in_grad.dptr<DType>(), out_grad.dptr<DType>(),
+ in_data.dptr<DType>(), param.a, param.b);
+ });
+ });
+}
+
+} // namespace op
+} // namespace mxnet
+
+#endif // MXNET_OPERATOR_CONTRIB_QUADRATIC_OP_INL_H_
diff --git a/src/operator/contrib/quadratic_op.cc b/src/operator/contrib/quadratic_op.cc
new file mode 100644
index 0000000..5b2d84c
--- /dev/null
+++ b/src/operator/contrib/quadratic_op.cc
@@ -0,0 +1,68 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+/*!
+ * \file quadratic_op.cc
+ * \brief CPU Implementation of quadratic op
+ */
+#include "./quadratic_op-inl.h"
+
+namespace mxnet {
+namespace op {
+
+DMLC_REGISTER_PARAMETER(QuadraticParam);
+
+NNVM_REGISTER_OP(_contrib_quadratic)
+.describe(R"code(This operators implements the quadratic function:
+.. math::
+ f(x) = ax^2+bx+c
+where :math:`x` is an input tensor and all operations
+in the function are element-wise.
+Example::
+ x = [[1, 2], [3, 4]]
+ y = quadratic(data=x, a=1, b=2, c=3)
+ y = [[6, 11], [18, 27]]
+)code" ADD_FILELINE)
+.set_attr_parser(ParamParser<QuadraticParam>)
+.set_num_inputs(1)
+.set_num_outputs(1)
+.set_attr<nnvm::FListInputNames>("FListInputNames",
+ [](const NodeAttrs& attrs) {
+ return std::vector<std::string>{"data"};
+ })
+.set_attr<nnvm::FInferShape>("FInferShape", QuadraticOpShape)
+.set_attr<nnvm::FInferType>("FInferType", QuadraticOpType)
+.set_attr<FCompute>("FCompute<cpu>", QuadraticOpForward<cpu>)
+.set_attr<nnvm::FGradient>("FGradient", ElemwiseGradUseIn{"_contrib_backward_quadratic"})
+.set_attr<nnvm::FInplaceOption>("FInplaceOption",
+ [](const NodeAttrs& attrs) {
+ return std::vector<std::pair<int, int> >{{0, 0}};
+ })
+.add_argument("data", "NDArray-or-Symbol", "Input ndarray")
+.add_arguments(QuadraticParam::__FIELDS__());
+
+NNVM_REGISTER_OP(_contrib_backward_quadratic)
+.set_attr_parser(ParamParser<QuadraticParam>)
+.set_num_inputs(2)
+.set_num_outputs(1)
+.set_attr<nnvm::TIsBackward>("TIsBackward", true)
+.set_attr<FCompute>("FCompute<cpu>", QuadraticOpBackward<cpu>);
+
+} // namespace op
+} // namespace mxnet
diff --git a/src/operator/contrib/quadratic_op.cu b/src/operator/contrib/quadratic_op.cu
new file mode 100644
index 0000000..ede773a
--- /dev/null
+++ b/src/operator/contrib/quadratic_op.cu
@@ -0,0 +1,36 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+/*!
+ * \file quadratic_op.cu
+ * \brief GPU Implementation of quadratic op
+ */
+#include "./quadratic_op-inl.h"
+
+namespace mxnet {
+namespace op {
+
+NNVM_REGISTER_OP(_contrib_quadratic)
+.set_attr<FCompute>("FCompute<gpu>", QuadraticOpForward<gpu>);
+
+NNVM_REGISTER_OP(_contrib_backward_quadratic)
+.set_attr<FCompute>("FCompute<gpu>", QuadraticOpBackward<gpu>);
+
+} // namespace op
+} // namespace mxnet
diff --git a/tests/python/unittest/test_operator.py b/tests/python/unittest/test_operator.py
index 96ff61a..c1df291 100644
--- a/tests/python/unittest/test_operator.py
+++ b/tests/python/unittest/test_operator.py
@@ -5305,6 +5305,29 @@ def test_multi_proposal_op():
check_forward(1000, 500)
check_backward(rpn_pre_nms_top_n, rpn_post_nms_top_n)
+@with_seed()
+def test_quadratic_function():
+ def f(x, a, b, c):
+ return a * x**2 + b * x + c
+
+ a = np.random.random_sample()
+ b = np.random.random_sample()
+ c = np.random.random_sample()
+ # check forward
+ for ndim in range(1, 6):
+ shape = rand_shape_nd(ndim, 5)
+ data = rand_ndarray(shape=shape, stype='default')
+ data_np = data.asnumpy()
+ expected = f(data_np, a, b, c)
+ output = mx.nd.contrib.quadratic(data, a=a, b=b, c=c)
+ assert_almost_equal(output.asnumpy(), expected, rtol=0.001, atol=0.0001)
+
+ # check backward using finite difference
+ data = mx.sym.Variable('data')
+ quad_sym = mx.sym.contrib.quadratic(data=data, a=a, b=b, c=c)
+ check_numeric_gradient(quad_sym, [data_np], atol=0.001)
+
+
if __name__ == '__main__':
import nose
nose.runmodule()
--
To stop receiving notification emails like this one, please contact
jxie@apache.org.