-
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
move net_design to framework #2553
Conversation
paddle/framework/net_design.md
Outdated
// The minimum a network should be implemented. | ||
class NetworkBase { | ||
public: | ||
BaseNetwork(const NetDef &def, 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.
#2547 (comment)
If Network won`t hold scope, why we feed a scope to constructor?
paddle/framework/net_design.md
Outdated
A simple implemention is as followed: | ||
|
||
```c++ | ||
class Network final : public BaseNetwork { |
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 you fogot modifying 'BaseNetwork'.
Please consider the following use case while we go on improving the design: Workspace w1(GPUPlace(0));
Workspace w2(CPUPlace());
w1.CreateVariables(net_desc);
w1.InitVariables(net_desc);
w1.GetVar("weights")->FixValue();
w2.CreateVariables(net_desc);
w2.InitVariables(net_desc);
w2.GetVar("hello")->SetValue(...);
auto net = CreateNet(net_desc);
net.Run(&w1);
net.Run(&w2); |
paddle/framework/net_design.md
Outdated
|
||
// run all the operators and return success(true) or not, all the | ||
// variables are located in `scope`. | ||
virtual bool Run(Scope* scope) = 0; |
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.
There is a discussion in here. Should our Operator
be stateless
? If our Operator
is stateless
, then NetBase::Run()
should be 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/net_design.md
Outdated
A method of factory pattern can be defined like | ||
|
||
```c++ | ||
std::unique<NetworkBase* CreateNet(const NetDef& def) { |
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.
lost a '>'?
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/net_design.md
Outdated
|
||
protected: | ||
// Create operators accordding to `def`. | ||
bool CreateNet(const NetDef &def); |
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`t the difference ScratchNet::CreateNet and CreateNet in line#43. Or shall we rename ScratchNet::CreateNet to a better name, such as: CreateOps ?
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 ScratchNet.CreateNet
just will create operators, maybe some other things should do like some network-level initializations.
Maybe we should rename it to InitNet
? @wanghaoshuang
paddle/framework/net_design.md
Outdated
class NetworkBase { | ||
public: | ||
// `def` is a proto message that describe the structure of a network. | ||
NetworkBase(const NetDef& def); |
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 addOperator
method is very useful, especially when we generating backward ops and generating optimization ops.
Also, the constructor of NetworkBase
should invoke addOperator
as well.
class NetworkBase {
public:
Error AddBackwardOps(const std::string& lossVariableName, float lossGrad = 1.0f) {
for (eachOp reversely) {
for (gradOp in GetGradientOps(eachOp)) {
addOperator(gradOp)
}
}
}
Error AddOptimizerOps(const Map<string, string> paramToGradMap) {
for (paramName, gradName in paramToGradMap) {
addOperator(SGD(input={gradName, paramName}, output={paramName}));
}
}
};
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.
Is it better to unify all the AddXXOps
to AddOp(const OpDef &def)
in base class ?
Or move the above interfaces into ScratchNet
? @reyoung
paddle/framework/net_design.md
Outdated
class NetworkBase { | ||
public: | ||
// `def` is a proto message that describe the structure of a network. | ||
NetworkBase(const NetDef& def); |
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, If NetworkBase
is a base class, the constructor may not include NetDef
protobuf. Because it is not used in base class.
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/net_design.md
Outdated
|
||
protected: | ||
// keys of the input variables feed into the network. | ||
std::vector<string> inputs_; |
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 a network needs inputs_ & outputs_ field?
paddle/framework/net_design.md
Outdated
public: | ||
// `def` is a proto message that describe the structure of a network. | ||
NetworkBase(const NetDef& def); | ||
|
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 addOperator
should return a Index. Maybe code like this,
class NetworkBase {
public:
using OpIndex = size_t;
OpIndex addOperator(const OpDesc& op);
};
So that Run
method can take a begin
and end
argument like:
bool Run(Scope* scope, OpIndex begin = -1UL, OpIndex end = -1UL);
It will be very helpful if a network can run partially.
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.
@reyoung Network maybe run from multiple start-operators to multiple end-operators?
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.
Why don't we use the OpName instead of the OpIndex?
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.
Agree with @wanghaoshuang. It seems that operators within [begin_index, end_index] cannot define arbitrary sub-DAG.
paddle/framework/net_design.md
Outdated
|
||
// run all the operators and return success(true) or not, all the | ||
// variables are located in `scope`. | ||
virtual bool Run(Scope* scope) = 0; |
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 Run can return paddle::Error
.
paddle/framework/net_design.md
Outdated
A very basic implemention is as followed, all it does is simply to run every operators in sequence. | ||
|
||
```c++ | ||
class ScratchNet final : public NetworkBase { |
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.
Sorry, I don't understand why the basic implementation is called Scratch
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.
paddle/framework/net_design.md
Outdated
|
||
## A Simple Network Implemention | ||
|
||
A very basic implemention is as followed, all it does is simply to run every operators in sequence. |
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.
implemention -> implementation
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.
- as followed --> as follows.
- ", all" --> "All"
paddle/framework/net_design.md
Outdated
// Add a operator which is identified as `type` and has attributes described | ||
// in `attrs`, the `inputs` are the keys of readonly input variables, | ||
// `outputs` are keys of mutable output variables. | ||
bool AddOp(const std::string &type, const std::vector<string> &inputs, |
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 addOp should be an interface of NetworkBase. Because there may be some instance will manipulate NetworkBase
in CPP, such as adding gradient ops, adding optimization ops, etc.
If we want user passing a protobuf message contains backward ops, we need to write AddGradientOps
in Python. It will let Paddle coupled with Python
language, which we did not want to.
paddle/framework/net_design.md
Outdated
|
||
private: | ||
// the operators owned by `Network`. | ||
std::vector<std::unique_ptr<Operator>> ops_; |
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 just std::vector<Operator> ops_
is enough? I am not sure. But it seems in interface, we are not using ops_ as a pointer?
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/net_design.md
Outdated
|
||
```c++ | ||
// create an empty scope located on CPU device. | ||
Scope scope(CPUPlace()); |
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 scope do not take Place
as an argument. A scope is just an association from name to variable. Each tensor in variables could have different Place
.
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.
sample code
As described in the sample code, Scope has a place, maybe more discussion here? @wangkuiyi @reyoung
paddle/framework/net_design.md
Outdated
Benefit from the decoupling of `ScratchNet.Run` and `Scope`, `ScratchNet` is compatible with future RNN design, | ||
for example we can implement a simple recurrent neural network as followed | ||
|
||
```c++ |
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.
Well, this part should be rewritten.
Scope
contains a parent
argument. The local scope can access the parent scope variables. It should not copy variables between scopes.
Scope parent;
// in RNN
NetworkBase& stepNet;
std::vector<Scope> timestepScopes;
for (size_t i=0; i < seqLen; ++i) {
timestepScopes.push_back(Scope(&parent));
stepNet.Run(×tepScopes);
}
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 will give another commit soon to fix this.
paddle/framework/net_design.md
Outdated
|
||
Network is designed as the container of operators, to make it more extendable, | ||
we decompling it from the related variable resources. | ||
A `scope` is provided to `Run` so that the network structure can be reused |
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
Run(Scope* scope)
takes a scope as the parameter and so that it can run in different scopes
is better for understanding.
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/net_design.md
Outdated
|
||
protected: | ||
// Create operators accordding to `def`. | ||
bool CreateNet(const NetDef &def); |
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 InitNet()
is better? Because I think CreatNet will return a created Net and InitNet will fulfill and init itself.
paddle/framework/net_design.md
Outdated
@@ -0,0 +1,159 @@ | |||
# Network Design | |||
|
|||
`Network` is the container and controller of a set of operators in a network, |
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.
Network
is the container and controller of a set of operators in a network.
=>
Network
is the container and controller of a set of operators.
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/net_design.md
Outdated
# Network Design | ||
|
||
`Network` is the container and controller of a set of operators in a network, | ||
users can build a real network from a `NetDef` in protobuf message |
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.
or use AddOp to modify this Net
paddle/framework/net_design.md
Outdated
public: | ||
// `def` is a proto message that describe the structure of a network. | ||
NetworkBase(const NetDef& def); | ||
|
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.
Agree with @wanghaoshuang. It seems that operators within [begin_index, end_index] cannot define arbitrary sub-DAG.
paddle/framework/net_design.md
Outdated
virtual bool Run(Scope* scope) const = 0; | ||
|
||
protected: | ||
// keys of the input variables feed into the network. |
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.
feed --> fed
paddle/framework/net_design.md
Outdated
|
||
All network implementations should build networks from a protobuf message which | ||
describes the structure of a real network; `Run` method should be implemented by | ||
all implementations to offer a universal method to forward or backward compute a network. |
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 be implemented by all implementations --> should be implemented by all its inheriting class
paddle/framework/net_design.md
Outdated
} | ||
``` | ||
|
||
Network is designed as the container of operators, to make it more extendable, |
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.
--> Network is designed as a container for operators, with related variable resources decoupled from it to make it more extendable.
paddle/framework/net_design.md
Outdated
A `scope` is provided to `Run` so that the network structure can be reused | ||
in different scopes. | ||
|
||
Finally, `NetworkBase` can be used as followed |
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 followed --> as follows:
paddle/framework/net_design.md
Outdated
|
||
## A Simple Network Implemention | ||
|
||
A very basic implemention is as followed, all it does is simply to run every operators in sequence. |
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 followed --> as follows.
- ", all" --> "All"
我觉得 因为:
故 |
Scope scope(CPUPlace()); | ||
|
||
// create and init variables described in `net_desc`. | ||
scope.CreateVariables(net_desc); |
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.
NetworkBase
has a member function called InferShape(Scope*)
to infer shapes and create variables in scope, is its function duplicate with scope.CreateVariables
?
Because the variables' information is located in OpDef
and there is no field called vars
in NetDef
that holds all the information of variables required by the network, is scope.CreateVariables
necessary?
@wangkuiyi @reyoung @jacquesqiao
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.
Variable
information is not stored in NetDef
, and in OpDef
, there will only be input/output names for Variable
. So CreateVariables
be performed only by NetDef
.
Maybe there should be a high-level concept called NetworkBuilder
or Model
. A NetworkBuilder
takes a NetworkBase
and a Scope
as its inputs. In NetworkBuilder
, the user can add layers, add backward ops, and get all parameters. During AddLayer
functions, the variable
is created by Network Builder.
NetworkBase network;
Scope scope;
Variable* image = scope.CreateVariable("Image");
Variable* label = scope.CreateVariable("Label");
NetworkBuilder builder(&network, &scope);
Variable* fc_out = builder.FCLayer(input=image, size=100, activation="Sigmoid");
Variable* prediction = builder.FCLayer(input=fc_out, size=10, activation="Sigmoid");
Variable* loss = builder.CrossEntropy(input=prediction, label=label);
Variable* avg_loss = builder.Mean(loss);
auto allParams = builder.Parameters();
builder.BackwardFrom(avg_loss)
builder.AddOptimization(1e-4, "adam");
// train one mini-batch
network.run(&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.
Can we merge NetworkBuiler
into NetworkBase
?
NetworkBase
is the base class of all "network" implementations, with a different implementation, NetBuilder may be different.
For example, SimpleNet
's network structure is different with DAGNet
's structure,
so a different NetBuilder.ApplyGradient may be needed. In other words, NetBuilder is coupled to specific implementation of NetworkBase.
If we merge NetBuilder's functions into NetworkBase
's specific implementations, then it is natural to have different "BackwardFrom" implementations.
@reyoung
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 the logic of ApplyGradient
is same for each implementation of NetworkBase
. The different between PlainNet
and other implementation is how to implement AddOperator
.
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 create another PR with NetBuilder
NetBuilder
is treated as a user-friendly syntax API.
NetBase
is the detailed implementation of Network-related APIs.
Users can create BaseNet
using NetBuilder
, but the detail of BaseNet
is not visible to them.
With this two-level design, we will focus our use-related API on NetBuilder
and implementation details only on NetBase
.
Both of them are not coupled with each other.
* add senet * add annotations according to review
I fixed all the comments in the previous PR