2016-10-01 4 views
13

Ich habe meinen Kopf gegen diese Mauer für so etwas wie eine Ewigkeit geschlagen, und ich kann einfach nicht scheinen, meinen Kopf darum zu wickeln. Ich versuche, einen Autoencoder zu implementieren, der nur numpy und Matrixmultiplikation verwendet. Keine theano oder keras Tricks erlaubt.Stuck Implementierung von einfachen neuronalen Netzwerk

Ich werde das Problem und all seine Details beschreiben. Es ist anfangs etwas komplex, da es viele Variablen gibt, aber es ist wirklich ziemlich einfach.

Was wir wissen

1) X ist ein m von n Matrix, die unsere Eingaben ist. Die Eingaben sind Zeilen dieser Matrix. Jede Eingabe ist ein n dimensionaler Zeilenvektor, und wir haben m von ihnen.

2) Die Anzahl der Neuronen in unserer (einzelnen) versteckten Schicht, die k ist.

3) Die Aktivierungsfunktion unserer Neuronen (sigmoid, wird als g(x) bezeichnet) und sein Derivat g'(x)

Was wir wissen und wollen nicht

Insgesamt war unser Ziel zu finden ist finden 6 Matrizen: w1 die n von k ist, b1 die m von k ist, w2 die k von n, b2 ist die m ist durch n, w3 das ist n von n und b3, die m von n ist.

Sie werden zufällig initialisiert und wir finden die beste Lösung mit Gradientenabstieg.

Der Prozess

Der gesamte Prozess so etwas wie dieses enter image description here

Zuerst haben wir z1 = Xw1+b1 berechnen aussieht. Es ist m von k und ist der Eingang zu unserer versteckten Schicht. Wir berechnen dann h1 = g(z1), was einfach die Sigmoidfunktion auf alle Elemente von z1 anwendet. natürlich ist es auch m von k und ist die Ausgabe unserer versteckten Schicht.

Wir berechnen dann z2 = h1w2+b2, die m von n ist und ist der Eingang in die Ausgangsschicht unseres neuronalen Netzes. Dann berechnen wir h2 = g(z2), was wiederum natürlich auch m von n ist und der Ausgang unseres neuronalen Netzes ist.

Schließlich nehmen wir diese Ausgabe und führen einige lineare Operator auf es: Xhat = h2w3+b3, die auch m von n ist und ist unser Endergebnis.

Wo ich stecken bin

Die Kostenfunktion I minimieren wollen, ist der mittlere Fehler im Quadrat. Ich setzte es bereits in numpy Code

def cost(x, xhat): 
    return (1.0/(2 * m)) * np.trace(np.dot(x-xhat,(x-xhat).T)) 

Das Problem ist die Derivate der Kosten in Bezug auf w1,b1,w2,b2,w3,b3 zu finden. Lassen Sie uns die Kosten S nennen.

Nachdem ich mich abzuleiten und mich numerisch Überprüfung habe ich die folgenden Tatsachen festgestellt:

1) dSdxhat = (1/m) * np.dot(xhat-x)

2) dSdw3 = np.dot(h2.T,dSdxhat)

3) dSdb3 = dSdxhat

4) dSdh2 = np.dot(dSdxhat, w3.T)

Aber ich kann nicht für das Leben von mir dSdz2 herausfinden. Es ist eine Backsteinmauer.

Von Chain-Regel sollte es sein, dass dSdz2 = dSdh2 * dh2dz2 aber die Dimensionen nicht übereinstimmen.

Was ist die Formel, um die Ableitung von S in Bezug auf z2 zu berechnen?

Bearbeiten - Dies ist mein Code für den gesamten Feed-Forward-Betrieb des Autoencoders.

import numpy as np 

def g(x): #sigmoid activation functions 
    return 1/(1+np.exp(-x)) #same shape as x! 

def gGradient(x): #gradient of sigmoid 
    return g(x)*(1-g(x)) #same shape as x! 

def cost(x, xhat): #mean squared error between x the data and xhat the output of the machine 
    return (1.0/(2 * m)) * np.trace(np.dot(x-xhat,(x-xhat).T)) 

#Just small random numbers so we can test that it's working small scale 
m = 5 #num of examples 
n = 2 #num of features in each example 
k = 2 #num of neurons in the hidden layer of the autoencoder 
x = np.random.rand(m, n) #the data, shape (m, n) 

w1 = np.random.rand(n, k) #weights from input layer to hidden layer, shape (n, k) 
b1 = np.random.rand(m, k) #bias term from input layer to hidden layer (m, k) 
z1 = np.dot(x,w1)+b1 #output of the input layer, shape (m, k) 
h1 = g(z1) #input of hidden layer, shape (m, k) 

w2 = np.random.rand(k, n) #weights from hidden layer to output layer of the autoencoder, shape (k, n) 
b2 = np.random.rand(m, n) #bias term from hidden layer to output layer of autoencoder, shape (m, n) 
z2 = np.dot(h1, w2)+b2 #output of the hidden layer, shape (m, n) 
h2 = g(z2) #Output of the entire autoencoder. The output layer of the autoencoder. shape (m, n) 

w3 = np.random.rand(n, n) #weights from output layer of autoencoder to entire output of the machine, shape (n, n) 
b3 = np.random.rand(m, n) #bias term from output layer of autoencoder to entire output of the machine, shape (m, n) 
xhat = np.dot(h2, w3)+b3 #the output of the machine, which hopefully resembles the original data x, shape (m, n) 
+0

Sind Sie sicher, dass Ihre Dimensionen nicht ausgerichtet sind, nur weil Sie die Bias-Einheiten zu Ihrer Liste von h2-Einheiten hinzugefügt haben? Das Derivat scheint mir gut zu sein. – Paul

+0

Nun, der Unterschied in den Formen ist größer als 1, also kann es nicht der Verzerrungsterm sein. Und ich berücksichtige auch den Bias-Begriff in meinen Derivaten. –

+1

Apropos deine Voreingenommenheitsbegriffe - normalerweise würdest du eine konstante Voreingenommenheit anwenden (und den Wert davon lernen), und nicht eine andere bei jeder Iteration (dh sie sollten die Form (k,) und (n,) haben). Es gibt nicht viel, was du verallgemeinern kannst, wenn es sich für jede Eingabe ändert. Etwas anderes, das mich verwirrt, ist, dass du eindeutig zwei versteckte Ebenen hast, aber sag, dass du nur eine hast. Ich denke, es wäre hilfreich, wenn du den Code für die vollständige Implementierung - dann können wir sehen, was andere Shenanigans Sie tun. – Paul

Antwort

4

OK, hier ist ein Vorschlag. Wenn Sie im Vektorfall x als Vektor der Länge n haben, dann ist g(x) auch ein Vektor der Länge n. Jedoch ist g'(x) kein Vektor, es ist die Jacobian matrix und wird von der Größe n X n sein. Ähnlich ist in dem Minibatch-Fall, wo X eine Matrix der Größe m X n ist, g(X) ist m X n aber g'(X) ist n X n. Versuchen Sie:

@Paul ist richtig, dass die Verzerrung Begriffe sollten Vektoren sein, nicht Matrizen. Sie sollten:

b1 = np.random.rand(k) #bias term from input layer to hidden layer (k,) 
b2 = np.random.rand(n) #bias term from hidden layer to output layer of autoencoder, shape (n,) 
b3 = np.random.rand(n) #bias term from output layer of autoencoder to entire output of the machine, shape (n,) 

Numpy Rundfunk bedeutet, dass Sie müssen nicht Ihre Berechnung von xhat ändern.

Dann (glaube ich!), Um die Derivate wie folgt berechnen kann:

dSdxhat = (1/float(m)) * (xhat-x) 
dSdw3 = np.dot(h2.T,dSdxhat) 
dSdb3 = dSdxhat.mean(axis=0) 
dSdh2 = np.dot(dSdxhat, w3.T) 
dSdz2 = np.dot(dSdh2, gGradient(z2)) 
dSdb2 = dSdz2.mean(axis=0) 
dSdw2 = np.dot(h1.T,dSdz2) 
dSdh1 = np.dot(dSdz2, w2.T) 
dSdz1 = np.dot(dSdh1, gGradient(z1)) 
dSdb1 = dSdz1.mean(axis=0) 
dSdw1 = np.dot(x.T,dSdz1) 

diese Arbeit für Sie?

bearbeiten

Ich habe beschlossen, dass ich nicht sicher bin, dass gGradient soll eine Matrix sein.Wie wäre es mit:

dSdxhat = (xhat-x)/m 
dSdw3 = np.dot(h2.T,dSdxhat) 
dSdb3 = dSdxhat.sum(axis=0) 
dSdh2 = np.dot(dSdxhat, w3.T) 
dSdz2 = h2 * (1-h2) * dSdh2 
dSdb2 = dSdz2.sum(axis=0) 
dSdw2 = np.dot(h1.T,dSdz2) 
dSdh1 = np.dot(dSdz2, w2.T) 
dSdz1 = h1 * (1-h1) * dSdh1 
dSdb1 = dSdz1.sum(axis=0) 
dSdw1 = np.dot(x.T,dSdz1) 
+0

Ich werde versuchen, aber ich denke, da ist ein Problem. Betrachte die Zeile z1 = np.dot (x, w1) + b1. das Skalarprodukt von x und w1 ist m von k, aber b1 ist (nach Ihnen) k um 1. Das Hinzufügen von ihnen ist unmöglich. Vielleicht meintest du, dass ich dieses k mal um 1 mal m mal replizieren soll? –

+0

Also, [Broadcasting] (http://docs.scipy.org/doc/numpy/user/basics.broadcasting.html) bedeutet, dass numpy automatisch den Vektor für Sie repliziert. – wildwilhelm

+0

Oh, ich sehe, vielen Dank, das wusste ich nicht. Ich werde sicher sein, es zu überprüfen und die Ergebnisse bald zu veröffentlichen! –

Verwandte Themen