@@ -17,24 +17,55 @@ Since we design our Python API concepts based on `compile-time`, we try to map o
| Python Class | Compile-time protobuf |
| --- | --- |
| Program | ProgramDesc |
| Block | BlockDesc |
| Operator | OpDesc |
| Variable | VarDesc |
### Program
`Program` is the description of the whole training process and there can only be one `Program` object, which is created automatically by the system at the very beginning. `Program` is formed by a series of `Block`.
`Program` will create the first block in its constructor. The first block is called 'global block'. It is where all parameters are stored.
### Block
Block is just like programming languages `{}`, which contains many operators and variables. There are two data fields in `Block`. 1) An associate map, whose key is variable name and value is variable itself; 2) A list of operators.
The block is hierarchical because PaddlePaddle supports RNN and IfElse. For example, RNN is like `for-loop` in programming languages. There is new `block` inside a `for-loop`. To represent hierarchies, `Block` stores the `parent Block` inside. If `parent=None`, the `Block` is the outermost block, i.e., the `global` block.
The block is hierarchical because PaddlePaddle supports RNN and IfElse. For example, RNN is like `for-loop` in programming languages. There is new `block` inside a `for-loop`. To represent hierarchies, `Block` stores the index of `parent Block` inside. The 'index' means the block's position in `Program`'s `blocks`. If `parent_idx=None`, the block itself is the outermost block, i.e., the 'global block'.
```python
classBlock(objects):
def__init__(self,parent=None):
def__init__(self,parent_idx,idx):
self.vars=map<string,Variable>()
self.ops=vector<Operator>()
self.parent=parent
self.idx=idx
self.parent_idx=parent_idx
defcreate_var(self,...):
# create variable in `self.vars`
...
...
@@ -42,8 +73,9 @@ class Block(objects):
defcreate_global_var(self,...):
ifself.parentisnotNone:
returnself.parent.create_global_var(...)
ifself.parent_idxisnotNone:
parent_block=program.get_block(parent_idx)
returnparent_block.create_global_var(...)
else:
returnself.create_var(...)
...
...
@@ -126,9 +158,8 @@ Here are examples of how to write a data layer and FC layer:
### Data Layer
```python
defdata_layer(name,type,block=None):
ifblockisNone:
block=g_block
defdata_layer(name,type):
block=program.current_block()
# type = dense_vector(size=10) / integer_value(range=10)
Before building new variables, we need to specify which block to use. If we don't, the default one `g_block` will be used. In the above `data_layer` code, a variable is created and be inserted into the root block to make it global. This variable is going to be used as input data of the whole network.
All the new variables and operators will be built in the `current block`. In the above `data_layer` code, a variable is created and be inserted into the root block to make it global. This variable is going to be used as input data of the whole network.
In the `fc_layer` code, we create two parameters(`w` and `b`), one variable(`out`) and one operator(`FC operator`), then insert all of them into the specified block.
In the `fc_layer` code, we create two parameters(`w` and `b`), one variable(`out`) and one operator(`FC operator`), then insert all of them into the `current block`.