提交 a09a1ffd 编写于 作者: T Travis CI

Deploy to GitHub Pages: 118d950e

上级 e5e21f22
# Design Doc: Parallel_Do in PaddlePaddle
In PaddlePaddle, we use parallel_do primitive to represent multithread data parallel processing.
## Design overview
The definition of a parallel_do op looks like the following
```c++
AddInput(kInputs, "Inputs needed to be split onto different devices").AsDuplicable();
AddInput(kParameters, "Parameters are duplicated over different devices")
.AsDuplicable();
AddInput(kPlaces, "Devices used for parallel processing");
AddOutput(kOutputs, "Outputs needed to be merged from different devices").AsDuplicable();
AddOutput(kParallelScopes,
"Scopes for all local variables in forward pass. One scope for each device");
AddAttr<framework::BlockDesc *>(kParallelBlock,
"List of operaters to be executed in parallel");
```
A vanilla implementation of parallel_do can be shown as the following (`|` means single thread and
`||||` means multiple threads)
```
In the forward pass
| Split input onto different devices
| Copy parameter to onto different devices
|||| Compute forward pass in parallel
| Merge output from different devices
In the backward pass
| Split output@grad onto different devices
|||| Compute backward pass in parallel
| accumulate param@grad from different devices to the first device
| Merge input@grad from different devices
 | Copy param@grad to the place of parallel_do_op
```
This implementation allows to write mixed device program like this
```python
# get embedding feature on CPU
feature = some_cpu_only_op(data)
gpu_places = get_place(use_gpu=True)
# parallel processing on multiple GPUs
pd = ParallelDo(gpu_places)
with pd.do():
read_input(feature)
prediction = my_net(feature)
write_output(prediction)
prediction = pd()
loss = cross_entropy(prediction, label)
```
And the programDesc are like the following
```
# start_program will be run by executor(CPUPlace), all w1, w2 will be allocated on CPU
start_program
{
vars: w1, w2
ops: init(w1), init(w2)
}
main_program
{
block0 {
vars: data, places, w1, w2
ops: data, get_place, parallel_do(block1),
parallel_do_grad(block2),
sgd(w2, w2_grad),
sgd(w1, w1_grad)
}
block1 {
parent_block: 0
vars: data, h1, h2, loss
ops: fc, fc, softmax
}
block2 {
parent_block: 1
vars: data_grad, h1_grad, h2_grad, loss_gard, w1_grad, w2_grad
ops: softmax_grad,
fc_grad
fc_grad
}
}
```
## Proformance Imporvement
There are serial places we can make this parallel_do faster.
### forward: split input onto different devices
If the input of the parallel_do is independent from any prior opeartors, we can avoid this step by
prefetching the input onto different devices in a seperate background thread. And the python code
looks like this.
```python
pd = ParallelDo(gpu_places)
with pd.do():
   feature = get_data_from_prefetch_queue(gpu_places)
prediction = my_net(feature)
write_output(activation)
```
### forward: Copy parameter to onto different devices
We can avoid this step by making each device have a copy of the parameter. This requires:
1. `fluid.default_start_up_program()` to be run on all devices
1. In the backward, allreduce param@grad at different devices, this requires
1. `backward.py` add `allreduce` operators at parallel_do_grad
1. `allreduce` operators need to be called in async mode to achieve maximum throughput
1. apply gradients related op(i.e. cliping, normalization, decay, sgd) on different devices in parallel
By doing so, we also avoided "backward: accumulate param@grad from different devices to the first device".
And the ProgramDesc looks like the following
```
# w1, w2 will be allocated on all GPUs
start_program
{
block0 {
parallel_do(block1)
}
block1 {
parent_block: 0
vars: w1, w2
ops: init(w1), init(w2)
}
}
main_program
{
block0 {
vars: data, places, w1, w2
ops: data, get_place, parallel_do(block1),
parallel_do_grad(block2), # append_backward
parallel_do(block3) # append_optimization
}
block1 {
parent_block: 0
vars: data, h1, h2, loss
ops: fc, fc, softmax
}
block2 {
parent_block: 1
vars: data_grad, h1_grad, h2_grad, loss_gard, w1_grad, w2_grad
ops: softmax_grad,
fc_grad, allreduce(places, scopes, w1_grad),
fc_grad, allreduce(places, scopes, w2_grad)
}
block3 {
parent_block: 0
vars: lr
ops: sgd(w2, w2_grad),
sgd(w1, w1_grad)
}
}
```
<!DOCTYPE html>
<!--[if IE 8]><html class="no-js lt-ie9" lang="en" > <![endif]-->
<!--[if gt IE 8]><!--> <html class="no-js" lang="en" > <!--<![endif]-->
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Design Doc: Parallel_Do in PaddlePaddle &mdash; PaddlePaddle documentation</title>
<link rel="stylesheet" href="../_static/css/theme.css" type="text/css" />
<link rel="index" title="Index"
href="../genindex.html"/>
<link rel="search" title="Search" href="../search.html"/>
<link rel="top" title="PaddlePaddle documentation" href="../index.html"/>
<link rel="stylesheet" href="https://cdn.jsdelivr.net/perfect-scrollbar/0.6.14/css/perfect-scrollbar.min.css" type="text/css" />
<link rel="stylesheet" href="../_static/css/override.css" type="text/css" />
<script>
var _hmt = _hmt || [];
(function() {
var hm = document.createElement("script");
hm.src = "//hm.baidu.com/hm.js?b9a314ab40d04d805655aab1deee08ba";
var s = document.getElementsByTagName("script")[0];
s.parentNode.insertBefore(hm, s);
})();
</script>
<script src="../_static/js/modernizr.min.js"></script>
</head>
<body class="wy-body-for-nav" role="document">
<header class="site-header">
<div class="site-logo">
<a href="/"><img src="../_static/images/PP_w.png"></a>
</div>
<div class="site-nav-links">
<div class="site-menu">
<a class="fork-on-github" href="https://github.com/PaddlePaddle/Paddle" target="_blank"><i class="fa fa-github"></i>Fork me on Github</a>
<div class="language-switcher dropdown">
<a type="button" data-toggle="dropdown">
<span>English</span>
<i class="fa fa-angle-up"></i>
<i class="fa fa-angle-down"></i>
</a>
<ul class="dropdown-menu">
<li><a href="/doc_cn">中文</a></li>
<li><a href="/doc">English</a></li>
</ul>
</div>
<ul class="site-page-links">
<li><a href="/">Home</a></li>
</ul>
</div>
<div class="doc-module">
<ul>
<li class="toctree-l1"><a class="reference internal" href="../getstarted/index_en.html">GET STARTED</a></li>
<li class="toctree-l1"><a class="reference internal" href="../build_and_install/index_en.html">Install and Build</a></li>
<li class="toctree-l1"><a class="reference internal" href="../howto/index_en.html">HOW TO</a></li>
<li class="toctree-l1"><a class="reference internal" href="../dev/index_en.html">Development</a></li>
</ul>
<div role="search">
<form id="rtd-search-form" class="wy-form" action="../search.html" method="get">
<input type="text" name="q" placeholder="Search docs" />
<input type="hidden" name="check_keywords" value="yes" />
<input type="hidden" name="area" value="default" />
</form>
</div>
</div>
</div>
</header>
<div class="main-content-wrap">
<nav class="doc-menu-vertical" role="navigation">
<ul>
<li class="toctree-l1"><a class="reference internal" href="../getstarted/index_en.html">GET STARTED</a><ul>
<li class="toctree-l2"><a class="reference internal" href="../getstarted/quickstart_en.html">Quick Start</a></li>
</ul>
</li>
<li class="toctree-l1"><a class="reference internal" href="../build_and_install/index_en.html">Install and Build</a><ul>
<li class="toctree-l2"><a class="reference internal" href="../build_and_install/pip_install_en.html">Install Using pip</a></li>
<li class="toctree-l2"><a class="reference internal" href="../build_and_install/docker_install_en.html">Run in Docker Containers</a></li>
<li class="toctree-l2"><a class="reference internal" href="../build_and_install/build_from_source_en.html">Build from Sources</a></li>
</ul>
</li>
<li class="toctree-l1"><a class="reference internal" href="../howto/index_en.html">HOW TO</a><ul>
<li class="toctree-l2"><a class="reference internal" href="../howto/cmd_parameter/index_en.html">Set Command-line Parameters</a><ul>
<li class="toctree-l3"><a class="reference internal" href="../howto/cmd_parameter/use_case_en.html">Use Case</a></li>
<li class="toctree-l3"><a class="reference internal" href="../howto/cmd_parameter/arguments_en.html">Argument Outline</a></li>
<li class="toctree-l3"><a class="reference internal" href="../howto/cmd_parameter/detail_introduction_en.html">Detail Description</a></li>
</ul>
</li>
<li class="toctree-l2"><a class="reference internal" href="../howto/cluster/index_en.html">Distributed Training</a><ul>
<li class="toctree-l3"><a class="reference internal" href="../howto/cluster/preparations_en.html">Preparations</a></li>
<li class="toctree-l3"><a class="reference internal" href="../howto/cluster/cmd_argument_en.html">Command-line arguments</a></li>
<li class="toctree-l3"><a class="reference internal" href="../howto/cluster/multi_cluster/index_en.html">Use different clusters</a><ul>
<li class="toctree-l4"><a class="reference internal" href="../howto/cluster/multi_cluster/fabric_en.html">Cluster Training Using Fabric</a></li>
<li class="toctree-l4"><a class="reference internal" href="../howto/cluster/multi_cluster/openmpi_en.html">Cluster Training Using OpenMPI</a></li>
<li class="toctree-l4"><a class="reference internal" href="../howto/cluster/multi_cluster/k8s_en.html">PaddlePaddle On Kubernetes</a></li>
<li class="toctree-l4"><a class="reference internal" href="../howto/cluster/multi_cluster/k8s_aws_en.html">Distributed PaddlePaddle Training on AWS with Kubernetes</a></li>
</ul>
</li>
</ul>
</li>
<li class="toctree-l2"><a class="reference internal" href="../howto/rnn/index_en.html">RNN Models</a><ul>
<li class="toctree-l3"><a class="reference internal" href="../howto/rnn/rnn_config_en.html">RNN Configuration</a></li>
</ul>
</li>
<li class="toctree-l2"><a class="reference internal" href="../howto/optimization/gpu_profiling_en.html">Tune GPU Performance</a></li>
</ul>
</li>
<li class="toctree-l1"><a class="reference internal" href="../dev/index_en.html">Development</a><ul>
<li class="toctree-l2"><a class="reference internal" href="../dev/new_layer_en.html">Write New Layers</a></li>
<li class="toctree-l2"><a class="reference internal" href="../dev/contribute_to_paddle_en.html">Contribute Code</a></li>
<li class="toctree-l2"><a class="reference internal" href="../dev/write_docs_en.html">Contribute Documentation</a></li>
</ul>
</li>
</ul>
</nav>
<section class="doc-content-wrap">
<div role="navigation" aria-label="breadcrumbs navigation">
<ul class="wy-breadcrumbs">
<li>Design Doc: Parallel_Do in PaddlePaddle</li>
</ul>
</div>
<div class="wy-nav-content" id="doc-content">
<div class="rst-content">
<div role="main" class="document" itemscope="itemscope" itemtype="http://schema.org/Article">
<div itemprop="articleBody">
<div class="section" id="design-doc-parallel-do-in-paddlepaddle">
<span id="design-doc-parallel-do-in-paddlepaddle"></span><h1>Design Doc: Parallel_Do in PaddlePaddle<a class="headerlink" href="#design-doc-parallel-do-in-paddlepaddle" title="Permalink to this headline"></a></h1>
<p>In PaddlePaddle, we use parallel_do primitive to represent multithread data parallel processing.</p>
<div class="section" id="design-overview">
<span id="design-overview"></span><h2>Design overview<a class="headerlink" href="#design-overview" title="Permalink to this headline"></a></h2>
<p>The definition of a parallel_do op looks like the following</p>
<div class="highlight-c++"><div class="highlight"><pre><span></span><span class="n">AddInput</span><span class="p">(</span><span class="n">kInputs</span><span class="p">,</span> <span class="s">&quot;Inputs needed to be split onto different devices&quot;</span><span class="p">).</span><span class="n">AsDuplicable</span><span class="p">();</span>
<span class="n">AddInput</span><span class="p">(</span><span class="n">kParameters</span><span class="p">,</span> <span class="s">&quot;Parameters are duplicated over different devices&quot;</span><span class="p">)</span>
<span class="p">.</span><span class="n">AsDuplicable</span><span class="p">();</span>
<span class="n">AddInput</span><span class="p">(</span><span class="n">kPlaces</span><span class="p">,</span> <span class="s">&quot;Devices used for parallel processing&quot;</span><span class="p">);</span>
<span class="n">AddOutput</span><span class="p">(</span><span class="n">kOutputs</span><span class="p">,</span> <span class="s">&quot;Outputs needed to be merged from different devices&quot;</span><span class="p">).</span><span class="n">AsDuplicable</span><span class="p">();</span>
<span class="n">AddOutput</span><span class="p">(</span><span class="n">kParallelScopes</span><span class="p">,</span>
<span class="s">&quot;Scopes for all local variables in forward pass. One scope for each device&quot;</span><span class="p">);</span>
<span class="n">AddAttr</span><span class="o">&lt;</span><span class="n">framework</span><span class="o">::</span><span class="n">BlockDesc</span> <span class="o">*&gt;</span><span class="p">(</span><span class="n">kParallelBlock</span><span class="p">,</span>
<span class="s">&quot;List of operaters to be executed in parallel&quot;</span><span class="p">);</span>
</pre></div>
</div>
<p>A vanilla implementation of parallel_do can be shown as the following (<code class="docutils literal"><span class="pre">|</span></code> means single thread and
<code class="docutils literal"><span class="pre">||||</span></code> means multiple threads)</p>
<div class="highlight-default"><div class="highlight"><pre><span></span><span class="n">In</span> <span class="n">the</span> <span class="n">forward</span> <span class="k">pass</span>
<span class="o">|</span> <span class="n">Split</span> <span class="nb">input</span> <span class="n">onto</span> <span class="n">different</span> <span class="n">devices</span>
<span class="o">|</span> <span class="n">Copy</span> <span class="n">parameter</span> <span class="n">to</span> <span class="n">onto</span> <span class="n">different</span> <span class="n">devices</span>
<span class="o">||||</span> <span class="n">Compute</span> <span class="n">forward</span> <span class="k">pass</span> <span class="ow">in</span> <span class="n">parallel</span>
<span class="o">|</span> <span class="n">Merge</span> <span class="n">output</span> <span class="kn">from</span> <span class="nn">different</span> <span class="n">devices</span>
<span class="n">In</span> <span class="n">the</span> <span class="n">backward</span> <span class="k">pass</span>
<span class="o">|</span> <span class="n">Split</span> <span class="n">output</span><span class="nd">@grad</span> <span class="n">onto</span> <span class="n">different</span> <span class="n">devices</span>
<span class="o">||||</span> <span class="n">Compute</span> <span class="n">backward</span> <span class="k">pass</span> <span class="ow">in</span> <span class="n">parallel</span>
<span class="o">|</span> <span class="n">accumulate</span> <span class="n">param</span><span class="nd">@grad</span> <span class="kn">from</span> <span class="nn">different</span> <span class="n">devices</span> <span class="n">to</span> <span class="n">the</span> <span class="n">first</span> <span class="n">device</span>
<span class="o">|</span> <span class="n">Merge</span> <span class="nb">input</span><span class="nd">@grad</span> <span class="kn">from</span> <span class="nn">different</span> <span class="n">devices</span>
 <span class="o">|</span> <span class="n">Copy</span> <span class="n">param</span><span class="nd">@grad</span> <span class="n">to</span> <span class="n">the</span> <span class="n">place</span> <span class="n">of</span> <span class="n">parallel_do_op</span>
</pre></div>
</div>
<p>This implementation allows to write mixed device program like this</p>
<div class="highlight-python"><div class="highlight"><pre><span></span><span class="c1"># get embedding feature on CPU</span>
<span class="n">feature</span> <span class="o">=</span> <span class="n">some_cpu_only_op</span><span class="p">(</span><span class="n">data</span><span class="p">)</span>
<span class="n">gpu_places</span> <span class="o">=</span> <span class="n">get_place</span><span class="p">(</span><span class="n">use_gpu</span><span class="o">=</span><span class="bp">True</span><span class="p">)</span>
<span class="c1"># parallel processing on multiple GPUs</span>
<span class="n">pd</span> <span class="o">=</span> <span class="n">ParallelDo</span><span class="p">(</span><span class="n">gpu_places</span><span class="p">)</span>
<span class="k">with</span> <span class="n">pd</span><span class="o">.</span><span class="n">do</span><span class="p">():</span>
<span class="n">read_input</span><span class="p">(</span><span class="n">feature</span><span class="p">)</span>
<span class="n">prediction</span> <span class="o">=</span> <span class="n">my_net</span><span class="p">(</span><span class="n">feature</span><span class="p">)</span>
<span class="n">write_output</span><span class="p">(</span><span class="n">prediction</span><span class="p">)</span>
<span class="n">prediction</span> <span class="o">=</span> <span class="n">pd</span><span class="p">()</span>
<span class="n">loss</span> <span class="o">=</span> <span class="n">cross_entropy</span><span class="p">(</span><span class="n">prediction</span><span class="p">,</span> <span class="n">label</span><span class="p">)</span>
</pre></div>
</div>
<p>And the programDesc are like the following</p>
<div class="highlight-default"><div class="highlight"><pre><span></span><span class="c1"># start_program will be run by executor(CPUPlace), all w1, w2 will be allocated on CPU</span>
<span class="n">start_program</span>
<span class="p">{</span>
<span class="nb">vars</span><span class="p">:</span> <span class="n">w1</span><span class="p">,</span> <span class="n">w2</span>
<span class="n">ops</span><span class="p">:</span> <span class="n">init</span><span class="p">(</span><span class="n">w1</span><span class="p">),</span> <span class="n">init</span><span class="p">(</span><span class="n">w2</span><span class="p">)</span>
<span class="p">}</span>
<span class="n">main_program</span>
<span class="p">{</span>
<span class="n">block0</span> <span class="p">{</span>
<span class="nb">vars</span><span class="p">:</span> <span class="n">data</span><span class="p">,</span> <span class="n">places</span><span class="p">,</span> <span class="n">w1</span><span class="p">,</span> <span class="n">w2</span>
<span class="n">ops</span><span class="p">:</span> <span class="n">data</span><span class="p">,</span> <span class="n">get_place</span><span class="p">,</span> <span class="n">parallel_do</span><span class="p">(</span><span class="n">block1</span><span class="p">),</span>
<span class="n">parallel_do_grad</span><span class="p">(</span><span class="n">block2</span><span class="p">),</span>
<span class="n">sgd</span><span class="p">(</span><span class="n">w2</span><span class="p">,</span> <span class="n">w2_grad</span><span class="p">),</span>
<span class="n">sgd</span><span class="p">(</span><span class="n">w1</span><span class="p">,</span> <span class="n">w1_grad</span><span class="p">)</span>
<span class="p">}</span>
<span class="n">block1</span> <span class="p">{</span>
<span class="n">parent_block</span><span class="p">:</span> <span class="mi">0</span>
<span class="nb">vars</span><span class="p">:</span> <span class="n">data</span><span class="p">,</span> <span class="n">h1</span><span class="p">,</span> <span class="n">h2</span><span class="p">,</span> <span class="n">loss</span>
<span class="n">ops</span><span class="p">:</span> <span class="n">fc</span><span class="p">,</span> <span class="n">fc</span><span class="p">,</span> <span class="n">softmax</span>
<span class="p">}</span>
<span class="n">block2</span> <span class="p">{</span>
<span class="n">parent_block</span><span class="p">:</span> <span class="mi">1</span>
<span class="nb">vars</span><span class="p">:</span> <span class="n">data_grad</span><span class="p">,</span> <span class="n">h1_grad</span><span class="p">,</span> <span class="n">h2_grad</span><span class="p">,</span> <span class="n">loss_gard</span><span class="p">,</span> <span class="n">w1_grad</span><span class="p">,</span> <span class="n">w2_grad</span>
<span class="n">ops</span><span class="p">:</span> <span class="n">softmax_grad</span><span class="p">,</span>
<span class="n">fc_grad</span>
<span class="n">fc_grad</span>
<span class="p">}</span>
<span class="p">}</span>
</pre></div>
</div>
</div>
<div class="section" id="proformance-imporvement">
<span id="proformance-imporvement"></span><h2>Proformance Imporvement<a class="headerlink" href="#proformance-imporvement" title="Permalink to this headline"></a></h2>
<p>There are serial places we can make this parallel_do faster.</p>
<div class="section" id="forward-split-input-onto-different-devices">
<span id="forward-split-input-onto-different-devices"></span><h3>forward: split input onto different devices<a class="headerlink" href="#forward-split-input-onto-different-devices" title="Permalink to this headline"></a></h3>
<p>If the input of the parallel_do is independent from any prior opeartors, we can avoid this step by
prefetching the input onto different devices in a seperate background thread. And the python code
looks like this.</p>
<div class="highlight-python"><div class="highlight"><pre><span></span>pd = ParallelDo(gpu_places)
with pd.do():
   feature = get_data_from_prefetch_queue(gpu_places)
prediction = my_net(feature)
write_output(activation)
</pre></div>
</div>
</div>
<div class="section" id="forward-copy-parameter-to-onto-different-devices">
<span id="forward-copy-parameter-to-onto-different-devices"></span><h3>forward: Copy parameter to onto different devices<a class="headerlink" href="#forward-copy-parameter-to-onto-different-devices" title="Permalink to this headline"></a></h3>
<p>We can avoid this step by making each device have a copy of the parameter. This requires:</p>
<ol class="simple">
<li><code class="docutils literal"><span class="pre">fluid.default_start_up_program()</span></code> to be run on all devices</li>
<li>In the backward, allreduce param&#64;grad at different devices, this requires<ol>
<li><code class="docutils literal"><span class="pre">backward.py</span></code> add <code class="docutils literal"><span class="pre">allreduce</span></code> operators at parallel_do_grad</li>
<li><code class="docutils literal"><span class="pre">allreduce</span></code> operators need to be called in async mode to achieve maximum throughput</li>
</ol>
</li>
<li>apply gradients related op(i.e. cliping, normalization, decay, sgd) on different devices in parallel</li>
</ol>
<p>By doing so, we also avoided &#8220;backward: accumulate param&#64;grad from different devices to the first device&#8221;.
And the ProgramDesc looks like the following</p>
<div class="highlight-default"><div class="highlight"><pre><span></span><span class="c1"># w1, w2 will be allocated on all GPUs</span>
<span class="n">start_program</span>
<span class="p">{</span>
<span class="n">block0</span> <span class="p">{</span>
<span class="n">parallel_do</span><span class="p">(</span><span class="n">block1</span><span class="p">)</span>
<span class="p">}</span>
<span class="n">block1</span> <span class="p">{</span>
<span class="n">parent_block</span><span class="p">:</span> <span class="mi">0</span>
<span class="nb">vars</span><span class="p">:</span> <span class="n">w1</span><span class="p">,</span> <span class="n">w2</span>
<span class="n">ops</span><span class="p">:</span> <span class="n">init</span><span class="p">(</span><span class="n">w1</span><span class="p">),</span> <span class="n">init</span><span class="p">(</span><span class="n">w2</span><span class="p">)</span>
<span class="p">}</span>
<span class="p">}</span>
<span class="n">main_program</span>
<span class="p">{</span>
<span class="n">block0</span> <span class="p">{</span>
<span class="nb">vars</span><span class="p">:</span> <span class="n">data</span><span class="p">,</span> <span class="n">places</span><span class="p">,</span> <span class="n">w1</span><span class="p">,</span> <span class="n">w2</span>
<span class="n">ops</span><span class="p">:</span> <span class="n">data</span><span class="p">,</span> <span class="n">get_place</span><span class="p">,</span> <span class="n">parallel_do</span><span class="p">(</span><span class="n">block1</span><span class="p">),</span>
<span class="n">parallel_do_grad</span><span class="p">(</span><span class="n">block2</span><span class="p">),</span> <span class="c1"># append_backward</span>
<span class="n">parallel_do</span><span class="p">(</span><span class="n">block3</span><span class="p">)</span> <span class="c1"># append_optimization</span>
<span class="p">}</span>
<span class="n">block1</span> <span class="p">{</span>
<span class="n">parent_block</span><span class="p">:</span> <span class="mi">0</span>
<span class="nb">vars</span><span class="p">:</span> <span class="n">data</span><span class="p">,</span> <span class="n">h1</span><span class="p">,</span> <span class="n">h2</span><span class="p">,</span> <span class="n">loss</span>
<span class="n">ops</span><span class="p">:</span> <span class="n">fc</span><span class="p">,</span> <span class="n">fc</span><span class="p">,</span> <span class="n">softmax</span>
<span class="p">}</span>
<span class="n">block2</span> <span class="p">{</span>
<span class="n">parent_block</span><span class="p">:</span> <span class="mi">1</span>
<span class="nb">vars</span><span class="p">:</span> <span class="n">data_grad</span><span class="p">,</span> <span class="n">h1_grad</span><span class="p">,</span> <span class="n">h2_grad</span><span class="p">,</span> <span class="n">loss_gard</span><span class="p">,</span> <span class="n">w1_grad</span><span class="p">,</span> <span class="n">w2_grad</span>
<span class="n">ops</span><span class="p">:</span> <span class="n">softmax_grad</span><span class="p">,</span>
<span class="n">fc_grad</span><span class="p">,</span> <span class="n">allreduce</span><span class="p">(</span><span class="n">places</span><span class="p">,</span> <span class="n">scopes</span><span class="p">,</span> <span class="n">w1_grad</span><span class="p">),</span>
<span class="n">fc_grad</span><span class="p">,</span> <span class="n">allreduce</span><span class="p">(</span><span class="n">places</span><span class="p">,</span> <span class="n">scopes</span><span class="p">,</span> <span class="n">w2_grad</span><span class="p">)</span>
<span class="p">}</span>
<span class="n">block3</span> <span class="p">{</span>
<span class="n">parent_block</span><span class="p">:</span> <span class="mi">0</span>
<span class="nb">vars</span><span class="p">:</span> <span class="n">lr</span>
<span class="n">ops</span><span class="p">:</span> <span class="n">sgd</span><span class="p">(</span><span class="n">w2</span><span class="p">,</span> <span class="n">w2_grad</span><span class="p">),</span>
<span class="n">sgd</span><span class="p">(</span><span class="n">w1</span><span class="p">,</span> <span class="n">w1_grad</span><span class="p">)</span>
<span class="p">}</span>
<span class="p">}</span>
</pre></div>
</div>
</div>
</div>
</div>
</div>
</div>
<footer>
<hr/>
<div role="contentinfo">
<p>
&copy; Copyright 2016, PaddlePaddle developers.
</p>
</div>
Built with <a href="http://sphinx-doc.org/">Sphinx</a> using a <a href="https://github.com/snide/sphinx_rtd_theme">theme</a> provided by <a href="https://readthedocs.org">Read the Docs</a>.
</footer>
</div>
</div>
</section>
</div>
<script type="text/javascript">
var DOCUMENTATION_OPTIONS = {
URL_ROOT:'../',
VERSION:'',
COLLAPSE_INDEX:false,
FILE_SUFFIX:'.html',
HAS_SOURCE: true,
SOURCELINK_SUFFIX: ".txt",
};
</script>
<script type="text/javascript" src="../_static/jquery.js"></script>
<script type="text/javascript" src="../_static/underscore.js"></script>
<script type="text/javascript" src="../_static/doctools.js"></script>
<script type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/mathjax/2.7.0/MathJax.js?config=TeX-AMS-MML_HTMLorMML"></script>
<script type="text/javascript" src="../_static/js/theme.js"></script>
<script src="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/js/bootstrap.min.js" integrity="sha384-Tc5IQib027qvyjSMfHjOMaLkfuWVxZxUPnCJA7l2mCWNIpG9mGCD8wGNIcPD7Txa" crossorigin="anonymous"></script>
<script src="https://cdn.jsdelivr.net/perfect-scrollbar/0.6.14/js/perfect-scrollbar.jquery.min.js"></script>
<script src="../_static/js/paddle_doc_init.js"></script>
</body>
</html>
\ No newline at end of file
因为 它太大了无法显示 source diff 。你可以改为 查看blob
# Design Doc: Parallel_Do in PaddlePaddle
In PaddlePaddle, we use parallel_do primitive to represent multithread data parallel processing.
## Design overview
The definition of a parallel_do op looks like the following
```c++
AddInput(kInputs, "Inputs needed to be split onto different devices").AsDuplicable();
AddInput(kParameters, "Parameters are duplicated over different devices")
.AsDuplicable();
AddInput(kPlaces, "Devices used for parallel processing");
AddOutput(kOutputs, "Outputs needed to be merged from different devices").AsDuplicable();
AddOutput(kParallelScopes,
"Scopes for all local variables in forward pass. One scope for each device");
AddAttr<framework::BlockDesc *>(kParallelBlock,
"List of operaters to be executed in parallel");
```
A vanilla implementation of parallel_do can be shown as the following (`|` means single thread and
`||||` means multiple threads)
```
In the forward pass
| Split input onto different devices
| Copy parameter to onto different devices
|||| Compute forward pass in parallel
| Merge output from different devices
In the backward pass
| Split output@grad onto different devices
|||| Compute backward pass in parallel
| accumulate param@grad from different devices to the first device
| Merge input@grad from different devices
 | Copy param@grad to the place of parallel_do_op
```
This implementation allows to write mixed device program like this
```python
# get embedding feature on CPU
feature = some_cpu_only_op(data)
gpu_places = get_place(use_gpu=True)
# parallel processing on multiple GPUs
pd = ParallelDo(gpu_places)
with pd.do():
read_input(feature)
prediction = my_net(feature)
write_output(prediction)
prediction = pd()
loss = cross_entropy(prediction, label)
```
And the programDesc are like the following
```
# start_program will be run by executor(CPUPlace), all w1, w2 will be allocated on CPU
start_program
{
vars: w1, w2
ops: init(w1), init(w2)
}
main_program
{
block0 {
vars: data, places, w1, w2
ops: data, get_place, parallel_do(block1),
parallel_do_grad(block2),
sgd(w2, w2_grad),
sgd(w1, w1_grad)
}
block1 {
parent_block: 0
vars: data, h1, h2, loss
ops: fc, fc, softmax
}
block2 {
parent_block: 1
vars: data_grad, h1_grad, h2_grad, loss_gard, w1_grad, w2_grad
ops: softmax_grad,
fc_grad
fc_grad
}
}
```
## Proformance Imporvement
There are serial places we can make this parallel_do faster.
### forward: split input onto different devices
If the input of the parallel_do is independent from any prior opeartors, we can avoid this step by
prefetching the input onto different devices in a seperate background thread. And the python code
looks like this.
```python
pd = ParallelDo(gpu_places)
with pd.do():
   feature = get_data_from_prefetch_queue(gpu_places)
prediction = my_net(feature)
write_output(activation)
```
### forward: Copy parameter to onto different devices
We can avoid this step by making each device have a copy of the parameter. This requires:
1. `fluid.default_start_up_program()` to be run on all devices
1. In the backward, allreduce param@grad at different devices, this requires
1. `backward.py` add `allreduce` operators at parallel_do_grad
1. `allreduce` operators need to be called in async mode to achieve maximum throughput
1. apply gradients related op(i.e. cliping, normalization, decay, sgd) on different devices in parallel
By doing so, we also avoided "backward: accumulate param@grad from different devices to the first device".
And the ProgramDesc looks like the following
```
# w1, w2 will be allocated on all GPUs
start_program
{
block0 {
parallel_do(block1)
}
block1 {
parent_block: 0
vars: w1, w2
ops: init(w1), init(w2)
}
}
main_program
{
block0 {
vars: data, places, w1, w2
ops: data, get_place, parallel_do(block1),
parallel_do_grad(block2), # append_backward
parallel_do(block3) # append_optimization
}
block1 {
parent_block: 0
vars: data, h1, h2, loss
ops: fc, fc, softmax
}
block2 {
parent_block: 1
vars: data_grad, h1_grad, h2_grad, loss_gard, w1_grad, w2_grad
ops: softmax_grad,
fc_grad, allreduce(places, scopes, w1_grad),
fc_grad, allreduce(places, scopes, w2_grad)
}
block3 {
parent_block: 0
vars: lr
ops: sgd(w2, w2_grad),
sgd(w1, w1_grad)
}
}
```
<!DOCTYPE html>
<!--[if IE 8]><html class="no-js lt-ie9" lang="en" > <![endif]-->
<!--[if gt IE 8]><!--> <html class="no-js" lang="en" > <!--<![endif]-->
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Design Doc: Parallel_Do in PaddlePaddle &mdash; PaddlePaddle 文档</title>
<link rel="stylesheet" href="../_static/css/theme.css" type="text/css" />
<link rel="index" title="索引"
href="../genindex.html"/>
<link rel="search" title="搜索" href="../search.html"/>
<link rel="top" title="PaddlePaddle 文档" href="../index.html"/>
<link rel="stylesheet" href="https://cdn.jsdelivr.net/perfect-scrollbar/0.6.14/css/perfect-scrollbar.min.css" type="text/css" />
<link rel="stylesheet" href="../_static/css/override.css" type="text/css" />
<script>
var _hmt = _hmt || [];
(function() {
var hm = document.createElement("script");
hm.src = "//hm.baidu.com/hm.js?b9a314ab40d04d805655aab1deee08ba";
var s = document.getElementsByTagName("script")[0];
s.parentNode.insertBefore(hm, s);
})();
</script>
<script src="../_static/js/modernizr.min.js"></script>
</head>
<body class="wy-body-for-nav" role="document">
<header class="site-header">
<div class="site-logo">
<a href="/"><img src="../_static/images/PP_w.png"></a>
</div>
<div class="site-nav-links">
<div class="site-menu">
<a class="fork-on-github" href="https://github.com/PaddlePaddle/Paddle" target="_blank"><i class="fa fa-github"></i>Fork me on Github</a>
<div class="language-switcher dropdown">
<a type="button" data-toggle="dropdown">
<span>English</span>
<i class="fa fa-angle-up"></i>
<i class="fa fa-angle-down"></i>
</a>
<ul class="dropdown-menu">
<li><a href="/doc_cn">中文</a></li>
<li><a href="/doc">English</a></li>
</ul>
</div>
<ul class="site-page-links">
<li><a href="/">Home</a></li>
</ul>
</div>
<div class="doc-module">
<ul>
<li class="toctree-l1"><a class="reference internal" href="../getstarted/index_cn.html">新手入门</a></li>
<li class="toctree-l1"><a class="reference internal" href="../build_and_install/index_cn.html">安装与编译</a></li>
<li class="toctree-l1"><a class="reference internal" href="../howto/index_cn.html">进阶使用</a></li>
<li class="toctree-l1"><a class="reference internal" href="../dev/index_cn.html">开发标准</a></li>
<li class="toctree-l1"><a class="reference internal" href="../faq/index_cn.html">FAQ</a></li>
</ul>
<div role="search">
<form id="rtd-search-form" class="wy-form" action="../search.html" method="get">
<input type="text" name="q" placeholder="Search docs" />
<input type="hidden" name="check_keywords" value="yes" />
<input type="hidden" name="area" value="default" />
</form>
</div>
</div>
</div>
</header>
<div class="main-content-wrap">
<nav class="doc-menu-vertical" role="navigation">
<ul>
<li class="toctree-l1"><a class="reference internal" href="../getstarted/index_cn.html">新手入门</a><ul>
<li class="toctree-l2"><a class="reference internal" href="../getstarted/quickstart_cn.html">快速开始</a></li>
<li class="toctree-l2"><a class="reference internal" href="../getstarted/concepts/use_concepts_cn.html">基本使用概念</a></li>
</ul>
</li>
<li class="toctree-l1"><a class="reference internal" href="../build_and_install/index_cn.html">安装与编译</a><ul>
<li class="toctree-l2"><a class="reference internal" href="../build_and_install/pip_install_cn.html">使用pip安装</a></li>
<li class="toctree-l2"><a class="reference internal" href="../build_and_install/docker_install_cn.html">使用Docker安装运行</a></li>
<li class="toctree-l2"><a class="reference internal" href="../build_and_install/build_from_source_cn.html">从源码编译</a></li>
</ul>
</li>
<li class="toctree-l1"><a class="reference internal" href="../howto/index_cn.html">进阶使用</a><ul>
<li class="toctree-l2"><a class="reference internal" href="../howto/cmd_parameter/index_cn.html">命令行参数设置</a><ul>
<li class="toctree-l3"><a class="reference internal" href="../howto/cmd_parameter/use_case_cn.html">使用案例</a></li>
<li class="toctree-l3"><a class="reference internal" href="../howto/cmd_parameter/arguments_cn.html">参数概述</a></li>
<li class="toctree-l3"><a class="reference internal" href="../howto/cmd_parameter/detail_introduction_cn.html">细节描述</a></li>
</ul>
</li>
<li class="toctree-l2"><a class="reference internal" href="../howto/cluster/index_cn.html">分布式训练</a><ul>
<li class="toctree-l3"><a class="reference internal" href="../howto/cluster/preparations_cn.html">环境准备</a></li>
<li class="toctree-l3"><a class="reference internal" href="../howto/cluster/cmd_argument_cn.html">启动参数说明</a></li>
<li class="toctree-l3"><a class="reference internal" href="../howto/cluster/multi_cluster/index_cn.html">在不同集群中运行</a><ul>
<li class="toctree-l4"><a class="reference internal" href="../howto/cluster/multi_cluster/fabric_cn.html">使用fabric启动集群训练</a></li>
<li class="toctree-l4"><a class="reference internal" href="../howto/cluster/multi_cluster/openmpi_cn.html">在OpenMPI集群中提交训练作业</a></li>
<li class="toctree-l4"><a class="reference internal" href="../howto/cluster/multi_cluster/k8s_cn.html">Kubernetes单机训练</a></li>
<li class="toctree-l4"><a class="reference internal" href="../howto/cluster/multi_cluster/k8s_distributed_cn.html">Kubernetes分布式训练</a></li>
<li class="toctree-l4"><a class="reference internal" href="../howto/cluster/multi_cluster/k8s_aws_cn.html">Distributed PaddlePaddle Training on AWS with Kubernetes</a></li>
</ul>
</li>
</ul>
</li>
<li class="toctree-l2"><a class="reference internal" href="../howto/capi/index_cn.html">C-API预测库</a><ul>
<li class="toctree-l3"><a class="reference internal" href="../howto/capi/compile_paddle_lib_cn.html">安装与编译C-API预测库</a></li>
<li class="toctree-l3"><a class="reference internal" href="../howto/capi/organization_of_the_inputs_cn.html">输入/输出数据组织</a></li>
<li class="toctree-l3"><a class="reference internal" href="../howto/capi/workflow_of_capi_cn.html">C-API使用流程</a></li>
</ul>
</li>
<li class="toctree-l2"><a class="reference internal" href="../howto/rnn/index_cn.html">RNN模型</a><ul>
<li class="toctree-l3"><a class="reference internal" href="../howto/rnn/rnn_config_cn.html">RNN配置</a></li>
<li class="toctree-l3"><a class="reference internal" href="../howto/rnn/recurrent_group_cn.html">Recurrent Group教程</a></li>
<li class="toctree-l3"><a class="reference internal" href="../howto/rnn/hierarchical_layer_cn.html">支持双层序列作为输入的Layer</a></li>
<li class="toctree-l3"><a class="reference internal" href="../howto/rnn/hrnn_rnn_api_compare_cn.html">单双层RNN API对比介绍</a></li>
</ul>
</li>
<li class="toctree-l2"><a class="reference internal" href="../howto/optimization/gpu_profiling_cn.html">GPU性能调优</a></li>
</ul>
</li>
<li class="toctree-l1"><a class="reference internal" href="../dev/index_cn.html">开发标准</a><ul>
<li class="toctree-l2"><a class="reference internal" href="../dev/contribute_to_paddle_cn.html">如何贡献代码</a></li>
<li class="toctree-l2"><a class="reference internal" href="../dev/write_docs_cn.html">如何贡献文档</a></li>
</ul>
</li>
<li class="toctree-l1"><a class="reference internal" href="../faq/index_cn.html">FAQ</a><ul>
<li class="toctree-l2"><a class="reference internal" href="../faq/build_and_install/index_cn.html">编译安装与单元测试</a></li>
<li class="toctree-l2"><a class="reference internal" href="../faq/model/index_cn.html">模型配置</a></li>
<li class="toctree-l2"><a class="reference internal" href="../faq/parameter/index_cn.html">参数设置</a></li>
<li class="toctree-l2"><a class="reference internal" href="../faq/local/index_cn.html">本地训练与预测</a></li>
<li class="toctree-l2"><a class="reference internal" href="../faq/cluster/index_cn.html">集群训练与预测</a></li>
</ul>
</li>
</ul>
</nav>
<section class="doc-content-wrap">
<div role="navigation" aria-label="breadcrumbs navigation">
<ul class="wy-breadcrumbs">
<li>Design Doc: Parallel_Do in PaddlePaddle</li>
</ul>
</div>
<div class="wy-nav-content" id="doc-content">
<div class="rst-content">
<div role="main" class="document" itemscope="itemscope" itemtype="http://schema.org/Article">
<div itemprop="articleBody">
<div class="section" id="design-doc-parallel-do-in-paddlepaddle">
<span id="design-doc-parallel-do-in-paddlepaddle"></span><h1>Design Doc: Parallel_Do in PaddlePaddle<a class="headerlink" href="#design-doc-parallel-do-in-paddlepaddle" title="永久链接至标题"></a></h1>
<p>In PaddlePaddle, we use parallel_do primitive to represent multithread data parallel processing.</p>
<div class="section" id="design-overview">
<span id="design-overview"></span><h2>Design overview<a class="headerlink" href="#design-overview" title="永久链接至标题"></a></h2>
<p>The definition of a parallel_do op looks like the following</p>
<div class="highlight-c++"><div class="highlight"><pre><span></span><span class="n">AddInput</span><span class="p">(</span><span class="n">kInputs</span><span class="p">,</span> <span class="s">&quot;Inputs needed to be split onto different devices&quot;</span><span class="p">).</span><span class="n">AsDuplicable</span><span class="p">();</span>
<span class="n">AddInput</span><span class="p">(</span><span class="n">kParameters</span><span class="p">,</span> <span class="s">&quot;Parameters are duplicated over different devices&quot;</span><span class="p">)</span>
<span class="p">.</span><span class="n">AsDuplicable</span><span class="p">();</span>
<span class="n">AddInput</span><span class="p">(</span><span class="n">kPlaces</span><span class="p">,</span> <span class="s">&quot;Devices used for parallel processing&quot;</span><span class="p">);</span>
<span class="n">AddOutput</span><span class="p">(</span><span class="n">kOutputs</span><span class="p">,</span> <span class="s">&quot;Outputs needed to be merged from different devices&quot;</span><span class="p">).</span><span class="n">AsDuplicable</span><span class="p">();</span>
<span class="n">AddOutput</span><span class="p">(</span><span class="n">kParallelScopes</span><span class="p">,</span>
<span class="s">&quot;Scopes for all local variables in forward pass. One scope for each device&quot;</span><span class="p">);</span>
<span class="n">AddAttr</span><span class="o">&lt;</span><span class="n">framework</span><span class="o">::</span><span class="n">BlockDesc</span> <span class="o">*&gt;</span><span class="p">(</span><span class="n">kParallelBlock</span><span class="p">,</span>
<span class="s">&quot;List of operaters to be executed in parallel&quot;</span><span class="p">);</span>
</pre></div>
</div>
<p>A vanilla implementation of parallel_do can be shown as the following (<code class="docutils literal"><span class="pre">|</span></code> means single thread and
<code class="docutils literal"><span class="pre">||||</span></code> means multiple threads)</p>
<div class="highlight-default"><div class="highlight"><pre><span></span><span class="n">In</span> <span class="n">the</span> <span class="n">forward</span> <span class="k">pass</span>
<span class="o">|</span> <span class="n">Split</span> <span class="nb">input</span> <span class="n">onto</span> <span class="n">different</span> <span class="n">devices</span>
<span class="o">|</span> <span class="n">Copy</span> <span class="n">parameter</span> <span class="n">to</span> <span class="n">onto</span> <span class="n">different</span> <span class="n">devices</span>
<span class="o">||||</span> <span class="n">Compute</span> <span class="n">forward</span> <span class="k">pass</span> <span class="ow">in</span> <span class="n">parallel</span>
<span class="o">|</span> <span class="n">Merge</span> <span class="n">output</span> <span class="kn">from</span> <span class="nn">different</span> <span class="n">devices</span>
<span class="n">In</span> <span class="n">the</span> <span class="n">backward</span> <span class="k">pass</span>
<span class="o">|</span> <span class="n">Split</span> <span class="n">output</span><span class="nd">@grad</span> <span class="n">onto</span> <span class="n">different</span> <span class="n">devices</span>
<span class="o">||||</span> <span class="n">Compute</span> <span class="n">backward</span> <span class="k">pass</span> <span class="ow">in</span> <span class="n">parallel</span>
<span class="o">|</span> <span class="n">accumulate</span> <span class="n">param</span><span class="nd">@grad</span> <span class="kn">from</span> <span class="nn">different</span> <span class="n">devices</span> <span class="n">to</span> <span class="n">the</span> <span class="n">first</span> <span class="n">device</span>
<span class="o">|</span> <span class="n">Merge</span> <span class="nb">input</span><span class="nd">@grad</span> <span class="kn">from</span> <span class="nn">different</span> <span class="n">devices</span>
 <span class="o">|</span> <span class="n">Copy</span> <span class="n">param</span><span class="nd">@grad</span> <span class="n">to</span> <span class="n">the</span> <span class="n">place</span> <span class="n">of</span> <span class="n">parallel_do_op</span>
</pre></div>
</div>
<p>This implementation allows to write mixed device program like this</p>
<div class="highlight-python"><div class="highlight"><pre><span></span><span class="c1"># get embedding feature on CPU</span>
<span class="n">feature</span> <span class="o">=</span> <span class="n">some_cpu_only_op</span><span class="p">(</span><span class="n">data</span><span class="p">)</span>
<span class="n">gpu_places</span> <span class="o">=</span> <span class="n">get_place</span><span class="p">(</span><span class="n">use_gpu</span><span class="o">=</span><span class="bp">True</span><span class="p">)</span>
<span class="c1"># parallel processing on multiple GPUs</span>
<span class="n">pd</span> <span class="o">=</span> <span class="n">ParallelDo</span><span class="p">(</span><span class="n">gpu_places</span><span class="p">)</span>
<span class="k">with</span> <span class="n">pd</span><span class="o">.</span><span class="n">do</span><span class="p">():</span>
<span class="n">read_input</span><span class="p">(</span><span class="n">feature</span><span class="p">)</span>
<span class="n">prediction</span> <span class="o">=</span> <span class="n">my_net</span><span class="p">(</span><span class="n">feature</span><span class="p">)</span>
<span class="n">write_output</span><span class="p">(</span><span class="n">prediction</span><span class="p">)</span>
<span class="n">prediction</span> <span class="o">=</span> <span class="n">pd</span><span class="p">()</span>
<span class="n">loss</span> <span class="o">=</span> <span class="n">cross_entropy</span><span class="p">(</span><span class="n">prediction</span><span class="p">,</span> <span class="n">label</span><span class="p">)</span>
</pre></div>
</div>
<p>And the programDesc are like the following</p>
<div class="highlight-default"><div class="highlight"><pre><span></span><span class="c1"># start_program will be run by executor(CPUPlace), all w1, w2 will be allocated on CPU</span>
<span class="n">start_program</span>
<span class="p">{</span>
<span class="nb">vars</span><span class="p">:</span> <span class="n">w1</span><span class="p">,</span> <span class="n">w2</span>
<span class="n">ops</span><span class="p">:</span> <span class="n">init</span><span class="p">(</span><span class="n">w1</span><span class="p">),</span> <span class="n">init</span><span class="p">(</span><span class="n">w2</span><span class="p">)</span>
<span class="p">}</span>
<span class="n">main_program</span>
<span class="p">{</span>
<span class="n">block0</span> <span class="p">{</span>
<span class="nb">vars</span><span class="p">:</span> <span class="n">data</span><span class="p">,</span> <span class="n">places</span><span class="p">,</span> <span class="n">w1</span><span class="p">,</span> <span class="n">w2</span>
<span class="n">ops</span><span class="p">:</span> <span class="n">data</span><span class="p">,</span> <span class="n">get_place</span><span class="p">,</span> <span class="n">parallel_do</span><span class="p">(</span><span class="n">block1</span><span class="p">),</span>
<span class="n">parallel_do_grad</span><span class="p">(</span><span class="n">block2</span><span class="p">),</span>
<span class="n">sgd</span><span class="p">(</span><span class="n">w2</span><span class="p">,</span> <span class="n">w2_grad</span><span class="p">),</span>
<span class="n">sgd</span><span class="p">(</span><span class="n">w1</span><span class="p">,</span> <span class="n">w1_grad</span><span class="p">)</span>
<span class="p">}</span>
<span class="n">block1</span> <span class="p">{</span>
<span class="n">parent_block</span><span class="p">:</span> <span class="mi">0</span>
<span class="nb">vars</span><span class="p">:</span> <span class="n">data</span><span class="p">,</span> <span class="n">h1</span><span class="p">,</span> <span class="n">h2</span><span class="p">,</span> <span class="n">loss</span>
<span class="n">ops</span><span class="p">:</span> <span class="n">fc</span><span class="p">,</span> <span class="n">fc</span><span class="p">,</span> <span class="n">softmax</span>
<span class="p">}</span>
<span class="n">block2</span> <span class="p">{</span>
<span class="n">parent_block</span><span class="p">:</span> <span class="mi">1</span>
<span class="nb">vars</span><span class="p">:</span> <span class="n">data_grad</span><span class="p">,</span> <span class="n">h1_grad</span><span class="p">,</span> <span class="n">h2_grad</span><span class="p">,</span> <span class="n">loss_gard</span><span class="p">,</span> <span class="n">w1_grad</span><span class="p">,</span> <span class="n">w2_grad</span>
<span class="n">ops</span><span class="p">:</span> <span class="n">softmax_grad</span><span class="p">,</span>
<span class="n">fc_grad</span>
<span class="n">fc_grad</span>
<span class="p">}</span>
<span class="p">}</span>
</pre></div>
</div>
</div>
<div class="section" id="proformance-imporvement">
<span id="proformance-imporvement"></span><h2>Proformance Imporvement<a class="headerlink" href="#proformance-imporvement" title="永久链接至标题"></a></h2>
<p>There are serial places we can make this parallel_do faster.</p>
<div class="section" id="forward-split-input-onto-different-devices">
<span id="forward-split-input-onto-different-devices"></span><h3>forward: split input onto different devices<a class="headerlink" href="#forward-split-input-onto-different-devices" title="永久链接至标题"></a></h3>
<p>If the input of the parallel_do is independent from any prior opeartors, we can avoid this step by
prefetching the input onto different devices in a seperate background thread. And the python code
looks like this.</p>
<div class="highlight-python"><div class="highlight"><pre><span></span>pd = ParallelDo(gpu_places)
with pd.do():
   feature = get_data_from_prefetch_queue(gpu_places)
prediction = my_net(feature)
write_output(activation)
</pre></div>
</div>
</div>
<div class="section" id="forward-copy-parameter-to-onto-different-devices">
<span id="forward-copy-parameter-to-onto-different-devices"></span><h3>forward: Copy parameter to onto different devices<a class="headerlink" href="#forward-copy-parameter-to-onto-different-devices" title="永久链接至标题"></a></h3>
<p>We can avoid this step by making each device have a copy of the parameter. This requires:</p>
<ol class="simple">
<li><code class="docutils literal"><span class="pre">fluid.default_start_up_program()</span></code> to be run on all devices</li>
<li>In the backward, allreduce param&#64;grad at different devices, this requires<ol>
<li><code class="docutils literal"><span class="pre">backward.py</span></code> add <code class="docutils literal"><span class="pre">allreduce</span></code> operators at parallel_do_grad</li>
<li><code class="docutils literal"><span class="pre">allreduce</span></code> operators need to be called in async mode to achieve maximum throughput</li>
</ol>
</li>
<li>apply gradients related op(i.e. cliping, normalization, decay, sgd) on different devices in parallel</li>
</ol>
<p>By doing so, we also avoided &#8220;backward: accumulate param&#64;grad from different devices to the first device&#8221;.
And the ProgramDesc looks like the following</p>
<div class="highlight-default"><div class="highlight"><pre><span></span><span class="c1"># w1, w2 will be allocated on all GPUs</span>
<span class="n">start_program</span>
<span class="p">{</span>
<span class="n">block0</span> <span class="p">{</span>
<span class="n">parallel_do</span><span class="p">(</span><span class="n">block1</span><span class="p">)</span>
<span class="p">}</span>
<span class="n">block1</span> <span class="p">{</span>
<span class="n">parent_block</span><span class="p">:</span> <span class="mi">0</span>
<span class="nb">vars</span><span class="p">:</span> <span class="n">w1</span><span class="p">,</span> <span class="n">w2</span>
<span class="n">ops</span><span class="p">:</span> <span class="n">init</span><span class="p">(</span><span class="n">w1</span><span class="p">),</span> <span class="n">init</span><span class="p">(</span><span class="n">w2</span><span class="p">)</span>
<span class="p">}</span>
<span class="p">}</span>
<span class="n">main_program</span>
<span class="p">{</span>
<span class="n">block0</span> <span class="p">{</span>
<span class="nb">vars</span><span class="p">:</span> <span class="n">data</span><span class="p">,</span> <span class="n">places</span><span class="p">,</span> <span class="n">w1</span><span class="p">,</span> <span class="n">w2</span>
<span class="n">ops</span><span class="p">:</span> <span class="n">data</span><span class="p">,</span> <span class="n">get_place</span><span class="p">,</span> <span class="n">parallel_do</span><span class="p">(</span><span class="n">block1</span><span class="p">),</span>
<span class="n">parallel_do_grad</span><span class="p">(</span><span class="n">block2</span><span class="p">),</span> <span class="c1"># append_backward</span>
<span class="n">parallel_do</span><span class="p">(</span><span class="n">block3</span><span class="p">)</span> <span class="c1"># append_optimization</span>
<span class="p">}</span>
<span class="n">block1</span> <span class="p">{</span>
<span class="n">parent_block</span><span class="p">:</span> <span class="mi">0</span>
<span class="nb">vars</span><span class="p">:</span> <span class="n">data</span><span class="p">,</span> <span class="n">h1</span><span class="p">,</span> <span class="n">h2</span><span class="p">,</span> <span class="n">loss</span>
<span class="n">ops</span><span class="p">:</span> <span class="n">fc</span><span class="p">,</span> <span class="n">fc</span><span class="p">,</span> <span class="n">softmax</span>
<span class="p">}</span>
<span class="n">block2</span> <span class="p">{</span>
<span class="n">parent_block</span><span class="p">:</span> <span class="mi">1</span>
<span class="nb">vars</span><span class="p">:</span> <span class="n">data_grad</span><span class="p">,</span> <span class="n">h1_grad</span><span class="p">,</span> <span class="n">h2_grad</span><span class="p">,</span> <span class="n">loss_gard</span><span class="p">,</span> <span class="n">w1_grad</span><span class="p">,</span> <span class="n">w2_grad</span>
<span class="n">ops</span><span class="p">:</span> <span class="n">softmax_grad</span><span class="p">,</span>
<span class="n">fc_grad</span><span class="p">,</span> <span class="n">allreduce</span><span class="p">(</span><span class="n">places</span><span class="p">,</span> <span class="n">scopes</span><span class="p">,</span> <span class="n">w1_grad</span><span class="p">),</span>
<span class="n">fc_grad</span><span class="p">,</span> <span class="n">allreduce</span><span class="p">(</span><span class="n">places</span><span class="p">,</span> <span class="n">scopes</span><span class="p">,</span> <span class="n">w2_grad</span><span class="p">)</span>
<span class="p">}</span>
<span class="n">block3</span> <span class="p">{</span>
<span class="n">parent_block</span><span class="p">:</span> <span class="mi">0</span>
<span class="nb">vars</span><span class="p">:</span> <span class="n">lr</span>
<span class="n">ops</span><span class="p">:</span> <span class="n">sgd</span><span class="p">(</span><span class="n">w2</span><span class="p">,</span> <span class="n">w2_grad</span><span class="p">),</span>
<span class="n">sgd</span><span class="p">(</span><span class="n">w1</span><span class="p">,</span> <span class="n">w1_grad</span><span class="p">)</span>
<span class="p">}</span>
<span class="p">}</span>
</pre></div>
</div>
</div>
</div>
</div>
</div>
</div>
<footer>
<hr/>
<div role="contentinfo">
<p>
&copy; Copyright 2016, PaddlePaddle developers.
</p>
</div>
Built with <a href="http://sphinx-doc.org/">Sphinx</a> using a <a href="https://github.com/snide/sphinx_rtd_theme">theme</a> provided by <a href="https://readthedocs.org">Read the Docs</a>.
</footer>
</div>
</div>
</section>
</div>
<script type="text/javascript">
var DOCUMENTATION_OPTIONS = {
URL_ROOT:'../',
VERSION:'',
COLLAPSE_INDEX:false,
FILE_SUFFIX:'.html',
HAS_SOURCE: true,
SOURCELINK_SUFFIX: ".txt",
};
</script>
<script type="text/javascript" src="../_static/jquery.js"></script>
<script type="text/javascript" src="../_static/underscore.js"></script>
<script type="text/javascript" src="../_static/doctools.js"></script>
<script type="text/javascript" src="../_static/translations.js"></script>
<script type="text/javascript" src="https://cdn.bootcss.com/mathjax/2.7.0/MathJax.js"></script>
<script type="text/javascript" src="../_static/js/theme.js"></script>
<script src="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/js/bootstrap.min.js" integrity="sha384-Tc5IQib027qvyjSMfHjOMaLkfuWVxZxUPnCJA7l2mCWNIpG9mGCD8wGNIcPD7Txa" crossorigin="anonymous"></script>
<script src="https://cdn.jsdelivr.net/perfect-scrollbar/0.6.14/js/perfect-scrollbar.jquery.min.js"></script>
<script src="../_static/js/paddle_doc_init.js"></script>
</body>
</html>
\ No newline at end of file
因为 它太大了无法显示 source diff 。你可以改为 查看blob
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册