2015-11-15 15 views
28

Jako przykład zabawki próbuję dopasować funkcję f(x) = 1/x ze 100 punktów danych bez szumów. Domyślna implementacja programu Matlab jest fenomenalnie skuteczna ze średnią różnicą kwadratów ~ 10^-10 i idealnie interpoluje.Dlaczego ta implementacja TensorFlow jest mniej skuteczna niż NN Matlaba?

Implementuję sieć neuronową z jedną ukrytą warstwą 10 sigmoidalnych neuronów. Jestem początkującym w sieciach neuronowych, więc miej się na baczności przed głupim kodem.

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) 

Średnia różnica kwadratów kończy się na ~ 2 * 10^-3, czyli około 7 rzędów wielkości gorszych niż matlab. Wizualizacja z

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

widzimy dopasowanie jest systematycznie niedoskonały: enter image description here natomiast Matlab wygląda idealny gołym okiem z różnicami równomiernie < 10^-5: enter image description here starałem się replikować z TensorFlow schemat sieci Matlab:

enter image description here

Nawiasem mówiąc, schemat wydaje się sugerować tanh zamiast esicy activa funkcja. Nie mogę znaleźć nigdzie w dokumentacji, aby być pewnym. Jednak gdy próbuję użyć neuronu tanha w TensorFlow, dopasowanie szybko zawiedzie z nan dla zmiennych. Nie wiem dlaczego.

Matlab używa algorytmu szkolenia Levenberga-Marquardta. Bayesowska regularyzacja jest jeszcze bardziej skuteczna ze średnimi kwadratami przy 10^-12 (prawdopodobnie znajdujemy się w obszarze oparów arytmetyki pływaków).

Dlaczego wdrożenie TensorFlow jest znacznie gorsze i co mogę zrobić, aby było lepiej?

+0

Nie zajrzałem jeszcze do przepływu tensora, więc przepraszam za to, ale robisz dziwne rzeczy z numpy tam z funkcją 'toNd'. 'np.linspace' już zwraca ndarray, a nie listę, jeśli chcesz przekonwertować listę do ndarray, wszystko co musisz zrobić to 'np.array (my_list)', a jeśli potrzebujesz tylko dodatkowej osi, możesz zrobić 'new_array = my_array [np.newaxis,:]'. Może to być zatrzymanie się na zero błędu zerowego, ponieważ ma to zrobić. Większość danych zawiera szumy i nie koniecznie chcesz zerwać błąd szkolenia. Sądząc po "reduce_mean", może używać sprawdzania krzyżowego. –

+0

@AdamAcosta 'toNd' to zdecydowanie przerwa dla mojego braku doświadczenia. Próbowałem wcześniej 'np.array' i problem wydaje się, że' np.array ([5,7]). Shape' to '(2,)' a nie '(2,1)'. 'my_array [np.newaxis,:]' wydaje się to poprawiać, dziękuję! Nie używam Pythona, ale raczej F # z dnia na dzień. – Arbil

+0

@AdamAcostaI Nie uważam, że 'reduce_mean' ma sprawdzanie krzyżowe. Z dokumentów: "Oblicza średnią elementów w wymiarach tensora". Matlab sprawdza krzyżowo, co moim zdaniem powinno zmniejszyć dopasowanie do próbki treningowej w porównaniu do braku sprawdzania krzyżowego, czy to prawda? – Arbil

Odpowiedz

23

Próbowałem szkolenia dla 50000 iteracji, które dostałem do błędu 0.00012. Tesla K40 trwa około 180 sekund.

enter image description here

Wydaje się, że dla tego rodzaju problemu, pierwsze zamówienie gradientu zejście nie jest dobrym rozwiązaniem (gra słów nie przeznaczonych), i trzeba Levenberg-Marquardt lub L-BFGS. Nie sądzę, by ktokolwiek jeszcze je zaimplementował w TensorFlow.

Edytuj Użyj tego tf.train.AdamOptimizer(0.1). Po 4000 iteracjach przechodzi do 3.13729e-05. Ponadto GPU z domyślną strategią również wydaje się złym pomysłem na ten problem. Istnieje wiele małych operacji, a narzut powoduje, że wersja GPU działa 3 razy wolniej niż CPU na moim komputerze.

+0

Dzięki za sprawdzenie tego. Masz na myśli 5000 moich pętli, więc podstawowe przebiegi 20M? Czy możesz potwierdzić, że zawodzi podczas zmiany ukrytej warstwy na neurony tanh, a jeśli tak, to czy wiesz, dlaczego tak się dzieje? – Arbil

+1

Właśnie zmieniłem twój xrange (4001) na xrange (5000). Jeśli chodzi o tanh, wygląda na to, że trening różni się od nauki 0,5. Ogólnie mówiąc, dla pochylenia gradientu, musisz ustawić szybkość uczenia się dla każdego problemu, wydaje się, że działa, jeśli robię tf.train.GradientDescentOptimizer (0.1) –

+0

Widzę o parametrze gradientu. To bardzo dziwne xrange (0, 5000) daje o rząd wielkości lepszą dokładność niż zakres 4k i trwa 180 sekund na GPU. Używam tego samego zakresu na procesorze z dokładnością niezmienioną i zajmuje to mniej niż 10 sekund. – Arbil

16

Przy okazji, oto nieco oczyszczona wersja powyższego, która czyści niektóre problemy z kształtem i niepotrzebnie odbija się między tf i np. Osiąga 3e-08 po 40k kroków, czyli około 1,5-e-5 po 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) 

Wszystko, co powiedział, to prawdopodobnie nie jest zbyt zaskakujące, że LMA robi lepiej niż bardziej ogólnym DNN stylu optymalizator do zamocowania Krzywa 2D. Adam i reszta są nastawieni na problemy z bardzo dużą przestrzennością, i LMA starts to get glacially slow for very large networks (patrz 12-15).