¿Por qué esta implementación de TensorFlow es mucho menos exitosa que la NN de Matlab?

Como ejemplo de juguete, estoy tratando de ajustar una función f(x) = 1/x desde 100 puntos de datos sin ruido. La implementación predeterminada de matlab es fenomenalmente exitosa con la diferencia de la media de los cuadrados ~ 10 ^ -10, e interpola perfectamente.

Implemento una neural network con una capa oculta de 10 neuronas sigmoideas. Soy un principiante en las redes neuronales, así que mantente alerta contra el código tonto.

 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 diferencia cuadrática media termina en ~ 2 * 10 ^ -3, por lo que aproximadamente 7 órdenes de magnitud son peores que matlab. Visualizando 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() 

Podemos ver que el ajuste es sistemáticamente imperfecto: introduzca la descripción de la imagen aquí mientras que el matlab se ve perfecto a simple vista con las diferencias uniformemente <10 ^ -5: introduzca la descripción de la imagen aquí He intentado replicar con TensorFlow el diagtwig de la red de Matlab:

introduzca la descripción de la imagen aquí

Incidentalmente, el diagtwig parece implicar una función de activación tano en lugar de sigmoide. No puedo encontrarlo en ningún lugar en la documentación para estar seguro. Sin embargo, cuando trato de usar una neurona tanh en TensorFlow, la conexión falla rápidamente con nan para las variables. No se por que.

Matlab utiliza el algoritmo de entrenamiento Levenberg-Marquardt. La regularización bayesiana es aún más exitosa con los cuadrados medios en 10 ^ -12 (probablemente nos encontremos en el área de vapores de aritmética flotante).

¿Por qué la implementación de TensorFlow es mucho peor y qué puedo hacer para mejorarla?

Intenté entrenar para 50000 iteraciones y obtuve un error de 0,00012. Se tarda unos 180 segundos en Tesla K40.

introduzca la descripción de la imagen aquí

Parece que para este tipo de problema, el descenso de gradiente de primer orden no es un buen ajuste (es decir, juego de palabras), y necesita Levenberg – Marquardt o l-BFGS. No creo que nadie los haya implementado en TensorFlow todavía.

Editar Utilice tf.train.AdamOptimizer(0.1) para este problema. Se llega a 3.13729e-05 después de 4000 iteraciones. Además, GPU con estrategia predeterminada también parece ser una mala idea para este problema. Hay muchas operaciones pequeñas y la sobrecarga hace que la versión de GPU se ejecute 3 veces más lento que la CPU en mi máquina.

por cierto, aquí hay una versión ligeramente mejorada de la anterior que limpia algunos de los problemas de forma y el rebote innecesario entre tf y np. Consigue 3e-08 después de 40k pasos, o alrededor de 1.5e-5 después de 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) 

Dicho todo esto, probablemente no sea demasiado sorprendente que a LMA le vaya mejor que a un optimizador de estilo DNN más general para ajustar una curva 2D. Adam y el rest están enfocados en problemas de dimensionalidad muy alta, y LMA comienza a volverse glacialmente lento para redes muy grandes (ver 12-15).