Ich habe ein 3-Schicht-Neuronales Netzwerk mit Python implementiert und versucht, XNOR zu identifizieren. Ich habe auch die Formeln veröffentlicht. Wenn Sie interessiert sind, lesen Sie sie bitte. Ich habe ["Deep Learning"](http://www.amazon.co.jp/ Deep Learning-Maschinelles Lernen Professional Series-Okaya-Takayuki / dp / 4061529021) als Lehrbuch verwendet.
Struktur dieses Artikels
Ein neuronales Netzwerk ist ein Modell, das die neuronalen Schaltkreise des menschlichen Gehirns nachahmt. Mit diesem Modell sind Bilderkennung und Spracherkennung möglich. Das diesmal implementierte Netzwerk hat eine dreischichtige Struktur, die aus einer Eingangsschicht, einer Zwischenschicht (1 Schicht) und einer Ausgangsschicht besteht.
Ich werde mit der folgenden Abbildung erklären.
Das Gewicht von der $ i $ -ten Einheit in der $ l-1 $ -Ebene zur $ j $ -ten Einheit in der $ l $ -Ebene sei $ w_ {ji} ^ {(l)} $. Außerdem sei $ u_ {i} ^ {(l-1)} $ der Wert, der von der $ i $ -ten Einheit in der $ l-1 $ -Ebene gehalten wird. Die Sigmoidfunktion $ g (x) $ wird als Aktivierungsfunktion verwendet. Dies ist zweckmäßig, da der Differenzwert unter Verwendung des Werts vor der Differenzierung erhalten werden kann.
g(x) = \cfrac{1}{1 + \exp(-x)} \\
g'(x) = g(x)(1 - g(x))
Der quadratische Fehler $ E_n $ wird als Zielfunktion verwendet, und das Gewicht wird durch die folgende Formel aktualisiert, um es zu minimieren. $ E_n $ ist der Fehler, der durch eine Stichprobe verursacht wird, und die Methode zum Aktualisieren des Gewichts unter Verwendung dieser $ E_n $ wird als stochastische Gradientenabstiegsmethode bezeichnet. Die probabilistische Gradientenabstiegsmethode hat den Vorteil, dass sie weniger wahrscheinlich in der lokalen Lösung eingeschlossen ist, da sie sich jedes Mal ändert, wenn die Zielfunktion aktualisiert wird. $ \ Epsilon $ wird als Lernrate bezeichnet und ist ein Parameter, der die Lerngeschwindigkeit bestimmt. Der Punkt ist, wie der Begriff der partiellen Differenzierung berechnet wird.
{{w}_{ji}^{(l)}}_{new} = {w_{ji}^{(l)}}_{old} - \epsilon\cfrac{\partial E_n}{\partial {w_{ji}^{(l)}}_{old}}
Jetzt werde ich erklären, wie man $ \ cfrac {\ partielles E_n} {\ partielles w_ {ji} ^ {(l)}} $ findet. Da sich die Methode zum Erhalten der Ausgabeschicht und der Zwischenschicht geringfügig unterscheidet, werden sie separat erläutert.
**
\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}
**
\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}
Der erste Begriff auf der rechten Seite ist
\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}
Der zweite Term auf der rechten Seite ist
\begin{align}
\cfrac{\partial u_{j}^{(l)}}{\partial w_{ji}^{(l)}} &= g(u_{i}^{(l-1)})
\end{align}
Von Oben,
\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}
Beim Aktualisieren des Gewichts der mittleren Schicht $ l $ wird $ \ delta_ {k} ^ {(l + 1)} $ der nächsten Schicht $ l + 1 $ benötigt. $ \ Delta $ in der Ausgabeschicht kann als Differenz zwischen dem Ausgabewert und dem Lehrer erhalten werden, und indem dies in der Reihenfolge von der Ausgabeschicht zur Eingabeschicht weitergegeben wird, wird das Gewicht der Zwischenschicht aktualisiert. Dies ist der Grund, warum es als Fehlerrückübertragung bezeichnet wird.
XNOR
XNOR gibt $ 1 $ aus, wenn die Eingabewerte gleich sind, und $ 0 $, wenn die Eingabewerte unterschiedlich sind. Es kann nicht linear identifiziert werden.
0 | 0 | 1 |
0 | 1 | 0 |
1 | 0 | 0 |
1 | 1 | 1 |
Wir haben ein neuronales Netzwerk implementiert, das XNOR identifiziert. Die Anzahl der Zwischenschichten beträgt eins und die Anzahl der Einheiten in der Zwischenschicht beträgt zwei. Die Lernrate beträgt $ \ epsilon = 0,1 $ und der Impulskoeffizient beträgt $ \ mu = 0,9 $. (Momentum ist eine der Methoden zur Verbesserung der Konvergenzleistung, und der Gewichtskorrekturbetrag wird addiert, indem der vorherige Gewichtskorrekturbetrag mit einem Koeffizienten multipliziert wird.)
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 ""
Es kann korrekt identifiziert werden.
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 ] |
Ich habe eine Grafik erstellt, die zeigt, wie der Fehler abnimmt. Die horizontale Achse ist die Anzahl der Epochen und die vertikale Achse ist der Fehler.
Wir haben ein dreischichtiges neuronales Netzwerk implementiert und konnten XNOR identifizieren. Es gibt noch viel zu tun, wie zum Beispiel Lerntricks (wie man den anfänglichen Gewichtswert bestimmt, wie man die Lernrate bestimmt, AdaGrad, Impuls), aber dies ist das Ende.
Recommended Posts