来自tensorflow的AdamOptimizer和GradientDescentOptimizer无法适应简单数据

AdamOptimizer and GradientDescentOptimizer from tensorflow not able to fit simple data

类似问题:

我正在试用 TensorFlow。我生成了可线性分离的简单数据,并尝试对其拟合线性方程。这是代码。

np.random.seed(2010)
n = 300
x_data = np.random.random([n, 2]).tolist()
y_data = [[1., 0.] if v[0]> 0.5 else [0., 1.] for v in x_data]

x = tf.placeholder(tf.float32, [None, 2]) 
W = tf.Variable(tf.zeros([2, 2]))
b = tf.Variable(tf.zeros([2]))
y = tf.sigmoid(tf.matmul(x , W) + b)

y_ = tf.placeholder(tf.float32, [None, 2]) 
cross_entropy = -tf.reduce_sum(y_ * tf.log(tf.clip_by_value(y, 1e-9, 1)))
train_step = tf.train.AdamOptimizer(0.01).minimize(cross_entropy)

correct_predict = tf.equal(tf.argmax(y, 1), tf.argmax(y_, 1)) 
accuracy = tf.reduce_mean(tf.cast(correct_predict, tf.float32))

s = tf.Session()
s.run(tf.initialize_all_variables())

for i in range(10):
        s.run(train_step, feed_dict = {x: x_data, y_: y_data})
        print(s.run(accuracy, feed_dict = {x: x_data, y_: y_data}))

print(s.run(accuracy, feed_dict = {x: x_data, y_: y_data}), end=",")

我得到以下输出:

0.536667, 0.46, 0.46, 0.46, 0.46, 0.46, 0.46, 0.46, 0.46, 0.46, 0.46

在第一次迭代之后,它在 0.46 处被击中。

剧情如下:

然后我更改了代码以使用梯度下降:

train_step = tf.train.GradientDescentOptimizer(0.01).minimize(cross_entropy)

现在我得到以下值:0.54、0.54、0.63、0.70、0.75、0.8、0.84、0.89、0.92、0.94、0.94

剧情如下:

我的问题:

1) 为什么 AdamOptimizer 会失败?

2) 如果问题出在学习率或其他我需要调整的参数上,我通常如何调试它们?

3) 我 运行 梯度下降 50 次迭代(我 运行 上面的 10 次)并每 5 次迭代打印一次精度,这是输出:

0.54, 0.8, 0.95, 0.96, 0.92, 0.89, 0.87, 0.84, 0.81, 0.79, 0.77.

很明显它开始发散,看起来问题出在固定的学习率上(它在一个点后超调)。我说得对吗?

4) 在这个玩具示例中,可以做些什么来获得更好的配合。理想情况下,它应该具有 1.0 的精度,因为数据是线性可分的。

[编辑]

应@Yaroslav 的要求,这里是用于绘图的代码

xx = [v[0] for v in x_data]
yy = [v[1] for v in x_data]
x_min, x_max = min(xx) - 0.5, max(xx) + 0.5 
y_min, y_max = min(yy) - 0.5, max(yy) + 0.5 
xxx, yyy = np.meshgrid(np.arange(x_min, x_max, 0.02), np.arange(y_min, y_max, 0.02))
pts = np.c_[xxx.ravel(), yyy.ravel()].tolist()
# ---> Important
z = s.run(tf.argmax(y, 1), feed_dict = {x: pts})
z = np.array(z).reshape(xxx.shape)
plt.pcolormesh(xxx, yyy, z)
plt.scatter(xx, yy, c=['r' if v[0] == 1 else 'b' for v in y_data], edgecolor='k', s=50)
plt.show()

TLDR;你的损失是错误的。在不降低准确性的情况下损失变为零。

问题是你的概率没有标准化。如果你看看你的损失,它正在下降,但是 y[:0]y[:1] 的概率都将变为 1,所以 argmax 是没有意义的。

传统的解决方案是只使用 1 个自由度而不是 2 个,所以第一个 class 的概率是 sigmoid(y),第二个 class 的概率是 1-sigmoid(y) 所以交叉熵类似于 -y[0]log(sigmoid(y0)) - y[1]log(1-sigmoid(y0))

或者您可以更改您的代码,使用 tf.nn.softmax 而不是 tf.sigmoid。这除以概率之和,因此优化器无法通过同时将两个概率都驱动为 1 来减少损失。

以下达到 0.99666673 准确度。

tf.reset_default_graph()
np.random.seed(2010)
n = 300
x_data = np.random.random([n, 2]).tolist()
y_data = [[1., 0.] if v[0]> 0.5 else [0., 1.] for v in x_data]

x = tf.placeholder(tf.float32, [None, 2]) 
W = tf.Variable(tf.zeros([2, 2]))
b = tf.Variable(tf.zeros([2]))
y = tf.nn.softmax(tf.matmul(x , W) + b)

y_ = tf.placeholder(tf.float32, [None, 2]) 
cross_entropy = -tf.reduce_sum(y_ * tf.log(y))
regularizer = tf.reduce_sum(tf.square(y))
train_step = tf.train.AdamOptimizer(1.0).minimize(cross_entropy+regularizer)

correct_predict = tf.equal(tf.argmax(y, 1), tf.argmax(y_, 1)) 
accuracy = tf.reduce_mean(tf.cast(correct_predict, tf.float32))

s = tf.Session()
s.run(tf.initialize_all_variables())

for i in range(30):
        s.run(train_step, feed_dict = {x: x_data, y_: y_data})
        cost1,cost2=s.run([cross_entropy,accuracy], feed_dict = {x: x_data, y_: y_data})
        print(cost1, cost2)

PS:你能分享一下你用来制作上面的图的代码吗?