This is an automated email from the ASF dual-hosted git repository.

bgawrych 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 c70ea50014 [FEATURE] Integrate oneDNN support for scalar power() 
operator  (#20904)
c70ea50014 is described below

commit c70ea500142576439e1eb1e8725be6bed063457b
Author: AdamGrabowski <[email protected]>
AuthorDate: Tue Apr 26 10:31:34 2022 +0200

    [FEATURE] Integrate oneDNN support for scalar power() operator  (#20904)
    
    * Integrate oneDNN support for power() operator from MXNet NumPy and 
NDArray modules
    
    * Move DNNLPowerForward function to dnnl file
    
    * Fix include files, declaration, SupportDNNL function and OPCHECK macros
    
    * Support only fp32
---
 src/operator/nn/dnnl/dnnl_base-inl.h               |  1 +
 src/operator/nn/dnnl/dnnl_ops-inl.h                |  6 ++
 src/operator/nn/dnnl/dnnl_power_scalar-inl.h       | 61 ++++++++++++++
 src/operator/nn/dnnl/dnnl_power_scalar.cc          | 94 ++++++++++++++++++++++
 .../numpy/np_elemwise_broadcast_op_scalar.cc       |  4 +
 src/operator/tensor/elemwise_binary_scalar_op.h    | 17 ++++
 .../tensor/elemwise_binary_scalar_op_extended.cc   | 33 ++++++++
 7 files changed, 216 insertions(+)

diff --git a/src/operator/nn/dnnl/dnnl_base-inl.h 
b/src/operator/nn/dnnl/dnnl_base-inl.h
index c1766d9355..8e3d4835d1 100644
--- a/src/operator/nn/dnnl/dnnl_base-inl.h
+++ b/src/operator/nn/dnnl/dnnl_base-inl.h
@@ -206,6 +206,7 @@ bool SupportDNNLSplit(const NDArray& input);
 bool SupportDNNLStack(const std::vector<NDArray>& inputs);
 bool SupportDNNLBinary(const std::vector<NDArray>& inputs);
 bool SupportDNNLEltwise(const NDArray& input, const NDArray& output);
+bool SupportDNNLPower(const NDArray& input);
 }  // namespace op
 
 static int GetTypeSize(int dtype) {
diff --git a/src/operator/nn/dnnl/dnnl_ops-inl.h 
b/src/operator/nn/dnnl/dnnl_ops-inl.h
index 06ed1e0f26..8ccdaaceda 100644
--- a/src/operator/nn/dnnl/dnnl_ops-inl.h
+++ b/src/operator/nn/dnnl/dnnl_ops-inl.h
@@ -217,6 +217,12 @@ void DNNLWhereForward(const nnvm::NodeAttrs& attrs,
                       const std::vector<OpReqType>& req,
                       const std::vector<NDArray>& outputs);
 
+void DNNLPowerForward(const nnvm::NodeAttrs& attrs,
+                      const OpContext& ctx,
+                      const NDArray& input,
+                      const OpReqType& req,
+                      const NDArray& output);
+
 }  // namespace op
 }  // namespace mxnet
 
diff --git a/src/operator/nn/dnnl/dnnl_power_scalar-inl.h 
b/src/operator/nn/dnnl/dnnl_power_scalar-inl.h
new file mode 100644
index 0000000000..eddbffffff
--- /dev/null
+++ b/src/operator/nn/dnnl/dnnl_power_scalar-inl.h
@@ -0,0 +1,61 @@
+/*
+ * 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 dnnl_power_scalar-inl.h
+ * \author: Adam Grabowski, [email protected]
+ */
+
+#ifndef MXNET_OPERATOR_NN_DNNL_DNNL_POWER_SCALAR_INL_H_
+#define MXNET_OPERATOR_NN_DNNL_DNNL_POWER_SCALAR_INL_H_
+
+#if MXNET_USE_ONEDNN == 1
+
+#include "dnnl_base-inl.h"
+#include "dnnl_ops-inl.h"
+#include "operator/tensor/elemwise_binary_scalar_op.h"
+
+namespace mxnet {
+namespace op {
+
+using eltwise_fwd_t    = dnnl::eltwise_forward;
+using eltwise_fwd_pd_t = dnnl::eltwise_forward::primitive_desc;
+
+class DNNLPowerFwd {
+ public:
+  static DNNLPowerFwd& GetPowerForward(const nnvm::NodeAttrs& attrs,
+                                       const NDArray& input,
+                                       const NDArray& outputs);
+
+  DNNLPowerFwd(const NDArray& input, const float exponent);
+
+  void Execute(const NDArray& input, const OpReqType& req, const NDArray& 
output);
+
+ private:
+  std::shared_ptr<eltwise_fwd_t> fwd;
+  std::shared_ptr<eltwise_fwd_pd_t> fwd_pd;
+};
+
+typedef OpSignature DNNLPowerSignature;
+
+}  // namespace op
+}  // namespace mxnet
+
+#endif  // MXNET_USE_ONEDNN == 1
+#endif  // MXNET_OPERATOR_NN_DNNL_DNNL_POWER_SCALAR_INL_H_
diff --git a/src/operator/nn/dnnl/dnnl_power_scalar.cc 
b/src/operator/nn/dnnl/dnnl_power_scalar.cc
new file mode 100644
index 0000000000..223ab21c1c
--- /dev/null
+++ b/src/operator/nn/dnnl/dnnl_power_scalar.cc
@@ -0,0 +1,94 @@
+/*
+ * 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 dnnl_power_scalar.cc
+ * \author: Adam Grabowski, [email protected]
+ */
+
+#if MXNET_USE_ONEDNN == 1
+
+#include "dnnl_power_scalar-inl.h"
+
+namespace mxnet {
+namespace op {
+
+DNNLPowerFwd& DNNLPowerFwd::GetPowerForward(const nnvm::NodeAttrs& attrs,
+                                            const NDArray& input,
+                                            const NDArray& output) {
+  const NumpyBinaryScalarParam& param = 
nnvm::get<NumpyBinaryScalarParam>(attrs.parsed);
+#if DMLC_CXX11_THREAD_LOCAL
+  static thread_local std::unordered_map<DNNLPowerSignature, DNNLPowerFwd, 
OpHash> fwds;
+#else
+  static MX_THREAD_LOCAL std::unordered_map<DNNLPowerSignature, DNNLPowerFwd, 
OpHash> fwds;
+#endif
+  DNNLPowerSignature key;
+  key.AddSign(static_cast<float>(param.scalar));
+  key.AddSign(input);
+  key.AddSign(output);
+
+  auto it = fwds.find(key);
+  if (it == fwds.end()) {
+    const DNNLPowerFwd fwd(input, static_cast<float>(param.scalar));
+    it = AddToCache(&fwds, key, fwd);
+  }
+  return it->second;
+}
+
+DNNLPowerFwd::DNNLPowerFwd(const NDArray& input, const float exponent) {
+  auto src_desc = input.GetDNNLData()->get_desc();
+  dnnl::eltwise_forward::desc fwd_desc(
+      dnnl::prop_kind::forward_scoring, dnnl::algorithm::eltwise_pow, 
src_desc, 1, exponent);
+  fwd_pd = std::make_shared<eltwise_fwd_pd_t>(fwd_desc, 
mxnet::CpuEngine::Get()->get_engine());
+  fwd    = std::make_shared<eltwise_fwd_t>(*fwd_pd);
+}
+
+void DNNLPowerFwd::Execute(const NDArray& input, const OpReqType& req, const 
NDArray& output) {
+  auto engine           = mxnet::CpuEngine::Get()->get_engine();
+  auto src              = input.GetDNNLData();
+  dnnl_output_t out_mem = CreateDNNLMem(output, fwd_pd->dst_desc(), req, 
&input);
+
+  dnnl_args_map_t args = {
+      {DNNL_ARG_SRC, *src},
+      {DNNL_ARG_DST, *out_mem.second},
+  };
+
+  DNNLStream::Get()->RegisterPrimArgs(*fwd, args);
+  CommitOutput(output, out_mem);
+  DNNLStream::Get()->Submit();
+}
+
+void DNNLPowerForward(const nnvm::NodeAttrs& attrs,
+                      const OpContext& ctx,
+                      const NDArray& input,
+                      const OpReqType& req,
+                      const NDArray& output) {
+  DNNLPowerFwd& fwd = DNNLPowerFwd::GetPowerForward(attrs, input, output);
+  fwd.Execute(input, req, output);
+}
+
+bool SupportDNNLPower(const NDArray& input) {
+  return input.shape().Size() != 0 && input.shape().ndim() > 0 && 
input.shape().ndim() <= 6 &&
+         input.dtype() == mshadow::kFloat32;
+}
+
+}  // namespace op
+}  // namespace mxnet
+
+#endif  // MXNET_USE_ONEDNN == 1
diff --git a/src/operator/numpy/np_elemwise_broadcast_op_scalar.cc 
b/src/operator/numpy/np_elemwise_broadcast_op_scalar.cc
index e4e61d1226..0e7cdaf3df 100644
--- a/src/operator/numpy/np_elemwise_broadcast_op_scalar.cc
+++ b/src/operator/numpy/np_elemwise_broadcast_op_scalar.cc
@@ -55,6 +55,10 @@ MXNET_OPERATOR_REGISTER_NP_BINARY_SCALAR(_npi_rmod_scalar)
 
 MXNET_OPERATOR_REGISTER_NP_BINARY_SCALAR(_npi_power_scalar)
     .set_attr<FCompute>("FCompute<cpu>", BinaryScalarOp::Compute<cpu, 
mshadow_op::power>)
+#if MXNET_USE_ONEDNN == 1
+    .set_attr<FComputeEx>("FComputeEx<cpu>", PowerComputeExCPU)
+    .set_attr<FInferStorageType>("FInferStorageType", PowerStorageType)
+#endif
     .set_attr<nnvm::FGradient>("FGradient", 
ElemwiseGradUseIn{"_backward_power_scalar"});
 
 MXNET_OPERATOR_REGISTER_NP_BINARY_SCALAR(_npi_rpower_scalar)
diff --git a/src/operator/tensor/elemwise_binary_scalar_op.h 
b/src/operator/tensor/elemwise_binary_scalar_op.h
index 8c025ef9ec..f18cc16c44 100644
--- a/src/operator/tensor/elemwise_binary_scalar_op.h
+++ b/src/operator/tensor/elemwise_binary_scalar_op.h
@@ -33,6 +33,9 @@
 #include "../elemwise_op_common.h"
 #include "../../common/alm.h"
 #include "elemwise_unary_op.h"
+#if MXNET_USE_ONEDNN == 1
+#include "operator/nn/dnnl/dnnl_power_scalar-inl.h"
+#endif
 
 namespace mxnet {
 namespace op {
@@ -441,6 +444,20 @@ class BinaryScalarOp : public UnaryOp {
   }
 };
 
+#if MXNET_USE_ONEDNN == 1
+bool PowerStorageType(const nnvm::NodeAttrs& attrs,
+                      const int dev_mask,
+                      DispatchMode* dispatch_mode,
+                      std::vector<int>* inputs,
+                      std::vector<int>* outputs);
+
+void PowerComputeExCPU(const nnvm::NodeAttrs& attrs,
+                       const OpContext& ctx,
+                       const std::vector<mxnet::NDArray>& inputs,
+                       const std::vector<OpReqType>& req,
+                       const std::vector<mxnet::NDArray>& outputs);
+#endif
+
 #define MXNET_OPERATOR_REGISTER_BINARY_SCALAR(name)                            
           \
   NNVM_REGISTER_OP(name)                                                       
           \
       .set_num_inputs(1)                                                       
           \
diff --git a/src/operator/tensor/elemwise_binary_scalar_op_extended.cc 
b/src/operator/tensor/elemwise_binary_scalar_op_extended.cc
index 3c4938074f..564951138a 100644
--- a/src/operator/tensor/elemwise_binary_scalar_op_extended.cc
+++ b/src/operator/tensor/elemwise_binary_scalar_op_extended.cc
@@ -49,8 +49,41 @@ MXNET_OPERATOR_REGISTER_BINARY(_backward_minimum_scalar)
     .set_attr_parser(ParamParser<NumpyBinaryScalarParam>)
     .set_attr<FCompute>("FCompute<cpu>", BinaryScalarOp::Backward<cpu, 
mshadow_op::le>);
 
+#if MXNET_USE_ONEDNN == 1
+bool PowerStorageType(const nnvm::NodeAttrs& attrs,
+                      const int dev_mask,
+                      DispatchMode* dispatch_mode,
+                      std::vector<int>* inputs,
+                      std::vector<int>* outputs) {
+  CHECK_EQ(inputs->size(), 1);
+  CHECK_EQ(outputs->size(), 1);
+
+  return DNNLStorageType(attrs, dev_mask, true, dispatch_mode, inputs, 
outputs);
+}
+
+void PowerComputeExCPU(const nnvm::NodeAttrs& attrs,
+                       const OpContext& ctx,
+                       const std::vector<mxnet::NDArray>& inputs,
+                       const std::vector<OpReqType>& req,
+                       const std::vector<mxnet::NDArray>& outputs) {
+  if (SupportDNNLPower(inputs[0])) {
+    DNNL_OPCHECK_INIT(false, outputs.size(), inputs, outputs);
+    DNNLRun(DNNLPowerForward, attrs, ctx, inputs[0], req[0], outputs[0]);
+    DNNL_OPCHECK_RUN(
+        (BinaryScalarOp::Compute<cpu, mshadow_op::power>), attrs, ctx, inputs, 
req, outputs);
+  } else {
+    FallBackCompute(
+        BinaryScalarOp::Compute<cpu, mshadow_op::power>, attrs, ctx, inputs, 
req, outputs);
+  }
+}
+#endif  // MXNET_USE_ONEDNN == 1
+
 MXNET_OPERATOR_REGISTER_BINARY_SCALAR(_power_scalar)
     .set_attr<FCompute>("FCompute<cpu>", BinaryScalarOp::Compute<cpu, 
mshadow_op::power>)
+#if MXNET_USE_ONEDNN == 1
+    .set_attr<FComputeEx>("FComputeEx<cpu>", PowerComputeExCPU)
+    .set_attr<FInferStorageType>("FInferStorageType", PowerStorageType)
+#endif
     .set_attr<nnvm::FGradient>("FGradient", 
ElemwiseGradUseIn{"_backward_power_scalar"})
     .add_alias("_PowerScalar");
 

Reply via email to