使用NetworkX模組繪製深度神經網路(DNN)結構圖
本文將展示如何利用Python中的NetworkX模組來繪製深度神經網路(DNN)結構圖。 在文章Keras入門(一)搭建深度神經網路(DNN)解決多分類問題中,我們建立的DNN結構圖如下:
該DNN模型由輸入層、隱藏層、輸出層和softmax層組成,每一層的神經元個數分別為4,5,6,3,3。不知道聰明的讀者有沒有發現,這張示意圖完全是由筆者自己用Python繪製出來的,因為並不存在現成的結構圖。那麼,如何利用Python來繪製出這種相對複雜的神經網路的示意圖呢?答案是利用NetworkX模組。
NetworkX是一個用Python語言開發的圖論與複雜網路建模工具,內建了常用的圖與複雜網路分析演算法,可以方便地進行復雜網路資料分析、模擬建模等工作。NetworkX支援建立簡單無向圖、有向圖和多重圖,內建許多標準的圖論演算法,節點可為任意資料,支援任意的邊值維度,功能豐富,簡單易用。
首先,我們需要繪製出該DNN的大致框架,其Python程式碼如下:
# -*- coding:utf-8 -*-
import networkx as nx
import matplotlib.pyplot as plt
# 建立DAG
G = nx.DiGraph()
# 頂點列表
vertex_list = ['v'+str(i) for i in range(1, 22)]
# 新增頂點
G.add_nodes_from(vertex_list)
# 邊列表
edge_list = [
('v1', 'v5'), ('v1', 'v6'), ('v1' , 'v7'),('v1', 'v8'),('v1', 'v9'),
('v2', 'v5'), ('v2', 'v6'), ('v2', 'v7'),('v2', 'v8'),('v2', 'v9'),
('v3', 'v5'), ('v3', 'v6'), ('v3', 'v7'),('v3', 'v8'),('v3', 'v9'),
('v4', 'v5'), ('v4', 'v6'), ('v4', 'v7'),('v4', 'v8'),('v4', 'v9'),
('v5','v10' ),('v5','v11'),('v5','v12'),('v5','v13'),('v5','v14'),('v5','v15'),
('v6','v10'),('v6','v11'),('v6','v12'),('v6','v13'),('v6','v14'),('v6','v15'),
('v7','v10'),('v7','v11'),('v7','v12'),('v7','v13'),('v7','v14'),('v7','v15'),
('v8','v10'),('v8','v11'),('v8','v12'),('v8','v13'),('v8','v14'),('v8','v15'),
('v9','v10'),('v9','v11'),('v9','v12'),('v9','v13'),('v9','v14'),('v9','v15'),
('v10','v16'),('v10','v17'),('v10','v18'),
('v11','v16'),('v11','v17'),('v11','v18'),
('v12','v16'),('v12','v17'),('v12','v18'),
('v13','v16'),('v13','v17'),('v13','v18'),
('v14','v16'),('v14','v17'),('v14','v18'),
('v15','v16'),('v15','v17'),('v15','v18'),
('v16','v19'),('v16','v20'),('v16','v21'),
('v17','v19'),('v17','v20'),('v17','v21'),
('v18','v19'),('v18','v20'),('v18','v21')
]
# 通過列表形式來新增邊
G.add_edges_from(edge_list)
# 繪製DAG圖
plt.title('DNN for iris') #圖片標題
nx.draw(
G,
node_color = 'red', # 頂點顏色
edge_color = 'black', # 邊的顏色
with_labels = True, # 顯示頂點標籤
font_size =10, # 文字大小
node_size =300 # 頂點大小
)
# 顯示圖片
plt.show()
可以看到,我們在程式碼中已經設定好了這22個神經元以及它們之間的連線情況,但繪製出來的結構如卻是這樣的:
這顯然不是我們想要的結果,因為各神經的連線情況不明朗,而且很多神經都擠在了一起,看不清楚。之所以出現這種情況,是因為我們沒有給神經元設定座標,導致每個神經元都是隨機放置的。 接下來,引入座標機制,即設定好每個神經元節點的座標,使得它們的位置能夠按照事先設定好的來放置,其Python程式碼如下:
# -*- coding:utf-8 -*-
import networkx as nx
import matplotlib.pyplot as plt
# 建立DAG
G = nx.DiGraph()
# 頂點列表
vertex_list = ['v'+str(i) for i in range(1, 22)]
# 新增頂點
G.add_nodes_from(vertex_list)
# 邊列表
edge_list = [
('v1', 'v5'), ('v1', 'v6'), ('v1', 'v7'),('v1', 'v8'),('v1', 'v9'),
('v2', 'v5'), ('v2', 'v6'), ('v2', 'v7'),('v2', 'v8'),('v2', 'v9'),
('v3', 'v5'), ('v3', 'v6'), ('v3', 'v7'),('v3', 'v8'),('v3', 'v9'),
('v4', 'v5'), ('v4', 'v6'), ('v4', 'v7'),('v4', 'v8'),('v4', 'v9'),
('v5','v10'),('v5','v11'),('v5','v12'),('v5','v13'),('v5','v14'),('v5','v15'),
('v6','v10'),('v6','v11'),('v6','v12'),('v6','v13'),('v6','v14'),('v6','v15'),
('v7','v10'),('v7','v11'),('v7','v12'),('v7','v13'),('v7','v14'),('v7','v15'),
('v8','v10'),('v8','v11'),('v8','v12'),('v8','v13'),('v8','v14'),('v8','v15'),
('v9','v10'),('v9','v11'),('v9','v12'),('v9','v13'),('v9','v14'),('v9','v15'),
('v10','v16'),('v10','v17'),('v10','v18'),
('v11','v16'),('v11','v17'),('v11','v18'),
('v12','v16'),('v12','v17'),('v12','v18'),
('v13','v16'),('v13','v17'),('v13','v18'),
('v14','v16'),('v14','v17'),('v14','v18'),
('v15','v16'),('v15','v17'),('v15','v18'),
('v16','v19'),('v16','v20'),('v16','v21'),
('v17','v19'),('v17','v20'),('v17','v21'),
('v18','v19'),('v18','v20'),('v18','v21')
]
# 通過列表形式來新增邊
G.add_edges_from(edge_list)
# 指定繪製DAG圖時每個頂點的位置
pos = {
'v1':(-2,1.5),
'v2':(-2,0.5),
'v3':(-2,-0.5),
'v4':(-2,-1.5),
'v5':(-1,2),
'v6': (-1,1),
'v7':(-1,0),
'v8':(-1,-1),
'v9':(-1,-2),
'v10':(0,2.5),
'v11':(0,1.5),
'v12':(0,0.5),
'v13':(0,-0.5),
'v14':(0,-1.5),
'v15':(0,-2.5),
'v16':(1,1),
'v17':(1,0),
'v18':(1,-1),
'v19':(2,1),
'v20':(2,0),
'v21':(2,-1)
}
# 繪製DAG圖
plt.title('DNN for iris') #圖片標題
plt.xlim(-2.2, 2.2) #設定X軸座標範圍
plt.ylim(-3, 3) #設定Y軸座標範圍
nx.draw(
G,
pos = pos, # 點的位置
node_color = 'red', # 頂點顏色
edge_color = 'black', # 邊的顏色
with_labels = True, # 顯示頂點標籤
font_size =10, # 文字大小
node_size =300 # 頂點大小
)
# 顯示圖片
plt.show()
可以看到,在程式碼中,通過pos字典已經規定好了每個神經元節點的位置,那麼,繪製好的DNN結構示意圖如下:
可以看到,現在這個DNN模型的結構已經大致顯現出來了。 接下來,我們需要對這個框架圖進行更為細緻地修改,需要修改的地方為:
- 去掉神經元節點的標籤;
- 新增模型層的文字註釋(比如Input layer).
其中,第二步的文字註釋,我們藉助opencv來完成。完整的Python程式碼如下:
# -*- coding:utf-8 -*-
import cv2
import networkx as nx
import matplotlib.pyplot as plt
# 建立DAG
G = nx.DiGraph()
# 頂點列表
vertex_list = ['v'+str(i) for i in range(1, 22)]
# 新增頂點
G.add_nodes_from(vertex_list)
# 邊列表
edge_list = [
('v1', 'v5'), ('v1', 'v6'), ('v1', 'v7'),('v1', 'v8'),('v1', 'v9'),
('v2', 'v5'), ('v2', 'v6'), ('v2', 'v7'),('v2', 'v8'),('v2', 'v9'),
('v3', 'v5'), ('v3', 'v6'), ('v3', 'v7'),('v3', 'v8'),('v3', 'v9'),
('v4', 'v5'), ('v4', 'v6'), ('v4', 'v7'),('v4', 'v8'),('v4', 'v9'),
('v5','v10'),('v5','v11'),('v5','v12'),('v5','v13'),('v5','v14'),('v5','v15'),
('v6','v10'),('v6','v11'),('v6','v12'),('v6','v13'),('v6','v14'),('v6','v15'),
('v7','v10'),('v7','v11'),('v7','v12'