2016-07-01 16 views
4

Ich bin ein Neuling im maschinellen Lernen und ich folge Tensorflow Tutorial, um einige einfache Neuronale Netze zu erstellen, die die MNIST Daten lernen.Wie man ein zweischichtiges neuronales Netzwerk mit TensorFlow und Python auf MNIST Daten erstellt

Ich habe ein Single-Layer-Netzwerk (nach dem Tutotial) gebaut, die Genauigkeit betrug etwa 0,92, was für mich in Ordnung ist. Aber dann habe ich eine weitere Ebene hinzugefügt, die Genauigkeit wurde auf 0,113 reduziert, was sehr schlecht ist.

Unten finden Sie die Beziehung zwischen zwei Schichten:

import tensorflow as tf 
x = tf.placeholder(tf.float32, [None, 784]) 

#layer 1 
W1 = tf.Variable(tf.zeros([784, 100])) 
b1 = tf.Variable(tf.zeros([100])) 
y1 = tf.nn.softmax(tf.matmul(x, W1) + b1) 

#layer 2 
W2 = tf.Variable(tf.zeros([100, 10])) 
b2 = tf.Variable(tf.zeros([10])) 
y2 = tf.nn.softmax(tf.matmul(y1, W2) + b2) 

#output 
y = y2 
y_ = tf.placeholder(tf.float32, [None, 10]) 

Ist meine Struktur in Ordnung? Was ist der Grund, warum es so schlecht läuft? Wie sollte ich mein Netzwerk ändern?

Antwort

7

Der Eingang der 2. Schicht ist der softmax des Ausgangs der ersten Schicht. Das willst du nicht machen.

Sie erzwingen die Summe dieser Werte zu 1. Wenn ein Wert von tf.matmul(x, W1) + b1 ungefähr 0 ist (und einige sind es sicherlich), verringert die softmax-Operation diesen Wert auf 0. Ergebnis: Sie töten den Farbverlauf und nichts kann durch diese Neuronen fließen.

Wenn Sie die Softmax zwischen den Ebenen entfernen (aber leve it die Softmax auf der Ausgabeschicht, wenn Sie die Werte als Wahrscheinlichkeit betrachten möchten), wird Ihr Netzwerk gut funktionieren.

Tl; dr:

import tensorflow as tf 
x = tf.placeholder(tf.float32, [None, 784]) 

#layer 1 
W1 = tf.Variable(tf.zeros([784, 100])) 
b1 = tf.Variable(tf.zeros([100])) 
y1 = tf.matmul(x, W1) + b1 #remove softmax 

#layer 2 
W2 = tf.Variable(tf.zeros([100, 10])) 
b2 = tf.Variable(tf.zeros([10])) 
y2 = tf.nn.softmax(tf.matmul(y1, W2) + b2) 

#output 
y = y2 
y_ = tf.placeholder(tf.float32, [None, 10]) 
+0

Danke @nessuno, Sie haben Recht! Jetzt ersetze ich es durch ReLU und es funktioniert sehr gut ^^ –

0

in genau kam das gleiche Problem, Steigungen abwich und bekam eine Reihe von nan für die vorhergesagte y. Implementiert, was von Nessuno vorgeschlagen wurde, leider sind die divergierenden Gradienten noch nicht behoben.

Stattdessen habe ich versucht sigmoid als Aktivierungsfunktion für Schicht 1, es hat funktioniert! Aber für relu nicht funktioniert, wenn W1 und als Nullmatrizen initiieren, ist die Genauigkeit nur 0,11135. Um sowohl relu als auch sigmoid arbeiten zu lassen, sollte die Initialisierung von W1 und W2 besser randomisiert werden. Hier ist der modifizierte Code

import tensorflow as tf 

x = tf.placeholder(tf.float32, [None, 784]) 

# layer 1 
with tf.variable_scope('layer1'): 
    W1 = tf.get_variable('w1',[784,200], 
         initializer=tf.random_normal_initializer()) 
    b1 = tf.get_variable('b1',[1,], 
         initializer=tf.constant_initializer(0.0)) 
    y1 = tf.nn.sigmoid(tf.matmul(x, W1) + b1) 
# y1 = tf.nn.relu(tf.matmul(x, W1) + b1) # alternative choice for activation 

# layer 2 
with tf.variable_scope('layer2'): 
    W2 = tf.get_variable('w2',[200,10], 
        initializer= tf.random_normal_nitializer()) 
    b2 = tf.get_variable('b2',[1,], 
         initializer=tf.constant_initializer(0.0)) 
    y2 = tf.nn.softmax(tf.matmul(y1, W2) + b2) 

# output 
y = y2 
y_ = tf.placeholder(tf.float32, [None, 10]) 

Ich fand this link nützlich ist, siehe Frage 2 Teil (c), das Backpropagation-Derivate für ein grundlegendes 2-Schicht neuronale Netz gibt. Meiner Meinung nach, wenn Benutzer keine Aktivierungsfunktion angegeben haben, wenden Sie einfach linearen Fluss in Schicht 1 an, wird am Ende mit der Rückprogression eines Farbverlaufs etwas wie (sth)*W2^T*W1^T, und wie wir W1 und W2 als Nullen initiieren, ist ihr Produkt wahrscheinlich sehr nahe Null zu sein, was zu verschwindenden Gradienten führt.

UPDATE

Das von der Quoren Antwort ist Ofir posted über eine gute Anfangsgewichte in einem neuronalen Netzwerk.

Die häufigsten Initialisierungen sind zufällige Initialisierung und Xavier Initialisierung. Die zufällige Initialisierung tastet nur jedes Gewicht von einer Standardverteilung ab (oft eine normale Verteilung) mit einer niedrigen Abweichung.Die geringe Abweichung können Sie Voreingenommenheit das Netzwerk in Richtung die ‚einfache‘ 0 Lösung, ohne die schlechten Auswirkungen der tatsächlich Initialisierung der Gewichte auf 0.

0

Ich versuchte, die Code-Schnipsel oben zu laufen. Ergebnisse unter 90% wurden verworfen und ich war nie wirklich sicher, ob ich das tat, was die obigen Kommentare hatten. Hier ist mein vollständiger Code.

import tensorflow as tf 
from tensorflow.examples.tutorials.mnist import input_data 
mnist = input_data.read_data_sets("MNIST_data/", one_hot=True) 
x = tf.placeholder(tf.float32, [None, 784]) 

#layer 1 
W1 = tf.get_variable('w1', [784, 100], initializer=tf.random_normal_initializer()) 
b1 = tf.get_variable('b1', [1,], initializer=tf.random_normal_initializer()) 
y1 = tf.nn.sigmoid(tf.matmul(x, W1) + b1) 

#layer 2 
W2 = tf.get_variable('w2',[100,10], initializer= 
tf.random_normal_initializer()) 
b2 = tf.get_variable('b2',[1,], initializer=tf.random_normal_initializer()) 
y2 = tf.nn.softmax(tf.matmul(y1, W2) + b2) 

#output 
y = y2 
y_ = tf.placeholder(tf.float32, [None, 10]) 

cross_entropy = tf.reduce_mean(-tf.reduce_sum(y_ * tf.log(y), 
reduction_indices=[1])) 
train_step = tf.train.GradientDescentOptimizer(0.2).minimize(cross_entropy) 
sess = tf.InteractiveSession() 
tf.global_variables_initializer().run() 

for _ in range(10000): 
    batch_xs, batch_ys = mnist.train.next_batch(100) 
    sess.run(train_step, feed_dict={x: batch_xs, y_: batch_ys}) 

correct_prediction = tf.equal(tf.argmax(y,1), tf.argmax(y_,1)) 
accuracy = tf.reduce_mean(tf.cast(correct_prediction, tf.float32)) 

print(sess.run(accuracy, feed_dict={x: mnist.test.images, y_: 
mnist.test.labels})) 

Durch Ändern von 10000 -> 200000 erreichte ich 95,5%.

+0

Ich arbeitete ein bisschen mehr und sogar 95,5% zu wiederholen war hart. Dies wäre sehr nett von einigen professionellen könnte kommentieren. Das Ergebnis liegt weit unter dem Erwarteten. Die Varianten, die ich ausprobiert habe, sind der Gradient-Parameter, die Anzahl der Wiederholungen, progressiv reduziert Gradientenparameter. Da es fast 80000 Variablen im Raster gibt, ist ein fast perfektes Ergebnis das, was ich erwartet habe. Ich weiß über https://www.tensorflow.org/get_started/mnist/pros Bescheid, aber das beinhaltet eine große Anzahl aufschlussreicher Nutzungen. Etwas zu sehen, was so einfach korrigiert wurde, würde mir sowieso mehr helfen. –

+0

Sie können auch bessere Ergebnisse erzielen, wenn Sie solche Gewichte initialisieren: 'W = tf.Variable (tf.random_uniform ([784,100], -0,01, 0,01))'. Klingt nicht nach viel, aber die Initialisierung von Gewichten nahe 0 hilft in diesem Fall. – Massyanya