未验证 提交 e23984a9 编写于 作者: A Aurelius84 提交者: GitHub

add input_spec zh and en doc (#2594)

* add input_spec cn

* add input_spec cn

* fix === style

* fix file name typo

* add ref

* add en doc

* fix en doc

* refine according reviewer

* remove user comment

* refine doc

* refine doc
上级 d8645ff1
......@@ -6,6 +6,8 @@
- `支持语法列表 <grammar_list_cn.html>`_ :介绍了动态图转静态图支持的语法以及罗列不支持的语法写法
- `InputSpec功能介绍 <input_spec_cn.html>`_ :介绍了动态图转静态图指定输入InputSpec的功能和用法
- `报错信息处理 <error_handling_cn.html>`_ :介绍了动态图转静态图支持的报错信息处理方法
- `调试方法 <debugging_cn.html>`_ :介绍了动态图转静态图支持的调试方法
......@@ -16,5 +18,6 @@
grammar_list_cn.rst
program_translator_cn.rst
input_spec_cn.rst
error_handling_cn.md
debugging_cn.md
.. _user_guide_dy2sta_input_spec_cn:
InputSpec功能介绍
=================
在PaddlePaddle(下文简称:Paddle)框架中,可以通过 ``paddle.jit.to_static`` 装饰普通函数或 Layer 的最外层 forward 函数,将动态图模型转换为静态图执行。但在动转静时,需要给模型传入 Tensor 数据并执行一次前向,以保证正确地推导出网络中各 Tensor 的 shape 。此转换流程需要显式地执行一次动态图函数,增加了接口使用的成本;同时,传入实际 Tensor 数据则无法定制化模型输入的shape,如指定某些维度为 None 。
因此,Paddle 提供了 InputSpec 接口,可以更加便捷地执行动转静功能,以及定制化输入 Tensor 的 shape 、name 等信息。
一、InputSpec 对象构造方法
-------------------------
1.1 直接构造 InputSpec 对象
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
InputSpec 接口在 ``paddle.static`` 目录下,用于描述一个 Tensor 的签名信息:shape、dtype、name。使用样例如下:
.. code-block:: python
from paddle.static import InputSpec
x = InputSpec([None, 784], 'float32', 'x')
label = InputSpec([None, 1], 'int64', 'label')
print(x) # InputSpec(shape=(-1, 784), dtype=VarType.FP32, name=x)
print(label) # InputSpec(shape=(-1, 1), dtype=VarType.INT64, name=label)
InputSpec 初始化中的只有 ``shape`` 是必须参数, ``dtype`` 和 ``name`` 可以缺省,默认取值分别为 ``float32`` 和 ``None`` 。
1.2 根据 Tensor 构造 InputSpec 对象
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
可以借助 ``InputSpec.from_tensor`` 方法,从一个 Tensor 直接创建 InputSpec 对象,其拥有与源 Tensor 相同的 ``shape`` 和 ``dtype`` 。使用样例如下:
.. code-block:: python
import numpy as np
import paddle
from paddle.static import InputSpec
paddle.disable_static()
x = paddle.to_tensor(np.ones([2, 2], np.float32))
x_spec = InputSpec.from_tensor(x, name='x')
print(x_spec) # InputSpec(shape=(2, 2), dtype=VarType.FP32, name=x)
.. note::
若未在 ``from_tensor`` 中指定新的name,则默认使用与源Tensor相同的name。
1.3 根据 numpy.ndarray 构造 InputSpec 对象
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
也可以借助 ``InputSpec.from_numpy`` 方法,从一个 Numpy.ndarray 直接创建 InputSpec 对象,其拥有与源 ndarray 相同的 ``shape`` 和 ``dtype`` 。使用样例如下:
.. code-block:: python
import numpy as np
from paddle.static import InputSpec
x = np.ones([2, 2], np.float32)
x_spec = InputSpec.from_numpy(x, name='x')
print(x_spec) # InputSpec(shape=(2, 2), dtype=VarType.FP32, name=x)
.. note::
若未在 ``from_numpy`` 中指定新的 name,则默认使用 None 。
二、基本使用方法
------------------
动转静 ``paddle.jit.to_static`` 装饰器支持 ``input_spec`` 参数,用于指定被装饰函数每个 Tensor 类型输入参数的 ``shape`` 、 ``dtype`` 、 ``name`` 等签名信息。不必再显式地传入 Tensor 数据以触发网络层 shape 的推导。 Paddle 会解析 ``to_static`` 中指定的 ``input_spec`` 参数,构建网络的起始输入,进行后续的模型组网。
同时,借助 ``input_spec`` 参数,可以自定义输入 Tensor 的 shape ,比如指定 shape 为 ``[None, 784]`` ,其中 ``None`` 表示变长的维度。
2.1 to_static 装饰器模式
^^^^^^^^^^^^^^^^^^^^^^^^^^
如下是一个简单的使用样例:
.. code-block:: python
import paddle
from paddle.jit import to_static
from paddle.static import InputSpec
from paddle.fluid.dygraph import Layer
class SimpleNet(Layer):
def __init__(self):
super(SimpleNet, self).__init__()
self.linear = paddle.nn.Linear(10, 3)
@to_static(input_spec=[InputSpec(shape=[None, 10], name='x'), InputSpec(shape=[3], name='y')])
def forward(self, x, y):
out = self.linear(x)
out = out + y
return out
paddle.disable_static()
net = SimpleNet()
# save static model for inference directly
paddle.jit.save(net, './simple_net')
在上述的样例中, ``to_static`` 装饰器中的 ``input_spec`` 为一个 InputSpec 对象组成的列表,用于依次指定参数 x 和 y 对应的 Tensor 签名信息。在实例化 SimpleNet 后,可以直接调用 ``paddle.jit.save`` 保存静态图模型,不需要执行任何其他的代码。
.. note::
1. input_spec 参数中只支持 InputSpec 对象,暂不支持如 int 、 float 等类型。
2. 若指定 input_spec 参数,则需为被装饰函数的所有必选参数都添加对应的 InputSpec 对象,如上述样例中,不支持仅指定 x 的签名信息。
3. 若被装饰函数中包括非 Tensor 参数,且指定了 input_spec ,请确保函数的非 Tensor 参数都有默认值,如 ``forward(self, x, use_bn=False)``
2.2 to_static函数调用
^^^^^^^^^^^^^^^^^^^^
若期望在动态图下训练模型,在训练完成后保存预测模型,并指定预测时需要的签名信息,则可以选择在保存模型时,直接调用 ``to_static`` 函数。使用样例如下:
.. code-block:: python
class SimpleNet(Layer):
def __init__(self):
super(SimpleNet, self).__init__()
self.linear = paddle.nn.Linear(10, 3)
def forward(self, x, y):
out = self.linear(x)
out = out + y
return out
paddle.disable_static()
net = SimpleNet()
# train process (Pseudo code)
for epoch_id in range(10):
train_step(net, train_reader)
net = to_static(net, input_spec=[InputSpec(shape=[None, 10], name='x'), InputSpec(shape=[3], name='y')])
# save static model for inference directly
paddle.jit.save(net, './simple_net')
如上述样例代码中,在完成训练后,可以借助 ``to_static(net, input_spec=...)`` 形式对模型实例进行处理。Paddle 会根据 input_spec 信息对 forward 函数进行递归的动转静,得到完整的静态图,且包括当前训练好的参数数据。
2.3 支持 list 和 dict 推导
^^^^^^^^^^^^^^^^^^^^^^^^^^^^
上述两个样例中,被装饰的 forward 函数的参数均为 Tensor 。这种情况下,参数个数必须与 InputSpec 个数相同。但当被装饰的函数参数为list或dict类型时,``input_spec`` 需要与函数参数保持相同的嵌套结构。
当函数的参数为 list 类型时,input_spec 列表中对应元素的位置,也必须是包含相同元素的 InputSpec 列表。使用样例如下:
.. code-block:: python
class SimpleNet(Layer):
def __init__(self):
super(SimpleNet, self).__init__()
self.linear = paddle.nn.Linear(10, 3)
@to_static(input_spec=[[InputSpec(shape=[None, 10], name='x'), InputSpec(shape=[3], name='y')]])
def forward(self, inputs):
x, y = inputs[0], inputs[1]
out = self.linear(x)
out = out + y
return out
其中 ``input_spec`` 参数是长度为 1 的 list ,对应 forward 函数的 inputs 参数。 ``input_spec[0]`` 包含了两个 InputSpec 对象,对应于参数 inputs 的两个 Tensor 签名信息。
当函数的参数为dict时, ``input_spec`` 列表中对应元素的位置,也必须是包含相同键(key)的 InputSpec 列表。使用样例如下:
.. code-block:: python
class SimpleNet(Layer):
def __init__(self):
super(SimpleNet, self).__init__()
self.linear = paddle.nn.Linear(10, 3)
@to_static(input_spec=[InputSpec(shape=[None, 10], name='x'), {'x': InputSpec(shape=[3], name='bias')}])
def forward(self, x, bias_info):
x_bias = bias_info['x']
out = self.linear(x)
out = out + x_bias
return out
其中 ``input_spec`` 参数是长度为 2 的 list ,对应 forward 函数的 x 和 bias_info 两个参数。 ``input_spec`` 的最后一个元素是包含键名为 x 的 InputSpec 对象的 dict ,对应参数 bias_info 的 Tensor 签名信息。
更多关于动转静 ``to_static`` 搭配 ``paddle.jit.save/load`` 的使用方式,可以参考 :ref:`user_guide_model_save_load` 。
\ No newline at end of file
.. _user_guide_dy2sta_input_spec_cn:
Introduction of InputSpec
===========================
In PaddlePaddle(Referred to as "Paddle"), The dygraph model can be converted to static program by decorating the outermost forward function of Layer with ``paddle.jit.to_static`` . But actual Tensor data should be feeded into the model to ensure that the shape of each Tensor in the network is correctly deduced in transformation. This transformation process needs to explicitly execute the forward function, which increases the cost of the interface. Meanwhile, the way that need feed Tensor data fails to customize the shape of inputs, such as assigning some dimensions to None.
Therefore, Paddle provides the InputSpec interface to perform the transformation more easily, and supports to customize the signature of input Tensor, such as shape, name and so on.
1. InputSpec interface
-------------------------
1.1 Construct InputSpec object
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
The InputSpec interface is under the ``paddle.static`` directory. It's used to describe the Tensor's signature information: shape, dtype, name. See example as follows:
.. code-block:: python
from paddle.static import InputSpec
x = InputSpec([None, 784], 'float32', 'x')
label = InputSpec([None, 1], 'int64', 'label')
print(x) # InputSpec(shape=(-1, 784), dtype=VarType.FP32, name=x)
print(label) # InputSpec(shape=(-1, 1), dtype=VarType.INT64, name=label)
In InputSpec initialization, only ``shape`` is a required parameter. ``dtype`` and ``name`` can be default with values ``Float32`` and ``None`` respectively.
1.2 Constructed from Tensor
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
An InputSpec object can be created directly from a Tensor by using ``inputSpec.from_tensor`` method. It has same ``shape`` and ``dtype`` as the source Tensor. See example as follows:
.. code-block:: python
import numpy as np
import paddle
from paddle.static import InputSpec
paddle.disable_static()
x = paddle.to_tensor(np.ones([2, 2], np.float32))
x_spec = InputSpec.from_tensor(x, name='x')
print(x_spec) # InputSpec(shape=(2, 2), dtype=VarType.FP32, name=x)
.. note::
If a new name is not specified in ``from_tensor`` , the name from source Tensor is used by default.
1.3 Constructed from numpy.ndarray
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
An InputSpec object can also be created directly from an Numpy.ndarray by using the ``inputSpec.from_numpy`` method. It has same ``shape`` and ``dtype`` as the source ndarray. See example as follows:
.. code-block:: python
import numpy as np
from paddle.static import InputSpec
x = np.ones([2, 2], np.float32)
x_spec = InputSpec.from_numpy(x, name='x')
print(x_spec) # InputSpec(shape=(2, 2), dtype=VarType.FP32, name=x)
.. note::
If a new name is not specified in ``from_numpy`` , ``None`` is used by default.
2. Basic usage
------------------
Currently, the decorator ``paddle.jit.to_static`` support ``input_spec`` argument. It is used to specify signature information such as ``shape`` , ``dtype`` , ``name`` for each Tensor corresponding to argument from decorated function. Users do not have to feed actual data explicitly to trigger the deduction of the shape in the network. The ``input_spec`` argument specified in ``to_static`` will be analyzed to construct input placeholder of the network.
At the same time, the ``input_spec`` allow us to easily define input Tensor shape. For example, specifying shape as ``[None, 784]`` , where ``None`` represents a variable length dimension.
2.1 Decorator mode of to_static
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
A simple example as follows:
.. code-block:: python
import paddle
from paddle.jit import to_static
from paddle.static import InputSpec
from paddle.fluid.dygraph import Layer
class SimpleNet(Layer):
def __init__(self):
super(SimpleNet, self).__init__()
self.linear = paddle.nn.Linear(10, 3)
@to_static(input_spec=[InputSpec(shape=[None, 10], name='x'), InputSpec(shape=[3], name='y')])
def forward(self, x, y):
out = self.linear(x)
out = out + y
return out
paddle.disable_static()
net = SimpleNet()
# save static model for inference directly
paddle.jit.save(net, './simple_net')
In the above example, ``input_spec`` in ``to_static`` decorator is a list of InputSpec objects. It is used to specify signature information corresponding x and y. After instantiating SimpleNet, ``paddle.jit.save`` can be directly called to save the static graph model without executing any other code.
.. note::
1. Only InputSpec objects are supported in input_spec argument, and types such as int, float, etc. are not supported temporarily.
2. If you specify the input_spec argument, you need to add the corresponding InputSpec object for all non-default parameters of the decorated function. As above sample, only specifying signature information x is not supported.
3. If the decorated function includes non-tensor parameters and input_spec is specified, make sure that the non-tensor parameters of the function have default values, such as ``forward(self, x, use_bn=False)`` .
2.2 Call to_static directly
^^^^^^^^^^^^^^^^^^^^^^^^^^^
If we want to train model in dygraph mode and only expect to save the inference model after training with specified the signature information. We can call ``to_static`` function directly while saving the model. See example as follows:
.. code-block:: python
class SimpleNet(Layer):
def __init__(self):
super(SimpleNet, self).__init__()
self.linear = paddle.nn.Linear(10, 3)
def forward(self, x, y):
out = self.linear(x)
out = out + y
return out
paddle.disable_static()
net = SimpleNet()
# train process (Pseudo code)
for epoch_id in range(10):
train_step(net, train_reader)
net = to_static(net, input_spec=[InputSpec(shape=[None, 10], name='x'), InputSpec(shape=[3], name='y')])
# save static model for inference directly
paddle.jit.save(net, './simple_net')
In the above example, ``to_static(net, input_spec=...)`` can be used to process the model after training. Paddle will recursively convert forward function to get the complete static program according to ``input_spec`` information. Meanwhile, it includes the trained parameters.
2.3 Support list and dict derivation
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
In the above two examples, the arguments of the decorated forward function correspond to the InputSpec one to one. But when the decorated function takes arguments with a list or dict type, ``input_spec`` needs to have the same nested structure as the arguments.
If a function takes an argument of type list, the element in the ``input_spec`` must also be an InputSpec list containing the same elements. A simple example as follows:
.. code-block:: python
class SimpleNet(Layer):
def __init__(self):
super(SimpleNet, self).__init__()
self.linear = paddle.nn.Linear(10, 3)
@to_static(input_spec=[[InputSpec(shape=[None, 10], name='x'), InputSpec(shape=[3], name='y')]])
def forward(self, inputs):
x, y = inputs[0], inputs[1]
out = self.linear(x)
out = out + y
return out
The length of ``input_spec`` is 1 corresponding to argument inputs in forward function. ``input_spec[0]`` contains two InputSpec objects corresponding to two Tensor signature information of inputs.
If a function takes an argument of type dict, the element in the ``input_spec`` must also be an InputSpec dict containing the same keys. A simple example as follows:
.. code-block:: python
class SimpleNet(Layer):
def __init__(self):
super(SimpleNet, self).__init__()
self.linear = paddle.nn.Linear(10, 3)
@to_static(input_spec=[InputSpec(shape=[None, 10], name='x'), {'x': InputSpec(shape=[3], name='bias')}])
def forward(self, x, bias_info):
x_bias = bias_info['x']
out = self.linear(x)
out = out + x_bias
return out
The length of ``input_spec`` is 2 corresponding to arguments x and bias_info in forward function. The last element of ``input_spec`` is a InputSpec dict with same key corresponding to signature information of bias_info.
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册