You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Copy file name to clipboardExpand all lines: doc/design/program.md
+91-13Lines changed: 91 additions & 13 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -1,8 +1,10 @@
1
-
# Design Doc: ProgramDesc
1
+
# Design Doc: PaddlePaddle Programs
2
2
3
-
The basic structure of a PaddlePaddle program is some nested blocks, as a C++ or Java program.
3
+
## Compile and Execution
4
+
5
+
A PaddlePaddle program consists of two parts -- the first generates a `ProgramDesc` protobuf message that describes the program, and the second runs this message using a C++ class `Executor`.
4
6
5
-
As described in [graph.md](./graph.md), the first five lines of the following PaddlePaddle program
7
+
A simple example PaddlePaddle program can be found in [graph.md](./graph.md):
6
8
7
9
```python
8
10
x = layer.data("images")
@@ -13,36 +15,112 @@ optimize(cost)
13
15
train(cost, reader=mnist.train())
14
16
```
15
17
16
-
generates, or compiles, a PaddelPaddle program, which is represented by the following protobuf message:
18
+
The first five lines of the following PaddlePaddle program generates, or, compiles, the `ProgramDesc` message. The last line runs it.
17
19
18
-
```protobuf
19
-
message ProgramDesc {
20
-
repeated BlockDesc blocks = 1;
20
+
## Programs and Blocks
21
+
22
+
The basic structure of a PaddlePaddle program is some nested blocks, as a C++ or Java program.
23
+
24
+
- program: some nested blocks
25
+
-[block](./block.md):
26
+
- some local variable definitions, and
27
+
- a sequence of operators
28
+
29
+
The concept of block comes from usual programs. For example, the following C++ program has three blocks:
30
+
31
+
```c++
32
+
intmain() { // block 0
33
+
int i = 0;
34
+
if (i < 10) { // block 1
35
+
for (int j = 0; j < 10; j++) { // block 2
36
+
}
37
+
}
38
+
return 0;
21
39
}
40
+
```
41
+
42
+
The following PaddlePaddle program has three blocks:
43
+
44
+
```python
45
+
import paddle as pd // block 0
46
+
47
+
x = minibatch([10, 20, 30]) # shape=[None, 1]
48
+
y = var(1) # shape=[1], value=1
49
+
z = minibatch([10, 20, 30]) # shape=[None, 1]
50
+
cond = larger_than(x, 15) # [false, true, true]
22
51
52
+
ie = pd.ifelse()
53
+
with ie.true_block(): // block 1
54
+
d = pd.layer.add_scalar(x, y)
55
+
ie.output(d, pd.layer.softmax(d))
56
+
with ie.false_block(): // block 2
57
+
d = pd.layer.fc(z)
58
+
ie.output(d, d+1)
59
+
o1, o2 = ie(cond)
60
+
```
61
+
62
+
## `BlockDesc` and `ProgramDesc`
63
+
64
+
All protobuf messages are defined in `framework.proto`.
65
+
66
+
`BlockDesc` is straight-forward -- it includes local variable definitions, `vars`, and a sequence of operators, `ops`.
67
+
68
+
```protobuf
23
69
message BlockDesc {
24
70
required int32 parent = 1;
25
71
repeated VarDesc vars = 2;
26
72
repeated OpDesc ops = 3;
27
73
}
74
+
```
75
+
76
+
The parent ID indicates the parent block so that operators in a block can refer to variables defined locally and also those defined in their ancestor blocks.
77
+
78
+
All hierarchical blocks in a program are flattened and stored in an array. The block ID is the index of the block in this array.
79
+
80
+
```protobuf
81
+
message ProgramDesc {
82
+
repeated BlockDesc blocks = 1;
83
+
}
84
+
```
85
+
86
+
87
+
### Global Block
28
88
89
+
The global block is the first one in the above array.
90
+
91
+
## Operators that Use Blocks
92
+
93
+
In the above example, the operator `IfElseOp` has two blocks -- the true branch and the false branch.
94
+
95
+
The definition of `OpDesc` shows that an operator could have some attributes:
96
+
97
+
```protobuf
29
98
message OpDesc {
30
99
AttrDesc attrs = 1;
31
100
...
32
101
}
102
+
```
103
+
104
+
and an attribute could be of type block, which is, in fact, a block ID as described above:
33
105
106
+
```
34
107
message AttrDesc {
35
-
required AttrType type = 1;
108
+
required string name = 1;
36
109
37
-
// index into ProgramDesc::blocks when type==BLOCK
38
-
optional int32 block = 2;
110
+
enum AttrType {
111
+
INT = 1,
112
+
STRING = 2,
113
+
...
114
+
BLOCK = ...
115
+
}
116
+
required AttrType type = 2;
117
+
118
+
optional int32 block = 10; // when type == BLOCK
39
119
...
40
120
}
41
121
```
42
122
43
-
When each of the first five lines runs, related Python function, e.g., `layer.fc`, calls C++ InferShape functions. This InferShape function needs to access the properties of VarDesc's accessed by the current OpDesc. These VarDesc's might not be defined in the current block, but in some ancestor blocks. This requires that we can trace the parent of a block.
44
-
45
-
A nested block is often an attribute of an operator, most likely, an IfElseOp or a WhileOp. In above solution, all blocks are in `ProgramDesc::blocks`, this implicitly assigns a zero-based ID to each block -- the index of the block in `ProgramDesc::blocks`. So that `AttrDesc::block` could be an integer block ID.
123
+
## InferShape
46
124
47
125
With this design, the InferShape function should take the following parameters:
0 commit comments