大學(xué)網(wǎng)頁設(shè)計課程鄭州seo外包服務(wù)
對于神經(jīng)網(wǎng)絡(luò)架構(gòu)的可視化是很有意義的,可以在很大程度上幫助到我們清晰直觀地了解到整個架構(gòu),我們在前面的 PyTorch的ONNX結(jié)合MNIST手寫數(shù)字?jǐn)?shù)據(jù)集的應(yīng)用(.pth和.onnx的轉(zhuǎn)換與onnx運行時)
有介紹,可以將模型架構(gòu)文件(常見的格式都可以)在線上傳到 https://netron.app/,將會生成架構(gòu)示意圖,比如將yolov5s.pt這個預(yù)訓(xùn)練模型,上傳之后,將出現(xiàn)下面這樣的圖片(局部):
這種屬于非常簡單的層的連接展示,也能夠直觀知道整個架構(gòu)是由哪些層組成,雖然每層可以查看一些屬性,不過對于每層的具體細(xì)節(jié)并沒有那么直觀展現(xiàn)在圖片當(dāng)中。
接下來介紹的這兩款都會生成漂亮的可視化神經(jīng)網(wǎng)絡(luò)圖,可以用來繪制報告和演示使用,效果非常棒。?
1、NN-SVG
NN-SVG生成神經(jīng)網(wǎng)絡(luò)架構(gòu)的地址:http://alexlenail.me/NN-SVG/AlexNet.html
顯示可能很慢,最好科學(xué)上網(wǎng),進(jìn)去之后,我們可以看到,有三種神經(jīng)網(wǎng)絡(luò)架構(gòu)可以進(jìn)行設(shè)置:FCNN、LeNet、AlexNet 我們分別來看下:
1.1、FCNN?
第一種就是最基礎(chǔ)的全連接神經(jīng)網(wǎng)絡(luò)FCNN,輸入層-->隱藏層(若干)-->輸出層,截圖如下:
左側(cè)邊欄可以進(jìn)行一些顏色、形狀、透明度等設(shè)置,也可以很方便的增加和減少層。右邊就會實時的顯示出操作的效果。
1.2、LeNet
LeNet是一種經(jīng)典的卷積神經(jīng)網(wǎng)絡(luò),最初用來識別手寫數(shù)字,我們來看下其結(jié)構(gòu):
可以看到架構(gòu)主要是由卷積層組成,輸入層-->卷積層-->最大池化層-->...-->全連接層-->輸出層。
左邊同樣的都是可以設(shè)置顏色,透明度等,可以增減層數(shù),在每層里可以設(shè)置數(shù)量、高寬以及卷積核大小,還可以指定是否顯示層的名稱,這樣就更加清楚的知道架構(gòu)是由哪些具體的層組成了。
1.3、AlexNet
AlexNet是辛頓和他的學(xué)生Alex Krizhevsky設(shè)計的CNN,在2012年ImageNet的競賽中獲得冠軍,它是在LeNet的基礎(chǔ)上應(yīng)用了ReLU激活函數(shù)(取代Sigmoid)、Dropout層(避免過擬合)、LRN層(增強泛化能力)等的一種神經(jīng)網(wǎng)絡(luò),截圖如下:
同樣的可以直觀看到,每個層的數(shù)量、寬高、卷積核的大小,這些直觀的神經(jīng)網(wǎng)絡(luò)示意圖,尤其對于初學(xué)者來說可以很好的理解某個神經(jīng)網(wǎng)絡(luò)的整個計算過程。
最后的這些都是可以點擊"Download SVG"將其下載成svg格式(一種XML格式)的文件。
2、PlotNeuralNet
2.1、安裝
首先確認(rèn)自己的操作系統(tǒng),然后對應(yīng)著進(jìn)行安裝,后面出現(xiàn)的示例是本人的Ubuntu 18.04版本上做的。
Ubuntu 16.04
sudo apt-get install texlive-latex-extra
Ubuntu 18.04.2
基于本網(wǎng)站,請安裝以下軟件包,包含一些字體包:
sudo apt-get install texlive-latex-base
sudo apt-get install texlive-fonts-recommended
sudo apt-get install texlive-fonts-extra
sudo apt-get install texlive-latex-extra
Windows或其他系統(tǒng)
下載安裝MiKTeX:https://miktex.org/download
下載安裝Git bash:https://git-scm.com/download/win
或者Cygwin:https://www.cygwin.com/
準(zhǔn)備就緒之后運行即可:
cd pyexamples/
bash ../tikzmake.sh test_simple
2.2、克隆運行
上面的Latex安裝好了之后,就克隆PlotNeuralNet:?
git clone https://github.com/HarisIqbal88/PlotNeuralNet.git
?我們先來執(zhí)行自帶的一個測試文件
cd pyexamples/
bash ../tikzmake.sh test_simple
將生成test_simple.pdf,截圖如下:
2.3、test_simple.py
我們來看下自帶的test_simple.py內(nèi)容:
import sys
sys.path.append('../')
from pycore.tikzeng import *# defined your arch
arch = [to_head( '..' ),to_cor(),to_begin(),to_Conv("conv1", 512, 64, offset="(0,0,0)", to="(0,0,0)", height=64, depth=64, width=2 ),to_Pool("pool1", offset="(0,0,0)", to="(conv1-east)"),to_Conv("conv2", 128, 64, offset="(1,0,0)", to="(pool1-east)", height=32, depth=32, width=2 ),to_connection( "pool1", "conv2"), to_Pool("pool2", offset="(0,0,0)", to="(conv2-east)", height=28, depth=28, width=1),to_SoftMax("soft1", 10 ,"(3,0,0)", "(pool1-east)", caption="SOFT" ),to_connection("pool2", "soft1"), to_Sum("sum1", offset="(1.5,0,0)", to="(soft1-east)", radius=2.5, opacity=0.6),to_connection("soft1", "sum1"),to_end()]def main():namefile = str(sys.argv[0]).split('.')[0]to_generate(arch, namefile + '.tex' )if __name__ == '__main__':main()
代碼比較簡單,導(dǎo)入庫之后就是定義架構(gòu),然后就自定義的每一層都寫在arch這個列表中的?to_begin()?和?to_end()?之間,然后就通過函數(shù)?to_generate()?將arch列表生成.tex文件,最后就是通過bash自動轉(zhuǎn)換成pdf文件,我們查看下bash文件內(nèi)容:cat tikzmake.sh
#!/bin/bashpython $1.py
pdflatex $1.texrm *.aux *.log *.vscodeLog
rm *.texif [[ "$OSTYPE" == "darwin"* ]]; thenopen $1.pdf
elsexdg-open $1.pdf
fi
2.4、自定義網(wǎng)絡(luò)架構(gòu)
接下來我們自定義一個網(wǎng)絡(luò)架構(gòu)測試下,tony.py:
import sys
sys.path.append('../')
from pycore.tikzeng import *# defined your arch
arch = [to_head('..'),to_cor(),to_begin(),to_input('dog.png', width=18, height=14),to_Conv("conv1", 512, 64, offset="(1,0,0)", to="(0,0,0)", height=64, depth=64, width=10,caption="Conv1 Layer"),to_Pool("pool1", offset="(0,0,0)", to="(conv1-east)",caption="Pool1 Layer"),to_Conv("conv2", 128, 64, offset="(4,0,0)", to="(pool1-east)", height=32, depth=32, width=5,caption="Conv2 Layer"),to_connection("pool1", "conv2"),to_Pool("pool2", offset="(0,0,0)", to="(conv2-east)", height=28, depth=28, width=1,caption="Pool2 Layer"),to_SoftMax("soft1", 10 ,"(8,0,0)", "(pool1-east)", caption="Softmax Layer"),to_connection("pool2", "soft1"),to_skip(of="pool1",to="pool2",pos=1.25),to_end()]def main():namefile = str(sys.argv[0]).split('.')[0]to_generate(arch, namefile + '.tex' )if __name__ == '__main__':main()
其中一些代碼的解釋:
to_input:可以指定輸入圖片
to="(conv1-east)":表示當(dāng)前層在conv1的東邊(右邊)
to_connection( "pool1", "conv2"):在兩者之間畫連接線
caption:標(biāo)題
to_skip:做跳線,其中pos大于1表示向上進(jìn)行畫線,小于1就是向下,這個可以自己進(jìn)行調(diào)試
如果對一些方法不明確其有哪些參數(shù),可以使用幫助:helpto_input(pathfile, to='(-3,0,0)', width=8, height=8, name='temp')
to_SoftMax(name, s_filer=10, offset='(0,0,0)', to='(0,0,0)', width=1.5, height=3, depth=25, opacity=0.8, caption=' ')
當(dāng)然這里的需要命令行進(jìn)入到PlotNeuralNet目錄,因為需要加載:from pycore.tikzeng import *
其他層需要加入,依葫蘆畫瓢即可,很簡單,比如:
to_UnPool('Unpool', offset="(5,0,0)", to="(0,0,0)",height=64, width=2, depth=64, caption='Unpool'),
to_ConvRes("ConvRes", ?s_filer=512, n_filer=64, offset="(10,0,0)", to="(0,0,0)", height=64, width=2, depth=64, caption='ConvRes'),
to_ConvSoftMax("ConvSoftMax", ?s_filer=512, ?offset="(15,0,0)", to="(0,0,0)", height=64, width=2, depth=64, caption='ConvSoftMax'),
to_Sum("sum", offset="(5,0,0)", to="(ConvSoftMax-east)", radius=2.5, opacity=0.6),...
2.5、tikzeng.py
我們來查看下tikzeng.py代碼:
import osdef to_head( projectpath ):pathlayers = os.path.join( projectpath, 'layers/' ).replace('\\', '/')return r"""
\documentclass[border=8pt, multi, tikz]{standalone}
\usepackage{import}
\subimport{"""+ pathlayers + r"""}{init}
\usetikzlibrary{positioning}
\usetikzlibrary{3d} %for including external image
"""def to_cor():return r"""
\def\ConvColor{rgb:yellow,5;red,2.5;white,5}
\def\ConvReluColor{rgb:yellow,5;red,5;white,5}
\def\PoolColor{rgb:red,1;black,0.3}
\def\UnpoolColor{rgb:blue,2;green,1;black,0.3}
\def\FcColor{rgb:blue,5;red,2.5;white,5}
\def\FcReluColor{rgb:blue,5;red,5;white,4}
\def\SoftmaxColor{rgb:magenta,5;black,7}
\def\SumColor{rgb:blue,5;green,15}
"""def to_begin():return r"""
\newcommand{\copymidarrow}{\tikz \draw[-Stealth,line width=0.8mm,draw={rgb:blue,4;red,1;green,1;black,3}] (-0.3,0) -- ++(0.3,0);}\begin{document}
\begin{tikzpicture}
\tikzstyle{connection}=[ultra thick,every node/.style={sloped,allow upside down},draw=\edgecolor,opacity=0.7]
\tikzstyle{copyconnection}=[ultra thick,every node/.style={sloped,allow upside down},draw={rgb:blue,4;red,1;green,1;black,3},opacity=0.7]
"""# layers definitiondef to_input( pathfile, to='(-3,0,0)', width=8, height=8, name="temp" ):return r"""
\node[canvas is zy plane at x=0] (""" + name + """) at """+ to +""" {\includegraphics[width="""+ str(width)+"cm"+""",height="""+ str(height)+"cm"+"""]{"""+ pathfile +"""}};
"""# Conv
def to_Conv( name, s_filer=256, n_filer=64, offset="(0,0,0)", to="(0,0,0)", width=1, height=40, depth=40, caption=" " ):return r"""
\pic[shift={"""+ offset +"""}] at """+ to +""" {Box={name=""" + name +""",caption="""+ caption +r""",xlabel={{"""+ str(n_filer) +""", }},zlabel="""+ str(s_filer) +""",fill=\ConvColor,height="""+ str(height) +""",width="""+ str(width) +""",depth="""+ str(depth) +"""}};
"""# Conv,Conv,relu
# Bottleneck
def to_ConvConvRelu( name, s_filer=256, n_filer=(64,64), offset="(0,0,0)", to="(0,0,0)", width=(2,2), height=40, depth=40, caption=" " ):return r"""
\pic[shift={ """+ offset +""" }] at """+ to +""" {RightBandedBox={name="""+ name +""",caption="""+ caption +""",xlabel={{ """+ str(n_filer[0]) +""", """+ str(n_filer[1]) +""" }},zlabel="""+ str(s_filer) +""",fill=\ConvColor,bandfill=\ConvReluColor,height="""+ str(height) +""",width={ """+ str(width[0]) +""" , """+ str(width[1]) +""" },depth="""+ str(depth) +"""}};
"""# Pool
def to_Pool(name, offset="(0,0,0)", to="(0,0,0)", width=1, height=32, depth=32, opacity=0.5, caption=" "):return r"""
\pic[shift={ """+ offset +""" }] at """+ to +""" {Box={name="""+name+""",caption="""+ caption +r""",fill=\PoolColor,opacity="""+ str(opacity) +""",height="""+ str(height) +""",width="""+ str(width) +""",depth="""+ str(depth) +"""}};
"""# unpool4,
def to_UnPool(name, offset="(0,0,0)", to="(0,0,0)", width=1, height=32, depth=32, opacity=0.5, caption=" "):return r"""
\pic[shift={ """+ offset +""" }] at """+ to +""" {Box={name="""+ name +r""",caption="""+ caption +r""",fill=\UnpoolColor,opacity="""+ str(opacity) +""",height="""+ str(height) +""",width="""+ str(width) +""",depth="""+ str(depth) +"""}};
"""def to_ConvRes( name, s_filer=256, n_filer=64, offset="(0,0,0)", to="(0,0,0)", width=6, height=40, depth=40, opacity=0.2, caption=" " ):return r"""
\pic[shift={ """+ offset +""" }] at """+ to +""" {RightBandedBox={name="""+ name + """,caption="""+ caption + """,xlabel={{ """+ str(n_filer) + """, }},zlabel="""+ str(s_filer) +r""",fill={rgb:white,1;black,3},bandfill={rgb:white,1;black,2},opacity="""+ str(opacity) +""",height="""+ str(height) +""",width="""+ str(width) +""",depth="""+ str(depth) +"""}};
"""# ConvSoftMax
def to_ConvSoftMax( name, s_filer=40, offset="(0,0,0)", to="(0,0,0)", width=1, height=40, depth=40, caption=" " ):return r"""
\pic[shift={"""+ offset +"""}] at """+ to +""" {Box={name=""" + name +""",caption="""+ caption +""",zlabel="""+ str(s_filer) +""",fill=\SoftmaxColor,height="""+ str(height) +""",width="""+ str(width) +""",depth="""+ str(depth) +"""}};
"""# SoftMax
def to_SoftMax( name, s_filer=10, offset="(0,0,0)", to="(0,0,0)", width=1.5, height=3, depth=25, opacity=0.8, caption=" " ):return r"""
\pic[shift={"""+ offset +"""}] at """+ to +""" {Box={name=""" + name +""",caption="""+ caption +""",xlabel={{" ","dummy"}},zlabel="""+ str(s_filer) +""",fill=\SoftmaxColor,opacity="""+ str(opacity) +""",height="""+ str(height) +""",width="""+ str(width) +""",depth="""+ str(depth) +"""}};
"""def to_Sum( name, offset="(0,0,0)", to="(0,0,0)", radius=2.5, opacity=0.6):return r"""
\pic[shift={"""+ offset +"""}] at """+ to +""" {Ball={name=""" + name +""",fill=\SumColor,opacity="""+ str(opacity) +""",radius="""+ str(radius) +""",logo=$+$}};
"""def to_connection( of, to):return r"""
\draw [connection] ("""+of+"""-east) -- node {\midarrow} ("""+to+"""-west);
"""def to_skip( of, to, pos=1.25):return r"""
\path ("""+ of +"""-southeast) -- ("""+ of +"""-northeast) coordinate[pos="""+ str(pos) +"""] ("""+ of +"""-top) ;
\path ("""+ to +"""-south) -- ("""+ to +"""-north) coordinate[pos="""+ str(pos) +"""] ("""+ to +"""-top) ;
\draw [copyconnection] ("""+of+"""-northeast)
-- node {\copymidarrow}("""+of+"""-top)
-- node {\copymidarrow}("""+to+"""-top)
-- node {\copymidarrow} ("""+to+"""-north);
"""def to_end():return r"""
\end{tikzpicture}
\end{document}
"""def to_generate( arch, pathname="file.tex" ):with open(pathname, "w") as f: for c in arch:print(c)f.write( c )
從這些代碼也可以看出,通過這些方法,返回的是Latex代碼來進(jìn)行繪制的。
?運行命令:bash ../tikzmake.sh tony? ?生成如圖:
可以看到生成的可視化架構(gòu)圖,相比較于以前手工做圖來說,真的大大提高了效率。更多詳情可以去看具體源碼。
github:PlotNeuralNet