使用netron对mnist网络结构分析「建议收藏」
基于libonnx環(huán)境簡要分析一下mnist網(wǎng)絡(luò)算子結(jié)構(gòu),關(guān)于環(huán)境搭建可以參考前面兩篇文章:
xboot大神的libonnx環(huán)境搭建
使用netron實現(xiàn)對onnx模型結(jié)構(gòu)可視化
本文主要目的是搞清楚mnist各層之間數(shù)據(jù)shape的變化情況,關(guān)于什么是shape,引用一本書中的介紹:
“在tensorflow中,使用張量來表示計算圖中的所有數(shù)據(jù),張量在計算圖的節(jié)點之間流動,張量可以看成N維數(shù)組,而數(shù)組的維數(shù)就是張量的階數(shù)。因此,0階張量對應標量數(shù)據(jù),1階張量對應一維數(shù)組,也就是向量。二階張量對應二維數(shù)組,也就是矩陣,以此類推,N階張量對應n維數(shù)組,例如,一張RGB圖像可以表示為3階張量,而多張RGB圖構(gòu)成的數(shù)據(jù)可以表示為4階張量。shape(形狀)代表的就是張量的一種屬性,當然還有其他屬性,比如數(shù)據(jù)類型等等”
再算子執(zhí)行前面打斷點,依次觀察輸入數(shù)據(jù)和輸出數(shù)據(jù)的大小:
(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.
可以看出一個簡單的規(guī)律,就是前一級網(wǎng)絡(luò)的輸出size等于后一級網(wǎng)絡(luò)的輸入size.
對照網(wǎng)絡(luò),可以完全對應的上:
將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網(wǎng)絡(luò)舉例:
netron不但可以解析onnx格式的模型文件,還支持darknet中 .cfg格式的文件,比如:
不過貌似N,C,W,H的排列有所差別,在上面mnist網(wǎng)絡(luò)中,順序是,個數(shù)X通道數(shù)X長度X高度
而darknet的cfg中,對于輸出數(shù)據(jù),是WxHxC的方式,也即是寬X長X通道號,但是對于每個算子節(jié)點,則是CXNXWXH的方式,也即是通道數(shù)在前,之后依次是個數(shù),寬和長. N是batch size.
從最后一層的模型看不出它的結(jié)構(gòu),實際上它是一個全連接層:
這一點可以通過芯原的模型轉(zhuǎn)換工具的轉(zhuǎn)換結(jié)果看出來,芯原的轉(zhuǎn)換工具,可以將ONNX模型轉(zhuǎn)換為芯原NPU吃的json文件模型,而netron是支持此類型的可視化輸出的。
以下模型是和上圖同一個模型文件,轉(zhuǎn)換為芯原格式的JSON模型文件后,通過NETRON分析得到的網(wǎng)絡(luò)模型結(jié)構(gòu),可以看到,最后一層是全連接。
lenet 模型都需要對吃進去的圖像做數(shù)據(jù)歸一化,libonnx實現(xiàn)也不例外
結(jié)束!
總結(jié)
以上是生活随笔為你收集整理的使用netron对mnist网络结构分析「建议收藏」的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: CAD自动保存的图形在哪里?怎么打开复原
- 下一篇: Angular 自定义结构化指令,如何传