-
Notifications
You must be signed in to change notification settings - Fork 6.7k
[MXNET-117] Sparse operator broadcast_mul/div(csr, dense) = csr #10208
Conversation
b37e1ee to
7aa9bfd
Compare
| int& out_stype = out_attrs->at(0); | ||
| bool dispatched = false; | ||
| // For GPU, directly fallback | ||
| if (dev_mask == mshadow::gpu::kDevMask) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Should dispatch to fcompute for dense inputs/outputs
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done
7b1d7ab to
35d9ae7
Compare
|
@marcoabreu the pylint result failed on lines not added by this PR. Is there anything not tested on CI? |
97d198d to
f2ee977
Compare
|
@eric-haibin-lin the pylint check passed in http://jenkins.mxnet-ci.amazon-ml.com/blue/organizations/jenkins/incubator-mxnet/detail/PR-10208/7/pipeline. There was a short time between upgrading the instances and merging my PR to reflect the necessary changes (pylint fixes included) in which pylint failures could have been possible. It should be resolved now. |
f2ee977 to
ad17b4c
Compare
|
@sergeykolychev Hi, my PR is failing some tests because I've changed some interface in Python but I'm not familiar with Perl so I'm not able to make the same changes in Perl. I wonder if you could please give some help on how to make corresponding changes in Perl so that my builds could pass? Thanks! |
|
@haojin2 Hi Hao, certainly, when you need this by the latest ? I'm on vacation right now but if it's pressing I can look at it sooner. |
|
@sergeykolychev Probably by the end of this month would be a hard deadline for me, since it would be good check this in for the next release. I guess all what we need are some minor changes to the interface similar to my changes to sparse.py in this PR on the Perl side, so I think any help at your earliest convenience is appreciated, thanks for your response and enjoy your vacation! |
|
@haojin2 ok, I'll fix this problem for you until end of Thursday this week. |
|
Sure, please take your time! Thanks a lot for your help! |
ad17b4c to
0111aae
Compare
|
|
||
| @with_seed() | ||
| def test_sparse_broadcast_mul_div(): | ||
| from scipy.sparse import random, csr_matrix |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't think scipy.sparse.csr_matrix is used here
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Removed
| assert_almost_equal(mx.nd.broadcast_div(mx_lhs, mx_rhs).asnumpy(), np.divide(np_lhs, np_rhs), atol=1e-4) | ||
| shape = (4,3) | ||
| np_lhs = random(shape[0], shape[1], density=0.25, dtype=np.float32).tocsr() | ||
| mx_lhs = mx.nd.sparse.csr_matrix((np_lhs.data, np_lhs.indices, np_lhs.indptr), shape=shape) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why not just use test_utils.rand_ndarray(shape, stype, density)?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done, was not aware of that helper function
| _set_ndarray_class(_ndarray_cls) | ||
|
|
||
|
|
||
| def add(lhs, rhs): |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Need to update the document and clarify that it's equivalent to nd.elemwise_add() when shape matches. Same for other mul, div, sub
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done
| >>> mx.nd.sparse.zeros('row_sparse', (1,2), ctx=mx.cpu(), dtype='float16').asnumpy() | ||
| array([[ 0., 0.]], dtype=float16) | ||
| """ | ||
| # pylint: disable= no-member, protected-access |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is this added to every function? Maybe worth disable it at the beginning of the file instead of disabling it per function.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Not added to every function, so will keep this in this way.
| [ 1., 1., 1.]] | ||
| Supported sparse operations: | ||
| broadcast_mul(csr, dense(1D)) = csr |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
clarify that this is only supported on CPU
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done
|
@sergeykolychev Thank you very much! |
| '/=' => \¬_implemented; | ||
|
|
||
| method add(AI::MXNet::NDArray|Num $other, $reverse=) | ||
| { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I really appreciate your fast response @sergeykolychev thanks for unblocking us. While I'm not a perl user but some documentations for the new function will be great. Maybe worth adding next time
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yeah, I'll add the docs next time with more substantial changes in April. Tried to unblock quickly. Though I don't see anybody using the functions directly and not via the overloaded operators.
aebfa17 to
2ce2bbb
Compare
python/mxnet/ndarray/sparse.py
Outdated
| Examples | ||
| -------- | ||
| >>> x = mx.nd.ones((2,3)) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think we should replace the example with the supported case specifically for sparse:
>>> x = mx.nd.ones((2,3)).tostype('csr')
>>> y = mx.nd.ones((2,3)).tostype('csr')
>>> (x + y).asnumpy()
array([[ 2., 2., 2.],
[ 2., 2., 2.]], dtype=float32)
>>> (x + 2).asnumpy()
array([[ 3., 3., 3.],
[ 3., 3., 3.]], dtype=float32)
>>> mx.nd.sparse.add(x,y).asnumpy()
array([[ 2., 2., 2.],
[ 2., 2., 2.]], dtype=float32)
| # pylint: enable= no-member, protected-access | ||
|
|
||
|
|
||
| def multiply(lhs, rhs): |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Should these functions be added to __all__ in line 36?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Let's show a specific example for csr multiplied by 1D vector
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Changed, please check
python/mxnet/ndarray/sparse.py
Outdated
| Examples | ||
| -------- | ||
| >>> x = mx.nd.ones((2,3)) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Same comment: use sparse ndarray in the example
python/mxnet/ndarray/sparse.py
Outdated
| >>> (x/y).asnumpy() | ||
| array([[ 3., 3., 3.], | ||
| [ 3., 3., 3.]], dtype=float32) | ||
| >>> mx.nd.divide(x,y).asnumpy() |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Let's show a specific example for csr divided by 1D vector
| broadcast_mul(x, y) = [[ 0., 0., 0.], | ||
| [ 1., 1., 1.]] | ||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Shall we also edit https://github.com/apache/incubator-mxnet/blob/master/docs/api/python/ndarray/sparse.md#arithmetic-operations and add broadcast_mul / broadcast_div?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done
2ce2bbb to
0556ff3
Compare
68d2cd4 to
6f9d8c2
Compare
6f9d8c2 to
09a60a1
Compare
| def check_broadcast_div(mx_lhs, mx_rhs, np_lhs, np_rhs, dtype): | ||
| assert_almost_equal(mx.nd.sparse.divide(mx_lhs, mx_rhs).asnumpy(), np.divide(np_lhs, np_rhs), atol=1e-4) | ||
| stype = 'csr' | ||
| for num_rows in range(2, 6): |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Personally I think this is too much.. This will be tested repeatedly on CI, rand_shape_2d() should be sufficient.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Sure, done
| for num_rows in range(2, 6): | ||
| for num_cols in range(2, 6): | ||
| shape = (num_rows, num_cols) | ||
| density = random.uniform(0.15, 0.25) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actually what about densities = zero and a non-zero? We want to explicitly test the case where density = 0, since that's a special case in your code
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Changed
python/mxnet/ndarray/sparse.py
Outdated
| >>> (x+2).asnumpy() | ||
| array([[ 3., 3., 3.], | ||
| [ 3., 3., 3.]], dtype=float32) | ||
| >>> (x+y).asnumpy() |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think csr + dense will fallback. It's not good to put an example that is not efficient..
python/mxnet/ndarray/sparse.py
Outdated
| >>> (x*y).asnumpy() | ||
| array([[ 0., 0., 0.], | ||
| [ 1., 1., 1.]], dtype=float32) | ||
| >>> mx.nd.multiply(x, y).asnumpy() |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This should be sparse.multiply, right?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done
python/mxnet/ndarray/sparse.py
Outdated
| >>> (x/y).asnumpy() | ||
| array([[ 6., 6., 6.], | ||
| [ 3., 3., 3.]], dtype=float32) | ||
| >>> mx.nd.divide(x,y).asnumpy() |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
sparse.divide?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done
python/mxnet/ndarray/sparse.py
Outdated
| Examples | ||
| -------- | ||
| >>> x = mx.nd.ones((2,3)).tostype('csr') | ||
| >>> y = mx.nd.arange(2).reshape((2,1)) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
csr - dense will fallback..
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is multiply, subtract has been fixed above
| CHECK_EQ(inputs.size(), 2U); | ||
| CHECK_EQ(outputs.size(), 1U); | ||
| CHECK_EQ(req.size(), 1U); | ||
| CHECK_LE(inputs[1].shape().ndim(), 2U) << "input dense matrix should have less than 2 dimensions"; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
less than -> less than or equal?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done
| } else { | ||
| if (req[0] != kNullOp) { | ||
| // broadcast(CSR, Dense(1D)) = CSR | ||
| if (lhs_stype == kCSRStorage && rhs_stype == kDefaultStorage && out_stype == kCSRStorage) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What about rhs.shape = (1,1)? Will this work?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Made it work
| // If the input is not a vector | ||
| if ((rhs.shape().ndim() != 1U) && (rhs.shape()[0] != 1) && (rhs.shape()[1] != 1)) { | ||
| // Currently do not support elementwise_mul/div(csr, dense) = csr, log and exit | ||
| LogUnimplementedOp(attrs, ctx, inputs, req, outputs); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Let's print a more informational error msg
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done
3206737 to
1d3d43d
Compare
| 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, { | ||
| if (dns.shape().ndim() > 1 && dns.shape()[0] == 1 && dns.shape()[1] == 1) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
would rhs = mx.nd.array([5]) work?
1d3d43d to
b56f975
Compare
| } | ||
|
|
||
| template<typename xpu, typename OP> | ||
| void BinaryBroadcastComputeCsrEx(const nnvm::NodeAttrs& attrs, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
rename to BinaryBroadcastComputeEx
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done
| if (lhs_stype == kCSRStorage && rhs_stype == kDefaultStorage && out_stype == kCSRStorage) { | ||
| BinaryBroadcastCsrDnsCsrImpl<xpu, OP>(ctx, lhs, rhs, req[0], out); | ||
| } else { | ||
| LogUnimplementedOp(attrs, ctx, inputs, req, outputs); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Suggest to move LogUnimplementedOp to line 317. Otherwise it may not be called for some unimplemented case
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done
b56f975 to
99585fb
Compare
eric-haibin-lin
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nice work!
|
Update on 4/8: Results on p2.8xlarge instance with commit(2ae0bd5): |
…he#10208) * support broadcast_mul/div(csr, 1Ddense) = csr * address code reviews and support broadcast_mul/div(csr, 2Ddense) = csr * add test for both 1D and 2D dense case * address code review and fix test error * address code review and fix test error * added proper overrides for basic arithmetic functions for sparse tensors. * fix broadcast dimension * address code reviews
…he#10208) * support broadcast_mul/div(csr, 1Ddense) = csr * address code reviews and support broadcast_mul/div(csr, 2Ddense) = csr * add test for both 1D and 2D dense case * address code review and fix test error * address code review and fix test error * added proper overrides for basic arithmetic functions for sparse tensors. * fix broadcast dimension * address code reviews
Description
Add a sparse operator on CPU that supports broadcast_mul/div(csr, dense) = csr operations.
Checklist
Essentials
Please feel free to remove inapplicable items for your PR.
Changes
Comments
Duplicate PR with #10150, getting a new PR due to renaming of my branch
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)