2015-11-15 9 views
28

Как пример игрушки, я пытаюсь установить функцию f(x) = 1/x из 100 точек без шума. Реализация Matlab по умолчанию феноменально успешна со средней квадратичной разницей ~ 10^-10 и отлично интерполирует.Почему эта реализация TensorFlow намного менее успешна, чем NN Matlab?

Я реализую нейронную сеть с одним скрытым слоем из 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() 

мы можем видеть подгонку систематически несовершенны: enter image description here в то время как один MATLAB выглядит идеально невооруженным глазом с различиями равномерно < 10^-5: enter image description here я пытался повторить с TensorFlow диаграмма сети Matlab:

enter image description here

Кстати, схема, как представляется, подразумевает TANH, а не сигмовидной ACTIVA . Я не могу найти его где-нибудь в документации, чтобы быть уверенным. Тем не менее, когда я пытаюсь использовать tanh neuron в TensorFlow, фитинг быстро терпит неудачу с nan для переменных. Я не знаю почему.

Matlab использует алгоритм обучения Levenberg-Marquardt. Байесовская регуляризация еще более успешна со средними квадратами при 10^-12 (мы, вероятно, находимся в области паров арифметики с плавающей точкой).

Почему реализация TensorFlow намного хуже, и что я могу сделать, чтобы сделать ее лучше?

+0

Я еще не смотрел в поток тензоров, поэтому сожалею об этом, но вы делаете некоторые причудливые вещи с numpy там с этой функцией toNd. 'Нп.linspace' уже возвращает ndarray, а не список, если вы хотите преобразовать список в ndarray, все, что вам нужно сделать, это 'np.array (my_list)', и если вам просто нужна дополнительная ось, вы можете сделать 'new_array = my_array [np.newaxis,:]'. Это может быть просто прекращение нулевой ошибки, потому что это должно сделать это. У большинства данных есть шум, и вам не обязательно нужна нулевая ошибка обучения. Судя по «reduce_mean», он может использовать кросс-валидацию. –

+0

@AdamAcosta 'toNd' - определенно стоп-лосс для моего отсутствия опыта. Я пробовал 'np.array' раньше, и проблема заключается в том, что' np.array ([5,7]). Shape' is '(2,)', а не '(2,1)'. 'my_array [np.newaxis,:]' похоже, исправляет это, спасибо! Я не использую python, а скорее F # изо дня в день. – Arbil

+0

@AdamAcostaI Я не думаю, что 'reduce_mean' делает перекрестную проверку. Из документов: «Вычисляет среднее значение элементов в измерениях тензора». Matlab делает кросс-валидацию, которая, на мой взгляд, должна уменьшать соответствие учебного образца по сравнению с отсутствием перекрестной проверки, верно ли? – Arbil

ответ

23

Я пробовал тренироваться для 50000 итераций, полученных до ошибки 0.00012. Это займет около 180 секунд на Tesla K40.

enter image description here

кажется, что для такого рода проблемы, первый градиент порядка спуск не очень подходит (каламбур), и вам нужно Левенберга-Marquardt или л-BFGS. Я не думаю, что кто-то их реализовал в TensorFlow.

Редактировать tf.train.AdamOptimizer(0.1) для этой проблемы. Он достигает 3.13729e-05 после 4000 итераций. Кроме того, GPU со стратегией по умолчанию также кажется плохой идеей для этой проблемы. Существует много небольших операций, и накладные расходы приводят к тому, что версия графического процессора работает на 3 раза медленнее, чем процессор на моей машине.

+0

Спасибо, что проверили это. Вы имеете в виду 5000 моих петель, так что 20M базовых тренировок работает? Можете ли вы подтвердить, что это не удается при смене скрытого слоя на tanh нейроны, и если да, знаете ли вы, почему это происходит? – Arbil

+1

Я просто изменил xrange (4001) на xrange (5000). Для tanh, похоже, тренировка расходится со скоростью обучения 0,5. В общем, для градиентного спуска вам нужно настроить свою скорость обучения для каждой проблемы, она работает, если я делаю tf.train.GradientDescentOptimizer (0.1) –

+0

Я вижу параметр градиента. Это очень странный xrange (0, 5000) дает вам на порядок лучшую точность, чем диапазон 4k, и он занимает 180 секунд на графическом процессоре. Я запускаю тот же диапазон на процессоре с неизменной точностью и занимает менее 10 секунд. – Arbil

16

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 starts to get glacially slow for very large networks (см. 12-15).

Смежные вопросы