web-dev-qa-db-ja.com

ニューラルネットワークを視覚化する方法

学習中に変化する重みとニューロンの活性化を監視するために、ニューラルネットワークの動的な図を描きたいと思います。 Pythonでプロセスをどのようにシミュレートできますか?

より正確には、ネットワーク形状が[1000、300、50]の場合、それぞれ1000、300および50個のニューロンを含む3層のNNを描画します。さらに、写真が各エポック中の各層のニューロンの飽和を反映できることを願っています。

どうすればいいのか分かりません。誰かが私に光を当てることができますか?

21
fishiwhj

ミロの答えにいくつかの部分を適応させた

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つのニューロン
  • 1番目の隠れ層の8つのニューロン
  • 2番目の隠れ層の8つのニューロン
  • 1出力層のニューロン enter image description here
27
Oliver Wilken

Python library matplotlib は、円と線を描画するメソッドを提供します。アニメーションも可能です。

これを行う方法を示すサンプルコードをいくつか作成しました。私のコードは、各ニューロンが前の層のすべてのニューロンに接続されている、ニューラルネットワークの単純な静的ダイアグラムを生成します。それをアニメーション化するには、さらなる作業が必要になります。

Gitリポジトリでも利用できるようにしました

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()
13
Milo

Mykhaylo が提案したものを実装するために、 Miloのコード を少し変更して、すべての行の幅に影響する引数としてweghtsを提供できるようにしました。最後のレイヤーに重みを指定する意味がないため、この引数はオプションです。このすべてが、ニューラルネットワークで この演習 に対するソリューションを視覚化できるようにします。バイナリウェイト(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()
8
DenisFLASH

viznet (pip install viznet)という名前のmatplotlibに基づくライブラリを次に示します。最初に、これを読むことができます 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')のような2つのnodeブラシです

最初のパラメーターは、ノードのテーマを定義します。ニューラルネットワークノード(テーマは「nn。」で始まる)の場合、スタイルは Neural Network Zoo Pageenter image description here

edgesの場合、Edge = EdgeBrush('->', ax=d.ax, lw=2)のようにブラシを定義できます。最初のパラメーターはテーマ、直線の場合は '-'です。 '破線の場合は「=」、二重線の場合は「>」、「<」は左矢印と右矢印です。 「-」、「。」の割合テーマコードの「=」は、行の長さを決定します。たとえば、「->」と「->-」は、それぞれ端に矢印があり、中央に矢印がある行を表します。以下はいくつかの例です enter image description here

ノードとエッジだけでは不十分であるため、connectionのルールが基本的な役割を果たします。基本的な接続ルールを除き、ノードにピンを作成できます。ここで立ち止まって、書類のために残します。これらの柔軟な機能により、テンソルネットワークおよび量子回路も描画可能。

このプロジェクトはv0.1リリースを受け入れたばかりで、改善を続けていきます。 Github repo にアクセスして最新バージョンを入手し、プルリクエストまたはにようこそ投稿の問題

6
刘金国

線で結ばれた円のようなノードでネットワークを描きます。線の幅は、重みに比例する必要があります。線がなくても、非常に小さな重みを表示できます。

私は同じ問題を抱えていて、良い解決策を見つけられなかったので、簡単な描画を行うためのライブラリを作成しました。 3層のNNを描く方法の例を次に示します。

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")

enter image description here

以下を実行することで、そのライブラリをインストールできます。

pip install nnv

そして、それについての詳細情報を見つける: https://github.com/renatosc/nnv/

0
rsc

これ ソリューションには、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

例は、リポジトリの1つの下にあります。 OS Xでテストしましたが、Linuxでも動作するはずです。 Windowsについてはわかりません。当然、LaTeXディストリビューションがインストールされている必要があります。

enter image description here

0
0xDFDFDF