TensorFlow的tf.nn.softmax()函数比手写的softmax表现更好

3
我将使用TensorFlow编写一个简单的逻辑回归。我发现,当使用tf.nn.softmax时,算法收敛得更快,最终的准确率也更高。如果切换到自己实现的softmax函数,网络会收敛得更慢,并且最终的准确率不如使用tf.nn.softmax。
以下是代码:
SEED = 1025
W = tf.Variable(tf.truncated_normal([image_size * image_size, num_labels], seed=SEED))
b = tf.Variable(tf.zeros([num_labels]))
logits = tf.matmul(train_dataset, W) + b

# My softmax:
y_ = tf.exp(logits) / tf.reduce_sum(tf.exp(logits), axis=0)
# Tensorflow softmax: 
y_ = tf.nn.softmax(logits)

y_clipped = tf.clip_by_value(y_, 1e-10, 0.9999999)
loss = -tf.reduce_mean(tf.reduce_sum(train_labels * tf.log(y_clipped), axis=1))

使用我的softmax:
Loss at step 0: 22.213934
Training accuracy: 12.7%
Validation accuracy: 13.2%
Loss at step 100: 12.777291
Training accuracy: 45.3%
Validation accuracy: 45.5%
Loss at step 200: 11.361242
Training accuracy: 48.2%
Validation accuracy: 47.4%
Loss at step 300: 10.658278
Training accuracy: 51.4%
Validation accuracy: 49.7%
Loss at step 400: 9.297832
Training accuracy: 59.2%
Validation accuracy: 56.8%
Loss at step 500: 8.902699
Training accuracy: 62.0%
Validation accuracy: 59.2%
Loss at step 600: 8.681184
Training accuracy: 64.2%
Validation accuracy: 61.0%
Loss at step 700: 8.529438
Training accuracy: 65.8%
Validation accuracy: 62.3%
Loss at step 800: 8.416442
Training accuracy: 66.8%
Validation accuracy: 63.3%
Test accuracy: 70.4%

使用TensorFlow的softmax函数:
Loss at step 0: 13.555875
Training accuracy: 12.7%
Validation accuracy: 14.5%
Loss at step 100: 2.194562
Training accuracy: 72.5%
Validation accuracy: 72.0%
Loss at step 200: 1.808641
Training accuracy: 75.5%
Validation accuracy: 74.5%
Loss at step 300: 1.593390
Training accuracy: 76.8%
Validation accuracy: 75.0%
Loss at step 400: 1.442661
Training accuracy: 77.7%
Validation accuracy: 75.2%
Loss at step 500: 1.327751
Training accuracy: 78.2%
Validation accuracy: 75.4%
Loss at step 600: 1.236314
Training accuracy: 78.5%
Validation accuracy: 75.6%
Loss at step 700: 1.161479
Training accuracy: 78.9%
Validation accuracy: 75.6%
Loss at step 800: 1.098717
Training accuracy: 79.4%
Validation accuracy: 75.8%
Test accuracy: 83.3%

根据文档,理论上tensorflow的softmax函数应该与我自己实现的完全相同,是吗?

此函数执行以下等效操作:

softmax = tf.exp(logits) / tf.reduce_sum(tf.exp(logits), axis)

编辑:在从正态分布初始化时添加了种子后,我现在可以重现准确度结果。当在“我的softmax”行中设置轴值时,只有axis=0不会导致错误。设置axis=1或axis=-1都会导致以下错误:

tensorflow.python.framework.errors_impl.InvalidArgumentError: Dimensions must be equal, but are 10 and 10000 for 'truediv' (op: 'RealDiv') with input shapes: [10000,10], [10000].
3个回答

3
假设你的softmax实现是正确的。 首先,将tensorflow softmax与手写softmax进行比较是不公平的,因为你的程序中包含了随机性。 我的意思是,行W = tf.Variable(tf.truncated_normal([image_size * image_size, num_labels]))在你的程序中引入了随机性,因为权重最初是随机设置的,所以每次运行程序都会得到不同的结果。 只有当你有某种种子(一种起点)时,才能比较两个softmax。 现在,如果你多次执行上述实验,并且每次tensorflow softmax都击败了手写softmax,那么你的问题就是合理的。 tf.truncated_normal函数确实需要一个种子参数……你可以使用该参数并查看输出结果。 无论如何,如果你的手写softmax是正确的,那么使用种子后tensorflow softmax和你的softmax应该输出相同的结果。 我认为在你的情况下,轴应该是1,即最后一个轴,因为softmax应该沿着具有类别的轴。

谢谢!请查看我的修改,我添加了种子,但使用softmax函数后结果仍然更差。使用axis=1会导致错误。 - menphix

1
您正在将axis=0传递给“your” softmax。虽然我不知道您的数据长什么样,但通常情况下0是批处理轴,并沿着此轴执行softmax是不正确的。请参阅tf.nn.softmax的文档:默认值为axis为-1。通常,axis应该是包含不同类别的维度。

谢谢!但是将axis设置为-1会导致错误,请查看我的编辑。 - menphix
没错!目前的维度在求和之前/之后不兼容广播,所以导致了除法错误。尝试在reduce_sum中添加keepdims=True。这将使其输出一个形状为(10000, 1)的张量,可以广播到(10000, 10),从而使除法运算正常工作。 - xdurch0

0
总结一下,下面的实现方法是有效的。你可以通过MNIST初学者示例运行它,得到相同的准确性结果。
# My softmax:
y1 = tf.exp(logits)
y_ = y1 / tf.reduce_sum(y1, keepdims=True, axis=1)

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接