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 4efbbf5  [MXNET-176] Support axis=None for sum operator (#10405)
4efbbf5 is described below

commit 4efbbf5b281f26e9fd80db132012c83b135ce3a7
Author: Haibin Lin <linhaibin.e...@gmail.com>
AuthorDate: Fri Apr 6 10:41:59 2018 -0700

    [MXNET-176] Support axis=None for sum operator (#10405)
    
    * initial commit
    
    * add doc
    
    * update nnvm
    
    * fix squeeze param
    
    * fix gpu compliation
---
 3rdparty/nnvm                                    |  2 +-
 cpp-package/scripts/OpWrapperGenerator.py        |  1 +
 src/operator/tensor/broadcast_reduce_op.h        | 60 ++++++++++---------
 src/operator/tensor/broadcast_reduce_op_value.cc |  4 +-
 src/operator/tensor/broadcast_reduce_op_value.cu |  3 +-
 src/operator/tensor/matrix_op.cc                 |  2 +-
 src/operator/tensor/square_sum-inl.h             | 30 ++++++----
 tests/python/unittest/test_operator.py           | 75 +++++++++++++-----------
 8 files changed, 96 insertions(+), 81 deletions(-)

diff --git a/3rdparty/nnvm b/3rdparty/nnvm
index c342da7..2bc5144 160000
--- a/3rdparty/nnvm
+++ b/3rdparty/nnvm
@@ -1 +1 @@
-Subproject commit c342da72271c85e477480323f1d91997c6101ac0
+Subproject commit 2bc5144cd3733fd239287e3560c7db8285d21f02
diff --git a/cpp-package/scripts/OpWrapperGenerator.py 
b/cpp-package/scripts/OpWrapperGenerator.py
index ac95773..0c000d9 100644
--- a/cpp-package/scripts/OpWrapperGenerator.py
+++ b/cpp-package/scripts/OpWrapperGenerator.py
@@ -94,6 +94,7 @@ class Arg:
         'int or None':'dmlc::optional<int>',\
         'long':'int64_t',\
         'double':'double',\
+        'Shape or None':'dmlc::optional<Shape>',\
         'string':'const std::string&'}
     name = ''
     type = ''
diff --git a/src/operator/tensor/broadcast_reduce_op.h 
b/src/operator/tensor/broadcast_reduce_op.h
index 2f6864b..1d4ef0a 100644
--- a/src/operator/tensor/broadcast_reduce_op.h
+++ b/src/operator/tensor/broadcast_reduce_op.h
@@ -37,11 +37,11 @@
 namespace mxnet {
 namespace op {
 struct ReduceAxesParam : public dmlc::Parameter<ReduceAxesParam> {
-  TShape axis;
+  dmlc::optional<TShape> axis;
   bool keepdims;
   bool exclude;
   DMLC_DECLARE_PARAMETER(ReduceAxesParam) {
-    DMLC_DECLARE_FIELD(axis).set_default(TShape())
+    DMLC_DECLARE_FIELD(axis).set_default(dmlc::optional<TShape>())
       .describe(R"code(The axis or axes along which to perform the reduction.
 
       The default, `axis=()`, will compute over all elements into a
@@ -66,12 +66,12 @@ struct ReduceAxesParam : public 
dmlc::Parameter<ReduceAxesParam> {
 
 struct NormParam : public dmlc::Parameter<NormParam> {
   int ord;
-  TShape axis;
+  dmlc::optional<TShape> axis;
   bool keepdims;
   DMLC_DECLARE_PARAMETER(NormParam) {
     DMLC_DECLARE_FIELD(ord).set_default(2)
       .describe("Order of the norm. Currently ord=2 is supported.");
-    DMLC_DECLARE_FIELD(axis).set_default(TShape())
+    DMLC_DECLARE_FIELD(axis).set_default(dmlc::optional<TShape>())
       .describe(R"code(The axis or axes along which to perform the reduction.
       The default, `axis=()`, will compute over all elements into a
       scalar array with shape `(1,)`.
@@ -198,17 +198,18 @@ inline bool ReduceAxisShape(const nnvm::NodeAttrs& attrs,
   return true;
 }
 
-inline TShape ReduceAxesShapeImpl(const TShape& ishape, const TShape& axis,
+inline TShape ReduceAxesShapeImpl(const TShape& ishape, const 
dmlc::optional<TShape>& axis,
                                   bool keepdims, bool exclude) {
-  if (axis.ndim() == 0) {
+  // if axis doesn't have value, treat it same TShape().
+  if (!axis.has_value() || axis.value().ndim() == 0) {
     if (keepdims) {
       return TShape(ishape.ndim());
     } else {
       return TShape(1);
     }
   }
-
-  TShape axes(axis);
+  // axis has value
+  TShape axes(axis.value());
   for (index_t i = 0; i < axes.ndim(); i++) {
     if (axes[i] < 0) {
       axes[i] += ishape.ndim();
@@ -225,7 +226,7 @@ inline TShape ReduceAxesShapeImpl(const TShape& ishape, 
const TShape& axis,
     << "Reduction axis " << axes[axes.ndim()-1]
     << " Exceeds input dimensions " << ishape;
   CHECK_GE(axes[0], 0)
-    << "Reduction axis " << axis
+    << "Reduction axis " << axis.value()
     << " Exceeds input dimensions " << ishape;
 
   TShape oshape;
@@ -373,11 +374,12 @@ inline void BroadcastReduceShapeCompact(const TShape& 
big, const TShape& small,
   }
 }
 
-inline bool SumOpForwardInferStorageType(const nnvm::NodeAttrs& attrs,
-                                         const int dev_mask,
-                                         DispatchMode* dispatch_mode,
-                                         std::vector<int>* in_attrs,
-                                         std::vector<int>* out_attrs) {
+// infer storage function for sum(csr) and mean(csr)
+inline bool ReduceAxesOpForwardStorage(const nnvm::NodeAttrs& attrs,
+                                       const int dev_mask,
+                                       DispatchMode* dispatch_mode,
+                                       std::vector<int>* in_attrs,
+                                       std::vector<int>* out_attrs) {
   CHECK_EQ(in_attrs->size(), 1U);
   CHECK_EQ(out_attrs->size(), 1U);
   const ReduceAxesParam& param = nnvm::get<ReduceAxesParam>(attrs.parsed);
@@ -389,15 +391,14 @@ inline bool SumOpForwardInferStorageType(const 
nnvm::NodeAttrs& attrs,
   const auto dispatch_ex =
       invalid_ctx ? DispatchMode::kFComputeFallback : 
DispatchMode::kFComputeEx;
   if (!dispatched && in_stype == kDefaultStorage) {
-    // When input is dense output storage is set as  dense and dispatched to
+    // When input is dense output storage is set as dense and dispatched to
     // dense operator
     dispatched = storage_type_assign(&out_stype, kDefaultStorage, 
dispatch_mode,
                                      DispatchMode::kFCompute);
   }
-
-  if (!dispatched && in_stype == kCSRStorage && param.axis.ndim() == 1 &&
-      (param.axis[0] == 0 || param.axis[0] == 1) && !param.keepdims &&
-      !param.exclude) {
+  TShape axis = param.axis.has_value() ? param.axis.value() : TShape();
+  if (!dispatched && in_stype == kCSRStorage && axis.ndim() == 1 &&
+      (axis[0] == 0 || axis[0] == 1) && !param.keepdims && !param.exclude) {
     // If input is csr and axis is 0 or 1, and neither of keepdims or exclude
     // are set, dipsatch to sparse operator and output storage is set as dense
     dispatched = storage_type_assign(&out_stype, kDefaultStorage, 
dispatch_mode,
@@ -695,12 +696,14 @@ template <typename xpu, typename red_op, bool normalize = 
false>
 void ReduceCsr(const nnvm::NodeAttrs& attrs, mshadow::Stream<xpu>* s, const 
OpContext& ctx,
                const NDArray& input, const OpReqType req, NDArray* output) {
   const ReduceAxesParam& param = nnvm::get<ReduceAxesParam>(attrs.parsed);
-  CHECK_EQ(param.axis.ndim(), 1U) << "sum(csr)/mean(csr) only supports axis 0 
or 1";
-  CHECK(param.axis[0] == 0 || param.axis[0] == 1)
-      << "sum(csr)/mean(csr) only support axis 0 or 1";
+  CHECK(param.axis.has_value());
+  const TShape axis = param.axis.value();
+  CHECK_EQ(axis.ndim(), 1U) << "sum(csr)/mean(csr) only supports axis 0 or 1";
+  CHECK(axis[0] == 0 || axis[0] == 1)
+     << "sum(csr)/mean(csr) only support axis 0 or 1";
   CHECK(!param.keepdims) << "keepdims not supported for sparse";
   CHECK(!param.exclude) << "exclude not supported for sparse";
-  ReduceCsrImpl<xpu, red_op, normalize>(s, ctx, input, req, output, 
param.axis);
+  ReduceCsrImpl<xpu, red_op, normalize>(s, ctx, input, req, output, axis);
 }
 
 template <typename xpu, typename reducer, bool normalize = false>
@@ -1039,20 +1042,19 @@ void L2NormComputeEx(const nnvm::NodeAttrs& attrs,
   CHECK_EQ(param.ord, 2) << "norm only support ord=2";
   mshadow::Stream<xpu>* s = ctx.get_stream<xpu>();
   const NDArrayStorageType istype = inputs[0].storage_type();
-  if ((istype == kRowSparseStorage || istype == kCSRStorage)
-      && param.axis.ndim() == 0) {
+  const TShape axis = param.axis.has_value() ? param.axis.value() : TShape();
+  if ((istype == kRowSparseStorage || istype == kCSRStorage) && axis.ndim() == 
0) {
     // We only support norm on the entire array for now.
     L2NormComputeSparseImpl<xpu>(s, inputs[0], req[0], outputs[0].data());
-
   } else if (istype == kCSRStorage) {
     CHECK_EQ(inputs[0].shape().ndim(), 2U)
         << "norm(csr) op only supports 2D ndarray as input";
-    CHECK_EQ(param.axis.ndim(), 1U) << "sum(csr)/mean(csr) only supports axis 
0 or 1";
-    CHECK(param.axis[0] == 0 || param.axis[0] == 1)
+    CHECK_EQ(axis.ndim(), 1U) << "sum(csr)/mean(csr) only supports axis 0 or 
1";
+    CHECK(axis[0] == 0 || axis[0] == 1)
         << "sum(csr)/mean(csr) only support axis 0 or 1";
     CHECK(!param.keepdims) << "keepdims not supported for sparse";
     NDArray output = outputs[0];
-    ReduceCsrImpl<xpu, sq_sum, false>(s, ctx, inputs[0], req[0], &output, 
param.axis);
+    ReduceCsrImpl<xpu, sq_sum, false>(s, ctx, inputs[0], req[0], &output, 
axis);
     CHECK_EQ(outputs[0].storage_type(), kDefaultStorage);
     SqRootForL2<xpu>(ctx, req[0], outputs[0].data());
   } else {
diff --git a/src/operator/tensor/broadcast_reduce_op_value.cc 
b/src/operator/tensor/broadcast_reduce_op_value.cc
index da1d035..5f433cc 100644
--- a/src/operator/tensor/broadcast_reduce_op_value.cc
+++ b/src/operator/tensor/broadcast_reduce_op_value.cc
@@ -86,7 +86,7 @@ Example::
 )code" ADD_FILELINE)
 .set_attr<FCompute>("FCompute<cpu>", ReduceAxesCompute<cpu, mshadow::red::sum>)
 .set_attr<FComputeEx>("FComputeEx<cpu>", SumOpForwardEx<cpu, 
mshadow::red::sum>)
-.set_attr<FInferStorageType>("FInferStorageType", SumOpForwardInferStorageType)
+.set_attr<FInferStorageType>("FInferStorageType", ReduceAxesOpForwardStorage)
 .set_attr<FResourceRequest>("FResourceRequest",
   [](const NodeAttrs& attrs) {
     return std::vector<ResourceRequest>{ResourceRequest::kTempSpace};
@@ -102,7 +102,7 @@ MXNET_ADD_SPARSE_OP_ALIAS(mean)
 .describe(get_reduce_axes_description("mean", __LINE__))
 .set_attr<FCompute>("FCompute<cpu>", ReduceAxesCompute<cpu, mshadow::red::sum, 
true>)
 .set_attr<FComputeEx>("FComputeEx<cpu>", SumOpForwardEx<cpu, 
mshadow::red::sum, true>)
-.set_attr<FInferStorageType>("FInferStorageType", SumOpForwardInferStorageType)
+.set_attr<FInferStorageType>("FInferStorageType", ReduceAxesOpForwardStorage)
 .set_attr<FResourceRequest>("FResourceRequest",
   [](const NodeAttrs& attrs) {
     return std::vector<ResourceRequest>{ResourceRequest::kTempSpace};
diff --git a/src/operator/tensor/broadcast_reduce_op_value.cu 
b/src/operator/tensor/broadcast_reduce_op_value.cu
index dfff359..f1b19b4 100644
--- a/src/operator/tensor/broadcast_reduce_op_value.cu
+++ b/src/operator/tensor/broadcast_reduce_op_value.cu
@@ -39,9 +39,10 @@ void L2NormComputeEx<gpu>(const nnvm::NodeAttrs& attrs,
   mshadow::Stream<gpu>* s = ctx.get_stream<gpu>();
   const ReduceAxesParam& param = nnvm::get<ReduceAxesParam>(attrs.parsed);
   const NDArrayStorageType in_stype = inputs[0].storage_type();
+  nnvm::TShape axis = param.axis.has_value() ? param.axis.value() : TShape();
   // CSR and RowSparse only works on the entire array.
   if ((in_stype == kCSRStorage || in_stype == kRowSparseStorage)
-      && param.axis.ndim() == 0) {
+      && axis.ndim() == 0) {
     L2NormComputeSparseImpl(s, inputs[0], req[0], outputs[0].data());
   } else {
     LogUnimplementedOp(attrs, ctx, inputs, req, outputs);
diff --git a/src/operator/tensor/matrix_op.cc b/src/operator/tensor/matrix_op.cc
index d751ca1..9037827 100644
--- a/src/operator/tensor/matrix_op.cc
+++ b/src/operator/tensor/matrix_op.cc
@@ -824,7 +824,7 @@ Examples::
 .set_attr<FCompute>("FCompute<cpu>", UnaryOp::IdentityCompute<cpu>)
 .set_attr<nnvm::FGradient>("FGradient", 
ElemwiseGradUseNone{"_backward_squeeze"})
 .add_argument("data", "NDArray-or-Symbol[]", "data to squeeze")
-.add_arguments(StackParam::__FIELDS__());
+.add_arguments(SqueezeParam::__FIELDS__());
 
 NNVM_REGISTER_OP(_backward_squeeze)
 .set_num_inputs(1)
diff --git a/src/operator/tensor/square_sum-inl.h 
b/src/operator/tensor/square_sum-inl.h
index 0067ae1..162b3c8 100644
--- a/src/operator/tensor/square_sum-inl.h
+++ b/src/operator/tensor/square_sum-inl.h
@@ -53,13 +53,15 @@ inline bool SquareSumForwardInferStorageType(const 
nnvm::NodeAttrs& attrs,
   const auto& in_stype = in_attrs->at(0);
   auto& out_stype = out_attrs->at(0);
   bool dispatched = false;
-  if (!dispatched && in_stype == kRowSparseStorage && param.axis[0] == 1 && 
param.keepdims) {
+  const TShape axis = param.axis.has_value() ? param.axis.value() : TShape();
+  if (!dispatched && in_stype == kRowSparseStorage &&
+      axis.ndim() > 0 && axis[0] == 1 && param.keepdims) {
     // sum per row and keep dims
     dispatched = storage_type_assign(&out_stype, kRowSparseStorage,
                                      dispatch_mode, DispatchMode::kFComputeEx);
   }
-  if (!dispatched && in_stype == kRowSparseStorage &&
-      (param.axis[0] == 0 || (param.axis[0] == 1 && !param.keepdims))) {
+  if (!dispatched && in_stype == kRowSparseStorage && axis.ndim() > 0 &&
+      (axis[0] == 0 || (axis[0] == 1 && !param.keepdims))) {
       dispatched = storage_type_assign(&out_stype, kDefaultStorage,
                                        dispatch_mode, 
DispatchMode::kFComputeEx);
   }
@@ -264,13 +266,15 @@ void SquareSumRspImpl(const nnvm::NodeAttrs& attrs,
                       NDArray* output) {
   if (req == kNullOp) return;
   const ReduceAxesParam& param = nnvm::get<ReduceAxesParam>(attrs.parsed);
-  CHECK_EQ(param.axis.ndim(), 1U) << "_square_sum(row_sparse_matrix) only 
supports axis=0 or 1";
-  CHECK(param.axis[0] == 0 || param.axis[0] == 1)
+  CHECK(param.axis.has_value());
+  const TShape axis = param.axis.value();
+  CHECK_EQ(axis.ndim(), 1U) << "_square_sum(row_sparse_matrix) only supports 
axis=0 or 1";
+  CHECK(axis[0] == 0 || axis[0] == 1)
     << "_square_sum(row_sparse_matrix) only supports axis=0 or 1";
   CHECK_EQ(input.storage_type(), kRowSparseStorage)
     << "_square_sum op only supports row-sparse matrix as input";
   int64_t out_data_size = 0;
-  if (param.axis[0] == 0) {  // axis = 0
+  if (axis[0] == 0) {  // axis = 0
     CHECK_EQ(output->storage_type(), kDefaultStorage);
     out_data_size = input.storage_shape()[1];
   } else if (param.keepdims) {  // axis = 1, keepdims = true
@@ -305,7 +309,7 @@ void SquareSumRspImpl(const nnvm::NodeAttrs& attrs,
   const int64_t nnr = input.storage_shape()[0];
   const int64_t num_cols = input.storage_shape()[1];
   const TBlob& in_data = input.data();
-  if (0 == param.axis[0]) {  // axis = 0, output is dense
+  if (0 == axis[0]) {  // axis = 0, output is dense
     MSHADOW_TYPE_SWITCH(out_data.type_flag_, DType, {
       MXNET_ASSIGN_REQ_SWITCH(req, req_type, {
         Kernel<SquareSumRspKernel<req_type, 0, false>, xpu>::Launch(s, 
num_cols,
@@ -377,8 +381,10 @@ void SquareSumRspGradImpl(const nnvm::NodeAttrs& attrs,
                           NDArray* igrad) {
   if (req == kNullOp) return;
   const ReduceAxesParam& param = nnvm::get<ReduceAxesParam>(attrs.parsed);
-  CHECK_EQ(param.axis.ndim(), 1U) << "_square_sum(row_sparse_matrix) only 
supports axis=0/1";
-  CHECK(param.axis[0] == 0 || param.axis[0] == 1)
+  CHECK(param.axis.has_value());
+  const TShape axis = param.axis.value();
+  CHECK_EQ(axis.ndim(), 1U) << "_square_sum(row_sparse_matrix) only supports 
axis=0/1";
+  CHECK(axis[0] == 0 || axis[0] == 1)
     << "_square_sum(row_sparse_matrix) only supports axis=0 or 1";
   CHECK(ograd.storage_type() == kDefaultStorage || ograd.storage_type() == 
kRowSparseStorage);
   CHECK_EQ(input.storage_type(), kRowSparseStorage);
@@ -400,7 +406,7 @@ void SquareSumRspGradImpl(const nnvm::NodeAttrs& attrs,
     igrad->CheckAndAlloc({input.aux_shape(rowsparse::kIdx)});
     const TBlob& igrad_data = igrad->data();
     const TBlob igrad_row_idx = igrad->aux_data(rowsparse::kIdx);
-    if (0 == param.axis[0]) {  // forward is sum per column
+    if (0 == axis[0]) {  // forward is sum per column
       MSHADOW_TYPE_SWITCH(igrad_data.type_flag_, DType, {
         MSHADOW_IDX_TYPE_SWITCH(igrad_row_idx.type_flag_, IType, {
           MXNET_ASSIGN_REQ_SWITCH(req, req_type, {
@@ -424,8 +430,8 @@ void SquareSumRspGradImpl(const nnvm::NodeAttrs& attrs,
       })
     }
   } else if (ograd.storage_type() == kRowSparseStorage) {
-    CHECK_EQ(1, param.axis[0]) << "SquareSumRspGradImpl only supports axis = 1"
-                                   " when ograd_stype = kRowSparseStorage";
+    CHECK_EQ(1, axis[0]) << "SquareSumRspGradImpl only supports axis = 1"
+                            " when ograd_stype = kRowSparseStorage";
     CHECK_EQ(ograd.shape().ndim(), 2U);
     const TBlob ograd_row_idx = ograd.aux_data(rowsparse::kIdx);
     CHECK(ograd_row_idx.Size() == in_row_idx.Size() || in_row_idx.Size() == 
in_data.shape_[0]);
diff --git a/tests/python/unittest/test_operator.py 
b/tests/python/unittest/test_operator.py
index 629304d..61b4478 100644
--- a/tests/python/unittest/test_operator.py
+++ b/tests/python/unittest/test_operator.py
@@ -1737,8 +1737,8 @@ def test_reshape():
 @with_seed()
 def test_reduce():
     sample_num = 500
-    def test_reduce_inner(numpy_reduce_func, numpy_reduce_grad_func, 
mx_reduce_sym, nan_prob = 0,
-                          test_exclude = True):
+    def test_reduce_inner(numpy_reduce_func, numpy_reduce_grad_func, 
mx_reduce_sym, nan_prob=0,
+                          test_exclude=True, test_none_axis=False):
         for i in range(sample_num):
             # Generate random data that has ndim between 1-7 and all the shape 
dims between 1-5
             # Insert a NaN with probability equal to nan_prob
@@ -1763,7 +1763,10 @@ def test_reduce():
             keepdims = np.random.randint(0, 2)
             a = mx.symbol.Variable('a')
             if axes is None:
-                b = mx_reduce_sym(a, keepdims=keepdims)
+                if test_none_axis:
+                    b = mx_reduce_sym(a, keepdims=keepdims, axis=axes)
+                else:
+                    b = mx_reduce_sym(a, keepdims=keepdims)
             elif exclude and isinstance(axes, tuple) and len(axes) < ndim:
                 naxes = [i for i in range(ndim) if i not in axes]
                 b = mx_reduce_sym(a, axis=naxes, keepdims=keepdims, 
exclude=True)
@@ -1795,38 +1798,40 @@ def test_reduce():
             equal_backward = almost_equal_ignore_nan(grad_nd.asnumpy(), 
bc_grad_groundtruth, 1E-4, 1E-4)
             assert equal_backward
 
-    test_reduce_inner(lambda data, axis, keepdims:np_reduce(data, axis, 
keepdims, np.sum),
-                      lambda outgrad, data, outdata, axis, keepdims, 
keepdim_shape:
-                        outgrad.reshape(keepdim_shape),
-                      mx.symbol.sum)
-    test_reduce_inner(lambda data, axis, keepdims:np_reduce(data, axis, 
keepdims, np.mean),
-                      lambda outgrad, data, outdata, axis, keepdims, 
keepdim_shape:
-                        
outgrad.reshape(keepdim_shape)/(data.size/outdata.size),
-                      mx.symbol.mean)
-    test_reduce_inner(lambda data, axis, keepdims:np_reduce(data, axis, 
keepdims, np.prod),
-                      lambda outgrad, data, outdata, axis, keepdims, 
keepdim_shape:
-                        outgrad.reshape(keepdim_shape) * 
(outdata.reshape(keepdim_shape) / data),
-                      mx.symbol.prod)
-    test_reduce_inner(lambda data, axis, keepdims:np_reduce(data, axis, 
keepdims, np.nansum),
-                      lambda outgrad, data, outdata, axis, keepdims, 
keepdim_shape:
-                        np.where(np.isnan(data), 0, 
outgrad.reshape(keepdim_shape)),
-                      mx.symbol.nansum, 0.3)
-    test_reduce_inner(lambda data, axis, keepdims:np_reduce(data, axis, 
keepdims, np.nanprod),
-                      lambda outgrad, data, outdata, axis, keepdims, 
keepdim_shape:
-                        np.where(np.isnan(data), 0, 
outgrad.reshape(keepdim_shape) * (outdata.reshape(keepdim_shape) / data)),
-                      mx.symbol.nanprod, 0.3)
-    test_reduce_inner(lambda data, axis, keepdims:np_reduce(data, axis, 
keepdims, np.max),
-                      lambda outgrad, data, outdata, axis, keepdims, 
keepdim_shape:
-                        outgrad.reshape(keepdim_shape) * (np.equal(data, 
outdata.reshape(keepdim_shape)).astype(np.float)),
-                      mx.symbol.max)
-    test_reduce_inner(lambda data, axis, keepdims:np_reduce(data, axis, 
keepdims, np.min),
-                      lambda outgrad, data, outdata, axis, keepdims, 
keepdim_shape:
-                        outgrad.reshape(keepdim_shape) * (np.equal(data, 
outdata.reshape(keepdim_shape)).astype(np.float)),
-                      mx.symbol.min)
-    test_reduce_inner(lambda data, axis, keepdims:np_reduce(data, axis, 
keepdims, np.linalg.norm),
-                      lambda outgrad, data, outdata, axis, keepdims, 
keepdim_shape:
-                        outgrad.reshape(keepdim_shape) * (data / 
outdata.reshape(keepdim_shape)),
-                      mx.symbol.norm, test_exclude=False)
+    test_none_axis = [True, False]
+    for test_none in test_none_axis:
+      test_reduce_inner(lambda data, axis, keepdims:np_reduce(data, axis, 
keepdims, np.sum),
+                        lambda outgrad, data, outdata, axis, keepdims, 
keepdim_shape:
+                          outgrad.reshape(keepdim_shape),
+                        mx.symbol.sum, test_none_axis=test_none)
+      test_reduce_inner(lambda data, axis, keepdims:np_reduce(data, axis, 
keepdims, np.mean),
+                        lambda outgrad, data, outdata, axis, keepdims, 
keepdim_shape:
+                          
outgrad.reshape(keepdim_shape)/(data.size/outdata.size),
+                        mx.symbol.mean, test_none_axis=test_none)
+      test_reduce_inner(lambda data, axis, keepdims:np_reduce(data, axis, 
keepdims, np.prod),
+                        lambda outgrad, data, outdata, axis, keepdims, 
keepdim_shape:
+                          outgrad.reshape(keepdim_shape) * 
(outdata.reshape(keepdim_shape) / data),
+                        mx.symbol.prod, test_none_axis=test_none)
+      test_reduce_inner(lambda data, axis, keepdims:np_reduce(data, axis, 
keepdims, np.nansum),
+                        lambda outgrad, data, outdata, axis, keepdims, 
keepdim_shape:
+                          np.where(np.isnan(data), 0, 
outgrad.reshape(keepdim_shape)),
+                        mx.symbol.nansum, 0.3, test_none_axis=test_none)
+      test_reduce_inner(lambda data, axis, keepdims:np_reduce(data, axis, 
keepdims, np.nanprod),
+                        lambda outgrad, data, outdata, axis, keepdims, 
keepdim_shape:
+                          np.where(np.isnan(data), 0, 
outgrad.reshape(keepdim_shape) * (outdata.reshape(keepdim_shape) / data)),
+                        mx.symbol.nanprod, 0.3, test_none_axis=test_none)
+      test_reduce_inner(lambda data, axis, keepdims:np_reduce(data, axis, 
keepdims, np.max),
+                        lambda outgrad, data, outdata, axis, keepdims, 
keepdim_shape:
+                          outgrad.reshape(keepdim_shape) * (np.equal(data, 
outdata.reshape(keepdim_shape)).astype(np.float)),
+                        mx.symbol.max, test_none_axis=test_none)
+      test_reduce_inner(lambda data, axis, keepdims:np_reduce(data, axis, 
keepdims, np.min),
+                        lambda outgrad, data, outdata, axis, keepdims, 
keepdim_shape:
+                          outgrad.reshape(keepdim_shape) * (np.equal(data, 
outdata.reshape(keepdim_shape)).astype(np.float)),
+                        mx.symbol.min, test_none_axis=test_none)
+      test_reduce_inner(lambda data, axis, keepdims:np_reduce(data, axis, 
keepdims, np.linalg.norm),
+                        lambda outgrad, data, outdata, axis, keepdims, 
keepdim_shape:
+                          outgrad.reshape(keepdim_shape) * (data / 
outdata.reshape(keepdim_shape)),
+                        mx.symbol.norm, test_exclude=False, 
test_none_axis=test_none)
 
 
 @with_seed()

-- 
To stop receiving notification emails like this one, please contact
j...@apache.org.

Reply via email to