Skip to content
体验新版
项目
组织
正在加载...
登录
切换导航
打开侧边栏
机器未来
Paddle
提交
d78521d4
P
Paddle
项目概览
机器未来
/
Paddle
与 Fork 源项目一致
Fork自
PaddlePaddle / Paddle
通知
1
Star
1
Fork
0
代码
文件
提交
分支
Tags
贡献者
分支图
Diff
Issue
1
列表
看板
标记
里程碑
合并请求
0
Wiki
0
Wiki
分析
仓库
DevOps
项目成员
Pages
P
Paddle
项目概览
项目概览
详情
发布
仓库
仓库
文件
提交
分支
标签
贡献者
分支图
比较
Issue
1
Issue
1
列表
看板
标记
里程碑
合并请求
0
合并请求
0
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.
先完成此消息的编辑!
取消
想要评论请
注册
或
登录