-
Notifications
You must be signed in to change notification settings - Fork 5.6k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
[draft] add registry for Op, OpProto and OpAttrChecker #2739
Conversation
paddle/framework/op_registry.h
Outdated
}; | ||
|
||
class OpRegistry { | ||
typedef std::function<OperatorBase*(OpDesc& op_desc)> OpCreator; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
const OpDesc&
?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
In TypedAttrChecker::operator()
, we check attributes and complete default value, so the OpDesc
will be mutated in inner checkers.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
so, OpDesc& -> OpDesc*
better ?
paddle/framework/op_registry.h
Outdated
ProtoMakerType(&op_proto, &op_checker); | ||
} | ||
|
||
static OpBase* CreateOp(const std::string& op_type, OpDesc op_desc) const { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
const OpDesc&
?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
As mentioned above~
paddle/framework/op_registry.h
Outdated
} | ||
}; | ||
|
||
#define REGISTER_OP(op_class, op_maker_class, op_type) \ |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
op_class
-> __op_class
? other arguments are the same
a different name method to indicate these arguments are used in macro.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Got it. Thanks!
paddle/framework/op_registry.h
Outdated
} | ||
}; | ||
|
||
REGISTER_OP(CosineOp, CosineOpProtoAndCheckerMaker, "cos"); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
cos -> cos_sim or cossim ?
paddle/framework/attr_checker.h
Outdated
bool operator()(OpDesc& op_desc) const { | ||
//========= pseudocode begin ==========// | ||
// check whether attr need default value; | ||
if (!op_disc.has_fild(attr_name_)) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
op_disc
-> op_desc
?
paddle/framework/attr_checker.h
Outdated
class LargerThanChecker { | ||
public: | ||
LargerThanChecker(T lower_bound) : lower_bound_(lower_bound) {} | ||
bool operator()(const T& value) const { return value > lower_bound_; } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Maybe bool
is not enough to give the user a details information.
There can be two options:
- Use
PADDLE_ENFORCE
and return void. - Use
std::string
as return value. An empty string represents OK, others represent Errors.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Also, I think the interface of this function could be
(T* attr, bool alreadySet) -> void
And then the Default
can be a function, too. Like
[](T* attr, bool alreadySet) {
if (!alreadySet) { // not set by user
*attr = xxx; // set by us.
}
}
and Required
can be a function, too.
[](T* attr, bool alreadySet) {
if (!alreadySet) { // not set by user
return "error!!";
}
}
paddle/framework/attr_checker.h
Outdated
private: | ||
std::string attr_name_; | ||
std::vector<ValueChecker> value_checkers_; | ||
bool has_default_; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Not only Default
is needed, but also Required
is needed too.
paddle/framework/op_registry.h
Outdated
private: \ | ||
const static OpRegisterHelper<#op_class, #op_maker_class> reg; \ | ||
}; \ | ||
const Register op_class##Register::reg(#op_type); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Maybe we should move paddle/util/InitFunction
here.
既然我们从protobuf解析出Attribute的用来传递给C++的OpBase。并且在解析完毕传递之前,需要做一些约束检查。 那么,我们为啥不先将Protobuf中的所有Attributes解析成标准C++类型,以便之后进一步处理。而约束检查函数都以C++类型为输入类型就好。 可能的C++类型为: // boost::variant can be replaced by our implementaiton
using Attribute = boost::variant<boost::blank, int, float, std::string, std::vector<int>, std::vector<float>, std::vector<std::string>>;
using AttributeMap = std::unordered_map<std::string, Attribute>;
using AttributeConstraint = std::function<void(Attribute* attr)>; 那么,在注册OpCreator的时候,注册的函数可以为: std::unordered_map<string, std::vector<AttributeConstraint>> attr_constraints_;
auto creator = [] (const OpDesc& desc) {
AttributeMap attrs = ParseProtoAttrs(desc.attrs());
for (auto it = attr_constraints_.begin(); it != attr_constraints_.end(); ++it) {
auto attr_name = it->first;
auto& constraints = it->second;
for (auto& cons : constraints) {
cons(&attrs[attr_name]); // if attr_name is not exist, a boost::variant<blank> will be created.
}
}
return new OpBase(desc.inputs(), desc.outputs(), attrs); // just pass attrs to OpBase.
} 这样做的好处是:
这个实现依赖了boost::variant, 不过我们可以给用户传一个Attributes的接口,进而隔绝Op开发者直接使用boost::variant。譬如
|
仔细想了一下 @reyoung 提出的建议。和我目前的代码实现的主要差异在于: Attribute从Protobuf解析出来后会以boost::variant封装,以兼容多种可能的类型。在我的实现中,Attribute先从boost::variant中取出,转化成确定类型的值,再接受对应类型的各项checker的检查。在 @reyoung 的建议中,checker写成boost的visitor的形式,因此可以直接接受boost::variant类型的Attribute,无需确定类型。 两种方法最后的代码实现应该没有什么大的差别,就是底层checker是写成模板类还是boost visitor的区别。 除此之外, @reyoung 还建议将default的设置也抽取出来做成一个checker,以及用PADDLE_ENFORCE报错,这对我很有启发性,我稍后修改一下 |
…Map` is a unordered_map of <string, Attribute>, and `Attribute` is a boost::variant object to hold multiple types of attribute value. 2. Use `PADDLE_ENFORCE` to print checkers' fail message. 3. Abstract default value operations to a new function: `DefaultChecker`.
paddle/framework/attr_checker.h
Outdated
} | ||
T& attr_value = boost::get<T>(attr); | ||
for (const auto& checker : value_checkers_) { | ||
checker(attr_value); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The advantage of this design is checker contains a template parameter T.
paddle/framework/attr_checker.h
Outdated
private: | ||
std::string attr_name_; | ||
std::vector<ValueChecker> value_checkers_; | ||
std::vector<ValueChecker> default_checker_; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
default_checker_ is a little confusing, maybe default_setter_ would be better.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
done
paddle/framework/attr_checker.h
Outdated
} | ||
|
||
void operator()(AttributeMap& attr_map) const { | ||
Attribute& attr = attr_map.at(attr_name_); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
.at
will not construct a default Attribute.
See
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
done
paddle/framework/attr_checker.h
Outdated
// an attribute can have more than one limits | ||
template <typename T> | ||
class TypedAttrChecker { | ||
typedef std::function<void(const T&)> ValueChecker; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Maybe not important, but using
is better than typedef
.
http://blog.csdn.net/big_yellow_duck/article/details/52224068
public: | ||
TypedAttrChecker(const std::string& attr_name) : attr_name_(attr_name) {} | ||
|
||
TypedAttrChecker& LargerThan(const T& lower_bound) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Maybe we should provide a base API named
AddChecker(ValueChecker checker) {
checkers_.push_back(checker);
return *this;
}
Other API will invoke AddChecker
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Maybe AddCustomChecker
has done the same thing?
TypedAttrChecker& AddCustomChecker(const ValueChecker& checker) {
value_checkers_.push_back(checker);
return *this;
}
paddle/framework/attr_checker.h
Outdated
return *(checker.target<TypedAttrChecker<T>>()) | ||
} | ||
|
||
void Check(AttributeMap& attr_map) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Maybe Check
could mark to const
?
paddle/framework/attr_checker.h
Outdated
} | ||
|
||
void Check(AttributeMap& attr_map) { | ||
for (const auto& checker : attr_checkers_) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Also, const
is not need if Check is marked as const
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
done
paddle/framework/op_registry.h
Outdated
private: \ | ||
const static OpRegisterHelper<#__op_class, #__op_maker_class> reg; \ | ||
}; \ | ||
const Register __op_class##Register::reg(#__op_type); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What's the meaning of this line? const Register
?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
miss type... It should be OpRegisterHelper<#__op_class, #__op_maker_class>
1. Complete the development of interfaces between OpRegistry and Protobuf. 2. Add unit test for op_registry.h
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM
This is a draft to show our design about how to implement registry mechanisms of Op, OpProto and OpAttrChecker.
For convenience, a small part of
attr_checker.h
is written with pseudocode. It is indicated by comments==pseudocode begin==
and==pseudocode end==
.