-
Notifications
You must be signed in to change notification settings - Fork 65
Conversation
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.
Thanks for the contribution, few comments in-line.
-
Remove skip if not mxnet backend. these tests can be tested with tf backend as well.
-
Add assert is_sparse to make sure sparse tensor is used
-
There is no mxnet sparse implementation in this PR, suggest to change title to
Add sparse tests for sum and mean operator
. Make it available for tf backend, and make sure tests pass for tf backend. After sparse implementation, we can use these tests to test mxnet backend.
@@ -1702,6 +1702,56 @@ def test_sparse_concat(self): | |||
assert k_s_d.shape == k_d.shape | |||
assert_allclose(k_s_d, k_d, atol=1e-05) | |||
|
|||
@pytest.mark.skipif((K.backend() != 'mxnet'), | |||
reason='Testing only for MXNet backend') |
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.
There is nothing specific for mxnet, we can test tensorflow backend as well.
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.
the eval() implementation is different for mxnet - eval() converts the array into a numpy array - making it dense & fails the test. In Tensorflow the original class of the sparse tensor doesn't change - https://github.com/tensorflow/tensorflow/blob/r1.10/tensorflow/python/ops/sparse_ops.py#L724
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.
It's the same for both backends, eval() are supposed to convert to dense and return a numpy array. same in tensorflow backend. See tf_backend
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.
With MXNet backend, when we try to evaluate the value of a sparse KerasSymbol - the dense value is returned and because of this is_sparse(eval(KerasSymbol))
is always False
- we basically return the numpy array which is always dense.
In TF backend, a SparseTensor
class has been used and because of this even when the tensor is converted to dense it always remains an instance of the SparseTensor class
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.
Will this behavior not become an issue during training when weights are sparse tensor?
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 dont think this should be an issue. We are just abstracting the _forward_pass() operation in eval() and then converting it to a numpy array.
tests/keras/backend/backend_test.py
Outdated
|
||
W = np.random.random((5, 4)) | ||
|
||
k_s = K.eval(K.sum(K.variable(x_sparse), axis=0)) |
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.
add check for is_sparse
like in the test sparse concat
k_s = k.concatenate([k.variable(x_sparse_1), k.variable(x_sparse_2)])
assert k.is_sparse(k_s)
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.
For mxnet backend, currently sparse tensor is not created in K.variable, so this is comparing the same results. Adding assert k.is_sparse()
will ensure sparse tensor is used.
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.
added implementation of sparse tensor as well now
tests/keras/backend/backend_test.py
Outdated
assert k_s.shape == k_d.shape | ||
assert_allclose(k_s, k_d, atol=1e-05) | ||
|
||
@pytest.mark.skipif((K.backend() != 'mxnet'), |
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 as test_add
, There is nothing specific for mxnet, we can test tensorflow backend as well.
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.
see comment above
tests/keras/backend/backend_test.py
Outdated
x_sparse = sparse.csr_matrix((x_d, (x_r, x_c)), shape=(4, 5)) | ||
x_dense = x_sparse.toarray() | ||
|
||
k_s = K.eval(K.mean(K.variable(x_sparse), axis=0)) |
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 as above, add assert is_sparse
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.
added
tests/keras/backend/backend_test.py
Outdated
x_sparse = sparse.csr_matrix((x_d, (x_r, x_c)), shape=(4, 5)) | ||
x_dense = x_sparse.toarray() | ||
|
||
k_s = K.eval(K.mean(K.variable(x_sparse))) |
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 as above, add assert is_sparse
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.
added
tests/keras/backend/backend_test.py
Outdated
assert k_s.shape == k_d.shape | ||
assert_allclose(k_s, k_d, atol=1e-05) | ||
|
||
@pytest.mark.skipif((K.backend() != 'mxnet'), |
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 as test_add, There is nothing specific for mxnet, we can test tensorflow backend as well.
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 as above
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.
Thanks for the update! Really cool work!
Seems that this is a general solution, not specific to sum and mean ops, could you also enable other sparse tests to verify? for example test_sparse_dot
and test_sparse_concat
. In addition to adding new test cases, with this implementation, we should enable previously disabled unit tests in Keras that tests sparse.
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.
Thanks @kalyc . Great work! Looking forward for first end-to-end sparse model :-)
return tensor.toarray() | ||
elif isinstance(tensor, mx.sym.Symbol): | ||
return tensor.stype('default') | ||
elif isinstance(tensor, KerasSymbol): |
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.
else ?
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.
else returning tensor the way it is
@@ -4149,10 +4174,10 @@ def dfs_get_bind_values(node_start): | |||
return bind_values | |||
|
|||
|
|||
def _keras_variable(name, shape, dtype, is_vector=False, **kwargs): | |||
def _keras_variable(name, shape, dtype, stype, is_vector=False, **kwargs): |
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 we set default to 'default'?
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.
yep will do
@@ -1702,6 +1702,56 @@ def test_sparse_concat(self): | |||
assert k_s_d.shape == k_d.shape | |||
assert_allclose(k_s_d, k_d, atol=1e-05) | |||
|
|||
@pytest.mark.skipif((K.backend() != 'mxnet'), | |||
reason='Testing only for MXNet backend') |
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.
Will this behavior not become an issue during training when weights are sparse tensor?
@@ -1702,6 +1702,107 @@ def test_sparse_concat(self): | |||
assert k_s_d.shape == k_d.shape | |||
assert_allclose(k_s_d, k_d, atol=1e-05) | |||
|
|||
@pytest.mark.skipif((K.backend() != 'mxnet'), | |||
reason='Testing only for MXNet backend') | |||
def test_sparse_sum(self): |
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 it will be good idea to move all sparse tests to a separate file. may be - tests/keras/backend/sparse_test.py ?
It will be easier later for merge/rebase etc. and also cleanly separates the tests, that can be eventually contributed back to Keras tests
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.
sounds good - will do
PR continued here - #162 Have enabled sparse |
@kalyc - Please feel free to close this PR as we running through another PR :-) |
Closing this PR in place of this one - #162 |
Summary
Add sparse support for
sum
,mean
anddot
operatorsRelated Issues
Missing sparse operators
PR Overview