├── .gitignore ├── README.md ├── LICENSE.md └── main.py /.gitignore: -------------------------------------------------------------------------------- 1 | **/*.pyc 2 | .idea\ 3 | .idea/ 4 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Visualise Neural Network 2 | Generates a static diagram of a neural network, where each neuron is connected to every neuron in the previous layer. 3 | 4 | For example, this code: 5 | 6 | network = NeuralNetwork() 7 | network.add_layer(3) 8 | network.add_layer(4) 9 | network.add_layer(1) 10 | network.draw() 11 | 12 | Will generate this diagram: 13 | 14 | ![Diagram of a neural network with 3 neurons in the first layer, 4 neurons in the second layer and 1 neuron in the 3rd layer](http://i.stack.imgur.com/8oxCO.png) 15 | -------------------------------------------------------------------------------- /LICENSE.md: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2015 Milo Spencer-Harper 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. -------------------------------------------------------------------------------- /main.py: -------------------------------------------------------------------------------- 1 | from matplotlib import pyplot 2 | from math import cos, sin, atan 3 | 4 | 5 | class Neuron(): 6 | def __init__(self, x, y): 7 | self.x = x 8 | self.y = y 9 | 10 | def draw(self): 11 | circle = pyplot.Circle((self.x, self.y), radius=neuron_radius, fill=False) 12 | pyplot.gca().add_patch(circle) 13 | 14 | 15 | class Layer(): 16 | def __init__(self, network, number_of_neurons): 17 | self.previous_layer = self.__get_previous_layer(network) 18 | self.y = self.__calculate_layer_y_position() 19 | self.neurons = self.__intialise_neurons(number_of_neurons) 20 | 21 | def __intialise_neurons(self, number_of_neurons): 22 | neurons = [] 23 | x = self.__calculate_left_margin_so_layer_is_centered(number_of_neurons) 24 | for iteration in xrange(number_of_neurons): 25 | neuron = Neuron(x, self.y) 26 | neurons.append(neuron) 27 | x += horizontal_distance_between_neurons 28 | return neurons 29 | 30 | def __calculate_left_margin_so_layer_is_centered(self, number_of_neurons): 31 | return horizontal_distance_between_neurons * (number_of_neurons_in_widest_layer - number_of_neurons) / 2 32 | 33 | def __calculate_layer_y_position(self): 34 | if self.previous_layer: 35 | return self.previous_layer.y + vertical_distance_between_layers 36 | else: 37 | return 0 38 | 39 | def __get_previous_layer(self, network): 40 | if len(network.layers) > 0: 41 | return network.layers[-1] 42 | else: 43 | return None 44 | 45 | def __line_between_two_neurons(self, neuron1, neuron2): 46 | angle = atan((neuron2.x - neuron1.x) / float(neuron2.y - neuron1.y)) 47 | x_adjustment = neuron_radius * sin(angle) 48 | y_adjustment = neuron_radius * cos(angle) 49 | line = pyplot.Line2D((neuron1.x - x_adjustment, neuron2.x + x_adjustment), (neuron1.y - y_adjustment, neuron2.y + y_adjustment)) 50 | pyplot.gca().add_line(line) 51 | 52 | def draw(self): 53 | for neuron in self.neurons: 54 | neuron.draw() 55 | if self.previous_layer: 56 | for previous_layer_neuron in self.previous_layer.neurons: 57 | self.__line_between_two_neurons(neuron, previous_layer_neuron) 58 | 59 | 60 | class NeuralNetwork(): 61 | def __init__(self): 62 | self.layers = [] 63 | 64 | def add_layer(self, number_of_neurons): 65 | layer = Layer(self, number_of_neurons) 66 | self.layers.append(layer) 67 | 68 | def draw(self): 69 | for layer in self.layers: 70 | layer.draw() 71 | pyplot.axis('scaled') 72 | pyplot.show() 73 | 74 | if __name__ == "__main__": 75 | vertical_distance_between_layers = 6 76 | horizontal_distance_between_neurons = 2 77 | neuron_radius = 0.5 78 | number_of_neurons_in_widest_layer = 4 79 | network = NeuralNetwork() 80 | network.add_layer(3) 81 | network.add_layer(4) 82 | network.add_layer(1) 83 | network.draw() 84 | --------------------------------------------------------------------------------