tflearn / tensorflow 不学习 xor
tflearn / tensorflow does not learn xor
编写了以下代码来学习 XOR 函数,但大约有一半时间网络没有学习,并且每个 epoch 后的损失保持不变。
train_f = [[0, 0], [0, 1], [1, 0], [1, 1]]
train_c = [[0], [1], [1], [0]]
test_f = train_f
test_c = train_c
import tensorflow as tf
import tflearn
X = [[0., 0.], [0., 1.], [1., 0.], [1., 1.]]
Y_xor = [[0.], [1.], [1.], [0.]]
# Graph definition
with tf.Graph().as_default():
# Building a network with 2 optimizers
net = tflearn.input_data(shape=[None, 2])
# Nand operator definition
net = tflearn.fully_connected(net, 2, activation='relu')
net = tflearn.fully_connected(net, 2, activation='relu')
net = tflearn.fully_connected(net, 1, activation='sigmoid')
regressor = tflearn.regression(net, optimizer='adam', learning_rate=0.005, loss="mean_square",)
# Training
m = tflearn.DNN(regressor)
m.fit(X, Y_xor, n_epoch=256, snapshot_epoch=False)
# Testing
print("Testing XOR operator")
print("0 xor 0:", m.predict([[0., 0.]]))
print("0 xor 1:", m.predict([[0., 1.]]))
print("1 xor 0:", m.predict([[1., 0.]]))
print("1 xor 1:", m.predict([[1., 1.]]))
有时我会得到这样正确的结果:
Testing XOR operator
0 xor 0: [[0.1487255096435547]]
0 xor 1: [[0.9297153949737549]]
1 xor 0: [[0.9354135394096375]]
1 xor 1: [[0.1487255096435547]]
但通常是这样的:
Testing XOR operator
0 xor 0: [[0.4999997615814209]]
0 xor 1: [[0.5000002384185791]]
1 xor 0: [[0.4999997615814209]]
1 xor 1: [[0.5000001788139343]]
我的 2x2x1 网络应该能够执行 XOR,甚至有一些证据表明这个网络应该总是收敛 http://www.ncbi.nlm.nih.gov/pubmed/12662805
我也试过将relu层改成sigmoid,进行2048次迭代,做了一个4x4x1和6x6x1的网络,但有时还是会出现同样的问题
会不会是权重初始化有问题?
如何使用 tflearn 让神经网络学习 xor 函数?
具有 relu
的网络(如代码片段中所写)预计经常无法训练。原因是如果relu的输入小于零,输出为零,因此返回的梯度也为零。
因为你有两层,每层只有两个 relu 单元,通过随机初始化,这两层中的每一层都有 25% 的所有神经元返回零,因此返回零梯度 => 神经网络不会学习。在这样的网络中,最后一层(在最终 sigmoid 之前)的输出将为零,其中 sigmoid 为 0.5——这正是您在网络未收敛的尝试中观察到的结果。
由于每一层都有 25% 的几率造成这种损害,因此整个网络从一开始就无法训练的总几率约为 45% (1 - (1 - 0.25)^2
)。还有一个非零的可能性是网络一开始不是这样的状态,但在训练过程中恰好把自己带到这样的状态,进一步增加发散的机会。
有四个神经元时,机会会显着降低,但仍不为零。
现在,我唯一无法回答的是,当您将 relu
替换为 sigmoid
时,为什么您的网络不收敛——这样的网络应该始终能够学习 "xor".我唯一的假设是你只用 sigmoid
替换了一个 relu
,而不是两个。
你能用 sigmoid
替换两个 relu
并确认你仍然观察到分歧吗?
除了@Ishamael 的建议,考虑使用不同的损失函数。均方误差通常不是 sigmoid 激活的好选择,因为由于饱和度,梯度可能会收缩得太小而无法用于学习。
我决定添加另一个答案:我做了更多研究并提供了一些截然不同的建议。
略读 this 论文后,我突然意识到您看不到收敛的原因可能与初始权重有关。该论文特别引用了 Hirose 等人(Hirose、Yamashita 和 Hijiya 1991)的一些工作,这些工作发现使用有限范围的权重进行初始化会导致收敛的概率非常低。 “最佳点”似乎平均在 0.5 到 1 之间,才能可靠地收敛。
事实证明,tflearn 将默认使用标准差为 0.02 的截断正常初始化。所以权重的范围非常有限。我发现使用 -1.0 到 1.0 的随机统一初始化可以获得相当可靠的结果。
另外,顺便说一句,您添加了第 3 层。 XOR 只需要一个隐藏层,所以你可以去掉第二个。这是对我有用的代码:
import tensorflow as tf
import tflearn
X = [[0., 0.], [0., 1.], [1., 0.], [1., 1.]]
Y_xor = [[0.], [1.], [1.], [0.]]
# Graph definition
with tf.Graph().as_default():
tnorm = tflearn.initializations.uniform(minval=-1.0, maxval=1.0)
net = tflearn.input_data(shape=[None, 2])
net = tflearn.fully_connected(net, 2, activation='sigmoid', weights_init=tnorm)
net = tflearn.fully_connected(net, 1, activation='sigmoid', weights_init=tnorm)
regressor = tflearn.regression(net, optimizer='sgd', learning_rate=2., loss='mean_square')
# Training
m = tflearn.DNN(regressor)
m.fit(X, Y_xor, n_epoch=10000, snapshot_epoch=False)
# Testing
print("Testing XOR operator")
print("0 xor 0:", m.predict([[0., 0.]]))
print("0 xor 1:", m.predict([[0., 1.]]))
print("1 xor 0:", m.predict([[1., 0.]]))
print("1 xor 1:", m.predict([[1., 1.]]))
请注意,我使用的是均方误差。令我惊讶的是,它似乎最适合解决这个问题。交叉熵似乎会导致优化器在问题的相对平坦区域中萎靡不振 space。我本以为相反;也许精通数学的人能够更好地解释这一点。
我在寻找学习 XOR 所需的最小神经元网络架构时遇到了模拟问题,它应该是 (2,2,1) 网络。事实上,数学表明 (2,2,1) 网络可以解决异或问题,但数学并没有表明 (2,2,1) 网络易于训练。也就是说,我很容易通过 (2,3,1) 或 (2,4,1) 网络架构获得良好的结果。此外,使用 0.5 和 1.0 之间的随机数进行权重初始化有助于收敛。
这个问题好像和存在很多局部极小点有关。看看这篇 1998 年的论文,«Learning XOR: exploring the space of a classic problem»,作者是理查德·布兰德 (Richard Bland)。也许你可以尝试不同的权重随机初始化或改变你的损失函数。
使用损失函数 'mean_squared_error'、sigmoid 激活和 Adam 优化器,它在 Keras 或 TensorFlow 上运行良好。
编写了以下代码来学习 XOR 函数,但大约有一半时间网络没有学习,并且每个 epoch 后的损失保持不变。
train_f = [[0, 0], [0, 1], [1, 0], [1, 1]]
train_c = [[0], [1], [1], [0]]
test_f = train_f
test_c = train_c
import tensorflow as tf
import tflearn
X = [[0., 0.], [0., 1.], [1., 0.], [1., 1.]]
Y_xor = [[0.], [1.], [1.], [0.]]
# Graph definition
with tf.Graph().as_default():
# Building a network with 2 optimizers
net = tflearn.input_data(shape=[None, 2])
# Nand operator definition
net = tflearn.fully_connected(net, 2, activation='relu')
net = tflearn.fully_connected(net, 2, activation='relu')
net = tflearn.fully_connected(net, 1, activation='sigmoid')
regressor = tflearn.regression(net, optimizer='adam', learning_rate=0.005, loss="mean_square",)
# Training
m = tflearn.DNN(regressor)
m.fit(X, Y_xor, n_epoch=256, snapshot_epoch=False)
# Testing
print("Testing XOR operator")
print("0 xor 0:", m.predict([[0., 0.]]))
print("0 xor 1:", m.predict([[0., 1.]]))
print("1 xor 0:", m.predict([[1., 0.]]))
print("1 xor 1:", m.predict([[1., 1.]]))
有时我会得到这样正确的结果:
Testing XOR operator
0 xor 0: [[0.1487255096435547]]
0 xor 1: [[0.9297153949737549]]
1 xor 0: [[0.9354135394096375]]
1 xor 1: [[0.1487255096435547]]
但通常是这样的:
Testing XOR operator
0 xor 0: [[0.4999997615814209]]
0 xor 1: [[0.5000002384185791]]
1 xor 0: [[0.4999997615814209]]
1 xor 1: [[0.5000001788139343]]
我的 2x2x1 网络应该能够执行 XOR,甚至有一些证据表明这个网络应该总是收敛 http://www.ncbi.nlm.nih.gov/pubmed/12662805
我也试过将relu层改成sigmoid,进行2048次迭代,做了一个4x4x1和6x6x1的网络,但有时还是会出现同样的问题
会不会是权重初始化有问题? 如何使用 tflearn 让神经网络学习 xor 函数?
具有 relu
的网络(如代码片段中所写)预计经常无法训练。原因是如果relu的输入小于零,输出为零,因此返回的梯度也为零。
因为你有两层,每层只有两个 relu 单元,通过随机初始化,这两层中的每一层都有 25% 的所有神经元返回零,因此返回零梯度 => 神经网络不会学习。在这样的网络中,最后一层(在最终 sigmoid 之前)的输出将为零,其中 sigmoid 为 0.5——这正是您在网络未收敛的尝试中观察到的结果。
由于每一层都有 25% 的几率造成这种损害,因此整个网络从一开始就无法训练的总几率约为 45% (1 - (1 - 0.25)^2
)。还有一个非零的可能性是网络一开始不是这样的状态,但在训练过程中恰好把自己带到这样的状态,进一步增加发散的机会。
有四个神经元时,机会会显着降低,但仍不为零。
现在,我唯一无法回答的是,当您将 relu
替换为 sigmoid
时,为什么您的网络不收敛——这样的网络应该始终能够学习 "xor".我唯一的假设是你只用 sigmoid
替换了一个 relu
,而不是两个。
你能用 sigmoid
替换两个 relu
并确认你仍然观察到分歧吗?
除了@Ishamael 的建议,考虑使用不同的损失函数。均方误差通常不是 sigmoid 激活的好选择,因为由于饱和度,梯度可能会收缩得太小而无法用于学习。
我决定添加另一个答案:我做了更多研究并提供了一些截然不同的建议。
略读 this 论文后,我突然意识到您看不到收敛的原因可能与初始权重有关。该论文特别引用了 Hirose 等人(Hirose、Yamashita 和 Hijiya 1991)的一些工作,这些工作发现使用有限范围的权重进行初始化会导致收敛的概率非常低。 “最佳点”似乎平均在 0.5 到 1 之间,才能可靠地收敛。
事实证明,tflearn 将默认使用标准差为 0.02 的截断正常初始化。所以权重的范围非常有限。我发现使用 -1.0 到 1.0 的随机统一初始化可以获得相当可靠的结果。
另外,顺便说一句,您添加了第 3 层。 XOR 只需要一个隐藏层,所以你可以去掉第二个。这是对我有用的代码:
import tensorflow as tf
import tflearn
X = [[0., 0.], [0., 1.], [1., 0.], [1., 1.]]
Y_xor = [[0.], [1.], [1.], [0.]]
# Graph definition
with tf.Graph().as_default():
tnorm = tflearn.initializations.uniform(minval=-1.0, maxval=1.0)
net = tflearn.input_data(shape=[None, 2])
net = tflearn.fully_connected(net, 2, activation='sigmoid', weights_init=tnorm)
net = tflearn.fully_connected(net, 1, activation='sigmoid', weights_init=tnorm)
regressor = tflearn.regression(net, optimizer='sgd', learning_rate=2., loss='mean_square')
# Training
m = tflearn.DNN(regressor)
m.fit(X, Y_xor, n_epoch=10000, snapshot_epoch=False)
# Testing
print("Testing XOR operator")
print("0 xor 0:", m.predict([[0., 0.]]))
print("0 xor 1:", m.predict([[0., 1.]]))
print("1 xor 0:", m.predict([[1., 0.]]))
print("1 xor 1:", m.predict([[1., 1.]]))
请注意,我使用的是均方误差。令我惊讶的是,它似乎最适合解决这个问题。交叉熵似乎会导致优化器在问题的相对平坦区域中萎靡不振 space。我本以为相反;也许精通数学的人能够更好地解释这一点。
我在寻找学习 XOR 所需的最小神经元网络架构时遇到了模拟问题,它应该是 (2,2,1) 网络。事实上,数学表明 (2,2,1) 网络可以解决异或问题,但数学并没有表明 (2,2,1) 网络易于训练。也就是说,我很容易通过 (2,3,1) 或 (2,4,1) 网络架构获得良好的结果。此外,使用 0.5 和 1.0 之间的随机数进行权重初始化有助于收敛。
这个问题好像和存在很多局部极小点有关。看看这篇 1998 年的论文,«Learning XOR: exploring the space of a classic problem»,作者是理查德·布兰德 (Richard Bland)。也许你可以尝试不同的权重随机初始化或改变你的损失函数。
使用损失函数 'mean_squared_error'、sigmoid 激活和 Adam 优化器,它在 Keras 或 TensorFlow 上运行良好。