diff --git a/docs/api/paddle/jit/save_cn.rst b/docs/api/paddle/jit/save_cn.rst
index 51bbeddde63..547a8fd7d78 100644
--- a/docs/api/paddle/jit/save_cn.rst
+++ b/docs/api/paddle/jit/save_cn.rst
@@ -34,4 +34,96 @@ save
代码示例
:::::::::
-COPY-FROM: paddle.jit.save
+ ```python
+ # example 1: save layer
+ import numpy as np
+ import paddle
+ import paddle.nn as nn
+ import paddle.optimizer as opt
+
+ BATCH_SIZE = 16
+ BATCH_NUM = 4
+ EPOCH_NUM = 4
+
+ IMAGE_SIZE = 784
+ CLASS_NUM = 10
+
+ # define a random dataset
+ class RandomDataset(paddle.io.Dataset):
+ def __init__(self, num_samples):
+ self.num_samples = num_samples
+
+ def __getitem__(self, idx):
+ image = np.random.random([IMAGE_SIZE]).astype('float32')
+ label = np.random.randint(0, CLASS_NUM, (1, )).astype('int64')
+ return image, label
+
+ def __len__(self):
+ return self.num_samples
+
+ class LinearNet(nn.Layer):
+ def __init__(self):
+ super(LinearNet, self).__init__()
+ self._linear = nn.Linear(IMAGE_SIZE, CLASS_NUM)
+
+ @paddle.jit.to_static
+ def forward(self, x):
+ return self._linear(x)
+
+ def train(layer, loader, loss_fn, opt):
+ for epoch_id in range(EPOCH_NUM):
+ for batch_id, (images, labels) in enumerate(loader()):
+ out = layer(images)
+ loss = loss_fn(out, labels)
+ loss.backward()
+ opt.step()
+ opt.clear_grad()
+ print("Epoch {} batch {}: loss = {}".format(
+ epoch_id, batch_id, np.mean(loss.numpy())))
+
+ # 1. train & save model.
+
+ # create network
+ layer = LinearNet()
+ loss_fn = nn.CrossEntropyLoss()
+ adam = opt.Adam(learning_rate=0.001, parameters=layer.parameters())
+
+ # create data loader
+ dataset = RandomDataset(BATCH_NUM * BATCH_SIZE)
+ loader = paddle.io.DataLoader(dataset,
+ batch_size=BATCH_SIZE,
+ shuffle=True,
+ drop_last=True,
+ num_workers=2)
+
+ # train
+ train(layer, loader, loss_fn, adam)
+
+ # save
+ path = "example_model/linear"
+ paddle.jit.save(layer, path)
+ ```
+
+ ```python
+ # 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/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()
+ ```
diff --git a/docs/guides/jit/basic_usage_cn.md b/docs/guides/jit/basic_usage_cn.md
index 7d0518c1a9a..eb80bddbe2c 100644
--- a/docs/guides/jit/basic_usage_cn.md
+++ b/docs/guides/jit/basic_usage_cn.md
@@ -882,6 +882,11 @@ class SimpleNet(Layer):
若被装饰函数的参数列表除了 Tensor 类型,还包含其他如 Int、 String 等非 Tensor 类型时,推荐在函数中使用 kwargs 形式定义非 Tensor 参数,如下述样例中的 ``use_act`` 参数。
```python
+import paddle
+from paddle.jit import to_static
+from paddle.nn import Layer
+from paddle.static import InputSpec
+
class SimpleNet(Layer):
def __init__(self, ):
super(SimpleNet, self).__init__()
@@ -896,11 +901,11 @@ class SimpleNet(Layer):
net = SimpleNet()
# 方式一:save inference model with use_act=False
-net = to_static(input_spec=[InputSpec(shape=[None, 10], name='x')])
+net = to_static(net, input_spec=[InputSpec(shape=[None, 10], name='x')])
paddle.jit.save(net, path='./simple_net')
# 方式二:save inference model with use_act=True
-net = to_static(input_spec=[InputSpec(shape=[None, 10], name='x'), True])
+net = to_static(net, input_spec=[InputSpec(shape=[None, 10], name='x'), True])
paddle.jit.save(net, path='./simple_net')
```
diff --git a/docs/guides/jit/case_analysis_cn.md b/docs/guides/jit/case_analysis_cn.md
index 81595f75b7b..42bc6b232bd 100644
--- a/docs/guides/jit/case_analysis_cn.md
+++ b/docs/guides/jit/case_analysis_cn.md
@@ -96,10 +96,10 @@
def forward(self, x):
out = self.linear(x) # [bs, 3]
- # 以下将 tensor 转为了 numpy 进行一系列操作
+ # 以下将 tensor 转为了 numpy array 进行一系列操作
x_data = x.numpy().astype('float32') # [bs, 10]
- weight = np.random.randn([10,3])
- mask = paddle.to_tensor(x_data * weight) # 此处又转回了 Tensor
+ weight = np.random.randn(10, 3)
+ mask = paddle.to_tensor(x_data @ weight) # 此处又转回了 Tensor
out = out * mask
return out
@@ -113,7 +113,7 @@ def forward(self, x):
out = self.linear(x) # [bs, 3]
weight = paddle.randn([10,3], 'float32')
- mask = x * weight
+ mask = paddle.matmul(x, weight)
out = out * mask
return out
@@ -129,7 +129,7 @@ def forward(self, x):
## 四、to_tensor() 的使用
-``paddle.to_tensor()`` 接口是动态图模型代码中使用比较频繁的一个接口。 ``to_tensor`` 功能强大,将可以将一个 ``scalar`` , ``list`` ,``tuple`` , ``numpy.ndarray`` 转为 ``paddle.Tensor`` 类型。
+``paddle.to_tensor()`` 接口是动态图模型代码中使用比较频繁的一个接口。 ``to_tensor`` 功能强大,可以将一个 ``scalar`` , ``list`` ,``tuple`` , ``numpy.ndarray`` 转为 ``paddle.Tensor`` 类型。
此接口是动态图独有的接口,在动转静时,会转换为 ``assign`` 接口:
@@ -193,14 +193,14 @@ class SimpleNet(paddle.nn.Layer):
动态图模型常常包含很多嵌套的子网络,建议各个自定义的子网络 ``sublayer`` **无论是否包含了参数,都继承 ``nn.Layer`` .**
-从 **Parameters 和 Buffers** 章节可知,有些 ``paddle.to_tensor`` 接口转来的 ``Tensor`` 也可能参与预测逻辑分支的计算,即模型导出时,也需要作为参数序列化保存到 ``.pdiparams`` 文件中。
+从 [**Parameters 和 Buffers**](https://www.paddlepaddle.org.cn/documentation/docs/zh/develop/guides/jit/principle_cn.html#buffer) 章节可知,有些 ``paddle.to_tensor`` 接口转来的 ``Tensor`` 也可能参与预测逻辑分支的计算,即模型导出时,也需要作为参数序列化保存到 ``.pdiparams`` 文件中。
> **原因**: 若某个 sublayer 包含了 buffer Variables,但却没有继承 ``nn.Layer`` ,则可能导致保存的 ``.pdiparams`` 文件缺失部分重要参数。
**举个例子:**
```python
-class SimpleNet(object): # <---- 继承 Object
+class SimpleNet(object): # <---- 继承 object
def __init__(self, mask):
super(SimpleNet, self).__init__()
self.linear = paddle.nn.Linear(10, 3) # <---- Linear 参数永远都不会被更新
@@ -215,7 +215,7 @@ class SimpleNet(object): # <---- 继承 Object
同时,所有继承 ``nn.Layer`` 的 ``sublayer`` 都建议:
-+ 重写 ``forward`` 函数,尽量避免重写 ``__call__``` 函数
++ 重写 ``forward`` 函数,尽量避免重写 ``__call__`` 函数
> ``__call__`` 函数通常会包含框架层面的一些通用的处理逻辑,比如 ``pre_hook`` 和 ``post_hook`` 。重写此函数可能会覆盖框架层面的逻辑。
+ 尽量将 ``forward`` 函数作为 sublayers 的调用入口
@@ -265,19 +265,23 @@ def forward(self, x):
model = SimpleNet()
model.eval() # <---- 一键切换分支,则只会导出 eval 相关的预测分支
-jit.save(mode, model_path)
+paddle.jit.save(model, model_path)
```
推荐使用 ``self.training`` 或其他非 Tensor 类型的 bool 值进行区分。
-此 flag 继承自 ``nn.Layer`` ,因此可通过 ``model.train()`` 和 ``model.eval()`` 来全局切换所有 sublayers 的分支状态。
+此 flag 继承自 ``paddle.nn.Layer`` ,因此可通过 ``model.train()`` 和 ``model.eval()`` 来全局切换所有 sublayers 的分支状态。
## 七、非 forward 函数导出
-`@to_static` 与 `jit.save` 接口搭配也支持导出非 forward 的其他函数,具体使用方式如下:
+`@paddle.jit.to_static` 与 `paddle.jit.save` 接口搭配也支持导出非 forward 的其他函数,具体使用方式如下:
```python
+import paddle
+from paddle.jit import to_static
+from paddle.static import InputSpec
+
class SimpleNet(paddle.nn.Layer):
def __init__(self):
super(SimpleNet, self).__init__()
@@ -300,24 +304,24 @@ net = SimpleNet()
net.eval()
# step 2: 定义 InputSpec 信息 (同上)
-x_spec = InputSpec(shape=[None, 3], dtype='float32', name='x')
+x_spec = InputSpec(shape=[None, 10], dtype='float32', name='x')
# step 3: @to_static 装饰
static_func = to_static(net.another_func, input_spec=[x_spec])
-# step 4: 调用 jit.save 接口
-net = paddle.jit.save(static_func, path='another_func')
+# step 4: 调用 paddle.jit.save 接口
+paddle.jit.save(static_func, path='another_func')
```
使用上的区别主要在于:
+ **`@to_static` 装饰**:导出其他函数时需要显式地用 `@to_static` 装饰,以告知动静转换模块将其识别、并转为静态图 Program;
-+ **`save`接口参数**:调用`jit.save`接口时,需将上述被`@to_static` 装饰后的函数作为**参数**;
++ **`save`接口参数**:调用`paddle.jit.save`接口时,需将上述被`@to_static` 装饰后的函数作为**参数**;
执行上述代码样例后,在当前目录下会生成三个文件:
```
another_func.pdiparams // 存放模型中所有的权重数据
-another_func.pdimodel // 存放模型的网络结构
+another_func.pdmodel // 存放模型的网络结构
another_func.pdiparams.info // 存放额外的其他信息
```
@@ -326,7 +330,7 @@ another_func.pdiparams.info // 存放额外的其他信息
## 八、再谈控制流
-前面[【控制流转写】(./basic_usage_cn.html#sikongzhiliuzhuanxie)]提到,不论控制流 ``if/for/while`` 语句是否需要转为静态图中的 ``cond_op/while_op`` ,都会先进行代码规范化,如 ``IfElse`` 语句会规范为如下范式:
+前面[【控制流转写】](./principle_cn.html#kongzhiliuzhuanxie)提到,不论控制流 ``if/for/while`` 语句是否需要转为静态图中的 ``cond_op/while_op`` ,都会先进行代码规范化,如 ``IfElse`` 语句会规范为如下范式:
```python
def true_fn_0(out):
@@ -348,7 +352,7 @@ out = convert_ifelse(paddle.mean(x) > 5.0, true_fn_0, false_fn_0, (x,), (x,), (o
当控制流中,出现了 ``list.append`` 类似语法时,情况会有一点点特殊。
-Paddle 框架中的 ``cond_op`` 和 [``while_loop``](https://www.paddlepaddle.org.cn/documentation/docs/zh/api/paddle/fluid/layers/while_loop_cn.html#cn-api-fluid-layers-while-loop) 对输入和返回类型有一个要求:
+Paddle 框架中的 [``cond_op``](https://www.paddlepaddle.org.cn/documentation/docs/zh/develop/api/paddle/static/nn/cond_cn.html#cond) 和 [``while_loop``](https://www.paddlepaddle.org.cn/documentation/docs/zh/develop/api/paddle/static/nn/while_loop_cn.html) 对输入和返回类型有一个要求:
> 输入或者返回类型必须是:LoDTensor 或者 LoDTensorArray
> 即:不支持其他非 LoDTensor 类型
diff --git a/docs/guides/jit/grammar_list_cn.md b/docs/guides/jit/grammar_list_cn.md
index 6963c2d2928..30ff5532d44 100644
--- a/docs/guides/jit/grammar_list_cn.md
+++ b/docs/guides/jit/grammar_list_cn.md
@@ -135,9 +135,9 @@ def break_usage(x):
break # <------- jump out of while loop when break ;
return tensor_idx
```
-当时输入 x = Tensor([1.0, 2.0 ,3.0]) 时,输出的 tensor_idx 是 Tensor([1])。
+当输入 x = Tensor([1.0, 2.0 ,3.0]) 时,输出的 tensor_idx 是 Tensor([1])。
-> 注:这里虽然 idx 是-1,但是返回值还是 Tensor。因为`tensor_idx` 在 while loop 中转化为了`Tensor`。
+> 注:这里虽然 tensor_idx 初始值是-1,但是返回值还是 Tensor。因为 `idx` 在 while loop 中转化为了只含一个索引值的 `Tensor`。
### 3.5 与、或、非
@@ -167,9 +167,11 @@ def and(x, y):
**主要逻辑:**
-动态图中可以直接用 Python 的类型转化语法来转化 Tensor 类型。如若 x 是 Tensor 时,float(x)可以将 x 的类型转化为 float。
+动态图中可以直接用 Python 的类型转化语法来转化 Tensor 类型。如若 x 是 Tensor 时(只支持含有一个元素的 Tensor ),
-动转静在运行时判断 x 是否是 Tensor,若是,则在动转静时使用静态图`cast`接口转化相应的 Tensor 类型。
+float(x) 可以将 x 的类型转化为 float。动转静在运行时判断 x 是否是 Tensor,若是,则在动转静时使用静态图 `cast` 接口
+
+转化相应的 Tensor 类型。
**使用样例**:
@@ -239,7 +241,7 @@ def recur_call(x):
def list_example(x, y):
a = [ x ] # < ------ 支持直接创建
a.append(x) # < ------ 支持调用 append、pop 操作
- a[1] = y # < ------ 支持下标修改 append
+ a[1] = y # < ------ 支持下标修改
return a[0] # < ------ 支持下标获取
```