为什么这个 TensorFlow 实现远不如 Matlab 的神经网络成功?
Why is this TensorFlow implementation vastly less successful than Matlab's NN?
作为玩具示例,我试图从 100 个无噪声数据点拟合一个函数 f(x) = 1/x
。 matlab 默认实现非常成功,均方差为 ~10^-10,并且插值完美。
我实现了一个包含 10 个 sigmoid 神经元的隐藏层的神经网络。我是神经网络的初学者,所以要提防愚蠢的代码。
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 结束,因此比 matlab 差大约 7 个数量级。用
可视化
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()
我们可以看到拟合在系统上是不完美的:
而 matlab 的肉眼看起来很完美,差异均匀 < 10^-5:
我尝试用 TensorFlow 复制 Matlab 网络图:
顺便说一下,该图似乎暗示了 tanh 而不是 sigmoid 激活函数。可以肯定的是,我无法在文档中的任何地方找到它。但是,当我尝试在 TensorFlow 中使用 tanh 神经元时,拟合很快失败,变量为 nan
。不知道为什么。
Matlab 使用 Levenberg–Marquardt 训练算法。贝叶斯正则化在均方为 10^-12 时更加成功(我们可能处于浮点算术的蒸汽区域)。
为什么 TensorFlow 的实现如此糟糕,我可以做些什么来让它变得更好?
我尝试训练 50000 次迭代,结果出现 0.00012 错误。在 Tesla K40 上大约需要 180 秒。
对于这种问题,一阶梯度下降似乎不太合适(双关语),你需要Levenberg–Marquardt或l-BFGS。我认为还没有人在 TensorFlow 中实现它们。
编辑
使用 tf.train.AdamOptimizer(0.1)
来解决这个问题。它在 4000 次迭代后达到 3.13729e-05
。此外,使用默认策略的 GPU 似乎也不是解决这个问题的好主意。有许多小操作,开销导致 GPU 版本 运行 比我机器上的 CPU 慢 3 倍。
顺便说一句,这是上面的一个稍微清理过的版本,它清理了一些形状问题和 tf 和 np 之间不必要的弹跳。它在 40k 步后达到 3e-08,或在 4000 步后达到 1.5e-5:
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 在拟合 2D 曲线方面比更通用的 DNN 式优化器做得更好可能并不奇怪。 Adam 和其他人的目标是非常高维度的问题,LMA starts to get glacially slow for very large networks(见 12-15)。
作为玩具示例,我试图从 100 个无噪声数据点拟合一个函数 f(x) = 1/x
。 matlab 默认实现非常成功,均方差为 ~10^-10,并且插值完美。
我实现了一个包含 10 个 sigmoid 神经元的隐藏层的神经网络。我是神经网络的初学者,所以要提防愚蠢的代码。
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 结束,因此比 matlab 差大约 7 个数量级。用
可视化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()
我们可以看到拟合在系统上是不完美的:
顺便说一下,该图似乎暗示了 tanh 而不是 sigmoid 激活函数。可以肯定的是,我无法在文档中的任何地方找到它。但是,当我尝试在 TensorFlow 中使用 tanh 神经元时,拟合很快失败,变量为 nan
。不知道为什么。
Matlab 使用 Levenberg–Marquardt 训练算法。贝叶斯正则化在均方为 10^-12 时更加成功(我们可能处于浮点算术的蒸汽区域)。
为什么 TensorFlow 的实现如此糟糕,我可以做些什么来让它变得更好?
我尝试训练 50000 次迭代,结果出现 0.00012 错误。在 Tesla K40 上大约需要 180 秒。
对于这种问题,一阶梯度下降似乎不太合适(双关语),你需要Levenberg–Marquardt或l-BFGS。我认为还没有人在 TensorFlow 中实现它们。
编辑
使用 tf.train.AdamOptimizer(0.1)
来解决这个问题。它在 4000 次迭代后达到 3.13729e-05
。此外,使用默认策略的 GPU 似乎也不是解决这个问题的好主意。有许多小操作,开销导致 GPU 版本 运行 比我机器上的 CPU 慢 3 倍。
顺便说一句,这是上面的一个稍微清理过的版本,它清理了一些形状问题和 tf 和 np 之间不必要的弹跳。它在 40k 步后达到 3e-08,或在 4000 步后达到 1.5e-5:
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 在拟合 2D 曲线方面比更通用的 DNN 式优化器做得更好可能并不奇怪。 Adam 和其他人的目标是非常高维度的问题,LMA starts to get glacially slow for very large networks(见 12-15)。