2021年前后,大量的推理框架和训练框架层出不穷;训练框架有较新的Pytorch、TensorFlow,和老的Caffe、Darknet等;推理框架中有各种国产的、开源的,特别是边缘设备上的框架Ncnn、Tengine等;另外,国产的CANN更是兼顾了训练和推理两方面。
但是,以上所有的框架基本是拥有一种专属于自己的模型文件。比如caffe由.prototxt和.caffemodel文件组成,darknet由.cfg和.weight文件组成,pytorch由.pt组成,tensorflow lite由.tflite组成。它们按照一定的规则组成了整个模型描述,包括了有向图信息、权重数据、连接关系等一切的一切。
也许你会问:既然已经存在了这么多种类的模型格式,那我们何必要自定义一种自己的格式呢?如果一定要我胡说八道的话,那就是“有助于构建自己的AI框架;你的代码量将会得到提升....."。hhhhh,其实只是好玩,更是因为有成就感罢了,特别是如果你也拥有专属于自己的AI模型文件格式的话。
因此,你或许也想拥有专属于自己的AI模型文件格式,你现在就可以想好它的格式名称了,可以是.holly、.love等,随君所爱哈。
万事开头难,自定义一个专属的AI模型文件格式(后续为了简化,我将简称“专属于自己的AI模型文件格式”为“专ai模”),需要我们拥有一个整体的规划,好事多磨嘛。以下是本人的本次制作专爱模的整体规划。
序号 | 制作流程 |
1 | 了解现有的模型文件格式的信息组成以及自己的需求 |
2 | 制作环境准备、工具安装等事宜 |
3 | 专ai模的信息组成描述编写 |
4 | 为专爱模提供对应的操作的API,特别是生成模型、读模型等方面的功能需要编写 |
5 | 测试,或者是更多的特性开发 |
那么我话不多说,直接开干吧。
这里企图得到一份自定义的模型描述文件,在此主要探讨一份关于模型的描述文件应该定义哪些信息呢。如果从通用性来讲,应该怎么定义一个描述文件;从最小描述量来讲,又该如何描述这份文件;等等问题,以待探讨。
从工作流程上来说,我们想要得到一份自己的模型描述文件,这需要从自身的需求入手。即我们希望自定义的模型应该包含哪些信息。不管是什么模型文件,基本是具备如下所示的信息,如下表所示:
序号 |
信息 |
说明 |
1 |
模型注解 |
主要是作为附属信息嵌入到了文件内,对模型推理和训练可有可无。最常见的就是类似于作者信息、模型生成时间、版本号、模型描述版本号等 |
2 |
数据类型 |
这个数据类型不是单纯的像是编程语言中的基本数据类,而是包含了多层次、多属性的数据类型。其包含了最基本的数据类型,比如bool、int4、uint4、uint8、int8、fp16、fp32、量化类型(qint*)等;又包括了描述某层的输入是常量还是运行时Tensor等这类的描述;除上述所述外,还有其他的方面。 |
3 |
层描述 |
主要是用于描述模型中的网络层信息,一般而言:一个网络层在模型文件中拥有输入输出描述、附属描述(用于推理时或者是训练的必不可少的信息,比如卷积层的步长、是否补齐等信息)。特别地,层描述的输入输出决定了模型的有向图描述,当然,也可能是编写Table来描述模型的有向图。 |
4 |
张量描述 |
张量描述,即是构成有向图的边,也包括了比如权重张量等的描述在内。 |
从上面这张表格,我们可以看出如果专ai模拥有模型注解、数据类型、层描述以及张量描述,那么使用专ai模可以近乎完美地构建任何一个模型,管他什么语音识别还是目标检测等模型,统统可以变成专ai模的格式。
在进行环境和工具的搭建之前,需要说明一下这一步骤的重要性和必要性。
如果不了解现有的AI框架的模型文件格式,也许你会选择直接操控二进制来作为自己的专ai模,又或者是直接编写txt文本来描述自己的专ai模。但是我们可以预见:自己完全操控二进制文件将会使得我们难以解析和改变模型,加大了后续的开发难度,同时也难以维护;而编写txt文本确实拥有容易修改和解析的好处,但是要知道模型文件里面可是拥有海量的权重信息的,试想一下在电脑上打开一个拥有10m甚至100m float数据的文本将是什么体验——我只能说毫无体验。
因此,我在这里推荐两个数据协议编写工具,分别是ProtoBuffers和FlatBuffers。你可任选其中一个作为自己后续的开发工具,你所选择的开发工具将会成为描述你的专ai模的利器。
如果你接触过caffe训练框架或者是接触过服务器-客户端的网络协议的话,或许对这个工具会有所了解甚至已经非常熟悉。不管怎样,我还是说明以下这个ProtoBuffers,我以caffe训练框架作为举例来说明该具体的作用和体现的地方:
caffe训练框架是如何解析一个caffe模型的呢,.caffemodel和.prototxt组成了一个caffe模型,其中.prototxt是一个文本文件,是可以随意编辑的;而caffemodel是一个权重文件,这个权重文件包含的不仅仅是权重,准确来说是存放了带参的blob信息,这个结论我们可以从caffe.proto的描述看出:
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
// The train / test phase for computation.
optional Phase phase = 10;
// The amount of weight to assign each top blob in the objective.
// Each layer assigns a default value, usually of either 0 or 1,
// to each top blob.
repeated float loss_weight = 5;
// Specifies training parameters (multipliers on global learning constants,
// and the name and other settings used for weight sharing).
repeated ParamSpec param = 6;
// The blobs containing the numeric parameters of the layer.
repeated BlobProto blobs = 7;
//后续的是layer_param信息......
}
上述的BlobProto就是所有带参的blob,而参数保存在了.caffemodel内,准确来说,caffe中组成一个层需要得到prototxt的一个层的json描述和.caffemodel内对应的带权重的blob信息,举例来说就是如下所示:
# 这是一层卷积层的prototxt内的描述
layer {
name: "conv_conv1"
type: "Convolution"
# bottom表示该层的输入blob的名称
bottom: "data"
# 带有权重的blob是保存在了.caffemodel内,
# 这里无法看出来,保存的时候采用了ProtoBuffers工具保存
# top表示该层的输出blob的名称
top: "conv_conv1"
# *_param表示卷积的其他参数描述
convolution_param {
num_output: 96
kernel_size: 7
stride: 2
pad: 3
}
}
caffe就是靠着caffe.proto描述了一个模型格式,接着用ProtoBuffers来解析模型和加载权重的,如果你有兴趣,可以去以下的链接观看caffe.proto的全貌:
Caffe.proto的官方链接https://github.com/BVLC/caffe/blob/master/src/caffe/proto/caffe.proto 同Caffe类似的,我们只需要实现一份专ai模的.proto文件就可以定义自己的模型格式了,后续我们可以使用ProtoBuffers工具来解析和生成专ai模的模型文件了。
该工具因为官网的安装文档比较齐全,所以直接在这里放置官网的安装教程的链接,请点击此处进入ProtoBuffer安装教程界面https://github.com/protocolbuffers/protobuf/blob/master/src/README.md 如果实在有困难安装该工具的,可以在下方评论或者私信我。
FlatBuffers和ProtoBuffers的目的是一致的,就是实现数据协议的制定。在FlatBuffers的使用场景中,我们只需要实现一份自己的.fbs,后续就可以用FlatBuffers来解析和生成专ai模的模型文件了。
目前我了解到的使用了FlatBuffers来作为模型描述工具的有armnn、tensorflow lite、onnx等。后续我选用的是FlatBuffers工具进行过开发,所以建议读者也选用这个工具继续开发,可以减少读者的麻烦。
因为FlatBuffers官网的安装教程比较少,因此我在这里写下安装教程。
首先下载好FlatBuffers的源码:
wget -O flatbuffer.zip https://codeload.github.com/google/flatbuffers/zip/refs/heads/master
然后解压压缩包然后进入对应目录:
unzip flatbuffer.zip
cd flatbuffers-master/
开始编译:
# 使用cmake 构建工程
cmake -G "Unix Makefiles" -DCMAKE_BUILD_TYPE=Release
# 开始编译
make -j16
# 安装
make install
测试是否安装成功:
# 如果安装成功,将会显示flatc版本号
flatc --version
介于篇幅太多,我将会拆分出多个文章进行说明,尽请期待。