2016-04-02 5 views
2

Ich habe das folgende neuronale Netzwerk implementiert, um das XOR-Problem in Python zu lösen. Mein neuronales Netzwerk besteht aus einer Eingangsschicht von 2 Neuronen, einer versteckten Schicht von 2 Neuronen und einer Ausgangsschicht von 1 Neuron. Ich verwende die Sigmoid-Funktion als Aktivierungsfunktion für die verborgene Schicht und die linearen (Identität) Funktion als Aktivierungsfunktion für die Ausgangsschicht:XOR Neuronales Netzwerk konvergiert zu 0.5

import numpy as np 

def sigmoid(z): 
    return 1/(1+np.exp(-z)) 

def s_prime(z): 
    return np.multiply(sigmoid(z), sigmoid(1.0-z)) 

def init_weights(layers, epsilon): 
    weights = [] 
    for i in range(len(layers)-1): 
     w = np.random.rand(layers[i+1], layers[i]+1) 
     w = w * 2*epsilon - epsilon 
     weights.append(np.mat(w)) 
    return weights 

def fit(X, Y, w, predict=False, x=None): 
    w_grad = ([np.mat(np.zeros(np.shape(w[i]))) 
       for i in range(len(w))]) 
    for i in range(len(X)): 
     x = x if predict else X[0] 
     y = Y[0,i] 
     # forward propagate 
     a = x 
     a_s = [] 
     for j in range(len(w)): 
      a = np.mat(np.append(1, a)).T 
      a_s.append(a) 
      z = w[j] * a 
      a = sigmoid(z) 
     if predict: return a 
     # backpropagate 
     delta = a - y.T 
     w_grad[-1] += delta * a_s[-1].T 
     for j in reversed(range(1, len(w))): 
      delta = np.multiply(w[j].T*delta, s_prime(a_s[j])) 
      w_grad[j-1] += (delta[1:] * a_s[j-1].T) 
    return [w_grad[i]/len(X) for i in range(len(w))] 

def predict(x): 
    return fit(X, Y, w, True, x) 

#### 

X = np.mat([[0,0], 
      [0,1], 
      [1,0], 
      [1,1]]) 
Y = np.mat([0,1,1,0]) 
layers = [2,2,1] 
epochs = 10000 
alpha = 0.5 
w = init_weights(layers, 1) 

for i in range(epochs): 
    w_grad = fit(X, Y, w) 
    print w_grad 
    for j in range(len(w)): 
     w[j] -= alpha * w_grad[j] 

for i in range(len(X)): 
    x = X[i] 
    guess = predict(x) 
    print x, ":", guess 

Die Backpropagation für alle scheint richtig zu sein; das einzige Problem, das mir in den Sinn kommt, wäre ein Problem mit meiner Implementierung der Bias-Einheiten. In jedem Fall konvergieren alle Vorhersagen für jede Eingabe bei jeder Ausführung des Codes auf etwa 0,5. Ich habe den Code durchforstet und kann nicht finden, was falsch ist. Kann irgendjemand auf meine Implementierung hinweisen? Ich freue mich über jede Rückmeldung.

Wenn aus irgendeinem Grund könnte es, hier ist die Art der Ausgabe erhalte ich helfen:

[[0 0]] : [[ 0.5]] 
[[0 1]] : [[ 0.49483673]] 
[[1 0]] : [[ 0.52006739]] 
[[1 1]] : [[ 0.51610963]] 
+0

Eigentlich Code Sigmoidfunktion das Derivat kleines Problem, da 'g '(z) = a * (1-a) zu berechnen, bedeutet g Sigmoidfunktion, a = sigmoid (z) ', und Sie übergeben' a_s [j] 'an' s_prime() ', so sollte Ihr' s_prime() '' return np.multiply (z, 1.0-z) 'anstelle von' return np.multiply (Sigmoid (z), Sigmoid (1.0-z)) '. – Belter

Antwort

1

Ihre Implementierung von Vorwärts- und Backpropagation ist mehr oder weniger richtig. Aber wo du falsch liegst, ist ziemlich einfach. Der erste kleine Fehler ist in Ihrer fit Funktion aussehen - speziell die erste Anweisung in Ihrer for Schleife:

x = x if predict else X[0] 

Sie sagen, dass, wenn Sie nicht sagen voraus (dh Training durchführen), den Eingang Beispiel während jedem gewählt Iteration von Stochastic Gradient Descent muss immer das erste Beispiel sein, das ist [0 0] (dh X[0]). Dies ist der Grund, warum Sie 0,5 für alle Ihre Vorhersagen erhalten, weil Sie nur mit der ersten Eingabe trainieren. Sie müssen dies ändern, so dass es das richtige Beispiel liest, das Beispiel ist i:

x = x if predict else X[i] 

Die letzte Änderung, die Sie machen müssen, ist Ihre s_prime Funktion. Die Ableitung der Sigmoidfunktion ist in der Tat, was haben Sie da:

def s_prime(z): 
    return np.multiply(sigmoid(z), sigmoid(1.0-z)) 

Wenn Sie die Vorwärtspropagation berechnen, Sie haben bereits die Ausgangsaktivierungen jedes Neuron in a_s berechnet, so dass, wenn Sie berechnen die lokale Ableitung an diesen Neuronen , liefern Sie die Ausgangsaktivierungen direkt an s_prime, so dass Sie das Sigmoid nicht erneut berechnen müssen.

Deshalb:

def s_prime(z): 
    return np.multiply(z, 1.0-z) 

Nachdem ich diese beiden Änderungen vorgenommen haben, bekommen wir jetzt diese Ausgabe:

[[0 0]] : [[ 0.00239857]] 
[[0 1]] : [[ 0.99816778]] 
[[1 0]] : [[ 0.99816596]] 
[[1 1]] : [[ 0.0021052]] 

Sie können sehen, dass dies mit dem erwarteten Ausgang des XOR-Gatters stimmt mehr oder weniger . Eine letzte Sache, die ich empfehlen kann, ist, dass 10000 Iterationen viel zu lange rechnerisch Ihrer aktuellen Codestruktur entsprechen. Ich habe festgestellt, dass wir mit den obigen Korrekturen die erwartete Ausgabe in weniger Iterationen erreichen können. Ich habe die Iterationen auf 1000 verringert und die Lernrate alpha auf 0,75 erhöht. Ändern dieser beiden Dinge bekommen wir jetzt:

[[0 0]] : [[ 0.03029435]] 
[[0 1]] : [[ 0.95397528]] 
[[1 0]] : [[ 0.95371525]] 
[[1 1]] : [[ 0.04796917]] 
+1

Meine Güte, das war einfach, kann nicht glauben, dass ich das verpasst habe. Danke eine Million – Sam

+2

@Sam Sie sind herzlich willkommen. Ich war dort ... wo ich stundenlang auf Code gestarrt habe und ich kann nicht herausfinden, was falsch ist. Ich zeige einen Kumpel von mir und er bemerkt es sofort und es ist einer dieser kleinen, aber sehr wichtigen Fehler! Es hilft, wenn Sie eine frische Augen bekommen, um festzustellen, was los ist :). – rayryeng

Verwandte Themen