真真接触caffe,在电脑上成功安装且运行caffe也有半年多时间了 
之前做了不少训练和调参之类的工作,看了一些论文,了解了一些模型,如今有必要去更深地去了解一下Caffe框架了,也觉得需要去写点东西了,今天姑且把Protobuf这个东东写一下吧。 
1、Protobuf 
什么是Protobuf? 
Protobuf是由Google开发的一种可以实现内存与非易失存储介质(如硬盘文件)交换的协议接口。 
protobuf 是一个灵活、高效,使用自动化机制的结构化数据序列工具,类似于XML,但比XML更小巧、更快、而且也更简单。只需要定义一次数据结构,你就可以使用代码生成器生成各种编程语言和各种流式文件的结构化读取和写入。甚至可以在无需重新编译部署新程序的情况下更新新的结构化数据。 
Caffe源码中大量使用Protobuf作为权重和模型参数的载体。利用protoc编译能让协议细节等关键部分代码自动生成,所以使用Protobuf工具可以节省大量的开发和调试时间。 
prtotocol buffer是google于2008年开源的一款非常优秀的序列化反序列化工具,caffe中的参数管理基本都是由它实现的。 
既然Protobuf这么好,那该怎么用? 
一、Protobuf消息定义

消息由至少一个字段组合而成,类似于C语言中的结构。每个字段都有一定的格式。 
字段格式:限定修饰符① | 数据类型② | 字段名称③ | = | 字段编码值④ | [字段默认值⑤]

首先,我们用一个实例说明。在这里我们定义一个搜索请求消息的格式:每一条搜索请求有一个string类型的请求,一个我们希望搜索的页数,以及每一页期望返回多少结果。那么我们可以在.proto文件中定义以下的结构:

message SearchRequest{required string query = 1;optional int32 page_number = 2;optional int32 result_per_page = 3;
}

添加更多的消息类型

多个消息类型可以定义在同一个.proto文件内,这对定义多个有关联的消息是是十分有用的。例如,如果你想定义一个用于回复SearchResponse消息,你可以像这样在.proto内添加。

message SearchRequest {  required string query = 1;  optional int32 page_number = 2;  optional int32 result_per_page = 3;
}  message SearchResponse {  ...
}
message SearchRequest {  required string query = 1;  optional int32 page_number = 2;  optional int32 result_per_page = 3;
}  message SearchResponse {  ...
}  

1)限定修饰符包含 required\optional\repeated

Required(必须的): 表示是一个必须字段,必须相对于发送方,在发送消息之前必须设置该字段的值,对于接收方,必须能够识别该字段的意思。发送之前没有设置required字段或者无法识别required字段都会引发编解码异常,导致消息被丢弃。

Optional(可选的):表示是一个可选字段,可选对于发送方,在发送消息时,可以有选择性的设置或者不设置该字段的值。对于接收方,如果能够识别可选字段就进行相应的处理,如果无法识别,则忽略该字段,消息中的其它字段正常处理。—因为optional字段的特性,很多接口在升级版本中都把后来添加的字段都统一的设置为optional字段,这样老的版本无需升级程序也可以正常的与新的软件进行通信,只不过新的字段无法识别而已,因为并不是每个节点都需要新的功能,因此可以做到按需升级和平滑过渡。

Repeated(重复的):表示该字段可以包含0~N个元素。其特性和optional一样,但是每一次可以包含多个值。可以看作是在传递一个数组的值。 
因为历史的原因:repeated字段如果是基本的数字类型的话会无法编码。新的代码应该使用特殊的关键字[packed=true] 来使其得到有效的编码.例如

repeated int32 samples = 4 [packed=true];
  • 注意:你应该小心将字段设置为required,如果你希望在某些情况下取消required字段的读写,它将改变字段为optional属性,旧的的读取方将会认为此消息不完全。可能会无意的将其丢弃。你应该考虑自定义一个消息检查程序。google的一些工程师认为使用optinal字段的好处大于required。但是显然这个观点并不是通用的。

(2)数据类型 

(3)字段名称

字段名称的命名与C、C++、Java等语言的变量命名方式几乎是相同的。

protobuf建议字段的命名采用以下划线分割的驼峰式。例如 first_name 而不是firstName.

(4)字段编码值

有了该值,通信双方才能互相识别对方的字段。当然相同的编码值,其限定修饰符和数据类型必须相同。编码值的取值范围为 1~2^32(4294967296)。其中 1~15的编码时间和空间效率都是最高的,编码值越大,其编码的时间和空间效率就越低(相对于1-15),当然一般情况下相邻的2个值编码效率的是相同的,除非2个值恰好实在4字节,12字节,20字节等的临界区。比如15和16,还有1900~2000编码值为Google protobuf 系统内部保留值,建议不要在自己的项目中使用。

protobuf 还建议把经常要传递的值把其字段编码设置为1-15之间的值。消息中的字段的编码值无需连续,只要是合法的,并且不能在同一个消息中有字段包含相同的编码值。

建议:项目投入运营以后涉及到版本升级时的新增消息字段全部使用optional或者repeated,尽量不实用required。

(4)默认值

当在传递数据时,对于required数据类型,如果用户没有设置值,则使用默认值传递到对端。当接受数据是,对于optional字段,如果没有接收到optional字段,则设置为默认值。 
如果一个optional字段没有被指定其默认值。其默认值被自动替换为:

1.字符串:为空字符串.

2.bool:为false.

3.数字类型:为0;

4.枚举值:为第一个枚举值

例如:设置optional域默认值的语法是:

optional int32 restult_per_page = 3 [default = 10];

二、注意事项

(1)关于import

protobuf 接口文件可以像C语言的h文件一个,分离为多个,在需要的时候通过 import导入需要对文件。其行为和C语言的#include或者java的import的行为大致相同。

(2)关于package

避免名称冲突,可以给每个文件指定一个package名称,对于java解析为java中的包。对于C++则解析为名称空间。

(3)关于message

支持嵌套消息,消息可以包含另一个消息作为其字段。也可以在消息内定义一个新的消息。 
例如,我们希望在一个message中使用另一个message类型,则可以使用如下方法:

message SearchResponse{repeated Result result = 1;
}message Result{required string url = 1;optional string title = 2;repeated string snippets = 3;
}

(4)关于enum

枚举的定义和C++相同,但是有一些限制。

枚举值必须大于等于0的整数。

使用分号(;)分隔枚举变量而不是C++语言中的逗号(,)

当我们需要定义Message中的一个域,这个域的取值是我们预定义的一个集合中的一个元素。比如说,我们要在SearchRequest中添加一个域,这个域的取值是:UNIVERSAL, WEB, IMAGES, LOCAL, NEWS, PRODUCTS或者VIDEO中的一个,这时我们就需要枚举来帮忙了。

通过使用枚举,我们可以在message中添加一个枚举域,在这个域中定义一些常量。示例代码:

    message SearchRequest{required string query = 1;optional int32 page_numer =2;optional int32 result_per_page = 3[default = 10];enum Corpus{UNIVERAL = 0;WEB = 1;IMAGES = 2;LOCAL = 3;NEWS = 4;PRODUCTS = 5;VIDEO = 6;}optional Corpus corpus = 4 [default = UNIVERSAL];}

我们还可以在枚举中设置多个name对应一个相同的值,这是protocol buffer的别名机制(alias)。当然,我们必须首先设置这个别名,即,在enum中将allow_alias的选项设置为true。代码示例:

    enum EnumAllowingAlias{option allow_alias = true;UNKOWN = 0;STARTED = 1;RUNNING = 1;    }enum EnumNotAllowingAlias{UNKNOWN = 0;STARTED = 1;}

枚举类型必须能够用32bit整数表示,并且由于编码效率原因不建议使用负数。我们还可以在.proto文件中利用已经声明的枚举类型来声明一个域的类型。在不同message中可以使用相同的枚举类型。通过MessageType.EnumType使用(与C++中对象使用的方式类似)。

还有许多许多的需要详细阅读Google Developers中的文档https://developers.google.com/protocol-buffers/docs/proto

.proto文件会生成什么?

当你使用protobuf编译器编译一个.proto文件,它会生成在.proto内你描述的消息类型的操作代码,这些代码是根据你所选择的编程功能语言决定的。这些操作代码内包含了设置字段值 和读取字段值,以及序列化到输出流 和 从输入流反序列化。

C++:编译器会按照每个.proto文件生成与其对应的.h和.cc文件,每个消息类似都有独立的消息操作类。

Java:编译器将会生成一个.java文件和一个操作类,此操作类为所有消息类型所共有, 使用一个特别的Builder类为每个消息类型实例化.

Python:有一点不同 – 编译器会为每个消息生成一个模块每个模块有一个静态描述符, 该模块与一个元类在运行时创建一个需要的数据操作类。

参考 
http://www.cnblogs.com/yymn/p/5167013.html 
http://www.cnblogs.com/yymn/p/4483370.html 
http://www.cnblogs.com/yymn/p/4483370.html 
http://blog.csdn.net/sylar_d/article/details/51325987 
https://developers.google.com/protocol-buffers/docs/proto 
https://developers.google.com/protocol-buffers/docs/overview?csw=1

Caffe学习1 :ProtoBuffer相关推荐

  1. Caffe学习(一) —— caffe介绍和推荐学习资料

    介绍 Caffe(Convolutional Architecture for Fast Feature Embedding)是由伯克利视觉和学习中心(Berkeley Vision and Lear ...

  2. Caffe学习系列(8):solver优化方法

    Caffe学习系列(8):solver优化方法 上文提到,到目前为止,caffe总共提供了六种优化方法: Stochastic Gradient Descent (type: "SGD&qu ...

  3. CAFFE学习笔记(一)Caffe_Example之训练mnist

     CAFFE学习笔记(一)Caffe_Example之训练mnist 0.参考文献 [1]caffe官网<Training LeNet on MNIST with Caffe>;  [ ...

  4. Caffe学习系列(23):如何将别人训练好的model用到自己的数据上

    caffe团队用imagenet图片进行训练,迭代30多万次,训练出来一个model.这个model将图片分为1000类,应该是目前为止最好的图片分类model了. 假设我现在有一些自己的图片想进行分 ...

  5. Caffe学习系列(22):caffe图形化操作工具digits运行实例

    上接:Caffe学习系列(21):caffe图形化操作工具digits的安装与运行 经过前面的操作,我们就把数据准备好了. 一.训练一个model 右击右边Models模块的" Images ...

  6. Caffe学习系列(21):caffe图形化操作工具digits的安装与运行

    经过前面一系列的学习,我们基本上学会了如何在linux下运行caffe程序,也学会了如何用python接口进行数据及参数的可视化. 如果还没有学会的,请自行细细阅读: caffe学习系列:http:/ ...

  7. Caffe学习系列(19): 绘制loss和accuracy曲线

    转载自: Caffe学习系列(19): 绘制loss和accuracy曲线 - denny402 - 博客园 http://www.cnblogs.com/denny402/p/5110204.htm ...

  8. Caffe学习系列(18): 绘制网络模型

    转载自: Caffe学习系列(18): 绘制网络模型 - denny402 - 博客园 http://www.cnblogs.com/denny402/p/5106764.html python/dr ...

  9. Caffe学习系列(17):模型各层特征和过滤器可视化

    转载自: Caffe学习系列(17):模型各层特征和过滤器可视化 - denny402 - 博客园 http://www.cnblogs.com/denny402/p/5105911.html cif ...

  10. Caffe学习系列(16):各层权值参数可视化

    原文有更新: Caffe学习系列(16):各层权值参数可视化 - denny402 - 博客园 http://www.cnblogs.com/denny402/p/5103425.html 通过前面的 ...

最新文章

  1. 组合模式java怎么获取钥匙_java中组合模式详解和使用方法
  2. stl_alloc.h分配器
  3. python需要学多长时间
  4. android stringbuilder 一次插入多条数据_android开发面试题解析
  5. qt调用外部程序(exe)
  6. Confluence 6 SQL 异常的问题解决
  7. 向量化编程:arrayfun及cellfun函数的使用
  8. 12306为什么要安装根证书
  9. 基于HTTP协议的Java文件传输
  10. JavaSE,JavaEE,JavaME区别
  11. php yml,YAML、YML在线编辑器(格式化校验)
  12. CTF---图片隐写相关
  13. 马哥教育开学感想随笔
  14. Ubuntu16.04《解压7z.001文件》
  15. win7计算机睡眠快捷键,Win7系统在桌面创建睡眠模式快捷键的方法
  16. 苹果蓝牙耳机怎么样?与airpods媲美的无线耳机推荐
  17. 2022-2028年全球及中国红外(IR)传感器行业投资前景分析
  18. 「牛客网C」初学者入门训练BC156
  19. 20220607跌破建议零售价,GPU市场正全面走向供过于求...
  20. 硅谷一万清华人,为何打不过印度人

热门文章

  1. 07- HTTP协议详解及Fiddler抓包
  2. 二逼程序员与苦逼程序员
  3. SQL Server 中WITH (NOLOCK)
  4. 【LDAP】LDAP常用命令解析
  5. 实用 —— PowerCLI (二)
  6. CentOS下的sudo相关配置的总结归纳
  7. Android开发学习总结(五)——Android应用目录结构分析(转)
  8. 人和人之间不要靠的太近
  9. 【C】C99 restrict 关键字
  10. wifi破解到局域网渗透