This is an automated email from the ASF dual-hosted git repository. cjolivier01 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 52d809c Fix for issue #8491, elemwise_mul nan behavior (#8492) 52d809c is described below commit 52d809c9288e70927534dc783c439dfd65df7de7 Author: Chris Olivier <cjolivie...@gmail.com> AuthorDate: Fri Nov 3 20:29:06 2017 -0700 Fix for issue #8491, elemwise_mul nan behavior (#8492) * Fix for issue #8491, elemwise_mul nan behavior https://github.com/apache/incubator-mxnet/issues/8491 * Also make nan * 0 -> dense * Also make nan * 0 -> dense * Add Scala package dev tools for deploy (#8498) * [scala] do not print op definition during compiling by default * [scala] add dev tools for changing artifactId * [scala] add scala make clean * Getting read of maybe_uninitialized warnings (#8318) * Fix of log10_grad, log2_grad (#8502) * add default hash to ndarray (#8476) * bump up version (#8488) * fix makenonlossgrad bug (#8508) * fix expand_dims if axis< 0 (#8489) * fix expand_dims if axis< 0 * Update test_operator.py * Correct Initialization Description in Finetune Tutorial. (#8517) * Trigger rebuild --- src/operator/tensor/elemwise_binary_op.cc | 45 ------------------------ src/operator/tensor/elemwise_binary_op.h | 46 ++++++++++++++++++++++++- src/operator/tensor/elemwise_binary_op_basic.cc | 7 ++-- tests/python/unittest/test_sparse_operator.py | 11 ++++-- 4 files changed, 57 insertions(+), 52 deletions(-) diff --git a/src/operator/tensor/elemwise_binary_op.cc b/src/operator/tensor/elemwise_binary_op.cc index 00c5e10..931132b 100644 --- a/src/operator/tensor/elemwise_binary_op.cc +++ b/src/operator/tensor/elemwise_binary_op.cc @@ -86,50 +86,5 @@ bool ElemwiseBinaryOp::BackwardUseInStorageType(const nnvm::NodeAttrs& attrs, return true; } -bool ElemwiseBinaryOp::AllowLRDenseInputWithSparseOutputStorageType(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(), 2U) << " in operator " << attrs.name; - CHECK_EQ(out_attrs->size(), 1U) << " in operator " << attrs.name; - const auto& lhs_stype = in_attrs->at(0); - const auto& rhs_stype = in_attrs->at(1); - auto& out_stype = out_attrs->at(0); - bool dispatched = false; - const bool invalid_ctx = dev_mask != mshadow::cpu::kDevMask; - const auto dispatch_ex = invalid_ctx ? DispatchMode::kFComputeFallback : - DispatchMode::kFComputeEx; - if (!dispatched && lhs_stype == kDefaultStorage && rhs_stype == kDefaultStorage) { - // dns, dns -> dns - dispatched = storage_type_assign(&out_stype, kDefaultStorage, - dispatch_mode, DispatchMode::kFCompute); - } - if (!dispatched) { - if ((lhs_stype == kRowSparseStorage && rhs_stype == kRowSparseStorage) || - (lhs_stype == kRowSparseStorage && rhs_stype == kDefaultStorage) || - (lhs_stype == kDefaultStorage && rhs_stype == kRowSparseStorage)) { - // rsp, rsp -> rsp - // rsp, dns -> rsp - // dns, rsp -> rsp - dispatched = storage_type_assign(&out_stype, kRowSparseStorage, - dispatch_mode, dispatch_ex); - } else if (lhs_stype == kCSRStorage && rhs_stype == kCSRStorage) { - dispatched = storage_type_assign(&out_stype, kCSRStorage, - dispatch_mode, dispatch_ex); - } else if (lhs_stype == kCSRStorage || rhs_stype == kCSRStorage) { - dispatched = storage_type_assign(&out_stype, kCSRStorage, - dispatch_mode, DispatchMode::kFComputeFallback); - } - } - if (!dispatched) { - dispatch_fallback(out_attrs, dispatch_mode); - } - if (*dispatch_mode == DispatchMode::kFComputeFallback) { - LogStorageFallback(attrs, dev_mask, in_attrs, out_attrs); - } - return true; -} - } // namespace op } // namespace mxnet diff --git a/src/operator/tensor/elemwise_binary_op.h b/src/operator/tensor/elemwise_binary_op.h index 6a1cc02..b8b5bd1 100644 --- a/src/operator/tensor/elemwise_binary_op.h +++ b/src/operator/tensor/elemwise_binary_op.h @@ -273,11 +273,55 @@ class ElemwiseBinaryOp : public OpBase { * \param out_attrs Output storage attributes * \return true if handled */ + template<bool lhs_dense_ok = true, bool rhs_dense_ok = true> static bool AllowLRDenseInputWithSparseOutputStorageType(const nnvm::NodeAttrs& attrs, int dev_mask, DispatchMode* dispatch_mode, std::vector<int> *in_attrs, - std::vector<int> *out_attrs); + std::vector<int> *out_attrs) { + CHECK_EQ(in_attrs->size(), 2U) << " in operator " << attrs.name; + CHECK_EQ(out_attrs->size(), 1U) << " in operator " << attrs.name; + const auto& lhs_stype = in_attrs->at(0); + const auto& rhs_stype = in_attrs->at(1); + auto& out_stype = out_attrs->at(0); + bool dispatched = false; + const bool invalid_ctx = dev_mask != mshadow::cpu::kDevMask; + const auto dispatch_ex = invalid_ctx ? DispatchMode::kFComputeFallback : + DispatchMode::kFComputeEx; + if (!dispatched && lhs_stype == kDefaultStorage && rhs_stype == kDefaultStorage) { + // dns, dns -> dns + dispatched = storage_type_assign(&out_stype, kDefaultStorage, + dispatch_mode, DispatchMode::kFCompute); + } + if (!dispatched) { + if ((lhs_stype == kRowSparseStorage && rhs_stype == kRowSparseStorage) || + (rhs_dense_ok && lhs_stype == kRowSparseStorage && rhs_stype == kDefaultStorage) || + (lhs_dense_ok && lhs_stype == kDefaultStorage && rhs_stype == kRowSparseStorage)) { + // rsp, rsp -> rsp + // rsp, dns -> rsp + // dns, rsp -> rsp + dispatched = storage_type_assign(&out_stype, kRowSparseStorage, + dispatch_mode, dispatch_ex); + } else if (lhs_stype == kCSRStorage && rhs_stype == kCSRStorage) { + // csr, csr -> csr + dispatched = storage_type_assign(&out_stype, kCSRStorage, + dispatch_mode, dispatch_ex); + } else if ((lhs_stype == kCSRStorage && rhs_dense_ok) || + (rhs_stype == kCSRStorage && lhs_dense_ok)) { + // csr, dns -> csr + // dns, csr -> csr + dispatched = storage_type_assign(&out_stype, kCSRStorage, + dispatch_mode, DispatchMode::kFComputeFallback); + } + } + if (!dispatched) { + dispatch_fallback(out_attrs, dispatch_mode); + } + if (*dispatch_mode == DispatchMode::kFComputeFallback) { + LogStorageFallback(attrs, dev_mask, in_attrs, out_attrs); + } + return true; + } /*! * \brief Backward pass computing input gradient using forward inputs diff --git a/src/operator/tensor/elemwise_binary_op_basic.cc b/src/operator/tensor/elemwise_binary_op_basic.cc index f812fe0..b3be9e4 100644 --- a/src/operator/tensor/elemwise_binary_op_basic.cc +++ b/src/operator/tensor/elemwise_binary_op_basic.cc @@ -98,13 +98,14 @@ The storage type of ``elemwise_mul`` output depends on storage types of inputs - elemwise_mul(default, default) = default - elemwise_mul(row_sparse, row_sparse) = row_sparse - - elemwise_mul(default, row_sparse) = row_sparse - - elemwise_mul(row_sparse, default) = row_sparse + - elemwise_mul(default, row_sparse) = default + - elemwise_mul(row_sparse, default) = default - otherwise, ``elemwise_mul`` generates output with default storage )code") .set_attr<FInferStorageType>("FInferStorageType", - ElemwiseBinaryOp::AllowLRDenseInputWithSparseOutputStorageType) + ElemwiseBinaryOp::AllowLRDenseInputWithSparseOutputStorageType< + false, false>) // 0 * nan or nan * 0 -> nan, so rsp * dns -> dns .set_attr<FCompute>("FCompute<cpu>", ElemwiseBinaryOp::Compute<cpu, mshadow::op::mul>) .set_attr<FComputeEx>("FComputeEx<cpu>", ElemwiseBinaryOp::ComputeDnsLRValueEx<cpu, mshadow::op::mul, true, true>) diff --git a/tests/python/unittest/test_sparse_operator.py b/tests/python/unittest/test_sparse_operator.py index b281749..d440553 100644 --- a/tests/python/unittest/test_sparse_operator.py +++ b/tests/python/unittest/test_sparse_operator.py @@ -327,6 +327,11 @@ def test_elemwise_binary_ops(): return rstype return lstype + def most_dense(lstype, rstype): + if lstype == rstype: + return lstype + return 'default' + def check_elemwise_binary_ops(lhs_stype, rhs_stype, shape, lhs_grad_stype=None, rhs_grad_stype=None, lhs_density=.5, rhs_density=.5, @@ -362,7 +367,7 @@ def test_elemwise_binary_ops(): lambda outg, l, r: (outg * r, outg * l), least_sparse(lhs_stype, rhs_stype), least_sparse(lhs_stype, rhs_stype), - expected_result_storage_type=least_sparse(lhs_stype, rhs_stype), + expected_result_storage_type=most_dense(lhs_stype, rhs_stype), ograd_density=ograd_density, force_lr_overlap=force_lr_overlap, force_grad_overlap=force_grad_overlap, @@ -449,8 +454,8 @@ def test_elemwise_binary_ops(): shape = rand_shape_2d() - print(" force_lr_overlap={}, force_grad_overlap={}, shape={}" - .format(force_lr_overlap, force_grad_overlap, shape)) + print(" force_lr_overlap={}, force_grad_overlap={}, shape={}". + format(force_lr_overlap, force_grad_overlap, shape)) # Left and right always overlap when one is default storage # (assuming the row_sparse one has some entries in it) -- To stop receiving notification emails like this one, please contact ['"comm...@mxnet.apache.org" <comm...@mxnet.apache.org>'].