Skip to content
This repository was archived by the owner on Nov 17, 2023. It is now read-only.

[MXNET-117] [WIP] [DO NOT MERGE] Sparse operator broadcast_mul/div(csr, dense) = csr#10150

Closed
haojin2 wants to merge 2 commits intoapache:masterfrom
haojin2:broadcast_1D_mul
Closed

[MXNET-117] [WIP] [DO NOT MERGE] Sparse operator broadcast_mul/div(csr, dense) = csr#10150
haojin2 wants to merge 2 commits intoapache:masterfrom
haojin2:broadcast_1D_mul

Conversation

@haojin2
Copy link
Copy Markdown
Contributor

@haojin2 haojin2 commented Mar 18, 2018

Description

Add a sparse operator on CPU that supports broadcast_mul/div(csr, dense) = csr operations.

Checklist

Essentials

  • The PR title starts with [MXNET-117]
  • Changes are complete (i.e. I finished coding on this PR)
  • All changes have test coverage:
  • Unit tests are added for small changes to verify correctness (e.g. adding a new operator)
  • Nightly tests are added for complicated/long-running ones (e.g. changing distributed kvstore)
  • Build tests will be added for build configuration changes (e.g. adding a new build option with NCCL)
  • Code is well-documented:
  • For user-facing API changes, API doc string has been updated.
  • For new C++ functions in header files, their functionalities and arguments are documented.
  • For new examples, README.md is added to explain the what the example does, the source of the dataset, expected performance on test set and reference to the original paper if applicable
  • Check the API doc at http://mxnet-ci-doc.s3-accelerate.dualstack.amazonaws.com/PR-$PR_ID/$BUILD_ID/index.html
  • To the my best knowledge, examples are either not affected by this change, or have been fixed to be compatible with this change

Changes

  • Add support for broadcast_mul/div(csr, 1Ddense) = csr
  • Add support for broadcast_mul/div(csr, 2Ddense) = csr

Comments

Example for broadcast_mul/div(csr, 1Ddense) = csr
import mxnet as mx
a = mx.nd.array([[0,0,3],[0,2,0],[1,0,0]]).tostype('csr')
b = mx.nd.array([1,2,3])
mx.nd.broadcast_mul(a,b).asnumpy()
array([[ 0., 0., 3.],
[ 0., 4., 0.],
[ 3., 0., 0.]], dtype=float32)

@haojin2 haojin2 requested a review from cjolivier01 as a code owner March 18, 2018 17:42
}
};

template<typename DType, typename CType, typename RType, int req, typename OP>
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

can the template types be at function level and be inferred automatically by the arguments passed, or are you going for type checking?

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Agree with applying these as function's template arguments instead of the class's.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Will make that change soon.

MSHADOW_IDX_TYPE_SWITCH(output.aux_type(kIdx), CType, {
MSHADOW_IDX_TYPE_SWITCH(output.aux_type(kIndPtr), RType, {
MXNET_ASSIGN_REQ_SWITCH(req, req_type, {
Kernel<csr_dns_csr_broadcast_kernel<DType, CType, RType, req_type, OP>, xpu>::Launch(
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

yeah, you can probably get by without passing all of these template parameters

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done

bool col_vec = (dns.shape()[0] == csr.shape()[0])? true : false;
if (!csr.storage_initialized()) {
FillZerosCsrImpl(s, output);
return;
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

would just an else block rather than a return be more readable?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sure, will do that.

// out_stype == kDefaultStorage) {
// BinaryBroadCastCsrDnsDnsImpl(ctx, inputs[0], input[1], req[0], outputs[0]);
} else {
LogUnimplementedOp(attrs, ctx, inputs, req, outputs);
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

would catching this in the storage type inference and then doing a fallback not work for this case?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If we get really big sparse matrices as inputs then fallback may not be a better choice than throwing?

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Usually in the other cases, it falls back and will print a warning the first time. Are there other cases where it just throws an error rather than falling back?

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I agree that throwing an error is not desirable and blocks users from what they want to do. The problem is that finferstorage is not aware of shape and dtype, and dispatch only based on dev_mask and storage types. And for this sparse broadcast operator it's a lot of work to implement cases for 2-D and 3-D.

Maybe a temporary walk-around is to fallback inside the operator..

}

template<typename xpu, typename OP>
void BinaryBroadCastCsrDnsCsrImpl(const OpContext& ctx,
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

BroadCast -> Broadcast

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ok

}
};

template<typename DType, typename CType, typename RType, int req, typename OP>
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Agree with applying these as function's template arguments instead of the class's.

return true;
}

inline bool BinaryBroadcastStorageTypeCsr(const nnvm::NodeAttrs& attrs,
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No need to put Csr in the title since we may add row_sparse in the same function in future. Also the name is confusing because this is only for mul/div

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Changed to BinaryBroadcastMulStorageType

std::vector<int>* out_attrs) {
CHECK_EQ(in_attrs->size(), 2U);
CHECK_EQ(out_attrs->size(), 1U);
const int in1_stype = in_attrs->at(0);
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'd think left/right-hand side (lhs/rhs) is a better name compared to in1/in2

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

done

@@ -122,6 +122,8 @@ Example::

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please only add the docs for broadcast_mul here.

// out_stype == kDefaultStorage) {
// BinaryBroadCastCsrDnsDnsImpl(ctx, inputs[0], input[1], req[0], outputs[0]);
} else {
LogUnimplementedOp(attrs, ctx, inputs, req, outputs);
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I agree that throwing an error is not desirable and blocks users from what they want to do. The problem is that finferstorage is not aware of shape and dtype, and dispatch only based on dev_mask and storage types. And for this sparse broadcast operator it's a lot of work to implement cases for 2-D and 3-D.

Maybe a temporary walk-around is to fallback inside the operator..

using namespace mxnet_op;
using namespace csr;
CHECK_EQ(dns.shape().ndim(), 1) << "input dense should be a vector";
mshadow::Stream<xpu> *s = ctx.get_stream<xpu>();
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Need to check req != kAddTo / kWriteInplace

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done

@haojin2 haojin2 changed the title [WIP] [DO NOT MERGE] Sparse operator broadcast_mul/div(csr, dense) = csr [MXNET-117] [WIP] [DO NOT MERGE] Sparse operator broadcast_mul/div(csr, dense) = csr Mar 20, 2018
@haojin2 haojin2 force-pushed the broadcast_1D_mul branch 2 times, most recently from ddfa5b8 to 4626999 Compare March 21, 2018 00:06
MSHADOW_XINLINE static void Map(int row, const DType *csr_data, const CType *csr_indices,
const RType *csr_indptr, const DType *dns,
DType *out, const nnvm::dim_t row_length, bool col_vec) {
nnvm::dim_t curr_row_i = csr_indptr[row];
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: const

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done

template <typename DType, typename CType, typename RType>
MSHADOW_XINLINE static void Map(int row, const DType *csr_data, const CType *csr_indices,
const RType *csr_indptr, const DType *dns,
DType *out, const nnvm::dim_t row_length, bool col_vec) {
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

col_vec could be part of the template

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This flag may actually be abandoned later, will do if it still exists later.

@@ -122,6 +122,8 @@ Example::

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please only add the docs for broadcast_mul here.

@@ -156,6 +161,8 @@ Example::

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please update doc for broadcast_div

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done

@haojin2 haojin2 force-pushed the broadcast_1D_mul branch 2 times, most recently from d086e34 to edc6e28 Compare March 22, 2018 16:44
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants