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: tandis que le matlab semble parfait à l'œil nu avec les différences uniformément <10 ^ -5: J'ai essayé de répliquer avec TensorFlow le schéma du réseau Matlab:
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?
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.
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.
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).