You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@mxnet.apache.org by zh...@apache.org on 2021/05/18 16:34:41 UTC

[incubator-mxnet] branch v1.x updated: [v1.x][FEATURE] Add MKLDNN Deconvolution 1D and 3D support (#20137)

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

zhasheng pushed a commit to branch v1.x
in repository https://gitbox.apache.org/repos/asf/incubator-mxnet.git


The following commit(s) were added to refs/heads/v1.x by this push:
     new b3b92c0  [v1.x][FEATURE] Add MKLDNN Deconvolution 1D and 3D support (#20137)
b3b92c0 is described below

commit b3b92c02d1b506ab163c7777e571b3c6dcb64a9e
Author: Paweł Głomski <pa...@intel.com>
AuthorDate: Tue May 18 18:32:23 2021 +0200

    [v1.x][FEATURE] Add MKLDNN Deconvolution 1D and 3D support (#20137)
---
 src/operator/nn/deconvolution-inl.h            |  6 +++++-
 src/operator/nn/deconvolution.cc               | 28 +++++++++++++++++---------
 src/operator/nn/mkldnn/mkldnn_deconvolution.cc |  7 ++++---
 tests/python/mkl/test_mkldnn.py                |  9 +++++++--
 4 files changed, 35 insertions(+), 15 deletions(-)

diff --git a/src/operator/nn/deconvolution-inl.h b/src/operator/nn/deconvolution-inl.h
index 0aac39a..9bb8d9e 100644
--- a/src/operator/nn/deconvolution-inl.h
+++ b/src/operator/nn/deconvolution-inl.h
@@ -220,7 +220,11 @@ class DeconvolutionOp {
     using namespace mshadow::expr;
 
     if (param_.kernel.ndim() > 2) {
-      LOG(FATAL) << "If not using CUDNN, only 1D or 2D Deconvolution is supported";
+      LOG(FATAL) << "Only 1D or 2D Deconvolution is natively supported. "
+                 << ((MXNET_USE_MKLDNN || MXNET_USE_CUDNN)
+                         ? "Fallback to native implementation (if occurred) is therefore "
+                           "impossible for 3D Deconvolution."
+                         : "");
     }
 
     CHECK_EQ(req[deconv::kOut], kWriteTo);
diff --git a/src/operator/nn/deconvolution.cc b/src/operator/nn/deconvolution.cc
index 08d6306..4604d2b 100644
--- a/src/operator/nn/deconvolution.cc
+++ b/src/operator/nn/deconvolution.cc
@@ -43,9 +43,14 @@ static void DeconvolutionComputeExCPU(const nnvm::NodeAttrs& attrs,
                                       const std::vector<NDArray>& outputs) {
   const DeconvolutionParam& params = nnvm::get<DeconvolutionParam>(attrs.parsed);
   if (SupportMKLDNNDeconv(params, inputs[0])) {
-    MKLDNN_OPCHECK_INIT(false, outputs.size(), inputs, outputs);
-    MKLDNNRun(MKLDNNDeconvolutionForward, attrs, ctx, inputs, req, outputs);
-    MKLDNN_OPCHECK_RUN(DeconvolutionCompute<cpu>, attrs, ctx, inputs, req, outputs);
+    if (params.kernel.ndim() == 3) {
+      // we cannot check the output, as 3D deconvolution is not natively supported yet
+      MKLDNNRun(MKLDNNDeconvolutionForward, attrs, ctx, inputs, req, outputs);
+    } else {
+      MKLDNN_OPCHECK_INIT(false, outputs.size(), inputs, outputs);
+      MKLDNNRun(MKLDNNDeconvolutionForward, attrs, ctx, inputs, req, outputs);
+      MKLDNN_OPCHECK_RUN(DeconvolutionCompute<cpu>, attrs, ctx, inputs, req, outputs);
+    }
     return;
   }
   FallBackCompute(DeconvolutionCompute<cpu>, attrs, ctx, inputs, req, outputs);
@@ -58,9 +63,14 @@ static void DeconvolutionGradComputeExCPU(const nnvm::NodeAttrs& attrs,
                                           const std::vector<NDArray>& outputs) {
   const DeconvolutionParam& params = nnvm::get<DeconvolutionParam>(attrs.parsed);
   if (SupportMKLDNNDeconv(params, inputs[0])) {
-    MKLDNN_OPCHECK_INIT(true, outputs.size(), inputs, outputs);
-    MKLDNNRun(MKLDNNDeconvolutionBackward, attrs, ctx, inputs, req, outputs);
-    MKLDNN_OPCHECK_RUN(DeconvolutionGradCompute<cpu>, attrs, ctx, inputs, req, outputs);
+    if (params.kernel.ndim() == 3) {
+      // we cannot check the output, as 3D deconvolution is not natively supported yet
+      MKLDNNRun(MKLDNNDeconvolutionBackward, attrs, ctx, inputs, req, outputs);
+    } else {
+      MKLDNN_OPCHECK_INIT(true, outputs.size(), inputs, outputs);
+      MKLDNNRun(MKLDNNDeconvolutionBackward, attrs, ctx, inputs, req, outputs);
+      MKLDNN_OPCHECK_RUN(DeconvolutionGradCompute<cpu>, attrs, ctx, inputs, req, outputs);
+    }
     return;
   }
   FallBackCompute(DeconvolutionGradCompute<cpu>, attrs, ctx, inputs, req, outputs);
@@ -100,12 +110,12 @@ static bool DeconvolutionShape(const nnvm::NodeAttrs& attrs,
                                mxnet::ShapeVector *in_shape,
                                mxnet::ShapeVector *out_shape) {
   const DeconvolutionParam& param_ = nnvm::get<DeconvolutionParam>(attrs.parsed);
-#if MXNET_USE_CUDNN == 0
+#if MXNET_USE_CUDNN == 0 && MXNET_USE_MKLDNN == 0
   if (param_.kernel.ndim() > 2) {
-    LOG(FATAL) << "If not using CUDNN, only 1D or 2D Deconvolution is supported";
+    LOG(FATAL) << "If not using CUDNN or MKLDNN, only 1D or 2D Deconvolution is supported";
     return false;
   }
-#endif  // CUDNN
+#endif
 
   using namespace mshadow;
   if (!param_.no_bias) {
diff --git a/src/operator/nn/mkldnn/mkldnn_deconvolution.cc b/src/operator/nn/mkldnn/mkldnn_deconvolution.cc
index 7678567..2160815 100644
--- a/src/operator/nn/mkldnn/mkldnn_deconvolution.cc
+++ b/src/operator/nn/mkldnn/mkldnn_deconvolution.cc
@@ -29,7 +29,8 @@ namespace mxnet {
 namespace op {
 
 bool SupportMKLDNNDeconv(const DeconvolutionParam &params, const NDArray &input) {
-  return params.kernel.ndim() == 2 && input.shape().ndim() == 4 &&
+  return params.kernel.ndim() >= 1 && params.kernel.ndim() <= 3 &&
+         input.shape().ndim() == (params.kernel.ndim() + 2) &&
          (input.dtype() == mshadow::kFloat32 || input.dtype() == mshadow::kBfloat16);
 }
 
@@ -322,10 +323,10 @@ DeconvDescCreator::DeconvDescCreator(const DeconvolutionParam &param, const NDAr
       strides(param.stride.ndim()),
       padding(param.pad.ndim()),
       dilates(param.dilate.ndim()) {
-  // assuming only deconv2D is supported for now
   CHECK_EQ(param.stride.ndim(), param.pad.ndim());
   CHECK_EQ(param.stride.ndim(), param.dilate.ndim());
-  CHECK_EQ(param.stride.ndim(), 2);
+  CHECK_GE(param.stride.ndim(), 1);
+  CHECK_LE(param.stride.ndim(), 3);
   for (int i = 0; i < param.stride.ndim(); ++i) {
     strides[i] = param.stride[i];
     padding[i] = param.pad[i];
diff --git a/tests/python/mkl/test_mkldnn.py b/tests/python/mkl/test_mkldnn.py
index de0c249..061cc18 100644
--- a/tests/python/mkl/test_mkldnn.py
+++ b/tests/python/mkl/test_mkldnn.py
@@ -471,8 +471,8 @@ def test_convolution():
 @with_seed()
 def test_Deconvolution():
     def check_Deconvolution_training(stype):
-        for shape in [(3, 3, 10, 10)]: # testing only 2D for now
-            data_tmp = np.random.randint(256, size=shape)
+        for shape in [(3, 3, 10), (3, 3, 10, 10), (3, 3, 10, 10, 10)]:
+            data_tmp = np.random.normal(-0.1, 1, size=shape)
             data = mx.symbol.Variable('data', stype=stype)
 
             if np.array(shape).shape[0] == 3:
@@ -481,6 +481,11 @@ def test_Deconvolution():
             elif np.array(shape).shape[0] == 4:
                 test = mx.symbol.Deconvolution(data=data, kernel=(3, 3), stride=(2, 2), num_filter=4)
                 weight_tmp = np.random.normal(-0.1, 0.1, size=(3, 4, 3, 3))
+            elif np.array(shape).shape[0] == 5 and stype == "default":
+                # Unable to test fallback to native implementation for non-default storage types
+                # as 3D deconvolution is not natively supported
+                test = mx.symbol.Deconvolution(data=data, kernel=(3,3,3), stride=(2,2,2), num_filter=4)
+                weight_tmp = np.random.normal(-0.1, 0.1, size=(3, 4, 3, 3, 3))
             else:
                 return 0
             bias_tmp = np.random.normal(0.1, 0.1, size=(4,))