你或许也想拥有专属于自己的AI模型文件格式(可视化篇)-(4)

 前言:

        仔细想了一下,本来想要另开一个主题来继续接下来的内容,但是想到可视化专ai模这个步骤是在前面三篇的基础上继续的,因此这里就不打算另开一个主题了。

        如果没有了解过之前内容的人员,或者想要再次回顾之前的内容,可以点击如下的链接按照序号以此查看。

你或许也想拥有专属于自己的AI模型文件格式-(1)你或许也想拥有专属于自己的AI模型文件格式(可视化篇)-(4)https://blog.csdn.net/Pengcode/article/details/121754272你或许也想拥有专属于自己的AI模型文件格式-(2)你或许也想拥有专属于自己的AI模型文件格式(可视化篇)-(4)https://blog.csdn.net/Pengcode/article/details/121776674你或许也想拥有专属于自己的AI模型文件格式-(3)你或许也想拥有专属于自己的AI模型文件格式(可视化篇)-(4)https://blog.csdn.net/Pengcode/article/details/121843704

接下来的目标-(可视化专ai模)

        前三篇文章,我们成功定义了专属于自己的AI模型文件格式,同时在第三篇文章中,也成功地生成了第一个模型文件,这个模型文件是真正意义上的完完全全自定义出来的。毫不夸张地说,恭喜你成功地定义了一套可以叫做onnx-mini的模型。

        可是,总觉得还不够完美,还记得我们上次怎么查看模型内部的信息的吗?我们使用flatc工具把模型解析成了json文本,然后打开json文本查看内部信息,这传出去让别人知道了,感觉得多没面子呀!!一想到别人家的Caffe、Tensorflow、Pytorch都可以可视化,我们的专ai模也势必要拿下可视化这个槛!!

        因此,决定了,接下来的目标就是实现在netron可视化我们的自己专ai模。我们要编译出一份适配我们模型的netron来!!

        或不多说,开干!!!

netron可视化自定义模型格式文件

        之前我采用了flatbuffers实现了自定义模型文件的数据结构描述,得到了后缀名为PzkM的模型。编写了相应的C++代码来生成基于自定义格式的第一个模型文件,上次只是采用了flatc把二进制文件解析成了json文本文件,这样依然不太完美,因此这次就是打算让我们的自定义模型文件可以适配netron,达到可视化的目的。

        这个计划在我源码编译netron的时候就已经陆陆续续地进行着,为此花费了不少时间,因此目标是适配自定义模型,而我采用了flatbuffers工具,为了更好地参考,我以tensorflow lite的tflite这个同样使用了flatbuffers工具来描述模型文件的模型格式作为主要研究对象,试图加快开发速度。

一、netron适配源码解读

        一开始,看到如此庞大的js代码,实在是无所适从。这次采用的直接chrome的开发工具调试,追踪netron的一个按钮,即入口是index.html文件,重点查看一个id=”open-file-buttom”的button标签;button绑定的操作中,其整体流程如下所示:

(1)用户打开一个模型文件后,js获取了模型文件信息(路径、文件名、文件后缀、好像还当作二进制代码进行了读操作);

(2)js根据模型文件信息,根据一定的判断逻辑,判断出该模型文件对应哪个框架,比如.tflite模型文件对应tensorflow lite,那么之后会调用类成员函数require(id)获取到名为tflite.js这个源代码,会export到tflite.js内的模型适配接口,其通过”module.exports.ModelFactory = tflite.ModelFactory;”这句js代码获取到了模型适配接口;

(3)然后调用了ModelFactory.match(context),ModelFactory.open(context,match)这两个接口实现了tflite模型文件的适配工作;

(4)最后netron再调用.open()后的信息绘制出了模型可视化图像(这部分的源码未阅读,后续待解读)

二、tflite的schema的设计思想解读

        tflite也存在一个schema文件,同我们自定义的模型文件类似。因此想要阅读tflite的适配源码,读懂其schmea文件也是非常重要。

        从tflte的设计思想来看,其主要的有向图连接信息主要体现在ops上,ops中同样含有input-id、output-id这些信息,这样也就可以得到连接信息了。

三、flatbuffes在javascript的使用

        因为netron的编程语言是javascript,目前遇到比较棘手的问题就是最新版的flatbuffers对于javascript的支持已经抛弃,需要走schema->typescript->javascript的路线。而flatbuffers官网的关于javascript的教程却没有对应的更新,而且schema->typescript生成的typescript代码是千差万别的,因此不建议跟随flatbuffers官网的关于javascript的教程进行操作(因为无法完全复现官网的教程)。

        通过一通摸索,终于知道了如何在javascript使用flatbuffers工具了。我将继续延续之前的schema文件来说明如何在javascript中来读取我们之前生成的模型,也就是解析我们的专ai模的第一个模型文件。

3.1. 使用flatc编译schema文件为typescript

#/bin/bash

# cd到存放schema文件的目录

$ cd schema-path

# 使用flatc编译器编译schema文件为typescript

$ flatc --ts pzk-schema.fbs

# 将会在当前目录下生成pzk-model的文件夹和pzk-schema.ts文件

$ ls

#pzk-model pzk-schema.ts pzk-schema.fbs

3.2. 安装相关依赖库和工具

        该部分主要有两部分:一部分是flatbuffers在javascript中使用需要在node中进行安装依赖库;第二就是typescript转换到javascript这个步骤需要使用到tsc这个代码转换工具。

        相关的安装命令如下所示:

#/bin/bash

# 全局安装flatbuffer关于javascript的依赖库

$ npm install -g flatbuffers

# 全局安装tsc工具

$ npm install -g typescript

# 以上的库可以不安装在全局环境中,当你希望只在当前工程中使用,那么只需要在去掉-g参数即可;强烈建议你安装在全局环境中,因此这样比较容易使用tsc命令

3.3. typescript->javascript实操

        这部分是至关重要的,因为从这部分开始,按照官网的教程就无法走通了。同时,如果你自己的自定义模型情况不一致,还需要结合我接下的操作实际修改。

3.3.1. 第一步:找出需要转换的主typescript文件

        因为flatc编译器的目标是typescript时,其将会生成多个typescript代码文件。如上所示,之前我所定义的schema生成了一个pzk-schema.ts和一个pzk-model文件夹,这个pzk-model文件夹下拥有多个typescript文件,如下所示:

序号

typescript文件名

跟schema文件对应关系

1

attr-meta.ts

table AttrMeta

2

attributes.ts

table Attributes

3

connect.ts

table Connect

4

data-layout.ts

enum DataLayout

5

data-type.ts

enum DataType

6

layer.ts

table Layer

7

p-model.ts

table PModel

8

tensor-shape.ts

enum DataLayout

9

tensor-type.ts

enum TensorType

10

tensor.ts

table Tensor

11

time.ts

table time

12

weights.ts

table Weights

        因此,我们很容易看出flatc把我们定义的所有数据结构都通过封装成多个typescript文件,而且这些typescript文件的名称非常有规律,就是按照驼峰命名法进行转换,比如我的schema中存在一个叫做AxxxxBxxxxCxxx的数据结构,那么flatc编译成typescript时,那么就会产生一个叫做axxxx-bxxxx-cxxx.ts的文件。

        因此知道了这层关系后,我们就知道该对那个typescript文件进行转换了。没错,就是p-model.ts是我们的主程序文件,因为我们的定义的schema文件中PModel作为了我们的根数据类型。(按照flatbuffers官网的说明,那个最外面的pzk-schema.ts是主程序文件,但是你按照这个思路去转换,你将会发现有的数据结构没有被转换成javascript)。

        因此,我们紧接如下操作。

3.3.2. 第二步:正式转换typescript->javascript

        上步我们知道了主程序文件,将下来使用如下的转换命令:

#/bin/bash

# 使用tsc转换工具

$ tsc pzk-model/p-model.ts

# 清除不必要的typescript文件

$ find . -name "*.ts" |xargs rm -rfv

        至此,操作无误的话,我们就会得到如下的js文件:

#/bin/bash
$ ls pzk-model
:<<!
#得到如下的javascript代码文件
attributes.js  connect.js      data-type.js  p-model.js  tensor-shape.js  time.js

attr-meta.js   data-layout.js  layer.js      tensor.js   tensor-type.js   weights.js
!

3.4. 在javascript中实际使用flatbuffers

        在此将使用上步生成的javascript代码来实际解析读取专ai模的第一个模型文件。

        新建一个javascript文件,我这里取名为try-flatc.js,其内部代码如下所示:

const fs = require('fs');

var flatbuffers = require('flatbuffers');

var PModel = require('./pzk-model/p-model').PModel;

var builder = new flatbuffers.Builder(1024);

var author = builder.createString("name");

var version = builder.createString("v1.0");

var modelname = builder.createString("what fuck");

console.log("try use flatbuffer");

console.log(author == undefined);

console.log("try load custom model file");
// 读取二进制模型文件
var bytes = new Uint8Array(fs.readFileSync('/home/pengzhikang/project/custom-model/build/release/first.PZKM'));
// 使用flatbuffers接口解析二进制文件
var buf = new flatbuffers.ByteBuffer(bytes);
// 从解析后的buf中获取到我们的PModel数据结构体
var mymodel = PModel.getRootAsPModel(buf);
// 获取模型的作者信息
console.log("author is " + mymodel.author());
// 获取模型的版本号
console.log("model version is " + mymodel.version());
// 获取模型的名称
console.log("model name is " + mymodel.modelName());
// 获取模型的创建时间
var model_time = mymodel.createTime();
// 打印时间信息
console.log("mode create time is " + model_time.year() + "/" + model_time.month() + "/"

                + model_time.day() + " " + model_time.hour() + ":" + model_time.min() +

                ":" + model_time.sec());
// 以下是从模型文件中读取出列表的操作
var inputid_array = mymodel.modelRuntimeInputIdArray();
console.log("model runtime input id list is above:");
for(x in inputid_array)
{
    console.log(x + ",");
}
var tensor_array = mymodel.tensorBuffer();
console.log("model tensor length is "+ mymodel.tensorBufferLength());
for (var i = 0; i < mymodel.tensorBufferLength(); i++)
{
    console.log(mymodel.tensorBuffer(i).id() + ":" + mymodel.tensorBuffer(i).name());
}

        运行try-flatc.js文件:

#/bin/bash

$ node try-flatc.js

:<<!

# 其将会打印出如下所示的模型信息:作者、版本号、创建时间、张量信息等

try use flatbuffer

false

try load custom model file

author is pengzhikang

model version is v2.1

model name is holly-model

mode create time is 2021/12/9 23:38:53

model runtime input id list is above:

0,

model tensor length is 4

0:model_input_0

1:tensor_1

2:tensor_2

3:tensor_3

!

        至此,我们在javascript中解析专ai模的第一个模型文件的实例就完成了。

        限于控制篇幅和本人是边开发边写作的情况,所以就有点随性和文章长短不一。请大家多多包涵以及及时提出意见,如果有兴趣一起来进行开发也是可以的,热烈欢迎!

上一篇:在线JSON转typescript工具


下一篇:【TypeScript】TypeScript之Record的用法