Почему реализация TensorFlow намного менее успешна, чем Matlab NN?
В качестве примера игрушек я пытаюсь установить функцию f(x) = 1/x
из 100 точек без шума. Реализация по умолчанию Matlab феноменально успешна со средней квадратичной разностью ~ 10 ^ -10 и идеально интерполируется.
Я реализую нейронную сеть с одним скрытым слоем из 10 сигмовидных нейронов. Я новичок в нейронных сетях, так что будьте осторожны с немым кодом.
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)
Средняя квадратная разница заканчивается на ~ 2 * 10 ^ -3, что примерно на 7 порядков хуже, чем у Matlab. Визуализация с помощью
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()
мы видим, что посадка систематически несовершенна:
в то время как матрица выглядит идеально для невооруженного глаза с равномерными различиями, 10 ^ -5:
Я попытался реплицировать с помощью TensorFlow диаграмму сети Matlab:
![введите описание изображения здесь]()
Кстати, диаграмма, по-видимому, подразумевает функцию активации tanh, а не сигмоида. Я не могу найти его где-нибудь в документации, чтобы быть уверенным. Однако, когда я пытаюсь использовать tanh neuron в TensorFlow, установка быстро терпит неудачу с nan
для переменных. Я не знаю, почему.
Matlab использует алгоритм обучения Левенберга-Марквардта. Байесовская регуляризация еще более успешна со средними квадратами при 10 ^ -12 (мы, вероятно, находимся в области паров арифметики с плавающей точкой).
Почему реализация TensorFlow намного хуже, и что я могу сделать, чтобы сделать ее лучше?
Ответы
Ответ 1
Я пробовал тренироваться за 50000 итераций, которые он получил до ошибки 0.00012. Это займет около 180 секунд на Tesla K40.
![введите описание изображения здесь]()
Кажется, что для такого рода проблем спуск градиента первого порядка не подходит (каламбур), и вам нужны Levenberg-Marquardt или l-BFGS. Я не думаю, что кто-то их реализовал в TensorFlow.
Edit
Используйте tf.train.AdamOptimizer(0.1)
для этой проблемы. Он достигает 3.13729e-05
после 4000 итераций. Кроме того, GPU со стратегией по умолчанию также кажется плохой идеей для этой проблемы. Существует много небольших операций, и накладные расходы приводят к тому, что версия графического процессора работает на 3 раза медленнее, чем процессор на моей машине.
Ответ 2
btw, здесь немного очищенная версия выше, которая очищает некоторые проблемы с формой и ненужное подпрыгивание между tf и np. Он достигает 3e-08 после 40k шагов или около 1,5e-5 после 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)
Все, что было сказано, вероятно, не слишком удивительно, что LMA работает лучше, чем более общий оптимизатор DNN-стиля для установки 2D-кривой. Адам и остальные нацелены на очень большие проблемы размерности, а LMA начинает медленно лежать на очень больших сетях (см. 12-15).