Skip to content
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

Design Of Refactor Topology #1665

Closed
Show file tree
Hide file tree
Changes from 6 commits
Commits
Show all changes
33 commits
Select commit Hold shift + click to select a range
0e92fbf
Design Draft for using map in protobuf.
reyoung Mar 21, 2017
f5a14b4
Add whole design
reyoung Mar 21, 2017
cf2d77c
Typo
reyoung Mar 21, 2017
a09299a
Make self mutable
reyoung Mar 21, 2017
52d43cd
Add invoke graph
reyoung Mar 21, 2017
b79af86
Add More details
reyoung Mar 21, 2017
cab093d
Update Design.
reyoung Mar 27, 2017
d30c033
Follow luotao's tips, add more description.
reyoung Mar 27, 2017
f001bc9
Fix wrong code style.
reyoung Mar 31, 2017
857f752
Rearrange Documentation
reyoung Apr 5, 2017
1cfd1da
Merge branch 'develop' of github.com:baidu/Paddle into feature/design…
reyoung Apr 5, 2017
b922b00
Add how to write a layer in pure cpp.
reyoung Apr 5, 2017
b3a3b0e
Add skeleton of dynet
reyoung Apr 5, 2017
4a94baa
Add comparation of ways to define layer.
reyoung Apr 5, 2017
d346d49
Merge remote-tracking branch 'reyoung/feature/design_of_layer_code_ge…
QiJune Apr 5, 2017
3e5d22a
add dynamic net doc
QiJune Apr 5, 2017
e3d0fa6
Merge pull request #4 from QiJune/feature/dynamic_net_doc
reyoung Apr 6, 2017
7d440eb
Merge branch 'develop' of github.com:baidu/Paddle into feature/design…
reyoung Apr 6, 2017
4ac8719
Simplize dynamic net implementation
reyoung Apr 6, 2017
386133a
Add link to dynet
reyoung Apr 6, 2017
ff63670
Add how to write a layer in pure cpp
reyoung Apr 6, 2017
12a430a
Change highlight to text
reyoung Apr 6, 2017
7ce9fd5
Merge branch 'develop' of github.com:baidu/Paddle into feature/design…
reyoung May 6, 2017
03184c1
Unify topology design in CPP
reyoung May 6, 2017
4acd579
Add topology user stories and goals
reyoung May 10, 2017
a109c54
Add title
reyoung May 10, 2017
e99e19c
Fix typo
reyoung May 10, 2017
6b8893e
Refine English
reyoung May 10, 2017
726ba05
Add implementation steps.
reyoung May 10, 2017
d4ccdea
Typo
reyoung May 10, 2017
bb562b6
Merge branch 'develop' of github.com:baidu/Paddle into feature/design…
reyoung May 16, 2017
bb68fda
Update developer code example
reyoung May 17, 2017
ccf5d7d
Add implementation details
reyoung May 17, 2017
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
249 changes: 249 additions & 0 deletions doc/design/layer_generation/00.how_to_write_a_layer.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,249 @@
# 如何写一个Layer

这个文档是一个概念性的文档,描述在重构后用户如何写一个Layer。

## 基本目标
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

建议修改成三部分:

  1. 现状
  2. 问题何在
  3. 应该怎么修改

由此一步一步地论证修改的“道理”。


用户只需要写Layer的计算信息,而不需要写配置解析器,也不修改写Protobuf的内容。就可以完成Layer的书写。
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Protobuf ==> protobuf


## 实现方式

### 总体概览

* 在注册Layer的时候,不只注册Layer的C++类型,同时注册Layer的元信息,元信息使用Protobuf来表示。
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Layer ==> layer

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

为什么metadata要用protobuf来描述?

* 使用全局静态函数生成Layer的元信息。代码生成器通过Layer访问元信息来生成配置解析器(ConfigParser)
* 将神经网络参数推导(每一个参数的size多大,输出size是多大)功能,移至Paddle C++ Core中

### Layer元信息

Paddle将**每种**Layer在C++端注册元信息,将元信息声明成Protobuf。

主要的元信息有两个

#### LayerDef
* LayerDef 是描述了每**种**Layer的元信息,他包含每种Layer的类型名,注释,可以接受的输入类型,参数类型,Layer的其他属性。不包括这个Layer输出什么类型
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Github compatible Markdown 里的bullet用 - 而不是 *

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

* 注意这是**元信息**。一个`LayerDef`描述了一**种**`Layer`的类型,而不是一**个**`Layer`的具体参数。
* 同理,LayerDef中使用的 `ArgumentDef`描述的是某**一种输入参数的类型**,而不是某一个具体的输入参数是什么。`AttributeDef`是表示某一个属性(Attribute)的**类型**,而不是这个属性的具体参数。
* 一个全连接层(FullyConnected, 下简写为FC)的LayerDef可能为

```json
{
"type": "fc",
"description": "Fully Connected Layer is the simplest layer in nerual network. ...",
"inputs" : [
{
"name": "input",
"description": "The input of fully connected layer, could be several.",
"data_type": ["Dense", "Sparse", "SparseInt", "Int"],
"seq_nested_level": [0, 1, 2],
"repeatable": true
}
],
"parameter_attr": [
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

可以继承base layer 元信息吗?这样可以简化parameter_attr等说明。

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

这段protobuf是在Paddle C++部分生成的。所以,虽然这里有重复的信息,但是在C++部分可以使用同一个函数来生成Protobuf数据。

Copy link
Contributor

@lzhao4ever lzhao4ever Mar 22, 2017

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

知道了。如果只是在已定义的Layer里修改/增加一些参数,是否只需修改/增加相应元信息即可?

{
"attributes": [{
"name": "weight_decay",
"type": "float",
"description": "The weight decay rate of parameter, used to implement L2 Norm",
"default_value": 0.0,
"max_value": 1.0,
"min_value": 0.0
}, {
"name": "gradient_clipping",
"type": "float",
"description": "The gradient clipping threshold",
"default_value": 0.0,
"min_value": 0.0
}]
}
],
"bias_attr": {
"attributes": [{
"name": "weight_decay",
"type": "float",
"description": "The weight decay rate of parameter, used to implement L2 Norm",
"default_value": 0.0,
"max_value": 1.0,
"min_value": 0.0
}]
},
"layer_attr": [
{
"name": "dropout_rate",
"type": "float",
"description": "The dropout rate of this layer",
"default_value": 0.0,
"max_value": 1.0,
"min_value": 0.0
}
]
}
```

#### LayerOutputType

* LayerOutputType 表示的是,某一个Layer输入输出具体是什么类型的(不是输入输出具体是什么值)。这是在运行时中计算出来的。
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

need to consider the possibility of multiple outputs.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

目前的LstmStepLayer实际上是2个output。第二个output是通过另一个GetOutputLayer来获得的。

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

同意需要支持多个output,在网络配置时能够支持取其中的某些层连接到不同的层~

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

是的,所以getLayerOutputType返回的是std::vector<LayerOutputType>

* 某一个FC Layer的LayerOutputType可能是

```json
{
"type": "Dense",
"size": 200,
"seq_nested_level": 2
}
```

#### Layer元信息的Protobuf定义

下面是Layer元信息的Protobuf定义。

```protobuf
enum DataType {
DENSE=0,
SPARSE_INT=1,
SPARSE=2,
INT=3,
}

enum AttributeType {
STRING=0,
INT=1,
FLOAT=2,
DOUBLE=3,
...
}

message Attribute {
oneof {
string s_value = 1;
int i_value = 2;
float f_value = 3;
...
}
}

message AttributeDef {
required string name = 1; // supported attribute name.
required AttributeType type = 2; // supported type.
required string description = 3; // Attribute description & comments.

optional Attribute default_value = 4; // default value.
optional Attribute max_value = 5; // max value.
optional Attribute min_value = 6; // min value.
}

// Argument Define the Supported InputTypes.
message ArgumentDef {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ArgumentDef 是否和 function/BufferArg(用来描述function的input/output)有一定的对应关系?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

已线下和道远聊过。

结论

enum DataType {
   Dense = 1;
   Sparse = 2;
   SparseBinary = 3;
   Index = 4;
};

enum SequenceNestedLevel {
    NO_SEQUENCE=0;
    PLAIN_SEQUENCE = 1;
    NESTED_SEQUENCE = 2;
};

InputType = DataType << 16 | SequenceNestedLevel

// Supported Input Type.
// The data type of input/output.
repeated DataType data_type = 1;
// 0 means it is not a sequence. 1 means a plain sequence. 2 means a nested sequence. One layer could support many sequence type.
repeated uint32 seq_nested_level = 2;

// In paddle, some layer can handle variable length input.
// If some input is repeatable, it means there are one or many inputs as the same input type.
required bool repeatable = 3;

// In Paddle, a layer could return many outputs. Each output contains a different name.
required string name = 4;

// Comments
required string description = 5;
}

message LayerDef {
required string type = 1; // Layer type, such as 'fc', 'conv'
required string description = 2; // Layer description & comments.


repeated ArgumentDef inputs = 3;


message ParameterDef {
repeated AttributeDef attributes = 1; // Parameter Attributes Definition.
}

// Each input of Paddle Layer should contain zero or one parameter.
// so parameter_attr.size() == inputs.size()
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

parameter_attr.size() <= inputs.size()

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

parameter_attr.size() == inputs.size()

如果是这个输入不应该有参数,那就传一个空的ParameterDef。 inputsparameter_attr两个数组是使用数组下标一一对应的。

repeated ParameterDef parameter_attr = 5;

// Set the bias attribute, If this layer support bias.
optional ParameterDef bias_attr = 6;

// The Layer Attributes.
repeated AttributeDef layer_attr = 7;
}

// Define the layer's output types by given input types.
message LayerOutputType {
// Output name, Each Paddle Layer could have multiple outputs.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Paddle目前一个layer只有一个output。

我理解layer的input, output是相同的类型,ArgumentDef。 这里似乎只看到:

message LayerDef {
    ...
    repeated ArgumentDef inputs = 3;
    ...
}
...
message  LayerOutputDef {}

没有看到layer的output是啥类型?还是 ArgumentDef嘛?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Layer的输出并不在Layer的元信息中指定。

因为每一个Layer的输出形状是解析配置时计算的,而不是元信息可以规定的。所以在LayerDef里面没有outputs

optional string name = 1;

// Output type
required DataType type = 2;
required uint32 size = 3;
required uint32 seq_nested_level = 4;

}
```

### C++ 端暴露LayerDef/LayerOutputType Protobuf.

基本想法:

* 对于每一种类型的Layer,Paddle根据Layer的名字约定两个全局函数的名字。例如,对于FC Layer,全局函数的名字是 `__get_fc_layer_definition__` 和 `__get_fc_layer_output_type__`。 这两个全局函数通过`REGISTER_LAYER`自动生成。
* 对于每个Layer实现的时候,实现两个静态(`static`)函数,分别实现这两个函数。
* 对于获得LayerOutputType的函数,同时完成**神经网络推导**过程。即在运行时设置ParameterSize,动态添加Layer的辅助输入等等。

举例来说,例如对于FCLayer,可能的实现为:

```C++

class FCLayer :public Layer {
public:
void init() { ... }
void forward() { ... }
void backward() { ... }
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

可以定义loss layer, 它的gradient 是在python中计算后传入吗?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

有道理。


static void getLayerDefinition(LayerDef& def) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

看起来流程是,cpp端也是构造了一个proto,来描述这个layer的性质(input/output),然后python get这个proto,再对应的构造出python class,如果都是proto作为属性,是不是都不需要python专门生成一段对应的代码了,而是类似v2的converter那样,把proto信息convert成函数定义,用户如果想查看某个layer的定义,也是直接解析这两个proto就行了。

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

不过在layer拼接的时候,应该有一些特殊的逻辑,这些信息需要表现在layer定义里边么

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

看起来流程是,cpp端也是构造了一个proto,来描述这个layer的性质(input/output),然后python get这个proto,再对应的构造出python class,如果都是proto作为属性,是不是都不需要python专门生成一段对应的代码了,而是类似v2的converter那样,把proto信息convert成函数定义,用户如果想查看某个layer的定义,也是直接解析这两个proto就行了。

对于Python这种动态类型语言,直接生成函数比代码生成器更简单。

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

不过在layer拼接的时候,应该有一些特殊的逻辑,这些信息需要表现在layer定义里边么

没有想好具体有哪些『特殊的逻辑』。如果有这个结构覆盖不到的问题,譬如recurrent_group,可能定义到代码生成器里面也好?因为这个本身是一种语言一个最佳实践的。

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

recurrent_group来说,使用代码生成器是否会太晦涩,现在v2版本转的那块,已经挺难懂的了。

LayerDefinition::supportSize(def);
LayerDefinition::supportDropout(def);
LayerDefinition::addInput()
.setRepeatable(True)
.addSupport({ InputType::Dense, InputType::SparseInt, InputType::Sparse })
.addSupportSeqLevel({0, 1, 2})
.addDoc("FC Layer is fully connected. Blah blah blah...");
}

static std::vector<LayerOutputType> getLayerOutputType(const std::vector<LayerOutputDef>& inputs,
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

need to check whether inputs are consistent (e.g., whether dimensions and types match)

LayerConfig& self) {
// self could be modified, for calculating parameter size, etc.
LayerOutputDef out;
out.set_size(self.size());
out.set_type(InputType::Dense);
out.set_seq_nested_level(inputs[0].seq_nested_level);
return { out };
}
};


REGISTER_LAYER(fc, FCLayer);
```

### 配置解析运行流程

配置解析(config parser)的运行流程如下图所示:

![配置解析运行流程](http://api.paddlepaddle.org/graphviz?dot=https://gist.githubusercontent.com/reyoung/0a3d7bfb44e45d61d7bd80b26ca18fbc/raw/4177e2ca56f0410a65338a089cf4e37b9bb87c93/gistfile1.txt)

1. 读取Paddle Core中所有的Layer的元信息, LayerDef。
1. 根据所有Layer的元信息,LayerDefs生成解析器ConfigParser
* 如何生成解析器是每个语言自定义的过程
* 这个过程可以是离线的过程。即先将所有Layer的LayerDef写入到一个文件里,然后其他语言读取这个文件,来生成代码。
* 这个过程同时也可以是在线的过程。比如对于Python这种动态类型语言,运行时生成函数比较简单,就没必要先生成代码,再生成函数了。
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

这里生成config_parser是先于读取用户定义的网络结构的,那就是需要对所有的layer元信息都遍历一遍。
是否可以考虑先读取用户配置的网络结构,得知需要哪些layer的元信息,然后再生成config_parser。

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

确实也是可以的。这个工作也可以是Lazy的。即用户使用某一个函数的时候,Python找不到这个函数,然后代码生成器再生成这个函数。

不过为了生成Sphinx文档方便,在解析配置之前生成config_parser可能更有道理。这样,Sphinx才能查找到所有支持的Layer,进而生成文档。

1. 使用ConfigParser,解析用户的配置文件`trainer_config.conf`。
* 这时,解析器只返回一个调用图,即Layer与Layer之间的调用关系(`Graph Protobuf`),而不返回真正的`ModelConfig`。
* 这个Graph Protobuf非常简单,只包括调用了哪个Layer,设置了那个Attribute即可
1. 讲这个调用图传递给Paddle Core,生成真正的`ModelConfig`。
Copy link
Member

@QiJune QiJune Mar 21, 2017

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

讲=>将
从调用图GraphProtobuf转换成真正的ModelConfig的具体过程是什么样的,是在哪一步转的啊,是直接把protobuf反序列化吗?

* 对于`GraphProtobuf`中每一个项目,生成每一个LayerConfig。
* 进而顺序执行 `getLayerOutputType`获得这个Layer的输出,并完成神经网络参数推导过程。再将这个LayerConfig传递给下一个Layer。
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

推导的过程是在初始化GradientMachine时做的吗

62 changes: 62 additions & 0 deletions doc/design/layer_generation/01.use_map_in_protobuf.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
# 在Protobuf中支持多种类型的字典字段

## 背景

这项工作的背景是我们要使用代码生成器或者运行时自动生成模型配置函数,并在运行时自动检查配置的正确性。


现阶段如何编写一个Layer呢?可以参考[文章](http://www.paddlepaddle.org/doc/dev/new_layer/index.html)。主体可以分为以下几个步骤:

* 在[Protobuf文件](https://github.com/PaddlePaddle/Paddle/blob/develop/proto/ModelConfig.proto#L284)里,添加里面编写这个Layer需要的参数。如果这个Layer只需要size等常见配置,这个protobuf已经包含,复用即可。但是如果这个Layer有其他自定义的参数,就需要在这个文件里面添加字段。
* 也就是目前新建Layer和修改Protobuf文件是强耦合的。且这个protobuf message已经有了52个字段了。
* 在C++端实现Layer
* 在Python端实现这个Layer的解析函数,Wrapper,V2Layer等等。


这个设计文档,旨在解决 Protobuf文件和Layer之间的耦合性,让用户新建一个Layer的时候不需要改Protobuf。并且,极大的简化Protobuf文件。

## 实现方式

使用Protobuf中的[map](https://developers.google.com/protocol-buffers/docs/proto#maps)和[oneof](https://developers.google.com/protocol-buffers/docs/proto#oneof)将Paddle Potobuf中的配置简化成一个`map<string, variant>`形式。

简单的示例代码为:

```protobuf
message Attribute {
oneof AttributeField {
string s_value = 1;
int i_value = 2;
float f_value = 3;
double d_value = 4;
...
}
}

message LayerConfig {
Copy link
Contributor

@qingqing01 qingqing01 Mar 21, 2017

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

这里说是 "简单的示例代码", LayerConfig其实并不全吧? 最终会降 https://github.com/PaddlePaddle/Paddle/blob/develop/proto/ModelConfig.proto#L284 里所有的属性都以代码生成吗? 主要是指 LayerInputConfig, OperatorConfig等

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

有道理。。LayerInputConfig,OperatorConfig我没考虑周全,那个是一个repeated所以不能这么搞。

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

已经添加实例

required string name = 1;
required string type = 2;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

是否需要description字段,文字描述这个layer?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

这里的LayerConfig是每一个Layer实际的一些参数,例如某一个具体的fc_layer的size是多大,activation是啥。

Description写到了LayerDef里面,LayerDef是说一个FC Layer可以有哪些参数,在那里面加一个Description作为Layer的注释即可。

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

明白了!

map<string, Attribute> attributes = 3;
}
```

其中,每种Layer都有不同的`type`。 而`attributes`作为一个`map`,他的Key可以被每个Layer自己定义。对于一些常见的配置参数,例如`activation`,可以共享一个key。对于一些layer专有属性,可以使用`.`分隔开。例如,对于CTCLayer可以设置`blank`属性,它的Key可以为`ctc.blank`。

这样,实现一个新的Layer,用户就不需要修改Protobuf消息了。并且,用户写一个新的Layer的时候,可以说明自己需要哪些属性,而这些属性的取值范围又是如何的。这样,我们在生成Python配置函数的代码时,可以生成运行时检查的代码。避免用户错误的配置神经网络。

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

这里是用户在C++代码里面说明Layer的属性吗?
然后用户在Python配置Layer时获取这些属性,所以需要在C++中暴露出这个获取属性的api?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

参见第一个00.how_to_write_a_layer.md


## 实现问题

实现这项工作目前来看有如下几个先决条件需要解决:

* 这项工作会修改 `Python <==> Paddle core`中间的protobuf消息定义,对于Python端Layer解析函数,需要有覆盖完整的单元测试,才能保证这一步工作进行完之后,系统行为没有问题。否则,直接修改 Protobuf 风险较高。
* `oneof`与`map`是`protobuf2`语法,但是这是在`Protobuf 3.0`之后的代码库中添加的功能,如果Paddle依赖这个功能,那么Paddle必须依赖Protobuf 3.0以上的Protobuf版本。
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

看到有地方是oneof是比较晚的protobuf2版本才支持,这个有说明文章的链接么,了解下细节

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

https://developers.google.com/protocol-buffers/docs/proto#oneof

我记得官网之前有一些说明,但是现在我找不到了,你可以google再搜一下。。

map和oneof应该是protobuf2的library都不支持的,只有protobuf3的library支持。但是map和oneof是proto2的语法(Syntax)。

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

嗯,好的,我刚才也是搜了下没找到,不过明确了就行了



## 总结

* 最终目的: 用户只需要写Layer的C++实现,剩下的Python代码自动生成
* 阶段目的: 解耦合 Protobuf与Layer的C++实现
* 解决办法: 用`map`和`oneof`,将属性变成一个多种类型的字典
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

这个字典是否可以考虑直接用C++里面的map来做呢?即给每一个Layer定义一个map成员变量,用来描述属性,干脆移除proto中LayerConfig,Attribute这两个message。

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

理论上当然可以。但是现实里会比较麻烦。

Protobuf在这里只是用来做多语言之间的通信协议。如果不使用这个通信协议,那就要直接调用C++的函数。对于比较复杂的消息类型,直接调用C++函数还挺麻烦的。

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

我们需要支持动态图,那还需要确保构造模型的overhead不大。python的protobuf很慢,所以也可以考虑直接通过C++API来构造图是否可行。

* 问题:
* 需要先完善config_parser的单测,增加单测覆盖率
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

新旧两种方式又共存的可能性么,比如老的还在,新的重新在另外一个地方加入,但是parse的时候拼接在一起,然后逐步替换,还是说直接修改老的config_parser更加合理

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

真正实现的时候,肯定还是得一个Attribute一个Attribute的改(估计不是一个Layer一个Layer的改)。。所以会是一个渐近的过程,不会有突变。

* 这会让Paddle强制依赖`Protobuf 3.0+`的Protobuf