InputSpec 功能介绍

    因此,Paddle 提供了 InputSpec 接口,可以更加便捷地执行动转静功能,以及定制化输入 Tensor 的 shape 、name 等信息。

    InputSpec 接口在 paddle.static 目录下,用于描述一个 Tensor 的签名信息:shape、dtype、name。使用样例如下:

    InputSpec 初始化中的只有 shape 是必须参数, dtypename 可以缺省,默认取值分别为 float32None

    1.2 根据 Tensor 构造 InputSpec 对象

    可以借助 InputSpec.from_tensor 方法,从一个 Tensor 直接创建 InputSpec 对象,其拥有与源 Tensor 相同的 shapedtype 。使用样例如下:

    1. import numpy as np
    2. import paddle
    3. from paddle.static import InputSpec
    4. x = paddle.to_tensor(np.ones([2, 2], np.float32))
    5. x_spec = InputSpec.from_tensor(x, name='x')
    6. print(x_spec) # InputSpec(shape=(2, 2), dtype=VarType.FP32, name=x)

    注解

    若未在 from_tensor 中指定新的name,则默认使用与源Tensor相同的name。

    也可以借助 InputSpec.from_numpy 方法,从一个 Numpy.ndarray 直接创建 InputSpec 对象,其拥有与源 ndarray 相同的 shapedtype 。使用样例如下:

    注解

    二、基本使用方法

    动转静 paddle.jit.to_static 装饰器支持 input_spec 参数,用于指定被装饰函数每个 Tensor 类型输入参数的 shapedtypename 等签名信息。不必再显式地传入 Tensor 数据以触发网络层 shape 的推导。 Paddle 会解析 to_static 中指定的 input_spec 参数,构建网络的起始输入,进行后续的模型组网。

    同时,借助 input_spec 参数,可以自定义输入 Tensor 的 shape ,比如指定 shape 为 [None, 784] ,其中 None 表示变长的维度。

    2.1 to_static 装饰器模式

    如下是一个简单的使用样例:

    1. import paddle
    2. from paddle.jit import to_static
    3. from paddle.static import InputSpec
    4. from paddle.fluid.dygraph import Layer
    5. class SimpleNet(Layer):
    6. def __init__(self):
    7. super(SimpleNet, self).__init__()
    8. self.linear = paddle.nn.Linear(10, 3)
    9. @to_static(input_spec=[InputSpec(shape=[None, 10], name='x'), InputSpec(shape=[3], name='y')])
    10. def forward(self, x, y):
    11. out = self.linear(x)
    12. out = out + y
    13. return out
    14. net = SimpleNet()
    15. # save static model for inference directly
    16. paddle.jit.save(net, './simple_net')

    在上述的样例中, to_static 装饰器中的 input_spec 为一个 InputSpec 对象组成的列表,用于依次指定参数 x 和 y 对应的 Tensor 签名信息。在实例化 SimpleNet 后,可以直接调用 paddle.jit.save 保存静态图模型,不需要执行任何其他的代码。

    注解

    1. input_spec 参数中只支持 InputSpec 对象,暂不支持如 int 、 float 等类型。

    2. 若指定 input_spec 参数,则需为被装饰函数的所有必选参数都添加对应的 InputSpec 对象,如上述样例中,不支持仅指定 x 的签名信息。

    3. 若被装饰函数中包括非 Tensor 参数,且指定了 input_spec ,请确保函数的非 Tensor 参数都有默认值,如 forward(self, x, use_bn=False)

    如上述样例代码中,在完成训练后,可以借助 to_static(net, input_spec=...) 形式对模型实例进行处理。Paddle 会根据 input_spec 信息对 forward 函数进行递归的动转静,得到完整的静态图,且包括当前训练好的参数数据。

    2.3 支持 list 和 dict 推导

    上述两个样例中,被装饰的 forward 函数的参数均为 Tensor 。这种情况下,参数个数必须与 InputSpec 个数相同。但当被装饰的函数参数为list或dict类型时,input_spec 需要与函数参数保持相同的嵌套结构。

    当函数的参数为 list 类型时,input_spec 列表中对应元素的位置,也必须是包含相同元素的 InputSpec 列表。使用样例如下:

    1. class SimpleNet(Layer):
    2. def __init__(self):
    3. super(SimpleNet, self).__init__()
    4. self.linear = paddle.nn.Linear(10, 3)
    5. @to_static(input_spec=[[InputSpec(shape=[None, 10], name='x'), InputSpec(shape=[3], name='y')]])
    6. def forward(self, inputs):
    7. x, y = inputs[0], inputs[1]
    8. out = self.linear(x)
    9. out = out + y
    10. return out

    其中 input_spec 参数是长度为 1 的 list ,对应 forward 函数的 inputs 参数。 input_spec[0] 包含了两个 InputSpec 对象,对应于参数 inputs 的两个 Tensor 签名信息。

    当函数的参数为dict时, 列表中对应元素的位置,也必须是包含相同键(key)的 InputSpec 列表。使用样例如下:

    其中 input_spec 参数是长度为 2 的 list ,对应 forward 函数的 x 和 bias_info 两个参数。 input_spec 的最后一个元素是包含键名为 x 的 InputSpec 对象的 dict ,对应参数 bias_info 的 Tensor 签名信息。

    目前,to_static 装饰器中的 input_spec 参数仅接收 InputSpec 类型对象。若被装饰函数的参数列表除了 Tensor 类型,还包含其他如 Int、 String 等非 Tensor 类型时,推荐在函数中使用 kwargs 形式定义非 Tensor 参数,如下述样例中的 use_act 参数。

    1. class SimpleNet(Layer):
    2. super(SimpleNet, self).__init__()
    3. self.linear = paddle.nn.Linear(10, 3)
    4. self.relu = paddle.nn.ReLU()
    5. @to_static(input_spec=[InputSpec(shape=[None, 10], name='x')])
    6. def forward(self, x, use_act=False):
    7. out = self.linear(x)
    8. if use_act:
    9. out = self.relu(out)
    10. return out
    11. net = SimpleNet()
    12. adam = paddle.optimizer.Adam(parameters=net.parameters())
    13. # train model
    14. batch_num = 10
    15. for step in range(batch_num):
    16. x = paddle.rand([4, 10], 'float32')
    17. use_act = (step%2 == 0)
    18. out = net(x, use_act)
    19. loss = paddle.mean(out)
    20. loss.backward()
    21. adam.minimize(loss)
    22. net.clear_gradients()
    23. paddle.jit.save(net, model_path='./simple_net')

    在上述样例中,step 为奇数时,use_act 取值为 False ; step 为偶数时, use_act 取值为 True 。动转静支持非 Tensor 参数在训练时取不同的值,且保证了取值不同的训练过程都可以更新模型的网络参数,行为与动态图一致。

    更多关于动转静 搭配 paddle.jit.save/load 的使用方式,可以参考 。