TFLite: flatbuffers

总述:

FlatBuffers 是一个序列化开源库,实现了与 Protocol Buffers,Thrift,Apache Avro,SBE 和 Cap'n Proto 类似的序列化格式,主要由 Wouter van Oortmerssen 编写,并由 Google 开源。Oortmerssen 最初为 Android 游戏和注重性能的应用而开发了FlatBuffers。现在它具有C ++,C#,C,Go,Java,PHP,Python 和 JavaScript 的端口。

FlatBuffer 是一个二进制 buffer,它使用 offset 组织嵌套对象(struct,table,vectors,等),可以使数据像任何基于指针的数据结构一样,就地访问数据。然而 FlatBuffer 与大多数内存中的数据结构不同,它使用严格的对齐规则和字节顺序来确保 buffer 是跨平台的。此外,对于 table 对象,FlatBuffers 提供前向/后向兼容性和 optional 字段,以支持大多数格式的演变。

FlatBuffers 的主要目标是避免反序列化。这是通过定义二进制数据协议来实现的,一种将定义好的将数据转换为二进制数据的方法。由该协议创建的二进制结构可以 wire 发送,并且无需进一步处理即可读取。相比较而言,在传输 JSON 时,我们需要将数据转换为字符串,通过 wire 发送,解析字符串,并将其转换为本地对象。Flatbuffers 不需要这些操作。你用二进制装入数据,发送相同的二进制文件,并直接从二进制文件读取。

通过flatc 编译schema文件描述的数据结构,生成序列化和反序列化的文件,可以直接使用该文件。

对tensorflow lite而言,已经得到序列化后的的模型文件,从中解析出 tensor(训练出的参数)和操作符等,然后让输入数据流过解析出的固化网络,经过各种运算后得到输出。

flatbuffers/samples: flatbuffers官方提供的demo 路径;

http://google.github.io/flatbuffers/flatbuffers_guide_use_cpp.html

how to use Flatbuffers

https://github.com/google/flatbuffers/blob/master/samples/sample_binary.cpp

flatbuffers数据类型


FlatBuffers 支持的数据结构有:基本类型和复杂类型。

基本类型: 
8 bit:  byte     ubyte     bool
16 bit: short     ushort
32 bit: int     uint     float
64 bit: long     ulong     double
3 个特殊的类型:SOffsetT、UOffsetT、VOffsetT。
SOffsetT 存储的是一个有符号的 offset,
UOffsetT 存储的是数组数据的无符号的 offset,
VOffsetT 存储的是 vtable 中的无符号的 offset。
SOffsetT int32,它的 size = 4;UOffsetT uint32,它的 size = 4;VOffsetT uint16,它的 size = 2。

复杂类型:
数组 (用中括号表示 [type]). 不支持嵌套数组,可以用table实现
字符串 string, 支持 UTF-8 或者 7-bit ASCII. 对于其他编码可以用数组 [byte]或者[ubyte]表示。
Struct 只支持基本类型或者嵌套Struct
Table 类似Struct,但是可以支持任何类型。

基本的数据类型,只有标量值可以有默认值,非标量(string/vector/table)字段默认不存在时为null。

其中数据类型table最为灵活常用,可以向前后兼容,table的seriale也最复杂。

请参考

http://coolpers.github.io/android/2016/03/14/android-flatbuffers-brief.html

flatc安装:


编译安装工具flatc工具
首先要先装Cmake(apt install cmake)
(1)下载FlatBuffers源码,从gitHub上下载项目源代码:

git clone https://github.com/google/flatbuffers.git

(2)进入flatbuffers项目根目录,输入如下命令
cmake -G "Unix Makefiles" //生成MakeFile
make //生成flatc
make install //安装flatc

(3)查看flatc
➜  flatbuffers git:(master) flatc --version
flatc version 1.10.0

./include/flatbuffers/flatbuffers.h
➜  flatbuffers git:(master) pwd
/home/ws/code/flatbuffers/include/

g++ -std=c++11 ./test.cpp -I /home/ws/code/flatbuffers/include/

 

test.fbs

namespace TestApp;                                                                                                                                                                                                 
struct KV {
 key: ulong;
 value: double;
}
 
table TestObj {
 id:ulong;
 name:string;
 flag:ubyte = 0;
 list:[ulong];
 kv:KV;
}
 
root_type TestObj;

test.cpp

  #include "test_generated.h"                                                                                                                                                                                      
  #include <vector>
  #include <iostream>
   
  using namespace std;
  using namespace TestApp;
   
  int main()
  {
      flatbuffers::FlatBufferBuilder builder;
   
      /////////// Serialize //////////
      // Create list 
      std::vector<uint64_t> vec;
      for(size_t i=0;i<10;i++)
      {   
          vec.push_back(i);
      }   
      // Create flat buffer inner type
      auto id = 123;
      auto name = builder.CreateString("name");
      auto list = builder.CreateVector(vec); // vector
      uint8_t flag = 1;
      auto kv = KV(1, 1.0); // struct
      // table
      auto mloc = CreateTestObj(builder, id, name, flag, list, &kv);
      builder.Finish(mloc);
   
      char* ptr = (char*)builder.GetBufferPointer();
>>    uint64_t size = builder.GetSize();
      
      ////////// Deserialize //////////
      auto obj = GetTestObj((uint8_t*)ptr);
   
      cout << obj->id() << endl;
      cout << obj->name()->c_str() << endl;
      cout << obj->flag() << endl;
      for(size_t i=0;i<obj->list()->size();i++)
      {   
          cout << obj->list()->Get(i) << endl;
      }   
   
      // can use assign to std::vector for speed up
      // vec.reserve(obj->list()->size());
      // vec.assign(obj->list()->begin(), obj->list()->end());
   
      cout << obj->kv()->key() << endl;
      cout << obj->kv()->value() << endl;
   
  }

compile and run

➜  learning_test g++ -std=c++11 ./test.cpp -I /home/ws/code/flatbuffers/include/
➜  learning_test ./a.out 
123
name
//这里为什么是乱码?
0
1
2
3
4
5
6
7
8
9
1
1

生成的文件test_generated.h

其中g++ -std=c++11 ./test.cpp -I /home/ws/code/flatbuffers/include/

参数 -I 指的是 "flatbuffers/flatbuffers.h"所在路径 (编译依赖flatbuffers的源码)

#include "flatbuffers/flatbuffers.h"                                                                                                                                                                               

namespace TestApp {