Skip to content

Commit ff5804f

Browse files
committed
refine content
1 parent 6471f1b commit ff5804f

File tree

1 file changed

+83
-81
lines changed

1 file changed

+83
-81
lines changed

docs/guides/04_dygraph_to_static/basic_usage_cn.md

Lines changed: 83 additions & 81 deletions
Original file line numberDiff line numberDiff line change
@@ -35,86 +35,6 @@ net = paddle.jit.to_static(net) # 动静转换
3535
<img src="https://raw.githubusercontent.com/PaddlePaddle/docs/develop/docs/guides/04_dygraph_to_static/images/to_static_train.png" style="zoom:50%" />
3636

3737

38-
### 1.1 动态图 layer 生成 Program
39-
40-
上述样例中的 ``forward`` 函数包含两行组网代码: ``Linear````add`` 操作。以 ``Linear`` 为例,在 Paddle 的框架底层,每个 Paddle 的组网 API 的实现包括两个分支:
41-
42-
```python
43-
44-
class Linear(...):
45-
def __init__(self, ...):
46-
# ...(略)
47-
48-
def forward(self, input):
49-
50-
if in_dygraph_mode(): # 动态图分支
51-
core.ops.matmul(input, self.weight, pre_bias, ...)
52-
return out
53-
else: # 静态图分支
54-
self._helper.append_op(type="matmul", inputs=inputs, ...) # <----- 生成一个 Op
55-
if self.bias is not None:
56-
self._helper.append_op(type='elementwise_add', ...) # <----- 生成一个 Op
57-
58-
return out
59-
```
60-
61-
动态图 ``layer`` 生成 ``Program`` ,其实是开启 ``paddle.enable_static()`` 时,在静态图下逐行执行用户定义的组网代码,依次添加(对应 ``append_op`` 接口) 到默认的主 Program(即 ``main_program`` ) 中。
62-
63-
### 1.2 动态图 Tensor 转为静态图 Variable
64-
65-
上面提到,所有的组网代码都会在静态图模式下执行,以生成完整的 ``Program``**但静态图 ``append_op`` 有一个前置条件必须满足:**
66-
67-
> **前置条件**:append_op() 时,所有的 inputs,outputs 必须都是静态图的 Variable 类型,不能是动态图的 Tensor 类型。
68-
69-
70-
**原因**:静态图下,操作的都是**描述类单元**:计算相关的 ``OpDesc`` ,数据相关的 ``VarDesc`` 。可以分别简单地理解为 ``Program`` 中的 ``Op````Variable``
71-
72-
因此,在动转静时,我们在需要在**某个统一的入口处**,将动态图 ``Layers````Tensor`` 类型(包含具体数据)的 ``Weight````Bias`` 等变量转换为**同名的静态图 ``Variable``**
73-
74-
+ ParamBase &rarr; Parameters
75-
+ VarBase &rarr; Variable
76-
77-
技术实现上,我们选取了框架层面两个地方作为类型**转换的入口**
78-
79-
+ ``Paddle.nn.Layer`` 基类的 ``__call__`` 函数
80-
```python
81-
def __call__(self, *inputs, **kwargs):
82-
# param_guard 会对将 Tensor 类型的 Param 和 buffer 转为静态图 Variable
83-
with param_guard(self._parameters), param_guard(self._buffers):
84-
# ... forward_pre_hook 逻辑
85-
86-
outputs = self.forward(*inputs, **kwargs) # 此处为forward函数
87-
88-
# ... forward_post_hook 逻辑
89-
90-
return outpus
91-
```
92-
93-
+ ``Block.append_op`` 函数中,生成 ``Op`` 之前
94-
```python
95-
def append_op(self, *args, **kwargs):
96-
if in_dygraph_mode():
97-
# ... (动态图分支)
98-
else:
99-
inputs=kwargs.get("inputs", None)
100-
outputs=kwargs.get("outputs", None)
101-
# param_guard 会确保将 Tensor 类型的 inputs 和 outputs 转为静态图 Variable
102-
with param_guard(inputs), param_guard(outputs):
103-
op = Operator(
104-
block=self,
105-
desc=op_desc,
106-
type=kwargs.get("type", None),
107-
inputs=inputs,
108-
outputs=outputs,
109-
attrs=kwargs.get("attrs", None))
110-
```
111-
112-
113-
以上,是动态图转为静态图的两个核心逻辑,总结如下:
114-
115-
+ 动态图 ``layer`` 调用在动转静时会走底层 ``append_op`` 的分支,以生成 ``Program``
116-
+ 动态图 ``Tensor`` 转为静态图 ``Variable`` ,并确保编译期的 ``InferShape`` 正确执行
117-
11838

11939
## 二、 输入层 InputSpec
12040

@@ -419,6 +339,89 @@ def depend_tensor_while(x):
419339

420340
## 五、 Parameters 与 Buffers
421341

342+
### 1.1 动态图 layer 生成 Program
343+
344+
文档开始的样例中 ``forward`` 函数包含两行组网代码: ``Linear````add`` 操作。以 ``Linear`` 为例,在 Paddle 的框架底层,每个 Paddle 的组网 API 的实现包括两个分支:
345+
346+
```python
347+
348+
class Linear(...):
349+
def __init__(self, ...):
350+
# ...(略)
351+
352+
def forward(self, input):
353+
354+
if in_dygraph_mode(): # 动态图分支
355+
core.ops.matmul(input, self.weight, pre_bias, ...)
356+
return out
357+
else: # 静态图分支
358+
self._helper.append_op(type="matmul", inputs=inputs, ...) # <----- 生成一个 Op
359+
if self.bias is not None:
360+
self._helper.append_op(type='elementwise_add', ...) # <----- 生成一个 Op
361+
362+
return out
363+
```
364+
365+
动态图 ``layer`` 生成 ``Program`` ,其实是开启 ``paddle.enable_static()`` 时,在静态图下逐行执行用户定义的组网代码,依次添加(对应 ``append_op`` 接口) 到默认的主 Program(即 ``main_program`` ) 中。
366+
367+
### 1.2 动态图 Tensor 转为静态图 Variable
368+
369+
上面提到,所有的组网代码都会在静态图模式下执行,以生成完整的 ``Program``**但静态图 ``append_op`` 有一个前置条件必须满足:**
370+
371+
> **前置条件**:append_op() 时,所有的 inputs,outputs 必须都是静态图的 Variable 类型,不能是动态图的 Tensor 类型。
372+
373+
374+
**原因**:静态图下,操作的都是**描述类单元**:计算相关的 ``OpDesc`` ,数据相关的 ``VarDesc`` 。可以分别简单地理解为 ``Program`` 中的 ``Op````Variable``
375+
376+
因此,在动转静时,我们在需要在**某个统一的入口处**,将动态图 ``Layers````Tensor`` 类型(包含具体数据)的 ``Weight````Bias`` 等变量转换为**同名的静态图 ``Variable``**
377+
378+
+ ParamBase &rarr; Parameters
379+
+ VarBase &rarr; Variable
380+
381+
技术实现上,我们选取了框架层面两个地方作为类型**转换的入口**
382+
383+
+ ``Paddle.nn.Layer`` 基类的 ``__call__`` 函数
384+
```python
385+
def __call__(self, *inputs, **kwargs):
386+
# param_guard 会对将 Tensor 类型的 Param 和 buffer 转为静态图 Variable
387+
with param_guard(self._parameters), param_guard(self._buffers):
388+
# ... forward_pre_hook 逻辑
389+
390+
outputs = self.forward(*inputs, **kwargs) # 此处为forward函数
391+
392+
# ... forward_post_hook 逻辑
393+
394+
return outpus
395+
```
396+
397+
+ ``Block.append_op`` 函数中,生成 ``Op`` 之前
398+
```python
399+
def append_op(self, *args, **kwargs):
400+
if in_dygraph_mode():
401+
# ... (动态图分支)
402+
else:
403+
inputs=kwargs.get("inputs", None)
404+
outputs=kwargs.get("outputs", None)
405+
# param_guard 会确保将 Tensor 类型的 inputs 和 outputs 转为静态图 Variable
406+
with param_guard(inputs), param_guard(outputs):
407+
op = Operator(
408+
block=self,
409+
desc=op_desc,
410+
type=kwargs.get("type", None),
411+
inputs=inputs,
412+
outputs=outputs,
413+
attrs=kwargs.get("attrs", None))
414+
```
415+
416+
417+
以上,是动态图转为静态图的两个核心逻辑,总结如下:
418+
419+
+ 动态图 ``layer`` 调用在动转静时会走底层 ``append_op`` 的分支,以生成 ``Program``
420+
+ 动态图 ``Tensor`` 转为静态图 ``Variable`` ,并确保编译期的 ``InferShape`` 正确执行
421+
422+
423+
### 1.3 Buffer 变量
424+
422425
**什么是 ``Buffers`` 变量?**
423426

424427
+ **Parameters**``persistable````True`` ,且每个 batch 都被 Optimizer 更新的变量
@@ -471,4 +474,3 @@ class SimpleNet(paddle.nn.Layer):
471474
总结一下 ``buffers`` 的用法:
472475

473476
+ 若某个非 ``Tensor`` 数据需要当做 ``Persistable`` 的变量序列化到磁盘,则最好在 ``__init__`` 中调用 ``self.XX= paddle.to_tensor(xx)`` 接口转为 ``buffer`` 变量
474-

0 commit comments

Comments
 (0)