Skip to content
体验新版
项目
组织
正在加载...
登录
切换导航
打开侧边栏
PaddlePaddle
FluidDoc
提交
0885b4ba
F
FluidDoc
项目概览
PaddlePaddle
/
FluidDoc
通知
5
Star
2
Fork
0
代码
文件
提交
分支
Tags
贡献者
分支图
Diff
Issue
23
列表
看板
标记
里程碑
合并请求
111
Wiki
0
Wiki
分析
仓库
DevOps
项目成员
Pages
F
FluidDoc
项目概览
项目概览
详情
发布
仓库
仓库
文件
提交
分支
标签
贡献者
分支图
比较
Issue
23
Issue
23
列表
看板
标记
里程碑
合并请求
111
合并请求
111
Pages
分析
分析
仓库分析
DevOps
Wiki
0
Wiki
成员
成员
收起侧边栏
关闭侧边栏
动态
分支图
创建新Issue
提交
Issue看板
体验新版 GitCode,发现更多精彩内容 >>
提交
0885b4ba
编写于
4月 22, 2019
作者:
C
chengduozh
浏览文件
操作
浏览文件
下载
电子邮件补丁
差异文件
update op role
上级
afc2979a
变更
1
隐藏空白更改
内联
并排
Showing
1 changed file
with
35 addition
and
6 deletion
+35
-6
doc/fluid/advanced_usage/development/new_op/op_notes.md
doc/fluid/advanced_usage/development/new_op/op_notes.md
+35
-6
未找到文件。
doc/fluid/advanced_usage/development/new_op/op_notes.md
浏览文件 @
0885b4ba
...
...
@@ -4,7 +4,7 @@
### 1.Fluid中Op的构建逻辑
Fluid中所有的Op都继承自
`OperatorBase`
,且所有的Op都是无状态的,每个Op包含的成员变量只有四个:type、inputs、outputs、attribute。
Op的核心方法是Run,Run方法需要两方面的资源:数据资源和计算资源,这两个资源分别通过
`Scope`
和
`Place`
获取。框架内部有一个全局的
`DeviceContextPool`
,用来记录
`Place`
和
`DeviceContext`
之间的对应的关系,即每个
`Place`
有且仅有一个
`DeviceContext`
与之对应,
`DeviceContext`
中存放了当前设备的计算资源。比如对于GPU,这些资源包括
`cudnn_handle`
、
`cublas_handle`
、
`stream`
等,
Op内部所有的计算(数据拷贝和CUDA Kernel等)都必须在
`DeviceContext`
中进行
。
Op的核心方法是Run,Run方法需要两方面的资源:数据资源和计算资源,这两个资源分别通过
`Scope`
和
`Place`
获取。框架内部有一个全局的
`DeviceContextPool`
,用来记录
`Place`
和
`DeviceContext`
之间的对应的关系,即每个
`Place`
有且仅有一个
`DeviceContext`
与之对应,
`DeviceContext`
中存放了当前设备的计算资源。比如对于GPU,这些资源包括
`cudnn_handle`
、
`cublas_handle`
、
`stream`
等,
**Op内部所有的计算(数据拷贝和CUDA Kernel等)都必须在`DeviceContext`中进行**
。
Fluid框架的设计理念是可以在多种设备及第三方库上运行,有些Op的实现可能会因为设备或者第三方库的不同而不同。为此,Fluid引入了OpKernel的方式,即一个Op可以有多个OpKernel,这类Op继承自
`OperatorWithKernel`
,这类Op的代表是conv_op,conv_op的OpKerne有:
`GemmConvKernel`
、
`CUDNNConvOpKernel`
、
`ConvMKLDNNOpKernel`
,且每个OpKernel都有double和float两种数据类型。不需要OpKernel的代表有
`WhileOp`
等。
...
...
@@ -120,13 +120,42 @@ ShareDataWith的功能是使两个Tensor共享底层buffer,在调用这个操
目前稀疏梯度在做更新更新的时候会先对梯度做merge,即对相同参数的梯度做累加,然后做参数以及附加参数(如velocity)的更新。
### 7.显存优化
通常反向Op会依赖于前向Op的某些输入
、输出变量,以供反向Op计算使用。但有些情况下,反向Op完全不需要任何前向的输入和输出;有些情况下,反向Op只需要前向Op的部分输入和输出;有些情况下,反向Op只需要使用前向Op中输入和输出变量的Shape和LoD信息。若op开发者在注册反向Op时,将不必要的前向Op输入和输出作为反向o
p的输入,会导致这部分显存无法被框架现有的显存优化策略优化,从而导致模型显存占用过高。
通常反向Op会依赖于前向Op的某些输入
(Input)、输出(Output),以供反向Op计算使用。但有些情况下,反向Op不需要前向Op的所有输入和输出;有些情况下,反向Op只需要前向Op的部分输入和输出;有些情况下,反向Op只需要使用前向Op中输入和输出变量的Shape和LoD信息。若Op开发者在注册反向Op时,将不必要的前向Op输入和输出作为反向O
p的输入,会导致这部分显存无法被框架现有的显存优化策略优化,从而导致模型显存占用过高。
所以在写注册反向Op时需要注意一下几点:
-
Fluid提供的
`DefaultGradOpDescMaker`
,默认会将前向op的所有输入(Input)、输出(Output)以及输出变量所对应的梯度(Output@Grad)作为反向Op的输入,将前向Op输入所对应的梯度(Input@Grad)作为反向Op的输出。所以在使用
`DefaultGradOpDescMaker`
时需要考虑是否有些变量在计算中不被用到。
-
如果有些反向Op需要依赖前向Op的输入、输出的shape或lod,但不依赖于Tensor的Buffer,且不能根据其他信息推断出shape和lod,需要注册
`NoNeedBufferVarsInference`
,一旦注册了
`NoNeedBufferVarsIference`
,反向op中就不能读写这些Tensor的buffer,只能调用Tensor的dims()和lod()方法。具体可参考:
[
sequence_concat_op
](
https://github.com/PaddlePaddle/Paddle/blob/develop/paddle/fluid/operators/sequence_ops/sequence_concat_op.cc
)
。
所以在写注册反向Op时需要注意以下几点:
-
Fluid提供的
`DefaultGradOpDescMaker`
,默认会将前向op的所有输入(
`Input`
)、输出(
`Output`
)以及输出变量所对应的梯度(
`Output@Grad`
)作为反向Op的输入,将前向Op输入所对应的梯度(
`Input@Grad`
)作为反向Op的输出。所以在使用
`DefaultGradOpDescMaker`
时需要考虑是否有些变量在计算中不被用到。
-
如果有些反向Op需要依赖前向Op的输入或输出变量的的Shape或LoD,但不依赖于变量中Tensor的Buffer,且不能根据其他变量推断出该Shape和LoD,需要对该变量在反向Op中进行注册
`NoNeedBufferVarsInference`
。
**一旦注册了`NoNeedBufferVarsIference`,反向op中就不能读写该变量对应的Tensor中的buffer,只能调用Tensor的dims()和LoD()方法**
。比如在
`SliceOpGrad`
中只会用到
`Input`
中变量的Shape信息,所以需要为对
`Input`
在
`SliceOpGrad`
上进行注册:
```
namespace paddle {
namespace operators {
// ...
class SliceOpGradMaker : public framework::SingleGradOpDescMaker {
public:
using framework::SingleGradOpDescMaker::SingleGradOpDescMaker;
protected:
std::unique_ptr<framework::OpDesc> Apply() const override {
auto* bind = new framework::OpDesc();
bind->SetInput("Input", Input("Input"));
bind->SetInput(framework::GradVarName("Out"), OutputGrad("Out"));
bind->SetOutput(framework::GradVarName("Input"), InputGrad("Input"));
bind->SetAttrMap(Attrs());
bind->SetType("slice_grad");
return std::unique_ptr<framework::OpDesc>(bind);
}
};
DECLARE_NO_NEED_BUFFER_VARS_INFERENCE(SliceOpGradNoNeedBufferVarsInference,
"Input");
} // namespace operators
} // namespace paddle
namespace ops = paddle::operators;
REGISTER_OPERATOR(slice, ops::SliceOp, ops::SliceOpMaker,
ops::SliceOpGradMaker);
REGISTER_OPERATOR(slice_grad, ops::SliceOpGrad,
ops::SliceOpGradNoNeedBufferVarsInference);
```
### 8. 反向op注册规范问题
...
...
编辑
预览
Markdown
is supported
0%
请重试
或
添加新附件
.
添加附件
取消
You are about to add
0
people
to the discussion. Proceed with caution.
先完成此消息的编辑!
取消
想要评论请
注册
或
登录