提交 8cdddf35 编写于 作者: T Travis CI

Deploy to GitHub Pages: 0a74fed1

上级 294a9139
......@@ -5,12 +5,12 @@
Both deep learning systems and programming languages help users describe computation procedures. These systems use various representations of computation:
- Caffe, Torch, and Paddle: sequences of layers.
- TensorFlow, Caffe2, Mxnet: graphs of operators.
- TensorFlow, Caffe2, Mxnet: graph of operators.
- PaddlePaddle: nested blocks, like C++ and Java programs.
## Block in Programming Languages and Deep Learning
In programming languages, a block is a pair of curly braces that includes local variables definitions and a sequence of instructions, or operators.
In programming languages, a block is a pair of curly braces that includes local variables definitions and a sequence of instructions or operators.
Blocks work with control flow structures like `if`, `else`, and `for`, which have equivalents in deep learning:
......@@ -24,14 +24,14 @@ A key difference is that a C++ program describes a one pass computation, whereas
## Stack Frames and the Scope Hierarchy
The existence of the backward makes the execution of a block of traditional programs and PaddlePaddle different to each other:
The existence of the backward pass makes the execution of a block of PaddlePaddle different from traditional programs:
| programming languages | PaddlePaddle |
|-----------------------|-------------------------------|
| stack | scope hierarchy |
| stack frame | scope |
| push at entering block| push at entering block |
| pop at leaving block | destroy at minibatch completes|
| programming languages | PaddlePaddle |
|-----------------------|---------------------------------|
| stack | scope hierarchy |
| stack frame | scope |
| push at entering block| push at entering block |
| pop at leaving block | destroy when minibatch completes|
1. In traditional programs:
......@@ -42,9 +42,9 @@ The existence of the backward makes the execution of a block of traditional prog
1. In PaddlePaddle
- When the execution enters a block, PaddlePaddle adds a new scope, where it realizes variables.
- PaddlePaddle doesn't pop a scope after the execution of the block because variables therein are to be used by the backward pass. So it has a stack forest known as a *scope hierarchy*.
- PaddlePaddle doesn't pop a scope after the execution of the block because variables therein are used by the backward pass. So it has a stack forest known as a *scope hierarchy*.
- The height of the highest tree is the maximum depth of nested blocks.
- After the process of a minibatch, PaddlePaddle destroys the scope hierarchy.
- After the processing of a minibatch, PaddlePaddle destroys the scope hierarchy.
## Use Blocks in C++ and PaddlePaddle Programs
......@@ -94,14 +94,14 @@ with ie.false_block():
o1, o2 = ie(cond)
```
In both examples, the left branch computes `x+y` and `softmax(x+y)`, the right branch computes `x+1` and `fc(x)`.
In both examples, the left branch computes `x+y` and `softmax(x+y)`, the right branch computes `fc(x)` and `x+1` .
A difference is that variables in the C++ program contain scalar values, whereas those in the PaddlePaddle programs are mini-batches of instances. The `ie.input(true, 0)` invocation returns instances in the 0-th input, `x`, that corresponds to true values in `cond` as the local variable `x`, where `ie.input(false, 0)` returns instances corresponding to false values.
The difference is that variables in the C++ program contain scalar values, whereas those in the PaddlePaddle programs are mini-batches of instances.
### Blocks with `for` and `RNNOp`
The following RNN model from the [RNN design doc](./rnn.md)
The following RNN model in PaddlePaddle from the [RNN design doc](./rnn.md) :
```python
x = sequence([10, 20, 30]) # shape=[None, 1]
......@@ -112,9 +112,9 @@ U = var(0.375, param=true) # shape=[1]
rnn = pd.rnn()
with rnn.step():
h = rnn.memory(init = m)
hh = rnn.previous_memory(h)
h_prev = rnn.previous_memory(h)
a = layer.fc(W, x)
b = layer.fc(U, hh)
b = layer.fc(U, h_prev)
s = pd.add(a, b)
act = pd.sigmoid(s)
rnn.update_memory(h, act)
......@@ -147,9 +147,9 @@ for (int i = 1; i <= sizeof(x)/sizeof(x[0]); ++i) {
## Compilation and Execution
Like TensorFlow programs, a PaddlePaddle program is written in Python. The first part describes a neural network as a protobuf message, and the rest part executes the message for training or inference.
Like TensorFlow, a PaddlePaddle program is written in Python. The first part describes a neural network as a protobuf message, and the rest executes the message for training or inference.
The generation of this protobuf message is like what a compiler generates a binary executable file. The execution of the message that the OS executes the binary file.
The generation of this protobuf message is similar to how a compiler generates a binary executable file. The execution of the message is similar to how the OS executes the binary file.
## The "Binary Executable File Format"
......@@ -186,8 +186,8 @@ Also, the RNN operator in above example is serialized into a protobuf message of
```
OpDesc {
inputs = {0} // the index of x
outputs = {5, 3} // indices of act and hidden_out
inputs = {0} // the index of x in vars of BlockDesc above
outputs = {5, 3} // indices of act and hidden_out in vars of BlockDesc above
attrs {
"memories" : {1} // the index of h
"step_net" : <above step net>
......@@ -203,14 +203,14 @@ This `OpDesc` value is in the `ops` field of the `BlockDesc` value representing
During the generation of the Protobuf message, the Block should store VarDesc (the Protobuf message which describes Variable) and OpDesc (the Protobuf message which describes Operator).
VarDesc in a block should have its name scope to avoid local variables affect parent block's name scope.
Child block's name scopes should inherit the parent's so that OpDesc in child block can reference a VarDesc that stored in parent block. For example
Child block's name scopes should inherit the parent's so that OpDesc in child block can reference a VarDesc that stored in parent block. For example:
```python
a = pd.Varaible(shape=[20, 20])
a = pd.Variable(shape=[20, 20])
b = pd.fc(a, params=["fc.w", "fc.b"])
rnn = pd.create_rnn()
with rnn.stepnet()
with rnn.stepnet():
x = a.as_step_input()
# reuse fc's parameter
fc_without_b = pd.get_variable("fc.w")
......@@ -218,17 +218,17 @@ with rnn.stepnet()
out = rnn()
```
the method `pd.get_variable` can help retrieve a Variable by a name, a Variable may store in a parent block, but might be retrieved in a child block, so block should have a variable scope that supports inheritance.
The method `pd.get_variable` can help retrieve a Variable by the name. The Variable may be stored in a parent block, but might be retrieved in a child block, so block should have a variable scope that supports inheritance.
In compiler design, the symbol table is a data structure created and maintained by compilers to store information about the occurrence of various entities such as variable names, function names, classes, etc.
To store the definition of variables and operators, we define a C++ class `SymbolTable`, like the one used in compilers.
`SymbolTable` can do the following stuff:
`SymbolTable` can do the following:
- store the definitions (some names and attributes) of variables and operators,
- to verify if a variable was declared,
- to make it possible to implement type checking (offer Protobuf message pointers to `InferShape` handlers).
- verify if a variable was declared,
- make it possible to implement type checking (offer Protobuf message pointers to `InferShape` handlers).
```c++
......@@ -240,19 +240,18 @@ class SymbolTable {
OpDesc* NewOp(const string& name="");
// TODO determine whether name is generated by python or C++
// currently assume that a unique name will be generated by C++ if the
// argument name left default.
// TODO determine whether name is generated by python or C++.
// Currently assume that a unique name will be generated by C++ if the
// argument name is left default.
VarDesc* NewVar(const string& name="");
// find a VarDesc by name, if recursive true, find parent's SymbolTable
// find a VarDesc by name, if recursive is true, find parent's SymbolTable
// recursively.
// this interface is introduced to support InferShape, find protobuf messages
// of variables and operators, pass pointers into InferShape.
// operator
//
// NOTE maybe some C++ classes such as VarDescBuilder and OpDescBuilder should
// be proposed and embedded into pybind to enable python operate on C++ pointers.
// be proposed and embedded into pybind to enable python operation on C++ pointers.
VarDesc* FindVar(const string& name, bool recursive=true);
OpDesc* FindOp(const string& name);
......@@ -270,7 +269,7 @@ class SymbolTable {
After all the description of variables and operators is added into SymbolTable,
the block has enough information to run.
The `Block` class takes a `BlockDesc` as input, and provide `Run` and `InferShape` functions.
The `Block` class takes a `BlockDesc` as input, and provides `Run` and `InferShape` functions.
```c++
......@@ -302,7 +301,7 @@ public:
void CreateVariables(const framework::Scope& scope);
void CreateOperators();
// some other necessary interfaces of NetOp are list below
// some other necessary interfaces of NetOp are listed below
// ...
private:
......@@ -316,15 +315,14 @@ private:
Block inherits from OperatorBase, which has a Run method.
Block's Run method will run its operators sequentially.
There is another important interface called `Eval`, which take some arguments called targets, and generate a minimal graph which takes targets as the end points and creates a new Block,
after `Run`, `Eval` will get the latest value and return the targets.
There is another important interface called `Eval`, which takes some arguments called targets and generates a minimal graph which treats targets as the end points and creates a new Block. After `Run`, `Eval` will get the latest value and return the targets.
The definition of Eval is as follows:
```c++
// clean a block description by targets using the corresponding dependency graph.
// return a new BlockDesc with minimal number of operators.
// NOTE not return a Block but the block's description so that this can be distributed
// NOTE: The return type is not a Block but the block's description so that this can be distributed
// to a cluster.
BlockDesc Prune(const BlockDesc& desc, vector<string> targets);
......
......@@ -184,13 +184,13 @@
<p>Both deep learning systems and programming languages help users describe computation procedures. These systems use various representations of computation:</p>
<ul class="simple">
<li>Caffe, Torch, and Paddle: sequences of layers.</li>
<li>TensorFlow, Caffe2, Mxnet: graphs of operators.</li>
<li>TensorFlow, Caffe2, Mxnet: graph of operators.</li>
<li>PaddlePaddle: nested blocks, like C++ and Java programs.</li>
</ul>
</div>
<div class="section" id="block-in-programming-languages-and-deep-learning">
<span id="block-in-programming-languages-and-deep-learning"></span><h2>Block in Programming Languages and Deep Learning<a class="headerlink" href="#block-in-programming-languages-and-deep-learning" title="Permalink to this headline"></a></h2>
<p>In programming languages, a block is a pair of curly braces that includes local variables definitions and a sequence of instructions, or operators.</p>
<p>In programming languages, a block is a pair of curly braces that includes local variables definitions and a sequence of instructions or operators.</p>
<p>Blocks work with control flow structures like <code class="docutils literal"><span class="pre">if</span></code>, <code class="docutils literal"><span class="pre">else</span></code>, and <code class="docutils literal"><span class="pre">for</span></code>, which have equivalents in deep learning:</p>
<p>| programming languages | PaddlePaddle |
|&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8211;|&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8211;|
......@@ -201,13 +201,13 @@
</div>
<div class="section" id="stack-frames-and-the-scope-hierarchy">
<span id="stack-frames-and-the-scope-hierarchy"></span><h2>Stack Frames and the Scope Hierarchy<a class="headerlink" href="#stack-frames-and-the-scope-hierarchy" title="Permalink to this headline"></a></h2>
<p>The existence of the backward makes the execution of a block of traditional programs and PaddlePaddle different to each other:</p>
<p>| programming languages | PaddlePaddle |
|&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8211;|&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;-|
| stack | scope hierarchy |
| stack frame | scope |
| push at entering block| push at entering block |
| pop at leaving block | destroy at minibatch completes|</p>
<p>The existence of the backward pass makes the execution of a block of PaddlePaddle different from traditional programs:</p>
<p>| programming languages | PaddlePaddle |
|&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8211;|&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;|
| stack | scope hierarchy |
| stack frame | scope |
| push at entering block| push at entering block |
| pop at leaving block | destroy when minibatch completes|</p>
<ol class="simple">
<li>In traditional programs:<ul>
<li>When the execution enters the left curly brace of a block, the runtime pushes a frame into the stack, where it realizes local variables.</li>
......@@ -217,9 +217,9 @@
</li>
<li>In PaddlePaddle<ul>
<li>When the execution enters a block, PaddlePaddle adds a new scope, where it realizes variables.</li>
<li>PaddlePaddle doesn&#8217;t pop a scope after the execution of the block because variables therein are to be used by the backward pass. So it has a stack forest known as a <em>scope hierarchy</em>.</li>
<li>PaddlePaddle doesn&#8217;t pop a scope after the execution of the block because variables therein are used by the backward pass. So it has a stack forest known as a <em>scope hierarchy</em>.</li>
<li>The height of the highest tree is the maximum depth of nested blocks.</li>
<li>After the process of a minibatch, PaddlePaddle destroys the scope hierarchy.</li>
<li>After the processing of a minibatch, PaddlePaddle destroys the scope hierarchy.</li>
</ul>
</li>
</ol>
......@@ -266,12 +266,12 @@
<span class="n">o1</span><span class="p">,</span> <span class="n">o2</span> <span class="o">=</span> <span class="n">ie</span><span class="p">(</span><span class="n">cond</span><span class="p">)</span>
</pre></div>
</div>
<p>In both examples, the left branch computes <code class="docutils literal"><span class="pre">x+y</span></code> and <code class="docutils literal"><span class="pre">softmax(x+y)</span></code>, the right branch computes <code class="docutils literal"><span class="pre">x+1</span></code> and <code class="docutils literal"><span class="pre">fc(x)</span></code>.</p>
<p>A difference is that variables in the C++ program contain scalar values, whereas those in the PaddlePaddle programs are mini-batches of instances. The <code class="docutils literal"><span class="pre">ie.input(true,</span> <span class="pre">0)</span></code> invocation returns instances in the 0-th input, <code class="docutils literal"><span class="pre">x</span></code>, that corresponds to true values in <code class="docutils literal"><span class="pre">cond</span></code> as the local variable <code class="docutils literal"><span class="pre">x</span></code>, where <code class="docutils literal"><span class="pre">ie.input(false,</span> <span class="pre">0)</span></code> returns instances corresponding to false values.</p>
<p>In both examples, the left branch computes <code class="docutils literal"><span class="pre">x+y</span></code> and <code class="docutils literal"><span class="pre">softmax(x+y)</span></code>, the right branch computes <code class="docutils literal"><span class="pre">fc(x)</span></code> and <code class="docutils literal"><span class="pre">x+1</span></code> .</p>
<p>The difference is that variables in the C++ program contain scalar values, whereas those in the PaddlePaddle programs are mini-batches of instances.</p>
</div>
<div class="section" id="blocks-with-for-and-rnnop">
<span id="blocks-with-for-and-rnnop"></span><h3>Blocks with <code class="docutils literal"><span class="pre">for</span></code> and <code class="docutils literal"><span class="pre">RNNOp</span></code><a class="headerlink" href="#blocks-with-for-and-rnnop" title="Permalink to this headline"></a></h3>
<p>The following RNN model from the <a class="reference external" href="design/rnn.md">RNN design doc</a></p>
<p>The following RNN model in PaddlePaddle from the <a class="reference external" href="design/rnn.md">RNN design doc</a> :</p>
<div class="highlight-python"><div class="highlight"><pre><span></span><span class="n">x</span> <span class="o">=</span> <span class="n">sequence</span><span class="p">([</span><span class="mi">10</span><span class="p">,</span> <span class="mi">20</span><span class="p">,</span> <span class="mi">30</span><span class="p">])</span> <span class="c1"># shape=[None, 1]</span>
<span class="n">m</span> <span class="o">=</span> <span class="n">var</span><span class="p">(</span><span class="mi">0</span><span class="p">)</span> <span class="c1"># shape=[1]</span>
<span class="n">W</span> <span class="o">=</span> <span class="n">var</span><span class="p">(</span><span class="mf">0.314</span><span class="p">,</span> <span class="n">param</span><span class="o">=</span><span class="n">true</span><span class="p">)</span> <span class="c1"># shape=[1]</span>
......@@ -280,9 +280,9 @@
<span class="n">rnn</span> <span class="o">=</span> <span class="n">pd</span><span class="o">.</span><span class="n">rnn</span><span class="p">()</span>
<span class="k">with</span> <span class="n">rnn</span><span class="o">.</span><span class="n">step</span><span class="p">():</span>
<span class="n">h</span> <span class="o">=</span> <span class="n">rnn</span><span class="o">.</span><span class="n">memory</span><span class="p">(</span><span class="n">init</span> <span class="o">=</span> <span class="n">m</span><span class="p">)</span>
<span class="n">hh</span> <span class="o">=</span> <span class="n">rnn</span><span class="o">.</span><span class="n">previous_memory</span><span class="p">(</span><span class="n">h</span><span class="p">)</span>
<span class="n">h_prev</span> <span class="o">=</span> <span class="n">rnn</span><span class="o">.</span><span class="n">previous_memory</span><span class="p">(</span><span class="n">h</span><span class="p">)</span>
<span class="n">a</span> <span class="o">=</span> <span class="n">layer</span><span class="o">.</span><span class="n">fc</span><span class="p">(</span><span class="n">W</span><span class="p">,</span> <span class="n">x</span><span class="p">)</span>
<span class="n">b</span> <span class="o">=</span> <span class="n">layer</span><span class="o">.</span><span class="n">fc</span><span class="p">(</span><span class="n">U</span><span class="p">,</span> <span class="n">hh</span><span class="p">)</span>
<span class="n">b</span> <span class="o">=</span> <span class="n">layer</span><span class="o">.</span><span class="n">fc</span><span class="p">(</span><span class="n">U</span><span class="p">,</span> <span class="n">h_prev</span><span class="p">)</span>
<span class="n">s</span> <span class="o">=</span> <span class="n">pd</span><span class="o">.</span><span class="n">add</span><span class="p">(</span><span class="n">a</span><span class="p">,</span> <span class="n">b</span><span class="p">)</span>
<span class="n">act</span> <span class="o">=</span> <span class="n">pd</span><span class="o">.</span><span class="n">sigmoid</span><span class="p">(</span><span class="n">s</span><span class="p">)</span>
<span class="n">rnn</span><span class="o">.</span><span class="n">update_memory</span><span class="p">(</span><span class="n">h</span><span class="p">,</span> <span class="n">act</span><span class="p">)</span>
......@@ -316,8 +316,8 @@
</div>
<div class="section" id="compilation-and-execution">
<span id="compilation-and-execution"></span><h2>Compilation and Execution<a class="headerlink" href="#compilation-and-execution" title="Permalink to this headline"></a></h2>
<p>Like TensorFlow programs, a PaddlePaddle program is written in Python. The first part describes a neural network as a protobuf message, and the rest part executes the message for training or inference.</p>
<p>The generation of this protobuf message is like what a compiler generates a binary executable file. The execution of the message that the OS executes the binary file.</p>
<p>Like TensorFlow, a PaddlePaddle program is written in Python. The first part describes a neural network as a protobuf message, and the rest executes the message for training or inference.</p>
<p>The generation of this protobuf message is similar to how a compiler generates a binary executable file. The execution of the message is similar to how the OS executes the binary file.</p>
</div>
<div class="section" id="the-binary-executable-file-format">
<span id="the-binary-executable-file-format"></span><h2>The &#8220;Binary Executable File Format&#8221;<a class="headerlink" href="#the-binary-executable-file-format" title="Permalink to this headline"></a></h2>
......@@ -348,8 +348,8 @@
</div>
<p>Also, the RNN operator in above example is serialized into a protobuf message of type <code class="docutils literal"><span class="pre">OpDesc</span></code> and would look like:</p>
<div class="highlight-default"><div class="highlight"><pre><span></span><span class="n">OpDesc</span> <span class="p">{</span>
<span class="n">inputs</span> <span class="o">=</span> <span class="p">{</span><span class="mi">0</span><span class="p">}</span> <span class="o">//</span> <span class="n">the</span> <span class="n">index</span> <span class="n">of</span> <span class="n">x</span>
<span class="n">outputs</span> <span class="o">=</span> <span class="p">{</span><span class="mi">5</span><span class="p">,</span> <span class="mi">3</span><span class="p">}</span> <span class="o">//</span> <span class="n">indices</span> <span class="n">of</span> <span class="n">act</span> <span class="ow">and</span> <span class="n">hidden_out</span>
<span class="n">inputs</span> <span class="o">=</span> <span class="p">{</span><span class="mi">0</span><span class="p">}</span> <span class="o">//</span> <span class="n">the</span> <span class="n">index</span> <span class="n">of</span> <span class="n">x</span> <span class="ow">in</span> <span class="nb">vars</span> <span class="n">of</span> <span class="n">BlockDesc</span> <span class="n">above</span>
<span class="n">outputs</span> <span class="o">=</span> <span class="p">{</span><span class="mi">5</span><span class="p">,</span> <span class="mi">3</span><span class="p">}</span> <span class="o">//</span> <span class="n">indices</span> <span class="n">of</span> <span class="n">act</span> <span class="ow">and</span> <span class="n">hidden_out</span> <span class="ow">in</span> <span class="nb">vars</span> <span class="n">of</span> <span class="n">BlockDesc</span> <span class="n">above</span>
<span class="n">attrs</span> <span class="p">{</span>
<span class="s2">&quot;memories&quot;</span> <span class="p">:</span> <span class="p">{</span><span class="mi">1</span><span class="p">}</span> <span class="o">//</span> <span class="n">the</span> <span class="n">index</span> <span class="n">of</span> <span class="n">h</span>
<span class="s2">&quot;step_net&quot;</span> <span class="p">:</span> <span class="o">&lt;</span><span class="n">above</span> <span class="n">step</span> <span class="n">net</span><span class="o">&gt;</span>
......@@ -363,12 +363,12 @@
<span id="the-compilation-of-blocks"></span><h2>The Compilation of Blocks<a class="headerlink" href="#the-compilation-of-blocks" title="Permalink to this headline"></a></h2>
<p>During the generation of the Protobuf message, the Block should store VarDesc (the Protobuf message which describes Variable) and OpDesc (the Protobuf message which describes Operator).</p>
<p>VarDesc in a block should have its name scope to avoid local variables affect parent block&#8217;s name scope.
Child block&#8217;s name scopes should inherit the parent&#8217;s so that OpDesc in child block can reference a VarDesc that stored in parent block. For example</p>
<div class="highlight-python"><div class="highlight"><pre><span></span><span class="n">a</span> <span class="o">=</span> <span class="n">pd</span><span class="o">.</span><span class="n">Varaible</span><span class="p">(</span><span class="n">shape</span><span class="o">=</span><span class="p">[</span><span class="mi">20</span><span class="p">,</span> <span class="mi">20</span><span class="p">])</span>
Child block&#8217;s name scopes should inherit the parent&#8217;s so that OpDesc in child block can reference a VarDesc that stored in parent block. For example:</p>
<div class="highlight-python"><div class="highlight"><pre><span></span><span class="n">a</span> <span class="o">=</span> <span class="n">pd</span><span class="o">.</span><span class="n">Variable</span><span class="p">(</span><span class="n">shape</span><span class="o">=</span><span class="p">[</span><span class="mi">20</span><span class="p">,</span> <span class="mi">20</span><span class="p">])</span>
<span class="n">b</span> <span class="o">=</span> <span class="n">pd</span><span class="o">.</span><span class="n">fc</span><span class="p">(</span><span class="n">a</span><span class="p">,</span> <span class="n">params</span><span class="o">=</span><span class="p">[</span><span class="s2">&quot;fc.w&quot;</span><span class="p">,</span> <span class="s2">&quot;fc.b&quot;</span><span class="p">])</span>
<span class="n">rnn</span> <span class="o">=</span> <span class="n">pd</span><span class="o">.</span><span class="n">create_rnn</span><span class="p">()</span>
<span class="k">with</span> <span class="n">rnn</span><span class="o">.</span><span class="n">stepnet</span><span class="p">()</span>
<span class="k">with</span> <span class="n">rnn</span><span class="o">.</span><span class="n">stepnet</span><span class="p">():</span>
<span class="n">x</span> <span class="o">=</span> <span class="n">a</span><span class="o">.</span><span class="n">as_step_input</span><span class="p">()</span>
<span class="c1"># reuse fc&#39;s parameter</span>
<span class="n">fc_without_b</span> <span class="o">=</span> <span class="n">pd</span><span class="o">.</span><span class="n">get_variable</span><span class="p">(</span><span class="s2">&quot;fc.w&quot;</span><span class="p">)</span>
......@@ -377,14 +377,14 @@ Child block&#8217;s name scopes should inherit the parent&#8217;s so that OpDesc
<span class="n">out</span> <span class="o">=</span> <span class="n">rnn</span><span class="p">()</span>
</pre></div>
</div>
<p>the method <code class="docutils literal"><span class="pre">pd.get_variable</span></code> can help retrieve a Variable by a name, a Variable may store in a parent block, but might be retrieved in a child block, so block should have a variable scope that supports inheritance.</p>
<p>The method <code class="docutils literal"><span class="pre">pd.get_variable</span></code> can help retrieve a Variable by the name. The Variable may be stored in a parent block, but might be retrieved in a child block, so block should have a variable scope that supports inheritance.</p>
<p>In compiler design, the symbol table is a data structure created and maintained by compilers to store information about the occurrence of various entities such as variable names, function names, classes, etc.</p>
<p>To store the definition of variables and operators, we define a C++ class <code class="docutils literal"><span class="pre">SymbolTable</span></code>, like the one used in compilers.</p>
<p><code class="docutils literal"><span class="pre">SymbolTable</span></code> can do the following stuff:</p>
<p><code class="docutils literal"><span class="pre">SymbolTable</span></code> can do the following:</p>
<ul class="simple">
<li>store the definitions (some names and attributes) of variables and operators,</li>
<li>to verify if a variable was declared,</li>
<li>to make it possible to implement type checking (offer Protobuf message pointers to <code class="docutils literal"><span class="pre">InferShape</span></code> handlers).</li>
<li>verify if a variable was declared,</li>
<li>make it possible to implement type checking (offer Protobuf message pointers to <code class="docutils literal"><span class="pre">InferShape</span></code> handlers).</li>
</ul>
<div class="highlight-c++"><div class="highlight"><pre><span></span><span class="c1">// Information in SymbolTable is enough to trace the dependency graph. So maybe</span>
<span class="c1">// the Eval() interface takes a SymbolTable is enough.</span>
......@@ -394,19 +394,18 @@ Child block&#8217;s name scopes should inherit the parent&#8217;s so that OpDesc
<span class="n">OpDesc</span><span class="o">*</span> <span class="n">NewOp</span><span class="p">(</span><span class="k">const</span> <span class="n">string</span><span class="o">&amp;</span> <span class="n">name</span><span class="o">=</span><span class="s">&quot;&quot;</span><span class="p">);</span>
<span class="c1">// TODO determine whether name is generated by python or C++</span>
<span class="c1">// currently assume that a unique name will be generated by C++ if the</span>
<span class="c1">// argument name left default.</span>
<span class="c1">// TODO determine whether name is generated by python or C++.</span>
<span class="c1">// Currently assume that a unique name will be generated by C++ if the</span>
<span class="c1">// argument name is left default.</span>
<span class="n">VarDesc</span><span class="o">*</span> <span class="nf">NewVar</span><span class="p">(</span><span class="k">const</span> <span class="n">string</span><span class="o">&amp;</span> <span class="n">name</span><span class="o">=</span><span class="s">&quot;&quot;</span><span class="p">);</span>
<span class="c1">// find a VarDesc by name, if recursive true, find parent&#39;s SymbolTable</span>
<span class="c1">// find a VarDesc by name, if recursive is true, find parent&#39;s SymbolTable</span>
<span class="c1">// recursively.</span>
<span class="c1">// this interface is introduced to support InferShape, find protobuf messages</span>
<span class="c1">// of variables and operators, pass pointers into InferShape.</span>
<span class="c1">// operator</span>
<span class="c1">//</span>
<span class="c1">// NOTE maybe some C++ classes such as VarDescBuilder and OpDescBuilder should</span>
<span class="c1">// be proposed and embedded into pybind to enable python operate on C++ pointers.</span>
<span class="c1">// be proposed and embedded into pybind to enable python operation on C++ pointers.</span>
<span class="n">VarDesc</span><span class="o">*</span> <span class="nf">FindVar</span><span class="p">(</span><span class="k">const</span> <span class="n">string</span><span class="o">&amp;</span> <span class="n">name</span><span class="p">,</span> <span class="kt">bool</span> <span class="n">recursive</span><span class="o">=</span><span class="nb">true</span><span class="p">);</span>
<span class="n">OpDesc</span><span class="o">*</span> <span class="nf">FindOp</span><span class="p">(</span><span class="k">const</span> <span class="n">string</span><span class="o">&amp;</span> <span class="n">name</span><span class="p">);</span>
......@@ -423,7 +422,7 @@ Child block&#8217;s name scopes should inherit the parent&#8217;s so that OpDesc
</div>
<p>After all the description of variables and operators is added into SymbolTable,
the block has enough information to run.</p>
<p>The <code class="docutils literal"><span class="pre">Block</span></code> class takes a <code class="docutils literal"><span class="pre">BlockDesc</span></code> as input, and provide <code class="docutils literal"><span class="pre">Run</span></code> and <code class="docutils literal"><span class="pre">InferShape</span></code> functions.</p>
<p>The <code class="docutils literal"><span class="pre">Block</span></code> class takes a <code class="docutils literal"><span class="pre">BlockDesc</span></code> as input, and provides <code class="docutils literal"><span class="pre">Run</span></code> and <code class="docutils literal"><span class="pre">InferShape</span></code> functions.</p>
<div class="highlight-c++"><div class="highlight"><pre><span></span><span class="k">namespace</span> <span class="p">{</span>
<span class="k">class</span> <span class="nc">Block</span> <span class="o">:</span> <span class="n">OperatorBase</span> <span class="p">{</span>
......@@ -452,7 +451,7 @@ the block has enough information to run.</p>
<span class="kt">void</span> <span class="n">CreateVariables</span><span class="p">(</span><span class="k">const</span> <span class="n">framework</span><span class="o">::</span><span class="n">Scope</span><span class="o">&amp;</span> <span class="n">scope</span><span class="p">);</span>
<span class="kt">void</span> <span class="nf">CreateOperators</span><span class="p">();</span>
<span class="c1">// some other necessary interfaces of NetOp are list below</span>
<span class="c1">// some other necessary interfaces of NetOp are listed below</span>
<span class="c1">// ...</span>
<span class="k">private</span><span class="o">:</span>
......@@ -466,12 +465,11 @@ the block has enough information to run.</p>
<span id="the-execution-of-blocks"></span><h2>The Execution of Blocks<a class="headerlink" href="#the-execution-of-blocks" title="Permalink to this headline"></a></h2>
<p>Block inherits from OperatorBase, which has a Run method.
Block&#8217;s Run method will run its operators sequentially.</p>
<p>There is another important interface called <code class="docutils literal"><span class="pre">Eval</span></code>, which take some arguments called targets, and generate a minimal graph which takes targets as the end points and creates a new Block,
after <code class="docutils literal"><span class="pre">Run</span></code>, <code class="docutils literal"><span class="pre">Eval</span></code> will get the latest value and return the targets.</p>
<p>There is another important interface called <code class="docutils literal"><span class="pre">Eval</span></code>, which takes some arguments called targets and generates a minimal graph which treats targets as the end points and creates a new Block. After <code class="docutils literal"><span class="pre">Run</span></code>, <code class="docutils literal"><span class="pre">Eval</span></code> will get the latest value and return the targets.</p>
<p>The definition of Eval is as follows:</p>
<div class="highlight-c++"><div class="highlight"><pre><span></span><span class="c1">// clean a block description by targets using the corresponding dependency graph.</span>
<span class="c1">// return a new BlockDesc with minimal number of operators.</span>
<span class="c1">// NOTE not return a Block but the block&#39;s description so that this can be distributed</span>
<span class="c1">// NOTE: The return type is not a Block but the block&#39;s description so that this can be distributed</span>
<span class="c1">// to a cluster.</span>
<span class="n">BlockDesc</span> <span class="nf">Prune</span><span class="p">(</span><span class="k">const</span> <span class="n">BlockDesc</span><span class="o">&amp;</span> <span class="n">desc</span><span class="p">,</span> <span class="n">vector</span><span class="o">&lt;</span><span class="n">string</span><span class="o">&gt;</span> <span class="n">targets</span><span class="p">);</span>
......
因为 它太大了无法显示 source diff 。你可以改为 查看blob
......@@ -5,12 +5,12 @@
Both deep learning systems and programming languages help users describe computation procedures. These systems use various representations of computation:
- Caffe, Torch, and Paddle: sequences of layers.
- TensorFlow, Caffe2, Mxnet: graphs of operators.
- TensorFlow, Caffe2, Mxnet: graph of operators.
- PaddlePaddle: nested blocks, like C++ and Java programs.
## Block in Programming Languages and Deep Learning
In programming languages, a block is a pair of curly braces that includes local variables definitions and a sequence of instructions, or operators.
In programming languages, a block is a pair of curly braces that includes local variables definitions and a sequence of instructions or operators.
Blocks work with control flow structures like `if`, `else`, and `for`, which have equivalents in deep learning:
......@@ -24,14 +24,14 @@ A key difference is that a C++ program describes a one pass computation, whereas
## Stack Frames and the Scope Hierarchy
The existence of the backward makes the execution of a block of traditional programs and PaddlePaddle different to each other:
The existence of the backward pass makes the execution of a block of PaddlePaddle different from traditional programs:
| programming languages | PaddlePaddle |
|-----------------------|-------------------------------|
| stack | scope hierarchy |
| stack frame | scope |
| push at entering block| push at entering block |
| pop at leaving block | destroy at minibatch completes|
| programming languages | PaddlePaddle |
|-----------------------|---------------------------------|
| stack | scope hierarchy |
| stack frame | scope |
| push at entering block| push at entering block |
| pop at leaving block | destroy when minibatch completes|
1. In traditional programs:
......@@ -42,9 +42,9 @@ The existence of the backward makes the execution of a block of traditional prog
1. In PaddlePaddle
- When the execution enters a block, PaddlePaddle adds a new scope, where it realizes variables.
- PaddlePaddle doesn't pop a scope after the execution of the block because variables therein are to be used by the backward pass. So it has a stack forest known as a *scope hierarchy*.
- PaddlePaddle doesn't pop a scope after the execution of the block because variables therein are used by the backward pass. So it has a stack forest known as a *scope hierarchy*.
- The height of the highest tree is the maximum depth of nested blocks.
- After the process of a minibatch, PaddlePaddle destroys the scope hierarchy.
- After the processing of a minibatch, PaddlePaddle destroys the scope hierarchy.
## Use Blocks in C++ and PaddlePaddle Programs
......@@ -94,14 +94,14 @@ with ie.false_block():
o1, o2 = ie(cond)
```
In both examples, the left branch computes `x+y` and `softmax(x+y)`, the right branch computes `x+1` and `fc(x)`.
In both examples, the left branch computes `x+y` and `softmax(x+y)`, the right branch computes `fc(x)` and `x+1` .
A difference is that variables in the C++ program contain scalar values, whereas those in the PaddlePaddle programs are mini-batches of instances. The `ie.input(true, 0)` invocation returns instances in the 0-th input, `x`, that corresponds to true values in `cond` as the local variable `x`, where `ie.input(false, 0)` returns instances corresponding to false values.
The difference is that variables in the C++ program contain scalar values, whereas those in the PaddlePaddle programs are mini-batches of instances.
### Blocks with `for` and `RNNOp`
The following RNN model from the [RNN design doc](./rnn.md)
The following RNN model in PaddlePaddle from the [RNN design doc](./rnn.md) :
```python
x = sequence([10, 20, 30]) # shape=[None, 1]
......@@ -112,9 +112,9 @@ U = var(0.375, param=true) # shape=[1]
rnn = pd.rnn()
with rnn.step():
h = rnn.memory(init = m)
hh = rnn.previous_memory(h)
h_prev = rnn.previous_memory(h)
a = layer.fc(W, x)
b = layer.fc(U, hh)
b = layer.fc(U, h_prev)
s = pd.add(a, b)
act = pd.sigmoid(s)
rnn.update_memory(h, act)
......@@ -147,9 +147,9 @@ for (int i = 1; i <= sizeof(x)/sizeof(x[0]); ++i) {
## Compilation and Execution
Like TensorFlow programs, a PaddlePaddle program is written in Python. The first part describes a neural network as a protobuf message, and the rest part executes the message for training or inference.
Like TensorFlow, a PaddlePaddle program is written in Python. The first part describes a neural network as a protobuf message, and the rest executes the message for training or inference.
The generation of this protobuf message is like what a compiler generates a binary executable file. The execution of the message that the OS executes the binary file.
The generation of this protobuf message is similar to how a compiler generates a binary executable file. The execution of the message is similar to how the OS executes the binary file.
## The "Binary Executable File Format"
......@@ -186,8 +186,8 @@ Also, the RNN operator in above example is serialized into a protobuf message of
```
OpDesc {
inputs = {0} // the index of x
outputs = {5, 3} // indices of act and hidden_out
inputs = {0} // the index of x in vars of BlockDesc above
outputs = {5, 3} // indices of act and hidden_out in vars of BlockDesc above
attrs {
"memories" : {1} // the index of h
"step_net" : <above step net>
......@@ -203,14 +203,14 @@ This `OpDesc` value is in the `ops` field of the `BlockDesc` value representing
During the generation of the Protobuf message, the Block should store VarDesc (the Protobuf message which describes Variable) and OpDesc (the Protobuf message which describes Operator).
VarDesc in a block should have its name scope to avoid local variables affect parent block's name scope.
Child block's name scopes should inherit the parent's so that OpDesc in child block can reference a VarDesc that stored in parent block. For example
Child block's name scopes should inherit the parent's so that OpDesc in child block can reference a VarDesc that stored in parent block. For example:
```python
a = pd.Varaible(shape=[20, 20])
a = pd.Variable(shape=[20, 20])
b = pd.fc(a, params=["fc.w", "fc.b"])
rnn = pd.create_rnn()
with rnn.stepnet()
with rnn.stepnet():
x = a.as_step_input()
# reuse fc's parameter
fc_without_b = pd.get_variable("fc.w")
......@@ -218,17 +218,17 @@ with rnn.stepnet()
out = rnn()
```
the method `pd.get_variable` can help retrieve a Variable by a name, a Variable may store in a parent block, but might be retrieved in a child block, so block should have a variable scope that supports inheritance.
The method `pd.get_variable` can help retrieve a Variable by the name. The Variable may be stored in a parent block, but might be retrieved in a child block, so block should have a variable scope that supports inheritance.
In compiler design, the symbol table is a data structure created and maintained by compilers to store information about the occurrence of various entities such as variable names, function names, classes, etc.
To store the definition of variables and operators, we define a C++ class `SymbolTable`, like the one used in compilers.
`SymbolTable` can do the following stuff:
`SymbolTable` can do the following:
- store the definitions (some names and attributes) of variables and operators,
- to verify if a variable was declared,
- to make it possible to implement type checking (offer Protobuf message pointers to `InferShape` handlers).
- verify if a variable was declared,
- make it possible to implement type checking (offer Protobuf message pointers to `InferShape` handlers).
```c++
......@@ -240,19 +240,18 @@ class SymbolTable {
OpDesc* NewOp(const string& name="");
// TODO determine whether name is generated by python or C++
// currently assume that a unique name will be generated by C++ if the
// argument name left default.
// TODO determine whether name is generated by python or C++.
// Currently assume that a unique name will be generated by C++ if the
// argument name is left default.
VarDesc* NewVar(const string& name="");
// find a VarDesc by name, if recursive true, find parent's SymbolTable
// find a VarDesc by name, if recursive is true, find parent's SymbolTable
// recursively.
// this interface is introduced to support InferShape, find protobuf messages
// of variables and operators, pass pointers into InferShape.
// operator
//
// NOTE maybe some C++ classes such as VarDescBuilder and OpDescBuilder should
// be proposed and embedded into pybind to enable python operate on C++ pointers.
// be proposed and embedded into pybind to enable python operation on C++ pointers.
VarDesc* FindVar(const string& name, bool recursive=true);
OpDesc* FindOp(const string& name);
......@@ -270,7 +269,7 @@ class SymbolTable {
After all the description of variables and operators is added into SymbolTable,
the block has enough information to run.
The `Block` class takes a `BlockDesc` as input, and provide `Run` and `InferShape` functions.
The `Block` class takes a `BlockDesc` as input, and provides `Run` and `InferShape` functions.
```c++
......@@ -302,7 +301,7 @@ public:
void CreateVariables(const framework::Scope& scope);
void CreateOperators();
// some other necessary interfaces of NetOp are list below
// some other necessary interfaces of NetOp are listed below
// ...
private:
......@@ -316,15 +315,14 @@ private:
Block inherits from OperatorBase, which has a Run method.
Block's Run method will run its operators sequentially.
There is another important interface called `Eval`, which take some arguments called targets, and generate a minimal graph which takes targets as the end points and creates a new Block,
after `Run`, `Eval` will get the latest value and return the targets.
There is another important interface called `Eval`, which takes some arguments called targets and generates a minimal graph which treats targets as the end points and creates a new Block. After `Run`, `Eval` will get the latest value and return the targets.
The definition of Eval is as follows:
```c++
// clean a block description by targets using the corresponding dependency graph.
// return a new BlockDesc with minimal number of operators.
// NOTE not return a Block but the block's description so that this can be distributed
// NOTE: The return type is not a Block but the block's description so that this can be distributed
// to a cluster.
BlockDesc Prune(const BlockDesc& desc, vector<string> targets);
......
......@@ -198,13 +198,13 @@
<p>Both deep learning systems and programming languages help users describe computation procedures. These systems use various representations of computation:</p>
<ul class="simple">
<li>Caffe, Torch, and Paddle: sequences of layers.</li>
<li>TensorFlow, Caffe2, Mxnet: graphs of operators.</li>
<li>TensorFlow, Caffe2, Mxnet: graph of operators.</li>
<li>PaddlePaddle: nested blocks, like C++ and Java programs.</li>
</ul>
</div>
<div class="section" id="block-in-programming-languages-and-deep-learning">
<span id="block-in-programming-languages-and-deep-learning"></span><h2>Block in Programming Languages and Deep Learning<a class="headerlink" href="#block-in-programming-languages-and-deep-learning" title="永久链接至标题"></a></h2>
<p>In programming languages, a block is a pair of curly braces that includes local variables definitions and a sequence of instructions, or operators.</p>
<p>In programming languages, a block is a pair of curly braces that includes local variables definitions and a sequence of instructions or operators.</p>
<p>Blocks work with control flow structures like <code class="docutils literal"><span class="pre">if</span></code>, <code class="docutils literal"><span class="pre">else</span></code>, and <code class="docutils literal"><span class="pre">for</span></code>, which have equivalents in deep learning:</p>
<p>| programming languages | PaddlePaddle |
|&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8211;|&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8211;|
......@@ -215,13 +215,13 @@
</div>
<div class="section" id="stack-frames-and-the-scope-hierarchy">
<span id="stack-frames-and-the-scope-hierarchy"></span><h2>Stack Frames and the Scope Hierarchy<a class="headerlink" href="#stack-frames-and-the-scope-hierarchy" title="永久链接至标题"></a></h2>
<p>The existence of the backward makes the execution of a block of traditional programs and PaddlePaddle different to each other:</p>
<p>| programming languages | PaddlePaddle |
|&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8211;|&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;-|
| stack | scope hierarchy |
| stack frame | scope |
| push at entering block| push at entering block |
| pop at leaving block | destroy at minibatch completes|</p>
<p>The existence of the backward pass makes the execution of a block of PaddlePaddle different from traditional programs:</p>
<p>| programming languages | PaddlePaddle |
|&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8211;|&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;|
| stack | scope hierarchy |
| stack frame | scope |
| push at entering block| push at entering block |
| pop at leaving block | destroy when minibatch completes|</p>
<ol class="simple">
<li>In traditional programs:<ul>
<li>When the execution enters the left curly brace of a block, the runtime pushes a frame into the stack, where it realizes local variables.</li>
......@@ -231,9 +231,9 @@
</li>
<li>In PaddlePaddle<ul>
<li>When the execution enters a block, PaddlePaddle adds a new scope, where it realizes variables.</li>
<li>PaddlePaddle doesn&#8217;t pop a scope after the execution of the block because variables therein are to be used by the backward pass. So it has a stack forest known as a <em>scope hierarchy</em>.</li>
<li>PaddlePaddle doesn&#8217;t pop a scope after the execution of the block because variables therein are used by the backward pass. So it has a stack forest known as a <em>scope hierarchy</em>.</li>
<li>The height of the highest tree is the maximum depth of nested blocks.</li>
<li>After the process of a minibatch, PaddlePaddle destroys the scope hierarchy.</li>
<li>After the processing of a minibatch, PaddlePaddle destroys the scope hierarchy.</li>
</ul>
</li>
</ol>
......@@ -280,12 +280,12 @@
<span class="n">o1</span><span class="p">,</span> <span class="n">o2</span> <span class="o">=</span> <span class="n">ie</span><span class="p">(</span><span class="n">cond</span><span class="p">)</span>
</pre></div>
</div>
<p>In both examples, the left branch computes <code class="docutils literal"><span class="pre">x+y</span></code> and <code class="docutils literal"><span class="pre">softmax(x+y)</span></code>, the right branch computes <code class="docutils literal"><span class="pre">x+1</span></code> and <code class="docutils literal"><span class="pre">fc(x)</span></code>.</p>
<p>A difference is that variables in the C++ program contain scalar values, whereas those in the PaddlePaddle programs are mini-batches of instances. The <code class="docutils literal"><span class="pre">ie.input(true,</span> <span class="pre">0)</span></code> invocation returns instances in the 0-th input, <code class="docutils literal"><span class="pre">x</span></code>, that corresponds to true values in <code class="docutils literal"><span class="pre">cond</span></code> as the local variable <code class="docutils literal"><span class="pre">x</span></code>, where <code class="docutils literal"><span class="pre">ie.input(false,</span> <span class="pre">0)</span></code> returns instances corresponding to false values.</p>
<p>In both examples, the left branch computes <code class="docutils literal"><span class="pre">x+y</span></code> and <code class="docutils literal"><span class="pre">softmax(x+y)</span></code>, the right branch computes <code class="docutils literal"><span class="pre">fc(x)</span></code> and <code class="docutils literal"><span class="pre">x+1</span></code> .</p>
<p>The difference is that variables in the C++ program contain scalar values, whereas those in the PaddlePaddle programs are mini-batches of instances.</p>
</div>
<div class="section" id="blocks-with-for-and-rnnop">
<span id="blocks-with-for-and-rnnop"></span><h3>Blocks with <code class="docutils literal"><span class="pre">for</span></code> and <code class="docutils literal"><span class="pre">RNNOp</span></code><a class="headerlink" href="#blocks-with-for-and-rnnop" title="永久链接至标题"></a></h3>
<p>The following RNN model from the <a class="reference external" href="design/rnn.md">RNN design doc</a></p>
<p>The following RNN model in PaddlePaddle from the <a class="reference external" href="design/rnn.md">RNN design doc</a> :</p>
<div class="highlight-python"><div class="highlight"><pre><span></span><span class="n">x</span> <span class="o">=</span> <span class="n">sequence</span><span class="p">([</span><span class="mi">10</span><span class="p">,</span> <span class="mi">20</span><span class="p">,</span> <span class="mi">30</span><span class="p">])</span> <span class="c1"># shape=[None, 1]</span>
<span class="n">m</span> <span class="o">=</span> <span class="n">var</span><span class="p">(</span><span class="mi">0</span><span class="p">)</span> <span class="c1"># shape=[1]</span>
<span class="n">W</span> <span class="o">=</span> <span class="n">var</span><span class="p">(</span><span class="mf">0.314</span><span class="p">,</span> <span class="n">param</span><span class="o">=</span><span class="n">true</span><span class="p">)</span> <span class="c1"># shape=[1]</span>
......@@ -294,9 +294,9 @@
<span class="n">rnn</span> <span class="o">=</span> <span class="n">pd</span><span class="o">.</span><span class="n">rnn</span><span class="p">()</span>
<span class="k">with</span> <span class="n">rnn</span><span class="o">.</span><span class="n">step</span><span class="p">():</span>
<span class="n">h</span> <span class="o">=</span> <span class="n">rnn</span><span class="o">.</span><span class="n">memory</span><span class="p">(</span><span class="n">init</span> <span class="o">=</span> <span class="n">m</span><span class="p">)</span>
<span class="n">hh</span> <span class="o">=</span> <span class="n">rnn</span><span class="o">.</span><span class="n">previous_memory</span><span class="p">(</span><span class="n">h</span><span class="p">)</span>
<span class="n">h_prev</span> <span class="o">=</span> <span class="n">rnn</span><span class="o">.</span><span class="n">previous_memory</span><span class="p">(</span><span class="n">h</span><span class="p">)</span>
<span class="n">a</span> <span class="o">=</span> <span class="n">layer</span><span class="o">.</span><span class="n">fc</span><span class="p">(</span><span class="n">W</span><span class="p">,</span> <span class="n">x</span><span class="p">)</span>
<span class="n">b</span> <span class="o">=</span> <span class="n">layer</span><span class="o">.</span><span class="n">fc</span><span class="p">(</span><span class="n">U</span><span class="p">,</span> <span class="n">hh</span><span class="p">)</span>
<span class="n">b</span> <span class="o">=</span> <span class="n">layer</span><span class="o">.</span><span class="n">fc</span><span class="p">(</span><span class="n">U</span><span class="p">,</span> <span class="n">h_prev</span><span class="p">)</span>
<span class="n">s</span> <span class="o">=</span> <span class="n">pd</span><span class="o">.</span><span class="n">add</span><span class="p">(</span><span class="n">a</span><span class="p">,</span> <span class="n">b</span><span class="p">)</span>
<span class="n">act</span> <span class="o">=</span> <span class="n">pd</span><span class="o">.</span><span class="n">sigmoid</span><span class="p">(</span><span class="n">s</span><span class="p">)</span>
<span class="n">rnn</span><span class="o">.</span><span class="n">update_memory</span><span class="p">(</span><span class="n">h</span><span class="p">,</span> <span class="n">act</span><span class="p">)</span>
......@@ -330,8 +330,8 @@
</div>
<div class="section" id="compilation-and-execution">
<span id="compilation-and-execution"></span><h2>Compilation and Execution<a class="headerlink" href="#compilation-and-execution" title="永久链接至标题"></a></h2>
<p>Like TensorFlow programs, a PaddlePaddle program is written in Python. The first part describes a neural network as a protobuf message, and the rest part executes the message for training or inference.</p>
<p>The generation of this protobuf message is like what a compiler generates a binary executable file. The execution of the message that the OS executes the binary file.</p>
<p>Like TensorFlow, a PaddlePaddle program is written in Python. The first part describes a neural network as a protobuf message, and the rest executes the message for training or inference.</p>
<p>The generation of this protobuf message is similar to how a compiler generates a binary executable file. The execution of the message is similar to how the OS executes the binary file.</p>
</div>
<div class="section" id="the-binary-executable-file-format">
<span id="the-binary-executable-file-format"></span><h2>The &#8220;Binary Executable File Format&#8221;<a class="headerlink" href="#the-binary-executable-file-format" title="永久链接至标题"></a></h2>
......@@ -362,8 +362,8 @@
</div>
<p>Also, the RNN operator in above example is serialized into a protobuf message of type <code class="docutils literal"><span class="pre">OpDesc</span></code> and would look like:</p>
<div class="highlight-default"><div class="highlight"><pre><span></span><span class="n">OpDesc</span> <span class="p">{</span>
<span class="n">inputs</span> <span class="o">=</span> <span class="p">{</span><span class="mi">0</span><span class="p">}</span> <span class="o">//</span> <span class="n">the</span> <span class="n">index</span> <span class="n">of</span> <span class="n">x</span>
<span class="n">outputs</span> <span class="o">=</span> <span class="p">{</span><span class="mi">5</span><span class="p">,</span> <span class="mi">3</span><span class="p">}</span> <span class="o">//</span> <span class="n">indices</span> <span class="n">of</span> <span class="n">act</span> <span class="ow">and</span> <span class="n">hidden_out</span>
<span class="n">inputs</span> <span class="o">=</span> <span class="p">{</span><span class="mi">0</span><span class="p">}</span> <span class="o">//</span> <span class="n">the</span> <span class="n">index</span> <span class="n">of</span> <span class="n">x</span> <span class="ow">in</span> <span class="nb">vars</span> <span class="n">of</span> <span class="n">BlockDesc</span> <span class="n">above</span>
<span class="n">outputs</span> <span class="o">=</span> <span class="p">{</span><span class="mi">5</span><span class="p">,</span> <span class="mi">3</span><span class="p">}</span> <span class="o">//</span> <span class="n">indices</span> <span class="n">of</span> <span class="n">act</span> <span class="ow">and</span> <span class="n">hidden_out</span> <span class="ow">in</span> <span class="nb">vars</span> <span class="n">of</span> <span class="n">BlockDesc</span> <span class="n">above</span>
<span class="n">attrs</span> <span class="p">{</span>
<span class="s2">&quot;memories&quot;</span> <span class="p">:</span> <span class="p">{</span><span class="mi">1</span><span class="p">}</span> <span class="o">//</span> <span class="n">the</span> <span class="n">index</span> <span class="n">of</span> <span class="n">h</span>
<span class="s2">&quot;step_net&quot;</span> <span class="p">:</span> <span class="o">&lt;</span><span class="n">above</span> <span class="n">step</span> <span class="n">net</span><span class="o">&gt;</span>
......@@ -377,12 +377,12 @@
<span id="the-compilation-of-blocks"></span><h2>The Compilation of Blocks<a class="headerlink" href="#the-compilation-of-blocks" title="永久链接至标题"></a></h2>
<p>During the generation of the Protobuf message, the Block should store VarDesc (the Protobuf message which describes Variable) and OpDesc (the Protobuf message which describes Operator).</p>
<p>VarDesc in a block should have its name scope to avoid local variables affect parent block&#8217;s name scope.
Child block&#8217;s name scopes should inherit the parent&#8217;s so that OpDesc in child block can reference a VarDesc that stored in parent block. For example</p>
<div class="highlight-python"><div class="highlight"><pre><span></span><span class="n">a</span> <span class="o">=</span> <span class="n">pd</span><span class="o">.</span><span class="n">Varaible</span><span class="p">(</span><span class="n">shape</span><span class="o">=</span><span class="p">[</span><span class="mi">20</span><span class="p">,</span> <span class="mi">20</span><span class="p">])</span>
Child block&#8217;s name scopes should inherit the parent&#8217;s so that OpDesc in child block can reference a VarDesc that stored in parent block. For example:</p>
<div class="highlight-python"><div class="highlight"><pre><span></span><span class="n">a</span> <span class="o">=</span> <span class="n">pd</span><span class="o">.</span><span class="n">Variable</span><span class="p">(</span><span class="n">shape</span><span class="o">=</span><span class="p">[</span><span class="mi">20</span><span class="p">,</span> <span class="mi">20</span><span class="p">])</span>
<span class="n">b</span> <span class="o">=</span> <span class="n">pd</span><span class="o">.</span><span class="n">fc</span><span class="p">(</span><span class="n">a</span><span class="p">,</span> <span class="n">params</span><span class="o">=</span><span class="p">[</span><span class="s2">&quot;fc.w&quot;</span><span class="p">,</span> <span class="s2">&quot;fc.b&quot;</span><span class="p">])</span>
<span class="n">rnn</span> <span class="o">=</span> <span class="n">pd</span><span class="o">.</span><span class="n">create_rnn</span><span class="p">()</span>
<span class="k">with</span> <span class="n">rnn</span><span class="o">.</span><span class="n">stepnet</span><span class="p">()</span>
<span class="k">with</span> <span class="n">rnn</span><span class="o">.</span><span class="n">stepnet</span><span class="p">():</span>
<span class="n">x</span> <span class="o">=</span> <span class="n">a</span><span class="o">.</span><span class="n">as_step_input</span><span class="p">()</span>
<span class="c1"># reuse fc&#39;s parameter</span>
<span class="n">fc_without_b</span> <span class="o">=</span> <span class="n">pd</span><span class="o">.</span><span class="n">get_variable</span><span class="p">(</span><span class="s2">&quot;fc.w&quot;</span><span class="p">)</span>
......@@ -391,14 +391,14 @@ Child block&#8217;s name scopes should inherit the parent&#8217;s so that OpDesc
<span class="n">out</span> <span class="o">=</span> <span class="n">rnn</span><span class="p">()</span>
</pre></div>
</div>
<p>the method <code class="docutils literal"><span class="pre">pd.get_variable</span></code> can help retrieve a Variable by a name, a Variable may store in a parent block, but might be retrieved in a child block, so block should have a variable scope that supports inheritance.</p>
<p>The method <code class="docutils literal"><span class="pre">pd.get_variable</span></code> can help retrieve a Variable by the name. The Variable may be stored in a parent block, but might be retrieved in a child block, so block should have a variable scope that supports inheritance.</p>
<p>In compiler design, the symbol table is a data structure created and maintained by compilers to store information about the occurrence of various entities such as variable names, function names, classes, etc.</p>
<p>To store the definition of variables and operators, we define a C++ class <code class="docutils literal"><span class="pre">SymbolTable</span></code>, like the one used in compilers.</p>
<p><code class="docutils literal"><span class="pre">SymbolTable</span></code> can do the following stuff:</p>
<p><code class="docutils literal"><span class="pre">SymbolTable</span></code> can do the following:</p>
<ul class="simple">
<li>store the definitions (some names and attributes) of variables and operators,</li>
<li>to verify if a variable was declared,</li>
<li>to make it possible to implement type checking (offer Protobuf message pointers to <code class="docutils literal"><span class="pre">InferShape</span></code> handlers).</li>
<li>verify if a variable was declared,</li>
<li>make it possible to implement type checking (offer Protobuf message pointers to <code class="docutils literal"><span class="pre">InferShape</span></code> handlers).</li>
</ul>
<div class="highlight-c++"><div class="highlight"><pre><span></span><span class="c1">// Information in SymbolTable is enough to trace the dependency graph. So maybe</span>
<span class="c1">// the Eval() interface takes a SymbolTable is enough.</span>
......@@ -408,19 +408,18 @@ Child block&#8217;s name scopes should inherit the parent&#8217;s so that OpDesc
<span class="n">OpDesc</span><span class="o">*</span> <span class="n">NewOp</span><span class="p">(</span><span class="k">const</span> <span class="n">string</span><span class="o">&amp;</span> <span class="n">name</span><span class="o">=</span><span class="s">&quot;&quot;</span><span class="p">);</span>
<span class="c1">// TODO determine whether name is generated by python or C++</span>
<span class="c1">// currently assume that a unique name will be generated by C++ if the</span>
<span class="c1">// argument name left default.</span>
<span class="c1">// TODO determine whether name is generated by python or C++.</span>
<span class="c1">// Currently assume that a unique name will be generated by C++ if the</span>
<span class="c1">// argument name is left default.</span>
<span class="n">VarDesc</span><span class="o">*</span> <span class="nf">NewVar</span><span class="p">(</span><span class="k">const</span> <span class="n">string</span><span class="o">&amp;</span> <span class="n">name</span><span class="o">=</span><span class="s">&quot;&quot;</span><span class="p">);</span>
<span class="c1">// find a VarDesc by name, if recursive true, find parent&#39;s SymbolTable</span>
<span class="c1">// find a VarDesc by name, if recursive is true, find parent&#39;s SymbolTable</span>
<span class="c1">// recursively.</span>
<span class="c1">// this interface is introduced to support InferShape, find protobuf messages</span>
<span class="c1">// of variables and operators, pass pointers into InferShape.</span>
<span class="c1">// operator</span>
<span class="c1">//</span>
<span class="c1">// NOTE maybe some C++ classes such as VarDescBuilder and OpDescBuilder should</span>
<span class="c1">// be proposed and embedded into pybind to enable python operate on C++ pointers.</span>
<span class="c1">// be proposed and embedded into pybind to enable python operation on C++ pointers.</span>
<span class="n">VarDesc</span><span class="o">*</span> <span class="nf">FindVar</span><span class="p">(</span><span class="k">const</span> <span class="n">string</span><span class="o">&amp;</span> <span class="n">name</span><span class="p">,</span> <span class="kt">bool</span> <span class="n">recursive</span><span class="o">=</span><span class="nb">true</span><span class="p">);</span>
<span class="n">OpDesc</span><span class="o">*</span> <span class="nf">FindOp</span><span class="p">(</span><span class="k">const</span> <span class="n">string</span><span class="o">&amp;</span> <span class="n">name</span><span class="p">);</span>
......@@ -437,7 +436,7 @@ Child block&#8217;s name scopes should inherit the parent&#8217;s so that OpDesc
</div>
<p>After all the description of variables and operators is added into SymbolTable,
the block has enough information to run.</p>
<p>The <code class="docutils literal"><span class="pre">Block</span></code> class takes a <code class="docutils literal"><span class="pre">BlockDesc</span></code> as input, and provide <code class="docutils literal"><span class="pre">Run</span></code> and <code class="docutils literal"><span class="pre">InferShape</span></code> functions.</p>
<p>The <code class="docutils literal"><span class="pre">Block</span></code> class takes a <code class="docutils literal"><span class="pre">BlockDesc</span></code> as input, and provides <code class="docutils literal"><span class="pre">Run</span></code> and <code class="docutils literal"><span class="pre">InferShape</span></code> functions.</p>
<div class="highlight-c++"><div class="highlight"><pre><span></span><span class="k">namespace</span> <span class="p">{</span>
<span class="k">class</span> <span class="nc">Block</span> <span class="o">:</span> <span class="n">OperatorBase</span> <span class="p">{</span>
......@@ -466,7 +465,7 @@ the block has enough information to run.</p>
<span class="kt">void</span> <span class="n">CreateVariables</span><span class="p">(</span><span class="k">const</span> <span class="n">framework</span><span class="o">::</span><span class="n">Scope</span><span class="o">&amp;</span> <span class="n">scope</span><span class="p">);</span>
<span class="kt">void</span> <span class="nf">CreateOperators</span><span class="p">();</span>
<span class="c1">// some other necessary interfaces of NetOp are list below</span>
<span class="c1">// some other necessary interfaces of NetOp are listed below</span>
<span class="c1">// ...</span>
<span class="k">private</span><span class="o">:</span>
......@@ -480,12 +479,11 @@ the block has enough information to run.</p>
<span id="the-execution-of-blocks"></span><h2>The Execution of Blocks<a class="headerlink" href="#the-execution-of-blocks" title="永久链接至标题"></a></h2>
<p>Block inherits from OperatorBase, which has a Run method.
Block&#8217;s Run method will run its operators sequentially.</p>
<p>There is another important interface called <code class="docutils literal"><span class="pre">Eval</span></code>, which take some arguments called targets, and generate a minimal graph which takes targets as the end points and creates a new Block,
after <code class="docutils literal"><span class="pre">Run</span></code>, <code class="docutils literal"><span class="pre">Eval</span></code> will get the latest value and return the targets.</p>
<p>There is another important interface called <code class="docutils literal"><span class="pre">Eval</span></code>, which takes some arguments called targets and generates a minimal graph which treats targets as the end points and creates a new Block. After <code class="docutils literal"><span class="pre">Run</span></code>, <code class="docutils literal"><span class="pre">Eval</span></code> will get the latest value and return the targets.</p>
<p>The definition of Eval is as follows:</p>
<div class="highlight-c++"><div class="highlight"><pre><span></span><span class="c1">// clean a block description by targets using the corresponding dependency graph.</span>
<span class="c1">// return a new BlockDesc with minimal number of operators.</span>
<span class="c1">// NOTE not return a Block but the block&#39;s description so that this can be distributed</span>
<span class="c1">// NOTE: The return type is not a Block but the block&#39;s description so that this can be distributed</span>
<span class="c1">// to a cluster.</span>
<span class="n">BlockDesc</span> <span class="nf">Prune</span><span class="p">(</span><span class="k">const</span> <span class="n">BlockDesc</span><span class="o">&amp;</span> <span class="n">desc</span><span class="p">,</span> <span class="n">vector</span><span class="o">&lt;</span><span class="n">string</span><span class="o">&gt;</span> <span class="n">targets</span><span class="p">);</span>
......
因为 它太大了无法显示 source diff 。你可以改为 查看blob
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册