Caffe代碼導讀(1):Protobuf例子_參數傳遞

來源:互聯網
上載者:User

Protobuf是一種可以實現記憶體與外存交換的協議介面。這是由Google開發的開源工具,目前研究Caffe源碼時用到。

一個軟體項目 = 資料結構 + 演算法 + 參數,對於資料結構和演算法我們都已經有較多研究,但不同開發人員對參數管理卻各有千秋。有人喜歡TXT格式化的參數檔案,有人喜歡BIN簡單高效,也有人喜歡圖形化介面的直觀。不一致的參數管理帶來很多問題,例如一個項目組內不同成員必須約定一套統一的參數方案,或者稱為通訊協定,這樣便於模組整合。而Protobuf工具就完美解決了這個問題,關鍵區段代碼自動產生,節省了大量的開發、調試時間。


首先下載protobuf,地址(打不開。……不解釋)

這裡用Linux版本2.5.0

解壓:

tar zxvf protobuf-2.5.0.tar.gz

切到主目錄:

cd protobuf-2.5.0

編譯:

./configure

make

sudo make install


添加環境變數:

export PKG_CONFIG_PATH=$(pwd)


編譯examples:

cd examples/

make cpp

這裡我們只編譯C++代碼。


編譯完成,產生了以下可執行檔:

add_person_cpp

list_people_cpp

這是個通訊錄的例子。我們首先運行add_person_cpp:

./add_person_cpp zykzyk: File not found.  Creating a new file.Enter person ID number: 123Enter name: zhaoyongkeEnter email address (blank for none): zhaoyongke@yeah.netEnter a phone number (or leave blank to finish): 188188188Is this a mobile, home, or work phone?(斷行符號)Unknown phone type.  Using default.Enter a phone number (or leave blank to finish):(斷行符號)

然後運行list_people_cpp:

./list_people_cpp zykPerson ID: 123  Name: zhaoyongke  E-mail address: zhaoyongke@yeah.net  Home phone #: 188188188

可見我們產生了新的通訊錄zyk,裡面儲存了相應的資訊。


例子運行結束了,我們看下代碼是如何產生的。

protobuf使用前,先編寫proto檔案,這是描述我們需要配置參數的資料結構。這個例子裡面的proto如下:

// See README.txt for information and build instructions.package tutorial;option java_package = "com.example.tutorial";option java_outer_classname = "AddressBookProtos";message Person {  required string name = 1;  required int32 id = 2;        // Unique ID number for this person.  optional string email = 3;  enum PhoneType {    MOBILE = 0;    HOME = 1;    WORK = 2;  }  message PhoneNumber {    required string number = 1;    optional PhoneType type = 2 [default = HOME];  }  repeated PhoneNumber phone = 4;}// Our address book file is just one of these.message AddressBook {  repeated Person person = 1;}

前幾行是定義包的,可以忽略。

message Person{...}定義了一個需要傳輸的參數結構體,可見包括這麼幾個單元:name(string類型)、id(int32類型)、email(string類型)、phone(PhoneNumber類型,嵌套在Person內的類)。前面標記為“required”是必須有值的,而“optional“則為可選項,”repeated“表示後面單元為相同類型的一組向量。


有了如上定義,我們可以用protobuf工具產生介面代碼,命令如下:

protoc --cpp_out=.  addressbook.proto

運行後產生了兩個檔案:addressbook.pb.cc 和addressbook.pb.h,代碼比較長就不貼了。我們的應用程式可以通過自動產生的介面實現參數的序列化/還原序列化,代碼如下:

//add_person.c#include <iostream>#include <fstream>#include <string>#include "addressbook.pb.h"using namespace std;// This function fills in a Person message based on user input.void PromptForAddress(tutorial::Person* person) {  cout << "Enter person ID number: ";  int id;  cin >> id;  person->set_id(id);  cin.ignore(256, '\n');  cout << "Enter name: ";  getline(cin, *person->mutable_name());  cout << "Enter email address (blank for none): ";  string email;  getline(cin, email);  if (!email.empty()) {    person->set_email(email);  }  while (true) {    cout << "Enter a phone number (or leave blank to finish): ";    string number;    getline(cin, number);    if (number.empty()) {      break;    }    tutorial::Person::PhoneNumber* phone_number = person->add_phone();    phone_number->set_number(number);    cout << "Is this a mobile, home, or work phone? ";    string type;    getline(cin, type);    if (type == "mobile") {      phone_number->set_type(tutorial::Person::MOBILE);    } else if (type == "home") {      phone_number->set_type(tutorial::Person::HOME);    } else if (type == "work") {      phone_number->set_type(tutorial::Person::WORK);    } else {      cout << "Unknown phone type.  Using default." << endl;    }  }}// Main function:  Reads the entire address book from a file,//   adds one person based on user input, then writes it back out to the same//   file.int main(int argc, char* argv[]) {  // Verify that the version of the library that we linked against is  // compatible with the version of the headers we compiled against.  GOOGLE_PROTOBUF_VERIFY_VERSION;  if (argc != 2) {    cerr << "Usage:  " << argv[0] << " ADDRESS_BOOK_FILE" << endl;    return -1;  }  tutorial::AddressBook address_book;  {    // Read the existing address book.    fstream input(argv[1], ios::in | ios::binary);    if (!input) {      cout << argv[1] << ": File not found.  Creating a new file." << endl;    } else if (!address_book.ParseFromIstream(&input)) {      cerr << "Failed to parse address book." << endl;      return -1;    }  }  // Add an address.  PromptForAddress(address_book.add_person());  {    // Write the new address book back to disk.    fstream output(argv[1], ios::out | ios::trunc | ios::binary);    if (!address_book.SerializeToOstream(&output)) {      cerr << "Failed to write address book." << endl;      return -1;    }  }  // Optional:  Delete all global objects allocated by libprotobuf.  google::protobuf::ShutdownProtobufLibrary();  return 0;}

可見只需要調用addressbook.pb.h中聲明的tutorial::AddressBook類、Person類中的介面(add_person(), add_phone(), set_number(), set_email()等)就能操作相應的參數,最後將記憶體中的參數序列化為檔案只需要執行SerializeToOstream()。相應的讀取參數檔案的操作為ParseFromIstream()。這裡貼出例子中的第二個程式如下:

// list_people.c#include <iostream>#include <fstream>#include <string>#include "addressbook.pb.h"using namespace std;// Iterates though all people in the AddressBook and prints info about them.void ListPeople(const tutorial::AddressBook& address_book) {  for (int i = 0; i < address_book.person_size(); i++) {    const tutorial::Person& person = address_book.person(i);    cout << "Person ID: " << person.id() << endl;    cout << "  Name: " << person.name() << endl;    if (person.has_email()) {      cout << "  E-mail address: " << person.email() << endl;    }    for (int j = 0; j < person.phone_size(); j++) {      const tutorial::Person::PhoneNumber& phone_number = person.phone(j);      switch (phone_number.type()) {        case tutorial::Person::MOBILE:          cout << "  Mobile phone #: ";          break;        case tutorial::Person::HOME:          cout << "  Home phone #: ";          break;        case tutorial::Person::WORK:          cout << "  Work phone #: ";          break;      }      cout << phone_number.number() << endl;    }  }}// Main function:  Reads the entire address book from a file and prints all//   the information inside.int main(int argc, char* argv[]) {  // Verify that the version of the library that we linked against is  // compatible with the version of the headers we compiled against.  GOOGLE_PROTOBUF_VERIFY_VERSION;  if (argc != 2) {    cerr << "Usage:  " << argv[0] << " ADDRESS_BOOK_FILE" << endl;    return -1;  }  tutorial::AddressBook address_book;  {    // Read the existing address book.    fstream input(argv[1], ios::in | ios::binary);    if (!address_book.ParseFromIstream(&input)) {      cerr << "Failed to parse address book." << endl;      return -1;    }  }  ListPeople(address_book);  // Optional:  Delete all global objects allocated by libprotobuf.  google::protobuf::ShutdownProtobufLibrary();  return 0;}

相信做完這個實驗,你將不再對Caffe代碼中的參數初始化、參數儲存操作感到陌生,一切都很自然。

 除了上述簡易功能,Protobuf還可以用來傳遞不同語言(C/C++與Java、Python)之間的參數,省去了自己手動維護資料結構的繁瑣工作。也可以支援用戶端/伺服器模式,在主機/從機之間傳遞參數。

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.