Skip to content
体验新版
项目
组织
正在加载...
登录
切换导航
打开侧边栏
PaddlePaddle
PaddleDetection
提交
d924a658
P
PaddleDetection
项目概览
PaddlePaddle
/
PaddleDetection
1 年多 前同步成功
通知
696
Star
11112
Fork
2696
代码
文件
提交
分支
Tags
贡献者
分支图
Diff
Issue
184
列表
看板
标记
里程碑
合并请求
40
Wiki
0
Wiki
分析
仓库
DevOps
项目成员
Pages
P
PaddleDetection
项目概览
项目概览
详情
发布
仓库
仓库
文件
提交
分支
标签
贡献者
分支图
比较
Issue
184
Issue
184
列表
看板
标记
里程碑
合并请求
40
合并请求
40
Pages
分析
分析
仓库分析
DevOps
Wiki
0
Wiki
成员
成员
收起侧边栏
关闭侧边栏
动态
分支图
创建新Issue
提交
Issue看板
提交
d924a658
编写于
9月 06, 2017
作者:
Q
QI JUN
提交者:
GitHub
9月 06, 2017
浏览文件
操作
浏览文件
下载
差异文件
Merge pull request #3750 from QiJune/add_eigen_user_doc
add how to use eigen cn doc
上级
7002e69b
beafabc7
变更
2
隐藏空白更改
内联
并排
Showing
2 changed file
with
152 addition
and
1 deletion
+152
-1
doc/howto/dev/new_op_cn.md
doc/howto/dev/new_op_cn.md
+6
-1
doc/howto/dev/use_eigen_cn.md
doc/howto/dev/use_eigen_cn.md
+146
-0
未找到文件。
doc/howto/dev/new_op_cn.md
浏览文件 @
d924a658
...
...
@@ -169,6 +169,8 @@ class MulKernel : public framework::OpKernel {
`MulKernel`
需要重写
`Compute`
接口,该接口参数为
`const framework::ExecutionContext& context`
,
`ExecutionContext`
相比
`InferShapeContext`
增加了设备类型,同样可获取到输入输出和属性参数,
`Compute`
函数里写具体实现时。
注意,不同设备(CPU、GPU)共享一个Op定义,是否则共享同一个
`OpKernel`
,取决于
`Compute`
调用的函数是否支持不同设备。
`MulOp`
的CPU、GPU实现共享同一个
`Kernel`
,
`OpKernel`
不共享的例子可以参考
[
`OnehotCrossEntropyOpKernel`
](
https://github.com/PaddlePaddle/Paddle/blob/develop/paddle/operators/cross_entropy_op.h#L43
)
。
为了使得
`OpKernel`
的计算过程书写较为简单,CPU、GPU的代码可以复用,我们通常借助Eigen unsupported Tensor模块来实现。关于在paddle中如何使用Eigen库,请参考对应的使用
[
文档
](
https://github.com/PaddlePaddle/Paddle/blob/develop/doc/howto/dev/use_eigen_cn.md
)
到此前向Op实现完成,需要在
`.cc`
文件中注册该op和kernel。反向Op类的定义和Kernel定义与前向Op类似,这里不再重复。但注意,反向Op没有
`ProtoMaker`
。
...
...
@@ -188,9 +190,12 @@ REGISTER_OP_CPU_KERNEL(mul_grad,
-
`REGISTER_OP_WITHOUT_GRADIENT`
: 用于注册没有反向的Op。
-
`REGISTER_OP_CPU_KERNEL`
:注册
`ops::MulKernel`
类,并特化模板参数为
`paddle::platform::CPUPlace`
和
`float`
类型,同理,注册
`ops::MulKernel`
类。
在
`.cu`
文件中注册GPU Kernel。
在
`.cu`
文件中注册GPU Kernel。
请注意,如果GPU Kernel的实现是基于Eigen unsupported模块,那么在
`.cu`
的最前面请加上宏定义
`#define EIGEN_USE_GPU`
```
c++
// if use Eigen unsupported module before include head files
#define EIGEN_USE_GPU
namespace
ops
=
paddle
::
operators
;
REGISTER_OP_GPU_KERNEL
(
mul
,
ops
::
MulKernel
<
paddle
::
platform
::
GPUPlace
,
float
>
);
REGISTER_OP_GPU_KERNEL
(
mul_grad
,
...
...
doc/howto/dev/use_eigen_cn.md
0 → 100644
浏览文件 @
d924a658
## 在Paddle中如何使用Eigen
神经网络本质上是一个计算图,计算需要的数据存放在
`Tensor`
中,而计算过程是由
`Operartor`
来描述的。在执行时,
`Operator`
调用对应
`OpKernel`
中的
`Compute`
接口,实现对
`Tensor`
的操作。
### Eigen Tensor模块
Eigen Tensor模块对element-wise计算提供了强大的支持,并且书写一份代码,可以同时在CPU、GPU执行。但Eigen Tensor是一个正在开发中的模块,因此可能测试不够完备,文档较少。
关于Eigen Tensor模块的详细介绍请参考
[
文档1
](
https://github.com/RLovelett/eigen/blob/master/unsupported/Eigen/CXX11/src/Tensor/README.md
)
和
[
文档2
](
https://bitbucket.org/eigen/eigen/src/default/unsupported/Eigen/CXX11/src/Tensor/README.md
)
### paddle::framework::Tensor
Paddle Tensor定义在framework目录下,其主要接口如下:
```
cpp
class
Tensor
{
public:
/*! Return a pointer to mutable memory block. */
template
<
typename
T
>
inline
T
*
data
();
/**
* @brief Return a pointer to mutable memory block.
* @note If not exist, then allocation.
*/
template
<
typename
T
>
inline
T
*
mutable_data
(
platform
::
Place
place
);
/**
* @brief Return a pointer to mutable memory block.
*
* @param[in] dims The dimensions of the memory block.
* @param[in] place The place of the memory block.
*
* @note If not exist, then allocation.
*/
template
<
typename
T
>
inline
T
*
mutable_data
(
DDim
dims
,
platform
::
Place
place
);
/*! Resize the dimensions of the memory block. */
inline
Tensor
&
Resize
(
const
DDim
&
dims
);
/*! Return the dimensions of the memory block. */
inline
const
DDim
&
dims
()
const
;
private:
/*! holds the memory block if allocated. */
std
::
shared_ptr
<
Placeholder
>
holder_
;
/*! points to dimensions of memory block. */
DDim
dim_
;
};
```
`Placeholder`
的作用是延迟分配内存,即我们可以先定义一个Tensor,然后使用Resize接口设置Tensor的大小,最后再调用mutable_data接口分配实际的内存。
```
cpp
paddle
::
framework
::
Tensor
t
;
paddle
::
platform
::
CPUPlace
place
;
// set size first
t
.
Resize
({
2
,
3
});
// allocate memory on CPU later
t
.
mutable_data
(
place
);
```
### paddle::framework::Tensor使用样例
下面以AddOp为例说明Tensor的使用过程:
-
InferShape
在运行神经网络计算图时,我们先调用每个
`Operator`
的
`InferShape`
接口,根据输入Tensor的大小来设置输出Tensor的大小,
`Resize`
接口会被调用。
```
cpp
void
InferShape
(
const
framework
::
InferShapeContext
&
ctx
)
const
override
{
PADDLE_ENFORCE_EQ
(
ctx
.
Input
<
Tensor
>
(
"X"
)
->
dims
(),
ctx
.
Input
<
Tensor
>
(
"Y"
)
->
dims
(),
"Two input of Add Op's dimension must be same."
);
ctx
.
Output
<
Tensor
>
(
"Out"
)
->
Resize
(
ctx
.
Input
<
Tensor
>
(
"X"
)
->
dims
());
}
```
-
Run
`Operator`
的
`Run`
接口最终会调用对应
`OpKernel`
的
`Compute`
接口,在这时真正的分配内存,
`mutable_data`
接口会被调用。
```
cpp
void
Compute
(
const
framework
::
ExecutionContext
&
context
)
const
override
{
auto
*
input0
=
context
.
Input
<
Tensor
>
(
"X"
);
auto
*
input1
=
context
.
Input
<
Tensor
>
(
"Y"
);
auto
*
output
=
context
.
Output
<
Tensor
>
(
"Out"
);
output
->
mutable_data
<
T
>
(
context
.
GetPlace
());
auto
x
=
EigenVector
<
T
>::
Flatten
(
*
input0
);
auto
y
=
EigenVector
<
T
>::
Flatten
(
*
input1
);
auto
z
=
EigenVector
<
T
>::
Flatten
(
*
output
);
auto
place
=
context
.
GetEigenDevice
<
Place
>
();
z
.
device
(
place
)
=
x
+
y
;
}
```
### paddle::framework::Tensor到EigenTensor的转换
如上一小节所示,在具体的计算中,我们需要先把输入Tensor和输出Tensor转换为Eigen支持的格式。我们在
[
eigen.h
](
https://github.com/PaddlePaddle/Paddle/blob/develop/paddle/framework/eigen.h
)
中提供了一些全局函数用来实现paddle::framework::Tensor到EigenTensor/EigenMatrix/EigenVector/EigenScalar的转换。
以EigenTensor为例,做一个介绍
```
cpp
Tensor
t
;
float
*
p
=
t
.
mutable_data
<
float
>
(
make_ddim
({
1
,
2
,
3
}),
platform
::
CPUPlace
());
for
(
int
i
=
0
;
i
<
1
*
2
*
3
;
i
++
)
{
p
[
i
]
=
static_cast
<
float
>
(
i
);
}
EigenTensor
<
float
,
3
>::
Type
et
=
EigenTensor
<
float
,
3
>::
From
(
t
);
```
From是EigenTensor模板提供的一个接口,可以实现从paddle::framework::Tensor到对EigenTensor的转换。由于Tensor的rank是模板参数,因此在转换时需要显示的指定。
在Eigen中,不同rank的Tensor是不同类型,Vector是rank为1的Tensor。需要额外注意的是,EigenVector
<T>
::From方法是把paddle中的一维Tensor转为Eigen的一维Tensor,在这里用EigenVector来表示;而EigenVector
<T>
::Flatten方法是把paddle中的一个Tensor进行reshape操作,压扁成为Eigen的一维Tensor,类型仍然为EigenVector。
更多的转换方法请参考eigen_test.cc中的
[
单元测试
](
https://github.com/PaddlePaddle/Paddle/blob/develop/paddle/framework/eigen_test.cc
)
。
### 实现计算
当需要完成计算时,我们需要等式左边的EigenTensor调用device接口。在这里需要注意的是,这里的EigenTensor之间的运算只是改变了原有Tensor中的数据,而不会改变原有Tensor的shape信息。
```
cpp
auto
x
=
EigenVector
<
T
>::
Flatten
(
*
input0
);
auto
y
=
EigenVector
<
T
>::
Flatten
(
*
input1
);
auto
z
=
EigenVector
<
T
>::
Flatten
(
*
output
);
auto
place
=
context
.
GetEigenDevice
<
Place
>
();
z
.
device
(
place
)
=
x
+
y
;
```
在这段代码中,input0/input1/output可以是任意维度的Tensor。我们调用了EigenVector的Flatten接口,把任意维度的Tensor转为了一维的EigenVector。而在计算结束之后,input0/input1/output的原有shape信息不变。如果想改变原有Tensor的shape信息,可以调用Resize接口进行改变。
由于Eigen Tensor模块的文档较少,我们可以参考TensorFlow的
[
kernels
](
https://github.com/tensorflow/tensorflow/tree/master/tensorflow/core/kernels
)
模块下的相关
`OpKernel`
的计算代码。
编辑
预览
Markdown
is supported
0%
请重试
或
添加新附件
.
添加附件
取消
You are about to add
0
people
to the discussion. Proceed with caution.
先完成此消息的编辑!
取消
想要评论请
注册
或
登录