You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@mxnet.apache.org by jx...@apache.org on 2017/12/28 20:33:42 UTC

[incubator-mxnet] branch master updated: Add result sections in sparse tutorials (#9085)

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 35781a4  Add result sections in sparse tutorials (#9085)
35781a4 is described below

commit 35781a41383f2bdd575bf25f246233000a32eee3
Author: Haibin Lin <li...@gmail.com>
AuthorDate: Thu Dec 28 12:33:38 2017 -0800

    Add result sections in sparse tutorials (#9085)
    
    * Update csr.md
    
    * Update row_sparse.md
    
    * Update train.md
---
 docs/tutorials/sparse/csr.md        | 181 ++++++++++++++++++++++++++++++++++++
 docs/tutorials/sparse/row_sparse.md | 181 +++++++++++++++++++++++++++++++++++-
 docs/tutorials/sparse/train.md      |  67 ++++++++++++-
 3 files changed, 424 insertions(+), 5 deletions(-)

diff --git a/docs/tutorials/sparse/csr.md b/docs/tutorials/sparse/csr.md
index 19ab482..f4d7b7d 100644
--- a/docs/tutorials/sparse/csr.md
+++ b/docs/tutorials/sparse/csr.md
@@ -84,6 +84,15 @@ a.asnumpy()
 ```
 
 
+
+
+    array([[ 7.,  0.,  8.,  0.],
+           [ 0.,  0.,  0.,  0.],
+           [ 0.,  9.,  0.,  0.]], dtype=float32)
+
+
+
+
 ```python
 import numpy as np
 # Create a CSRNDArray with numpy arrays
@@ -95,11 +104,31 @@ b.asnumpy()
 ```
 
 
+
+
+    array([[7, 0, 8, 0],
+           [0, 0, 0, 0],
+           [0, 9, 0, 0]])
+
+
+
+
 ```python
 # Compare the two. They are exactly the same.
 {'a':a.asnumpy(), 'b':b.asnumpy()}
 ```
 
+
+
+
+    {'a': array([[ 7.,  0.,  8.,  0.],
+            [ 0.,  0.,  0.,  0.],
+            [ 0.,  9.,  0.,  0.]], dtype=float32), 'b': array([[7, 0, 8, 0],
+            [0, 0, 0, 0],
+            [0, 9, 0, 0]])}
+
+
+
 You can create an MXNet CSRNDArray from a `scipy.sparse.csr.csr_matrix` object by using the `array` function:
 
 
@@ -115,8 +144,14 @@ except ImportError:
     print("scipy package is required")
 ```
 
+    d:[[7 0 8 0]
+     [0 0 0 0]
+     [0 9 0 0]]
+
+
 What if you have a big set of data and you haven't calculated indices or indptr yet? Let's try a simple CSRNDArray from an existing array of data and derive those values with some built-in functions. We can mockup a "big" dataset with a random amount of the data being non-zero, then compress it by using the `tostype` function, which is explained further in the [Storage Type Conversion](#storage-type-conversion) section:
 
+
 ```python
 big_array = mx.nd.round(mx.nd.random.uniform(low=0, high=1, shape=(1000, 100)))
 print(big_array)
@@ -130,6 +165,17 @@ data = big_array_csr.data
 # The total size of `data`, `indices` and `indptr` arrays is much lesser than the dense big_array!
 ```
 
+    
+    [[ 1.  1.  0. ...,  0.  1.  1.]
+     [ 0.  0.  0. ...,  0.  0.  1.]
+     [ 1.  0.  0. ...,  1.  0.  0.]
+     ..., 
+     [ 0.  1.  1. ...,  0.  0.  0.]
+     [ 1.  1.  0. ...,  1.  0.  1.]
+     [ 1.  0.  1. ...,  1.  0.  0.]]
+    <NDArray 1000x100 @cpu(0)>
+
+
 You can also create a CSRNDArray from another using the `array` function specifying the element data type with the option `dtype`,
 which accepts a numpy type. By default, `float32` is used.
 
@@ -142,6 +188,13 @@ f = mx.nd.array(a, dtype=np.float16)
 (e.dtype, f.dtype)
 ```
 
+
+
+
+    (numpy.float32, numpy.float16)
+
+
+
 ## Inspecting Arrays
 
 A variety of methods are available for you to use for inspecting CSR arrays:
@@ -158,6 +211,15 @@ its contents into a dense `numpy.ndarray` using the `asnumpy` function.
 a.asnumpy()
 ```
 
+
+
+
+    array([[ 7.,  0.,  8.,  0.],
+           [ 0.,  0.,  0.,  0.],
+           [ 0.,  9.,  0.,  0.]], dtype=float32)
+
+
+
 You can also inspect the internal storage of a CSRNDArray by accessing attributes such as `indptr`, `indices` and `data`:
 
 
@@ -171,6 +233,19 @@ indptr = a.indptr
 {'a.stype': a.stype, 'data':data, 'indices':indices, 'indptr':indptr}
 ```
 
+
+
+
+    {'a.stype': 'csr', 'data': 
+     [ 7.  8.  9.]
+     <NDArray 3 @cpu(0)>, 'indices': 
+     [0 2 1]
+     <NDArray 3 @cpu(0)>, 'indptr': 
+     [0 2 2 3]
+     <NDArray 4 @cpu(0)>}
+
+
+
 ## Storage Type Conversion
 
 You can also convert storage types with:
@@ -190,6 +265,17 @@ dense = csr.tostype('default')
 {'csr':csr, 'dense':dense}
 ```
 
+
+
+
+    {'csr': 
+     <CSRNDArray 2x2 @cpu(0)>, 'dense': 
+     [[ 1.  1.]
+      [ 1.  1.]]
+     <NDArray 2x2 @cpu(0)>}
+
+
+
 To convert the storage type by using the `cast_storage` operator:
 
 
@@ -203,6 +289,17 @@ dense = mx.nd.sparse.cast_storage(csr, 'default')
 {'csr':csr, 'dense':dense}
 ```
 
+
+
+
+    {'csr': 
+     <CSRNDArray 2x2 @cpu(0)>, 'dense': 
+     [[ 1.  1.]
+      [ 1.  1.]]
+     <NDArray 2x2 @cpu(0)>}
+
+
+
 ## Copies
 
 You can use the `copy` method which makes a deep copy of the array and its data, and returns a new array.
@@ -219,6 +316,16 @@ a.copyto(d)
 {'b is a': b is a, 'b.asnumpy()':b.asnumpy(), 'c.asnumpy()':c.asnumpy(), 'd.asnumpy()':d.asnumpy()}
 ```
 
+
+
+
+    {'b is a': False, 'b.asnumpy()': array([[ 1.,  1.],
+            [ 1.,  1.]], dtype=float32), 'c.asnumpy()': array([[ 1.,  1.],
+            [ 1.,  1.]], dtype=float32), 'd.asnumpy()': array([[ 1.,  1.],
+            [ 1.,  1.]], dtype=float32)}
+
+
+
 If the storage types of source array and destination array do not match,
 the storage type of destination array will not change when copying with `copyto` or
 the slice operator `[]`.
@@ -233,6 +340,13 @@ g.copyto(f)
 {'e.stype':e.stype, 'f.stype':f.stype, 'g.stype':g.stype}
 ```
 
+
+
+
+    {'e.stype': 'csr', 'f.stype': 'csr', 'g.stype': 'default'}
+
+
+
 ## Indexing and Slicing
 You can slice a CSRNDArray on axis 0 with operator `[]`, which copies the slices and returns a new CSRNDArray.
 
@@ -244,6 +358,18 @@ c = a[:].asnumpy()
 {'a':a, 'b':b, 'c':c}
 ```
 
+
+
+
+    {'a': 
+     <CSRNDArray 3x2 @cpu(0)>,
+     'b': array([[ 2.,  3.]], dtype=float32),
+     'c': array([[ 0.,  1.],
+            [ 2.,  3.],
+            [ 4.,  5.]], dtype=float32)}
+
+
+
 Note that multi-dimensional indexing or slicing along a particular axis is currently not supported for a CSRNDArray.
 
 ## Sparse Operators and Storage Type Inference
@@ -262,6 +388,17 @@ out = mx.nd.sparse.dot(a, rhs)  # invoke sparse dot operator specialized for dot
 {'out':out}
 ```
 
+
+
+
+    {'out': 
+     [[ 15.]
+      [  0.]
+      [  9.]]
+     <NDArray 3x1 @cpu(0)>}
+
+
+
 For any sparse operator, the storage type of output array is inferred based on inputs. You can either read the documentation or inspect the `stype` attribute of the output array to know what storage type is inferred:
 
 
@@ -271,6 +408,13 @@ c = a + mx.nd.ones(shape=(3, 4))  # c will be a dense NDArray
 {'b.stype':b.stype, 'c.stype':c.stype}
 ```
 
+
+
+
+    {'b.stype': 'csr', 'c.stype': 'default'}
+
+
+
 For operators that don't specialize in sparse arrays, we can still use them with sparse inputs with some performance penalty. In MXNet, dense operators require all inputs and outputs to be in the dense format.
 
 If sparse inputs are provided, MXNet will convert sparse inputs into dense ones temporarily, so that the dense operator can be used.
@@ -285,6 +429,13 @@ e = mx.nd.log(a, out=e) # dense operator with a sparse output
 {'a.stype':a.stype, 'd.stype':d.stype, 'e.stype':e.stype} # stypes of a and e will be not changed
 ```
 
+
+
+
+    {'a.stype': 'csr', 'd.stype': 'default', 'e.stype': 'csr'}
+
+
+
 Note that warning messages will be printed when such a storage fallback event happens. If you are using jupyter notebook, the warning message will be printed in your terminal console.
 
 ## Data Loading
@@ -302,6 +453,16 @@ dataiter = mx.io.NDArrayIter(data, labels, batch_size, last_batch_handle='discar
 [batch.data[0] for batch in dataiter]
 ```
 
+
+
+
+    [
+     <CSRNDArray 3x4 @cpu(0)>, 
+     <CSRNDArray 3x4 @cpu(0)>, 
+     <CSRNDArray 3x4 @cpu(0)>]
+
+
+
 You can also load data stored in the [libsvm file format](https://www.csie.ntu.edu.tw/~cjlin/libsvmtools/datasets/) using `mx.io.LibSVMIter`, where the format is: ``<label> <col_idx1>:<value1> <col_idx2>:<value2> ... <col_idxN>:<valueN>``. Each line in the file records the label and the column indices and data for non-zero entries. For example, for a matrix with 6 columns, ``1 2:1.5 4:-3.5`` means the label is ``1``, the data is ``[[0, 0, 1,5, 0, -3.5, 0]]``. More detailed examples of `m [...]
 
 
@@ -328,6 +489,23 @@ for batch in data_train:
     print(data_train.getlabel())
 ```
 
+    
+    <CSRNDArray 3x10 @cpu(0)>
+    
+    [ 1.  1.  1.]
+    <NDArray 3 @cpu(0)>
+    
+    <CSRNDArray 3x10 @cpu(0)>
+    
+    [ 1. -1. -2.]
+    <NDArray 3 @cpu(0)>
+    
+    <CSRNDArray 3x10 @cpu(0)>
+    
+    [-3. -3.  4.]
+    <NDArray 3 @cpu(0)>
+
+
 Note that in the file the column indices are expected to be sorted in ascending order per row, and be zero-based instead of one-based.
 
 ## Advanced Topics
@@ -351,5 +529,8 @@ except mx.MXNetError as err:
     sys.stderr.write(str(err))
 ```
 
+
 <!-- INSERT SOURCE DOWNLOAD BUTTONS -->
 
+
+
diff --git a/docs/tutorials/sparse/row_sparse.md b/docs/tutorials/sparse/row_sparse.md
index 55f8a7d..70ca6b8 100644
--- a/docs/tutorials/sparse/row_sparse.md
+++ b/docs/tutorials/sparse/row_sparse.md
@@ -8,6 +8,7 @@ the weights of models with sparse datasets, the derived gradients of the weights
 
 Let's say we perform a matrix multiplication of ``X``  and ``W``, where ``X`` is a 1x2 matrix, and ``W`` is a 2x3 matrix. Let ``Y`` be the matrix multiplication of the two matrices:
 
+
 ```python
 import mxnet as mx
 X = mx.nd.array([[1,0]])
@@ -16,6 +17,20 @@ Y = mx.nd.dot(X, W)
 {'X': X, 'W': W, 'Y': Y}
 ```
 
+
+
+
+    {'W': 
+     [[ 3.  4.  5.]
+      [ 6.  7.  8.]]
+     <NDArray 2x3 @cpu(0)>, 'X': 
+     [[ 1.  0.]]
+     <NDArray 1x2 @cpu(0)>, 'Y': 
+     [[ 3.  4.  5.]]
+     <NDArray 1x3 @cpu(0)>}
+
+
+
 As you can see,
 
 ```
@@ -37,11 +52,22 @@ grad_W[1][2] = X[0][1] = 0
 
 As a matter of fact, you can calculate ``grad_W`` by multiplying the transpose of ``X`` with a matrix of ones:
 
+
 ```python
 grad_W = mx.nd.dot(X, mx.nd.ones_like(Y), transpose_a=True)
 grad_W
 ```
 
+
+
+
+    
+    [[ 1.  1.  1.]
+     [ 0.  0.  0.]]
+    <NDArray 2x3 @cpu(0)>
+
+
+
 As you can see, row 0 of ``grad_W`` contains non-zero values while row 1 of ``grad_W`` does not. Why did that happen?
 If you look at how ``grad_W`` is calculated, notice that since column 1 of ``X`` is filled with zeros, row 1 of ``grad_W`` is filled with zeros too.
 
@@ -96,7 +122,6 @@ The row sparse representation would be:
 - `indices` array stores the row index for each row slice with non-zero elements.
 
 
-
 ```python
 data = [[1, 2, 3], [4, 0, 5]]
 indices = [0, 2]
@@ -150,6 +175,15 @@ b = mx.nd.sparse.row_sparse_array((data_np, indices_np), shape=shape)
 {'a':a, 'b':b}
 ```
 
+
+
+
+    {'a': 
+     <RowSparseNDArray 6x2 @cpu(0)>, 'b': 
+     <RowSparseNDArray 6x2 @cpu(0)>}
+
+
+
 ## Function Overview
 
 Similar to `CSRNDArray`, the are several functions with `RowSparseNDArray` that behave the same way. In the code blocks below you can try out these common functions:
@@ -177,6 +211,13 @@ d = mx.nd.array(a, dtype=np.float16)
 (c.dtype, d.dtype)
 ```
 
+
+
+
+    (numpy.float32, numpy.float16)
+
+
+
 ## Inspecting Arrays
 
 As with `CSRNDArray`, you can inspect the contents of a `RowSparseNDArray` by filling
@@ -187,6 +228,18 @@ its contents into a dense `numpy.ndarray` using the `asnumpy` function.
 a.asnumpy()
 ```
 
+
+
+
+    array([[ 0.,  0.],
+           [ 1.,  2.],
+           [ 0.,  0.],
+           [ 0.,  0.],
+           [ 3.,  4.],
+           [ 0.,  0.]], dtype=float32)
+
+
+
 You can inspect the internal storage of a RowSparseNDArray by accessing attributes such as `indices` and `data`:
 
 
@@ -198,6 +251,18 @@ indices = a.indices
 {'a.stype': a.stype, 'data':data, 'indices':indices}
 ```
 
+
+
+
+    {'a.stype': 'row_sparse', 'data': 
+     [[ 1.  2.]
+      [ 3.  4.]]
+     <NDArray 2x2 @cpu(0)>, 'indices': 
+     [1 4]
+     <NDArray 2 @cpu(0)>}
+
+
+
 ## Storage Type Conversion
 
 You can convert an NDArray to a RowSparseNDArray and vice versa by using the `tostype` function:
@@ -213,6 +278,17 @@ dense = rsp.tostype('default')
 {'rsp':rsp, 'dense':dense}
 ```
 
+
+
+
+    {'dense': 
+     [[ 1.  1.]
+      [ 1.  1.]]
+     <NDArray 2x2 @cpu(0)>, 'rsp': 
+     <RowSparseNDArray 2x2 @cpu(0)>}
+
+
+
 You can also convert the storage type by using the `cast_storage` operator:
 
 
@@ -226,6 +302,17 @@ dense = mx.nd.sparse.cast_storage(rsp, 'default')
 {'rsp':rsp, 'dense':dense}
 ```
 
+
+
+
+    {'dense': 
+     [[ 1.  1.]
+      [ 1.  1.]]
+     <NDArray 2x2 @cpu(0)>, 'rsp': 
+     <RowSparseNDArray 2x2 @cpu(0)>}
+
+
+
 ## Copies
 
 You can use the `copy` method which makes a deep copy of the array and its data, and returns a new array.
@@ -242,6 +329,16 @@ a.copyto(d)
 {'b is a': b is a, 'b.asnumpy()':b.asnumpy(), 'c.asnumpy()':c.asnumpy(), 'd.asnumpy()':d.asnumpy()}
 ```
 
+
+
+
+    {'b is a': False, 'b.asnumpy()': array([[ 1.,  1.],
+            [ 1.,  1.]], dtype=float32), 'c.asnumpy()': array([[ 1.,  1.],
+            [ 1.,  1.]], dtype=float32), 'd.asnumpy()': array([[ 1.,  1.],
+            [ 1.,  1.]], dtype=float32)}
+
+
+
 If the storage types of source array and destination array do not match,
 the storage type of destination array will not change when copying with `copyto` or the slice operator `[]`. The source array will be temporarily converted to desired storage type before the copy.
 
@@ -255,6 +352,13 @@ g.copyto(f)
 {'e.stype':e.stype, 'f.stype':f.stype, 'g.stype':g.stype}
 ```
 
+
+
+
+    {'e.stype': 'row_sparse', 'f.stype': 'row_sparse', 'g.stype': 'default'}
+
+
+
 ## Retain Row Slices
 
 You can retain a subset of row slices from a RowSparseNDArray specified by their row indices.
@@ -269,6 +373,22 @@ rsp_retained = mx.nd.sparse.retain(rsp, mx.nd.array([0, 1]))
 {'rsp.asnumpy()': rsp.asnumpy(), 'rsp_retained': rsp_retained, 'rsp_retained.asnumpy()': rsp_retained.asnumpy()}
 ```
 
+
+
+
+    {'rsp.asnumpy()': array([[ 1.,  2.],
+            [ 0.,  0.],
+            [ 3.,  4.],
+            [ 5.,  6.],
+            [ 0.,  0.]], dtype=float32), 'rsp_retained': 
+     <RowSparseNDArray 5x2 @cpu(0)>, 'rsp_retained.asnumpy()': array([[ 1.,  2.],
+            [ 0.,  0.],
+            [ 0.,  0.],
+            [ 0.,  0.],
+            [ 0.,  0.]], dtype=float32)}
+
+
+
 ## Sparse Operators and Storage Type Inference
 
 Operators that have specialized implementation for sparse arrays can be accessed in ``mx.nd.sparse``. You can read the [mxnet.ndarray.sparse API documentation](http://mxnet.io/versions/master/api/python/ndarray/sparse.html) to find what sparse operators are available.
@@ -288,6 +408,18 @@ transpose_dot = mx.nd.sparse.dot(lhs, rhs, transpose_a=True)
 {'transpose_dot': transpose_dot, 'transpose_dot.asnumpy()': transpose_dot.asnumpy()}
 ```
 
+
+
+
+    {'transpose_dot': 
+     <RowSparseNDArray 5x2 @cpu(0)>, 'transpose_dot.asnumpy()': array([[ 7.,  7.],
+            [ 9.,  9.],
+            [ 8.,  8.],
+            [ 0.,  0.],
+            [ 0.,  0.]], dtype=float32)}
+
+
+
 For any sparse operator, the storage type of output array is inferred based on inputs. You can either read the documentation or inspect the `stype` attribute of output array to know what storage type is inferred:
 
 
@@ -298,6 +430,13 @@ c = a + mx.nd.ones((5, 2))  # c will be a dense NDArray
 {'b.stype':b.stype, 'c.stype':c.stype}
 ```
 
+
+
+
+    {'b.stype': 'row_sparse', 'c.stype': 'default'}
+
+
+
 For operators that don't specialize in sparse arrays, you can still use them with sparse inputs with some performance penalty.
 In MXNet, dense operators require all inputs and outputs to be in the dense format.
 
@@ -315,6 +454,13 @@ e = mx.nd.log(a, out=e) # dense operator with a sparse output
 {'a.stype':a.stype, 'd.stype':d.stype, 'e.stype':e.stype} # stypes of a and e will be not changed
 ```
 
+
+
+
+    {'a.stype': 'row_sparse', 'd.stype': 'default', 'e.stype': 'row_sparse'}
+
+
+
 Note that warning messages will be printed when such a storage fallback event happens. If you are using jupyter notebook, the warning message will be printed in your terminal console.
 
 ## Sparse Optimizers
@@ -355,12 +501,42 @@ momentum = sgd.create_state(0, weight)
 ```
 
 
+
+
+    {'grad.asnumpy()': array([[ 0.,  0.],
+            [ 1.,  2.],
+            [ 4.,  5.],
+            [ 0.,  0.]], dtype=float32), 'momentum.asnumpy()': array([[ 0.,  0.],
+            [ 0.,  0.],
+            [ 0.,  0.],
+            [ 0.,  0.]], dtype=float32), 'weight.asnumpy()': array([[ 1.,  1.],
+            [ 1.,  1.],
+            [ 1.,  1.],
+            [ 1.,  1.]], dtype=float32)}
+
+
+
+
 ```python
 sgd.update(0, weight, grad, momentum)
 # Only row 0 and row 2 are updated for both weight and momentum
 {"weight.asnumpy()":weight.asnumpy(), "momentum.asnumpy()":momentum.asnumpy()}
 ```
 
+
+
+
+    {'momentum.asnumpy()': array([[ 0.  ,  0.  ],
+            [-0.01, -0.02],
+            [-0.04, -0.05],
+            [ 0.  ,  0.  ]], dtype=float32),
+     'weight.asnumpy()': array([[ 1.        ,  1.        ],
+            [ 0.99000001,  0.98000002],
+            [ 0.95999998,  0.94999999],
+            [ 1.        ,  1.        ]], dtype=float32)}
+
+
+
 Note that both [mxnet.optimizer.SGD](https://mxnet.incubator.apache.org/api/python/optimization.html#mxnet.optimizer.SGD)
 and [mxnet.optimizer.Adam](https://mxnet.incubator.apache.org/api/python/optimization.html#mxnet.optimizer.Adam) support sparse updates in MXNet.
 
@@ -387,6 +563,5 @@ except mx.MXNetError as err:
 ```
 
 
-<!-- INSERT SOURCE DOWNLOAD BUTTONS -->
-
 
+<!-- INSERT SOURCE DOWNLOAD BUTTONS -->
diff --git a/docs/tutorials/sparse/train.md b/docs/tutorials/sparse/train.md
index d75f741..6f4e808 100644
--- a/docs/tutorials/sparse/train.md
+++ b/docs/tutorials/sparse/train.md
@@ -45,6 +45,13 @@ c = mx.sym.Variable('c', stype='row_sparse')
 (a, b, c)
 ```
 
+
+
+
+    (<Symbol a>, <Symbol b>, <Symbol c>)
+
+
+
 ### Bind with Sparse Arrays
 
 The sparse symbols constructed above declare storage types of the arrays to hold.
@@ -67,6 +74,11 @@ c_exec.forward()
 print(b_exec.outputs, c_exec.outputs)
 ```
 
+    ([
+    <CSRNDArray 2x2 @cpu(0)>], [
+    <RowSparseNDArray 2x2 @cpu(0)>])
+
+
 You can update the array held by the variable by accessing executor's `arg_dict` and assigning new values.
 
 
@@ -78,6 +90,15 @@ eval_b = b_exec.outputs[0]
 {'eval_b': eval_b, 'eval_b.asnumpy()': eval_b.asnumpy()}
 ```
 
+
+
+
+    {'eval_b': 
+     <CSRNDArray 2x2 @cpu(0)>, 'eval_b.asnumpy()': array([[ 1.,  1.],
+            [ 1.,  1.]], dtype=float32)}
+
+
+
 ## Symbol Composition and Storage Type Inference
 
 ### Basic Symbol Composition
@@ -96,6 +117,15 @@ f = mx.sym.sparse.elemwise_add(c, c)
 {'d':d, 'e':e, 'f':f}
 ```
 
+
+
+
+    {'d': <Symbol elemwise_add0>,
+     'e': <Symbol negative0>,
+     'f': <Symbol elemwise_add1>}
+
+
+
 ### Storage Type Inference
 
 What will be the output storage types of sparse symbols? In MXNet, for any sparse symbol, the result storage types are inferred based on storage types of inputs.
@@ -113,6 +143,15 @@ rsp_add = add_exec.outputs[2]
 {'dense_add.stype': dense_add.stype, 'csr_add.stype':csr_add.stype, 'rsp_add.stype': rsp_add.stype}
 ```
 
+
+
+
+    {'csr_add.stype': 'csr',
+     'dense_add.stype': 'default',
+     'rsp_add.stype': 'row_sparse'}
+
+
+
 ### Storage Type Fallback
 
 For operators that don't specialize in certain sparse arrays, you can still use them with sparse inputs with some performance penalty. In MXNet, dense operators require all inputs and outputs to be in the dense format. If sparse inputs are provided, MXNet will convert sparse inputs into dense ones temporarily so that the dense operator can be used. If sparse outputs are provided, MXNet will convert the dense outputs generated by the dense operator into the provided sparse format. Warning [...]
@@ -130,6 +169,19 @@ fallback_log = fallback_exec.outputs[1]
 {'fallback_add': fallback_add, 'fallback_log': fallback_log}
 ```
 
+
+
+
+    {'fallback_add': 
+     [[ 0.  0.]
+      [ 0.  0.]]
+     <NDArray 2x2 @cpu(0)>, 'fallback_log': 
+     [[-inf -inf]
+      [-inf -inf]]
+     <NDArray 2x2 @cpu(0)>}
+
+
+
 ### Inspecting Storage Types of the Symbol Graph (Work in Progress)
 
 When the environment variable `MXNET_INFER_STORAGE_TYPE_VERBOSE_LOGGING` is set to `1`, MXNet will log the storage type information of
@@ -247,11 +299,22 @@ for epoch in range(10):
 assert metric.get()[1] < 1, "Achieved MSE (%f) is larger than expected (1.0)" % metric.get()[1]    
 ```
 
+    Epoch 0, Metric = ('mse', 886.16457029229127)
+    Epoch 1, Metric = ('mse', 173.16523056503445)
+    Epoch 2, Metric = ('mse', 71.625164168341811)
+    Epoch 3, Metric = ('mse', 29.625375983519298)
+    Epoch 4, Metric = ('mse', 12.45004676561909)
+    Epoch 5, Metric = ('mse', 6.9090727975622368)
+    Epoch 6, Metric = ('mse', 3.0759215722750142)
+    Epoch 7, Metric = ('mse', 1.3106610134811276)
+    Epoch 8, Metric = ('mse', 0.63063102482907718)
+    Epoch 9, Metric = ('mse', 0.35979430613957991)
+
+
+
 
 ### Training the model with multiple machines
 
 To train a sparse model with multiple machines, please refer to the example in [mxnet/example/sparse/](https://github.com/apache/incubator-mxnet/tree/master/example/sparse)
 
 <!-- INSERT SOURCE DOWNLOAD BUTTONS -->
-
-

-- 
To stop receiving notification emails like this one, please contact
['"commits@mxnet.apache.org" <co...@mxnet.apache.org>'].