• <noscript id="e0iig"><kbd id="e0iig"></kbd></noscript>
  • <td id="e0iig"></td>
  • <option id="e0iig"></option>
  • <noscript id="e0iig"><source id="e0iig"></source></noscript>
  • caffe源碼 數據結構 google protobuf

    標簽: caffe源碼  數據結構  protobuf

    caffe的數據結構,除了使用blob作為數據塊,大部分的數據結構都用proto文件來定義。

    我們為表達網絡結構所寫prototxt文件就是protobuf讀取的文件,從其中,protobuf可以獲取層、參數的設置,反饋NetParameter、LayerParameter等重要初始化信息用于網絡、層的建立和設置。

    caffe編譯時,第一個編譯的就是caffe.proto,它是所有文件的基礎。

    什么是protobuf,為什么選用它?

    Google Protocol Buffer( 簡稱 Protobuf) 是 Google 公司內部的混合語言數據標準,目前已經正在使用的有超過 48,162 種報文格式定義和超過 12,183 個 .proto 文件。他們用于 RPC 系統和持續數據存儲系統。

    Protocol Buffers 是一種輕便高效的結構化數據存儲格式,可以用于結構化數據串行化,或者說序列化。它很適合做數據存儲或 RPC 數據交換格式。可用于通訊協議、數據存儲等領域的語言無關、平臺無關、可擴展的序列化結構數據格式。目前提供了 C++、Java、Python 三種語言的 API。

    Protocol buffers是一種靈活,高效,自動化的方案,用于解決這類問題。有了protocol buffers, 你可以編寫.proto文件去存儲你想描述的數據結構。Protocol buffers編譯器會創造一個類來將protocol buffer數據自動編碼和解析成高效的二進制格式。生成的類為protocol buffer中的字段提供了getters和setters接口,而且還把讀寫protocal的細節封裝成了一個單元。最重要的,protocol buffer支持擴展格式,隨著時間的推移,這樣的代碼仍然可以用舊的格式讀取數據編碼。

    通過使用,我們可以直觀的了解它的作用及用法,使用方法:


    1.定義你的protocol format,寫.proto:

    .proto文件是十分簡單的:你需要為每個你想序列化的數據結構寫一個消息message,并為每一個在消息里的字段指定名稱和類型。

    1.1 *.proto文件中數據類型可以分為兩大類:

    復合數據類型 + 標準數據類型

    復合數據類型包括:枚舉和message類型

    標準數據類型包含:整型,浮點,字符串等

    1.2 數據類型前面修飾詞:

    ①required: 必須賦值,不能為空,否則該條message會被認為是“uninitialized”。build一個“uninitialized” message會拋出一個RuntimeException異常,解析一條“uninitialized” message會拋出一條IOException異常。除此之外,“required”字段跟“optional”字段并無差別。

    ②optional:字段可以賦值,也可以不賦值。假如沒有賦值的話,會被賦上默認值。對于簡單的類型, 您可以指定自己的默認值, [default=HIT]。否則,會用系統提供的值:數值類型為0,字符類型為空, 布爾類型為false。對于嵌入式消息,默認值總是“默認實例”或“原型”這些消息里沒有設置的字段。調用訪問器來獲得一個可選的(或要求)字段的值(沒有被顯式地設置),總是會返回字段的默認值的.

    ③repeated: 該字段可以重復任意次數,包括0次。重復數據的順序將會保存在protocol buffer中,將這個字段想象成一個可以自動設置size的數組就可以了,repeated字段將作動態數組。

    1.3.每個字段要給數字:

    該Number是用來標記該字段在序列化后的二進制數據中所在的field,每個字段的Number在message內部都是獨一無二的。也不能進行改變,否則數據就不能正確的解包。

    1.4 數據類型

    Protobuf支持的基本數據類型的表


    1.5 例子

    這里有一個.proto文件已經定義好你的消息addressbook.proto,引自官方教程:

    https://developers.google.com/protocol-buffers/docs/cpptutorial

    syntax = "proto2";
    
    package tutorial;//包名稱聲明,預防命名沖突,生成的充當數據結構的類會被放在相應的命名空間中。
    
    message Person {//用message定義一個數據結構
      required string name = 1;
      required int32 id = 2;
      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 phones = 4;//可加多個電話號碼和電話類型
    }
    
    message AddressBook {
      repeated Person people = 1;//嵌套數據類型
    }
    消息message: 一個消息只是一些類型字段的集合。許多標準簡單的數據類型可以作為字段的類型,包括bool,int32,float,double和string。你還可以進一步構建你的消息通過使用其他消息類型作為字段類型——在上面的例子中,Person消息包含了PhoneNumber消息,而AddressBook消息也包含了Person消息。你甚至可以定義消息類型嵌套在其他消息中——如你所見,PhoneNumber類型在Person中定義。您還可以定義枚舉類型,如果你想你的一個字段有一個預定義的值列表——在這里你想指定一個電話號碼可以是MOBILE,HOME,WORK。


    每個元素中的“= 1”,“= 2”標記符是識別使用的二進制編碼字段的獨特的“標簽”。標簽號碼1-15要求的字節會比號碼高的少點,所以你想優化一下,你可以使用這些標簽用于常用的或repeated元素,把標簽16和更高的標簽給那些不常用或optional元素。每一個repeated的元素需要重新編碼標記號,所以repeated字段特別適合優化。


    2.編譯Protocol Buffers:

    現在你已經有了.proto文件,你需要做的下一件事是生成你需要read and write AddressBook(和后面的Person和PhoneNumber)消息的類。要做到這一點,您需要運行protocol buffer編譯器protoc編譯你的.proto :

    現在運行編譯器, 指定源碼目錄(你的應用源碼呆的地方——如果你不提供這個值,默認為現在的目錄),目標目錄(你希望生成代碼的目錄;通常會與源碼目錄相同),和你的.proto文件的路徑。在這種情況下,你...:

    protoc -I=$SRC_DIR --cpp_out=$DST_DIR $SRC_DIR/addressbook.proto

    因為你想用C++的類,所以你要寫--cpp_out選項——類似的選項對其他受支持的語言也有提供,例如java:--java_out,python:--python_out

    這個會在你指定目標目錄下生成下列文件c++:

    • addressbook.pb.h,聲明你生成的類的頭文件。//caffe編譯caffe.proto生成的caffe.pb.h被很多重要類引用,實現數據結構的創建和使用
    • addressbook.pb.cc, 包含你的類的實現文件。

    python會生成 addressbook_pb2.py


    3.Protocol Buffer的API

    讓我們來看看一些生成的代碼,看看編譯器生成了哪些類和函數給你。如果你看了tutorial.pb.h,你可以看到,你有一個您在tutorial.proto中指定每個消息的類。 再看看Person類,您可以看到,編譯為每個字段生成了訪問器。比如,對于name,id,email,和phone字段,c++你會有這些方法


        // name  
          inline bool has_name() const;  
          inline void clear_name();  
          inline const ::std::string& name() const;  
          inline void set_name(const ::std::string& value);  
          inline void set_name(const char* value);  
          inline ::std::string* mutable_name();  
          
          // id  
          inline bool has_id() const;  
          inline void clear_id();  
          inline int32_t id() const;  
          inline void set_id(int32_t value);  
          
          // email  
          inline bool has_email() const;  
          inline void clear_email();  
          inline const ::std::string& email() const;  
          inline void set_email(const ::std::string& value);  
          inline void set_email(const char* value);  
          inline ::std::string* mutable_email();  
          
          // phone  
          inline int phone_size() const;  
          inline void clear_phone();  
          inline const ::google::protobuf::RepeatedPtrField< ::tutorial::Person_PhoneNumber >& phone() const;  
          inline ::google::protobuf::RepeatedPtrField< ::tutorial::Person_PhoneNumber >* mutable_phone();  
          inline const ::tutorial::Person_PhoneNumber& phone(int index) const;  
          inline ::tutorial::Person_PhoneNumber* mutable_phone(int index);  
          inline ::tutorial::Person_PhoneNumber* add_phone();  

    getters有完整的名稱包含小寫的字段,setter函數始于set_。還有has_函數為每個單獨的字段(required和optional)驗證是否已經被設置。最后,每個字段都有一個clear_函數使該字段重置到空的狀態。

    然而,數字類型id字段只有基本的set,而name和email字段因為是字符串,所以有一對額外的函數。——一個讓你可以得到一個直接指向字符串的指針(可修改目標)的mutable_ getter,和一個額外的setter。注意,您可以調用mutable_email(),即使email還沒有設置;它將被自動初始化為一個空字符串。如果你有一個單獨的消息字段在這個例子中,它還將會有一個mutable_函數但不會是一個set_函數。

    Repeated字段也有一些特殊的函數——看repeated phone字段的函數,你可以發現

    • 檢查repeated字段的_size(換句話說,有多少電話號碼與這個Person有關)。
    • 得到一個使用其索引指定的電話號碼。
    • 在指定的索引中更新現有的電話號碼。
    • 添加另一個您可以編輯的電話號碼的消息(repeated標量類型有一個add_可以讓你使用新值)。


    python比較不同,并不直接生成數據訪問代碼,而是生成特定的描述器為所有messages, enums, and fields,和一些空類,每個對應一種數據類型:

    class Person(message.Message):
      __metaclass__ = reflection.GeneratedProtocolMessageType
    
      class PhoneNumber(message.Message):
        __metaclass__ = reflection.GeneratedProtocolMessageType
        DESCRIPTOR = _PERSON_PHONENUMBER
      DESCRIPTOR = _PERSON
    
    class AddressBook(message.Message):
      __metaclass__ = reflection.GeneratedProtocolMessageType
      DESCRIPTOR = _ADDRESSBOOK

    __metaclass__ = reflection.GeneratedProtocolMessageType這個很重要,可當作用于創建類的模板。加載時,GeneratedProtocolMessageType metaclass用特定的描述器來創建所有的python方法,可以使用Person class 當作它 定義了 each field of the Message base class as a regular field,例如:

    import addressbook_pb2
    person = addressbook_pb2.Person()
    person.id = 1234
    person.name = "John Doe"
    person.email = "[email protected]"
    phone = person.phones.add()
    phone.number = "555-4321"
    phone.type = addressbook_pb2.Person.HOME


    4.caffe.proto 中選段編譯:

    取了caffe.proto 中關于Blob結構定義的部分,單獨取出來:

    syntax = "proto2";
    
    package blob_paractice;
    
    // Specifies the shape (dimensions) of a Blob.
    message BlobShape {
      repeated int64 dim = 1 [packed = true];
    }
    
    message BlobProto {
      optional BlobShape shape = 7;
      repeated float data = 5 [packed = true];
      repeated float diff = 6 [packed = true];
      repeated double double_data = 8 [packed = true];
      repeated double double_diff = 9 [packed = true];
    
      // 4D dimensions -- deprecated.  Use "shape" instead.
      optional int32 num = 1 [default = 0];
      optional int32 channels = 2 [default = 0];
      optional int32 height = 3 [default = 0];
      optional int32 width = 4 [default = 0];
    }
    

    然后進到目錄里編譯:

    protoc --cpp_out=./ ./blob.proto

    生成了blob.pb.h     blob.pb.cc,其中blob.pb.h:

    namespace blob_paractice {
    
    // Internal implementation detail -- do not call these.
    void protobuf_AddDesc_blob_2eproto();
    void protobuf_AssignDesc_blob_2eproto();
    void protobuf_ShutdownFile_blob_2eproto();
    
    class BlobProto;
    class BlobShape;
    
    // ===================================================================
    
    class BlobShape : public ::google::protobuf::Message /* @@protoc_insertion_point(class_definition:blob_paractice.BlobShape) */ {
     public:
      BlobShape();
      virtual ~BlobShape();
    
      BlobShape(const BlobShape& from);
    
      inline BlobShape& operator=(const BlobShape& from) {
        CopyFrom(from);
        return *this;
      }

    這段程序之前有一些頭文件引用,省略了,之后還有一些定義了類的功能部分也略去了,只看咱們要用的API部分:

      // nested types ----------------------------------------------------
    
      // accessors -------------------------------------------------------
    
      // repeated int64 dim = 1 [packed = true];
      int dim_size() const;
      void clear_dim();
      static const int kDimFieldNumber = 1;
      ::google::protobuf::int64 dim(int index) const;
      void set_dim(int index, ::google::protobuf::int64 value);
      void add_dim(::google::protobuf::int64 value);
      const ::google::protobuf::RepeatedField< ::google::protobuf::int64 >&
          dim() const;
      ::google::protobuf::RepeatedField< ::google::protobuf::int64 >*
          mutable_dim();

    從上面,可以清楚的看到對BlobShape結構中repeated int64 dim = 1 [packed = true];的功能:

    大小、清理、查看、設置、重復定義和mutable_指針獲取

    當然還有BlobProto的:

      // nested types ----------------------------------------------------
    
      // accessors -------------------------------------------------------
    
      // optional .blob_paractice.BlobShape shape = 7;
      bool has_shape() const;
      void clear_shape();
      static const int kShapeFieldNumber = 7;
      const ::blob_paractice::BlobShape& shape() const;
      ::blob_paractice::BlobShape* mutable_shape();
      ::blob_paractice::BlobShape* release_shape();
      void set_allocated_shape(::blob_paractice::BlobShape* shape);
    
      // repeated float data = 5 [packed = true];
      int data_size() const;
      void clear_data();
      static const int kDataFieldNumber = 5;
      float data(int index) const;
      void set_data(int index, float value);
      void add_data(float value);
      const ::google::protobuf::RepeatedField< float >&
          data() const;
      ::google::protobuf::RepeatedField< float >*
          mutable_data();
    
      // repeated float diff = 6 [packed = true];
      int diff_size() const;
      void clear_diff();
      static const int kDiffFieldNumber = 6;
      float diff(int index) const;
      void set_diff(int index, float value);
      void add_diff(float value);
      const ::google::protobuf::RepeatedField< float >&
          diff() const;
      ::google::protobuf::RepeatedField< float >*
          mutable_diff();
    
      // repeated double double_data = 8 [packed = true];
      int double_data_size() const;
      void clear_double_data();
      static const int kDoubleDataFieldNumber = 8;
      double double_data(int index) const;
      void set_double_data(int index, double value);
      void add_double_data(double value);
      const ::google::protobuf::RepeatedField< double >&
          double_data() const;
      ::google::protobuf::RepeatedField< double >*
          mutable_double_data();
    
      // repeated double double_diff = 9 [packed = true];
      int double_diff_size() const;
      void clear_double_diff();
      static const int kDoubleDiffFieldNumber = 9;
      double double_diff(int index) const;
      void set_double_diff(int index, double value);
      void add_double_diff(double value);
      const ::google::protobuf::RepeatedField< double >&
          double_diff() const;
      ::google::protobuf::RepeatedField< double >*
          mutable_double_diff();
    
      // optional int32 num = 1 [default = 0];
      bool has_num() const;
      void clear_num();
      static const int kNumFieldNumber = 1;
      ::google::protobuf::int32 num() const;
      void set_num(::google::protobuf::int32 value);
    
      // optional int32 channels = 2 [default = 0];
      bool has_channels() const;
      void clear_channels();
      static const int kChannelsFieldNumber = 2;
      ::google::protobuf::int32 channels() const;
      void set_channels(::google::protobuf::int32 value);
    
      // optional int32 height = 3 [default = 0];
      bool has_height() const;
      void clear_height();
      static const int kHeightFieldNumber = 3;
      ::google::protobuf::int32 height() const;
      void set_height(::google::protobuf::int32 value);
    
      // optional int32 width = 4 [default = 0];
      bool has_width() const;
      void clear_width();
      static const int kWidthFieldNumber = 4;
      ::google::protobuf::int32 width() const;
      void set_width(::google::protobuf::int32 value);

    一應功能,說來就來,方便快捷,運行效率有保證。
    版權聲明:本文為qq_28660035原創文章,遵循 CC 4.0 BY-SA 版權協議,轉載請附上原文出處鏈接和本聲明。
    本文鏈接:https://blog.csdn.net/qq_28660035/article/details/80360073

    智能推薦

    Netty -08- Google Protobuf

    編碼和解碼的基本介紹 編寫網絡應用程序時,因為數據在網絡中傳輸的都是二進制字節碼數據,在發送數據時就需要編碼,接收數據 時就需要解碼 codec(編解碼器) 的組成部分有兩個:decoder(解碼器)和 encoder(編碼器)。encoder 負責把業務數據轉換成字節 碼數據,decoder 負責把字節碼數據轉換成業務數據 Netty 本身的編碼解碼的機制和問題分析 Netty 自身提供了一些 ...

    十一、Google Protobuf 編解碼

    Protobuf是一個靈活、高效、結構化的數據序列化框架,相比于XML等傳統的序列化工具,它更小、更快、更簡單。Protobuf支持數據結構化一次可以到處使用,甚至跨語言使用,通過代碼生成工具可以自動生成不同語言版本的源代碼,甚至可以在使用不同版本的數據結構進程間進行數據傳遞,實現數據結構的前向兼容。 一、Protobuf環境搭建 開發環境:Win10 64 bit; JDK 1.8; proto...

    google protobuf (c++) 學習

    probuf是goole推出的微型RPC框架,這里記錄下安裝測試。 參考文章: Google Protocol Buffers淺析(一) 一、Ubuntu 18.04安裝 C++ Protocol 首先參考官方README文檔進行安裝: 前提 當然可以在如下網站進行源碼下載離線安裝。 https://github.com/protocolbuffers/protobuf/releases/late...

    網頁搜索引擎中的核心索引結構 - 利用 Google Protobuf 構建

    索引結構 — Index 利用 Google Protobuf 構建索引結構 —– Index 在搜索引擎中,常見的索引方法就是正排索引和倒排索引,因此我們 Index 索引結構要包括兩兩個方面: 正排索引 — ( forward_index ) 倒排索引 — ( inverted_index ) 正排索引 正排索引是根據文件的id號,得...

    【C++】Google Protocol Buffer(protobuf)詳解

    1、簡介 Google Protocol Buffer( 簡稱 Protobuf) 是 Google 公司內部的混合語言數據標準, Protocol Buffers 是一種輕便高效的結構化數據存儲格式,可以用于結構化數據串行化,或者說序列化。它很適合做數據存儲或 RPC 數據交換格式。可用于通訊協議、數據存儲等領域的語言無關、平臺無關、可擴展的序列化結構數據格式。目前提供了 C++、Java、Py...

    猜你喜歡

    使用CSharp編寫Google Protobuf插件

    什么是 Google Protocol Buffer? Google Protocol Buffer( 簡稱 Protobuf) 是 Google 公司內部的混合語言數據標準,目前已經正在使用的有超過 48,162 種報文格式定義和超過 12,183 個 .proto 文件。他們用于 RPC 系統和持續數據存儲系統。 Protocol Buffers 是一種輕便高效的結構化數據存儲格式,可以用于結...

    【JAVA】google protobuf 3.0 安裝使用

    一開始從官網下載的protobuf 3.3.0的最新版本,但是編譯安裝的時候有bug,回退到3.0穩定版本 下載鏈接 tar.gz解壓后安裝 tar -zxvf xxx.tar.gz ./configure --prefix=/home/protobuf make make install 寫proto文件 生成java文件 序列化寫入磁盤文件并讀取出來...

    HTML中常用操作關于:頁面跳轉,空格

    1.頁面跳轉 2.空格的代替符...

    freemarker + ItextRender 根據模板生成PDF文件

    1. 制作模板 2. 獲取模板,并將所獲取的數據加載生成html文件 2. 生成PDF文件 其中由兩個地方需要注意,都是關于獲取文件路徑的問題,由于項目部署的時候是打包成jar包形式,所以在開發過程中時直接安照傳統的獲取方法沒有一點文件,但是當打包后部署,總是出錯。于是參考網上文章,先將文件讀出來到項目的臨時目錄下,然后再按正常方式加載該臨時文件; 還有一個問題至今沒有解決,就是關于生成PDF文件...

    電腦空間不夠了?教你一個小秒招快速清理 Docker 占用的磁盤空間!

    Docker 很占用空間,每當我們運行容器、拉取鏡像、部署應用、構建自己的鏡像時,我們的磁盤空間會被大量占用。 如果你也被這個問題所困擾,咱們就一起看一下 Docker 是如何使用磁盤空間的,以及如何回收。 docker 占用的空間可以通過下面的命令查看: TYPE 列出了docker 使用磁盤的 4 種類型: Images:所有鏡像占用的空間,包括拉取下來的鏡像,和本地構建的。 Con...

    精品国产乱码久久久久久蜜桃不卡