diff --git a/docs/tutorials/gluon/hybrid.md b/docs/tutorials/gluon/hybrid.md index 5c8372a51f4e..f9f2c112f532 100644 --- a/docs/tutorials/gluon/hybrid.md +++ b/docs/tutorials/gluon/hybrid.md @@ -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() @@ -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') +``` diff --git a/python/mxnet/gluon/block.py b/python/mxnet/gluon/block.py index 689b7abf14b7..f8f01fc83c3b 100644 --- a/python/mxnet/gluon/block.py +++ b/python/mxnet/gluon/block.py @@ -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 ---------- @@ -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. """ @@ -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() @@ -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. @@ -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 `_ to see - the end-to-end usage. + Please see references for detailed tutorial. + References + ---------- + `Hybrid - Faster training and easy deployment + `_ """ def __init__(self, prefix=None, params=None): super(HybridBlock, self).__init__(prefix=prefix, params=params) diff --git a/python/mxnet/gluon/parameter.py b/python/mxnet/gluon/parameter.py index c0d89fbd4cc1..73fca6050acf 100644 --- a/python/mxnet/gluon/parameter.py +++ b/python/mxnet/gluon/parameter.py @@ -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. @@ -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 @@ -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 @@ -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. @@ -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 '' @@ -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