TensorFlow API:logits 的 softmax 交叉熵的计算

本文对 softmax_cross_entropy_with_logitssparse_softmax_cross_entropy_with_logits 两种交叉熵 API 的使用和之间的差别进行概要说明。

基础函数

基础函数不做说明:

1
2
3
4
5
6
7
8
from __future__ import absolute_import
from __future__ import division
from __future__ import print_function

import numpy as np
import tensorflow as tf

sess = tf.InteractiveSession()

logits 概率

假设有三张 MNIST 图片,logits(可以理解成归一化之前的概率表征)如下,形状为 [3, 10]

1
2
3
4
5
6
logits = tf.constant(
np.array([[100, 0, 0, 0, 0, 0, 2, 0, 0, 1], [0, 53, 0, 0, 0, 0, 0, 48, 0, 0], [2, 1, 27, 69, 8, 1, 6, 24, 1, 2]]),
dtype=tf.float32,
shape=[3, 10])

print(sess.run(tf.nn.softmax(logits)))

通过 softmax 计算的实际概率如下,可以看到这三张图片依次预测为数字 013

1
2
3
4
5
6
[[1.0000000e+00 0.0000000e+00 0.0000000e+00 0.0000000e+00 0.0000000e+00
0.0000000e+00 0.0000000e+00 0.0000000e+00 0.0000000e+00 0.0000000e+00]
[9.5384107e-24 9.9330717e-01 9.5384107e-24 9.5384107e-24 9.5384107e-24
9.5384107e-24 9.5384107e-24 6.6928510e-03 9.5384107e-24 9.5384107e-24]
[7.9849040e-30 2.9374821e-30 5.7495225e-19 1.0000000e+00 3.2213403e-27
2.9374821e-30 4.3596101e-28 2.8625186e-20 2.9374821e-30 7.9849040e-30]]

对于某一项,如果 logits 越大,则相应的 softmax 归一化概率也越大。

计算 softmax 交叉熵的两个 API

假设我们的图片实际标签依次为 073,即第一张和最后一张识别正确,中间一张识别有误(7 识别成了 1)。

sparse_softmax_cross_entropy_with_logits

sparse_softmax_cross_entropy_with_logits 需要使用一维形状labels,每个元素为整型标签:

1
2
3
4
5
6
7
8
9
# tf.nn.sparse_softmax_cross_entropy_with_logits
# needs labels to be 1-D shape [batch_size]
labels_1d = tf.constant(np.array([0, 7, 3]), dtype=tf.int64, shape=[3])

loss1 = tf.reduce_mean(tf.nn.sparse_softmax_cross_entropy_with_logits(logits=logits, labels=labels_1d))
correct_prediction1 = tf.equal(labels_1d, tf.argmax(logits, 1))
accuracy1 = tf.reduce_mean(tf.cast(correct_prediction1, tf.float32))

print(sess.run([loss1, correct_prediction1, accuracy1]))

输出为:

1
[1.6689051, array([ True, False, True]), 0.6666667]

softmax_cross_entropy_with_logits

sparse_softmax_cross_entropy_with_logits 需要使用二维形状labels,每个元素为独热编码(One Hot Encoder)标签:

1
2
3
4
5
6
7
8
9
10
11
12
# tf.nn.softmax_cross_entropy_with_logits
# needs labels to be 2-D shape [batch_size, num_classes]
labels_2d = tf.constant(
np.array([[1, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 1, 0, 0], [0, 0, 0, 1, 0, 0, 0, 0, 0, 0]]),
dtype=tf.float32,
shape=[3, 10])

loss2 = tf.reduce_mean(tf.nn.softmax_cross_entropy_with_logits(logits=logits, labels=labels_2d))
correct_prediction2 = tf.equal(tf.argmax(labels_2d, 1), tf.argmax(logits, 1))
accuracy2 = tf.reduce_mean(tf.cast(correct_prediction2, tf.float32))

print(sess.run([loss2, correct_prediction2, accuracy2]))

输出为:

1
[1.6689051, array([ True, False, True]), 0.6666667]

标签的维度转换

观察 labels_1dlabels_2d 其中的元素,实际上后者就是前者的独热编码转换:

1
print(sess.run([tf.one_hot(labels_1d, depth=10)]))
1
2
3
[array([[1., 0., 0., 0., 0., 0., 0., 0., 0., 0.],
[0., 0., 0., 0., 0., 0., 0., 1., 0., 0.],
[0., 0., 0., 1., 0., 0., 0., 0., 0., 0.]], dtype=float32)]