Caffe学习(十)protobuf及caffe.proto解析
使用protobuf的原由
一個(gè)好的軟件框架應(yīng)該要有明確的輸入和輸出,對(duì)于CNN網(wǎng)絡(luò)而言,其主要有兩部分組成:網(wǎng)絡(luò)具體結(jié)構(gòu)和網(wǎng)絡(luò)的具體優(yōu)化算法及參數(shù)。對(duì)于框架的使用者而言,用戶只需輸入兩個(gè)描述文件即可得到對(duì)該網(wǎng)絡(luò)的優(yōu)化結(jié)果,這無(wú)疑是非常方便的。
caffe框架選擇使用谷歌的開源protobuf工具對(duì)這兩部分進(jìn)行描述,解析和存儲(chǔ),這一部分為caffe的實(shí)現(xiàn)節(jié)省了大量的代碼。
如前面講述的目標(biāo)檢測(cè)demo,py-faster-rcnn,其主要分為訓(xùn)練和測(cè)試兩個(gè)過(guò)程,兩個(gè)過(guò)程的核心文件都是prototxt格式的文本文件。
如訓(xùn)練過(guò)程
輸入:
(1)slover.prototxt。描述網(wǎng)絡(luò)訓(xùn)練時(shí)的各種參數(shù)文件,如訓(xùn)練的策略,學(xué)習(xí)率的變化率,模型保存的頻率等參數(shù)
(2)train.prototxt。描述訓(xùn)練網(wǎng)絡(luò)的網(wǎng)絡(luò)結(jié)構(gòu)文件。
(3)test.prototxt。描述測(cè)試網(wǎng)絡(luò)的網(wǎng)絡(luò)結(jié)構(gòu)文件。
輸出:
VGG16.caffemodel:保存的訓(xùn)練好的網(wǎng)絡(luò)參數(shù)文件。
protobuf的使用流程
protobuf工具主要是數(shù)據(jù)序列化存儲(chǔ)和解析。在實(shí)際使用的時(shí)候主要是作為一個(gè)代碼自動(dòng)生成工具來(lái)使用,通過(guò)生成對(duì)所定義的數(shù)據(jù)結(jié)構(gòu)的標(biāo)準(zhǔn)讀寫代碼,用戶可以通過(guò)標(biāo)準(zhǔn)的讀寫接口從文件中進(jìn)行數(shù)據(jù)的讀取,解析和存儲(chǔ)。
目前proto支持C++,python,java等語(yǔ)言,這里主要演示caffe中使用的C++調(diào)用。
主要使用過(guò)程為:
(1)編寫XXX.proto文件。該文件里主要定義了各種數(shù)據(jù)結(jié)構(gòu)及對(duì)應(yīng)的數(shù)據(jù)類型,如int,string等。
(2)使用protoc對(duì)XXX.proto文件進(jìn)行編譯,生成對(duì)應(yīng)的數(shù)據(jù)結(jié)構(gòu)文件的讀取和寫入程序,程序接口都是標(biāo)準(zhǔn)化的。生成的文件一般名為XXX.pb.cc和XXX.pb.h。
(3)在新程序中使用XXX.pb.c和XXX.pb.h提供的代碼。
簡(jiǎn)易caffe.proto編寫解析示例
為了后面更加清楚的理解protobuf工具,這里一個(gè)簡(jiǎn)單的caffe.proto為例進(jìn)行solver.prototxt和train.prototxt的解析
caffe.proto文件編寫:
syntax = "proto2";package caffe;//c++ namespacemessage NetParameter {optional string name = 1; // consider giving the network a namerepeated LayerParameter layer = 2; // ID 100 so layers are printed last. }message SolverParameter {optional string train_net = 1;optional float base_lr = 2;optional string lr_policy = 3;optional NetParameter net_param = 4; }message ParamSpec {optional string name = 1;optional float lr_mult = 3 [default = 1.0];optional float decay_mult = 4 [default = 1.0]; } // LayerParameter next available layer-specific ID: 147 (last added: recurrent_param) message LayerParameter {optional string name = 1; // the layer nameoptional string type = 2; // the layer typerepeated string bottom = 3; // the name of each bottom blobrepeated string top = 4; // the name of each top blobrepeated ParamSpec param = 6;// Layer type-specific parameters.optional ConvolutionParameter convolution_param = 106;optional PythonParameter python_param = 130; }message ConvolutionParameter {optional uint32 num_output = 1; // The number of outputs for the layer// Pad, kernel size, and stride are all given as a single value for equal// dimensions in all spatial dimensions, or once per spatial dimension.repeated uint32 pad = 3; // The padding size; defaults to 0repeated uint32 kernel_size = 4; // The kernel sizerepeated uint32 stride = 6; // The stride; defaults to 1 }message PythonParameter {optional string module = 1;optional string layer = 2;// This value is set to the attribute `param_str` of the `PythonLayer` object// in Python before calling the `setup()` method. This could be a number,// string, dictionary in Python dict format, JSON, etc. You may parse this// string in `setup` method and use it in `forward` and `backward`.optional string param_str = 3 [default = '']; }- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
- 41
- 42
- 43
- 44
- 45
- 46
- 47
- 48
- 49
- 50
- 51
- 52
編譯生成caffe.pb.cc與caffe.pb.h文件
protoc caffe.proto --cpp_out=.//在當(dāng)前目錄生成cpp文件及頭文件- 1
編寫測(cè)試文件main.cpp
#include <fcntl.h> #include <unistd.h>#include <iostream> #include <string> #include <google/protobuf/io/coded_stream.h> #include <google/protobuf/io/zero_copy_stream_impl.h> #include <google/protobuf/text_format.h>#include "caffe.pb.h" using namespace caffe; using namespace std;using google::protobuf::io::FileInputStream; using google::protobuf::Message; bool ReadProtoFromTextFile(const char* filename, Message* proto) {int fd = open(filename, O_RDONLY);FileInputStream* input = new FileInputStream(fd);bool success = google::protobuf::TextFormat::Parse(input, proto);delete input;close(fd);return success; }int main() {SolverParameter SGD;if(!ReadProtoFromTextFile("solver.prototxt", &SGD)){cout<<"error opening file"<<endl; return -1;}cout<<"hello,world"<<endl;cout<<SGD.train_net()<<endl;cout<<SGD.base_lr()<<endl;cout<<SGD.lr_policy()<<endl;NetParameter VGG16;if(!ReadProtoFromTextFile("train.prototxt", &VGG16)){cout<<"error opening file"<<endl; return -1;}cout<<VGG16.name()<<endl;return 0; }- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
- 41
- 42
- 43
- 44
- 45
- 46
- 47
- 48
- 49
編寫solver與train網(wǎng)絡(luò)描述文件
solver.prototxt內(nèi)容
train_net: "/home/bryant/cuda-test/train.prototxt" base_lr: 0.001 lr_policy: "step"- 1
- 2
- 3
train.prototxt內(nèi)容:
name: "VGG_ILSVRC_16_layers" layer {name: 'input-data'type: 'Python'top: 'data'top: 'im_info'top: 'gt_boxes'python_param {module: 'roi_data_layer.layer'layer: 'RoIDataLayer'param_str: "'num_classes': 2"} }layer {name: "conv1_1"type: "Convolution"bottom: "data"top: "conv1_1"param {lr_mult: 0decay_mult: 0}param {lr_mult: 0decay_mult: 0}convolution_param {num_output: 64pad: 1kernel_size: 3} }- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
編譯鏈接,生成main
g++ caffe.pb.cc main.cpp -o main -lprotobuf- 1
運(yùn)行結(jié)果
bryant@bryant:~/cuda-test/src$ ./main hello,world /home/bryant/cuda-test/train.prototxt 0.001 step VGG_ILSVRC_16_layers bryant@bryant:~/cuda-test/src$總結(jié)
以上是生活随笔為你收集整理的Caffe学习(十)protobuf及caffe.proto解析的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: faster-rcnn系列assert
- 下一篇: Caffe学习系列(17):模型各层数据