Skip to content
This repository has been archived by the owner on Nov 17, 2023. It is now read-only.

Commit

Permalink
Improve hybridblock doc (#11236)
Browse files Browse the repository at this point in the history
* Improve hybridblock doc

* fix
  • Loading branch information
piiswrong authored Jun 14, 2018
1 parent a40055e commit ee1a10f
Show file tree
Hide file tree
Showing 3 changed files with 70 additions and 20 deletions.
38 changes: 25 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,35 @@ 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.

`hybridize` also accepts several options for performance tuning. For example, you
can do

```python
net.hybridize(static_alloc=True)
# or
net.hybridize(static_alloc=True, static_shape=True)
```

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 -->
38 changes: 34 additions & 4 deletions python/mxnet/gluon/block.py
Original file line number Diff line number Diff line change
Expand Up @@ -149,7 +149,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 @@ -310,6 +311,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 @@ -336,6 +339,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 @@ -635,9 +640,31 @@ def _summary_hook(block, _, outputs):
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 @@ -647,9 +674,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 @@ -391,6 +391,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 @@ -587,8 +589,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 @@ -739,7 +741,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 @@ -814,6 +816,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 @@ -846,6 +850,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 @@ -870,6 +876,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 ee1a10f

Please sign in to comment.