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 6452fe6 More sparse related docs (#7911)
6452fe6 is described below
commit 6452fe681e1102d4a1ac9b18b4e3edbd3ba05306
Author: Haibin Lin <[email protected]>
AuthorDate: Wed Sep 27 14:27:20 2017 -0700
More sparse related docs (#7911)
* more sparse related docs
* fix lint
* fix grammar
* raise exception on unimplemented aux type for sparse
---
docs/api/python/ndarray/ndarray.md | 2 +
docs/api/python/ndarray/sparse.md | 108 ++++++++++++++++++++++++++-
docs/tutorials/basic/ndarray.md | 4 +-
python/mxnet/ndarray/sparse.py | 20 +++--
python/mxnet/optimizer.py | 4 +-
python/mxnet/test_utils.py | 53 ++++++++++---
src/engine/threaded_engine.h | 2 +-
src/io/iter_libsvm.cc | 5 +-
tests/python/unittest/test_kvstore.py | 32 ++++----
tests/python/unittest/test_module.py | 8 +-
tests/python/unittest/test_sparse_ndarray.py | 10 +--
11 files changed, 191 insertions(+), 57 deletions(-)
diff --git a/docs/api/python/ndarray/ndarray.md
b/docs/api/python/ndarray/ndarray.md
index 315410a..064f070 100644
--- a/docs/api/python/ndarray/ndarray.md
+++ b/docs/api/python/ndarray/ndarray.md
@@ -461,6 +461,7 @@ The `ndarray` package provides several classes:
sqrt
rsqrt
square
+ reciprocal
```
### Logic functions
@@ -476,6 +477,7 @@ The `ndarray` package provides several classes:
lesser
lesser_equal
```
+
### Random sampling
```eval_rst
diff --git a/docs/api/python/ndarray/sparse.md
b/docs/api/python/ndarray/sparse.md
index ace9a0d..78f351b 100644
--- a/docs/api/python/ndarray/sparse.md
+++ b/docs/api/python/ndarray/sparse.md
@@ -91,7 +91,6 @@ We summarize the interface for each class in the following
sections.
:nosignatures:
CSRNDArray.shape
- CSRNDArray.size
CSRNDArray.context
CSRNDArray.dtype
CSRNDArray.stype
@@ -153,7 +152,6 @@ We summarize the interface for each class in the following
sections.
:nosignatures:
RowSparseNDArray.shape
- RowSparseNDArray.size
RowSparseNDArray.context
RowSparseNDArray.dtype
RowSparseNDArray.stype
@@ -185,6 +183,20 @@ We summarize the interface for each class in the following
sections.
RowSparseNDArray.zeros_like
```
+### Array rounding
+
+```eval_rst
+.. autosummary::
+ :nosignatures:
+
+ RowSparseNDArray.round
+ RowSparseNDArray.rint
+ RowSparseNDArray.fix
+ RowSparseNDArray.floor
+ RowSparseNDArray.ceil
+ RowSparseNDArray.trunc
+```
+
### Indexing
```eval_rst
@@ -216,6 +228,8 @@ We summarize the interface for each class in the following
sections.
zeros_like
csr_matrix
row_sparse_array
+ mxnet.ndarray.load
+ mxnet.ndarray.save
```
## Array manipulation routines
@@ -248,10 +262,93 @@ We summarize the interface for each class in the
following sections.
:nosignatures:
elemwise_add
+ elemwise_sub
+ elemwise_mul
+ negative
dot
add_n
```
+### Trigonometric functions
+
+```eval_rst
+.. autosummary::
+ :nosignatures:
+
+ sin
+ tan
+ arcsin
+ arctan
+ degrees
+ radians
+```
+
+### Hyperbolic functions
+
+```eval_rst
+.. autosummary::
+ :nosignatures:
+
+ sinh
+ tanh
+ arcsinh
+ arctanh
+```
+
+### Rounding
+
+```eval_rst
+.. autosummary::
+ :nosignatures:
+
+ round
+ rint
+ fix
+ floor
+ ceil
+ trunc
+```
+
+### Exponents and logarithms
+
+```eval_rst
+.. autosummary::
+ :nosignatures:
+
+ expm1
+ log1p
+```
+
+### Powers
+
+```eval_rst
+.. autosummary::
+ :nosignatures:
+
+ sqrt
+ square
+```
+
+### Miscellaneous
+
+```eval_rst
+.. autosummary::
+ :nosignatures:
+
+ abs
+ sign
+```
+
+### More
+
+```eval_rst
+.. autosummary::
+ :nosignatures:
+
+ make_loss
+ stop_gradient
+```
+
## API Reference
<script type="text/javascript"
src='../../../_static/js/auto_module_index.js'></script>
@@ -259,10 +356,10 @@ We summarize the interface for each class in the
following sections.
```eval_rst
.. autoclass:: mxnet.ndarray.sparse.CSRNDArray
- :members: shape, size, context, dtype, stype, data, indices, indptr, copy,
copyto, as_in_context, asnumpy, asscalar, astype, tostype, slice, wait_to_read,
zeros_like, __getitem__, __setitem__
+ :members: shape, context, dtype, stype, data, indices, indptr, copy,
copyto, as_in_context, asnumpy, asscalar, astype, tostype, slice, wait_to_read,
zeros_like, __getitem__, __setitem__
.. autoclass:: mxnet.ndarray.sparse.RowSparseNDArray
- :members: shape, size, context, dtype, stype, data, indices, copy, copyto,
as_in_context, asnumpy, asscalar, astype, tostype, wait_to_read, zeros_like,
__getitem__, __setitem__
+ :members: shape, context, dtype, stype, data, indices, copy, copyto,
as_in_context, asnumpy, asscalar, astype, tostype, wait_to_read, zeros_like,
round, rint, fix, floor, ceil, trunc, __getitem__, __setitem__
.. automodule:: mxnet.ndarray.sparse
:members:
@@ -272,6 +369,9 @@ We summarize the interface for each class in the following
sections.
.. automodule:: mxnet.ndarray.sparse
:members: array, zeros, empty
+.. automodule:: mxnet.ndarray
+ :members: load, save
+
```
<script>auto_index("api-reference");</script>
diff --git a/docs/tutorials/basic/ndarray.md b/docs/tutorials/basic/ndarray.md
index bd76702..bc5ce89 100644
--- a/docs/tutorials/basic/ndarray.md
+++ b/docs/tutorials/basic/ndarray.md
@@ -33,7 +33,7 @@ Each NDArray supports some important attributes that you'll
often want to query:
and `m` columns, its `shape` will be `(n, m)`.
- **ndarray.dtype**: A `numpy` _type_ object describing the type of its
elements.
-- **ndarray.size**: the total number of components in the array - equal to the
+- **ndarray.size**: The total number of components in the array - equal to the
product of the components of its `shape`
- **ndarray.context**: The device on which this array is stored, e.g. `cpu()`
or
`gpu(1)`.
@@ -81,7 +81,7 @@ We can specify the element type with the option `dtype`,
which accepts a numpy
type. By default, `float32` is used:
```python
-# float32 is used in default
+# float32 is used by default
a = mx.nd.array([1,2,3])
# create an int32 array
b = mx.nd.array([1,2,3], dtype=np.int32)
diff --git a/python/mxnet/ndarray/sparse.py b/python/mxnet/ndarray/sparse.py
index 9d9dd28..7995da5 100644
--- a/python/mxnet/ndarray/sparse.py
+++ b/python/mxnet/ndarray/sparse.py
@@ -88,6 +88,9 @@ def _new_alloc_handle(stype, shape, ctx, delay_alloc, dtype,
aux_types, aux_shap
A new empty ndarray handle
"""
hdl = NDArrayHandle()
+ for aux_t in aux_types:
+ if np.dtype(aux_t) != np.dtype("int64"):
+ raise NotImplementedError("only int64 is supported for aux types")
aux_type_ids = [int(_DTYPE_NP_TO_MX[np.dtype(aux_t).type]) for aux_t in
aux_types]
aux_shapes = [(0,) for aux_t in aux_types] if aux_shapes is None else
aux_shapes
aux_shape_lens = [len(aux_shape) for aux_shape in aux_shapes]
@@ -149,6 +152,11 @@ class BaseSparseNDArray(NDArray):
def reshape(self, shape):
raise NotSupportedForSparseNDArray(self.reshape, None, shape)
+ @property
+ def size(self):
+ # the `size` for a sparse ndarray is ambiguous, hence disabled.
+ raise NotImplementedError()
+
def _aux_type(self, i):
"""Data-type of the array's ith aux data.
@@ -250,12 +258,12 @@ class BaseSparseNDArray(NDArray):
# pylint: disable=abstract-method
class CSRNDArray(BaseSparseNDArray):
- """A sparse representation of 2D NDArray in the standard CSR format.
+ """A sparse representation of 2D NDArray in the Compressed Sparse Row
format.
A CSRNDArray represents an NDArray as three separate arrays: `data`,
`indptr` and `indices`. It uses the standard CSR representation where the
column indices for
- row i are stored in indices[indptr[i]:indptr[i+1]] and their corresponding
values are stored
- in values[indptr[i]:indptr[i+1]].
+ row i are stored in ``indices[indptr[i]:indptr[i+1]]`` and their
corresponding values are stored
+ in ``data[indptr[i]:indptr[i+1]]``.
The column indices for a given row are expected to be sorted in ascending
order.
Duplicate column entries for the same row are not allowed.
@@ -492,7 +500,7 @@ class RowSparseNDArray(BaseSparseNDArray):
`indices`.
- data: an NDArray of any dtype with shape [D0, D1, ..., Dn].
- - indices: a 1-D int64 NDArray with shape [D0].
+ - indices: a 1-D int64 NDArray with shape [D0] with values sorted in
ascending order.
The `indices` stores the indices of the row slices with non-zeros,
while the values are stored in `data`. The corresponding NDArray ``dense``
@@ -513,11 +521,9 @@ class RowSparseNDArray(BaseSparseNDArray):
array([[ 1., 2., 3.],
[ 4., 0., 5.]], dtype=float32)
- A RowSparseNDArray is typically used to represent non-zero row-slices of a
large NDArray
+ A RowSparseNDArray is typically used to represent non-zero row slices of a
large NDArray
of shape [LARGE0, D1, .. , Dn] where LARGE0 >> D0 and most row slices are
zeros.
- The indices are expected to be sorted in ascending order.
-
RowSparseNDArray is used principally in the definition of gradients for
operations
that have sparse gradients (e.g. sparse dot and sparse embedding).
"""
diff --git a/python/mxnet/optimizer.py b/python/mxnet/optimizer.py
index ec0a1d4..9f89415 100644
--- a/python/mxnet/optimizer.py
+++ b/python/mxnet/optimizer.py
@@ -395,8 +395,8 @@ class SGD(Optimizer):
multi_precision: bool, optional
Flag to control the internal precision of the optimizer.
``False`` results in using the same precision as the weights (default),
- ``True`` makes internal 32-bit copy of the weights and applies gradients
- in 32-bit precision even if actual weights used in the model
have lower precision.
+ ``True`` makes internal 32-bit copy of the weights and applies
gradients \
+ in 32-bit precision even if actual weights used in the model
have lower precision.\
Turning this on can improve convergence and accuracy when
training with float16.
"""
def __init__(self, momentum=0.0, multi_precision=False, **kwargs):
diff --git a/python/mxnet/test_utils.py b/python/mxnet/test_utils.py
index f041118..bc92257 100644
--- a/python/mxnet/test_utils.py
+++ b/python/mxnet/test_utils.py
@@ -135,22 +135,32 @@ def _get_uniform_dataset_csr(num_rows, num_cols,
density=0.1, dtype=None,
"""Returns CSRNDArray with uniform distribution
This generates a csr matrix with totalnnz unique randomly chosen numbers
from num_rows*num_cols and arranges them in the 2d array in the
- following way: row_index = (random_number_generated / num_rows)
+ following way:
+ row_index = (random_number_generated / num_rows)
col_index = random_number_generated - row_index * num_cols
"""
_validate_csr_generation_inputs(num_rows, num_cols, density,
distribution="uniform")
- from scipy import sparse as spsp
- csr = spsp.rand(num_rows, num_cols, density, dtype=dtype, format="csr")
- if data_init is not None:
- csr.data.fill(data_init)
- if shuffle_csr_indices is True:
- shuffle_csr_column_indices(csr)
- result = mx.nd.sparse.csr_matrix(csr.data, csr.indptr, csr.indices,
- (num_rows, num_cols), dtype=dtype)
+ try:
+ from scipy import sparse as spsp
+ csr = spsp.rand(num_rows, num_cols, density, dtype=dtype, format="csr")
+ if data_init is not None:
+ csr.data.fill(data_init)
+ if shuffle_csr_indices is True:
+ shuffle_csr_column_indices(csr)
+ result = mx.nd.sparse.csr_matrix(csr.data, csr.indptr, csr.indices,
+ (num_rows, num_cols), dtype=dtype)
+ except ImportError:
+ assert(data_init is None), \
+ "data_init option is not supported when scipy is absent"
+ assert(not shuffle_csr_indices), \
+ "shuffle_csr_indices option is not supported when scipy is
absent"
+ # scipy not available. try to generate one from a dense array
+ dns = mx.nd.random.uniform(shape=(num_rows, num_cols), dtype=dtype)
+ masked_dns = dns * (dns < density)
+ result = masked_dns.tostype('csr')
return result
-
def _get_powerlaw_dataset_csr(num_rows, num_cols, density=0.1, dtype=None):
"""Returns CSRNDArray with powerlaw distribution
with exponentially increasing number of non zeros in each row.
@@ -246,6 +256,7 @@ def rand_sparse_ndarray(shape, stype, density=None,
dtype=None, distribution=Non
data_init=None, rsp_indices=None, modifier_func=None,
shuffle_csr_indices=False):
"""Generate a random sparse ndarray. Returns the ndarray, value(np) and
indices(np)
+
Parameters
----------
shape: list or tuple
@@ -253,9 +264,11 @@ def rand_sparse_ndarray(shape, stype, density=None,
dtype=None, distribution=Non
density, optional: float, should be between 0 and 1
distribution, optional: str, valid values: "uniform" or "powerlaw"
dtype, optional: numpy.dtype, default value is None
+
Returns
-------
Result of type CSRNDArray or RowSparseNDArray
+
Examples
--------
Below is an example of the powerlaw distribution with csr as the stype.
@@ -265,7 +278,18 @@ def rand_sparse_ndarray(shape, stype, density=None,
dtype=None, distribution=Non
else, remaining unused_nnzs will be used in n+1th row
If number of cols is too small and we have already reached column size it
will fill up
all following columns in all followings rows until we reach the required
density.
- density = rnd.rand() if density is None else density
+
+ >>> csr_arr, _ = rand_sparse_ndarray(shape=(5, 16), stype="csr",
+ density=0.50, distribution="powerlaw")
+ >>> indptr = csr_arr.indptr.asnumpy()
+ >>> indices = csr_arr.indices.asnumpy()
+ >>> data = csr_arr.data.asnumpy()
+ >>> row2nnz = len(data[indptr[1]:indptr[2]])
+ >>> row3nnz = len(data[indptr[2]:indptr[3]])
+ >>> assert(row3nnz == 2*row2nnz)
+ >>> row4nnz = len(data[indptr[3]:indptr[4]])
+ >>> assert(row4nnz == 2*row3nnz)
+
"""
density = rnd.rand() if density is None else density
dtype = default_dtype() if dtype is None else dtype
@@ -516,6 +540,13 @@ def assert_almost_equal_ignore_nan(a, b, rtol=None,
atol=None, names=('a', 'b'))
assert_almost_equal(a, b, rtol, atol, names)
+def assert_exception(f, exception_type, *args, **kwargs):
+ """Test that function f will throw an exception of type given by
`exception_type`"""
+ try:
+ f(*args, **kwargs)
+ assert(False)
+ except exception_type:
+ return
def retry(n):
"""Retry n times before failing for stochastic test cases."""
diff --git a/src/engine/threaded_engine.h b/src/engine/threaded_engine.h
index 9b7b74d..fef3346 100644
--- a/src/engine/threaded_engine.h
+++ b/src/engine/threaded_engine.h
@@ -345,7 +345,7 @@ class ThreadedEngine : public Engine {
if (what.find("driver shutting down") == std::string::npos &&
!shutdown_phase_) {
LOG(FATAL) << e.what() << "\n" <<
- "An fatal error occurred in asynchronous engine operation. "
+ "A fatal error occurred in asynchronous engine operation. "
"If you do not know what caused this error, "
"you can try set environment variable MXNET_ENGINE_TYPE "
"to NaiveEngine and run with debugger (i.e. gdb). "
diff --git a/src/io/iter_libsvm.cc b/src/io/iter_libsvm.cc
index 8e53e6f..ab6cacb 100644
--- a/src/io/iter_libsvm.cc
+++ b/src/io/iter_libsvm.cc
@@ -201,8 +201,9 @@ MXNET_REGISTER_IO_ITER(LibSVMIter)
.describe(R"code(Returns the libsvm file iterator which returns sparse data
with `csr`
storage type. This iterator is experimental and should be used with care.
-The input data is stored in a format similar to libsvm file format, except
that the indices
-are expected to be zero-based instead of one-based. Details of the libsvm
format are available
+The input data is stored in a format similar to libsvm file format, except
that the **indices
+are expected to be zero-based instead of one-based, and the column indices for
each row are
+expected to be sorted in ascending order**. Details of the libsvm format are
available
at `https://www.csie.ntu.edu.tw/~cjlin/libsvmtools/datasets/`
In this function, the `data_shape` parameter is used to set the shape of each
line of the data.
diff --git a/tests/python/unittest/test_kvstore.py
b/tests/python/unittest/test_kvstore.py
index 12feb7e..6ed037f 100644
--- a/tests/python/unittest/test_kvstore.py
+++ b/tests/python/unittest/test_kvstore.py
@@ -18,20 +18,13 @@
# pylint: skip-file
import mxnet as mx
import numpy as np
-from mxnet.test_utils import rand_ndarray, assert_almost_equal
-from mxnet.base import py_str
+from mxnet.test_utils import rand_ndarray, assert_almost_equal,
assert_exception
+from mxnet.base import py_str, MXNetError
shape = (4, 4)
keys = [5, 7, 11]
str_keys = ['b', 'c', 'd']
-def assert_exception(f, *args, **kwargs):
- try:
- f(*args, **kwargs)
- assert(False)
- except:
- return
-
def init_kv(stype='default'):
"""init kv """
kv = mx.kv.create()
@@ -258,29 +251,30 @@ def test_invalid_pull():
def check_invalid_rsp_pull_single(kv, key):
dns_val = mx.nd.ones(shape) * 2
- assert_exception(kv.row_sparse_pull, key, out=dns_val,
row_ids=mx.nd.array([1]))
+ assert_exception(kv.row_sparse_pull, MXNetError,
+ key, out=dns_val, row_ids=mx.nd.array([1]))
def check_invalid_rsp_pull_list(kv, key):
dns_val = [mx.nd.ones(shape) * 2] * len(key)
- assert_exception(kv.row_sparse_pull, key, out=dns_val,
+ assert_exception(kv.row_sparse_pull, MXNetError, key, out=dns_val,
row_ids=[mx.nd.array([1])] * len(key))
def check_invalid_key_types_single(kv, key):
dns_val = mx.nd.ones(shape) * 2
rsp_val = dns_val.tostype('row_sparse')
- assert_exception(kv.init, key, dns_val)
- assert_exception(kv.push, key, dns_val)
- assert_exception(kv.pull, key, dns_val)
- assert_exception(kv.row_sparse_pull, key, rsp_val,
+ assert_exception(kv.init, MXNetError, key, dns_val)
+ assert_exception(kv.push, MXNetError, key, dns_val)
+ assert_exception(kv.pull, MXNetError, key, dns_val)
+ assert_exception(kv.row_sparse_pull, MXNetError, key, rsp_val,
row_ids=mx.nd.array([1]))
def check_invalid_key_types_list(kv, key):
dns_val = [mx.nd.ones(shape) * 2] * len(key)
rsp_val = [val.tostype('row_sparse') for val in dns_val]
- assert_exception(kv.init, key, dns_val)
- assert_exception(kv.push, key, dns_val)
- assert_exception(kv.pull, key, dns_val)
- assert_exception(kv.row_sparse_pull, key, rsp_val,
+ assert_exception(kv.init, MXNetError, key, dns_val)
+ assert_exception(kv.push, MXNetError, key, dns_val)
+ assert_exception(kv.pull, MXNetError, key, dns_val)
+ assert_exception(kv.row_sparse_pull, MXNetError, key, rsp_val,
row_ids=[mx.nd.array([1])] * len(key))
int_kv = init_kv()
diff --git a/tests/python/unittest/test_module.py
b/tests/python/unittest/test_module.py
index 6813c48..542217f 100644
--- a/tests/python/unittest/test_module.py
+++ b/tests/python/unittest/test_module.py
@@ -512,14 +512,14 @@ def test_factorization_machine_module():
mod = mx.mod.Module(symbol=model, data_names=['data'],
label_names=['label'])
# allocate memory by given the input data and lable shapes
mod.bind(data_shapes=train_iter.provide_data,
label_shapes=train_iter.provide_label)
- # initialize parameters by uniform random numbers
+ # initialize parameters by random numbers
mod.init_params(initializer=init)
- # use Sparse SGD with learning rate 0.1 to train
+ # use sparse Adam with learning rate 0.1 to train
adam = mx.optimizer.Adam(clip_gradient=5.0, learning_rate=0.001,
rescale_grad=1.0/batch_size)
mod.init_optimizer(optimizer=adam)
- # use accuracy as the metric
+ # use MSE as the metric
metric = mx.metric.create('MSE')
- # train 10 epoch
+ # train 10 epochs
for epoch in range(10):
train_iter.reset()
metric.reset()
diff --git a/tests/python/unittest/test_sparse_ndarray.py
b/tests/python/unittest/test_sparse_ndarray.py
index 94ea228..52a1b3c 100644
--- a/tests/python/unittest/test_sparse_ndarray.py
+++ b/tests/python/unittest/test_sparse_ndarray.py
@@ -551,11 +551,11 @@ def test_synthetic_dataset_generator():
def test_sparse_nd_exception():
""" test invalid sparse operator will throw a exception """
a = mx.nd.zeros((2,2))
- try:
- b = mx.nd.sparse.retain(a, invalid_arg="garbage_value")
- assert(False)
- except:
- return
+ assert_exception(mx.nd.sparse.retain, mx.base.MXNetError,
+ a, invalid_arg="garbage_value")
+ assert_exception(mx.nd.sparse.zeros, NotImplementedError,
+ 'csr', (2,2), aux_types=[np.int32, np.int32])
+
if __name__ == '__main__':
import nose
--
To stop receiving notification emails like this one, please contact
['"[email protected]" <[email protected]>'].