前几天我发布了一个类似的问题在这里,但自那以后我已经修复了一些发现的错误,然而预测结果差的问题依然存在。
我有两个网络——一个有3个卷积层,另一个在3个卷积层之后接着3个反卷积层。两者都接受200×200的输入图像。输出也是相同的200×200分辨率,但它有两个分类(要么是0要么是1——这是一个分割网络),所以网络预测的维度是200x200x2(加上批次大小)。我们来讨论一下带有反卷积层的网络。
奇怪的是…在10次训练运行中,可能只有3次会收敛。其余7次会发散到准确率为0.0。
卷积和反卷积层由ReLu激活。优化器的行为有些奇怪。当我在每次训练迭代后打印预测值时,值的幅度开始很大——考虑到它们都通过了ReLu,这是正确的——但在每次迭代后,值会变小,直到它们大致在0到2之间。我随后将它们通过一个Sigmoid函数(sigmoid_cross_entropy_wight_logits
)——因此将大的负值压缩到0,将大的正值压缩到1。当我进行预测时,我通过再次将输出通过Sigmoid函数来重新激活输出。
所以在第一次迭代后,预测值是合理的…
Accuracy = 0.508033[[[[ 1. 0.] [ 0. 1.] [ 0. 0.] ..., [ 1. 0.] [ 1. 1.] [ 1. 0.]] [[ 0. 1.] [ 1. 1.] [ 0. 0.] ..., [ 1. 1.] [ 1. 1.] [ 0. 1.]]
但在几次迭代后,假设这次它确实收敛了,预测值看起来像…(因为优化器使输出变小,它们都在Sigmoid函数的奇怪中间地带)
[[ 0.51028508 0.63202268] [ 0.24386917 0.52015287] [ 0.62086064 0.6953823 ] ..., [ 0.2593964 0.13163178] [ 0.24617286 0.5210492 ] [ 0.24692698 0.5876413 ]]]]Accuracy = 0.999913
我是否使用了错误的优化器函数?
这是整个代码…跳到def conv_net
查看网络创建…在该函数之后是成本函数、优化器和准确率的定义。你会注意到当我测量准确率和进行预测时,我通过tf.nn.sigmoid(pred)
重新激活输出——这是因为成本函数sigmoid_cross_entropy_with_logits
将激活和损失结合在同一个函数中。换句话说,pred
(网络)输出一个线性值。
...
correct_pred
变量(测量准确率的变量)是一个简单的减法运算符,用于预测和真实值之间的差异,然后与零进行比较(如果两者相等,那么差异应该为零)。
此外,我已经绘制了网络,它看起来对我来说非常不对劲。这是一张图片,我不得不裁剪以便查看。
编辑:我发现我的图看起来很糟糕的原因(感谢Olivier),我还尝试更改我的损失函数,但没有结果——它仍然以同样的方式发散
...
编辑 现在完整的代码看起来像这样(仍然在发散)
...
回答:
反卷积的概念是输出与输入相同大小的内容。
在这一行:
conv6 = tf.nn.bias_add(conv6, biases['bdc3'])
你有这个形状为[batch_size, 200, 200, 2]
的输出,所以你不需要添加你的全连接层。只需返回conv6
(不带最终的ReLU)。
如果你在预测和真实标签y
中使用两个类别,你需要使用tf.nn.softmax_cross_entropy_with_logits()
,而不是Sigmoid交叉熵。
确保y
始终具有如下值:y[i, j] = [0., 1.]
或y[i, j] = [1., 0.]
pred = conv_net(x, weights, biases, keep_prob) # 新预测 conv6pred = tf.reshape(pred, [-1, n_classes])# 定义损失和优化器cost = tf.reduce_mean(tf.nn.softmax_cross_entropy_with_logits(pred, y))
如果你想让你的TensorBoard图看起来好看(至少是可读的),请确保使用tf.name_scope()
编辑:
你的准确率也是错误的。你测量softmax(pred)
和y
是否相等,但softmax(pred)
永远不会等于0.
或1.
,所以你的准确率将是0.
。
你应该这样做:
with tf.name_scope("acc") as scope: correct_pred = tf.equal(tf.argmax(temp_pred, 1), tf.argmax(temp_y, 1)) accuracy = tf.reduce_mean(tf.cast(correct_pred, tf.float32))
编辑2:
真正的错误是在convert_to_2_channel
中的一个拼写错误,在循环中
for j in xrange(3):
它应该是200而不是3。
教训:在调试时,逐步打印所有内容,使用非常简单的例子,你会发现那个有问题的函数返回了错误的输出。