Skip to content

  • 体验新版
    • 正在加载...
  • 登录
  • PaddlePaddle
  • Paddle
  • Issue
  • #2790

P
Paddle
  • 项目概览

PaddlePaddle / Paddle
大约 2 年 前同步成功

通知 2325
Star 20933
Fork 5424
  • 代码
    • 文件
    • 提交
    • 分支
    • 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看板
已关闭
开放中
Opened 7月 10, 2017 by saxon_zh@saxon_zhGuest

need op kernel for Operator

Created by: jacquesqiao

  • operator base实现:https://github.com/PaddlePaddle/Paddle/pull/2725
  • 在operator base基础上,带kernel的Op的demo:https://github.com/PaddlePaddle/Paddle/pull/2796 一个带kernel的op的demo cos_op

有两种实现Op的方式:

  • 无kernel。Op带模板参数,注册时注册不同类型Op,new Op的时候需要生成特定类型的Op。
  • 有kernel。Op不带模板参数,一种类型的Op只注册一次,同时每种Op需要注册多种kernel,new Op的时候无需特定类型的Op,运行前或者运行时决定运行哪种kernel。

上述两种方式的区别:

  • new op时是否需要带device信息。
    • 无kernel。new op时需要带device信息,构建之后Op类型确定,无法修改。构建过程会变得复杂,需要对每个op管理device信息,运行时也不好调整和优化。
    • 有kernel。new op时无需带device信息,构建完成后根据情况决定运行何种kernel。灵活,用户无需事先关心device信息,方便运行时优化。和paddle目前的做法保持一致。
  • 注册方式。

不同框架对比:

  • tensorflow。有kernel,构建Graph的时候,Node可以指定device,但是可以在真正运行时调整,kernel和device绑定,特定device的executor会选择对应的kernel运行。 refs: tensorflow-operator
  • Mxnet。有kernel,kernel以function的形式保存,在运行graph之前,会bind到具体的node上。refs: mxnet operator
  • caffe2。没有kernel,opdef中需要指定device信息,如果没有,默认使用net的device,创建Operator时会根据device_option 创建特定类型的Op,TryCreateOperator,运行时无法调整。

实现kernel带来的问题:

  • kernel如何与Op绑定。
    • 简单方法就是每个OP保存一个kernel数组。例如
  • 如何运行时根据上下文切换Kernel。
    • 简单做法,根据context判断

集中框架的对比。

  • 多数框架带有kernel。
  • 实现带kernel的版本不复杂。
  • 带kernel更易于优化整个计算过程(graph)。

一个demo op的实现

typedef std::function<void(OpContext*)> ComputeFun;

/// simple kernel
template<typename T>
void CosineCPU(OpContext* ctx) {
			printf("run cosin op CPU kernel, scale = %f\n", ctx->op->GetAttr<T>("scale"));
			printf("%s\n", ctx->op->DebugString().c_str());
}

template<typename T>
void CosineGPU(OpContext* ctx) {
	printf("run cosin op GPU kernel, scale = %f\n", ctx->op->GetAttr<T>("scale"));
	printf("%s\n", ctx->op->DebugString().c_str());
}

class CosOp : public OperatorBase {
 public:
	explicit CosOp() {
		kernels_["CPU"] = CosineCPU<float>;
		kernels_["GPU"] = CosineGPU<float>;
	}

  void Run(OpContext* ctx) const override {
		auto dev_ctx = dynamic_cast<CPUDeviceContext*>(ctx->device_context);
		if (dev_ctx != nullptr) {
			kernels_.at("CPU")(ctx);
		} else {
			kernels_.at("GPU")(ctx);
		}
  }

 private:
	std::map<std::string, ComputeFun> kernels_;
};

简单带kernel的Op的运行方式:

  • 构造不同类型的context
  • 使用更复杂的注册和key来寻找。
  • 运行之前统一bind一次,将kernel类型保存在op中。

op的运行

  DeviceContext* cpu_ctx = new CPUDeviceContext();
  DeviceContext* gpu_ctx = new CUDADeviceContext();
  auto scope = std::make_shared<Scope>();

  OperatorBase* op = paddle::framework::OpRegistry::CreateOp(op_desc);

  // will run on cpu kernel
  op->Run(scope, cpu_ctx);

  // will run on gpu kernel
  op->Run(scope, gpu_ctx);
指派人
分配到
无
里程碑
无
分配里程碑
工时统计
无
截止日期
无
标识: paddlepaddle/Paddle#2790
渝ICP备2023009037号

京公网安备11010502055752号

网络110报警服务 Powered by GitLab CE v13.7
开源知识
Git 入门 Pro Git 电子书 在线学 Git
Markdown 基础入门 IT 技术知识开源图谱
帮助
使用手册 反馈建议 博客
《GitCode 隐私声明》 《GitCode 服务条款》 关于GitCode
Powered by GitLab CE v13.7