2015-11-15 12 views
28

Come esempio di un esempio, sto cercando di installare una funzione f(x) = 1/x da 100 punti dati non rumorosi. L'implementazione di default matlab ha un successo fenomenale con una differenza quadratica media ~ 10^-10, e interpola perfettamente.Perché questa implementazione di TensorFlow ha meno successo rispetto all'NN di Matlab?

Implemento una rete neurale con uno strato nascosto di 10 neuroni sigmoidali. Sono un principiante alle reti neurali quindi stai in guardia contro il codice stupido.

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) 

differenza media quadrato termina a ~ 2 * 10^-3, così circa 7 ordini di grandezza peggio di MATLAB. Visualizzazione con

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() 

possiamo vedere la forma è sistematicamente imperfetta: enter image description here mentre il MATLAB uno sembra perfetto a occhio nudo con le differenze in modo uniforme < 10^-5: enter image description here ho cercato di replicare con tensorflow il diagramma della rete Matlab:

enter image description here

per inciso, il diagramma sembra implicare un tanh anziché sigma activa funzione di Non riesco a trovarlo da nessuna parte nella documentazione per essere sicuro. Tuttavia, quando provo a usare un neurone tanh in TensorFlow, il fitting fallisce rapidamente con nan per le variabili. Non so perché.

Matlab utilizza l'algoritmo di allenamento Levenberg-Marquardt. La regolarizzazione bayesiana ha ancora più successo con i quadrati medi a 10^-12 (probabilmente siamo nell'area dei vapori dell'aritmetica fluttuante).

Perché l'implementazione di TensorFlow è molto peggiore e cosa posso fare per migliorarla?

+0

Non ho ancora esaminato il flusso del tensore, mi spiace tanto, ma stai facendo alcune cose bizzarre con Numpy lì con quella funzione 'toNd'. 'Np.linspace' restituisce già un narray, non una lista, se vuoi convertire una lista in un narray, tutto ciò che devi fare è 'np.array (mia_elenco)', e se hai solo bisogno dell'asse extra, puoi fare 'new_array = my_array [np.newaxis,:]'. Potrebbe semplicemente fermarsi a causa di errore zero perché dovrebbe farlo. La maggior parte dei dati ha rumore e non si desidera necessariamente un errore di allenamento pari a zero. A giudicare da 'reduce_mean', può essere utilizzata la convalida incrociata. –

+0

@AdamAcosta 'toNd' è sicuramente uno stop-gap per la mia mancanza di esperienza. Ho provato 'np.array' prima e il problema sembra essere che' np.array ([5,7]). Shape' è '(2,)' e non '(2,1)'. 'my_array [np.newaxis,:]' sembra correggere questo, grazie! Non uso python ma piuttosto F # giorno per giorno. – Arbil

+0

@AdamAcostaI Non penso che 'reduce_mean' abbia una convalida incrociata. Dai documenti: "Calcola la media degli elementi tra le dimensioni di un tensore". Matlab fa una convalida incrociata che a mio avviso dovrebbe ridurre l'adattamento del campione di allenamento rispetto a nessuna convalida incrociata, giusto? – Arbil

risposta

23

Ho provato l'allenamento per 50000 iterazioni ottenendo l'errore 0,00012. Tesla K40 impiega circa 180 secondi.

enter image description here

Sembra che per questo tipo di problema, prima discesa ordine gradiente non è una buona misura (gioco di parole), e avete bisogno di Levenberg-Marquardt o L-BFGS. Non credo che qualcuno li abbia mai implementati in TensorFlow.

Modifica Usa tf.train.AdamOptimizer(0.1) per questo problema. Arriva a 3.13729e-05 dopo 4000 iterazioni. Inoltre, GPU con strategia predefinita sembra una cattiva idea per questo problema. Ci sono molte piccole operazioni e l'overhead fa girare la versione GPU 3 volte più lentamente della CPU sulla mia macchina.

+0

Grazie per aver controllato. Intendi 5000 dei miei loop, quindi 20 milioni di allenamenti di base? Puoi confermare che fallisce quando cambi il livello nascosto in tanh neuroni, e se è così, sai perché succede? – Arbil

+1

Ho appena cambiato il tuo xrange (4001) in xrange (5000). Per tanh, sembra che l'allenamento diverga con il tasso di apprendimento 0,5. In generale per la discesa del gradiente è necessario regolare la velocità di apprendimento per ogni problema, sembra funzionare se faccio tf.train.GradientDescentOptimizer (0.1) –

+0

Vedo il parametro del gradiente. È molto strano xrange (0, 5000) offre un ordine di grandezza di una precisione migliore di 4k e richiede 180 su una GPU. Eseguo la stessa gamma su CPU con precisione invariata e richiede meno di 10 secondi. – Arbil

16

btw, ecco una versione leggermente ripulita di quanto sopra che ripulisce alcuni dei problemi di forma e inutili rimbalzi tra tf e np. Raggiunge 3e-08 dopo 40K passi, o circa 1.5e-5 dopo 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) 

Detto questo, probabilmente non è troppo sorprendente che LMA sta facendo meglio di un più generale ottimizzatore stile DNN per il montaggio di un Curva 2D. Adam e il resto stanno prendendo di mira problemi di dimensionalità molto alti, e LMA starts to get glacially slow for very large networks (vedi 12-15).