提交 93198f9c 编写于 作者: T Travis CI

Deploy to GitHub Pages: c13805e9

上级 b03aadf1
# Intel® MKL Packed on PaddlePaddle: Design Doc
## Contents
- [Overview](#overview)
- [Key Points](#key-points)
- [Background](#background)
- [Solution](#solution)
- [Actions](#actions)
- [CMake](#cmake)
- [Layers](#layers)
- [Unit Tests](#unit-tests)
- [Python API](#python-api)
- [Benchmarking](#benchmarking)
## Overview
我们计划将 Intel® MKL 中引入的 GEMM Packed APIs\[[1](#references)\] 集成到 PaddlePaddle 中,充分发挥英特尔平台的优势,有效提升PaddlePaddle在英特尔架构上的性能。
现阶段的优化主要针对 Recurrent Neural Network(以下简称RNN)相关层(包括`RecurrentLayer`, `GatedRecurrentLayer`和`LstmLayer`), 以及 PaddlePaddle V1 API。
## Key Points
### Background
目前PaddlePaddle采用了 Intel® MKL库的[cblas_?gemm](https://software.intel.com/en-us/mkl-developer-reference-c-cblas-gemm)函数,这个函数本身会在计算前将原数据转换为更适合英特尔平台的内部格式。
1. 转换耗时 \
这一数据格式的转换操作(Packing),在问题本身的计算量比较小的时候,显得相对来说较为耗时。例如在DeepSpeech2 \[[2](#references)\] 的Vanilla RNN部分中,矩阵大小是`batch_size * 2048`。
2. 转换冗余 \
由于在现有的某些情况下(例如RNN),多次调用 cblas_?gemm 会使用相同的原数据,因此,每次调用时对原数据的重复Packing便成为了冗余。
为了最大程度减少多次调用 cblas_?gemm 在Packing上的耗时,Intel® MKL 引入了以下四个API:
* cblas_?gemm_alloc
* cblas_?gemm_pack
* cblas_?gemm_compute
* cblas_?gemm_free
通过使用这些API,我们可以先完成对原数据的Packing操作,再把已转换为Packed格式的数据传递给那些复用同一数据的gemm_compute函数,从而避免了Packing冗余。
### Solution
在RNN的情况下,同一次前向、后向(forward/backward)过程中所有时间步(time step)共享同一个权重(weight)。当只做推断(inference)时,各次前向之间也都使用了相同的权重,没有必要在每次前向中每个时间步的计算时对权重进行重复的Packing操作。
我们通过使用新引入的GEMM Packed APIs,在层初始化的时候,先完成对权重的Packing操作,然后在前向,后向时复用已经转换过的权重,并在每次权重更新后,对新的权重进行转换用于下次迭代。
* 优化前,对于序列长度(sequence length)为`T`的网络模型(model), `N`次迭代执行的转换次数为:
- `inference`: `N * T`
- `training`: `2 * N * T`
* 优化后,对于同样设置的网络模型,其转换次数减少至:
- `inference`: `1`
- `training`: `2 * N`
## Actions
添加的相关文件和目录结构如下:
```txt
PaddlePaddle/Paddle
├── ...
└── paddle/
├── ...
└── gserver/
├── ...
├── layers/
│ ├── ...
│ ├── MKLPackedRecurrentLayer.*
| ├── MKLPackedGatedRecurrentLayer.*
| ├── MKLPackedLstmLayer.*
| └── MKLPackedGemm.h
└── tests/
├── ...
└── test_MKLPacked.cpp
```
### CMake
在对应的`CMakeLists.txt`中根据`WITH_MKL`是否打开,来决定是否开启MKL Packed相关功能。
### Layers
所有的`MKLPacked*Layer`都继承于PaddlePaddle的基类`Layer`, 并添加头文件 `MKLPackedGemm.h`,该文件对相关GEMM Packed APIs做了封装。
### Unit Tests
我们会添加`test_MKLPacked.cpp`用于MKL Packed优化后layer的测试。
对于每一个新加的RNN layer,我们会对比如下2个方面:
1. 对比优化后layer自身,sequence mode(`rnn_use_batch=false`)与batch mode(`rnn_use_batch=true`)的结果。
2. 对比优化后layer与相对应的PaddlePaddle原有layer, 在batch mode下的结果。
### Python API
TBD
### Benchmarking
会添加相应的脚本用于测试和对比在使用MKL Packed recurrent layers 前后的网络性能。
## References
1. [Introducing the new Packed APIs for GEMM](https://software.intel.com/en-us/articles/introducing-the-new-packed-apis-for-gemm)
2. [DeepSpeech2 on PaddlePaddle](https://github.com/PaddlePaddle/DeepSpeech#deepspeech2-on-paddlepaddle)
# Intel® MKL-DNN on PaddlePaddle: Design Doc
我们计划将英特尔深度神经网络数学库[Intel MKL-DNN](https://github.com/01org/mkl-dnn)
(Intel Math Kernel Library for Deep Neural Networks)集成到PaddlePaddle,
充分展现英特尔平台的优势,有效提升PaddlePaddle在英特尔架构上的性能。
<div align="center">
<img src="image/overview.png"><br/>
Figure 1. PaddlePaddle on IA
</div>
近期目标
- 完成常用Layer的MKL-DNN实现。
- 完成常见深度神经网络VGG,GoogLeNet 和 ResNet的MKL-DNN实现。
目前的优化,主要针对PaddlePaddle在重构之前的代码框架以及V1的API。
具体的完成状态可以参见[这里](https://github.com/PaddlePaddle/Paddle/projects/21)。
## Contents
- [Overview](#overview)
- [Actions](#actions)
- [CMake](#cmake)
- [Matrix](#matrix)
- [Layers](#layers)
- [Activations](#activations)
- [Parameters](#parameters)
- [Gradients](#gradients)
- [Unit Tests](#unit-tests)
- [Python API](#python-api)
- [Benchmarking](#benchmarking)
- [Others](#others)
- [Design Concerns](#design-concerns)
## Overview
我们会把MKL-DNN会作为第三方库集成进PaddlePaddle,与其他第三方库一样,会在编译PaddlePaddle的时候下载并编译MKL-DNN。
同时,为了进一步提升PaddlePaddle在基本数学运算的计算速度,我们也将MKLML即(MKL small library\[[1](#references)\])
作为另一个第三方库集成进PaddlePaddle,它只会包括生成好的动态库和头文件。
MKL,MKLML以及MKL-DNN三者关系如下表:
| Name | Open Source | License | Descriptions |
| :---------- | :--------------- | :---------- | :------------ |
| MKL | No | Proprietary | Accelerate math processing routines |
| MKLML | No | Proprietary | Small package of MKL, especially for Machine Learning |
| MKL-DNN | Yes | Apache 2.0 | Accelerate primitives processing routines especially for Deep Neural Networks |
MKLML可以与MKL-DNN共同使用,以此达到最好的性能。
<div align="center">
<img src="image/engine.png"><br/>
Figure 2. PaddlePaddle with MKL Engines
</div>
## Actions
添加的相关文件和目录结构如下:
```txt
PaddlePaddle/Paddle
├── ...
├── cmake/
│ ├── external/
│ │ ├── ...
│ │ ├── mkldnn.cmake
│ │ └── mklml.cmake
└── paddle/
├── ...
├── math/
│ ├── ...
│ └── MKLDNNMatrix.*
└── gserver/
├── ...
├── layers/
│ ├── ...
│ └── MKLDNN*Layer.*
├── activations/
│ ├── ...
│ └── MKLDNNActivations.*
└── tests/
├── ...
├── MKLDNNTester.*
└── test_MKLDNN.cpp
```
### CMake
在`CMakeLists.txt`中提供一个与MKL有关的总开关:`WITH_MKL`,它负责决定编译时是否使用MKLML和MKL-DNN
- `WITH_MKLML` 控制是否使用MKLML库。
当打开`WITH_MKL`时,会自动使用MKLML库作为PaddlePaddle的CBLAS和LAPACK库,同时会开启Intel OpenMP用于提高MKLML的性能。
编译时会把对应的头文件和库放在`build/third_party/install/mklml/*`目录下对应的地方。
MKLML的库目前都是动态库,主要包括`libiomp5.so`和`libmklml_intel.so`。
- `WITH_MKLDNN` 控制是否使用MKL-DNN。
当开启`WITH_MKL`时,会自动根据硬件配置[[2](#references)]选择是否编译MKL-DNN。
编译时会把对应的头文件和库放在`build/third_party/install/mkldnn/*`目录下对应的地方。
MKL-DNN的库目前只有动态库`libmkldnn.so`。
### Matrix
目前在PaddlePaddle中数据都是以`NCHW`的格式存储,但是在MKL-DNN中的排列方式不止这一种。
所以我们定义了一个`MKLDNNMatrix`用于管理MKL-DNN数据的不同格式以及相互之间的转换。
<div align="center">
<img src="image/matrix.png"><br/>
Figure 3. MKLDNNMatrix
</div>
### Layers
所有MKL-DNN的Layers都会继承于`MKLDNNLayer`,该类继承于PaddlePaddle的基类`Layer`。
在`MKLDNNLayer`中会提供一些必要的接口和函数,并且会写好`forward`和`backward`的基本逻辑,
子类只需要使用定义好的接口,实现具体的函数功能即可。
<div align="center">
<img src="image/layers.png"><br/>
Figure 4. MKLDNNLayer
</div>
每个MKLDNNLayer都包含用于内部存储和外部存储的一系列MKLDNNMatrix:
- 内部存储(internel memory):`inVal_`,`inGrad_`,`outVal_`和`outGrad_`,分别代表输入数据,输入梯度,输出数据和输出梯度。
- 外部存储(external memory):都是以ext开头,比如`extInVal_`和`extInGrad_`,它们主要是用于,
当数据格式与PaddlePaddle默认的`NCHW`格式不匹配时,转换内存的工作。
需要注意的是,PaddlePaddle的activation会直接使用`output_.value`和`output_.grad`,
所以`extOutVal_`和`extOutGrad_`必须分别与`output_.value`和`output_.grad`共享内存,
如果不需要外部存储用于转换,那么对应的内部存储也会与它们共享内存。
- 转换函数(resetXXX): 包括`resetInValue`,`resetInGrad`,`resetOutValue`和`resetOutGrad`,
表示对输入数据,输入梯度,输出数据和输出梯度的转换。
这些函数会根据输入参数重新设置内部和外部存储,当然这两者也可以相等,即表示不需要转换。
注意:每个`MKLDNNlayer`的子类只需要使用内部存储就可以了,所有外部的转换工作都会在reset系列函数中都准备好。
### Activations
在重构前的PaddlePaddle中,激活函数是独立于`Layer`的概念,并且输入输出都是共用一块内存,
所以添加了对应的`MKLDNNActivation`来实现,方式类似于`MKLDNNLayer`。
### Parameters
对于有参数的层,我们会保证`MKLDNNLayer`使用的参数与PaddlePaddle申请的buffer共用一块内存。
如果存在数据排列格式不一样的情况时,我们会在网络训练之前把格式转换为MKL-DNN希望的格式,
在训练结束的时候再保存为PaddlePaddle的格式,但是整个训练过程中不需要任何转换。
这样既使得最终保存的参数格式与PaddlePaddle一致,又可以避免不必要的转换。
### Gradients
由于MKL-DNN的操作都是直接覆盖的形式,也就是说输出的结果不会在原来的数据上累加,
这样带来的好处就是不需要一直清空memory,节省了不必要的操作。
但是注意的是,当网络出现分支且在`backward`的时候,需要累加不同Layer传过来的梯度。
所以在`MKLDNNlayer`中实现了一个merge的方法,此时每个小分支的`Input Gradient`
会先临时保存在`MKLDNNMatrix`中,由分支处的Layer负责求和,并把结果放到当前层的`output_.grad`中。
所以整体上,在实现每个子类的时候就不需要关心分支的事情了。
<div align="center">
<img src="image/gradients.png"><br/>
Figure 5. Merge Gradients
</div>
### Unit Tests
我们会添加`test_MKLDNN.cpp`和`MKLDNNTester.*`用于MKL-DNN的测试。
测试分为每个Layer(或Activation)的单元测试和简单网络的整体测试。
每个测试会对比PaddlePaddle中CPU算出的结果与MKL-DNN的结果,小于某个比较小的阈值认为通过。
### Python API
目前只考虑**v1 API**。
计划在`python/paddle/trainer/config_parser.py`里面添加`use_mkldnn`这个选择,方便用户选择使用MKL-DNN的layers。
具体实现方式比如:
```python
use_mkldnn = bool(int(g_command_config_args.get("use_mkldnn", 0)))
if use_mkldnn
self.layer_type = mkldnn_*
```
所有MKL-DNN的`layer_type`会以*mkldnn_*开头,这些会在`MKLDNN*Layer`注册layer的时候保证,以示区分。
同时,会在`paddle/utils.Flags`中添加一个`use_mkldnn`的flag,用于选择是否使用MKL-DNN的相关功能。
### Benchmarking
会添加相应的脚本在[这里](https://github.com/PaddlePaddle/Paddle/tree/develop/benchmark/paddle/image),用于测试和对比在使用MKL-DNN前后的CNN网络性能。
测试的性能对比结果会在[IntelOptimizedPaddle.md](https://github.com/PaddlePaddle/Paddle/blob/develop/benchmark/IntelOptimizedPaddle.md)
### Others
1. 如果在使用MKL-DNN的情况下,会把CPU的Buffer对齐为4096,具体可以参考MKL-DNN中的[memory](https://github.com/01org/mkl-dnn/blob/master/include/mkldnn.hpp#L673)。
2. 深入PaddlePaddle,寻找有没有其他可以优化的可能,进一步优化。比如可能会用OpenMP改进SGD的更新性能。
## Design Concerns
为了更好的符合PaddlePaddle的代码风格\[[3](#references)\],同时又尽可能少的牺牲MKL-DNN的性能\[[4](#references)\]。
我们总结出一些特别需要注意的点:
1. 使用**deviceId_**。为了尽可能少的在父类Layer中添加变量或者函数,
我们决定使用已有的`deviceId_`变量来区分layer的属性,定义`-2`为`MKLDNNLayer`特有的设备ID。
2. 重写父类Layer的**init**函数,修改`deviceId_`为`-2`,代表这个layer是用于跑在MKL-DNN的环境下。
3. 创建`MKLDNNBase`,定义一些除了layer和memory相关的类和函数。
包括MKL-DNN会用到`MKLDNNStream`和`CPUEngine`,和未来可能还会用到`FPGAEngine`等。
4. 如果MKL-DNN layer的后面接有cpu device,那么就会使`output_.value`与`extOutVal_`共享内存,
同时数据格式就是`NCHW`,这样下一个cpu device就能拿到正确的数据。
在有普通的CPU layer时, `extOutVal_`和`extOutGrad_`的格式始终是`NCHW`或者`NC`。
## References
1. [MKL small library](https://github.com/01org/mkl-dnn#linking-your-application)是[Intel MKL](https://software.intel.com/en-us/mkl)的一个子集。
主要包括了深度学习相关的数学原语与操作,一般由MKL-DNN在发布[新版本](https://github.com/01org/mkl-dnn/releases)时一起更新。
2. [MKL-DNN System Requirements](https://github.com/01org/mkl-dnn#system-requirements)。
目前在PaddlePaddle中,仅会在支持AVX2指令集及以上的机器才使用MKL-DNN。
3. [原来的方案](https://github.com/PaddlePaddle/Paddle/pull/3096)会引入**nextLayer**的信息。
但是在PaddlePaddle中,无论是重构前的layer还是重构后的op,都不会想要知道next layer/op的信息。
4. MKL-DNN的高性能格式与PaddlePaddle原有的`NCHW`不同(PaddlePaddle中的cuDNN部分使用的也是`NCHW`,所以不存在这个问题)。
所以需要引入一个转换方法,并且只需要在必要的时候转换这种格式,才能更好的发挥MKL-DNN的性能。
<!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>Intel® MKL Packed on PaddlePaddle: Design Doc &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="../../howto/index_en.html">HOW TO</a></li>
<li class="toctree-l1"><a class="reference internal" href="../../api/index_en.html">API</a></li>
<li class="toctree-l1"><a class="reference internal" href="../../mobile/index_en.html">MOBILE</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/build_and_install/index_en.html">Install and Build</a><ul>
<li class="toctree-l3"><a class="reference internal" href="../../getstarted/build_and_install/pip_install_en.html">Install Using pip</a></li>
<li class="toctree-l3"><a class="reference internal" href="../../getstarted/build_and_install/docker_install_en.html">Run in Docker Containers</a></li>
<li class="toctree-l3"><a class="reference internal" href="../../howto/dev/build_en.html">Build using Docker</a></li>
<li class="toctree-l3"><a class="reference internal" href="../../getstarted/build_and_install/build_from_source_en.html">Build from Sources</a></li>
</ul>
</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/usage/cmd_parameter/index_en.html">Set Command-line Parameters</a><ul>
<li class="toctree-l3"><a class="reference internal" href="../../howto/usage/cmd_parameter/use_case_en.html">Use Case</a></li>
<li class="toctree-l3"><a class="reference internal" href="../../howto/usage/cmd_parameter/arguments_en.html">Argument Outline</a></li>
<li class="toctree-l3"><a class="reference internal" href="../../howto/usage/cmd_parameter/detail_introduction_en.html">Detail Description</a></li>
</ul>
</li>
<li class="toctree-l2"><a class="reference internal" href="../../howto/usage/cluster/cluster_train_en.html">PaddlePaddle Distributed Training</a></li>
<li class="toctree-l2"><a class="reference internal" href="../../howto/usage/k8s/k8s_en.html">Paddle On Kubernetes</a></li>
<li class="toctree-l2"><a class="reference internal" href="../../howto/usage/k8s/k8s_aws_en.html">Distributed PaddlePaddle Training on AWS with Kubernetes</a></li>
<li class="toctree-l2"><a class="reference internal" href="../../howto/dev/new_layer_en.html">Write New Layers</a></li>
<li class="toctree-l2"><a class="reference internal" href="../../howto/dev/contribute_to_paddle_en.html">Contribute Code</a></li>
<li class="toctree-l2"><a class="reference internal" href="../../howto/dev/write_docs_en.html">Contribute Documentation</a></li>
<li class="toctree-l2"><a class="reference internal" href="../../howto/deep_model/rnn/index_en.html">RNN Models</a><ul>
<li class="toctree-l3"><a class="reference internal" href="../../howto/deep_model/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="../../api/index_en.html">API</a><ul>
<li class="toctree-l2"><a class="reference internal" href="../../api/v2/model_configs.html">Model Configuration</a><ul>
<li class="toctree-l3"><a class="reference internal" href="../../api/v2/config/activation.html">Activation</a></li>
<li class="toctree-l3"><a class="reference internal" href="../../api/v2/config/layer.html">Layers</a></li>
<li class="toctree-l3"><a class="reference internal" href="../../api/v2/config/evaluators.html">Evaluators</a></li>
<li class="toctree-l3"><a class="reference internal" href="../../api/v2/config/optimizer.html">Optimizer</a></li>
<li class="toctree-l3"><a class="reference internal" href="../../api/v2/config/pooling.html">Pooling</a></li>
<li class="toctree-l3"><a class="reference internal" href="../../api/v2/config/networks.html">Networks</a></li>
<li class="toctree-l3"><a class="reference internal" href="../../api/v2/config/attr.html">Parameter Attribute</a></li>
</ul>
</li>
<li class="toctree-l2"><a class="reference internal" href="../../api/v2/data.html">Data Reader Interface and DataSets</a><ul>
<li class="toctree-l3"><a class="reference internal" href="../../api/v2/data/data_reader.html">Data Reader Interface</a></li>
<li class="toctree-l3"><a class="reference internal" href="../../api/v2/data/image.html">Image Interface</a></li>
<li class="toctree-l3"><a class="reference internal" href="../../api/v2/data/dataset.html">Dataset</a></li>
</ul>
</li>
<li class="toctree-l2"><a class="reference internal" href="../../api/v2/run_logic.html">Training and Inference</a></li>
<li class="toctree-l2"><a class="reference internal" href="../../api/v2/fluid.html">Fluid</a><ul>
<li class="toctree-l3"><a class="reference internal" href="../../api/v2/fluid/layers.html">Layers</a></li>
<li class="toctree-l3"><a class="reference internal" href="../../api/v2/fluid/data_feeder.html">DataFeeder</a></li>
<li class="toctree-l3"><a class="reference internal" href="../../api/v2/fluid/executor.html">Executor</a></li>
<li class="toctree-l3"><a class="reference internal" href="../../api/v2/fluid/initializer.html">Initializer</a></li>
<li class="toctree-l3"><a class="reference internal" href="../../api/v2/fluid/evaluator.html">Evaluator</a></li>
<li class="toctree-l3"><a class="reference internal" href="../../api/v2/fluid/nets.html">Nets</a></li>
<li class="toctree-l3"><a class="reference internal" href="../../api/v2/fluid/optimizer.html">Optimizer</a></li>
<li class="toctree-l3"><a class="reference internal" href="../../api/v2/fluid/param_attr.html">ParamAttr</a></li>
<li class="toctree-l3"><a class="reference internal" href="../../api/v2/fluid/profiler.html">Profiler</a></li>
<li class="toctree-l3"><a class="reference internal" href="../../api/v2/fluid/regularizer.html">Regularizer</a></li>
</ul>
</li>
</ul>
</li>
<li class="toctree-l1"><a class="reference internal" href="../../mobile/index_en.html">MOBILE</a><ul>
<li class="toctree-l2"><a class="reference internal" href="../../mobile/cross_compiling_for_android_en.html">Build PaddlePaddle for Android</a></li>
<li class="toctree-l2"><a class="reference internal" href="../../mobile/cross_compiling_for_ios_en.html">PaddlePaddle Compiling Guide for iOS</a></li>
<li class="toctree-l2"><a class="reference internal" href="../../mobile/cross_compiling_for_raspberry_en.html">Build PaddlePaddle for Raspberry Pi</a></li>
</ul>
</li>
</ul>
</nav>
<section class="doc-content-wrap">
<div role="navigation" aria-label="breadcrumbs navigation">
<ul class="wy-breadcrumbs">
<li>Intel® MKL Packed on PaddlePaddle: Design Doc</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="intel-mkl-packed-on-paddlepaddle-design-doc">
<span id="intel-mkl-packed-on-paddlepaddle-design-doc"></span><h1>Intel® MKL Packed on PaddlePaddle: Design Doc<a class="headerlink" href="#intel-mkl-packed-on-paddlepaddle-design-doc" title="Permalink to this headline"></a></h1>
<div class="section" id="contents">
<span id="contents"></span><h2>Contents<a class="headerlink" href="#contents" title="Permalink to this headline"></a></h2>
<ul class="simple">
<li><a class="reference external" href="#overview">Overview</a></li>
<li><a class="reference external" href="#key-points">Key Points</a><ul>
<li><a class="reference external" href="#background">Background</a></li>
<li><a class="reference external" href="#solution">Solution</a></li>
</ul>
</li>
<li><a class="reference external" href="#actions">Actions</a><ul>
<li><a class="reference external" href="#cmake">CMake</a></li>
<li><a class="reference external" href="#layers">Layers</a></li>
<li><a class="reference external" href="#unit-tests">Unit Tests</a></li>
<li><a class="reference external" href="#python-api">Python API</a></li>
<li><a class="reference external" href="#benchmarking">Benchmarking</a></li>
</ul>
</li>
</ul>
</div>
<div class="section" id="overview">
<span id="overview"></span><h2>Overview<a class="headerlink" href="#overview" title="Permalink to this headline"></a></h2>
<p>我们计划将 Intel® MKL 中引入的 GEMM Packed APIs[<a class="reference external" href="#references">1</a>] 集成到 PaddlePaddle 中,充分发挥英特尔平台的优势,有效提升PaddlePaddle在英特尔架构上的性能。
现阶段的优化主要针对 Recurrent Neural Network(以下简称RNN)相关层(包括<code class="docutils literal"><span class="pre">RecurrentLayer</span></code>, <code class="docutils literal"><span class="pre">GatedRecurrentLayer</span></code><code class="docutils literal"><span class="pre">LstmLayer</span></code>), 以及 PaddlePaddle V1 API。</p>
</div>
<div class="section" id="key-points">
<span id="key-points"></span><h2>Key Points<a class="headerlink" href="#key-points" title="Permalink to this headline"></a></h2>
<div class="section" id="background">
<span id="background"></span><h3>Background<a class="headerlink" href="#background" title="Permalink to this headline"></a></h3>
<p>目前PaddlePaddle采用了 Intel® MKL库的<a class="reference external" href="https://software.intel.com/en-us/mkl-developer-reference-c-cblas-gemm">cblas_?gemm</a>函数,这个函数本身会在计算前将原数据转换为更适合英特尔平台的内部格式。</p>
<ol class="simple">
<li>转换耗时 这一数据格式的转换操作(Packing),在问题本身的计算量比较小的时候,显得相对来说较为耗时。例如在DeepSpeech2 [<a class="reference external" href="#references">2</a>] 的Vanilla RNN部分中,矩阵大小是<code class="docutils literal"><span class="pre">batch_size</span> <span class="pre">*</span> <span class="pre">2048</span></code></li>
<li>转换冗余 由于在现有的某些情况下(例如RNN),多次调用 cblas_?gemm 会使用相同的原数据,因此,每次调用时对原数据的重复Packing便成为了冗余。</li>
</ol>
<p>为了最大程度减少多次调用 cblas_?gemm 在Packing上的耗时,Intel® MKL 引入了以下四个API:</p>
<ul class="simple">
<li>cblas_?gemm_alloc</li>
<li>cblas_?gemm_pack</li>
<li>cblas_?gemm_compute</li>
<li>cblas_?gemm_free</li>
</ul>
<p>通过使用这些API,我们可以先完成对原数据的Packing操作,再把已转换为Packed格式的数据传递给那些复用同一数据的gemm_compute函数,从而避免了Packing冗余。</p>
</div>
<div class="section" id="solution">
<span id="solution"></span><h3>Solution<a class="headerlink" href="#solution" title="Permalink to this headline"></a></h3>
<p>在RNN的情况下,同一次前向、后向(forward/backward)过程中所有时间步(time step)共享同一个权重(weight)。当只做推断(inference)时,各次前向之间也都使用了相同的权重,没有必要在每次前向中每个时间步的计算时对权重进行重复的Packing操作。</p>
<p>我们通过使用新引入的GEMM Packed APIs,在层初始化的时候,先完成对权重的Packing操作,然后在前向,后向时复用已经转换过的权重,并在每次权重更新后,对新的权重进行转换用于下次迭代。</p>
<ul class="simple">
<li>优化前,对于序列长度(sequence length)为<code class="docutils literal"><span class="pre">T</span></code>的网络模型(model), <code class="docutils literal"><span class="pre">N</span></code>次迭代执行的转换次数为:<ul>
<li><code class="docutils literal"><span class="pre">inference</span></code><code class="docutils literal"><span class="pre">N</span> <span class="pre">*</span> <span class="pre">T</span></code></li>
<li><code class="docutils literal"><span class="pre">training</span></code><code class="docutils literal"><span class="pre">2</span> <span class="pre">*</span> <span class="pre">N</span> <span class="pre">*</span> <span class="pre">T</span></code></li>
</ul>
</li>
<li>优化后,对于同样设置的网络模型,其转换次数减少至:<ul>
<li><code class="docutils literal"><span class="pre">inference</span></code><code class="docutils literal"><span class="pre">1</span></code></li>
<li><code class="docutils literal"><span class="pre">training</span></code><code class="docutils literal"><span class="pre">2</span> <span class="pre">*</span> <span class="pre">N</span></code></li>
</ul>
</li>
</ul>
</div>
</div>
<div class="section" id="actions">
<span id="actions"></span><h2>Actions<a class="headerlink" href="#actions" title="Permalink to this headline"></a></h2>
<p>添加的相关文件和目录结构如下:</p>
<div class="highlight-txt"><div class="highlight"><pre><span></span>PaddlePaddle/Paddle
├── ...
└── paddle/
├── ...
└── gserver/
├── ...
├── layers/
│ ├── ...
│ ├── MKLPackedRecurrentLayer.*
| ├── MKLPackedGatedRecurrentLayer.*
| ├── MKLPackedLstmLayer.*
| └── MKLPackedGemm.h
└── tests/
├── ...
└── test_MKLPacked.cpp
</pre></div>
</div>
<div class="section" id="cmake">
<span id="cmake"></span><h3>CMake<a class="headerlink" href="#cmake" title="Permalink to this headline"></a></h3>
<p>在对应的<code class="docutils literal"><span class="pre">CMakeLists.txt</span></code>中根据<code class="docutils literal"><span class="pre">WITH_MKL</span></code>是否打开,来决定是否开启MKL Packed相关功能。</p>
</div>
<div class="section" id="layers">
<span id="layers"></span><h3>Layers<a class="headerlink" href="#layers" title="Permalink to this headline"></a></h3>
<p>所有的<code class="docutils literal"><span class="pre">MKLPacked*Layer</span></code>都继承于PaddlePaddle的基类<code class="docutils literal"><span class="pre">Layer</span></code>, 并添加头文件 <code class="docutils literal"><span class="pre">MKLPackedGemm.h</span></code>,该文件对相关GEMM Packed APIs做了封装。</p>
</div>
<div class="section" id="unit-tests">
<span id="unit-tests"></span><h3>Unit Tests<a class="headerlink" href="#unit-tests" title="Permalink to this headline"></a></h3>
<p>我们会添加<code class="docutils literal"><span class="pre">test_MKLPacked.cpp</span></code>用于MKL Packed优化后layer的测试。
对于每一个新加的RNN layer,我们会对比如下2个方面:</p>
<ol class="simple">
<li>对比优化后layer自身,sequence mode(<code class="docutils literal"><span class="pre">rnn_use_batch=false</span></code>)与batch mode(<code class="docutils literal"><span class="pre">rnn_use_batch=true</span></code>)的结果。</li>
<li>对比优化后layer与相对应的PaddlePaddle原有layer, 在batch mode下的结果。</li>
</ol>
</div>
<div class="section" id="python-api">
<span id="python-api"></span><h3>Python API<a class="headerlink" href="#python-api" title="Permalink to this headline"></a></h3>
<p>TBD</p>
</div>
<div class="section" id="benchmarking">
<span id="benchmarking"></span><h3>Benchmarking<a class="headerlink" href="#benchmarking" title="Permalink to this headline"></a></h3>
<p>会添加相应的脚本用于测试和对比在使用MKL Packed recurrent layers 前后的网络性能。</p>
</div>
</div>
<div class="section" id="references">
<span id="references"></span><h2>References<a class="headerlink" href="#references" title="Permalink to this headline"></a></h2>
<div class="toctree-wrapper compound">
<ul>
<li class="toctree-l1"><a class="reference external" href="https://software.intel.com/en-us/articles/introducing-the-new-packed-apis-for-gemm">Introducing the new Packed APIs for GEMM</a></li>
<li class="toctree-l1"><a class="reference external" href="https://github.com/PaddlePaddle/DeepSpeech#deepspeech2-on-paddlepaddle">DeepSpeech2 on PaddlePaddle</a></li>
</ul>
</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
<!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>Intel® MKL-DNN on PaddlePaddle: Design Doc &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="../../howto/index_en.html">HOW TO</a></li>
<li class="toctree-l1"><a class="reference internal" href="../../api/index_en.html">API</a></li>
<li class="toctree-l1"><a class="reference internal" href="../../mobile/index_en.html">MOBILE</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/build_and_install/index_en.html">Install and Build</a><ul>
<li class="toctree-l3"><a class="reference internal" href="../../getstarted/build_and_install/pip_install_en.html">Install Using pip</a></li>
<li class="toctree-l3"><a class="reference internal" href="../../getstarted/build_and_install/docker_install_en.html">Run in Docker Containers</a></li>
<li class="toctree-l3"><a class="reference internal" href="../../howto/dev/build_en.html">Build using Docker</a></li>
<li class="toctree-l3"><a class="reference internal" href="../../getstarted/build_and_install/build_from_source_en.html">Build from Sources</a></li>
</ul>
</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/usage/cmd_parameter/index_en.html">Set Command-line Parameters</a><ul>
<li class="toctree-l3"><a class="reference internal" href="../../howto/usage/cmd_parameter/use_case_en.html">Use Case</a></li>
<li class="toctree-l3"><a class="reference internal" href="../../howto/usage/cmd_parameter/arguments_en.html">Argument Outline</a></li>
<li class="toctree-l3"><a class="reference internal" href="../../howto/usage/cmd_parameter/detail_introduction_en.html">Detail Description</a></li>
</ul>
</li>
<li class="toctree-l2"><a class="reference internal" href="../../howto/usage/cluster/cluster_train_en.html">PaddlePaddle Distributed Training</a></li>
<li class="toctree-l2"><a class="reference internal" href="../../howto/usage/k8s/k8s_en.html">Paddle On Kubernetes</a></li>
<li class="toctree-l2"><a class="reference internal" href="../../howto/usage/k8s/k8s_aws_en.html">Distributed PaddlePaddle Training on AWS with Kubernetes</a></li>
<li class="toctree-l2"><a class="reference internal" href="../../howto/dev/new_layer_en.html">Write New Layers</a></li>
<li class="toctree-l2"><a class="reference internal" href="../../howto/dev/contribute_to_paddle_en.html">Contribute Code</a></li>
<li class="toctree-l2"><a class="reference internal" href="../../howto/dev/write_docs_en.html">Contribute Documentation</a></li>
<li class="toctree-l2"><a class="reference internal" href="../../howto/deep_model/rnn/index_en.html">RNN Models</a><ul>
<li class="toctree-l3"><a class="reference internal" href="../../howto/deep_model/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="../../api/index_en.html">API</a><ul>
<li class="toctree-l2"><a class="reference internal" href="../../api/v2/model_configs.html">Model Configuration</a><ul>
<li class="toctree-l3"><a class="reference internal" href="../../api/v2/config/activation.html">Activation</a></li>
<li class="toctree-l3"><a class="reference internal" href="../../api/v2/config/layer.html">Layers</a></li>
<li class="toctree-l3"><a class="reference internal" href="../../api/v2/config/evaluators.html">Evaluators</a></li>
<li class="toctree-l3"><a class="reference internal" href="../../api/v2/config/optimizer.html">Optimizer</a></li>
<li class="toctree-l3"><a class="reference internal" href="../../api/v2/config/pooling.html">Pooling</a></li>
<li class="toctree-l3"><a class="reference internal" href="../../api/v2/config/networks.html">Networks</a></li>
<li class="toctree-l3"><a class="reference internal" href="../../api/v2/config/attr.html">Parameter Attribute</a></li>
</ul>
</li>
<li class="toctree-l2"><a class="reference internal" href="../../api/v2/data.html">Data Reader Interface and DataSets</a><ul>
<li class="toctree-l3"><a class="reference internal" href="../../api/v2/data/data_reader.html">Data Reader Interface</a></li>
<li class="toctree-l3"><a class="reference internal" href="../../api/v2/data/image.html">Image Interface</a></li>
<li class="toctree-l3"><a class="reference internal" href="../../api/v2/data/dataset.html">Dataset</a></li>
</ul>
</li>
<li class="toctree-l2"><a class="reference internal" href="../../api/v2/run_logic.html">Training and Inference</a></li>
<li class="toctree-l2"><a class="reference internal" href="../../api/v2/fluid.html">Fluid</a><ul>
<li class="toctree-l3"><a class="reference internal" href="../../api/v2/fluid/layers.html">Layers</a></li>
<li class="toctree-l3"><a class="reference internal" href="../../api/v2/fluid/data_feeder.html">DataFeeder</a></li>
<li class="toctree-l3"><a class="reference internal" href="../../api/v2/fluid/executor.html">Executor</a></li>
<li class="toctree-l3"><a class="reference internal" href="../../api/v2/fluid/initializer.html">Initializer</a></li>
<li class="toctree-l3"><a class="reference internal" href="../../api/v2/fluid/evaluator.html">Evaluator</a></li>
<li class="toctree-l3"><a class="reference internal" href="../../api/v2/fluid/nets.html">Nets</a></li>
<li class="toctree-l3"><a class="reference internal" href="../../api/v2/fluid/optimizer.html">Optimizer</a></li>
<li class="toctree-l3"><a class="reference internal" href="../../api/v2/fluid/param_attr.html">ParamAttr</a></li>
<li class="toctree-l3"><a class="reference internal" href="../../api/v2/fluid/profiler.html">Profiler</a></li>
<li class="toctree-l3"><a class="reference internal" href="../../api/v2/fluid/regularizer.html">Regularizer</a></li>
</ul>
</li>
</ul>
</li>
<li class="toctree-l1"><a class="reference internal" href="../../mobile/index_en.html">MOBILE</a><ul>
<li class="toctree-l2"><a class="reference internal" href="../../mobile/cross_compiling_for_android_en.html">Build PaddlePaddle for Android</a></li>
<li class="toctree-l2"><a class="reference internal" href="../../mobile/cross_compiling_for_ios_en.html">PaddlePaddle Compiling Guide for iOS</a></li>
<li class="toctree-l2"><a class="reference internal" href="../../mobile/cross_compiling_for_raspberry_en.html">Build PaddlePaddle for Raspberry Pi</a></li>
</ul>
</li>
</ul>
</nav>
<section class="doc-content-wrap">
<div role="navigation" aria-label="breadcrumbs navigation">
<ul class="wy-breadcrumbs">
<li>Intel® MKL-DNN on PaddlePaddle: Design Doc</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="intel-mkl-dnn-on-paddlepaddle-design-doc">
<span id="intel-mkl-dnn-on-paddlepaddle-design-doc"></span><h1>Intel® MKL-DNN on PaddlePaddle: Design Doc<a class="headerlink" href="#intel-mkl-dnn-on-paddlepaddle-design-doc" title="Permalink to this headline"></a></h1>
<p>我们计划将英特尔深度神经网络数学库<a class="reference external" href="https://github.com/01org/mkl-dnn">Intel MKL-DNN</a>
(Intel Math Kernel Library for Deep Neural Networks)集成到PaddlePaddle,
充分展现英特尔平台的优势,有效提升PaddlePaddle在英特尔架构上的性能。</p>
<div align="center">
<img src="image/overview.png"><br/>
Figure 1. PaddlePaddle on IA
</div><p>近期目标</p>
<ul class="simple">
<li>完成常用Layer的MKL-DNN实现。</li>
<li>完成常见深度神经网络VGG,GoogLeNet 和 ResNet的MKL-DNN实现。</li>
</ul>
<p>目前的优化,主要针对PaddlePaddle在重构之前的代码框架以及V1的API。
具体的完成状态可以参见<a class="reference external" href="https://github.com/PaddlePaddle/Paddle/projects/21">这里</a></p>
<div class="section" id="contents">
<span id="contents"></span><h2>Contents<a class="headerlink" href="#contents" title="Permalink to this headline"></a></h2>
<ul class="simple">
<li><a class="reference external" href="#overview">Overview</a></li>
<li><a class="reference external" href="#actions">Actions</a><ul>
<li><a class="reference external" href="#cmake">CMake</a></li>
<li><a class="reference external" href="#matrix">Matrix</a></li>
<li><a class="reference external" href="#layers">Layers</a></li>
<li><a class="reference external" href="#activations">Activations</a></li>
<li><a class="reference external" href="#parameters">Parameters</a></li>
<li><a class="reference external" href="#gradients">Gradients</a></li>
<li><a class="reference external" href="#unit-tests">Unit Tests</a></li>
<li><a class="reference external" href="#python-api">Python API</a></li>
<li><a class="reference external" href="#benchmarking">Benchmarking</a></li>
<li><a class="reference external" href="#others">Others</a></li>
</ul>
</li>
<li><a class="reference external" href="#design-concerns">Design Concerns</a></li>
</ul>
</div>
<div class="section" id="overview">
<span id="overview"></span><h2>Overview<a class="headerlink" href="#overview" title="Permalink to this headline"></a></h2>
<p>我们会把MKL-DNN会作为第三方库集成进PaddlePaddle,与其他第三方库一样,会在编译PaddlePaddle的时候下载并编译MKL-DNN。</p>
<p>同时,为了进一步提升PaddlePaddle在基本数学运算的计算速度,我们也将MKLML即(MKL small library[<a class="reference external" href="#references">1</a>])
作为另一个第三方库集成进PaddlePaddle,它只会包括生成好的动态库和头文件。</p>
<p>MKL,MKLML以及MKL-DNN三者关系如下表:</p>
<p>| Name | Open Source | License | Descriptions |
| :&#8212;&#8212;&#8212;- | :&#8212;&#8212;&#8212;&#8212;&#8212; | :&#8212;&#8212;&#8212;- | :&#8212;&#8212;&#8212;&#8212; |
| MKL | No | Proprietary | Accelerate math processing routines |
| MKLML | No | Proprietary | Small package of MKL, especially for Machine Learning |
| MKL-DNN | Yes | Apache 2.0 | Accelerate primitives processing routines especially for Deep Neural Networks |</p>
<p>MKLML可以与MKL-DNN共同使用,以此达到最好的性能。</p>
<div align="center">
<img src="image/engine.png"><br/>
Figure 2. PaddlePaddle with MKL Engines
</div></div>
<div class="section" id="actions">
<span id="actions"></span><h2>Actions<a class="headerlink" href="#actions" title="Permalink to this headline"></a></h2>
<p>添加的相关文件和目录结构如下:</p>
<div class="highlight-txt"><div class="highlight"><pre><span></span>PaddlePaddle/Paddle
├── ...
├── cmake/
│ ├── external/
│ │ ├── ...
│ │ ├── mkldnn.cmake
│ │ └── mklml.cmake
└── paddle/
├── ...
├── math/
│ ├── ...
│ └── MKLDNNMatrix.*
└── gserver/
├── ...
├── layers/
│ ├── ...
│ └── MKLDNN*Layer.*
├── activations/
│ ├── ...
│ └── MKLDNNActivations.*
└── tests/
├── ...
├── MKLDNNTester.*
└── test_MKLDNN.cpp
</pre></div>
</div>
<div class="section" id="cmake">
<span id="cmake"></span><h3>CMake<a class="headerlink" href="#cmake" title="Permalink to this headline"></a></h3>
<p><code class="docutils literal"><span class="pre">CMakeLists.txt</span></code>中提供一个与MKL有关的总开关:<code class="docutils literal"><span class="pre">WITH_MKL</span></code>,它负责决定编译时是否使用MKLML和MKL-DNN</p>
<ul class="simple">
<li><code class="docutils literal"><span class="pre">WITH_MKLML</span></code> 控制是否使用MKLML库。
当打开<code class="docutils literal"><span class="pre">WITH_MKL</span></code>时,会自动使用MKLML库作为PaddlePaddle的CBLAS和LAPACK库,同时会开启Intel OpenMP用于提高MKLML的性能。
编译时会把对应的头文件和库放在<code class="docutils literal"><span class="pre">build/third_party/install/mklml/*</span></code>目录下对应的地方。
MKLML的库目前都是动态库,主要包括<code class="docutils literal"><span class="pre">libiomp5.so</span></code><code class="docutils literal"><span class="pre">libmklml_intel.so</span></code></li>
<li><code class="docutils literal"><span class="pre">WITH_MKLDNN</span></code> 控制是否使用MKL-DNN。
当开启<code class="docutils literal"><span class="pre">WITH_MKL</span></code>时,会自动根据硬件配置[<a class="reference external" href="#references">2</a>]选择是否编译MKL-DNN。
编译时会把对应的头文件和库放在<code class="docutils literal"><span class="pre">build/third_party/install/mkldnn/*</span></code>目录下对应的地方。
MKL-DNN的库目前只有动态库<code class="docutils literal"><span class="pre">libmkldnn.so</span></code></li>
</ul>
</div>
<div class="section" id="matrix">
<span id="matrix"></span><h3>Matrix<a class="headerlink" href="#matrix" title="Permalink to this headline"></a></h3>
<p>目前在PaddlePaddle中数据都是以<code class="docutils literal"><span class="pre">NCHW</span></code>的格式存储,但是在MKL-DNN中的排列方式不止这一种。
所以我们定义了一个<code class="docutils literal"><span class="pre">MKLDNNMatrix</span></code>用于管理MKL-DNN数据的不同格式以及相互之间的转换。</p>
<div align="center">
<img src="image/matrix.png"><br/>
Figure 3. MKLDNNMatrix
</div></div>
<div class="section" id="layers">
<span id="layers"></span><h3>Layers<a class="headerlink" href="#layers" title="Permalink to this headline"></a></h3>
<p>所有MKL-DNN的Layers都会继承于<code class="docutils literal"><span class="pre">MKLDNNLayer</span></code>,该类继承于PaddlePaddle的基类<code class="docutils literal"><span class="pre">Layer</span></code>
<code class="docutils literal"><span class="pre">MKLDNNLayer</span></code>中会提供一些必要的接口和函数,并且会写好<code class="docutils literal"><span class="pre">forward</span></code><code class="docutils literal"><span class="pre">backward</span></code>的基本逻辑,
子类只需要使用定义好的接口,实现具体的函数功能即可。</p>
<div align="center">
<img src="image/layers.png"><br/>
Figure 4. MKLDNNLayer
</div><p>每个MKLDNNLayer都包含用于内部存储和外部存储的一系列MKLDNNMatrix:</p>
<ul class="simple">
<li>内部存储(internel memory):<code class="docutils literal"><span class="pre">inVal_</span></code>,<code class="docutils literal"><span class="pre">inGrad_</span></code>,<code class="docutils literal"><span class="pre">outVal_</span></code><code class="docutils literal"><span class="pre">outGrad_</span></code>,分别代表输入数据,输入梯度,输出数据和输出梯度。</li>
<li>外部存储(external memory):都是以ext开头,比如<code class="docutils literal"><span class="pre">extInVal_</span></code><code class="docutils literal"><span class="pre">extInGrad_</span></code>,它们主要是用于,
当数据格式与PaddlePaddle默认的<code class="docutils literal"><span class="pre">NCHW</span></code>格式不匹配时,转换内存的工作。
需要注意的是,PaddlePaddle的activation会直接使用<code class="docutils literal"><span class="pre">output_.value</span></code><code class="docutils literal"><span class="pre">output_.grad</span></code>
所以<code class="docutils literal"><span class="pre">extOutVal_</span></code><code class="docutils literal"><span class="pre">extOutGrad_</span></code>必须分别与<code class="docutils literal"><span class="pre">output_.value</span></code><code class="docutils literal"><span class="pre">output_.grad</span></code>共享内存,
如果不需要外部存储用于转换,那么对应的内部存储也会与它们共享内存。</li>
<li>转换函数(resetXXX): 包括<code class="docutils literal"><span class="pre">resetInValue</span></code><code class="docutils literal"><span class="pre">resetInGrad</span></code><code class="docutils literal"><span class="pre">resetOutValue</span></code><code class="docutils literal"><span class="pre">resetOutGrad</span></code>
表示对输入数据,输入梯度,输出数据和输出梯度的转换。
这些函数会根据输入参数重新设置内部和外部存储,当然这两者也可以相等,即表示不需要转换。</li>
</ul>
<p>注意:每个<code class="docutils literal"><span class="pre">MKLDNNlayer</span></code>的子类只需要使用内部存储就可以了,所有外部的转换工作都会在reset系列函数中都准备好。</p>
</div>
<div class="section" id="activations">
<span id="activations"></span><h3>Activations<a class="headerlink" href="#activations" title="Permalink to this headline"></a></h3>
<p>在重构前的PaddlePaddle中,激活函数是独立于<code class="docutils literal"><span class="pre">Layer</span></code>的概念,并且输入输出都是共用一块内存,
所以添加了对应的<code class="docutils literal"><span class="pre">MKLDNNActivation</span></code>来实现,方式类似于<code class="docutils literal"><span class="pre">MKLDNNLayer</span></code></p>
</div>
<div class="section" id="parameters">
<span id="parameters"></span><h3>Parameters<a class="headerlink" href="#parameters" title="Permalink to this headline"></a></h3>
<p>对于有参数的层,我们会保证<code class="docutils literal"><span class="pre">MKLDNNLayer</span></code>使用的参数与PaddlePaddle申请的buffer共用一块内存。
如果存在数据排列格式不一样的情况时,我们会在网络训练之前把格式转换为MKL-DNN希望的格式,
在训练结束的时候再保存为PaddlePaddle的格式,但是整个训练过程中不需要任何转换。
这样既使得最终保存的参数格式与PaddlePaddle一致,又可以避免不必要的转换。</p>
</div>
<div class="section" id="gradients">
<span id="gradients"></span><h3>Gradients<a class="headerlink" href="#gradients" title="Permalink to this headline"></a></h3>
<p>由于MKL-DNN的操作都是直接覆盖的形式,也就是说输出的结果不会在原来的数据上累加,
这样带来的好处就是不需要一直清空memory,节省了不必要的操作。
但是注意的是,当网络出现分支且在<code class="docutils literal"><span class="pre">backward</span></code>的时候,需要累加不同Layer传过来的梯度。
所以在<code class="docutils literal"><span class="pre">MKLDNNlayer</span></code>中实现了一个merge的方法,此时每个小分支的<code class="docutils literal"><span class="pre">Input</span> <span class="pre">Gradient</span></code>
会先临时保存在<code class="docutils literal"><span class="pre">MKLDNNMatrix</span></code>中,由分支处的Layer负责求和,并把结果放到当前层的<code class="docutils literal"><span class="pre">output_.grad</span></code>中。
所以整体上,在实现每个子类的时候就不需要关心分支的事情了。</p>
<div align="center">
<img src="image/gradients.png"><br/>
Figure 5. Merge Gradients
</div></div>
<div class="section" id="unit-tests">
<span id="unit-tests"></span><h3>Unit Tests<a class="headerlink" href="#unit-tests" title="Permalink to this headline"></a></h3>
<p>我们会添加<code class="docutils literal"><span class="pre">test_MKLDNN.cpp</span></code><code class="docutils literal"><span class="pre">MKLDNNTester.*</span></code>用于MKL-DNN的测试。
测试分为每个Layer(或Activation)的单元测试和简单网络的整体测试。
每个测试会对比PaddlePaddle中CPU算出的结果与MKL-DNN的结果,小于某个比较小的阈值认为通过。</p>
</div>
<div class="section" id="python-api">
<span id="python-api"></span><h3>Python API<a class="headerlink" href="#python-api" title="Permalink to this headline"></a></h3>
<p>目前只考虑<strong>v1 API</strong></p>
<p>计划在<code class="docutils literal"><span class="pre">python/paddle/trainer/config_parser.py</span></code>里面添加<code class="docutils literal"><span class="pre">use_mkldnn</span></code>这个选择,方便用户选择使用MKL-DNN的layers。</p>
<p>具体实现方式比如:</p>
<div class="highlight-python"><div class="highlight"><pre><span></span><span class="n">use_mkldnn</span> <span class="o">=</span> <span class="nb">bool</span><span class="p">(</span><span class="nb">int</span><span class="p">(</span><span class="n">g_command_config_args</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="s2">&quot;use_mkldnn&quot;</span><span class="p">,</span> <span class="mi">0</span><span class="p">)))</span>
<span class="k">if</span> <span class="n">use_mkldnn</span>
<span class="bp">self</span><span class="o">.</span><span class="n">layer_type</span> <span class="o">=</span> <span class="n">mkldnn_</span><span class="o">*</span>
</pre></div>
</div>
<p>所有MKL-DNN的<code class="docutils literal"><span class="pre">layer_type</span></code>会以*mkldnn_*开头,这些会在<code class="docutils literal"><span class="pre">MKLDNN*Layer</span></code>注册layer的时候保证,以示区分。</p>
<p>同时,会在<code class="docutils literal"><span class="pre">paddle/utils.Flags</span></code>中添加一个<code class="docutils literal"><span class="pre">use_mkldnn</span></code>的flag,用于选择是否使用MKL-DNN的相关功能。</p>
</div>
<div class="section" id="benchmarking">
<span id="benchmarking"></span><h3>Benchmarking<a class="headerlink" href="#benchmarking" title="Permalink to this headline"></a></h3>
<p>会添加相应的脚本在<a class="reference external" href="https://github.com/PaddlePaddle/Paddle/tree/develop/benchmark/paddle/image">这里</a>,用于测试和对比在使用MKL-DNN前后的CNN网络性能。
测试的性能对比结果会在<a class="reference external" href="https://github.com/PaddlePaddle/Paddle/blob/develop/benchmark/IntelOptimizedPaddle.md">IntelOptimizedPaddle.md</a></p>
</div>
<div class="section" id="others">
<span id="others"></span><h3>Others<a class="headerlink" href="#others" title="Permalink to this headline"></a></h3>
<ol class="simple">
<li>如果在使用MKL-DNN的情况下,会把CPU的Buffer对齐为4096,具体可以参考MKL-DNN中的<a class="reference external" href="https://github.com/01org/mkl-dnn/blob/master/include/mkldnn.hpp#L673">memory</a></li>
<li>深入PaddlePaddle,寻找有没有其他可以优化的可能,进一步优化。比如可能会用OpenMP改进SGD的更新性能。</li>
</ol>
</div>
</div>
<div class="section" id="design-concerns">
<span id="design-concerns"></span><h2>Design Concerns<a class="headerlink" href="#design-concerns" title="Permalink to this headline"></a></h2>
<p>为了更好的符合PaddlePaddle的代码风格[<a class="reference external" href="#references">3</a>],同时又尽可能少的牺牲MKL-DNN的性能[<a class="reference external" href="#references">4</a>]。</p>
<p>我们总结出一些特别需要注意的点:</p>
<ol class="simple">
<li>使用**deviceId_**。为了尽可能少的在父类Layer中添加变量或者函数,
我们决定使用已有的<code class="docutils literal"><span class="pre">deviceId_</span></code>变量来区分layer的属性,定义<code class="docutils literal"><span class="pre">-2</span></code><code class="docutils literal"><span class="pre">MKLDNNLayer</span></code>特有的设备ID。</li>
<li>重写父类Layer的<strong>init</strong>函数,修改<code class="docutils literal"><span class="pre">deviceId_</span></code><code class="docutils literal"><span class="pre">-2</span></code>,代表这个layer是用于跑在MKL-DNN的环境下。</li>
<li>创建<code class="docutils literal"><span class="pre">MKLDNNBase</span></code>,定义一些除了layer和memory相关的类和函数。
包括MKL-DNN会用到<code class="docutils literal"><span class="pre">MKLDNNStream</span></code><code class="docutils literal"><span class="pre">CPUEngine</span></code>,和未来可能还会用到<code class="docutils literal"><span class="pre">FPGAEngine</span></code>等。</li>
<li>如果MKL-DNN layer的后面接有cpu device,那么就会使<code class="docutils literal"><span class="pre">output_.value</span></code><code class="docutils literal"><span class="pre">extOutVal_</span></code>共享内存,
同时数据格式就是<code class="docutils literal"><span class="pre">NCHW</span></code>,这样下一个cpu device就能拿到正确的数据。
在有普通的CPU layer时, <code class="docutils literal"><span class="pre">extOutVal_</span></code><code class="docutils literal"><span class="pre">extOutGrad_</span></code>的格式始终是<code class="docutils literal"><span class="pre">NCHW</span></code>或者<code class="docutils literal"><span class="pre">NC</span></code></li>
</ol>
</div>
<div class="section" id="references">
<span id="references"></span><h2>References<a class="headerlink" href="#references" title="Permalink to this headline"></a></h2>
<ol class="simple">
<li><a class="reference external" href="https://github.com/01org/mkl-dnn#linking-your-application">MKL small library</a><a class="reference external" href="https://software.intel.com/en-us/mkl">Intel MKL</a>的一个子集。
主要包括了深度学习相关的数学原语与操作,一般由MKL-DNN在发布<a class="reference external" href="https://github.com/01org/mkl-dnn/releases">新版本</a>时一起更新。</li>
<li><a class="reference external" href="https://github.com/01org/mkl-dnn#system-requirements">MKL-DNN System Requirements</a>
目前在PaddlePaddle中,仅会在支持AVX2指令集及以上的机器才使用MKL-DNN。</li>
<li><a class="reference external" href="https://github.com/PaddlePaddle/Paddle/pull/3096">原来的方案</a>会引入<strong>nextLayer</strong>的信息。
但是在PaddlePaddle中,无论是重构前的layer还是重构后的op,都不会想要知道next layer/op的信息。</li>
<li>MKL-DNN的高性能格式与PaddlePaddle原有的<code class="docutils literal"><span class="pre">NCHW</span></code>不同(PaddlePaddle中的cuDNN部分使用的也是<code class="docutils literal"><span class="pre">NCHW</span></code>,所以不存在这个问题)。
所以需要引入一个转换方法,并且只需要在必要的时候转换这种格式,才能更好的发挥MKL-DNN的性能。</li>
</ol>
</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
# Intel® MKL Packed on PaddlePaddle: Design Doc
## Contents
- [Overview](#overview)
- [Key Points](#key-points)
- [Background](#background)
- [Solution](#solution)
- [Actions](#actions)
- [CMake](#cmake)
- [Layers](#layers)
- [Unit Tests](#unit-tests)
- [Python API](#python-api)
- [Benchmarking](#benchmarking)
## Overview
我们计划将 Intel® MKL 中引入的 GEMM Packed APIs\[[1](#references)\] 集成到 PaddlePaddle 中,充分发挥英特尔平台的优势,有效提升PaddlePaddle在英特尔架构上的性能。
现阶段的优化主要针对 Recurrent Neural Network(以下简称RNN)相关层(包括`RecurrentLayer`, `GatedRecurrentLayer`和`LstmLayer`), 以及 PaddlePaddle V1 API。
## Key Points
### Background
目前PaddlePaddle采用了 Intel® MKL库的[cblas_?gemm](https://software.intel.com/en-us/mkl-developer-reference-c-cblas-gemm)函数,这个函数本身会在计算前将原数据转换为更适合英特尔平台的内部格式。
1. 转换耗时 \
这一数据格式的转换操作(Packing),在问题本身的计算量比较小的时候,显得相对来说较为耗时。例如在DeepSpeech2 \[[2](#references)\] 的Vanilla RNN部分中,矩阵大小是`batch_size * 2048`。
2. 转换冗余 \
由于在现有的某些情况下(例如RNN),多次调用 cblas_?gemm 会使用相同的原数据,因此,每次调用时对原数据的重复Packing便成为了冗余。
为了最大程度减少多次调用 cblas_?gemm 在Packing上的耗时,Intel® MKL 引入了以下四个API:
* cblas_?gemm_alloc
* cblas_?gemm_pack
* cblas_?gemm_compute
* cblas_?gemm_free
通过使用这些API,我们可以先完成对原数据的Packing操作,再把已转换为Packed格式的数据传递给那些复用同一数据的gemm_compute函数,从而避免了Packing冗余。
### Solution
在RNN的情况下,同一次前向、后向(forward/backward)过程中所有时间步(time step)共享同一个权重(weight)。当只做推断(inference)时,各次前向之间也都使用了相同的权重,没有必要在每次前向中每个时间步的计算时对权重进行重复的Packing操作。
我们通过使用新引入的GEMM Packed APIs,在层初始化的时候,先完成对权重的Packing操作,然后在前向,后向时复用已经转换过的权重,并在每次权重更新后,对新的权重进行转换用于下次迭代。
* 优化前,对于序列长度(sequence length)为`T`的网络模型(model), `N`次迭代执行的转换次数为:
- `inference`: `N * T`
- `training`: `2 * N * T`
* 优化后,对于同样设置的网络模型,其转换次数减少至:
- `inference`: `1`
- `training`: `2 * N`
## Actions
添加的相关文件和目录结构如下:
```txt
PaddlePaddle/Paddle
├── ...
└── paddle/
├── ...
└── gserver/
├── ...
├── layers/
│ ├── ...
│ ├── MKLPackedRecurrentLayer.*
| ├── MKLPackedGatedRecurrentLayer.*
| ├── MKLPackedLstmLayer.*
| └── MKLPackedGemm.h
└── tests/
├── ...
└── test_MKLPacked.cpp
```
### CMake
在对应的`CMakeLists.txt`中根据`WITH_MKL`是否打开,来决定是否开启MKL Packed相关功能。
### Layers
所有的`MKLPacked*Layer`都继承于PaddlePaddle的基类`Layer`, 并添加头文件 `MKLPackedGemm.h`,该文件对相关GEMM Packed APIs做了封装。
### Unit Tests
我们会添加`test_MKLPacked.cpp`用于MKL Packed优化后layer的测试。
对于每一个新加的RNN layer,我们会对比如下2个方面:
1. 对比优化后layer自身,sequence mode(`rnn_use_batch=false`)与batch mode(`rnn_use_batch=true`)的结果。
2. 对比优化后layer与相对应的PaddlePaddle原有layer, 在batch mode下的结果。
### Python API
TBD
### Benchmarking
会添加相应的脚本用于测试和对比在使用MKL Packed recurrent layers 前后的网络性能。
## References
1. [Introducing the new Packed APIs for GEMM](https://software.intel.com/en-us/articles/introducing-the-new-packed-apis-for-gemm)
2. [DeepSpeech2 on PaddlePaddle](https://github.com/PaddlePaddle/DeepSpeech#deepspeech2-on-paddlepaddle)
# Intel® MKL-DNN on PaddlePaddle: Design Doc
我们计划将英特尔深度神经网络数学库[Intel MKL-DNN](https://github.com/01org/mkl-dnn)
(Intel Math Kernel Library for Deep Neural Networks)集成到PaddlePaddle,
充分展现英特尔平台的优势,有效提升PaddlePaddle在英特尔架构上的性能。
<div align="center">
<img src="image/overview.png"><br/>
Figure 1. PaddlePaddle on IA
</div>
近期目标
- 完成常用Layer的MKL-DNN实现。
- 完成常见深度神经网络VGG,GoogLeNet 和 ResNet的MKL-DNN实现。
目前的优化,主要针对PaddlePaddle在重构之前的代码框架以及V1的API。
具体的完成状态可以参见[这里](https://github.com/PaddlePaddle/Paddle/projects/21)。
## Contents
- [Overview](#overview)
- [Actions](#actions)
- [CMake](#cmake)
- [Matrix](#matrix)
- [Layers](#layers)
- [Activations](#activations)
- [Parameters](#parameters)
- [Gradients](#gradients)
- [Unit Tests](#unit-tests)
- [Python API](#python-api)
- [Benchmarking](#benchmarking)
- [Others](#others)
- [Design Concerns](#design-concerns)
## Overview
我们会把MKL-DNN会作为第三方库集成进PaddlePaddle,与其他第三方库一样,会在编译PaddlePaddle的时候下载并编译MKL-DNN。
同时,为了进一步提升PaddlePaddle在基本数学运算的计算速度,我们也将MKLML即(MKL small library\[[1](#references)\])
作为另一个第三方库集成进PaddlePaddle,它只会包括生成好的动态库和头文件。
MKL,MKLML以及MKL-DNN三者关系如下表:
| Name | Open Source | License | Descriptions |
| :---------- | :--------------- | :---------- | :------------ |
| MKL | No | Proprietary | Accelerate math processing routines |
| MKLML | No | Proprietary | Small package of MKL, especially for Machine Learning |
| MKL-DNN | Yes | Apache 2.0 | Accelerate primitives processing routines especially for Deep Neural Networks |
MKLML可以与MKL-DNN共同使用,以此达到最好的性能。
<div align="center">
<img src="image/engine.png"><br/>
Figure 2. PaddlePaddle with MKL Engines
</div>
## Actions
添加的相关文件和目录结构如下:
```txt
PaddlePaddle/Paddle
├── ...
├── cmake/
│ ├── external/
│ │ ├── ...
│ │ ├── mkldnn.cmake
│ │ └── mklml.cmake
└── paddle/
├── ...
├── math/
│ ├── ...
│ └── MKLDNNMatrix.*
└── gserver/
├── ...
├── layers/
│ ├── ...
│ └── MKLDNN*Layer.*
├── activations/
│ ├── ...
│ └── MKLDNNActivations.*
└── tests/
├── ...
├── MKLDNNTester.*
└── test_MKLDNN.cpp
```
### CMake
在`CMakeLists.txt`中提供一个与MKL有关的总开关:`WITH_MKL`,它负责决定编译时是否使用MKLML和MKL-DNN
- `WITH_MKLML` 控制是否使用MKLML库。
当打开`WITH_MKL`时,会自动使用MKLML库作为PaddlePaddle的CBLAS和LAPACK库,同时会开启Intel OpenMP用于提高MKLML的性能。
编译时会把对应的头文件和库放在`build/third_party/install/mklml/*`目录下对应的地方。
MKLML的库目前都是动态库,主要包括`libiomp5.so`和`libmklml_intel.so`。
- `WITH_MKLDNN` 控制是否使用MKL-DNN。
当开启`WITH_MKL`时,会自动根据硬件配置[[2](#references)]选择是否编译MKL-DNN。
编译时会把对应的头文件和库放在`build/third_party/install/mkldnn/*`目录下对应的地方。
MKL-DNN的库目前只有动态库`libmkldnn.so`。
### Matrix
目前在PaddlePaddle中数据都是以`NCHW`的格式存储,但是在MKL-DNN中的排列方式不止这一种。
所以我们定义了一个`MKLDNNMatrix`用于管理MKL-DNN数据的不同格式以及相互之间的转换。
<div align="center">
<img src="image/matrix.png"><br/>
Figure 3. MKLDNNMatrix
</div>
### Layers
所有MKL-DNN的Layers都会继承于`MKLDNNLayer`,该类继承于PaddlePaddle的基类`Layer`。
在`MKLDNNLayer`中会提供一些必要的接口和函数,并且会写好`forward`和`backward`的基本逻辑,
子类只需要使用定义好的接口,实现具体的函数功能即可。
<div align="center">
<img src="image/layers.png"><br/>
Figure 4. MKLDNNLayer
</div>
每个MKLDNNLayer都包含用于内部存储和外部存储的一系列MKLDNNMatrix:
- 内部存储(internel memory):`inVal_`,`inGrad_`,`outVal_`和`outGrad_`,分别代表输入数据,输入梯度,输出数据和输出梯度。
- 外部存储(external memory):都是以ext开头,比如`extInVal_`和`extInGrad_`,它们主要是用于,
当数据格式与PaddlePaddle默认的`NCHW`格式不匹配时,转换内存的工作。
需要注意的是,PaddlePaddle的activation会直接使用`output_.value`和`output_.grad`,
所以`extOutVal_`和`extOutGrad_`必须分别与`output_.value`和`output_.grad`共享内存,
如果不需要外部存储用于转换,那么对应的内部存储也会与它们共享内存。
- 转换函数(resetXXX): 包括`resetInValue`,`resetInGrad`,`resetOutValue`和`resetOutGrad`,
表示对输入数据,输入梯度,输出数据和输出梯度的转换。
这些函数会根据输入参数重新设置内部和外部存储,当然这两者也可以相等,即表示不需要转换。
注意:每个`MKLDNNlayer`的子类只需要使用内部存储就可以了,所有外部的转换工作都会在reset系列函数中都准备好。
### Activations
在重构前的PaddlePaddle中,激活函数是独立于`Layer`的概念,并且输入输出都是共用一块内存,
所以添加了对应的`MKLDNNActivation`来实现,方式类似于`MKLDNNLayer`。
### Parameters
对于有参数的层,我们会保证`MKLDNNLayer`使用的参数与PaddlePaddle申请的buffer共用一块内存。
如果存在数据排列格式不一样的情况时,我们会在网络训练之前把格式转换为MKL-DNN希望的格式,
在训练结束的时候再保存为PaddlePaddle的格式,但是整个训练过程中不需要任何转换。
这样既使得最终保存的参数格式与PaddlePaddle一致,又可以避免不必要的转换。
### Gradients
由于MKL-DNN的操作都是直接覆盖的形式,也就是说输出的结果不会在原来的数据上累加,
这样带来的好处就是不需要一直清空memory,节省了不必要的操作。
但是注意的是,当网络出现分支且在`backward`的时候,需要累加不同Layer传过来的梯度。
所以在`MKLDNNlayer`中实现了一个merge的方法,此时每个小分支的`Input Gradient`
会先临时保存在`MKLDNNMatrix`中,由分支处的Layer负责求和,并把结果放到当前层的`output_.grad`中。
所以整体上,在实现每个子类的时候就不需要关心分支的事情了。
<div align="center">
<img src="image/gradients.png"><br/>
Figure 5. Merge Gradients
</div>
### Unit Tests
我们会添加`test_MKLDNN.cpp`和`MKLDNNTester.*`用于MKL-DNN的测试。
测试分为每个Layer(或Activation)的单元测试和简单网络的整体测试。
每个测试会对比PaddlePaddle中CPU算出的结果与MKL-DNN的结果,小于某个比较小的阈值认为通过。
### Python API
目前只考虑**v1 API**。
计划在`python/paddle/trainer/config_parser.py`里面添加`use_mkldnn`这个选择,方便用户选择使用MKL-DNN的layers。
具体实现方式比如:
```python
use_mkldnn = bool(int(g_command_config_args.get("use_mkldnn", 0)))
if use_mkldnn
self.layer_type = mkldnn_*
```
所有MKL-DNN的`layer_type`会以*mkldnn_*开头,这些会在`MKLDNN*Layer`注册layer的时候保证,以示区分。
同时,会在`paddle/utils.Flags`中添加一个`use_mkldnn`的flag,用于选择是否使用MKL-DNN的相关功能。
### Benchmarking
会添加相应的脚本在[这里](https://github.com/PaddlePaddle/Paddle/tree/develop/benchmark/paddle/image),用于测试和对比在使用MKL-DNN前后的CNN网络性能。
测试的性能对比结果会在[IntelOptimizedPaddle.md](https://github.com/PaddlePaddle/Paddle/blob/develop/benchmark/IntelOptimizedPaddle.md)
### Others
1. 如果在使用MKL-DNN的情况下,会把CPU的Buffer对齐为4096,具体可以参考MKL-DNN中的[memory](https://github.com/01org/mkl-dnn/blob/master/include/mkldnn.hpp#L673)。
2. 深入PaddlePaddle,寻找有没有其他可以优化的可能,进一步优化。比如可能会用OpenMP改进SGD的更新性能。
## Design Concerns
为了更好的符合PaddlePaddle的代码风格\[[3](#references)\],同时又尽可能少的牺牲MKL-DNN的性能\[[4](#references)\]。
我们总结出一些特别需要注意的点:
1. 使用**deviceId_**。为了尽可能少的在父类Layer中添加变量或者函数,
我们决定使用已有的`deviceId_`变量来区分layer的属性,定义`-2`为`MKLDNNLayer`特有的设备ID。
2. 重写父类Layer的**init**函数,修改`deviceId_`为`-2`,代表这个layer是用于跑在MKL-DNN的环境下。
3. 创建`MKLDNNBase`,定义一些除了layer和memory相关的类和函数。
包括MKL-DNN会用到`MKLDNNStream`和`CPUEngine`,和未来可能还会用到`FPGAEngine`等。
4. 如果MKL-DNN layer的后面接有cpu device,那么就会使`output_.value`与`extOutVal_`共享内存,
同时数据格式就是`NCHW`,这样下一个cpu device就能拿到正确的数据。
在有普通的CPU layer时, `extOutVal_`和`extOutGrad_`的格式始终是`NCHW`或者`NC`。
## References
1. [MKL small library](https://github.com/01org/mkl-dnn#linking-your-application)是[Intel MKL](https://software.intel.com/en-us/mkl)的一个子集。
主要包括了深度学习相关的数学原语与操作,一般由MKL-DNN在发布[新版本](https://github.com/01org/mkl-dnn/releases)时一起更新。
2. [MKL-DNN System Requirements](https://github.com/01org/mkl-dnn#system-requirements)。
目前在PaddlePaddle中,仅会在支持AVX2指令集及以上的机器才使用MKL-DNN。
3. [原来的方案](https://github.com/PaddlePaddle/Paddle/pull/3096)会引入**nextLayer**的信息。
但是在PaddlePaddle中,无论是重构前的layer还是重构后的op,都不会想要知道next layer/op的信息。
4. MKL-DNN的高性能格式与PaddlePaddle原有的`NCHW`不同(PaddlePaddle中的cuDNN部分使用的也是`NCHW`,所以不存在这个问题)。
所以需要引入一个转换方法,并且只需要在必要的时候转换这种格式,才能更好的发挥MKL-DNN的性能。
<!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>Intel® MKL Packed on PaddlePaddle: Design Doc &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="../../howto/index_cn.html">进阶指南</a></li>
<li class="toctree-l1"><a class="reference internal" href="../../api/index_cn.html">API</a></li>
<li class="toctree-l1"><a class="reference internal" href="../../faq/index_cn.html">FAQ</a></li>
<li class="toctree-l1"><a class="reference internal" href="../../mobile/index_cn.html">MOBILE</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/build_and_install/index_cn.html">安装与编译</a><ul>
<li class="toctree-l3"><a class="reference internal" href="../../getstarted/build_and_install/pip_install_cn.html">使用pip安装</a></li>
<li class="toctree-l3"><a class="reference internal" href="../../getstarted/build_and_install/docker_install_cn.html">使用Docker安装运行</a></li>
<li class="toctree-l3"><a class="reference internal" href="../../howto/dev/build_cn.html">用Docker编译和测试PaddlePaddle</a></li>
<li class="toctree-l3"><a class="reference internal" href="../../getstarted/build_and_install/build_from_source_cn.html">从源码编译</a></li>
</ul>
</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="../../howto/index_cn.html">进阶指南</a><ul>
<li class="toctree-l2"><a class="reference internal" href="../../howto/usage/cmd_parameter/index_cn.html">设置命令行参数</a><ul>
<li class="toctree-l3"><a class="reference internal" href="../../howto/usage/cmd_parameter/use_case_cn.html">使用案例</a></li>
<li class="toctree-l3"><a class="reference internal" href="../../howto/usage/cmd_parameter/arguments_cn.html">参数概述</a></li>
<li class="toctree-l3"><a class="reference internal" href="../../howto/usage/cmd_parameter/detail_introduction_cn.html">细节描述</a></li>
</ul>
</li>
<li class="toctree-l2"><a class="reference internal" href="../../howto/usage/cluster/cluster_train_cn.html">PaddlePaddle分布式训练</a></li>
<li class="toctree-l2"><a class="reference internal" href="../../howto/usage/k8s/k8s_basis_cn.html">Kubernetes 简介</a></li>
<li class="toctree-l2"><a class="reference internal" href="../../howto/usage/k8s/k8s_cn.html">Kubernetes单机训练</a></li>
<li class="toctree-l2"><a class="reference internal" href="../../howto/usage/k8s/k8s_distributed_cn.html">Kubernetes分布式训练</a></li>
<li class="toctree-l2"><a class="reference internal" href="../../howto/dev/contribute_to_paddle_cn.html">如何贡献代码</a></li>
<li class="toctree-l2"><a class="reference internal" href="../../howto/dev/write_docs_cn.html">如何贡献/修改文档</a></li>
<li class="toctree-l2"><a class="reference internal" href="../../howto/deep_model/rnn/index_cn.html">RNN相关模型</a><ul>
<li class="toctree-l3"><a class="reference internal" href="../../howto/deep_model/rnn/rnn_config_cn.html">RNN配置</a></li>
<li class="toctree-l3"><a class="reference internal" href="../../howto/deep_model/rnn/recurrent_group_cn.html">Recurrent Group教程</a></li>
<li class="toctree-l3"><a class="reference internal" href="../../howto/deep_model/rnn/hierarchical_layer_cn.html">支持双层序列作为输入的Layer</a></li>
<li class="toctree-l3"><a class="reference internal" href="../../howto/deep_model/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="../../api/index_cn.html">API</a><ul>
<li class="toctree-l2"><a class="reference internal" href="../../api/v2/model_configs.html">模型配置</a><ul>
<li class="toctree-l3"><a class="reference internal" href="../../api/v2/config/activation.html">Activation</a></li>
<li class="toctree-l3"><a class="reference internal" href="../../api/v2/config/layer.html">Layers</a></li>
<li class="toctree-l3"><a class="reference internal" href="../../api/v2/config/evaluators.html">Evaluators</a></li>
<li class="toctree-l3"><a class="reference internal" href="../../api/v2/config/optimizer.html">Optimizer</a></li>
<li class="toctree-l3"><a class="reference internal" href="../../api/v2/config/pooling.html">Pooling</a></li>
<li class="toctree-l3"><a class="reference internal" href="../../api/v2/config/networks.html">Networks</a></li>
<li class="toctree-l3"><a class="reference internal" href="../../api/v2/config/attr.html">Parameter Attribute</a></li>
</ul>
</li>
<li class="toctree-l2"><a class="reference internal" href="../../api/v2/data.html">数据访问</a><ul>
<li class="toctree-l3"><a class="reference internal" href="../../api/v2/data/data_reader.html">Data Reader Interface</a></li>
<li class="toctree-l3"><a class="reference internal" href="../../api/v2/data/image.html">Image Interface</a></li>
<li class="toctree-l3"><a class="reference internal" href="../../api/v2/data/dataset.html">Dataset</a></li>
</ul>
</li>
<li class="toctree-l2"><a class="reference internal" href="../../api/v2/run_logic.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>
<li class="toctree-l1"><a class="reference internal" href="../../mobile/index_cn.html">MOBILE</a><ul>
<li class="toctree-l2"><a class="reference internal" href="../../mobile/cross_compiling_for_android_cn.html">Android平台编译指南</a></li>
<li class="toctree-l2"><a class="reference internal" href="../../mobile/cross_compiling_for_ios_cn.html">iOS平台编译指南</a></li>
<li class="toctree-l2"><a class="reference internal" href="../../mobile/cross_compiling_for_raspberry_cn.html">Raspberry Pi平台编译指南</a></li>
</ul>
</li>
</ul>
</nav>
<section class="doc-content-wrap">
<div role="navigation" aria-label="breadcrumbs navigation">
<ul class="wy-breadcrumbs">
<li>Intel® MKL Packed on PaddlePaddle: Design Doc</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="intel-mkl-packed-on-paddlepaddle-design-doc">
<span id="intel-mkl-packed-on-paddlepaddle-design-doc"></span><h1>Intel® MKL Packed on PaddlePaddle: Design Doc<a class="headerlink" href="#intel-mkl-packed-on-paddlepaddle-design-doc" title="永久链接至标题"></a></h1>
<div class="section" id="contents">
<span id="contents"></span><h2>Contents<a class="headerlink" href="#contents" title="永久链接至标题"></a></h2>
<ul class="simple">
<li><a class="reference external" href="#overview">Overview</a></li>
<li><a class="reference external" href="#key-points">Key Points</a><ul>
<li><a class="reference external" href="#background">Background</a></li>
<li><a class="reference external" href="#solution">Solution</a></li>
</ul>
</li>
<li><a class="reference external" href="#actions">Actions</a><ul>
<li><a class="reference external" href="#cmake">CMake</a></li>
<li><a class="reference external" href="#layers">Layers</a></li>
<li><a class="reference external" href="#unit-tests">Unit Tests</a></li>
<li><a class="reference external" href="#python-api">Python API</a></li>
<li><a class="reference external" href="#benchmarking">Benchmarking</a></li>
</ul>
</li>
</ul>
</div>
<div class="section" id="overview">
<span id="overview"></span><h2>Overview<a class="headerlink" href="#overview" title="永久链接至标题"></a></h2>
<p>我们计划将 Intel® MKL 中引入的 GEMM Packed APIs[<a class="reference external" href="#references">1</a>] 集成到 PaddlePaddle 中,充分发挥英特尔平台的优势,有效提升PaddlePaddle在英特尔架构上的性能。
现阶段的优化主要针对 Recurrent Neural Network(以下简称RNN)相关层(包括<code class="docutils literal"><span class="pre">RecurrentLayer</span></code>, <code class="docutils literal"><span class="pre">GatedRecurrentLayer</span></code><code class="docutils literal"><span class="pre">LstmLayer</span></code>), 以及 PaddlePaddle V1 API。</p>
</div>
<div class="section" id="key-points">
<span id="key-points"></span><h2>Key Points<a class="headerlink" href="#key-points" title="永久链接至标题"></a></h2>
<div class="section" id="background">
<span id="background"></span><h3>Background<a class="headerlink" href="#background" title="永久链接至标题"></a></h3>
<p>目前PaddlePaddle采用了 Intel® MKL库的<a class="reference external" href="https://software.intel.com/en-us/mkl-developer-reference-c-cblas-gemm">cblas_?gemm</a>函数,这个函数本身会在计算前将原数据转换为更适合英特尔平台的内部格式。</p>
<ol class="simple">
<li>转换耗时 这一数据格式的转换操作(Packing),在问题本身的计算量比较小的时候,显得相对来说较为耗时。例如在DeepSpeech2 [<a class="reference external" href="#references">2</a>] 的Vanilla RNN部分中,矩阵大小是<code class="docutils literal"><span class="pre">batch_size</span> <span class="pre">*</span> <span class="pre">2048</span></code></li>
<li>转换冗余 由于在现有的某些情况下(例如RNN),多次调用 cblas_?gemm 会使用相同的原数据,因此,每次调用时对原数据的重复Packing便成为了冗余。</li>
</ol>
<p>为了最大程度减少多次调用 cblas_?gemm 在Packing上的耗时,Intel® MKL 引入了以下四个API:</p>
<ul class="simple">
<li>cblas_?gemm_alloc</li>
<li>cblas_?gemm_pack</li>
<li>cblas_?gemm_compute</li>
<li>cblas_?gemm_free</li>
</ul>
<p>通过使用这些API,我们可以先完成对原数据的Packing操作,再把已转换为Packed格式的数据传递给那些复用同一数据的gemm_compute函数,从而避免了Packing冗余。</p>
</div>
<div class="section" id="solution">
<span id="solution"></span><h3>Solution<a class="headerlink" href="#solution" title="永久链接至标题"></a></h3>
<p>在RNN的情况下,同一次前向、后向(forward/backward)过程中所有时间步(time step)共享同一个权重(weight)。当只做推断(inference)时,各次前向之间也都使用了相同的权重,没有必要在每次前向中每个时间步的计算时对权重进行重复的Packing操作。</p>
<p>我们通过使用新引入的GEMM Packed APIs,在层初始化的时候,先完成对权重的Packing操作,然后在前向,后向时复用已经转换过的权重,并在每次权重更新后,对新的权重进行转换用于下次迭代。</p>
<ul class="simple">
<li>优化前,对于序列长度(sequence length)为<code class="docutils literal"><span class="pre">T</span></code>的网络模型(model), <code class="docutils literal"><span class="pre">N</span></code>次迭代执行的转换次数为:<ul>
<li><code class="docutils literal"><span class="pre">inference</span></code><code class="docutils literal"><span class="pre">N</span> <span class="pre">*</span> <span class="pre">T</span></code></li>
<li><code class="docutils literal"><span class="pre">training</span></code><code class="docutils literal"><span class="pre">2</span> <span class="pre">*</span> <span class="pre">N</span> <span class="pre">*</span> <span class="pre">T</span></code></li>
</ul>
</li>
<li>优化后,对于同样设置的网络模型,其转换次数减少至:<ul>
<li><code class="docutils literal"><span class="pre">inference</span></code><code class="docutils literal"><span class="pre">1</span></code></li>
<li><code class="docutils literal"><span class="pre">training</span></code><code class="docutils literal"><span class="pre">2</span> <span class="pre">*</span> <span class="pre">N</span></code></li>
</ul>
</li>
</ul>
</div>
</div>
<div class="section" id="actions">
<span id="actions"></span><h2>Actions<a class="headerlink" href="#actions" title="永久链接至标题"></a></h2>
<p>添加的相关文件和目录结构如下:</p>
<div class="highlight-txt"><div class="highlight"><pre><span></span>PaddlePaddle/Paddle
├── ...
└── paddle/
├── ...
└── gserver/
├── ...
├── layers/
│ ├── ...
│ ├── MKLPackedRecurrentLayer.*
| ├── MKLPackedGatedRecurrentLayer.*
| ├── MKLPackedLstmLayer.*
| └── MKLPackedGemm.h
└── tests/
├── ...
└── test_MKLPacked.cpp
</pre></div>
</div>
<div class="section" id="cmake">
<span id="cmake"></span><h3>CMake<a class="headerlink" href="#cmake" title="永久链接至标题"></a></h3>
<p>在对应的<code class="docutils literal"><span class="pre">CMakeLists.txt</span></code>中根据<code class="docutils literal"><span class="pre">WITH_MKL</span></code>是否打开,来决定是否开启MKL Packed相关功能。</p>
</div>
<div class="section" id="layers">
<span id="layers"></span><h3>Layers<a class="headerlink" href="#layers" title="永久链接至标题"></a></h3>
<p>所有的<code class="docutils literal"><span class="pre">MKLPacked*Layer</span></code>都继承于PaddlePaddle的基类<code class="docutils literal"><span class="pre">Layer</span></code>, 并添加头文件 <code class="docutils literal"><span class="pre">MKLPackedGemm.h</span></code>,该文件对相关GEMM Packed APIs做了封装。</p>
</div>
<div class="section" id="unit-tests">
<span id="unit-tests"></span><h3>Unit Tests<a class="headerlink" href="#unit-tests" title="永久链接至标题"></a></h3>
<p>我们会添加<code class="docutils literal"><span class="pre">test_MKLPacked.cpp</span></code>用于MKL Packed优化后layer的测试。
对于每一个新加的RNN layer,我们会对比如下2个方面:</p>
<ol class="simple">
<li>对比优化后layer自身,sequence mode(<code class="docutils literal"><span class="pre">rnn_use_batch=false</span></code>)与batch mode(<code class="docutils literal"><span class="pre">rnn_use_batch=true</span></code>)的结果。</li>
<li>对比优化后layer与相对应的PaddlePaddle原有layer, 在batch mode下的结果。</li>
</ol>
</div>
<div class="section" id="python-api">
<span id="python-api"></span><h3>Python API<a class="headerlink" href="#python-api" title="永久链接至标题"></a></h3>
<p>TBD</p>
</div>
<div class="section" id="benchmarking">
<span id="benchmarking"></span><h3>Benchmarking<a class="headerlink" href="#benchmarking" title="永久链接至标题"></a></h3>
<p>会添加相应的脚本用于测试和对比在使用MKL Packed recurrent layers 前后的网络性能。</p>
</div>
</div>
<div class="section" id="references">
<span id="references"></span><h2>References<a class="headerlink" href="#references" title="永久链接至标题"></a></h2>
<div class="toctree-wrapper compound">
<ul>
<li class="toctree-l1"><a class="reference external" href="https://software.intel.com/en-us/articles/introducing-the-new-packed-apis-for-gemm">Introducing the new Packed APIs for GEMM</a></li>
<li class="toctree-l1"><a class="reference external" href="https://github.com/PaddlePaddle/DeepSpeech#deepspeech2-on-paddlepaddle">DeepSpeech2 on PaddlePaddle</a></li>
</ul>
</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
<!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>Intel® MKL-DNN on PaddlePaddle: Design Doc &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="../../howto/index_cn.html">进阶指南</a></li>
<li class="toctree-l1"><a class="reference internal" href="../../api/index_cn.html">API</a></li>
<li class="toctree-l1"><a class="reference internal" href="../../faq/index_cn.html">FAQ</a></li>
<li class="toctree-l1"><a class="reference internal" href="../../mobile/index_cn.html">MOBILE</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/build_and_install/index_cn.html">安装与编译</a><ul>
<li class="toctree-l3"><a class="reference internal" href="../../getstarted/build_and_install/pip_install_cn.html">使用pip安装</a></li>
<li class="toctree-l3"><a class="reference internal" href="../../getstarted/build_and_install/docker_install_cn.html">使用Docker安装运行</a></li>
<li class="toctree-l3"><a class="reference internal" href="../../howto/dev/build_cn.html">用Docker编译和测试PaddlePaddle</a></li>
<li class="toctree-l3"><a class="reference internal" href="../../getstarted/build_and_install/build_from_source_cn.html">从源码编译</a></li>
</ul>
</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="../../howto/index_cn.html">进阶指南</a><ul>
<li class="toctree-l2"><a class="reference internal" href="../../howto/usage/cmd_parameter/index_cn.html">设置命令行参数</a><ul>
<li class="toctree-l3"><a class="reference internal" href="../../howto/usage/cmd_parameter/use_case_cn.html">使用案例</a></li>
<li class="toctree-l3"><a class="reference internal" href="../../howto/usage/cmd_parameter/arguments_cn.html">参数概述</a></li>
<li class="toctree-l3"><a class="reference internal" href="../../howto/usage/cmd_parameter/detail_introduction_cn.html">细节描述</a></li>
</ul>
</li>
<li class="toctree-l2"><a class="reference internal" href="../../howto/usage/cluster/cluster_train_cn.html">PaddlePaddle分布式训练</a></li>
<li class="toctree-l2"><a class="reference internal" href="../../howto/usage/k8s/k8s_basis_cn.html">Kubernetes 简介</a></li>
<li class="toctree-l2"><a class="reference internal" href="../../howto/usage/k8s/k8s_cn.html">Kubernetes单机训练</a></li>
<li class="toctree-l2"><a class="reference internal" href="../../howto/usage/k8s/k8s_distributed_cn.html">Kubernetes分布式训练</a></li>
<li class="toctree-l2"><a class="reference internal" href="../../howto/dev/contribute_to_paddle_cn.html">如何贡献代码</a></li>
<li class="toctree-l2"><a class="reference internal" href="../../howto/dev/write_docs_cn.html">如何贡献/修改文档</a></li>
<li class="toctree-l2"><a class="reference internal" href="../../howto/deep_model/rnn/index_cn.html">RNN相关模型</a><ul>
<li class="toctree-l3"><a class="reference internal" href="../../howto/deep_model/rnn/rnn_config_cn.html">RNN配置</a></li>
<li class="toctree-l3"><a class="reference internal" href="../../howto/deep_model/rnn/recurrent_group_cn.html">Recurrent Group教程</a></li>
<li class="toctree-l3"><a class="reference internal" href="../../howto/deep_model/rnn/hierarchical_layer_cn.html">支持双层序列作为输入的Layer</a></li>
<li class="toctree-l3"><a class="reference internal" href="../../howto/deep_model/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="../../api/index_cn.html">API</a><ul>
<li class="toctree-l2"><a class="reference internal" href="../../api/v2/model_configs.html">模型配置</a><ul>
<li class="toctree-l3"><a class="reference internal" href="../../api/v2/config/activation.html">Activation</a></li>
<li class="toctree-l3"><a class="reference internal" href="../../api/v2/config/layer.html">Layers</a></li>
<li class="toctree-l3"><a class="reference internal" href="../../api/v2/config/evaluators.html">Evaluators</a></li>
<li class="toctree-l3"><a class="reference internal" href="../../api/v2/config/optimizer.html">Optimizer</a></li>
<li class="toctree-l3"><a class="reference internal" href="../../api/v2/config/pooling.html">Pooling</a></li>
<li class="toctree-l3"><a class="reference internal" href="../../api/v2/config/networks.html">Networks</a></li>
<li class="toctree-l3"><a class="reference internal" href="../../api/v2/config/attr.html">Parameter Attribute</a></li>
</ul>
</li>
<li class="toctree-l2"><a class="reference internal" href="../../api/v2/data.html">数据访问</a><ul>
<li class="toctree-l3"><a class="reference internal" href="../../api/v2/data/data_reader.html">Data Reader Interface</a></li>
<li class="toctree-l3"><a class="reference internal" href="../../api/v2/data/image.html">Image Interface</a></li>
<li class="toctree-l3"><a class="reference internal" href="../../api/v2/data/dataset.html">Dataset</a></li>
</ul>
</li>
<li class="toctree-l2"><a class="reference internal" href="../../api/v2/run_logic.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>
<li class="toctree-l1"><a class="reference internal" href="../../mobile/index_cn.html">MOBILE</a><ul>
<li class="toctree-l2"><a class="reference internal" href="../../mobile/cross_compiling_for_android_cn.html">Android平台编译指南</a></li>
<li class="toctree-l2"><a class="reference internal" href="../../mobile/cross_compiling_for_ios_cn.html">iOS平台编译指南</a></li>
<li class="toctree-l2"><a class="reference internal" href="../../mobile/cross_compiling_for_raspberry_cn.html">Raspberry Pi平台编译指南</a></li>
</ul>
</li>
</ul>
</nav>
<section class="doc-content-wrap">
<div role="navigation" aria-label="breadcrumbs navigation">
<ul class="wy-breadcrumbs">
<li>Intel® MKL-DNN on PaddlePaddle: Design Doc</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="intel-mkl-dnn-on-paddlepaddle-design-doc">
<span id="intel-mkl-dnn-on-paddlepaddle-design-doc"></span><h1>Intel® MKL-DNN on PaddlePaddle: Design Doc<a class="headerlink" href="#intel-mkl-dnn-on-paddlepaddle-design-doc" title="永久链接至标题"></a></h1>
<p>我们计划将英特尔深度神经网络数学库<a class="reference external" href="https://github.com/01org/mkl-dnn">Intel MKL-DNN</a>
(Intel Math Kernel Library for Deep Neural Networks)集成到PaddlePaddle,
充分展现英特尔平台的优势,有效提升PaddlePaddle在英特尔架构上的性能。</p>
<div align="center">
<img src="image/overview.png"><br/>
Figure 1. PaddlePaddle on IA
</div><p>近期目标</p>
<ul class="simple">
<li>完成常用Layer的MKL-DNN实现。</li>
<li>完成常见深度神经网络VGG,GoogLeNet 和 ResNet的MKL-DNN实现。</li>
</ul>
<p>目前的优化,主要针对PaddlePaddle在重构之前的代码框架以及V1的API。
具体的完成状态可以参见<a class="reference external" href="https://github.com/PaddlePaddle/Paddle/projects/21">这里</a></p>
<div class="section" id="contents">
<span id="contents"></span><h2>Contents<a class="headerlink" href="#contents" title="永久链接至标题"></a></h2>
<ul class="simple">
<li><a class="reference external" href="#overview">Overview</a></li>
<li><a class="reference external" href="#actions">Actions</a><ul>
<li><a class="reference external" href="#cmake">CMake</a></li>
<li><a class="reference external" href="#matrix">Matrix</a></li>
<li><a class="reference external" href="#layers">Layers</a></li>
<li><a class="reference external" href="#activations">Activations</a></li>
<li><a class="reference external" href="#parameters">Parameters</a></li>
<li><a class="reference external" href="#gradients">Gradients</a></li>
<li><a class="reference external" href="#unit-tests">Unit Tests</a></li>
<li><a class="reference external" href="#python-api">Python API</a></li>
<li><a class="reference external" href="#benchmarking">Benchmarking</a></li>
<li><a class="reference external" href="#others">Others</a></li>
</ul>
</li>
<li><a class="reference external" href="#design-concerns">Design Concerns</a></li>
</ul>
</div>
<div class="section" id="overview">
<span id="overview"></span><h2>Overview<a class="headerlink" href="#overview" title="永久链接至标题"></a></h2>
<p>我们会把MKL-DNN会作为第三方库集成进PaddlePaddle,与其他第三方库一样,会在编译PaddlePaddle的时候下载并编译MKL-DNN。</p>
<p>同时,为了进一步提升PaddlePaddle在基本数学运算的计算速度,我们也将MKLML即(MKL small library[<a class="reference external" href="#references">1</a>])
作为另一个第三方库集成进PaddlePaddle,它只会包括生成好的动态库和头文件。</p>
<p>MKL,MKLML以及MKL-DNN三者关系如下表:</p>
<p>| Name | Open Source | License | Descriptions |
| :&#8212;&#8212;&#8212;- | :&#8212;&#8212;&#8212;&#8212;&#8212; | :&#8212;&#8212;&#8212;- | :&#8212;&#8212;&#8212;&#8212; |
| MKL | No | Proprietary | Accelerate math processing routines |
| MKLML | No | Proprietary | Small package of MKL, especially for Machine Learning |
| MKL-DNN | Yes | Apache 2.0 | Accelerate primitives processing routines especially for Deep Neural Networks |</p>
<p>MKLML可以与MKL-DNN共同使用,以此达到最好的性能。</p>
<div align="center">
<img src="image/engine.png"><br/>
Figure 2. PaddlePaddle with MKL Engines
</div></div>
<div class="section" id="actions">
<span id="actions"></span><h2>Actions<a class="headerlink" href="#actions" title="永久链接至标题"></a></h2>
<p>添加的相关文件和目录结构如下:</p>
<div class="highlight-txt"><div class="highlight"><pre><span></span>PaddlePaddle/Paddle
├── ...
├── cmake/
│ ├── external/
│ │ ├── ...
│ │ ├── mkldnn.cmake
│ │ └── mklml.cmake
└── paddle/
├── ...
├── math/
│ ├── ...
│ └── MKLDNNMatrix.*
└── gserver/
├── ...
├── layers/
│ ├── ...
│ └── MKLDNN*Layer.*
├── activations/
│ ├── ...
│ └── MKLDNNActivations.*
└── tests/
├── ...
├── MKLDNNTester.*
└── test_MKLDNN.cpp
</pre></div>
</div>
<div class="section" id="cmake">
<span id="cmake"></span><h3>CMake<a class="headerlink" href="#cmake" title="永久链接至标题"></a></h3>
<p><code class="docutils literal"><span class="pre">CMakeLists.txt</span></code>中提供一个与MKL有关的总开关:<code class="docutils literal"><span class="pre">WITH_MKL</span></code>,它负责决定编译时是否使用MKLML和MKL-DNN</p>
<ul class="simple">
<li><code class="docutils literal"><span class="pre">WITH_MKLML</span></code> 控制是否使用MKLML库。
当打开<code class="docutils literal"><span class="pre">WITH_MKL</span></code>时,会自动使用MKLML库作为PaddlePaddle的CBLAS和LAPACK库,同时会开启Intel OpenMP用于提高MKLML的性能。
编译时会把对应的头文件和库放在<code class="docutils literal"><span class="pre">build/third_party/install/mklml/*</span></code>目录下对应的地方。
MKLML的库目前都是动态库,主要包括<code class="docutils literal"><span class="pre">libiomp5.so</span></code><code class="docutils literal"><span class="pre">libmklml_intel.so</span></code></li>
<li><code class="docutils literal"><span class="pre">WITH_MKLDNN</span></code> 控制是否使用MKL-DNN。
当开启<code class="docutils literal"><span class="pre">WITH_MKL</span></code>时,会自动根据硬件配置[<a class="reference external" href="#references">2</a>]选择是否编译MKL-DNN。
编译时会把对应的头文件和库放在<code class="docutils literal"><span class="pre">build/third_party/install/mkldnn/*</span></code>目录下对应的地方。
MKL-DNN的库目前只有动态库<code class="docutils literal"><span class="pre">libmkldnn.so</span></code></li>
</ul>
</div>
<div class="section" id="matrix">
<span id="matrix"></span><h3>Matrix<a class="headerlink" href="#matrix" title="永久链接至标题"></a></h3>
<p>目前在PaddlePaddle中数据都是以<code class="docutils literal"><span class="pre">NCHW</span></code>的格式存储,但是在MKL-DNN中的排列方式不止这一种。
所以我们定义了一个<code class="docutils literal"><span class="pre">MKLDNNMatrix</span></code>用于管理MKL-DNN数据的不同格式以及相互之间的转换。</p>
<div align="center">
<img src="image/matrix.png"><br/>
Figure 3. MKLDNNMatrix
</div></div>
<div class="section" id="layers">
<span id="layers"></span><h3>Layers<a class="headerlink" href="#layers" title="永久链接至标题"></a></h3>
<p>所有MKL-DNN的Layers都会继承于<code class="docutils literal"><span class="pre">MKLDNNLayer</span></code>,该类继承于PaddlePaddle的基类<code class="docutils literal"><span class="pre">Layer</span></code>
<code class="docutils literal"><span class="pre">MKLDNNLayer</span></code>中会提供一些必要的接口和函数,并且会写好<code class="docutils literal"><span class="pre">forward</span></code><code class="docutils literal"><span class="pre">backward</span></code>的基本逻辑,
子类只需要使用定义好的接口,实现具体的函数功能即可。</p>
<div align="center">
<img src="image/layers.png"><br/>
Figure 4. MKLDNNLayer
</div><p>每个MKLDNNLayer都包含用于内部存储和外部存储的一系列MKLDNNMatrix:</p>
<ul class="simple">
<li>内部存储(internel memory):<code class="docutils literal"><span class="pre">inVal_</span></code>,<code class="docutils literal"><span class="pre">inGrad_</span></code>,<code class="docutils literal"><span class="pre">outVal_</span></code><code class="docutils literal"><span class="pre">outGrad_</span></code>,分别代表输入数据,输入梯度,输出数据和输出梯度。</li>
<li>外部存储(external memory):都是以ext开头,比如<code class="docutils literal"><span class="pre">extInVal_</span></code><code class="docutils literal"><span class="pre">extInGrad_</span></code>,它们主要是用于,
当数据格式与PaddlePaddle默认的<code class="docutils literal"><span class="pre">NCHW</span></code>格式不匹配时,转换内存的工作。
需要注意的是,PaddlePaddle的activation会直接使用<code class="docutils literal"><span class="pre">output_.value</span></code><code class="docutils literal"><span class="pre">output_.grad</span></code>
所以<code class="docutils literal"><span class="pre">extOutVal_</span></code><code class="docutils literal"><span class="pre">extOutGrad_</span></code>必须分别与<code class="docutils literal"><span class="pre">output_.value</span></code><code class="docutils literal"><span class="pre">output_.grad</span></code>共享内存,
如果不需要外部存储用于转换,那么对应的内部存储也会与它们共享内存。</li>
<li>转换函数(resetXXX): 包括<code class="docutils literal"><span class="pre">resetInValue</span></code><code class="docutils literal"><span class="pre">resetInGrad</span></code><code class="docutils literal"><span class="pre">resetOutValue</span></code><code class="docutils literal"><span class="pre">resetOutGrad</span></code>
表示对输入数据,输入梯度,输出数据和输出梯度的转换。
这些函数会根据输入参数重新设置内部和外部存储,当然这两者也可以相等,即表示不需要转换。</li>
</ul>
<p>注意:每个<code class="docutils literal"><span class="pre">MKLDNNlayer</span></code>的子类只需要使用内部存储就可以了,所有外部的转换工作都会在reset系列函数中都准备好。</p>
</div>
<div class="section" id="activations">
<span id="activations"></span><h3>Activations<a class="headerlink" href="#activations" title="永久链接至标题"></a></h3>
<p>在重构前的PaddlePaddle中,激活函数是独立于<code class="docutils literal"><span class="pre">Layer</span></code>的概念,并且输入输出都是共用一块内存,
所以添加了对应的<code class="docutils literal"><span class="pre">MKLDNNActivation</span></code>来实现,方式类似于<code class="docutils literal"><span class="pre">MKLDNNLayer</span></code></p>
</div>
<div class="section" id="parameters">
<span id="parameters"></span><h3>Parameters<a class="headerlink" href="#parameters" title="永久链接至标题"></a></h3>
<p>对于有参数的层,我们会保证<code class="docutils literal"><span class="pre">MKLDNNLayer</span></code>使用的参数与PaddlePaddle申请的buffer共用一块内存。
如果存在数据排列格式不一样的情况时,我们会在网络训练之前把格式转换为MKL-DNN希望的格式,
在训练结束的时候再保存为PaddlePaddle的格式,但是整个训练过程中不需要任何转换。
这样既使得最终保存的参数格式与PaddlePaddle一致,又可以避免不必要的转换。</p>
</div>
<div class="section" id="gradients">
<span id="gradients"></span><h3>Gradients<a class="headerlink" href="#gradients" title="永久链接至标题"></a></h3>
<p>由于MKL-DNN的操作都是直接覆盖的形式,也就是说输出的结果不会在原来的数据上累加,
这样带来的好处就是不需要一直清空memory,节省了不必要的操作。
但是注意的是,当网络出现分支且在<code class="docutils literal"><span class="pre">backward</span></code>的时候,需要累加不同Layer传过来的梯度。
所以在<code class="docutils literal"><span class="pre">MKLDNNlayer</span></code>中实现了一个merge的方法,此时每个小分支的<code class="docutils literal"><span class="pre">Input</span> <span class="pre">Gradient</span></code>
会先临时保存在<code class="docutils literal"><span class="pre">MKLDNNMatrix</span></code>中,由分支处的Layer负责求和,并把结果放到当前层的<code class="docutils literal"><span class="pre">output_.grad</span></code>中。
所以整体上,在实现每个子类的时候就不需要关心分支的事情了。</p>
<div align="center">
<img src="image/gradients.png"><br/>
Figure 5. Merge Gradients
</div></div>
<div class="section" id="unit-tests">
<span id="unit-tests"></span><h3>Unit Tests<a class="headerlink" href="#unit-tests" title="永久链接至标题"></a></h3>
<p>我们会添加<code class="docutils literal"><span class="pre">test_MKLDNN.cpp</span></code><code class="docutils literal"><span class="pre">MKLDNNTester.*</span></code>用于MKL-DNN的测试。
测试分为每个Layer(或Activation)的单元测试和简单网络的整体测试。
每个测试会对比PaddlePaddle中CPU算出的结果与MKL-DNN的结果,小于某个比较小的阈值认为通过。</p>
</div>
<div class="section" id="python-api">
<span id="python-api"></span><h3>Python API<a class="headerlink" href="#python-api" title="永久链接至标题"></a></h3>
<p>目前只考虑<strong>v1 API</strong></p>
<p>计划在<code class="docutils literal"><span class="pre">python/paddle/trainer/config_parser.py</span></code>里面添加<code class="docutils literal"><span class="pre">use_mkldnn</span></code>这个选择,方便用户选择使用MKL-DNN的layers。</p>
<p>具体实现方式比如:</p>
<div class="highlight-python"><div class="highlight"><pre><span></span><span class="n">use_mkldnn</span> <span class="o">=</span> <span class="nb">bool</span><span class="p">(</span><span class="nb">int</span><span class="p">(</span><span class="n">g_command_config_args</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="s2">&quot;use_mkldnn&quot;</span><span class="p">,</span> <span class="mi">0</span><span class="p">)))</span>
<span class="k">if</span> <span class="n">use_mkldnn</span>
<span class="bp">self</span><span class="o">.</span><span class="n">layer_type</span> <span class="o">=</span> <span class="n">mkldnn_</span><span class="o">*</span>
</pre></div>
</div>
<p>所有MKL-DNN的<code class="docutils literal"><span class="pre">layer_type</span></code>会以*mkldnn_*开头,这些会在<code class="docutils literal"><span class="pre">MKLDNN*Layer</span></code>注册layer的时候保证,以示区分。</p>
<p>同时,会在<code class="docutils literal"><span class="pre">paddle/utils.Flags</span></code>中添加一个<code class="docutils literal"><span class="pre">use_mkldnn</span></code>的flag,用于选择是否使用MKL-DNN的相关功能。</p>
</div>
<div class="section" id="benchmarking">
<span id="benchmarking"></span><h3>Benchmarking<a class="headerlink" href="#benchmarking" title="永久链接至标题"></a></h3>
<p>会添加相应的脚本在<a class="reference external" href="https://github.com/PaddlePaddle/Paddle/tree/develop/benchmark/paddle/image">这里</a>,用于测试和对比在使用MKL-DNN前后的CNN网络性能。
测试的性能对比结果会在<a class="reference external" href="https://github.com/PaddlePaddle/Paddle/blob/develop/benchmark/IntelOptimizedPaddle.md">IntelOptimizedPaddle.md</a></p>
</div>
<div class="section" id="others">
<span id="others"></span><h3>Others<a class="headerlink" href="#others" title="永久链接至标题"></a></h3>
<ol class="simple">
<li>如果在使用MKL-DNN的情况下,会把CPU的Buffer对齐为4096,具体可以参考MKL-DNN中的<a class="reference external" href="https://github.com/01org/mkl-dnn/blob/master/include/mkldnn.hpp#L673">memory</a></li>
<li>深入PaddlePaddle,寻找有没有其他可以优化的可能,进一步优化。比如可能会用OpenMP改进SGD的更新性能。</li>
</ol>
</div>
</div>
<div class="section" id="design-concerns">
<span id="design-concerns"></span><h2>Design Concerns<a class="headerlink" href="#design-concerns" title="永久链接至标题"></a></h2>
<p>为了更好的符合PaddlePaddle的代码风格[<a class="reference external" href="#references">3</a>],同时又尽可能少的牺牲MKL-DNN的性能[<a class="reference external" href="#references">4</a>]。</p>
<p>我们总结出一些特别需要注意的点:</p>
<ol class="simple">
<li>使用**deviceId_**。为了尽可能少的在父类Layer中添加变量或者函数,
我们决定使用已有的<code class="docutils literal"><span class="pre">deviceId_</span></code>变量来区分layer的属性,定义<code class="docutils literal"><span class="pre">-2</span></code><code class="docutils literal"><span class="pre">MKLDNNLayer</span></code>特有的设备ID。</li>
<li>重写父类Layer的<strong>init</strong>函数,修改<code class="docutils literal"><span class="pre">deviceId_</span></code><code class="docutils literal"><span class="pre">-2</span></code>,代表这个layer是用于跑在MKL-DNN的环境下。</li>
<li>创建<code class="docutils literal"><span class="pre">MKLDNNBase</span></code>,定义一些除了layer和memory相关的类和函数。
包括MKL-DNN会用到<code class="docutils literal"><span class="pre">MKLDNNStream</span></code><code class="docutils literal"><span class="pre">CPUEngine</span></code>,和未来可能还会用到<code class="docutils literal"><span class="pre">FPGAEngine</span></code>等。</li>
<li>如果MKL-DNN layer的后面接有cpu device,那么就会使<code class="docutils literal"><span class="pre">output_.value</span></code><code class="docutils literal"><span class="pre">extOutVal_</span></code>共享内存,
同时数据格式就是<code class="docutils literal"><span class="pre">NCHW</span></code>,这样下一个cpu device就能拿到正确的数据。
在有普通的CPU layer时, <code class="docutils literal"><span class="pre">extOutVal_</span></code><code class="docutils literal"><span class="pre">extOutGrad_</span></code>的格式始终是<code class="docutils literal"><span class="pre">NCHW</span></code>或者<code class="docutils literal"><span class="pre">NC</span></code></li>
</ol>
</div>
<div class="section" id="references">
<span id="references"></span><h2>References<a class="headerlink" href="#references" title="永久链接至标题"></a></h2>
<ol class="simple">
<li><a class="reference external" href="https://github.com/01org/mkl-dnn#linking-your-application">MKL small library</a><a class="reference external" href="https://software.intel.com/en-us/mkl">Intel MKL</a>的一个子集。
主要包括了深度学习相关的数学原语与操作,一般由MKL-DNN在发布<a class="reference external" href="https://github.com/01org/mkl-dnn/releases">新版本</a>时一起更新。</li>
<li><a class="reference external" href="https://github.com/01org/mkl-dnn#system-requirements">MKL-DNN System Requirements</a>
目前在PaddlePaddle中,仅会在支持AVX2指令集及以上的机器才使用MKL-DNN。</li>
<li><a class="reference external" href="https://github.com/PaddlePaddle/Paddle/pull/3096">原来的方案</a>会引入<strong>nextLayer</strong>的信息。
但是在PaddlePaddle中,无论是重构前的layer还是重构后的op,都不会想要知道next layer/op的信息。</li>
<li>MKL-DNN的高性能格式与PaddlePaddle原有的<code class="docutils literal"><span class="pre">NCHW</span></code>不同(PaddlePaddle中的cuDNN部分使用的也是<code class="docutils literal"><span class="pre">NCHW</span></code>,所以不存在这个问题)。
所以需要引入一个转换方法,并且只需要在必要的时候转换这种格式,才能更好的发挥MKL-DNN的性能。</li>
</ol>
</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.
先完成此消息的编辑!
想要评论请 注册