利用Graphviz画神经网络框架图

前言

做了神经网络这么久,偶尔想画一下自己模型的架构图,但是又无从下手,因为网络一般都比较复杂,如果自己手动利用Visio画的画又比较麻烦,而我又比较懒,网上搜了一下Graphviz
画图工具,学了会便开始打算利用它来画模型结构图。
关于Graphviz的介绍,可以参考我的前两篇博客:


dot画神经网络图

简单神经网络

digraph G {
	rankdir=LR;
	splines=line;
	nodesep=.1;
	node [label=""];
    subgraph cluster_0 {
		color=white;
		node [style=solid,color=green,shape=circle];
			i;
			label = "Input Layer";
	}

	subgraph cluster_1 {
		color=white;
		node [style=solid,color=blue, shape=circle];
			h11, h12, h13, h14;
			label = "Hidden Layer 1";
	}

	subgraph cluster_2 {
		color=white;
		node [style=solid,color=blue, shape=circle];
			h21, h22;
			label = "Hidden Layer 2";
	}

	subgraph cluster_3 {
		color=white;
		node [style=solid,color=red, shape=circle];
			o;
			label="Output Layer";
	}

        i -> h11
		i -> h12
		i -> h13
		i -> h14
		
		h11 -> h21
		h11 -> h22
		h12 -> h21
		h12 -> h22
		h13 -> h21
		h13 -> h22
		h14 -> h21
		h14 -> h22
		
		h21 -> o
		h22 -> o
		
		



}

这里我们定义了一个图G,及四个子图cluster_0cluster_1cluster_2cluster_ 3,并为每个子图定义了结点类node及其各自属性,由于神经网络是全连接,因此我们需要为每一个结点连上边(十分繁琐)。
将其保存为demo.dot文件,通过命令:
dot -Tpng demo.dot -o demo.png
将其转化为png图片,如下所示:
利用Graphviz画神经网络框架图
好了,这样就画好了一个简单的神经网络模型图了,但是当你遇上结点较多的情况怎么办?
你可能会说,我又不傻,难道一个个在dot脚本上写上去?我可以用省略号代替啊!好的,那么来试试省略号代替的“伪大型神经网络”样子。

大型神经网络(伪)

digraph G {
	rankdir=LR;
	splines=line;
	nodesep=.1;
	node [label=""];
	compound=true
    subgraph cluster_0 {
		color=white;
		node [style=solid,color=green,shape=circle];
			i;
			label = "Input Layer";
	}

	subgraph cluster_1 {
		color=white;
		node [style=solid,color=blue, shape=circle];
			h11, h12, h13, h14;
			label = "Hidden Layer 1 (4 nodes)";
	}

	subgraph cluster_2 {
		color=white;
		{
			node [style=solid,color=blue,shape=circle];
			 h21;h22;
		}
		node [style=solid,shape=point];
		p1; p2; p3;
		{
			node [style=solid,color=blue,shape=circle];	
			h23;h24;	
		}
		label = "Hidden Layer 2 (100 nodes)";
	}

	subgraph cluster_3 {
		color=white;
		node [style=solid,color=red, shape=circle];
			o;
			label="Output Layer";
	}

        i -> h11
		i -> h12
		i -> h13
		i -> h14
		
		h11 -> h21
		h11 -> h22
		h12 -> h21
		h12 -> h22
		h13 -> h21
		h13 -> h22
		h14 -> h21
		h14 -> h22
				

		
		h11 -> h23
		h11 -> h24
		h12 -> h23
		h12 -> h24
		h13 -> h23
		h13 -> h24
		h14 -> h23
		h14 -> h24

		
		h21 -> o
		h22 -> o
		h23 -> o
		h24 -> o

}

利用Graphviz画神经网络框架图
这里我通过增加了几个形状为point的结点,使得整个网络看起来像是一个大型的网络的缩略版。注意,画图的时候顺序是按照结点定义的顺序来画的,所以三个小黑点要定义在中间。


Python 画神经网络图

大型神经网络

虽然按照上面的做法能够“投机取巧”地画出一个伪大型神经网络结构图,但是当你要真正画一个大型神经网络并且观察它的连接细节呢?这种时候就要利用Python的力量了。
代码如下,相关解释已经写在代码注释中:

from graphviz import Digraph


def Neural_Network_Graph(input_layer, hidden_layers, output_layer, filename="demo"):
    g = Digraph('g', filename=filename)  # 定义一个有向图
    n = 0  # 所有结点的数量,用其来作为结点的名字(代号)
    g.graph_attr.update(splines="false", nodesep='0.8',
                        ranksep='2', rankdir="LR")  
                        # 设置下图的属性: 线类型,结点间隔,每一级的间隔

    # Input Layer
    with g.subgraph(name='cluster_input') as c:
        the_label = 'Input Layer'
        c.attr(color='white')
        for i in range(input_layer):
            n += 1
            c.node(str(n))
            c.attr(label=the_label, rank='same')
            c.node_attr.update(color="#2ecc71", style="filled",
                               fontcolor="#2ecc71", shape="circle")

    last_layer_nodes = input_layer  # 最后一层的结点数量
    nodes_up = input_layer  # 总结点数量
    
    # Hidden Layers
    
    hidden_layers_nr = len(hidden_layers)  # 隐藏层层数
    for i in range(hidden_layers_nr):
        with g.subgraph(name="cluster_" + str(i + 1)) as c:
            c.attr(color='white')
            c.attr(rank='same')
            the_label = "Hidden Layer" + str(i+1)
            c.attr(label=the_label)
            for j in range(hidden_layers[i]):
                n += 1
                c.node(str(n), shape="circle", style="filled",
                       color="#3498db", fontcolor="#3498db")
                for h in range(nodes_up - last_layer_nodes + 1, nodes_up + 1):
                    g.edge(str(h), str(n))  # 定义好上一层到下一层的连接线
            last_layer_nodes = hidden_layers[i]
            nodes_up += hidden_layers[i]

    # Output Layer
    with g.subgraph(name='cluster_output') as c:
        c.attr(color='white')
        c.attr(rank='same')
        for i in range(1, output_layer + 1):
            n += 1
            c.node(str(n), shape="circle", style="filled",
                   color="#e74c3c", fontcolor="#e74c3c")
            for h in range(nodes_up - last_layer_nodes + 1, nodes_up + 1):
                g.edge(str(h), str(n))
        c.attr(label='Output Layer')
        c.node_attr.update(color="#2ecc71", style="filled",
                           fontcolor="#2ecc71", shape="circle")

    g.attr(arrowShape="none")
    g.edge_attr.update(arrowhead="none", color="#707070")
    g.render(filename, format="png")


我编写了一个Neural_Network_Graph函数,接收输入为:

  • input_layer:输入层神经元数量
  • hidden_layers:列表类型,隐藏层层数及神经元数量
  • output_layer:输出层神经元数量
    通过定义三个参数,调用Neural_Network_Graph函数:
# -------------------------------------------
input_layer = 5  # 输入层的神经元数量
hidden_layers = [10, 6]  # 隐藏层层数和数量
output_layer = 1  # 输出层神经元数量
# -----------------------------------------------

Neural_Network_Graph(input_layer, hidden_layers, output_layer)

很容易得到一张png格式的神经网络图:

利用Graphviz画神经网络框架图