Skip to content
体验新版
项目
组织
正在加载...
登录
切换导航
打开侧边栏
PaddlePaddle
Paddle
提交
d6bdc463
P
Paddle
项目概览
PaddlePaddle
/
Paddle
1 年多 前同步成功
通知
2302
Star
20931
Fork
5422
代码
文件
提交
分支
Tags
贡献者
分支图
Diff
Issue
1423
列表
看板
标记
里程碑
合并请求
543
Wiki
0
Wiki
分析
仓库
DevOps
项目成员
Pages
P
Paddle
项目概览
项目概览
详情
发布
仓库
仓库
文件
提交
分支
标签
贡献者
分支图
比较
Issue
1,423
Issue
1,423
列表
看板
标记
里程碑
合并请求
543
合并请求
543
Pages
分析
分析
仓库分析
DevOps
Wiki
0
Wiki
成员
成员
收起侧边栏
关闭侧边栏
动态
分支图
创建新Issue
提交
Issue看板
提交
d6bdc463
编写于
8月 29, 2017
作者:
T
Travis CI
浏览文件
操作
浏览文件
下载
电子邮件补丁
差异文件
Deploy to GitHub Pages:
58419e7c
上级
f37be38d
变更
3
展开全部
隐藏空白更改
内联
并排
Showing
3 changed file
with
77 addition
and
36 deletion
+77
-36
develop/doc_cn/_sources/howto/dev/new_op_cn.md.txt
develop/doc_cn/_sources/howto/dev/new_op_cn.md.txt
+40
-16
develop/doc_cn/howto/dev/new_op_cn.html
develop/doc_cn/howto/dev/new_op_cn.html
+36
-19
develop/doc_cn/searchindex.js
develop/doc_cn/searchindex.js
+1
-1
未找到文件。
develop/doc_cn/_sources/howto/dev/new_op_cn.md.txt
浏览文件 @
d6bdc463
...
...
@@ -5,12 +5,13 @@
- [定义ProtoMaker类](#定义ProtoMaker类)
- [定义Operator类](#定义Operator类)
- [定义OpKernel类](#定义OpKernel类)
- [注册
类](#注册类
)
- [注册
Operator](#注册Operator
)
- [编译](#编译)
- [绑定Python](#绑定Python)
- [实现单元测试](#实现单元测试)
- [前向Operator单测](#前向Operator单测)
- [反向Operator单测](#反向Operator单测)
- [编译和执行](#编译和执行)
## 概念简介
...
...
@@ -22,19 +23,17 @@
- `framework::OperatorWithKernel`:继承自OperatorBase,Op有计算函数,称作有Kernel。
- `class OpProtoAndCheckerMaker`:描述该Op的输入、输出、属性、注释,主要用于Python API接口生成
依据是否包含kernel,将Op分为两种:包含Kernel的Op和不包含kernel的Op,前者Op的定义继承自`OperatorBase`,后者继承自`OperatorWithKernel`。本教程主要介绍带Kernel的Op如何写,简单总结如下:
依据是否包含kernel,将Op分为两种:包含Kernel的Op和不包含kernel的Op,前者Op的定义继承自`OperatorBase`,后者继承自`OperatorWithKernel`。本教程主要介绍带Kernel的Op如何写,简单总结
Op需要包含的内容
如下:
Forward Op需要包含:
- OpProtoMake定义
- Op定义
- Kernel实现
内容 | 定义位置
-------------- | :----------------------
OpProtoMake定义 | `.cc`文件,Backward Op不需要定义OpProtoMake
Op定义 | `.cc`文件
Kernel实现 | CPU、GPU共享Kernel在`.h`文件,否则,CPU可以在`.cc`文件,GPU可在`.cu`文件。
注册Op | Op注册在`.cc`文件;Kernel注册CPU在`.cc`文件,GPU在`.cu`文件
与之对应的Backward Op包含:
- Op定义
- Kernel实现
下面以矩阵乘操作,即[MulOp](https://github.com/PaddlePaddle/Paddle/blob/develop/paddle/operators/mul_op.cc)为例来介绍如何写带Kernel的Operator。
...
...
@@ -137,8 +136,9 @@ MulOp(const std::string &type, const framework::VariableNameMap &inputs,
```
还需要重写`InferShape`接口。`InferShape`为const函数,不能修改Op的成员变量,参数为`const framework::InferShapeContext &ctx`,通过该参数可获取到输入输出以及属性。它的功能是:
- 1). 做检查, 尽早报错:检查输入数据维度、类型等是否合法
- 2). 设置输出Tensor的形状
- 1). 做检查, 尽早报错:检查输入数据维度、类型等是否合法。
- 2). 设置输出Tensor的形状。
通常`OpProtoMaker`和`Op`类的定义写在`.cc`文件中,和要讲到的注册函数一起放在`.cc`中
...
...
@@ -172,7 +172,7 @@ class MulKernel : public framework::OpKernel {
到此前向Op实现完成,需要在`.cc`文件中注册该op和kernel。反向Op类的定义和Kernel定义与前向Op类似,这里不再重复。但注意,反向Op没有`ProtoMaker`。
### 4. 注册
类
### 4. 注册
Operator
在`.cc`文件中注册前向、反向Op类,注册CPU Kernel。
...
...
@@ -297,4 +297,28 @@ class TestMulOp(unittest.TestCase):
- 调用`create_op("mul")`创建反向Op对应的前向Op。
- 定义输入`inputs`。
- 调用`compare_grad`函数对比CPU、GPU计算结果。
- 调用`check_grad`检查梯度稳定性。
- 调用`check_grad`检查梯度稳定性,这里采用数值法检测梯度正确性。
- 第一个参数`op` : 前向op。
- 第二个参数`inputs` : 输入词典,词典的Key和`ProtoMaker`定义保持一致。
- 第三个参数`set(["X", "Y"])` : 指定对输入变量`X`、`Y`做梯度检测。
- 第四个参数`"Out"` : 指定前向网络最终的输出目标变量`Out`
### 编译和执行
单测完成之后,在[`python/paddle/v2/framework/tests/CMakeLists.txt`](https://github.com/PaddlePaddle/Paddle/blob/develop/python/paddle/v2/framework/tests/CMakeLists.txt)里添加编译:
```
py_test(test_mul_op SRCS test_mul_op.py)
```
编译时需要打开`WITH_TESTING`, 即 `cmake paddle_dir -DWITH_TESTING=ON`,编译成功之后执行单测命令为:
```
make test ARGS="-R test_mul_op -V"
```
或者:
```
ctest -R test_mul_op
```
develop/doc_cn/howto/dev/new_op_cn.html
浏览文件 @
d6bdc463
...
...
@@ -193,7 +193,7 @@
<li><a
class=
"reference external"
href=
"#定义ProtoMaker类"
>
定义ProtoMaker类
</a></li>
<li><a
class=
"reference external"
href=
"#定义Operator类"
>
定义Operator类
</a></li>
<li><a
class=
"reference external"
href=
"#定义OpKernel类"
>
定义OpKernel类
</a></li>
<li><a
class=
"reference external"
href=
"#注册
类"
>
注册类
</a></li>
<li><a
class=
"reference external"
href=
"#注册
Operator"
>
注册Operator
</a></li>
<li><a
class=
"reference external"
href=
"#编译"
>
编译
</a></li>
</ul>
</li>
...
...
@@ -201,6 +201,7 @@
<li><a
class=
"reference external"
href=
"#实现单元测试"
>
实现单元测试
</a><ul>
<li><a
class=
"reference external"
href=
"#前向Operator单测"
>
前向Operator单测
</a></li>
<li><a
class=
"reference external"
href=
"#反向Operator单测"
>
反向Operator单测
</a></li>
<li><a
class=
"reference external"
href=
"#编译和执行"
>
编译和执行
</a></li>
</ul>
</li>
</ul>
...
...
@@ -213,18 +214,11 @@
<li><code
class=
"docutils literal"
><span
class=
"pre"
>
framework::OperatorWithKernel
</span></code>
:继承自OperatorBase,Op有计算函数,称作有Kernel。
</li>
<li><code
class=
"docutils literal"
><span
class=
"pre"
>
class
</span>
<span
class=
"pre"
>
OpProtoAndCheckerMaker
</span></code>
:描述该Op的输入、输出、属性、注释,主要用于Python API接口生成
</li>
</ul>
<p>
依据是否包含kernel,将Op分为两种:包含Kernel的Op和不包含kernel的Op,前者Op的定义继承自
<code
class=
"docutils literal"
><span
class=
"pre"
>
OperatorBase
</span></code>
,后者继承自
<code
class=
"docutils literal"
><span
class=
"pre"
>
OperatorWithKernel
</span></code>
。本教程主要介绍带Kernel的Op如何写,简单总结如下:
</p>
<p>
Forward Op需要包含:
</p>
<ul
class=
"simple"
>
<li>
OpProtoMake定义
</li>
<li>
Op定义
</li>
<li>
Kernel实现
</li>
</ul>
<p>
与之对应的Backward Op包含:
</p>
<ul
class=
"simple"
>
<li>
Op定义
</li>
<li>
Kernel实现
</li>
</ul>
<p>
依据是否包含kernel,将Op分为两种:包含Kernel的Op和不包含kernel的Op,前者Op的定义继承自
<code
class=
"docutils literal"
><span
class=
"pre"
>
OperatorBase
</span></code>
,后者继承自
<code
class=
"docutils literal"
><span
class=
"pre"
>
OperatorWithKernel
</span></code>
。本教程主要介绍带Kernel的Op如何写,简单总结Op需要包含的内容如下:
</p>
<p>
内容 | 定义位置
————–
| :
———————
-OpProtoMake定义 |
<code
class=
"docutils literal"
><span
class=
"pre"
>
.cc
</span></code>
文件,Backward Op不需要定义OpProtoMake
Op定义 |
<code
class=
"docutils literal"
><span
class=
"pre"
>
.cc
</span></code>
文件
Kernel实现 | CPU、GPU共享Kernel在
<code
class=
"docutils literal"
><span
class=
"pre"
>
.h
</span></code>
文件,否则,CPU可以在
<code
class=
"docutils literal"
><span
class=
"pre"
>
.cc
</span></code>
文件,GPU可在
<code
class=
"docutils literal"
><span
class=
"pre"
>
.cu
</span></code>
文件。
注册Op | Op注册在
<code
class=
"docutils literal"
><span
class=
"pre"
>
.cc
</span></code>
文件;Kernel注册CPU在
<code
class=
"docutils literal"
><span
class=
"pre"
>
.cc
</span></code>
文件,GPU在
<code
class=
"docutils literal"
><span
class=
"pre"
>
.cu
</span></code>
文件
</p>
<p>
下面以矩阵乘操作,即
<a
class=
"reference external"
href=
"https://github.com/PaddlePaddle/Paddle/blob/develop/paddle/operators/mul_op.cc"
>
MulOp
</a>
为例来介绍如何写带Kernel的Operator。
</p>
</div>
<div
class=
"section"
id=
"c"
>
...
...
@@ -311,9 +305,11 @@
<span
class=
"o"
>
:
</span>
<span
class=
"n"
>
OperatorWithKernel
</span><span
class=
"p"
>
(
</span><span
class=
"n"
>
type
</span><span
class=
"p"
>
,
</span>
<span
class=
"n"
>
inputs
</span><span
class=
"p"
>
,
</span>
<span
class=
"n"
>
outputs
</span><span
class=
"p"
>
,
</span>
<span
class=
"n"
>
attrs
</span><span
class=
"p"
>
)
</span>
<span
class=
"p"
>
{}
</span>
</pre></div>
</div>
<p>
还需要重写
<code
class=
"docutils literal"
><span
class=
"pre"
>
InferShape
</span></code>
接口。
<code
class=
"docutils literal"
><span
class=
"pre"
>
InferShape
</span></code>
为const函数,不能修改Op的成员变量,参数为
<code
class=
"docutils literal"
><span
class=
"pre"
>
const
</span>
<span
class=
"pre"
>
framework::InferShapeContext
</span>
<span
class=
"pre"
>
&
ctx
</span></code>
,通过该参数可获取到输入输出以及属性。它的功能是:
- 1). 做检查, 尽早报错:检查输入数据维度、类型等是否合法
- 2). 设置输出Tensor的形状
</p>
<p>
还需要重写
<code
class=
"docutils literal"
><span
class=
"pre"
>
InferShape
</span></code>
接口。
<code
class=
"docutils literal"
><span
class=
"pre"
>
InferShape
</span></code>
为const函数,不能修改Op的成员变量,参数为
<code
class=
"docutils literal"
><span
class=
"pre"
>
const
</span>
<span
class=
"pre"
>
framework::InferShapeContext
</span>
<span
class=
"pre"
>
&
ctx
</span></code>
,通过该参数可获取到输入输出以及属性。它的功能是:
</p>
<ul
class=
"simple"
>
<li>
1). 做检查, 尽早报错:检查输入数据维度、类型等是否合法。
</li>
<li>
2). 设置输出Tensor的形状。
</li>
</ul>
<p>
通常
<code
class=
"docutils literal"
><span
class=
"pre"
>
OpProtoMaker
</span></code>
和
<code
class=
"docutils literal"
><span
class=
"pre"
>
Op
</span></code>
类的定义写在
<code
class=
"docutils literal"
><span
class=
"pre"
>
.cc
</span></code>
文件中,和要讲到的注册函数一起放在
<code
class=
"docutils literal"
><span
class=
"pre"
>
.cc
</span></code>
中
</p>
</div>
<div
class=
"section"
id=
"opkernel"
>
...
...
@@ -342,8 +338,8 @@
<p>
注意,不同设备(CPU、GPU)共享一个Op定义,是否则共享同一个
<code
class=
"docutils literal"
><span
class=
"pre"
>
OpKernel
</span></code>
,取决于
<code
class=
"docutils literal"
><span
class=
"pre"
>
Compute
</span></code>
调用的函数是否支持不同设备。
<code
class=
"docutils literal"
><span
class=
"pre"
>
MulOp
</span></code>
的CPU、GPU实现共享同一个
<code
class=
"docutils literal"
><span
class=
"pre"
>
Kernel
</span></code>
,
<code
class=
"docutils literal"
><span
class=
"pre"
>
OpKernel
</span></code>
不共享的例子可以参考
<a
class=
"reference external"
href=
"https://github.com/PaddlePaddle/Paddle/blob/develop/paddle/operators/cross_entropy_op.h#L43"
><code
class=
"docutils literal"
><span
class=
"pre"
>
OnehotCrossEntropyOpKernel
</span></code></a>
。
</p>
<p>
到此前向Op实现完成,需要在
<code
class=
"docutils literal"
><span
class=
"pre"
>
.cc
</span></code>
文件中注册该op和kernel。反向Op类的定义和Kernel定义与前向Op类似,这里不再重复。但注意,反向Op没有
<code
class=
"docutils literal"
><span
class=
"pre"
>
ProtoMaker
</span></code>
。
</p>
</div>
<div
class=
"section"
id=
""
>
<span
id=
"id3"
></span><h3>
4. 注册
类
<a
class=
"headerlink"
href=
"#
"
title=
"永久链接至标题"
>
¶
</a></h3>
<div
class=
"section"
id=
"
operator
"
>
<span
id=
"id3"
></span><h3>
4. 注册
Operator
<a
class=
"headerlink"
href=
"#operator
"
title=
"永久链接至标题"
>
¶
</a></h3>
<p>
在
<code
class=
"docutils literal"
><span
class=
"pre"
>
.cc
</span></code>
文件中注册前向、反向Op类,注册CPU Kernel。
</p>
<div
class=
"highlight-c++"
><div
class=
"highlight"
><pre><span></span><span
class=
"k"
>
namespace
</span>
<span
class=
"n"
>
ops
</span>
<span
class=
"o"
>
=
</span>
<span
class=
"n"
>
paddle
</span><span
class=
"o"
>
::
</span><span
class=
"n"
>
operators
</span><span
class=
"p"
>
;
</span>
<span
class=
"n"
>
REGISTER_OP
</span><span
class=
"p"
>
(
</span><span
class=
"n"
>
mul
</span><span
class=
"p"
>
,
</span>
<span
class=
"n"
>
ops
</span><span
class=
"o"
>
::
</span><span
class=
"n"
>
MulOp
</span><span
class=
"p"
>
,
</span>
<span
class=
"n"
>
ops
</span><span
class=
"o"
>
::
</span><span
class=
"n"
>
MulOpMaker
</span><span
class=
"p"
>
,
</span>
<span
class=
"n"
>
mul_grad
</span><span
class=
"p"
>
,
</span>
<span
class=
"n"
>
ops
</span><span
class=
"o"
>
::
</span><span
class=
"n"
>
MulOpGrad
</span><span
class=
"p"
>
);
</span>
...
...
@@ -457,9 +453,30 @@
<li>
调用
<code
class=
"docutils literal"
><span
class=
"pre"
>
create_op(
"
mul
"
)
</span></code>
创建反向Op对应的前向Op。
</li>
<li>
定义输入
<code
class=
"docutils literal"
><span
class=
"pre"
>
inputs
</span></code>
。
</li>
<li>
调用
<code
class=
"docutils literal"
><span
class=
"pre"
>
compare_grad
</span></code>
函数对比CPU、GPU计算结果。
</li>
<li>
调用
<code
class=
"docutils literal"
><span
class=
"pre"
>
check_grad
</span></code>
检查梯度稳定性。
</li>
<li>
调用
<code
class=
"docutils literal"
><span
class=
"pre"
>
check_grad
</span></code>
检查梯度稳定性,这里采用数值法检测梯度正确性。
<ul>
<li>
第一个参数
<code
class=
"docutils literal"
><span
class=
"pre"
>
op
</span></code>
: 前向op。
</li>
<li>
第二个参数
<code
class=
"docutils literal"
><span
class=
"pre"
>
inputs
</span></code>
: 输入词典,词典的Key和
<code
class=
"docutils literal"
><span
class=
"pre"
>
ProtoMaker
</span></code>
定义保持一致。
</li>
<li>
第三个参数
<code
class=
"docutils literal"
><span
class=
"pre"
>
set([
"
X
"
,
</span>
<span
class=
"pre"
>
"
Y
"
])
</span></code>
: 指定对输入变量
<code
class=
"docutils literal"
><span
class=
"pre"
>
X
</span></code>
、
<code
class=
"docutils literal"
><span
class=
"pre"
>
Y
</span></code>
做梯度检测。
</li>
<li>
第四个参数
<code
class=
"docutils literal"
><span
class=
"pre"
>
"
Out
"
</span></code>
: 指定前向网络最终的输出目标变量
<code
class=
"docutils literal"
><span
class=
"pre"
>
Out
</span></code></li>
</ul>
</li>
</ul>
</div>
<div
class=
"section"
id=
""
>
<span
id=
"id8"
></span><h3>
编译和执行
<a
class=
"headerlink"
href=
"#"
title=
"永久链接至标题"
>
¶
</a></h3>
<p>
单测完成之后,在
<a
class=
"reference external"
href=
"https://github.com/PaddlePaddle/Paddle/blob/develop/python/paddle/v2/framework/tests/CMakeLists.txt"
><code
class=
"docutils literal"
><span
class=
"pre"
>
python/paddle/v2/framework/tests/CMakeLists.txt
</span></code></a>
里添加编译:
</p>
<div
class=
"highlight-default"
><div
class=
"highlight"
><pre><span></span><span
class=
"n"
>
py_test
</span><span
class=
"p"
>
(
</span><span
class=
"n"
>
test_mul_op
</span>
<span
class=
"n"
>
SRCS
</span>
<span
class=
"n"
>
test_mul_op
</span><span
class=
"o"
>
.
</span><span
class=
"n"
>
py
</span><span
class=
"p"
>
)
</span>
</pre></div>
</div>
<p>
编译时需要打开
<code
class=
"docutils literal"
><span
class=
"pre"
>
WITH_TESTING
</span></code>
, 即
<code
class=
"docutils literal"
><span
class=
"pre"
>
cmake
</span>
<span
class=
"pre"
>
paddle_dir
</span>
<span
class=
"pre"
>
-DWITH_TESTING=ON
</span></code>
,编译成功之后执行单测命令为:
</p>
<div
class=
"highlight-default"
><div
class=
"highlight"
><pre><span></span><span
class=
"n"
>
make
</span>
<span
class=
"n"
>
test
</span>
<span
class=
"n"
>
ARGS
</span><span
class=
"o"
>
=
</span><span
class=
"s2"
>
"
-R test_mul_op -V
"
</span>
</pre></div>
</div>
<p>
或者:
</p>
<div
class=
"highlight-default"
><div
class=
"highlight"
><pre><span></span><span
class=
"n"
>
ctest
</span>
<span
class=
"o"
>
-
</span><span
class=
"n"
>
R
</span>
<span
class=
"n"
>
test_mul_op
</span>
</pre></div>
</div>
</div>
</div>
</div>
...
...
develop/doc_cn/searchindex.js
浏览文件 @
d6bdc463
此差异已折叠。
点击以展开。
编辑
预览
Markdown
is supported
0%
请重试
或
添加新附件
.
添加附件
取消
You are about to add
0
people
to the discussion. Proceed with caution.
先完成此消息的编辑!
取消
想要评论请
注册
或
登录