提交 b44f4ccb 编写于 作者: Y Yu Yang 提交者: Yang Yang(Tony)

Make InferShape as a field in OpInfo (#5139)

* Op developer can add `InferShape` to any operator
上级 7f8574c0
...@@ -28,7 +28,8 @@ enum OpInfoFillType { ...@@ -28,7 +28,8 @@ enum OpInfoFillType {
kOperator = 0, kOperator = 0,
kOpProtoAndCheckerMaker = 1, kOpProtoAndCheckerMaker = 1,
kGradOpDescMaker = 2, kGradOpDescMaker = 2,
kVarTypeInference = 3 kVarTypeInference = 3,
kShapeInference = 4
}; };
template <typename T> template <typename T>
...@@ -42,7 +43,10 @@ struct OpInfoFillTypeID { ...@@ -42,7 +43,10 @@ struct OpInfoFillTypeID {
? kGradOpDescMaker ? kGradOpDescMaker
: (std::is_base_of<VarTypeInference, T>::value : (std::is_base_of<VarTypeInference, T>::value
? kVarTypeInference ? kVarTypeInference
: static_cast<OpInfoFillType>(-1)))); : (std::is_base_of<InferShapeBase, T>::value
? kShapeInference
: static_cast<OpInfoFillType>(
-1)))));
} }
}; };
...@@ -121,6 +125,16 @@ struct OpInfoFiller<T, kVarTypeInference> { ...@@ -121,6 +125,16 @@ struct OpInfoFiller<T, kVarTypeInference> {
} }
}; };
template <typename T>
struct OpInfoFiller<T, kShapeInference> {
void operator()(const char* op_type, OpInfo* info) const {
info->infer_shape_ = [](InferShapeContext* ctx) {
T inference;
inference(ctx);
};
}
};
} // namespace details } // namespace details
} // namespace framework } // namespace framework
......
...@@ -14,6 +14,7 @@ limitations under the License. */ ...@@ -14,6 +14,7 @@ limitations under the License. */
#include "paddle/framework/op_desc.h" #include "paddle/framework/op_desc.h"
#include <functional> #include <functional>
#include <mutex>
#include <unordered_map> #include <unordered_map>
#include "paddle/framework/block_desc.h" #include "paddle/framework/block_desc.h"
#include "paddle/framework/operator.h" #include "paddle/framework/operator.h"
...@@ -229,26 +230,26 @@ void OpDescBind::Flush() { ...@@ -229,26 +230,26 @@ void OpDescBind::Flush() {
} }
} }
using InferShapeFuncMap = static std::once_flag init_infer_shape_funcs;
std::unordered_map<std::string /*op_type*/,
std::function<void(InferShapeContext *)>>; static void InitInferShapeFuncs() {
std::call_once(init_infer_shape_funcs, [] {
static InferShapeFuncMap &InferShapeFuncs() { auto &map = OpInfoMap::Instance();
static InferShapeFuncMap *g_map = nullptr; auto &info_map = *map.mutable_map();
if (g_map == nullptr) {
g_map = new InferShapeFuncMap(); for (auto &kern_pair : OperatorWithKernel::AllOpKernels()) {
auto &info_map = OpInfoMap::Instance(); auto op_type = kern_pair.first;
// all registered kernels auto &op_info = info_map.at(op_type);
for (auto &pair : OperatorWithKernel::AllOpKernels()) {
auto &info = info_map.Get(pair.first);
// use empty type here to avoid runtime checks.
auto op = auto op =
static_cast<OperatorWithKernel *>(info.Creator()("", {}, {}, {})); static_cast<OperatorWithKernel *>(op_info.Creator()("", {}, {}, {}));
g_map->insert( if (op_info.infer_shape_) { // infer_shape has been registered.
{pair.first, [op](InferShapeContext *ctx) { op->InferShape(ctx); }}); continue;
} }
op_info.infer_shape_ = [op](InferShapeContext *ctx) {
op->InferShape(ctx);
};
} }
return *g_map; });
} }
void OpDescBind::CheckAttrs() { void OpDescBind::CheckAttrs() {
...@@ -265,13 +266,12 @@ void OpDescBind::CheckAttrs() { ...@@ -265,13 +266,12 @@ void OpDescBind::CheckAttrs() {
void OpDescBind::InferShape(const BlockDescBind &block) const { void OpDescBind::InferShape(const BlockDescBind &block) const {
VLOG(3) << "CompileTime infer shape on " << Type(); VLOG(3) << "CompileTime infer shape on " << Type();
auto &funcs = InferShapeFuncs(); InitInferShapeFuncs();
auto it = funcs.find(this->Type()); auto &infer_shape = OpInfoMap::Instance().Get(this->Type()).infer_shape_;
if (it == funcs.end()) { PADDLE_ENFORCE(static_cast<bool>(infer_shape),
PADDLE_THROW("Operator %s has not been registered", this->Type()); "%s's infer_shape has not been registered", this->Type());
}
CompileTimeInferShapeContext ctx(*this, block); CompileTimeInferShapeContext ctx(*this, block);
it->second(&ctx); infer_shape(&ctx);
} }
void OpDescBind::InferVarType(BlockDescBind *block) const { void OpDescBind::InferVarType(BlockDescBind *block) const {
......
...@@ -25,12 +25,19 @@ ...@@ -25,12 +25,19 @@
namespace paddle { namespace paddle {
namespace framework { namespace framework {
class InferShapeBase {
public:
virtual ~InferShapeBase() = default;
virtual void operator()(InferShapeContext*) const = 0;
};
struct OpInfo { struct OpInfo {
OpCreator creator_; OpCreator creator_;
GradOpMakerFN grad_op_maker_; GradOpMakerFN grad_op_maker_;
OpProto* proto_{nullptr}; OpProto* proto_{nullptr};
OpAttrChecker* checker_{nullptr}; OpAttrChecker* checker_{nullptr};
InferVarTypeFN infer_var_type_; InferVarTypeFN infer_var_type_;
InferShapeFN infer_shape_;
bool HasOpProtoAndChecker() const { bool HasOpProtoAndChecker() const {
return proto_ != nullptr && checker_ != nullptr; return proto_ != nullptr && checker_ != nullptr;
...@@ -87,13 +94,13 @@ class OpInfoMap { ...@@ -87,13 +94,13 @@ class OpInfoMap {
} }
} }
const std::unordered_map<std::string, const OpInfo>& map() const { const std::unordered_map<std::string, OpInfo>& map() const { return map_; }
return map_;
} std::unordered_map<std::string, OpInfo>* mutable_map() { return &map_; }
private: private:
OpInfoMap() = default; OpInfoMap() = default;
std::unordered_map<std::string, const OpInfo> map_; std::unordered_map<std::string, OpInfo> map_;
DISABLE_COPY_AND_ASSIGN(OpInfoMap); DISABLE_COPY_AND_ASSIGN(OpInfoMap);
}; };
......
...@@ -636,7 +636,9 @@ class OperatorWithKernel : public OperatorBase { ...@@ -636,7 +636,9 @@ class OperatorWithKernel : public OperatorBase {
}); });
} }
virtual void InferShape(InferShapeContext* ctx) const = 0; virtual void InferShape(InferShapeContext* ctx) const {
OpInfoMap::Instance().Get(Type()).infer_shape_(ctx);
}
protected: protected:
// indicate kernel DataType by input data. Defaultly all input data must be // indicate kernel DataType by input data. Defaultly all input data must be
......
...@@ -28,6 +28,8 @@ class OperatorBase; ...@@ -28,6 +28,8 @@ class OperatorBase;
class OpDescBind; class OpDescBind;
class BlockDescBind; class BlockDescBind;
class BlockDesc; class BlockDesc;
class InferShapeContext;
using VariableNameMap = std::map<std::string, std::vector<std::string>>; using VariableNameMap = std::map<std::string, std::vector<std::string>>;
// The order should be as same as framework.proto // The order should be as same as framework.proto
...@@ -49,5 +51,7 @@ using GradOpMakerFN = std::function<std::vector<std::unique_ptr<OpDescBind>>( ...@@ -49,5 +51,7 @@ using GradOpMakerFN = std::function<std::vector<std::unique_ptr<OpDescBind>>(
using InferVarTypeFN = std::function<void(const OpDescBind& /*op_desc*/, using InferVarTypeFN = std::function<void(const OpDescBind& /*op_desc*/,
BlockDescBind* /*block*/)>; BlockDescBind* /*block*/)>;
using InferShapeFN = std::function<void(InferShapeContext*)>;
} // namespace framework } // namespace framework
} // namespace paddle } // namespace paddle
...@@ -19,11 +19,9 @@ namespace operators { ...@@ -19,11 +19,9 @@ namespace operators {
using framework::Tensor; using framework::Tensor;
class MulOp : public framework::OperatorWithKernel { class MulOpShapeInference : public framework::InferShapeBase {
public: public:
using framework::OperatorWithKernel::OperatorWithKernel; void operator()(framework::InferShapeContext* ctx) const override {
void InferShape(framework::InferShapeContext* ctx) const override {
PADDLE_ENFORCE(ctx->HasInput("X"), "Input(X) of MulOp should not be null."); PADDLE_ENFORCE(ctx->HasInput("X"), "Input(X) of MulOp should not be null.");
PADDLE_ENFORCE(ctx->HasInput("Y"), "Input(Y) of MulOp should not be null."); PADDLE_ENFORCE(ctx->HasInput("Y"), "Input(Y) of MulOp should not be null.");
PADDLE_ENFORCE(ctx->HasOutput("Out"), PADDLE_ENFORCE(ctx->HasOutput("Out"),
...@@ -137,7 +135,10 @@ class MulOpGrad : public framework::OperatorWithKernel { ...@@ -137,7 +135,10 @@ class MulOpGrad : public framework::OperatorWithKernel {
} // namespace paddle } // namespace paddle
namespace ops = paddle::operators; namespace ops = paddle::operators;
REGISTER_OP(mul, ops::MulOp, ops::MulOpMaker, mul_grad, ops::MulOpGrad); REGISTER_OPERATOR(mul, paddle::framework::OperatorWithKernel, ops::MulOpMaker,
ops::MulOpShapeInference,
paddle::framework::DefaultGradOpDescMaker<true>);
REGISTER_OPERATOR(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>);
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册