-
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
basic scope implementation #2629
Conversation
@@ -0,0 +1,50 @@ | |||
#pragma once |
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.
Need copyright information
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/scope.cc
Outdated
@@ -0,0 +1,55 @@ | |||
#include "paddle/framework/scope.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.
Need copyright information.
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/scope.h
Outdated
|
||
// Create Variable in this Scope. Return error if Variable already been | ||
// created. | ||
Error __must_check CreateVariable(const std::string& 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.
I checked the definition of __must_check
. It means "must use the returned value", and has nothing about "check".
Also, according to Google C++ style, a macro should be all captital, e.g., MUST_USED_RETVALUE
. It breaks the style.
Should we remove paddle/platform/must_check.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.
ok, I will remove __must_check
and return Variable directly
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/scope.h
Outdated
|
||
// Create Variable in this Scope. Return error if Variable already been | ||
// created. | ||
Error __must_check CreateVariable(const std::string& 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.
I checked Caffe2's source code of the similar functionality at here:
Blob* Workspace::CreateBlob(const string& name) {
if (HasBlob(name)) {
VLOG(1) << "Blob " << name << " already exists. Skipping.";
} else {
VLOG(1) << "Creating blob " << name;
blob_map_[name] = unique_ptr<Blob>(new Blob());
}
return GetBlob(name);
}
I am impressed that Caffe2's authors tried to handle the error as much as they could inside the function definition. Whereas, we simply return an error and use __must_check
to require users of our functions to handle the error. The best place to handle the error is at where it happens, where we have the most sufficient information to recover, to report, or to fail.
I'd suggest that we use:
Variable* CreateVar(const std::string& 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.
Done
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.
To give an accurate semantics, I prefer to provide two interfaces:
CreateVariable
will check and fail if there already have a variable with the same name in the scope.GetOrCreateVariable
is used to get a variable anyway.
Currently, I think the user should know exactly what they want.
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.
Good argue!
Let us think about this following the first principle.
What users need are
- Create
- Get
Create could err if there has been a variable with the same name there. We can do either of the following things with this error:
- we do nothing
- return the error
A basic design principle is that we handle the error as much as we could at where it happens, and try not to return to the users, because the users knows nothing about the detail and cannot really do much with this error. Also, if the variable is already there, users' intention (create the variable) is fulfilled, it doesn't worthy of returning an error. So I prefer Create takes no-op with the duplication error.
Similarly, Get could err if it cannot find the variable, and we can take the following possible actions:
- no-op
- return error
- create the variable
When the user Gets a variable, it assumes that the variable should have been there. If it has not, it implies that the creation process failed or we were creating a wrong network description. Anyway, there do have an error so we cannot take no-op. Similarly, if we create the variable, we hide the error; this is not right. So we must report error. Fortunately, reporting the error is simple -- just return nullptr would be enough.
Summarize above derivation, I think we should have
- CreateVar, which does nothing if there has been the variable, and
- Get, which returns nullptr if the variable isn't there.
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.
if the variable is already there, users' intention (create the variable) is fulfilled, there is really nothing worth of returning.
This line convinced me, thanks! I will try to learn more about the first principle
.
paddle/framework/scope.h
Outdated
Variable* GetVariable(const std::string& name) const; | ||
|
||
// find and return Variables in the scope it self. | ||
Variable* GetVarLocally(const std::string& name) 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.
In what situation we need GetVarLocally
instead of GetVaraible
?
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.
Removed
paddle/framework/scope.h
Outdated
|
||
// Get a Variable from Scope, if the Variable is not exist then create it. | ||
// User should call this function most of time. | ||
Variable* GetOrCreateVariable(const std::string& 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.
How about merge CreateVariable
and GetOrCreateVariable
into one -- CreateVar
?
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
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.
To give an accurate semantics, I prefer to provide two interfaces:
CreateVariable
will check and fail if there already have a variable with the same name in the scope.GetOrCreateVariable
is used to get a variable anyway.
Currently, I think the user should know exactly what they want.
paddle/framework/scope.h
Outdated
// User should call this function most of time. | ||
Variable* GetOrCreateVariable(const std::string& name); | ||
|
||
bool HaveVariable(const std::string& 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.
Have => Has, because the implied subject is "a workspace", not "workspaces" or something like that.
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/scope.h
Outdated
#include <unordered_map> | ||
#include <vector> | ||
#include "paddle/framework/variable.h" | ||
#include "paddle/utils/Error.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.
I don't see that this header file needs a special Error type. I think if we follow below comments, we can remove this inclusion.
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/scope.cc
Outdated
namespace framework { | ||
|
||
Variable* Scope::CreateVariable(const std::string& name) { | ||
if (!HasVariable(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.
If HasVariable, just ASSERT_FALSE is 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.
And local scope could create a variable that uses the same name in the parent. It means the local variable can hide parent variable.
void CreateVariable(const std::string& name) {
auto it = vars_.find(name);
ASSERT_EQ(it, vars_.end());
vars_[name] = std::unique_ptr<Variable>(new Variable());
}
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 our design, CreateVariable
is equal to GetOrCreateVariable
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 implement Get
, Create
by it means, and implement another method name GetOrCreateVariable()
.
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.
I prefer a concise interface. It takes the users only two lines to implement GetOrCreateVariable:
const Variable* v = ws.GetVar("something");
if (v == nullptr)
ws.CreateVar("something");
// do something with v.
doesn't differ much from
const Variable* v = ws.GetOrCreateVar("something");
// do something with v.
paddle/framework/scope.cc
Outdated
} | ||
|
||
Variable* Scope::GetVarLocally(const std::string& name) const { | ||
if (vars_.count(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.
vars_.count is not good.
auto it = vars_.find(name);
if (it != vars_.end()) {
return it->second.get();
}
return nullptr;
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.
ok, It's better to use find than count. Thanks for reminding!
paddle/framework/scope.cc
Outdated
} | ||
} | ||
|
||
bool Scope::HasVariable(const std::string &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.
HasVariable() 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.
I think we could implement Scope
in the header only. Not split them into cpp
files.
Because function in the header could be inlined, but in cpp
, the function cannot be inlined.
The scope function is simple and should be inlined.
paddle/framework/scope.h
Outdated
*/ | ||
class Scope { | ||
public: | ||
Scope() {} |
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.
Scope() = 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.
removed
paddle/framework/scope.h
Outdated
|
||
explicit Scope(const std::shared_ptr<Scope>& scope) : parent_(scope) {} | ||
|
||
~Scope() {} |
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.
Destructor is not needed.
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/scope.h
Outdated
public: | ||
Scope() {} | ||
|
||
explicit Scope(const std::shared_ptr<Scope>& scope) : parent_(scope) {} |
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 a single ctor is enough.
And ctor of Scope should be private. There should be another method create std::shared_ptr<Scope>
like:
private:
Scope(const std::shared_ptr<Scope>& parent): parent_(parent) {}
public:
static std::shared_ptr<Scope> Create(const std::shared_ptr<Scope>& parent=nullptr) {
return std::make_shared<Scope>(parent);
}
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 quite understand the reason to always create a shared_prt?
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.
Why not the simplest way:
class Scope {
public:
Scope(Scope* parent) : parent_(parent) {}
private:
std::shared_ptr<Scope> parent_;
};
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.
Because we want user to use Scope as shared_ptr(std::shared_ptr parent_), a create function will do this for user.
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, remove default argument
paddle/framework/scope.h
Outdated
|
||
~Scope() {} | ||
|
||
// Create Variable in this Scope. Return error if Variable already been |
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.
Use '///' or '/**', see doxygen style
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/scope.h
Outdated
public: | ||
static std::shared_ptr<Scope> Create( | ||
const std::shared_ptr<Scope>& parent = nullptr) { | ||
return std::make_shared<Scope>(Scope(parent)); |
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.
std::make_shared<Scope>(parent);
should enough.
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.
According to https://google.github.io/styleguide/cppguide.html#Default_Arguments, we shouldn't use default argument here.
My proposal in #2629 (comment) seems OK.
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.
it will fail if the default consturctor is private:
In file included from /Users/qiaolongfei/project/paddle/paddle/framework/scope_test.cc:15:
In file included from /Users/qiaolongfei/project/paddle/paddle/framework/scope.h:17:
In file included from /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/../include/c++/v1/string:439:
In file included from /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/../include/c++/v1/algorithm:628:
/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/../include/c++/v1/memory:2194:15: error: field of type 'paddle::framework::Scope' has private default constructor
__second_(_VSTD::forward<_Args2>(_VSTD::get<_I2>(__second_args))...)
^
/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/../include/c++/v1/memory:2457:15: note: in instantiation of function template specialization 'std::__1::__libcpp_compressed_pair_imp<std::__1::allocator<paddle::framework::Scope>, paddle::framework::Scope, 1>::__libcpp_compressed_pair_imp<std::__1::allocator<paddle::framework::Scope> &, const std::__1::shared_ptr<paddle::framework::Scope> &, 0, 0>' requested here
: base(__pc, _VSTD::move(__first_args), _VSTD::move(__second_args),
^
/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/../include/c++/v1/memory:3800:16: note: in instantiation of function template specialization 'std::__1::__compressed_pair<std::__1::allocator<paddle::framework::Scope>, paddle::framework::Scope>::__compressed_pair<std::__1::allocator<paddle::framework::Scope> &, const std::__1::shared_ptr<paddle::framework::Scope> &>' requested here
: __data_(piecewise_construct, _VSTD::forward_as_tuple(__a),
^
/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/../include/c++/v1/memory:4411:26: note: in instantiation of function template specialization 'std::__1::__shared_ptr_emplace<paddle::framework::Scope, std::__1::allocator<paddle::framework::Scope> >::__shared_ptr_emplace<const std::__1::shared_ptr<paddle::framework::Scope> &>' requested here
::new(__hold2.get()) _CntrlBlk(__a2, _VSTD::forward<_Args>(__args)...);
^
/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/../include/c++/v1/memory:4775:29: note: in instantiation of function template specialization 'std::__1::shared_ptr<paddle::framework::Scope>::make_shared<const std::__1::shared_ptr<paddle::framework::Scope> &>' requested here
return shared_ptr<_Tp>::make_shared(_VSTD::forward<_Args>(__args)...);
^
/Users/qiaolongfei/project/paddle/paddle/framework/scope.h:41:17: note: in instantiation of function template specialization 'std::__1::make_shared<paddle::framework::Scope, const std::__1::shared_ptr<paddle::framework::Scope> &>' requested here
return std::make_shared<Scope>(parent);
^
/Users/qiaolongfei/project/paddle/paddle/framework/scope.h:35:12: note: declared private here
explicit Scope(const std::shared_ptr<Scope>& parent = nullptr)
^
1 error generated.
make[2]: *** [paddle/framework/CMakeFiles/scope_test.dir/scope_test.cc.o] Error 1
make[1]: *** [paddle/framework/CMakeFiles/scope_test.dir/all] Error 2
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 argument removed
paddle/framework/scope.h
Outdated
/// Create Variable in this Scope. Failed if Variable already been | ||
/// created. | ||
Variable* CreateVariable(const std::string& name) { | ||
PADDLE_ASSERT(!HasVariable(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.
Should local scope hide parent scope variable?
If so, then here should be
PADDLE_ASSERT(vars_.find(name) == vars_.end());
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.
I am not sure why we need to hide parent scope variable
I approved because my questions were addressed. Please feel free to continue the discussion. |
* update readme en, test=document_fix * update doc
Basic implementation of Scope.