TensorFlow MLP 无法训练 XOR

我使用 Google 的 TensorFlow 库构建了一个多层感知器(MLP)。网络能够运行,但不知为何它无法正确学习。无论输入是什么,它总是收敛到接近 1.0 的输出值。

完整代码可以在 这里 查看。

有什么建议吗?


输入和输出(批量大小为 4)如下所示:

input_data = [[0., 0.], [0., 1.], [1., 0.], [1., 1.]]  # XOR 输入
output_data = [[0.], [1.], [1.], [0.]]  # XOR 输出
n_input = tf.placeholder(tf.float32, shape=[None, 2], name="n_input")
n_output = tf.placeholder(tf.float32, shape=[None, 1], name="n_output")

隐藏层配置如下:

# 隐藏层的偏置神经元
b_hidden = tf.Variable(0.1, name="hidden_bias")
# 隐藏层的权重矩阵,使用均匀分布初始化
W_hidden = tf.Variable(tf.random_uniform([2, hidden_nodes], -1.0, 1.0), name="hidden_weights")
# 计算隐藏层的激活
hidden = tf.sigmoid(tf.matmul(n_input, W_hidden) + b_hidden)

输出层配置如下:

W_output = tf.Variable(tf.random_uniform([hidden_nodes, 1], -1.0, 1.0), name="output_weights")  # 输出层的权重矩阵
output = tf.sigmoid(tf.matmul(hidden, W_output))  # 计算输出层的激活

我的学习方法如下所示:

loss = tf.reduce_mean(cross_entropy)  # 计算交叉熵的平均值
optimizer = tf.train.GradientDescentOptimizer(0.01)  # 使用梯度下降进行优化
train = optimizer.minimize(loss)  # 让优化器进行训练

我尝试了两种交叉熵设置:

cross_entropy = -tf.reduce_sum(n_output * tf.log(output))

cross_entropy = tf.nn.sigmoid_cross_entropy_with_logits(n_output, output)

其中 n_outputoutput_data 中描述的原始输出,output 是我的网络预测/计算的值。


在 for 循环中的训练(n 个周期)如下进行:

cvalues = sess.run([train, loss, W_hidden, b_hidden, W_output],
                   feed_dict={n_input: input_data, n_output: output_data})

我将结果保存到 cvalues 中,以便调试打印 lossW_hidden 等信息。


无论我尝试了什么,当我测试我的网络,试图验证输出时,它总是产生类似这样的结果:

(...)
step: 2000
loss: 0.0137040186673
b_hidden: 1.3272010088
W_hidden: [[ 0.23195425  0.53248233 -0.21644847 -0.54775208  0.52298909]
 [ 0.73933059  0.51440752 -0.08397482 -0.62724304 -0.53347367]]
W_output: [[ 1.65939867]
 [ 0.78912479]
 [ 1.4831928 ]
 [ 1.28612828]
 [ 1.12486529]]
(--- finished with 2000 epochs ---)
(测试输入用于验证:)
input: [0.0, 0.0] | output: [[ 0.99339396]]
input: [0.0, 1.0] | output: [[ 0.99289012]]
input: [1.0, 0.0] | output: [[ 0.99346077]]
input: [1.0, 1.0] | output: [[ 0.99261558]]

所以它没有正确学习,而是无论输入什么都总是收敛到接近 1.0 的值。


回答:

在此期间,在一位同事的帮助下,我能够修复我的解决方案,并想为了完整性而发布它。我的解决方案使用交叉熵,并且没有更改训练数据。此外,它具有所需的输入形状(1, 2)标量输出

它使用 AdamOptimizer,其减少错误的速度远快于GradientDescentOptimizer。有关优化器的更多信息(和问题^^),请参见此帖子

事实上,我的网络仅在 400-800 个学习步骤中就产生了相当好的结果。

经过 2000 个学习步骤后,输出几乎是“完美”的:

step: 2000
loss: 0.00103311243281
input: [0.0, 0.0] | output: [[ 0.00019799]]
input: [0.0, 1.0] | output: [[ 0.99979786]]
input: [1.0, 0.0] | output: [[ 0.99996307]]
input: [1.0, 1.0] | output: [[ 0.00033751]]

import tensorflow as tf
    ###################### 准备工作 #######################
# 定义输入和输出数据
input_data = [[0., 0.], [0., 1.], [1., 0.], [1., 1.]]  # XOR 输入
output_data = [[0.], [1.], [1.], [0.]]  # XOR 输出
# 创建输入的占位符
# None 表示输入的批量大小可变
# 一个输入的维度是 [1, 2],输出是 [1, 1]
n_input = tf.placeholder(tf.float32, shape=[None, 2], name="n_input")
n_output = tf.placeholder(tf.float32, shape=[None, 1], name="n_output")
# 隐藏层的神经元数量
hidden_nodes = 5
################# 隐藏层 ################
# 隐藏层的偏置神经元
b_hidden = tf.Variable(tf.random_normal([hidden_nodes]), name="hidden_bias")
# 隐藏层的权重矩阵,使用均匀分布初始化
W_hidden = tf.Variable(tf.random_normal([2, hidden_nodes]), name="hidden_weights")
# 计算隐藏层的激活
hidden = tf.sigmoid(tf.matmul(n_input, W_hidden) + b_hidden)
################# 输出层 #################
W_output = tf.Variable(tf.random_normal([hidden_nodes, 1]), name="output_weights")  # 输出层的权重矩阵
output = tf.sigmoid(tf.matmul(hidden, W_output))  # 计算输出层的激活
############# 学习 #############
cross_entropy = -(n_output * tf.log(output) + (1 - n_output) * tf.log(1 - output))
# cross_entropy = tf.square(n_output - output)  # 更简单,但也有效
loss = tf.reduce_mean(cross_entropy)  # 计算交叉熵的平均值
optimizer = tf.train.AdamOptimizer(0.01)  # 使用 Adam 优化器进行优化,步长为 0.01
train = optimizer.minimize(loss)  # 让优化器进行训练
##################### 初始化图 #####################
init = tf.initialize_all_variables()
sess = tf.Session()  # 创建会话并因此创建图
sess.run(init)  # 初始化所有变量
###################### 训练网络 ######################
for epoch in xrange(0, 2001):
    # 运行训练操作
    cvalues = sess.run([train, loss, W_hidden, b_hidden, W_output],
                       feed_dict={n_input: input_data, n_output: output_data})
    # 打印一些调试信息
    if epoch % 200 == 0:
        print("")
        print("step: {:>3}".format(epoch))
        print("loss: {}".format(cvalues[1]))
        # print("b_hidden: {}".format(cvalues[3]))
        # print("W_hidden: {}".format(cvalues[2]))
        # print("W_output: {}".format(cvalues[4]))
print("")
print("input: {} | output: {}".format(input_data[0], sess.run(output, feed_dict={n_input: [input_data[0]]})))
print("input: {} | output: {}".format(input_data[1], sess.run(output, feed_dict={n_input: [input_data[1]]})))
print("input: {} | output: {}".format(input_data[2], sess.run(output, feed_dict={n_input: [input_data[2]]})))
print("input: {} | output: {}".format(input_data[3], sess.run(output, feed_dict={n_input: [input_data[3]]})))

Related Posts

L1-L2正则化的不同系数

我想对网络的权重同时应用L1和L2正则化。然而,我找不…

使用scikit-learn的无监督方法将列表分类成不同组别,有没有办法?

我有一系列实例,每个实例都有一份列表,代表它所遵循的不…

f1_score metric in lightgbm

我想使用自定义指标f1_score来训练一个lgb模型…

通过相关系数矩阵进行特征选择

我在测试不同的算法时,如逻辑回归、高斯朴素贝叶斯、随机…

可以将机器学习库用于流式输入和输出吗?

已关闭。此问题需要更加聚焦。目前不接受回答。 想要改进…

在TensorFlow中,queue.dequeue_up_to()方法的用途是什么?

我对这个方法感到非常困惑,特别是当我发现这个令人费解的…

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注