web-dev-qa-db-fra.com

Pourquoi cette implémentation de TensorFlow est-elle beaucoup moins réussie que NN de Matlab?

Comme exemple de jouet, j'essaie d'adapter une fonction f(x) = 1/x à partir de 100 points de données sans bruit. L'implémentation par défaut de matlab est phénoménalement réussie avec une différence quadratique moyenne ~ 10 ^ -10 et interpole parfaitement.

J'implémente un réseau neuronal avec une couche cachée de 10 neurones sigmoïdes. Je suis un débutant dans les réseaux de neurones, alors soyez sur vos gardes contre le code stupide.

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)

La différence quadratique moyenne se termine à ~ 2 * 10 ^ -3, donc environ 7 ordres de grandeur pire que matlab. Visualiser avec

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

on voit que l'ajustement est systématiquement imparfait: enter image description here tandis que le matlab semble parfait à l'œil nu avec les différences uniformément <10 ^ -5: enter image description here J'ai essayé de répliquer avec TensorFlow le schéma du réseau Matlab:

enter image description here

Soit dit en passant, le diagramme semble impliquer une fonction d'activation tanh plutôt que sigmoïde. Je ne peux le trouver nulle part dans la documentation pour être sûr. Cependant, lorsque j'essaie d'utiliser un neurone tanh dans TensorFlow, l'ajustement échoue rapidement avec nan pour les variables. Je ne sais pas pourquoi.

Matlab utilise l'algorithme de formation de Levenberg – Marquardt. La régularisation bayésienne est encore plus réussie avec des carrés moyens à 10 ^ -12 (nous sommes probablement dans le domaine des vapeurs de l'arithmétique des flotteurs).

Pourquoi la mise en œuvre de TensorFlow est-elle tellement pire et que puis-je faire pour l'améliorer?

32
Arbil

J'ai essayé de m'entraîner pour 50000 itérations, il est arrivé à une erreur de 0,00012. Cela prend environ 180 secondes sur Tesla K40.

enter image description here

Il semble que pour ce type de problème, la descente de gradient de premier ordre n'est pas un bon ajustement (jeu de mots voulu), et vous avez besoin de Levenberg – Marquardt ou l-BFGS. Je pense que personne ne les a encore implémentés dans TensorFlow.

Modifier Utilisez tf.train.AdamOptimizer(0.1) pour ce problème. Il arrive à 3.13729e-05 après 4000 itérations. En outre, le GPU avec la stratégie par défaut semble également être une mauvaise idée pour ce problème. Il y a beaucoup de petites opérations et la surcharge fait que la version du GPU s'exécute 3 fois plus lentement que le CPU sur ma machine.

25
Yaroslav Bulatov

btw, voici une version légèrement nettoyée de ce qui précède qui nettoie certains des problèmes de forme et des rebonds inutiles entre tf et np. Il atteint 3e-08 après 40k étapes, ou environ 1,5e-5 après 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)

Cela dit, il n'est probablement pas trop surprenant que LMA fasse mieux qu'un optimiseur de style DNN plus général pour l'ajustement d'une courbe 2D. Adam et les autres ciblent des problèmes de très grande dimensionnalité, et LMA commence à devenir glacialement lent pour les très grands réseaux (voir 12-15).

16
dga