基于libonnx环境简要分析一下mnist网络算子结构,关于环境搭建可以参考前面两篇文章:

xboot大神的libonnx环境搭建

使用netron实现对onnx模型结构可视化


本文主要目的是搞清楚mnist各层之间数据shape的变化情况,关于什么是shape,引用一本书中的介绍:

"在tensorflow中,使用张量来表示计算图中的所有数据,张量在计算图的节点之间流动,张量可以看成N维数组,而数组的维数就是张量的阶数。因此,0阶张量对应标量数据,1阶张量对应一维数组,也就是向量。二阶张量对应二维数组,也就是矩阵,以此类推,N阶张量对应n维数组,例如,一张RGB图像可以表示为3阶张量,而多张RGB图构成的数据可以表示为4阶张量。shape(形状)代表的就是张量的一种属性,当然还有其他属性,比如数据类型等等"

再算子执行前面打断点,依次观察输入数据和输出数据的大小:

(gdb) b 2124
Breakpoint 2 at 0x555555560ef8: file onnx.c, line 2124.
(gdb) display n->inputs[0]->ndata
(gdb) display n->outputs[0]->ndata
(gdb) c
Continuing.
Breakpoint 2, onnx_run (ctx=0x555555a501e0) at onnx.c:2124
2124					n->operator(n);
1: n->inputs[0]->ndata = 2560
2: n->outputs[0]->ndata = 2560
(gdb) c
Continuing.

Breakpoint 2, onnx_run (ctx=0x555555a501e0) at onnx.c:2124
2124					n->operator(n);
1: n->inputs[0]->ndata = 784
2: n->outputs[0]->ndata = 6272
(gdb) c
Continuing.

Breakpoint 2, onnx_run (ctx=0x555555a501e0) at onnx.c:2124
2124					n->operator(n);
1: n->inputs[0]->ndata = 6272
2: n->outputs[0]->ndata = 6272
(gdb) c
Continuing.

Breakpoint 2, onnx_run (ctx=0x555555a501e0) at onnx.c:2124
2124					n->operator(n);
1: n->inputs[0]->ndata = 6272
2: n->outputs[0]->ndata = 6272
(gdb) c
Continuing.

Breakpoint 2, onnx_run (ctx=0x555555a501e0) at onnx.c:2124
2124					n->operator(n);
1: n->inputs[0]->ndata = 6272
2: n->outputs[0]->ndata = 1568
(gdb) c
Continuing.

Breakpoint 2, onnx_run (ctx=0x555555a501e0) at onnx.c:2124
2124					n->operator(n);
1: n->inputs[0]->ndata = 1568
2: n->outputs[0]->ndata = 3136
(gdb) c
Continuing.

Breakpoint 2, onnx_run (ctx=0x555555a501e0) at onnx.c:2124
2124					n->operator(n);
1: n->inputs[0]->ndata = 3136
2: n->outputs[0]->ndata = 3136
(gdb) c
Continuing.

Breakpoint 2, onnx_run (ctx=0x555555a501e0) at onnx.c:2124
2124					n->operator(n);
1: n->inputs[0]->ndata = 3136
2: n->outputs[0]->ndata = 3136
(gdb) c
Continuing.

Breakpoint 2, onnx_run (ctx=0x555555a501e0) at onnx.c:2124
2124					n->operator(n);
1: n->inputs[0]->ndata = 3136
2: n->outputs[0]->ndata = 256
(gdb) c
Continuing.

Breakpoint 2, onnx_run (ctx=0x555555a501e0) at onnx.c:2124
2124					n->operator(n);
1: n->inputs[0]->ndata = 256
2: n->outputs[0]->ndata = 256
(gdb) c
Continuing.

Breakpoint 2, onnx_run (ctx=0x555555a501e0) at onnx.c:2124
2124					n->operator(n);
1: n->inputs[0]->ndata = 256
2: n->outputs[0]->ndata = 10
(gdb) c
Continuing.

Breakpoint 2, onnx_run (ctx=0x555555a501e0) at onnx.c:2124
2124					n->operator(n);
1: n->inputs[0]->ndata = 10
2: n->outputs[0]->ndata = 10
(gdb) c
Continuing.

可以看出一个简单的规律,就是前一级网络的输出size等于后一级网络的输入size.

对照网络,可以完全对应的上:

将shape打印出(由dims表示),可以看出和上图完全吻合。(图中一维向量表示为1*N,也看成2维的shape).

Breakpoint 3, onnx_run (ctx=0x5555559ff250) at onnx.c:2124
2124					n->operator(n);
1: n->inputs[0]->ndata = 2560
2: n->outputs[0]->ndata = 2560
3: n->inputs[0]->ndim = 4
4: n->outputs[0]->ndim = 2
(gdb) c
Continuing.

Breakpoint 3, onnx_run (ctx=0x5555559ff250) at onnx.c:2124
2124					n->operator(n);
1: n->inputs[0]->ndata = 784
2: n->outputs[0]->ndata = 6272
3: n->inputs[0]->ndim = 4
4: n->outputs[0]->ndim = 4
(gdb) c
Continuing.

Breakpoint 3, onnx_run (ctx=0x5555559ff250) at onnx.c:2124
2124					n->operator(n);
1: n->inputs[0]->ndata = 6272
2: n->outputs[0]->ndata = 6272
3: n->inputs[0]->ndim = 4
4: n->outputs[0]->ndim = 4
(gdb) c
Continuing.

Breakpoint 3, onnx_run (ctx=0x5555559ff250) at onnx.c:2124
2124					n->operator(n);
1: n->inputs[0]->ndata = 6272
2: n->outputs[0]->ndata = 6272
3: n->inputs[0]->ndim = 4
4: n->outputs[0]->ndim = 4
(gdb) c
Continuing.

Breakpoint 3, onnx_run (ctx=0x5555559ff250) at onnx.c:2124
2124					n->operator(n);
1: n->inputs[0]->ndata = 6272
2: n->outputs[0]->ndata = 1568
3: n->inputs[0]->ndim = 4
4: n->outputs[0]->ndim = 4
(gdb) c
Continuing.

Breakpoint 3, onnx_run (ctx=0x5555559ff250) at onnx.c:2124
2124					n->operator(n);
1: n->inputs[0]->ndata = 1568
2: n->outputs[0]->ndata = 3136
3: n->inputs[0]->ndim = 4
4: n->outputs[0]->ndim = 4
(gdb) 
Continuing.

Breakpoint 3, onnx_run (ctx=0x5555559ff250) at onnx.c:2124
2124					n->operator(n);
1: n->inputs[0]->ndata = 3136
2: n->outputs[0]->ndata = 3136
3: n->inputs[0]->ndim = 4
4: n->outputs[0]->ndim = 4
(gdb) 
Continuing.

Breakpoint 3, onnx_run (ctx=0x5555559ff250) at onnx.c:2124
2124					n->operator(n);
1: n->inputs[0]->ndata = 3136
2: n->outputs[0]->ndata = 3136
3: n->inputs[0]->ndim = 4
4: n->outputs[0]->ndim = 4
(gdb) 
Continuing.

Breakpoint 3, onnx_run (ctx=0x5555559ff250) at onnx.c:2124
2124					n->operator(n);
1: n->inputs[0]->ndata = 3136
2: n->outputs[0]->ndata = 256
3: n->inputs[0]->ndim = 4
4: n->outputs[0]->ndim = 4
(gdb) 
Continuing.

Breakpoint 3, onnx_run (ctx=0x5555559ff250) at onnx.c:2124
2124					n->operator(n);
1: n->inputs[0]->ndata = 256
2: n->outputs[0]->ndata = 256
3: n->inputs[0]->ndim = 4
4: n->outputs[0]->ndim = 2
(gdb) 
Continuing.

Breakpoint 3, onnx_run (ctx=0x5555559ff250) at onnx.c:2124
2124					n->operator(n);
1: n->inputs[0]->ndata = 256
2: n->outputs[0]->ndata = 10
3: n->inputs[0]->ndim = 2
4: n->outputs[0]->ndim = 2
(gdb) 
Continuing.

Breakpoint 3, onnx_run (ctx=0x5555559ff250) at onnx.c:2124
2124					n->operator(n);
1: n->inputs[0]->ndata = 10
2: n->outputs[0]->ndata = 10
3: n->inputs[0]->ndim = 2
4: n->outputs[0]->ndim = 2
(gdb) 
Continuing.

然后再以ndim为上限,索引dims,还是以reshape为例:

可以看出和netron解析的图中reshape模块的shape完全吻合:

darknet网络举例:

netron不但可以解析onnx格式的模型文件,还支持darknet中 .cfg格式的文件,比如:

 不过貌似N,C,W,H的排列有所差别,在上面mnist网络中,顺序是,个数X通道数X长度X高度

而darknet的cfg中,对于输出数据,是WxHxC的方式,也即是宽X长X通道号,但是对于每个算子节点,则是CXNXWXH的方式,也即是通道数在前,之后依次是个数,宽和长. N是batch size.

从最后一层的模型看不出它的结构,实际上它是一个全连接层:

这一点可以通过芯原的模型转换工具的转换结果看出来,芯原的转换工具,可以将ONNX模型转换为芯原NPU吃的json文件模型,而netron是支持此类型的可视化输出的。

以下模型是和上图同一个模型文件,转换为芯原格式的JSON模型文件后,通过NETRON分析得到的网络模型结构,可以看到,最后一层是全连接。


lenet 模型都需要对吃进去的图像做数据归一化,libonnx实现也不例外

 

 


结束!

GitHub 加速计划 / ne / netron
27.06 K
2.72 K
下载
lutzroeder/netron: 是一个用于查看和可视化神经网络模型的桌面应用程序,支持多种深度学习框架和常用的神经网络格式。适合用于可视化神经网络模型,尤其是对于需要进行神经网络模型调试和可视化的开发人员和研究人员。
最近提交(Master分支:7 天前 )
9cee7758 - 1 个月前
63a272e8 - 1 个月前
Logo

旨在为数千万中国开发者提供一个无缝且高效的云端环境,以支持学习、使用和贡献开源项目。

更多推荐