Skip to content
体验新版
项目
组织
正在加载...
登录
切换导航
打开侧边栏
BaiXuePrincess
Paddle
提交
d6bdc463
P
Paddle
项目概览
BaiXuePrincess
/
Paddle
与 Fork 源项目一致
Fork自
PaddlePaddle / Paddle
通知
1
Star
1
Fork
0
代码
文件
提交
分支
Tags
贡献者
分支图
Diff
Issue
0
列表
看板
标记
里程碑
合并请求
0
Wiki
0
Wiki
分析
仓库
DevOps
项目成员
Pages
P
Paddle
项目概览
项目概览
详情
发布
仓库
仓库
文件
提交
分支
标签
贡献者
分支图
比较
Issue
0
Issue
0
列表
看板
标记
里程碑
合并请求
0
合并请求
0
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,18 +23,16 @@
- `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
因为 它太大了无法显示 source diff 。你可以改为
查看blob
。
编辑
预览
Markdown
is supported
0%
请重试
或
添加新附件
.
添加附件
取消
You are about to add
0
people
to the discussion. Proceed with caution.
先完成此消息的编辑!
取消
想要评论请
注册
或
登录