找回密码
 立即注册
查看: 182|回复: 0

Cmake动态编译Protobuf

[复制链接]
发表于 2022-6-3 05:52 | 显示全部楼层 |阅读模式
protobuf简介

protobuf是一种混合语言的数据标准:通过结构化数据进行序列化(串行化),用于通讯协议、数据存储等领域。
通常描述protobuf,有两个层面:

  • 在表现形式上,定义了一种源文件,扩展名为.proto,可以在其中定义存储类的内容;同时,protobuf有自己的专门编译器protoc(后面会介绍如何安装),可以将.protoc编译成.cc和.h文件,使之能在C++/Python工程中直接使用的类
  • 在本质上,定义了一种二进制数据交换格式,可以将C++/Python中定义的存储类的内容(结构化数据)二进制序列相互转换,主要用于数据存储和传输。
protobuf使用流程

目前proto支持C++,python,java等语言,这里主要演示caffe中使用的C++调用。

  • 编写XXX.proto文件。该文件里主要定义了各种数据结构及对应的数据类型,如int,string等。
  • 使用protoc对XXX.proto文件进行编译,生成对应的数据结构文件的读取和写入程序,程序接口都是标准化的。生成的文件一般名为http://XXX.pb.cc和XXX.pb.h。
  • 在新程序中使用XXX.pb.c和XXX.pb.h提供的代码。
syntax = "proto2";

package caffe;//c++ namespace

message NetParameter {
  optional string name = 1; // consider giving the network a name
  repeated LayerParameter layer = 2;  // ID 100 so layers are printed last.
}

// LayerParameter next available layer-specific ID: 147 (last added: recurrent_param)
message LayerParameter {
  optional string name = 1; // the layer name
  optional string type = 2; // the layer type
  repeated string bottom = 3; // the name of each bottom blob
  repeated string top = 4; // the name of each top blob

  // Layer type-specific parameters.
  optional ConvolutionParameter convolution_param = 106;
}

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 0
  repeated uint32 kernel_size = 4; // The kernel size
  repeated uint32 stride = 6; // The stride; defaults to 1
}其中,syntax 代表用的是proto版本号,package 对应C++的namespace,message 对应C++的类。
包声明(package):proto文件以package声明开头,有助于区分不同项目之间的命名冲突。在C++以package声明的文件内容对应生成的类,放在与包匹配的namesapce中,上面的.proto文件中声明都属于caffe。
字段声明(message): protobuf中定义一个消息类型是通过关键字message字段指定的,类似C++中class关键字,该类公开继承自google::protobuf::Message。(用Message关键字声明的消息体,允许你检查、增删改查整个消息,包括解析二进制字符串以及序列化二进制字符串等方法)
字段规则:1、required:消息体中必填字段,不设置会导致编解码异常;2、optional:消息体中可选字段,可通过defalut关键字设置默认值;3、repeated:消息体中可重复字段,重复的值的顺序会被保留。
总结,在一个AI训练的模型中,主要包括了模型的定义net_def模型的权重net_weight。而protobuf在其中起到的作用就是基于.proto文件以及prototxt文件构建出对应C++/Python的graph模型结构的定义(net_def),而模型权重,通常存储在caffe的blob数据结构中,可以从onnx或caffe.bin中读取。
Cmake编译protobuf

大致可以分为三个步骤:
1、下载对应版本protobuf release版本
https://github.com/protocolbuffers/protobuf/releases2、这篇是cmake和protobuf的结合使用,所以我这里安装的是protobuf-cpp-3.6.1.tar.gz
$ tar xf protobuf-cpp-3.6.1.tar.gz
$ cd protobuf-3.6.1
$ ./configure
$ make
$ sudo make install 3、编写 cmake 来自动产生 proto 对应的 .cc 和 .h 文件,文件名分别是caffe.pb.cc和caffe.pb.h
cmake_minimum_required(VERSION 3.10)
project(nart_proto)

# 查找 protobuf
find_package(Protobuf REQUIRED)
if (PROTOBUF_FOUND)
    message("protobuf found")
else ()
    message(FATAL_ERROR "Cannot find Protobuf")
endif ()

# 编译 proto 为 .cpp 和 .h
file(GLOB NART_PROTOS *.proto)
PROTOBUF_GENERATE_CPP(PROTO_SRCS PROTO_HDRS ${NART_PROTOS})

message("PROTO_SRCS = ${PROTO_SRCS}")
message("PROTO_HDRS = ${PROTO_HDRS}")

# 将PROTO_SRCS生成静态库nart_proto.a文件
add_library(nart_proto STATIC ${PROTO_SRCS})

target_include_directories(nart_proto
        PUBLIC ${CMAKE_CURRENT_BINARY_DIR}
        PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}
        PUBLIC ${PROTOBUF_INCLUDE_DIRS})

# 关联 protobuf 到最后的二进制文件,生成可执行文件
add_executable(cmake_protobuf
        src/main.cpp

        ${PROTO_SRCS}
        ${PROTO_HDRS})

target_link_libraries(cmake_protobuf nart_proto)
懒得打字嘛,点击右侧快捷回复 【右侧内容,后台自定义】
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

小黑屋|手机版|Unity开发者联盟 ( 粤ICP备20003399号 )

GMT+8, 2024-11-26 22:25 , Processed in 0.088916 second(s), 25 queries .

Powered by Discuz! X3.5 Licensed

© 2001-2024 Discuz! Team.

快速回复 返回顶部 返回列表