parent
f8192f72f5
commit
d34aadb3f6
@ -0,0 +1,95 @@
|
|||||||
|
# Executor Desgin Doc
|
||||||
|
|
||||||
|
## Overview
|
||||||
|
|
||||||
|
`Executor` evaluates a `ProgramDesc`. Essentially, it instantializes Variables and Operators, then run all the operators
|
||||||
|
|
||||||
|
```c++
|
||||||
|
void Executor::Run(const ProgramDesc& pdesc, Scope* scope) {
|
||||||
|
auto& block = pdesc.blocks(0);
|
||||||
|
auto& device = device_contexts_[0];
|
||||||
|
|
||||||
|
// Instantiate all the vars in the global scope
|
||||||
|
for (auto& var : block.vars()) {
|
||||||
|
scope->NewVar(var.name());
|
||||||
|
}
|
||||||
|
|
||||||
|
// Decide which operator should be run
|
||||||
|
std::vector<bool> should_run = Preprocess(pdesc);
|
||||||
|
|
||||||
|
// Run the block
|
||||||
|
Scope& local_scope = scope->NewScope();
|
||||||
|
for (size_t i = 0; i < should_run.size(); ++i) {
|
||||||
|
if (should_run[i]) {
|
||||||
|
for (auto var : block.ops(i).outputs()) {
|
||||||
|
for (auto argu : var.arguments()) {
|
||||||
|
// Create variable in the local_scope
|
||||||
|
if (local_scope.FindVar(argu) == nullptr) {
|
||||||
|
local_scope.NewVar(argu);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
auto op = paddle::framework::OpRegistry::CreateOp(block.ops(i));
|
||||||
|
op->Run(local_scope, *device);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
## Tasks
|
||||||
|
|
||||||
|
As shown above, it is not hard to simply evaluate the graph. The real problem
|
||||||
|
is how do we actually construct the `ProgramDesc`. There are several different
|
||||||
|
situations that we need to consider.
|
||||||
|
|
||||||
|
### 1. Init @tony @qijun
|
||||||
|
|
||||||
|
##### Problem:
|
||||||
|
|
||||||
|
Not sure which block to put init ops. Same concerns applys to `Load Model`.
|
||||||
|
|
||||||
|
##### Solution: In seperate Blocks
|
||||||
|
|
||||||
|
All `initop` and `parameter` goes to `block[0]`. Actual run starts from `block[1]`.
|
||||||
|
|
||||||
|
When user writes `a = Parameter(Variable, init)`, a init op is inserted into
|
||||||
|
`block[0]`, and a `NOP` is inserted into `block[1]` to substitute init op.
|
||||||
|
|
||||||
|
- Pro:
|
||||||
|
- Init Op can be run multiple times.
|
||||||
|
- Compatiable with current `Executor::Preprocessing`
|
||||||
|
- Still only one `ProgramDesc`
|
||||||
|
- Con:
|
||||||
|
- Let others know!
|
||||||
|
|
||||||
|
### 2. IO
|
||||||
|
|
||||||
|
#### 2.1 FeedOp and FetchOp
|
||||||
|
|
||||||
|
Design Doc: https://github.com/PaddlePaddle/Paddle/pull/4599
|
||||||
|
|
||||||
|
FeedOp and FetchOp in distributed environment:
|
||||||
|
https://github.com/PaddlePaddle/Paddle/issues/4613
|
||||||
|
|
||||||
|
#### 2.2 ReaderOp and WriterOp
|
||||||
|
|
||||||
|
### 3. Backward @jiayi
|
||||||
|
|
||||||
|
Executor test case is a good place to test `backward` module, even though executor
|
||||||
|
is not necessarily depends on `backward`. Currently exposed issue:
|
||||||
|
|
||||||
|
- Fill One: https://github.com/PaddlePaddle/Paddle/issues/4627
|
||||||
|
- Attribute map: https://github.com/PaddlePaddle/Paddle/issues/4642
|
||||||
|
|
||||||
|
### 4. Optimizer @longfei
|
||||||
|
|
||||||
|
Executor test case is a good place to test `optimizer `module, even though executor
|
||||||
|
is not necessarily depends on `optimizer `.
|
||||||
|
|
||||||
|
### 5. RNN @chunwei
|
||||||
|
|
||||||
|
To be discussed.
|
||||||
|
|
||||||
|
- How to deal with multiple blocks
|
||||||
|
- How to deal with LoDTensor
|
||||||
|
|
Loading…
Reference in new issue