2015-04-27 5 views
9

Я хочу нарисовать динамическую картинку для нейронной сети, чтобы наблюдать изменения веса и активировать нейроны во время обучения. Как я смоделировал процесс в Python?Как визуализировать нейронную сеть

Точнее, если форма сети: [1000, 300, 50], , тогда я хочу нарисовать трехслойный NN, который содержит 1000, 300 и 50 нейронов соответственно. Кроме того, я надеюсь, что изображение может отражать насыщение нейронов на каждом слое в каждую эпоху.

Я понятия не имею, как это сделать. Может кто-то пролить свет на меня?

+0

[graphwiz] (http://www.graphviz.org)? –

+0

Должны ли они быть видимыми в одно и то же время (со значениями)? – Caramiriel

+0

@Caramiriel Да. Существуют ли пакеты, поддерживающие эти потребности? – fishiwhj

ответ

1

Нарисуйте сеть узлами в виде кругов, связанных с линиями. Ширина линии должна быть пропорциональна весам. Очень маленькие весы могут отображаться даже без линии.

9

Библиотека 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() 
5

Чтобы осуществить то, что 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() 
13

Я приспособил некоторые части к ответу Милосской

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 = plotNN.DrawNN([2,8,8,1]) 
network.draw() 

Здесь чистый со следующей структурой строится:

  • 2 Нейроны во входном слое
  • 8 Нейроны в 1 скрытый слой
  • 8 Нейроны второй скрытый слой
  • 1 Нейрон в выходном слое enter image description here
0

Здесь находится библиотека, основанная на matplotlib, названная viznet (pip install viznet). Ниже приведен пример 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 

Здесь узел1 и узел2 два узла щетки, как node1 = NodeBrush('nn.input', ax=d.ax, size='normal')

Первый параметр определяет тему узла. . Для нейронной сети узла («пп» тема начать с), его стиль относится с Neural Network Zoo Page enter image description here

Для края, мы можем определить его кисть как edge = EdgeBrush('->', ax=d.ax, lw=2) Первые параметры тема, «-» для прямой, '.' для пунктирной линии '=' для двойной линии, '>', '<' - стрелка влево и вправо. Доля '-', '.' и '=' в коде темы решает их длину в строке. Например, '->' и '-> -' представляет строки со стрелкой в ​​конце и стрелкой в ​​центре соответственно. Ниже приведено несколько примеров enter image description here

С только узлами и ребрами не достаточно, то правило для связи играет роль принципиально. Кроме основного правила подключения, вы можете создавать контакты на узлах. Я остановлюсь здесь и оставлю его для документов. Эти гибкие функции делают его пригодным для нанесения также тензорных сетей и квантовых цепей.

Этот проект только что принял его выпуск v0.1, я продолжу его улучшать. Вы можете получить доступ к своему Github repo для получения последней версии, а также о доходах для потянув запросы или публикации вопросов!