Skip to content

paddle.save/load2.1 #3477

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 18 commits into from
May 14, 2021
30 changes: 28 additions & 2 deletions doc/paddle/api/paddle/fluid/dygraph/jit/save_cn.rst
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ save

.. py:function:: paddle.jit.save(layer, path, input_spec=None, **configs)

将输入的 ``Layer`` 存储为 ``paddle.jit.TranslatedLayer`` 格式的模型,载入后可用于预测推理或者fine-tune训练。
将输入的 ``Layer`` 或 ``function`` 存储为 ``paddle.jit.TranslatedLayer`` 格式的模型,载入后可用于预测推理或者fine-tune训练。

该接口会将输入 ``Layer`` 转写后的模型结构 ``Program`` 和所有必要的持久参数变量存储至输入路径 ``path`` 。

Expand All @@ -16,9 +16,12 @@ save
- ``paddle.static.load_inference_model``
- 其他预测库API

.. note::
当使用 ``paddle.jit.save`` 保存 ``function`` 时, ``function`` 不能包含参数变量。如果必须保存参数变量,请用Layer封装function,然后按照处理Layer的方式调用相应的API。

参数
:::::::::
- layer (Layer) - 需要存储的 ``Layer`` 对象
- layer (Layer|function) - 需要存储的 ``Layer`` 对象或者 ``function``
- path (str) - 存储模型的路径前缀。格式为 ``dirname/file_prefix`` 或者 ``file_prefix`` 。
- input_spec (list[InputSpec|Tensor], 可选) - 描述存储模型forward方法的输入,可以通过InputSpec或者示例Tensor进行描述。如果为 ``None`` ,所有原 ``Layer`` forward方法的输入变量将都会被配置为存储模型的输入变量。默认为 ``None``。
- **configs (dict, 可选) - 其他用于兼容的存储配置选项。这些选项将来可能被移除,如果不是必须使用,不推荐使用这些配置选项。默认为 ``None``。目前支持以下配置选项:(1) output_spec (list[Tensor]) - 选择存储模型的输出目标。默认情况下,所有原 ``Layer`` forward方法的返回值均会作为存储模型的输出。如果传入的 ``output_spec`` 列表不是所有的输出变量,存储的模型将会根据 ``output_spec`` 所包含的结果被裁剪。
Expand All @@ -32,6 +35,7 @@ save

.. code-block:: python

# example 1: save layer
import numpy as np
import paddle
import paddle.nn as nn
Expand Down Expand Up @@ -98,3 +102,25 @@ save
# save
path = "example_model/linear"
paddle.jit.save(layer, path)

# example 2: save function
import paddle
from paddle.static import InputSpec


def save_function():
@paddle.jit.to_static
def fun(inputs):
return paddle.tanh(inputs)

path = 'test_jit_save_load_function_1/func'
inps = paddle.rand([3, 6])
origin = fun(inps)

paddle.jit.save(fun, path)
load_func = paddle.jit.load(path)

load_result = load_func(inps)
print((load_result - origin).abs().max() < 1e-10)

save_function()
72 changes: 72 additions & 0 deletions doc/paddle/api/paddle/fluid/framework/Program_cn.rst
Original file line number Diff line number Diff line change
Expand Up @@ -469,3 +469,75 @@ list[ :ref:`api_guide_parameter` ],一个包含当前Program中所有参数的
# Here print(param) will print out all the properties of a parameter,
# including name, type and persistable, you can access to specific
# property of a parameter, such as param.name, param.type

.. py:method:: state_dict(mode='all', scope=None)

获取当前 ``Program`` 持久性变量。并将所有持久性变量s存放在dict结构中。
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

这里的s要去掉吗

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done, thx.


参数
:::::::::
- mode (str, 可选) - 获取何种持久性变量。目前支持以下选项: (1) 'opt':获得优化器的持久性变量放在dict结构中; (2) 'param':获得组网中的持久性变量放在dict结构中,不包含优化器中的持久性变量; (3) 'all':获得组网和优化器中的持久性变量放在dict结构中;默认值为'all'。
- scope (Scope, 可选) - 如果scope为 ``None`` ,通过 `paddle.static.global_scope()` 获取全局/默认作用域实例,并从中获取 ``state_dict`` ;否则从指定的 ``scope`` 获取 ``state_dict`` 。默认值为 ``None`` 。

返回
:::::::::
dict, 包含持久性变量的dict,键值是持久性变量的名字,值为持久性变量。

代码示例
:::::::::

.. code-block:: python

import paddle
import paddle.static as static

paddle.enable_static()

x = static.data(name="x", shape=[10, 10], dtype='float32')
y = static.nn.fc(x, 10)
z = static.nn.fc(y, 10)

place = paddle.CPUPlace()
exe = static.Executor(place)
exe.run(static.default_startup_program())
prog = static.default_main_program()

path = "./temp/model.pdparams"
paddle.save(prog.state_dict(), path)

.. py:method:: set_state_dict(state_dict, scope=None)

将 ``state_dict`` 中的持久性变量设置到 ``Program`` 中。

参数
:::::::::
- state_dict (dict) - 包含持久性变量的字典。键值是持久性变量的名字,值为持久性变量。
- scope (Scope, 可选) - 如果scope为 ``None`` ,通过 `paddle.static.global_scope()` 获取全局/默认作用域实例,并将 ``state_dict`` 中参数和可持久性buffers设置到这个作用域中;否则将 ``state_dict`` 设置到指定的 ``scope`` 中。默认值为 ``None`` 。

返回
:::::::::
None

代码示例
:::::::::

.. code-block:: python

import paddle
import paddle.static as static

paddle.enable_static()

x = static.data(name="x", shape=[10, 10], dtype='float32')
y = static.nn.fc(x, 10)
z = static.nn.fc(y, 10)

place = paddle.CPUPlace()
exe = static.Executor(place)
exe.run(static.default_startup_program())
prog = static.default_main_program()

path = "./temp/model.pdparams"
paddle.save(prog.state_dict(), path)
state_dict_load = paddle.load(path)
prog.set_state_dict(state_dict_load)
89 changes: 89 additions & 0 deletions doc/paddle/api/paddle/fluid/framework/Variable_cn.rst
Original file line number Diff line number Diff line change
Expand Up @@ -114,6 +114,95 @@ Variable
print("new var's dtype is: {}".format(new_variable.dtype))


.. py:method:: get_value(scope=None)

获取 :ref:`api_guide_Variable` 的值。

参数
:::::::::
- scope ( Scope,可选 ) - 从指定的 ``scope`` 中获取 :ref:`api_guide_Variable` 的值。如果 ``scope`` 为 ``None`` ,通过 `paddle.static.global_scope()` 获取全局/默认作用域实例,并从中获取 :ref:`api_guide_Variable` 的值;否则,从指定的 ``scope`` 中获取 :ref:`api_guide_Variable` 的值。

返回
:::::::::
Tensor, :ref:`api_guide_Variable` 的值

代码示例
::::::::::

.. code-block:: python

import paddle
import paddle.static as static
import numpy as np

paddle.enable_static()

x = static.data(name="x", shape=[10, 10], dtype='float32')

y = static.nn.fc(x, 10, name='fc')
place = paddle.CPUPlace()
exe = static.Executor(place)
prog = paddle.static.default_main_program()
exe.run(static.default_startup_program())
inputs = np.ones((10, 10), dtype='float32')
exe.run(prog, feed={'x': inputs}, fetch_list=[y, ])
path = 'temp/tensor_'
for var in prog.list_vars():
if var.persistable:
t = var.get_value()
paddle.save(t, path+var.name+'.pdtensor')

for var in prog.list_vars():
if var.persistable:
t_load = paddle.load(path+var.name+'.pdtensor')
var.set_value(t_load)


.. py:method:: set_value(value, scope=None)

将 ``value`` 设置为 :ref:`api_guide_Variable` 的值。

参数
:::::::::
- value ( Tensor|ndarray ) - :ref:`api_guide_Variable` 的值。
- scope ( Scope,可选 ) - 将 :ref:`api_guide_Variable` 的值设置到指定的 ``scope`` 中。如果 ``scope`` 为 ``None`` ,通过 `paddle.static.global_scope()` 获取全局/默认作用域实例,并将 :ref:`api_guide_Variable` 的值设置到这个用域实例中;否则,将 :ref:`api_guide_Variable` 的值设置到指定的 ``scope`` 中。

返回
:::::::::
None

代码示例
::::::::::

.. code-block:: python

import paddle
import paddle.static as static
import numpy as np

paddle.enable_static()

x = static.data(name="x", shape=[10, 10], dtype='float32')

y = static.nn.fc(x, 10, name='fc')
place = paddle.CPUPlace()
exe = static.Executor(place)
prog = paddle.static.default_main_program()
exe.run(static.default_startup_program())
inputs = np.ones((10, 10), dtype='float32')
exe.run(prog, feed={'x': inputs}, fetch_list=[y, ])
path = 'temp/tensor_'
for var in prog.list_vars():
if var.persistable:
t = var.get_value()
paddle.save(t, path+var.name+'.pdtensor')

for var in prog.list_vars():
if var.persistable:
t_load = paddle.load(path+var.name+'.pdtensor')
var.set_value(t_load)


属性
::::::::::::

Expand Down
4 changes: 2 additions & 2 deletions doc/paddle/api/paddle/fluid/io/save_cn.rst
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
save
-------------------------------

.. py:function:: paddle.static.save(program, model_path, pickle_protocol=2)
.. py:function:: paddle.static.save(program, model_path, protocol=2)

:api_attr: 声明式编程模式(静态图)

Expand All @@ -19,7 +19,7 @@ save
参数:
- **program** ( :ref:`cn_api_fluid_Program` ) – 要保存的Program。
- **model_path** (str) – 保存program的文件前缀。格式为 ``目录名称/文件前缀``。如果文件前缀为空字符串,会引发异常。
- **pickle_protocol** (int, 可选) – pickle模块的协议版本,默认值为2,取值范围是[2,4]。
- **protocol** (int, 可选) – pickle模块的协议版本,默认值为2,取值范围是[2,4]。在Python3环境中,推荐使用 ``protocol=4``

返回: 无

Expand Down
91 changes: 81 additions & 10 deletions doc/paddle/api/paddle/framework/io/load_cn.rst
Original file line number Diff line number Diff line change
Expand Up @@ -8,21 +8,20 @@ load
从指定路径载入可以在paddle中使用的对象实例。

.. note::
目前仅支持载入 Layer 或者 Optimizer 的 ``state_dict``
目前支持载入:Layer 或者 Optimizer 的 ``state_dict``,Layer对象,Tensor以及包含Tensor的嵌套list、tuple、dict,Program

.. note::
为了更高效地使用paddle存储的模型参数, ``paddle.load`` 支持从除 ``paddle.save`` 之外的其他save相关API的存储结果中载入 ``state_dict`` ,但是在不同场景中,参数 ``path`` 的形式有所不同:
1. 从 ``paddle.static.save`` 或者 ``paddle.Model().save(training=True)`` 的保存结果载入: ``path`` 需要是完整的文件名,例如 ``model.pdparams`` 或者 ``model.opt`` ;
2. 从 ``paddle.jit.save`` 或者 ``paddle.static.save_inference_model`` 或者 ``paddle.Model().save(training=False)`` 的保存结果载入: ``path`` 需要是路径前缀, 例如 ``model/mnist`` , ``paddle.load`` 会从 ``mnist.pdmodel`` 和 ``mnist.pdiparams`` 中解析 ``state_dict`` 的信息并返回。
3. 从paddle 1.x API ``paddle.fluid.io.save_inference_model`` 或者 ``paddle.fluid.io.save_params/save_persistables`` 的保存结果载入: ``path`` 需要是目录,例如 ``model`` ,此处model是一个文件夹路径。

.. note::
如果从 ``paddle.static.save`` 或者 ``paddle.static.save_inference_model`` 等静态图API的存储结果中载入 ``state_dict`` ,动态图模式下参数的结构性变量名将无法被恢复。在将载入的 ``state_dict`` 配置到当前Layer中时,需要配置 ``Layer.set_state_dict`` 的参数 ``use_structured_name=False`` 。
如果想进一步了解这个API,请参考:

.. toctree::
:maxdepth: 1

../../../../faq/save_cn.md

参数
:::::::::
- path (str) – 载入目标对象实例的路径。通常该路径是目标文件的路径,当从用于存储预测模型API的存储结果中载入state_dict时,该路径可能是一个文件前缀或者目录。
- **config (dict, 可选) - 其他用于兼容的载入配置选项。这些选项将来可能被移除,如果不是必须使用,不推荐使用这些配置选项。默认为 ``None``。目前支持以下配置选项:(1) model_filename (str) - paddle 1.x版本 ``save_inference_model`` 接口存储格式的预测模型文件名,原默认文件名为 ``__model__`` ; (2) params_filename (str) - paddle 1.x版本 ``save_inference_model`` 接口存储格式的参数文件名,没有默认文件名,默认将各个参数分散存储为单独的文件。
- **config (dict, 可选) - 其他用于兼容的载入配置选项。这些选项将来可能被移除,如果不是必须使用,不推荐使用这些配置选项。默认为 ``None``。目前支持以下配置选项:(1) model_filename (str) - paddle 1.x版本 ``save_inference_model`` 接口存储格式的预测模型文件名,原默认文件名为 ``__model__`` ; (2) params_filename (str) - paddle 1.x版本 ``save_inference_model`` 接口存储格式的参数文件名,没有默认文件名,默认将各个参数分散存储为单独的文件; (3) return_numpy(bool) - 如果被指定为 ``True`` ,``load`` 的结果中的Tensor会被转化为 ``numpy.ndarray`` ,默认为 ``False``

返回
:::::::::
Expand All @@ -33,10 +32,12 @@ Object,一个可以在paddle中使用的对象实例

.. code-block:: python

# example 1: dynamic graph
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

示例里面是不是没有Layer,Program,嵌套结构的示例,这个要补充一下吗?可能英文的也得补充

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done, thx.

import paddle

emb = paddle.nn.Embedding(10, 10)
layer_state_dict = emb.state_dict()

# save state_dict of emb
paddle.save(layer_state_dict, "emb.pdparams")

scheduler = paddle.optimizer.lr.NoamDecay(
Expand All @@ -45,7 +46,77 @@ Object,一个可以在paddle中使用的对象实例
learning_rate=scheduler,
parameters=emb.parameters())
opt_state_dict = adam.state_dict()

# save state_dict of optimizer
paddle.save(opt_state_dict, "adam.pdopt")
# save weight of emb
paddle.save(emb.weight, "emb.weight.pdtensor")

# load state_dict of emb
load_layer_state_dict = paddle.load("emb.pdparams")
# load state_dict of optimizer
load_opt_state_dict = paddle.load("adam.pdopt")
# load weight of emb
load_weight = paddle.load("emb.weight.pdtensor")

.. code-block:: python

# example 2: Load multiple state_dict at the same time
import paddle
from paddle import nn
from paddle.optimizer import Adam

layer = paddle.nn.Linear(3, 4)
adam = Adam(learning_rate=0.001, parameters=layer.parameters())
obj = {'model': layer.state_dict(), 'opt': adam.state_dict(), 'epoch': 100}
path = 'example/model.pdparams'
paddle.save(obj, path)
obj_load = paddle.load(path)


.. code-block:: python

# example 3: static graph
import paddle
import paddle.static as static

paddle.enable_static()

# create network
x = paddle.static.data(name="x", shape=[None, 224], dtype='float32')
z = paddle.static.nn.fc(x, 10)

place = paddle.CPUPlace()
exe = paddle.static.Executor(place)
exe.run(paddle.static.default_startup_program())
prog = paddle.static.default_main_program()
for var in prog.list_vars():
if list(var.shape) == [224, 10]:
tensor = var.get_value()
break

# save/load tensor
path_tensor = 'temp/tensor.pdtensor'
paddle.save(tensor, path_tensor)
load_tensor = paddle.load(path_tensor)

# save/load state_dict
path_state_dict = 'temp/model.pdparams'
paddle.save(prog.state_dict("param"), path_tensor)
load_state_dict = paddle.load(path_tensor)

.. code-block:: python

# example 4: load program
import paddle

paddle.enable_static()

data = paddle.static.data(
name='x_static_save', shape=(None, 224), dtype='float32')
y_static = z = paddle.static.nn.fc(data, 10)
main_program = paddle.static.default_main_program()
path = "example/main_program.pdmodel"
paddle.save(main_program, path)
load_main = paddle.load(path)
print(load_main)
Loading