Skip to content

Commit

Permalink
Improve hybridblock doc (apache#11236)
Browse files Browse the repository at this point in the history
  • Loading branch information
piiswrong authored and anirudh2290 committed Jun 15, 2018
1 parent 78c372a commit 8ac8901
Show file tree
Hide file tree
Showing 3 changed files with 62 additions and 20 deletions.
29 changes: 16 additions & 13 deletions docs/tutorials/gluon/hybrid.md
Original file line number Diff line number Diff line change
Expand Up @@ -87,7 +87,7 @@ net(x)
Hybrid execution can be activated by simply calling `.hybridize()` on the top
level layer. The first forward call after activation will try to build a
computation graph from `hybrid_forward` and cache it. On subsequent forward
calls the cached graph instead of `hybrid_forward` will be invoked:
calls the cached graph, instead of `hybrid_forward`, will be invoked:

```python
net.hybridize()
Expand All @@ -105,23 +105,26 @@ Hybridize will speed up execution and save memory. If the top level layer is
not a `HybridBlock`, you can still call `.hybridize()` on it and Gluon will try
to hybridize its children layers instead.

Please refer to the [API manual](https://mxnet.incubator.apache.org/api/python/gluon/gluon.html?highlight=hybridize#mxnet.gluon.Block.hybridize)
for details.

## Serializing trained model for deployment

Models implemented as `HybridBlock` can be easily serialized for deployment
using other language front-ends like C, C++ and Scala. To this end, we simply
forward the model with symbolic variables instead of NDArrays and save the
output Symbol(s):
Models implemented as `HybridBlock` can be easily serialized. The serialized
model can be loaded back later or used for deployment
with other language front-ends like C, C++ and Scala. To this end, we simply
use `export` and `SymbolBlock.imports`:

```python
x = mx.sym.var('data')
y = net(x)
print(y)
y.save('model.json')
net.save_parameters('model.params')
net.export('model', epoch=1)
```

If your network outputs more than one value, you can use `mx.sym.Group` to
combine them into a grouped Symbol and then save. The saved json and params
files can then be loaded with C, C++ and Scala interface for prediction.
Two files `model-symbol.json` and `model-0001.params` are saved on disk.
You can use other language bindings to load them. You can also load them back
to gluon with `SymbolBlock`:

```python
net2 = gluon.SymbolBlock.imports('model-symbol.json', ['data'], 'model-0001.params')
```

<!-- INSERT SOURCE DOWNLOAD BUTTONS -->
39 changes: 35 additions & 4 deletions python/mxnet/gluon/block.py
Original file line number Diff line number Diff line change
Expand Up @@ -148,7 +148,8 @@ def forward(self, x):
Child :py:class:`Block` assigned this way will be registered and :py:meth:`collect_params`
will collect their Parameters recursively.
will collect their Parameters recursively. You can also manually register
child blocks with :py:meth:`register_child`.
Parameters
----------
Expand Down Expand Up @@ -307,6 +308,8 @@ def _collect_params_with_prefix(self, prefix=''):
def save_parameters(self, filename):
"""Save parameters to file.
Parameters
----------
filename : str
Path to file.
"""
Expand All @@ -333,6 +336,8 @@ def load_parameters(self, filename, ctx=None, allow_missing=False,
ignore_extra=False):
"""Load parameters from file.
Parameters
----------
filename : str
Path to parameter file.
ctx : Context or list of Context, default cpu()
Expand Down Expand Up @@ -462,9 +467,31 @@ def forward(self, *args):
class HybridBlock(Block):
"""`HybridBlock` supports forwarding with both Symbol and NDArray.
`HybridBlock` is similar to `Block`, with a few differences::
import mxnet as mx
from mxnet.gluon import HybridBlock, nn
class Model(HybridBlock):
def __init__(self, **kwargs):
super(Model, self).__init__(**kwargs)
# use name_scope to give child Blocks appropriate names.
with self.name_scope():
self.dense0 = nn.Dense(20)
self.dense1 = nn.Dense(20)
def hybrid_forward(self, F, x):
x = F.relu(self.dense0(x))
return F.relu(self.dense1(x))
model = Model()
model.initialize(ctx=mx.cpu(0))
model.hybridize()
model(mx.nd.zeros((10, 10), ctx=mx.cpu(0)))
Forward computation in :py:class:`HybridBlock` must be static to work with :py:class:`Symbol` s,
i.e. you cannot call :py:meth:`NDArray.asnumpy`, :py:attr:`NDArray.shape`,
:py:attr:`NDArray.dtype`, etc on tensors.
:py:attr:`NDArray.dtype`, `NDArray` indexing (`x[i]`) etc on tensors.
Also, you cannot use branching or loop logic that bases on non-constant
expressions like random numbers or intermediate results, since they change
the graph structure for each iteration.
Expand All @@ -474,8 +501,12 @@ class HybridBlock(Block):
representing the forward computation and cache it. On subsequent forwards,
the cached graph will be used instead of :py:meth:`hybrid_forward`.
Refer `Hybrid tutorial <http://mxnet.io/tutorials/gluon/hybrid.html>`_ to see
the end-to-end usage.
Please see references for detailed tutorial.
References
----------
`Hybrid - Faster training and easy deployment
<http://mxnet.io/tutorials/gluon/hybrid.html>`_
"""
def __init__(self, prefix=None, params=None):
super(HybridBlock, self).__init__(prefix=prefix, params=params)
Expand Down
14 changes: 11 additions & 3 deletions python/mxnet/gluon/parameter.py
Original file line number Diff line number Diff line change
Expand Up @@ -342,6 +342,8 @@ def initialize(self, init=None, ctx=None, default_init=initializer.Uniform(),
def reset_ctx(self, ctx):
"""Re-assign Parameter to other contexts.
Parameters
----------
ctx : Context or list of Context, default ``context.current_context()``.
Assign Parameter to given context. If ctx is a list of Context, a
copy will be made for each context.
Expand Down Expand Up @@ -478,8 +480,8 @@ def __init__(self, **kwargs):
super(Block, self).__init__(**kwargs)
self.const = self.params.get_constant('const', [[1,2],[3,4]])
Parameter
---------
Parameters
----------
name : str
Name of the parameter.
value : array-like
Expand Down Expand Up @@ -619,7 +621,7 @@ def get_constant(self, name, value=None):
found, :py:func:`get` will create a new :py:class:`Constant` with key-word
arguments and insert it to self.
Constants
Parameters
----------
name : str
Name of the desired Constant. It will be prepended with this dictionary's
Expand Down Expand Up @@ -694,6 +696,8 @@ def zero_grad(self):
def reset_ctx(self, ctx):
"""Re-assign all Parameters to other contexts.
Parameters
----------
ctx : Context or list of Context, default :py:meth:`context.current_context()`.
Assign Parameter to given context. If ctx is a list of Context, a
copy will be made for each context.
Expand Down Expand Up @@ -726,6 +730,8 @@ def setattr(self, name, value):
def save(self, filename, strip_prefix=''):
"""Save parameters to file.
Parameters
----------
filename : str
Path to parameter file.
strip_prefix : str, default ''
Expand All @@ -750,6 +756,8 @@ def load(self, filename, ctx=None, allow_missing=False,
ignore_extra=False, restore_prefix=''):
"""Load parameters from file.
Parameters
----------
filename : str
Path to parameter file.
ctx : Context or list of Context
Expand Down

0 comments on commit 8ac8901

Please sign in to comment.