Implémentation de réseau neuronal en python

introduction

J'ai implémenté un réseau de neurones à 3 couches avec python et essayé d'identifier XNOR. J'ai également publié les formules, donc si vous êtes intéressé, veuillez les lire. J'ai utilisé ["Deep Learning"](http://www.amazon.co.jp/ Deep Learning-Machine Learning Professional Series-Okaya-Takayuki / dp / 4061529021) comme manuel.

Structure de cet article

réseau neuronal

Un réseau neuronal est un modèle qui imite les circuits neuronaux du cerveau humain. La reconnaissance d'image et la reconnaissance vocale sont possibles en utilisant ce modèle. Le réseau mis en œuvre cette fois a une structure à trois couches constituée d'une couche d'entrée, d'une couche intermédiaire (1 couche) et d'une couche de sortie.

Mise à jour du poids

Je vais expliquer avec la figure ci-dessous.

neu.png

Soit le poids de l'unité $ i $ ème dans la couche $ l-1 $ à l'unité $ j $ ème dans la couche $ l $ soit $ w_ {ji} ^ {(l)} $. Aussi, soit $ u_ {i} ^ {(l-1)} $ la valeur détenue par la $ i $ ème unité dans la couche $ l-1 $. La fonction sigmoïde $ g (x) $ est utilisée comme fonction d'activation. C'est pratique car la valeur différentielle peut être obtenue en utilisant la valeur avant différenciation.

g(x) = \cfrac{1}{1 + \exp(-x)} \\
g'(x) = g(x)(1 - g(x))

L'erreur carrée $ E_n $ est utilisée comme fonction objectif et le poids est mis à jour par la formule suivante pour le minimiser. $ E_n $ est l'erreur causée par un échantillon, et la méthode de mise à jour du poids à l'aide de ce $ E_n $ est appelée méthode de descente de gradient stochastique. La méthode de descente de gradient stochastique a l'avantage qu'elle est moins susceptible d'être piégée dans la solution locale car elle change chaque fois que la fonction objectif est mise à jour. $ \ Epsilon $ est appelé le taux d'apprentissage et est un paramètre qui détermine la vitesse d'apprentissage. Le point est de savoir comment calculer le terme de différenciation partielle.

{{w}_{ji}^{(l)}}_{new} = {w_{ji}^{(l)}}_{old} - \epsilon\cfrac{\partial E_n}{\partial {w_{ji}^{(l)}}_{old}}

Erreur de propagation de retour

Maintenant, je vais vous expliquer comment trouver $ \ cfrac {\ partial E_n} {\ partial w_ {ji} ^ {(l)}} $. Étant donné que la méthode d'obtention de la couche de sortie et de la couche intermédiaire sont légèrement différentes, nous les expliquerons séparément.

** ** L'enseignant est représenté par $ t_j $. Lorsque l'erreur carrée $ E_n $ est partiellement différenciée par le poids de la couche en sortie $ w_ {ji} ^ {(l)} $,

\begin{align}
\cfrac{\partial E_n}{\partial w_{ji}^{(l)}} &= \cfrac{\partial}{\partial w_{ji}^{(l)}}\cfrac{1}{2}(t_j - g(u_{j}^{(l)}))^{2} \\
&= (t_j - g(u_{j}^{(l)}))\cdot\cfrac{\partial}{\partial w_{ji}^{(l)}}(t_j - g(u_{j}^{(l)})) \\
&= (t_j - g(u_{j}^{(l)}))\cdot\cfrac{\partial}{\partial u_{j}^{(l)}}(t_j - g(u_{j}^{(l)}))\cdot\cfrac{\partial u_{j}^{(l)}}{\partial w_{ji}^{(l)}} \\
\\
&= (g(u_{j}^{(l)}) - t_j)\cdot g'(u_{j}^{(l)})\cdot g(u_{i}^{(l-1)}) \\
\\
&= (g(u_{j}^{(l)}) - t_j)g(u_{j}^{(l)})(1 - g(u_{j}^{(l)}))g(u_{i}^{(l-1)})
\end{align}

** <Couche intermédiaire> ** Lorsque l'erreur carrée $ E_n $ est partiellement différenciée par le poids de la couche intermédiaire $ w_ {ji} ^ {(l)} $,

\begin{align}
\cfrac{\partial E_n}{\partial w_{ji}^{(l)}} &= \cfrac{\partial E_n}{\partial u_{j}^{(l)}}\cfrac{\partial u_{j}^{(l)}}{\partial w_{ji}^{(l)}} \\
\\
&= \delta_{j}^{(l)}\cfrac{\partial u_{j}^{(l)}}{\partial w_{ji}^{(l)}}
\end{align}

Le premier terme du côté droit est

\begin{align}
\delta_{j}^{(l)} &= \cfrac{\partial E_n}{\partial u_{j}^{(l)}} \\
&= \sum_{k}\cfrac{\partial E_n}{\partial u_{k}^{(l+1)}}\cfrac{\partial u_{k}^{(l+1)}}{\partial u_{j}^{(l)}} \\
\\
&= \sum_{k}\delta_{k}^{(l+1)}w_{kj}^{(l+1)}g'(u_{j}^{(l)}) \\
\\
&= \Bigl(\sum_{k}\delta_{k}^{(l+1)}w_{kj}^{(l+1)}\Bigr)g(u_{j}^{(l)})(1 - g(u_{j}^{(l)}))
\end{align}

Le deuxième terme sur le côté droit est

\begin{align}
\cfrac{\partial u_{j}^{(l)}}{\partial w_{ji}^{(l)}} &= g(u_{i}^{(l-1)})
\end{align}

De ce qui précède,

\begin{align}
\cfrac{\partial E_n}{\partial w_{ji}^{(l)}} &= \delta_{j}^{(l)}\cfrac{\partial u_{j}^{(l)}}{\partial w_{ji}^{(l)}} \\
\\
&= \Bigl(\sum_{k}\delta_{k}^{(l+1)}w_{kj}^{(l+1)}\Bigr)g(u_{j}^{(l)})(1 - g(u_{j}^{(l)}))g(u_{i}^{(l-1)})
\end{align}

Lors de la mise à jour du poids de la couche intermédiaire $ l $, $ \ delta_ {k} ^ {(l + 1)} $ de la couche suivante $ l + 1 $ est nécessaire. $ \ Delta $ dans la couche de sortie peut être obtenu comme la différence entre la valeur de sortie et l'enseignant, et en propageant ceci dans l'ordre de la couche de sortie à la couche d'entrée, le poids de la couche intermédiaire est mis à jour. C'est la raison pour laquelle il est appelé propagation de retour d'erreur.

XNOR

XNOR génère $ 1 $ lorsque les valeurs d'entrée sont identiques et $ 0 $ lorsque les valeurs d'entrée sont différentes. Il ne peut pas être identifié de manière linéaire.

x_1 x_2 t
0 0 1
0 1 0
1 0 0
1 1 1
xnor.png

Implémentation en python

Nous avons implémenté un réseau neuronal qui identifie XNOR. Le nombre de couches intermédiaires est de un et le nombre d'unités dans la couche intermédiaire est de deux. Le taux d'apprentissage est $ \ epsilon = 0,1 $ et le coefficient d'élan est $ \ mu = 0,9 $. (Momentum est l'une des méthodes pour améliorer les performances de convergence, et le montant de correction de poids est ajouté en multipliant le montant de correction de poids précédent par un coefficient.)

neuralnetwork.py


import numpy
import math
import random
from matplotlib import pyplot

class Neural:

	# constructor
	def __init__(self, n_input, n_hidden, n_output):
		self.hidden_weight = numpy.random.random_sample((n_hidden, n_input + 1))
		self.output_weight = numpy.random.random_sample((n_output, n_hidden + 1))
		self.hidden_momentum = numpy.zeros((n_hidden, n_input + 1))
		self.output_momentum = numpy.zeros((n_output, n_hidden + 1))


# public method
	def train(self, X, T, epsilon, mu, epoch):
		self.error = numpy.zeros(epoch)
		N = X.shape[0]
		for epo in range(epoch):
			for i in range(N):
				x = X[i, :]
				t = T[i, :]

				self.__update_weight(x, t, epsilon, mu)

			self.error[epo] = self.__calc_error(X, T)


	def predict(self, X):
		N = X.shape[0]
		C = numpy.zeros(N).astype('int')
		Y = numpy.zeros((N, X.shape[1]))
		for i in range(N):
			x = X[i, :]
			z, y = self.__forward(x)

			Y[i] = y
			C[i] = y.argmax()

		return (C, Y)


	def error_graph(self):
		pyplot.ylim(0.0, 2.0)
		pyplot.plot(numpy.arange(0, self.error.shape[0]), self.error)
		pyplot.show()


# private method
	def __sigmoid(self, arr):
		return numpy.vectorize(lambda x: 1.0 / (1.0 + math.exp(-x)))(arr)


	def __forward(self, x):
		# z: output in hidden layer, y: output in output layer
		z = self.__sigmoid(self.hidden_weight.dot(numpy.r_[numpy.array([1]), x]))
		y = self.__sigmoid(self.output_weight.dot(numpy.r_[numpy.array([1]), z]))

		return (z, y)

	def __update_weight(self, x, t, epsilon, mu):
		z, y = self.__forward(x)

		# update output_weight
		output_delta = (y - t) * y * (1.0 - y)
		_output_weight = self.output_weight
		self.output_weight -= epsilon * output_delta.reshape((-1, 1)) * numpy.r_[numpy.array([1]), z] - mu * self.output_momentum
		self.output_momentum = self.output_weight - _output_weight

		# update hidden_weight
		hidden_delta = (self.output_weight[:, 1:].T.dot(output_delta)) * z * (1.0 - z)
		_hidden_weight = self.hidden_weight
		self.hidden_weight -= epsilon * hidden_delta.reshape((-1, 1)) * numpy.r_[numpy.array([1]), x]
		self.hidden_momentum = self.hidden_weight - _hidden_weight


	def __calc_error(self, X, T):
		N = X.shape[0]
		err = 0.0
		for i in range(N):
			x = X[i, :]
			t = T[i, :]

			z, y = self.__forward(x)
			err += (y - t).dot((y - t).reshape((-1, 1))) / 2.0

		return err

main.py


from neuralnetwork import *

if __name__ == '__main__':

	X = numpy.array([[0, 0], [0, 1], [1, 0], [1, 1]])
	T = numpy.array([[1, 0], [0, 1], [0, 1], [1, 0]])
	N = X.shape[0] # number of data

	input_size = X.shape[1]
	hidden_size = 2
	output_size = 2
	epsilon = 0.1
	mu = 0.9
	epoch = 10000

	nn = Neural(input_size, hidden_size, output_size)
	nn.train(X, T, epsilon, mu, epoch)
	nn.error_graph()

	C, Y = nn.predict(X)

	for i in range(N):
		x = X[i, :]
		y = Y[i, :]
		c = C[i]

		print x
		print y
		print c
		print ""

résultat

Il peut être identifié correctement.

x_1 x_2 t y
0 0 [ 1, 0 ] [ 0.92598739, 0.07297757 ]
0 1 [ 0, 1 ] [ 0.06824915, 0.93312514 ]
1 0 [ 0, 1 ] [ 0.06828438, 0.93309010 ]
1 1 [ 1, 0 ] [ 0.92610205, 0.07220633 ]

J'ai fait un graphique montrant comment l'erreur diminue. L'axe horizontal est le nombre d'époques et l'axe vertical est l'erreur.

error.png

en conclusion

Nous avons implémenté un réseau neuronal à trois couches et avons pu identifier XNOR. Il y a encore du travail à faire, comme des astuces d'apprentissage (comment déterminer la valeur de poids initiale, comment déterminer le taux d'apprentissage, AdaGrad, momentum), mais c'est la fin.

Recommended Posts

Implémentation de réseau neuronal en python
PRML Chapitre 5 Implémentation Python du réseau neuronal
Implémentation RNN en python
Implémentation ValueObject en Python
Implémentation SVM en python
Implémentation du tri rapide en Python
Implémentation de réseau neuronal (NumPy uniquement)
Implémentation simple d'un réseau neuronal à l'aide de Chainer
Réseau neuronal avec OpenCV 3 et Python 3
Algorithme de tri et implémentation en Python
Implémentation de l'estimation des paramètres HMM en python
Implémentation de distribution normale mixte en python
Implémentation d'un réseau de neurones à deux couches 2
Implémentation du jeu de vie en Python
Théorie et implémentation simples des réseaux neuronaux
Implémentation du tri original en Python
Essayez de créer un réseau de neurones en Python sans utiliser de bibliothèque
Quadtree en Python --2
CURL en Python
Métaprogrammation avec Python
Python 3.3 avec Anaconda
Géocodage en python
SendKeys en Python
PRML Chapter 5 Implémentation Python de réseau à densité mixte
Méta-analyse en Python
Unittest en Python
Module d'implémentation de file d'attente et Python "deque"
Implémentation d'un réseau neuronal à 3 couches (pas d'apprentissage)
Discord en Python
DCI en Python
tri rapide en python
nCr en python
N-Gram en Python
Programmation avec Python
Plink en Python
Constante en Python
Sqlite en Python
Étape AIC en Python
Implémentation de réseaux neuronaux "flous" avec Chainer
Implémentation de réseau neuronal simple à l'aide de la préparation Chainer-Data-
Implémenté dans Python PRML Chapter 5 Neural Network
LINE-Bot [0] en Python
CSV en Python
Assemblage inversé avec Python
Réflexion en Python
Constante en Python
nCr en Python.
format en python
Scons en Python 3
Mémo d'étude Python & Machine Learning ③: Réseau neuronal
Puyopuyo en python
python dans virtualenv
PPAP en Python
Quad-tree en Python
Réflexion en Python
Implémentation de réseau neuronal simple à l'aide de la description du modèle Chainer-
Chimie avec Python
Hashable en Python
DirectLiNGAM en Python