2015-11-15 6 views
28

Als ein Spielzeugbeispiel versuche ich eine Funktion f(x) = 1/x von 100 No-Noise-Datenpunkten anzupassen. Die Matlab-Standardimplementierung ist phänomenal erfolgreich mit einer mittleren quadratischen Differenz von ~ 10^-10 und interpoliert perfekt.Warum ist diese TensorFlow-Implementierung wesentlich weniger erfolgreich als Matlabs NN?

Ich implementiere ein neuronales Netzwerk mit einer versteckten Schicht von 10 sigmoiden Neuronen. Ich bin ein Anfänger in neuronalen Netzen, also seien Sie auf der Hut vor dummem Code.

import tensorflow as tf 
import numpy as np 

def weight_variable(shape): 
    initial = tf.truncated_normal(shape, stddev=0.1) 
    return tf.Variable(initial) 

def bias_variable(shape): 
    initial = tf.constant(0.1, shape=shape) 
    return tf.Variable(initial) 

#Can't make tensorflow consume ordinary lists unless they're parsed to ndarray 
def toNd(lst): 
    lgt = len(lst) 
    x = np.zeros((1, lgt), dtype='float32') 
    for i in range(0, lgt): 
     x[0,i] = lst[i] 
    return x 

xBasic = np.linspace(0.2, 0.8, 101) 
xTrain = toNd(xBasic) 
yTrain = toNd(map(lambda x: 1/x, xBasic)) 

x = tf.placeholder("float", [1,None]) 
hiddenDim = 10 

b = bias_variable([hiddenDim,1]) 
W = weight_variable([hiddenDim, 1]) 

b2 = bias_variable([1]) 
W2 = weight_variable([1, hiddenDim]) 

hidden = tf.nn.sigmoid(tf.matmul(W, x) + b) 
y = tf.matmul(W2, hidden) + b2 

# Minimize the squared errors. 
loss = tf.reduce_mean(tf.square(y - yTrain)) 
optimizer = tf.train.GradientDescentOptimizer(0.5) 
train = optimizer.minimize(loss) 

# For initializing the variables. 
init = tf.initialize_all_variables() 

# Launch the graph 
sess = tf.Session() 
sess.run(init) 

for step in xrange(0, 4001): 
    train.run({x: xTrain}, sess) 
    if step % 500 == 0: 
     print loss.eval({x: xTrain}, sess) 

Die mittlere quadratische Differenz endet bei ~ 2 * 10^-3, also etwa 7 Größenordnungen schlechter als Matlab. Visualisieren mit

xTest = np.linspace(0.2, 0.8, 1001) 
yTest = y.eval({x:toNd(xTest)}, sess) 
import matplotlib.pyplot as plt 
plt.plot(xTest,yTest.transpose().tolist()) 
plt.plot(xTest,map(lambda x: 1/x, xTest)) 
plt.show() 

wir das für richtig halten kann, ist systematisch unvollkommen: gleichmäßig < 10^-5 enter image description here während die Matlab eine mit dem bloßen Auge mit den Unterschieden perfekt aussieht: enter image description here Ich habe versucht, mit zu replizieren TensorFlow das Diagramm des Matlab-Netzwerk:

enter image description here

Übrigens scheint das Diagramm, das eine tanh zu implizieren, statt sigmoid activa Funktion. Ich kann es nirgends in der Dokumentation finden, um sicher zu sein. Wenn ich jedoch versuche, in TensorFlow ein tanh-Neuron zu verwenden, scheitert die Anpassung schnell an nan für Variablen. Keine Ahnung warum.

Matlab verwendet den Levenberg-Marquardt-Trainingsalgorithmus. Bayessche Regularisierung ist mit mittleren Quadraten bei 10^-12 noch erfolgreicher (wir sind wahrscheinlich im Bereich der Dämpfe der Float-Arithmetik).

Warum ist die TensorFlow-Implementierung so viel schlimmer, und was kann ich tun, um es besser zu machen?

+0

Ich habe noch nicht in Tensor Flow geschaut, tut mir leid, aber du machst einige bizarre Dinge mit numpy dort mit dieser 'toNd' Funktion. 'np.linspace gibt bereits ein ndarray zurück, nicht eine Liste, wenn Sie eine Liste in ein ndarray konvertieren wollen, müssen Sie nur 'np.array (my_list)' eingeben, und wenn Sie nur die zusätzliche Achse benötigen, können Sie das tun 'neuer_array = mein_array [np.newaxis,:]'. Es könnte nur kurz vor Null Fehler stehen, weil es das tun soll. Die meisten Daten haben Rauschen, und Sie möchten nicht notwendigerweise Null Trainingsfehler darauf. Gemessen an "reduce_mean" kann eine Kreuzvalidierung verwendet werden. –

+0

@AdamAcosta 'toNd' ist definitiv eine Lücke für meinen Mangel an Erfahrung. Ich habe 'np.array' vorher probiert und das Problem scheint zu sein, dass' np.array ([5,7]) .form' '' (2,) 'und nicht' (2,1) 'ist. 'my_array [np.newaxis,:]' scheint das zu korrigieren, danke! Ich benutze nicht Python sondern F # Tag für Tag. – Arbil

+0

@AdamAcostaI Ich glaube nicht, dass "reduce_mean" Kreuzvalidierung durchführt. Aus der Dokumentation: 'Berechnet den Mittelwert von Elementen über Dimensionen eines Tensors. Matlab führt eine Kreuzvalidierung durch, die meiner Meinung nach die Anpassung an die Trainingsstichprobe im Vergleich zu keiner Kreuzvalidierung reduzieren sollte, ist das richtig? – Arbil

Antwort

23

Ich versuchte Training für 50000 Iterationen es 0,00012 Fehler wurde. Es dauert etwa 180 Sekunden auf Tesla K40.

enter image description here

Es scheint, dass für diese Art von Problem, erste Ordnung Gradientenabfallsaktualisierung ist nicht eine gute Passform (Wortspiel beabsichtigt), und Sie müssen Levenberg-Marquardt oder l-BFGS. Ich glaube nicht, dass irgendjemand sie in TensorFlow implementiert hat.

Bearbeiten Verwenden Sie tf.train.AdamOptimizer(0.1) für dieses Problem. Es kommt nach 4000 Iterationen zu 3.13729e-05. Auch GPU mit Standardstrategie scheint für dieses Problem eine schlechte Idee zu sein. Es gibt viele kleine Operationen und der Overhead bewirkt, dass die GPU-Version 3x langsamer läuft als die CPU auf meinem Rechner.

+0

Vielen Dank für das Auschecken. Meinst du 5000 meiner Loops, also 20M Basic-Training? Kannst du bestätigen, dass es fehlschlägt, wenn du die versteckte Schicht in tanh Neuronen änderst, und wenn ja, weißt du, warum es passiert? – Arbil

+1

Ich habe gerade Xrange (4001) in Xrange (5000) geändert. Für tanh sieht es so aus, als würde das Training mit der Lernrate von 0,5 abweichen. Im Allgemeinen für Gradientenabfall müssen Sie Ihre Lernrate für jedes Problem abstimmen, es scheint zu funktionieren, wenn ich tf.train.GradientDescentOptimizer (0.1) –

+0

Ich sehe über den Gradientenparameter. Es ist sehr seltsam xrange (0, 5000) gibt Ihnen eine Größenordnung bessere Genauigkeit als 4k Bereich und es dauert 180s auf einer GPU. Ich betreibe den gleichen Bereich auf der CPU mit Genauigkeit unverändert und es dauert weniger als 10s. – Arbil

16

übrigens, hier ist eine leicht bereinigte Version der oben genannten, die einige der Formprobleme und unnötiges Springen zwischen TF und NP bereinigt. Er erreicht 3e-08 nach 40k Schritten oder etwa 1.5E-5 nach 4000:

import tensorflow as tf 
import numpy as np 

def weight_variable(shape): 
    initial = tf.truncated_normal(shape, stddev=0.1) 
    return tf.Variable(initial) 

def bias_variable(shape): 
    initial = tf.constant(0.1, shape=shape) 
    return tf.Variable(initial) 

xTrain = np.linspace(0.2, 0.8, 101).reshape([1, -1]) 
yTrain = (1/xTrain) 

x = tf.placeholder(tf.float32, [1,None]) 
hiddenDim = 10 

b = bias_variable([hiddenDim,1]) 
W = weight_variable([hiddenDim, 1]) 

b2 = bias_variable([1]) 
W2 = weight_variable([1, hiddenDim]) 

hidden = tf.nn.sigmoid(tf.matmul(W, x) + b) 
y = tf.matmul(W2, hidden) + b2 

# Minimize the squared errors.                 
loss = tf.reduce_mean(tf.square(y - yTrain)) 
step = tf.Variable(0, trainable=False) 
rate = tf.train.exponential_decay(0.15, step, 1, 0.9999) 
optimizer = tf.train.AdamOptimizer(rate) 
train = optimizer.minimize(loss, global_step=step) 
init = tf.initialize_all_variables() 

# Launch the graph                    
sess = tf.Session() 
sess.run(init) 

for step in xrange(0, 40001): 
    train.run({x: xTrain}, sess) 
    if step % 500 == 0: 
     print loss.eval({x: xTrain}, sess) 

Alles, was gesagt, es ist wahrscheinlich nicht allzu überraschend, dass LMA tut besser als ein allgemeinere DNN-style-Optimierer für ein Einpassen 2D-Kurve. Adam und der Rest zielen auf sehr hohe Dimensionalitätsprobleme und LMA starts to get glacially slow for very large networks (siehe 12-15).

Verwandte Themen