Skip to content
体验新版
项目
组织
正在加载...
登录
切换导航
打开侧边栏
PaddlePaddle
Paddle
提交
d78521d4
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看板
提交
d78521d4
编写于
8月 27, 2017
作者:
Q
qingqing01
浏览文件
操作
浏览文件
下载
电子邮件补丁
差异文件
fix doc format.
上级
f646f799
变更
1
隐藏空白更改
内联
并排
Showing
1 changed file
with
80 addition
and
80 deletion
+80
-80
doc/howto/dev/new_op_cn.md
doc/howto/dev/new_op_cn.md
+80
-80
未找到文件。
doc/howto/dev/new_op_cn.md
浏览文件 @
d78521d4
...
@@ -4,11 +4,13 @@
...
@@ -4,11 +4,13 @@
-
[
实现C++类
](
#实现C++类
)
-
[
实现C++类
](
#实现C++类
)
-
[
定义ProtoMaker类
](
#定义ProtoMaker类
)
-
[
定义ProtoMaker类
](
#定义ProtoMaker类
)
-
[
定义Operator类
](
#定义Operator类
)
-
[
定义Operator类
](
#定义Operator类
)
-
[
定义
`OpKernel`类
](
#定义`OpKernel`
类
)
-
[
定义
OpKernel类
](
#定义OpKernel
类
)
-
[
注册类
](
#注册类
)
-
[
注册类
](
#注册类
)
-
[
编译
](
#编译
)
-
[
编译
](
#编译
)
-
[
绑定Python
](
#绑定Python
)
-
[
绑定Python
](
#绑定Python
)
-
[
实现单元测试
](
#实现单元测试
)
-
[
实现单元测试
](
#实现单元测试
)
-
[
前向Operator单测
](
#前向Operator单测
)
-
[
反向Operator单测
](
#反向Operator单测
)
## 概念简介
## 概念简介
...
@@ -41,25 +43,23 @@ Forward Op需要包含:
...
@@ -41,25 +43,23 @@ Forward Op需要包含:
### 1. 定义ProtoMaker类
### 1. 定义ProtoMaker类
矩阵乘的公式:$$Out = X
*
Y$$ ,可见该计算由两个输入,一个输出组成。首先定义
`ProtoMaker`
来描述该Op的输入、输出及注释:
矩阵乘的公式:$Out = X
*
Y$, 可见该计算由两个输入,一个输出组成。首先定义
`ProtoMaker`
来描述该Op的输入、输出及注释:
```
```
class MulOpMaker : public framework::OpProtoAndCheckerMaker {
class MulOpMaker : public framework::OpProtoAndCheckerMaker {
public:
public:
MulOpMaker(framework::OpProto *proto, framework::OpAttrChecker *op_checker)
MulOpMaker(framework::OpProto *proto, framework::OpAttrChecker *op_checker)
: OpProtoAndCheckerMaker(proto, op_checker) {
: OpProtoAndCheckerMaker(proto, op_checker) {
AddInput("X", "The first input of mul op");
AddInput("X", "The first input of mul op");
AddInput("Y", "The second input of mul op");
AddInput("Y", "The second input of mul op");
AddOutput("Out", "The output of mul op");
AddOutput("Out", "The output of mul op");
AddComment(R"DOC(
AddComment(R"DOC(
Two Element Mul Operator.
Two Element Mul Operator.
The equation is: Out = X * Y
The equation is: Out = X * Y
)DOC");
)DOC");
}
}
};
};
```
```
[
`MulOpMaker`
](
https://github.com/PaddlePaddle/Paddle/blob/develop/paddle/operators/mul_op.cc#L43
)
继承自
`framework::OpProtoAndCheckerMaker`
,构造函数包括2个:
[
`MulOpMaker`
](
https://github.com/PaddlePaddle/Paddle/blob/develop/paddle/operators/mul_op.cc#L43
)
继承自
`framework::OpProtoAndCheckerMaker`
,构造函数包括2个:
...
@@ -73,8 +73,8 @@ Forward Op需要包含:
...
@@ -73,8 +73,8 @@ Forward Op需要包含:
再举个
[
`ScaleOp`
](
https://github.com/PaddlePaddle/Paddle/blob/develop/paddle/operators/scale_op.cc#L37
)
的例子:
再举个
[
`ScaleOp`
](
https://github.com/PaddlePaddle/Paddle/blob/develop/paddle/operators/scale_op.cc#L37
)
的例子:
```
C++
```
template <typename AttrType>
template <typename AttrType>
class ScaleOpMaker : public framework::OpProtoAndCheckerMaker {
class ScaleOpMaker : public framework::OpProtoAndCheckerMaker {
public:
public:
ScaleOpMaker(framework::OpProto *proto, framework::OpAttrChecker *op_checker)
ScaleOpMaker(framework::OpProto *proto, framework::OpAttrChecker *op_checker)
...
@@ -98,42 +98,42 @@ The equation is: Out = scale*X
...
@@ -98,42 +98,42 @@ The equation is: Out = scale*X
### 2. 定义Operator类
### 2. 定义Operator类
```C
++
```
c
++
class MulOp : public framework::OperatorWithKernel {
class
MulOp
:
public
framework
::
OperatorWithKernel
{
public:
public:
using framework::OperatorWithKernel::OperatorWithKernel;
using
framework
::
OperatorWithKernel
::
OperatorWithKernel
;
protected:
protected:
void InferShape(const framework::InferShapeContext &ctx) const override {
void
InferShape
(
const
framework
::
InferShapeContext
&
ctx
)
const
override
{
auto dim0 = ctx.Input<Tensor>("X")->dims();
auto
dim0
=
ctx
.
Input
<
Tensor
>
(
"X"
)
->
dims
();
auto dim1 = ctx.Input<Tensor>("Y")->dims();
auto
dim1
=
ctx
.
Input
<
Tensor
>
(
"Y"
)
->
dims
();
PADDLE_ENFORCE_EQ(dim0.size(), 2,
PADDLE_ENFORCE_EQ
(
dim0
.
size
(),
2
,
"input X(%s) should be a tensor with 2 dims, a matrix",
"input X(%s) should be a tensor with 2 dims, a matrix"
,
ctx.op_.Input("X"));
ctx
.
op_
.
Input
(
"X"
));
PADDLE_ENFORCE_EQ(dim1.size(), 2,
PADDLE_ENFORCE_EQ
(
dim1
.
size
(),
2
,
"input Y(%s) should be a tensor with 2 dims, a matrix",
"input Y(%s) should be a tensor with 2 dims, a matrix"
,
ctx.op_.Input("Y"));
ctx
.
op_
.
Input
(
"Y"
));
PADDLE_ENFORCE_EQ(
PADDLE_ENFORCE_EQ
(
dim0[1], dim1[0],
dim0
[
1
],
dim1
[
0
],
"First matrix's width must be equal with second matrix's height.");
"First matrix's width must be equal with second matrix's height."
);
ctx.Output<Tensor>("Out")->Resize({dim0[0], dim1[1]});
ctx
.
Output
<
Tensor
>
(
"Out"
)
->
Resize
({
dim0
[
0
],
dim1
[
1
]});
}
}
};
};
```
```
[
`MulOp`
](
https://github.com/PaddlePaddle/Paddle/blob/develop/paddle/operators/mul_op.cc#L22
)
继承自
`OperatorWithKernel`
。
`public`
成员:
[
`MulOp`
](
https://github.com/PaddlePaddle/Paddle/blob/develop/paddle/operators/mul_op.cc#L22
)
继承自
`OperatorWithKernel`
。
`public`
成员:
```
C
++
```
c
++
using
framework
::
OperatorWithKernel
::
OperatorWithKernel
;
using
framework
::
OperatorWithKernel
::
OperatorWithKernel
;
```
```
这句表示使用基类
`OperatorWithKernel`
的构造函数,也可写成:
这句表示使用基类
`OperatorWithKernel`
的构造函数,也可写成:
```
C
++
```
c
++
MulOp(const std::string &type, const framework::VariableNameMap &inputs,
MulOp
(
const
std
::
string
&
type
,
const
framework
::
VariableNameMap
&
inputs
,
const framework::VariableNameMap &outputs,
const
framework
::
VariableNameMap
&
outputs
,
const framework::AttributeMap &attrs)
const
framework
::
AttributeMap
&
attrs
)
: OperatorWithKernel(type, inputs, outputs, attrs) {}
:
OperatorWithKernel
(
type
,
inputs
,
outputs
,
attrs
)
{}
```
```
还需要重写
`InferShape`
接口。
`InferShape`
为const函数,不能修改Op的成员变量,参数为
`const framework::InferShapeContext &ctx`
,通过该参数可获取到输入输出以及属性。它的功能是:
还需要重写
`InferShape`
接口。
`InferShape`
为const函数,不能修改Op的成员变量,参数为
`const framework::InferShapeContext &ctx`
,通过该参数可获取到输入输出以及属性。它的功能是:
...
@@ -142,7 +142,7 @@ using framework::OperatorWithKernel::OperatorWithKernel;
...
@@ -142,7 +142,7 @@ using framework::OperatorWithKernel::OperatorWithKernel;
通常
`OpProtoMaker`
和
`Op`
类的定义写在
`.cc`
文件中,和要讲到的注册函数一起放在
`.cc`
中
通常
`OpProtoMaker`
和
`Op`
类的定义写在
`.cc`
文件中,和要讲到的注册函数一起放在
`.cc`
中
### 3. 定义
`OpKernel`
类
### 3. 定义
OpKernel
类
```
C++
```
C++
template <typename Place, typename T>
template <typename Place, typename T>
...
@@ -176,13 +176,13 @@ class MulKernel : public framework::OpKernel {
...
@@ -176,13 +176,13 @@ class MulKernel : public framework::OpKernel {
在
`.cc`
文件中注册前向、反向Op类,注册CPU Kernel。
在
`.cc`
文件中注册前向、反向Op类,注册CPU Kernel。
```C
++
```
c
++
namespace ops = paddle::operators;
namespace
ops
=
paddle
::
operators
;
REGISTER_OP(mul, ops::MulOp, ops::MulOpMaker, mul_grad, ops::MulOpGrad);
REGISTER_OP
(
mul
,
ops
::
MulOp
,
ops
::
MulOpMaker
,
mul_grad
,
ops
::
MulOpGrad
);
REGISTER_OP_CPU_KERNEL(mul, ops::MulKernel<paddle::platform::CPUPlace, float>);
REGISTER_OP_CPU_KERNEL
(
mul
,
ops
::
MulKernel
<
paddle
::
platform
::
CPUPlace
,
float
>
);
REGISTER_OP_CPU_KERNEL(mul_grad,
REGISTER_OP_CPU_KERNEL
(
mul_grad
,
ops::MulGradKernel<paddle::platform::CPUPlace, float>);
ops
::
MulGradKernel
<
paddle
::
platform
::
CPUPlace
,
float
>
);
```
```
-
`REGISTER_OP`
: 注册
`ops::MulOp`
类,类型名为
`mul`
,该类的
`ProtoMaker`
为
`ops::MulOpMaker`
,注册
`ops::MulOpGrad`
,类型名为
`mul_grad`
,
-
`REGISTER_OP`
: 注册
`ops::MulOp`
类,类型名为
`mul`
,该类的
`ProtoMaker`
为
`ops::MulOpMaker`
,注册
`ops::MulOpGrad`
,类型名为
`mul_grad`
,
-
`REGISTER_OP_WITHOUT_GRADIENT`
: 用于注册没有反向的Op。
-
`REGISTER_OP_WITHOUT_GRADIENT`
: 用于注册没有反向的Op。
...
@@ -190,32 +190,32 @@ class MulKernel : public framework::OpKernel {
...
@@ -190,32 +190,32 @@ class MulKernel : public framework::OpKernel {
在
`.cu`
文件中注册GPU Kernel。
在
`.cu`
文件中注册GPU Kernel。
```
```
c++
namespace ops = paddle::operators;
namespace
ops
=
paddle
::
operators
;
REGISTER_OP_GPU_KERNEL(mul, ops::MulKernel<paddle::platform::GPUPlace, float>);
REGISTER_OP_GPU_KERNEL
(
mul
,
ops
::
MulKernel
<
paddle
::
platform
::
GPUPlace
,
float
>
);
REGISTER_OP_GPU_KERNEL(mul_grad,
REGISTER_OP_GPU_KERNEL
(
mul_grad
,
ops::MulGradKernel<paddle::platform::GPUPlace, float>);
ops
::
MulGradKernel
<
paddle
::
platform
::
GPUPlace
,
float
>
);
```
```
### 5. 编译
### 5. 编译
在
[
paddle/operators/CMakeLists.txt
](
https://github.com/PaddlePaddle/Paddle/blob/develop/paddle/operators/CMakeLists.txt
)
文件中添加编译。
在
[
paddle/operators/CMakeLists.txt
](
https://github.com/PaddlePaddle/Paddle/blob/develop/paddle/operators/CMakeLists.txt
)
文件中添加编译。
```
```
op_library(mul_op SRCS mul_op.cc mul_op.cu DEPS math_function)
op_library(mul_op SRCS mul_op.cc mul_op.cu DEPS math_function)
```
```
下面命令可以编译:
下面命令可以编译:
```
```
make mul_op
make mul_op
```
```
## 绑定Python
## 绑定Python
-
绑定Python
-
绑定Python
在
[
`paddle/pybind/pybind.cc
在
[
`paddle/pybind/pybind.cc
`
](
https://github.com/PaddlePaddle/Paddle/blob/develop/paddle/pybind/pybind.cc
)
文件中添加该类:
`
](
https://github.com/PaddlePaddle/Paddle/blob/develop/paddle/pybind/pybind.cc
)
文件中添加该类:
```
```
...
@@ -232,23 +232,23 @@ class MulKernel : public framework::OpKernel {
...
@@ -232,23 +232,23 @@ class MulKernel : public framework::OpKernel {
-
生成库
-
生成库
在
[
`paddle/pybind/CMakeLists.txt`
](
https://github.com/PaddlePaddle/Paddle/blob/develop/paddle/pybind/CMakeLists.txt
)
文件添加类到
`DEPS`
中。
在
[
`paddle/pybind/CMakeLists.txt`
](
https://github.com/PaddlePaddle/Paddle/blob/develop/paddle/pybind/CMakeLists.txt
)
文件添加类到
`DEPS`
中
,使得该Op可以链接到生成的lib库中
。
```
```
if(WITH_PYTHON)
if(WITH_PYTHON)
cc_library(paddle_pybind SHARED
cc_library(paddle_pybind SHARED
SRCS pybind.cc
SRCS pybind.cc
DEPS pybind python backward
DEPS pybind python backward
mul_op
mul_op
minus_op)
minus_op)
endif(WITH_PYTHON)
endif(WITH_PYTHON)
```
```
## 实现单元测试
## 实现单元测试
单测包括对比前向Op不同设备(CPU、GPU)的实现、对比反向OP不同设备(CPU、GPU)的实现、反向Op的梯度测试。下面介绍介绍
[
`MulOp`的单测
](
https://github.com/PaddlePaddle/Paddle/blob/develop/python/paddle/v2/framework/tests/test_mul_op.py
)
。
单测包括对比前向Op不同设备(CPU、GPU)的实现、对比反向OP不同设备(CPU、GPU)的实现、反向Op的梯度测试。下面介绍介绍
[
`MulOp`的单测
](
https://github.com/PaddlePaddle/Paddle/blob/develop/python/paddle/v2/framework/tests/test_mul_op.py
)
。
-
前向Op
单测
### 前向Operator
单测
前向Op单测继承自
`unittest.TestCase`
,并定义元类
`__metaclass__ = OpTestMeta`
,具体单测流程在
`OpTestMeta`
里完成。需在
`setUp`
函数定义输入输出和属性参数,以及Python对比的输出值。
前向Op单测继承自
`unittest.TestCase`
,并定义元类
`__metaclass__ = OpTestMeta`
,具体单测流程在
`OpTestMeta`
里完成。需在
`setUp`
函数定义输入输出和属性参数,以及Python对比的输出值。
...
@@ -276,7 +276,7 @@ class TestMulOp(unittest.TestCase):
...
@@ -276,7 +276,7 @@ class TestMulOp(unittest.TestCase):
-
`self.outputs`
: 定义输出,并得到Python结算结果。
-
`self.outputs`
: 定义输出,并得到Python结算结果。
-
反向Op
单测
### 反向Operator
单测
反向Op单测继承自
`GradientChecker`
,而
`GradientChecker`
集成自
`unittest.TestCase`
,所以反向单测函数需要
`test_`
开头。
反向Op单测继承自
`GradientChecker`
,而
`GradientChecker`
集成自
`unittest.TestCase`
,所以反向单测函数需要
`test_`
开头。
...
...
编辑
预览
Markdown
is supported
0%
请重试
或
添加新附件
.
添加附件
取消
You are about to add
0
people
to the discussion. Proceed with caution.
先完成此消息的编辑!
取消
想要评论请
注册
或
登录