2 使用 NetworkX 画神经网络

1 构造 DAG 基类

由于神经网络的有向无环图(DAG),所以我们使用 NetworkX 的有向图包进行处理。下面先创建一个 DAG 的基类:

from matplotlib import pyplot as plt
import networkx as nx 


class DAGMeta:
    def __init__(self, layer_sizes, bbox=(.1, .1, .9, .9)):
        '''
        参数
        ==========
        bbox: DAG 所在矩形区域
        layer_sizes: DAG 每层的节点数
        '''
        self.bbox = bbox
        self.layer_sizes = layer_sizes
    
    @property
    def w(self):
        '''DAG 的画布宽度'''
        return self.bbox[2] - self.bbox[0]
    
    @property
    def h(self):
        '''DAG 的画布高度'''
        return self.bbox[3] - self.bbox[1]
    
    @property
    def x_center(self):
        '''DAG 的画布水平中心'''
        return (self.bbox[2] + self.bbox[0])/2
    
    @property
    def y_center(self):
        '''DAG 的画布竖直中心'''
        return (self.bbox[3] + self.bbox[1])/2
    
    def __len__(self):
        '''DAG 的层数'''
        return len(self.layer_sizes)
    
    @property
    def x_spacing(self):
        '''DAG 水平方向的留白间隙'''
        return self.w/(len(self) - 1)
    
    @property
    def y_spacing(self):
        '''DAG 竖直方向的留白间隙'''
        return self.h/max(self.layer_sizes)

2 简单的 DAG 创建

下面使用循环构造一个简单的 DAG:

class SlowlyDAG(DAGMeta):
    def plot(self):
        import random
        G = nx.DiGraph()
        node_count = 0
        for i, v in enumerate(self.layer_sizes):
            layer_top = self.y_spacing*(v-1)/2. + self.y_center
            for j in range(v):
                G.add_node(node_count, pos=(self.bbox[0] + i*self.x_spacing, layer_top - j*self.y_spacing))
                node_count += 1

        for x, (left_nodes, right_nodes) in enumerate(zip(self.layer_sizes[:-1], self.layer_sizes[1:])):
            for i in range(left_nodes):
                for j in range(right_nodes):
                    G.add_edge(i+sum(self.layer_sizes[:x]), j+sum(self.layer_sizes[:x+1]))  

        pos = nx.get_node_attributes(G,'pos')
        # 把每个节点中的位置pos信息导出来
        nx.draw(G, pos, 
                node_color=range(node_count), 
                with_labels=True,
                node_size=500, 
                edge_color=[random.random() for i in range(len(G.edges))], 
                width=2, 
                font_color='black',
                cmap=plt.cm.Paired, # matplotlib 的调色板,可以搜搜,很多颜色呢
                edge_cmap=plt.cm.Blues)
        plt.show() 

调用实例:

bbox = .1, .1, .9, .9 # 网络所在矩形区域
layer_sizes = [4, 7, 5, 2] # 网络每层的节点数
self = SlowlyDAG(layer_sizes, bbox)
self.plot()

效果图:

图1 一个简单的 DAG

3 高效的画出 DAG

SlowlyDAG 虽然画出了 DAG,但是速度有点慢,下面考虑使用 NetworkX 内置的函数和方法实现 DAG。

我们先看一个简单的例子:

import numpy as np


class DAG(DAGMeta):
    def __init__(self, layer_sizes, bbox=(.1, .1, .9, .9), name='DAG'):
        super().__init__(layer_sizes, bbox)
        self._dag = nx.DiGraph(name=name) # 可通过 self.name 获取名称
        #self.pairs = [(m, n) for m, layer in enumerate(self.layer_sizes) for n in range(layer)]
        #self.labels = {f"$x^{m}_{n}$":k for k, (m, n) in enumerate(self.pairs)}
        
    def node_position(self, m, n):
        '''节点的位置
        参数
        ============
        m: DAG 的层序号
        n: DAG 该层的节点序号
        '''
        x = self.bbox[0] + m * self.x_spacing
        layer_top = self.y_spacing*(self.layer_sizes[m]-1)/2. + self.y_center
        y = layer_top - n*self.y_spacing
        return x, y
        
    def layout_nodes(self):
        for m, layer in enumerate(self.layer_sizes):
            for n in range(layer):
                self._dag.add_node(f"$x^{m}_{n}$", pos=self.node_position(m, n))
    
    @property
    def pairs(self):
        sizes = self.layer_sizes.copy()
        edgelist = []
        n_layer = 0
        for size in sizes[1:]:
            x, y = np.meshgrid(np.arange(sizes[0]), np.arange(sizes[1]))
            paris = np.stack([x.flatten(), y.flatten()], axis=1)
            edgelist.extend([f"$x^{n_layer}_{i}$", f"$x^{n_layer+1}_{j}$"] for i, j in paris)
            del sizes[0]
            n_layer += 1
        return edgelist
                
    def plot(self):
        self.layout_nodes()
        pos = nx.get_node_attributes(self._dag,'pos')
        nodes = nx.draw_networkx_nodes(self._dag, pos, node_size=500, alpha=0.7)
        nx.draw_networkx_edges(self._dag, pos,
                               edgelist=self.pairs,
                               width=2, alpha=0.3, edge_color='g')
        nx.draw_networkx_labels(self._dag, pos, font_size=14)

调用实例:

bbox = .1, .1, .9, .9 # 网络所在矩形区域
layer_sizes = [5, 7, 5, 3, 2] # 网络每层的节点数
self = DAG(layer_sizes, bbox)
self.plot()
plt.axis('off')
plt.show()

效果图:

图2 带有层标识的 DAG

完整代码见我的 Github: xinetzone / draw_dag

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 219,539评论 6 508
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 93,594评论 3 396
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 165,871评论 0 356
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,963评论 1 295
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,984评论 6 393
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,763评论 1 307
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,468评论 3 420
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 39,357评论 0 276
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,850评论 1 317
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 38,002评论 3 338
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 40,144评论 1 351
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,823评论 5 346
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,483评论 3 331
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 32,026评论 0 22
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 33,150评论 1 272
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 48,415评论 3 373
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 45,092评论 2 355