我想为神经网络绘制动态图片,以观察体重变化和学习过程中神经元的激活。我怎么能在Python中模拟这个过程?
更确切地说,如果网络形状是:[1000,300,50], 然后我想绘制一个三层NN,分别包含1000,300和50个神经元。 此外,我希望这张照片可以反映每个时期每层神经元的饱和度。
我不知道该怎么做。有人可以对我有所了解吗?
答案 0 :(得分:25)
我根据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()
现在,图层也被标记,轴被删除,构建图更容易。它只是通过以下方式完成:
network = DrawNN( [2,8,8,1] )
network.draw()
这里构建了具有以下结构的网络:
答案 1 :(得分:12)
Python库matplotlib提供了绘制圆和线的方法。它还允许动画。
我已经编写了一些示例代码来说明如何完成此操作。我的代码生成一个神经网络的简单静态图,其中每个神经元连接到前一层中的每个神经元。需要进一步的工作来动画它。
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()
答案 2 :(得分:8)
为了实现Mykhaylo建议的内容,我稍微修改了Milo's code,以便允许提供weghts作为参数,这将影响每一行的宽度。这个参数是可选的,因为没有为最后一层提供权重的意义。 所有这些都能够在神经网络上可视化我对this exercise的解决方案。我已经给出了二进制权重(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()
答案 3 :(得分:6)
这是一个基于matplotlib的库,名为viznet(pip install viznet)。首先,您可以阅读此notebook。这是一个例子
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
这里,node1和node2是两个节点画笔,比如
node1 = NodeBrush('nn.input', ax=d.ax, size='normal')
第一个参数定义节点的主题。对于神经网络节点(主题以' nn。'开头),其样式来自Neural Network Zoo Page。
对于边,我们可以像edge = EdgeBrush('->', ax=d.ax, lw=2)
一样定义其画笔
第一个参数是主题,' - '对于直线,'。'对于虚线,' ='对于双线,'>','<'是左箭头和右箭头。 ' - ','。'的比例。和' ='在主题代码中确定它们的长度。例如,' - >'和' - > - '表示分别带有箭头的箭头和中心的箭头。以下是几个例子
只有节点和边缘是不够的,连接的规则起着根本性的作用。除基本连接规则外,您可以在节点上创建引脚。我会在这里停下来留下文件。这些灵活的功能使其能够绘制张量网络和量子电路。
这个项目刚刚接受了v0.1的发布,我会不断改进它。 您可以访问其Github repo获取最新版本,以及提取请求或发布问题的好处!
答案 4 :(得分:1)
将节点绘制为与线条相连的圆圈。线宽必须与重量成比例。即使没有线路,也可以显示非常小的重量。
答案 5 :(得分:0)
我也遇到同样的问题,没有找到一个好的解决方案,所以我创建了一个库来做简单的绘图。这是有关如何绘制三层NN的示例:
class Card extends StatelessWidget {
final Issue issue;
Color _bgColor;
Card({this.issue}) {
_bgColor = colorSwatch[issue.hashCode % colorSwatch.length];
}
@override
Widget build(BuildContext context) {
return Container(
margin: EdgeInsets.only(top: 12, left: 18, right: 18),
padding: EdgeInsets.only(top: 8, bottom: 8),
decoration: new BoxDecoration(
color: _bgColor,
border: new Border.all(color: _bgColor),
borderRadius: BorderRadius.all(
Radius.circular(10.0)
),
),
child: Row(children: [
IconButton(
padding: EdgeInsets.only(right: 16),
icon: Icon(Icons.play_arrow, color: Colors.white, size: 48),
tooltip: 'Start ${issue.issueName}',
onPressed: () {},
),
Expanded(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Container(
padding: const EdgeInsets.only(bottom: 8),
child: Text(
issue.title,
style: TextStyle(
color: Colors.white,
fontWeight: FontWeight.bold,
),
softWrap: true,
),
),
Text(
issue.issueName,
style: TextStyle(
color: Colors.white,
),
),
],
),
),
]));
}
}
您可以通过以下方式安装该库:
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")
并在以下位置找到有关它的更多信息: https://github.com/renatosc/nnv/
答案 6 :(得分:0)
This解决方案涉及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()
之后,您将生成TikZ图像...
bash ../tikzmake.sh my_arch
...这将为您的网络生成PDF:
示例中的示例之一在回购中提供。我已经在OS X上对其进行了测试,也应该在Linux上也可以使用。不确定Windows。当然,您需要安装LaTeX发行版。
答案 7 :(得分:0)
这就是我的做法: