Python 如何可视化神经网络
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/29888233/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
How to visualize a neural network
提问by fishiwhj
I want to draw a dynamic picture for a neural network to watch the weights changed and the activation of neurons during learning. How could I simulate the process in Python?
我想为神经网络绘制动态图,以观察学习过程中权重的变化和神经元的激活。我如何在 Python 中模拟这个过程?
More precisely, if the network shape is: [1000, 300, 50], then I wish to draw a three layer NN which contains 1000, 300 and 50 neurons respectively. Further, I hope the picture could reflect the saturation of neurons on each layer during each epoch.
更准确地说,如果网络形状是:[1000, 300, 50],那么我希望绘制一个三层 NN,分别包含 1000、300 和 50 个神经元。更进一步,我希望这张图能反映每个时期每一层神经元的饱和度。
I've no idea about how to do it. Can someone shed some light on me?
我不知道该怎么做。有人可以对我有所了解吗?
回答by Mykhaylo Kopytonenko
Draw the network with nodes as circles connected with lines. The line widths must be proportional to the weights. Very small weights can be displayed even without a line.
将节点绘制为用线连接的圆圈。线宽必须与权重成正比。即使没有线条,也可以显示非常小的重量。
回答by Milo
The Python library matplotlibprovides methods to draw circles and lines. It also allows for animation.
Python 库matplotlib提供了绘制圆和线的方法。它还允许动画。
I've written some sample code to indicate how this could be done. My code generates a simple static diagram of a neural network, where each neuron is connected to every neuron in the previous layer. Further work would be required to animate it.
我已经编写了一些示例代码来说明如何做到这一点。我的代码生成了一个简单的神经网络静态图,其中每个神经元都连接到前一层中的每个神经元。需要进一步的工作来制作动画。
I've also made it available in a Git repository.
from matplotlib import pyplot
from math import cos, sin, atan
class Neuron():
def __init__(self, x, y):
self.x = x
self.y = y
def draw(self):
circle = pyplot.Circle((self.x, self.y), radius=neuron_radius, fill=False)
pyplot.gca().add_patch(circle)
class Layer():
def __init__(self, network, number_of_neurons):
self.previous_layer = self.__get_previous_layer(network)
self.y = self.__calculate_layer_y_position()
self.neurons = self.__intialise_neurons(number_of_neurons)
def __intialise_neurons(self, number_of_neurons):
neurons = []
x = self.__calculate_left_margin_so_layer_is_centered(number_of_neurons)
for iteration in xrange(number_of_neurons):
neuron = Neuron(x, self.y)
neurons.append(neuron)
x += horizontal_distance_between_neurons
return neurons
def __calculate_left_margin_so_layer_is_centered(self, number_of_neurons):
return horizontal_distance_between_neurons * (number_of_neurons_in_widest_layer - number_of_neurons) / 2
def __calculate_layer_y_position(self):
if self.previous_layer:
return self.previous_layer.y + vertical_distance_between_layers
else:
return 0
def __get_previous_layer(self, network):
if len(network.layers) > 0:
return network.layers[-1]
else:
return None
def __line_between_two_neurons(self, neuron1, neuron2):
angle = atan((neuron2.x - neuron1.x) / float(neuron2.y - neuron1.y))
x_adjustment = neuron_radius * sin(angle)
y_adjustment = neuron_radius * cos(angle)
line = pyplot.Line2D((neuron1.x - x_adjustment, neuron2.x + x_adjustment), (neuron1.y - y_adjustment, neuron2.y + y_adjustment))
pyplot.gca().add_line(line)
def draw(self):
for neuron in self.neurons:
neuron.draw()
if self.previous_layer:
for previous_layer_neuron in self.previous_layer.neurons:
self.__line_between_two_neurons(neuron, previous_layer_neuron)
class NeuralNetwork():
def __init__(self):
self.layers = []
def add_layer(self, number_of_neurons):
layer = Layer(self, number_of_neurons)
self.layers.append(layer)
def draw(self):
for layer in self.layers:
layer.draw()
pyplot.axis('scaled')
pyplot.show()
if __name__ == "__main__":
vertical_distance_between_layers = 6
horizontal_distance_between_neurons = 2
neuron_radius = 0.5
number_of_neurons_in_widest_layer = 4
network = NeuralNetwork()
network.add_layer(3)
network.add_layer(4)
network.add_layer(1)
network.draw()
回答by DenisFLASH
To implement what Mykhaylohas suggested, I've slightly modified the Milo's codein order to allow providing weghts as an argument which will affect every line's width. This argument is optional, as there's no sense of providing weights for the last layer. All this to be able to visualize my solution to this exerciseon neural networks. I've given binary weights (either 0 or 1), so that lines with zero weight not be drawn at all (to make an image more clear).
为了实现Mykhaylo 的建议,我稍微修改了Milo 的代码,以允许提供权重作为影响每行宽度的参数。此参数是可选的,因为没有为最后一层提供权重的意义。所有这些都是为了能够在神经网络上可视化我对这个练习的解决方案。我已经给出了二进制权重(0 或 1),因此根本不会绘制权重为零的线(使图像更清晰)。
from matplotlib import pyplot
from math import cos, sin, atan
import numpy as np
class Neuron():
def __init__(self, x, y):
self.x = x
self.y = y
def draw(self):
circle = pyplot.Circle((self.x, self.y), radius=neuron_radius, fill=False)
pyplot.gca().add_patch(circle)
class Layer():
def __init__(self, network, number_of_neurons, weights):
self.previous_layer = self.__get_previous_layer(network)
self.y = self.__calculate_layer_y_position()
self.neurons = self.__intialise_neurons(number_of_neurons)
self.weights = weights
def __intialise_neurons(self, number_of_neurons):
neurons = []
x = self.__calculate_left_margin_so_layer_is_centered(number_of_neurons)
for iteration in range(number_of_neurons):
neuron = Neuron(x, self.y)
neurons.append(neuron)
x += horizontal_distance_between_neurons
return neurons
def __calculate_left_margin_so_layer_is_centered(self, number_of_neurons):
return horizontal_distance_between_neurons * (number_of_neurons_in_widest_layer - number_of_neurons) / 2
def __calculate_layer_y_position(self):
if self.previous_layer:
return self.previous_layer.y + vertical_distance_between_layers
else:
return 0
def __get_previous_layer(self, network):
if len(network.layers) > 0:
return network.layers[-1]
else:
return None
def __line_between_two_neurons(self, neuron1, neuron2, linewidth):
angle = atan((neuron2.x - neuron1.x) / float(neuron2.y - neuron1.y))
x_adjustment = neuron_radius * sin(angle)
y_adjustment = neuron_radius * cos(angle)
line_x_data = (neuron1.x - x_adjustment, neuron2.x + x_adjustment)
line_y_data = (neuron1.y - y_adjustment, neuron2.y + y_adjustment)
line = pyplot.Line2D(line_x_data, line_y_data, linewidth=linewidth)
pyplot.gca().add_line(line)
def draw(self):
for this_layer_neuron_index in range(len(self.neurons)):
neuron = self.neurons[this_layer_neuron_index]
neuron.draw()
if self.previous_layer:
for previous_layer_neuron_index in range(len(self.previous_layer.neurons)):
previous_layer_neuron = self.previous_layer.neurons[previous_layer_neuron_index]
weight = self.previous_layer.weights[this_layer_neuron_index, previous_layer_neuron_index]
self.__line_between_two_neurons(neuron, previous_layer_neuron, weight)
class NeuralNetwork():
def __init__(self):
self.layers = []
def add_layer(self, number_of_neurons, weights=None):
layer = Layer(self, number_of_neurons, weights)
self.layers.append(layer)
def draw(self):
for layer in self.layers:
layer.draw()
pyplot.axis('scaled')
pyplot.show()
if __name__ == "__main__":
vertical_distance_between_layers = 6
horizontal_distance_between_neurons = 2
neuron_radius = 0.5
number_of_neurons_in_widest_layer = 4
network = NeuralNetwork()
# weights to convert from 10 outputs to 4 (decimal digits to their binary representation)
weights1 = np.array([\
[0,0,0,0,0,0,0,0,1,1],\
[0,0,0,0,1,1,1,1,0,0],\
[0,0,1,1,0,0,1,1,0,0],\
[0,1,0,1,0,1,0,1,0,1]])
network.add_layer(10, weights1)
network.add_layer(4)
network.draw()
回答by Oliver Wilken
I adapted some parts to the answer of Milo
我根据米洛的回答改编了一些部分
from matplotlib import pyplot
from math import cos, sin, atan
class Neuron():
def __init__(self, x, y):
self.x = x
self.y = y
def draw(self, neuron_radius):
circle = pyplot.Circle((self.x, self.y), radius=neuron_radius, fill=False)
pyplot.gca().add_patch(circle)
class Layer():
def __init__(self, network, number_of_neurons, number_of_neurons_in_widest_layer):
self.vertical_distance_between_layers = 6
self.horizontal_distance_between_neurons = 2
self.neuron_radius = 0.5
self.number_of_neurons_in_widest_layer = number_of_neurons_in_widest_layer
self.previous_layer = self.__get_previous_layer(network)
self.y = self.__calculate_layer_y_position()
self.neurons = self.__intialise_neurons(number_of_neurons)
def __intialise_neurons(self, number_of_neurons):
neurons = []
x = self.__calculate_left_margin_so_layer_is_centered(number_of_neurons)
for iteration in xrange(number_of_neurons):
neuron = Neuron(x, self.y)
neurons.append(neuron)
x += self.horizontal_distance_between_neurons
return neurons
def __calculate_left_margin_so_layer_is_centered(self, number_of_neurons):
return self.horizontal_distance_between_neurons * (self.number_of_neurons_in_widest_layer - number_of_neurons) / 2
def __calculate_layer_y_position(self):
if self.previous_layer:
return self.previous_layer.y + self.vertical_distance_between_layers
else:
return 0
def __get_previous_layer(self, network):
if len(network.layers) > 0:
return network.layers[-1]
else:
return None
def __line_between_two_neurons(self, neuron1, neuron2):
angle = atan((neuron2.x - neuron1.x) / float(neuron2.y - neuron1.y))
x_adjustment = self.neuron_radius * sin(angle)
y_adjustment = self.neuron_radius * cos(angle)
line = pyplot.Line2D((neuron1.x - x_adjustment, neuron2.x + x_adjustment), (neuron1.y - y_adjustment, neuron2.y + y_adjustment))
pyplot.gca().add_line(line)
def draw(self, layerType=0):
for neuron in self.neurons:
neuron.draw( self.neuron_radius )
if self.previous_layer:
for previous_layer_neuron in self.previous_layer.neurons:
self.__line_between_two_neurons(neuron, previous_layer_neuron)
# write Text
x_text = self.number_of_neurons_in_widest_layer * self.horizontal_distance_between_neurons
if layerType == 0:
pyplot.text(x_text, self.y, 'Input Layer', fontsize = 12)
elif layerType == -1:
pyplot.text(x_text, self.y, 'Output Layer', fontsize = 12)
else:
pyplot.text(x_text, self.y, 'Hidden Layer '+str(layerType), fontsize = 12)
class NeuralNetwork():
def __init__(self, number_of_neurons_in_widest_layer):
self.number_of_neurons_in_widest_layer = number_of_neurons_in_widest_layer
self.layers = []
self.layertype = 0
def add_layer(self, number_of_neurons ):
layer = Layer(self, number_of_neurons, self.number_of_neurons_in_widest_layer)
self.layers.append(layer)
def draw(self):
pyplot.figure()
for i in range( len(self.layers) ):
layer = self.layers[i]
if i == len(self.layers)-1:
i = -1
layer.draw( i )
pyplot.axis('scaled')
pyplot.axis('off')
pyplot.title( 'Neural Network architecture', fontsize=15 )
pyplot.show()
class DrawNN():
def __init__( self, neural_network ):
self.neural_network = neural_network
def draw( self ):
widest_layer = max( self.neural_network )
network = NeuralNetwork( widest_layer )
for l in self.neural_network:
network.add_layer(l)
network.draw()
Now the layers are also labeled, the axis are deleted and constructing the plot is easier. It's simply done by:
现在图层也被标记了,轴被删除并且构建图更容易。它只是通过以下方式完成:
network = DrawNN( [2,8,8,1] )
network.draw()
Here a net with the following structure is constructed:
这里构造了一个具有以下结构的网络:
回答by u5488085
Here is a library based on matplotlib, named viznet(pip install viznet). To begin, you can read this notebook. Here is an example
这里有一个基于matplotlib的库,名为viznet(pip install viznet)。首先,您可以阅读本笔记本。这是一个例子
Viznet defines a set of brush rules.
Viznet 定义了一组画笔规则。
node1 >> (0, 1.2) # put a node centered at axis (0, 1.2)
node2 >> (2, 0) # put a node centered at axis (2, 0)
edge >> (node1, node2) # connect two nodes
Here, node1 and node2 are two nodebrushes, like
node1 = NodeBrush('nn.input', ax=d.ax, size='normal')
这里,node1 和 node2 是两个节点画笔,比如
node1 = NodeBrush('nn.input', ax=d.ax, size='normal')
The first parameter defines the theme of node. For a neural network node (theme start with 'nn.'), its style refers from Neural Network Zoo Page。
第一个参数定义了节点的主题。对于神经网络节点(主题以'nn.'开头),其样式参考Neural Network Zoo Page。
For edges, we can define its brush like edge = EdgeBrush('->', ax=d.ax, lw=2)
The first parameters is the theme,'-' for straight line, '.' for dashed line, '=' for double line, '>','<' are left arrow and right arrow. The proportion of '-', '.' and '=' in a theme code decides their length in a line. For example, '->' and '->-' represents lines with arrow at end and arrow at center respectively. The following are several examples
对于边缘,我们可以定义它的画笔像edge = EdgeBrush('->', ax=d.ax, lw=2)
第一个参数是主题,'-'为直线,'.' 虚线表示,'=' 表示双线,'>','<' 表示左箭头和右箭头。'-'、'.'的比例 主题代码中的 '=' 决定它们在一行中的长度。例如,'->' 和 '->-' 分别表示末端有箭头和中心有箭头的线。下面是几个例子
With only nodes and edges are not enough, the rule for connectionplays a fundamentally role. Except basic connection rule, you can create pins on nodes. I will stop here and leave it for documents. These flexible features make it capable for drawing also tensor networksand quantum circuits.
只有节点和边是不够的,连接规则起着根本性的作用。除了基本的连接规则,您可以在节点上创建引脚。我会在这里停下来,把它留给文件。这些灵活的特性使其能够绘制张量网络和量子电路。
This project just embraced its v0.1 release, I will keep improving it. You can access its Github repofor latest version, and wellcome for pulling requestsor posting issues!
这个项目刚刚接受了它的 v0.1 版本,我会继续改进它。您可以访问其最新版本的Github 存储库,并欢迎拉取请求或发布问题!
回答by rsc
I was with that same problem and didn't find a good solution, so I created a library to do simple drawings. Here is an example on how to draw a 3-layer NN:
我遇到了同样的问题并且没有找到好的解决方案,所以我创建了一个库来做简单的绘图。这是一个关于如何绘制 3 层神经网络的示例:
from nnv import NNV
layersList = [
{"title":"input\n(relu)", "units": 3, "color": "darkBlue"},
{"title":"hidden 1\n(relu)", "units": 3},
{"title":"output\n(sigmoid)", "units": 1,"color": "darkBlue"},
]
NNV(layersList).render(save_to_file="my_example.png")
You can install that library by doing:
您可以通过执行以下操作来安装该库:
pip install nnv
And find more info about it at: https://github.com/renatosc/nnv/
并在以下位置找到更多信息:https: //github.com/renatosc/nnv/
回答by 0xDFDFDFDF
Thissolution involves both Python and LaTeX. Might be an overkill for your case, but the results are really aesthetic and suit more complicated, modern architectures (deep learning etc.), so I guess it is worth mentioning here. You first need to define your network in Python, such as this one:
该解决方案涉及 Python 和 LaTeX。对于您的案例来说可能有点矫枉过正,但结果确实很美观,适合更复杂的现代架构(深度学习等),所以我想这里值得一提。您首先需要在 Python 中定义您的网络,例如:
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_end()
]
def main():
namefile = str(sys.argv[0]).split('.')[0]
to_generate(arch, namefile + '.tex' )
if __name__ == '__main__':
main()
After that, you generate a TikZ image...
之后,您生成一个 TikZ 图像...
bash ../tikzmake.sh my_arch
...which will yield you a PDF with your network:
...这将为您生成一个包含您网络的 PDF:
Examples are provided in the repo, below one of the them. I've tested it on OS X, should work on Linux as well. Not sure how about Windows. Naturally, you'll need a LaTeX distribution installed.
回购中提供了示例,在其中之一下方。我已经在 OS X 上测试过,应该也适用于 Linux。不知道 Windows 怎么样。当然,您需要安装 LaTeX 发行版。
回答by Pe Dro
This is how I did it:
我是这样做的:
- Head to the online graph creator by Alex : HERE
- Draw your
- Edit the svg file using the online tool at draw.io. For this, simply import the svg file into your workspace.This is how the end result should look like:
- 前往 Alex 的在线图表创建者:这里
- 画你的
- 使用 draw.io 上的在线工具编辑 svg 文件。为此,只需将 svg 文件导入您的工作区。最终结果应如下所示: