如何可视化神经网络

时间:2015-04-27 05:58:48

标签: python image neural-network

我想为神经网络绘制动态图片,以观察体重变化和学习过程中神经元的激活。我怎么能在Python中模拟这个过程?

更确切地说,如果网络形状是:[1000,300,50], 然后我想绘制一个三层NN,分别包含1000,300和50个神经元。 此外,我希望这张照片可以反映每个时期每层神经元的饱和度。

我不知道该怎么做。有人可以对我有所了解吗?

8 个答案:

答案 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()

这里构建了具有以下结构的网络:

  • 输入图层中的2个神经元
  • 第一个隐藏层中的8个神经元
  • 第二个隐藏层中的8个神经元
  • 输出图层中的1个神经元enter image description here

答案 1 :(得分:12)

Python库matplotlib提供了绘制圆和线的方法。它还允许动画。

我已经编写了一些示例代码来说明如何完成此操作。我的代码生成一个神经网络的简单静态图,其中每个神经元连接到前一层中的每个神经元。需要进一步的工作来动画它。

I've also made it available in a Git repository

A generated neural network diagram

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。这是一个例子 enter image description here

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 Pageenter image description here

对于,我们可以像edge = EdgeBrush('->', ax=d.ax, lw=2)一样定义其画笔 第一个参数是主题,' - '对于直线,'。'对于虚线,' ='对于双线,'>','<'是左箭头和右箭头。 ' - ','。'的比例。和' ='在主题代码中确定它们的长度。例如,' - >'和' - > - '表示分别带有箭头的箭头和中心的箭头。以下是几个例子 enter image description here

只有节点和边缘是不够的,连接的规则起着根本性的作用。除基本连接规则外,您可以在节点上创建引脚。我会在这里停下来留下文件。这些灵活的功能使其能够绘制张量网络量子电路

这个项目刚刚接受了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,
              ),
            ),
          ],
        ),
      ),
    ]));
  }
}

enter image description here

您可以通过以下方式安装该库:

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:

enter image description here

示例中的示例之一在回购中提供。我已经在OS X上对其进行了测试,也应该在Linux上也可以使用。不确定Windows。当然,您需要安装LaTeX发行版。

enter image description here

答案 7 :(得分:0)

这就是我的做法:

  • 前往Alex的在线图形创建者:HERE
  • 画你的
    • 使用FCNN(全连接神经网络)的浅层网络(由简单的输入-隐藏-输出层组成)
    • 或使用LeNet或AlexNet样式的深度/卷积网络。 这是您现在要拥有的:Shallow FCNN
  • 使用draw.io上的在线工具编辑svg文件。为此,只需将svg文件导入您的工作区中即可,这就是最终结果应如下所示:

enter image description here