TensorFlow 的 sparse_softmax_cross_entropy 中的 Logits 表示

Posted

技术标签:

【中文标题】TensorFlow 的 sparse_softmax_cross_entropy 中的 Logits 表示【英文标题】:Logits representation in TensorFlow’s sparse_softmax_cross_entropy 【发布时间】:2018-09-27 17:55:26 【问题描述】:

我对 TensorFlow 中的 sparse_softmax_cross_entropy 成本函数有疑问。

我想在语义分割上下文中使用它,其中我使用自动编码器架构,该架构使用典型的卷积操作对图像进行下采样以创建特征向量。这个向量比上采样(使用conv2d_transpose和一对一的卷积来创建输出图像。 因此,我的输入由形状为(1,128,128,1) 的单通道图像组成,其中第一个索引表示批量大小,最后一个索引表示通道数。图像的像素当前为01。所以每个像素都映射到一个类。自编码器的输出图像遵循相同的规则。因此,除了MSE 或前面提到的那个,我不能使用任何预定义的成本函数。

网络与MSE 一起工作正常。但我无法让它与sparse_softmax_cross_entropy 一起工作。在这种情况下,这似乎是正确的成本函数,但我对logits 的表示有点困惑。官方文档说 logits 的形状应该是(d_i,...,d_n,num_classes)。我试图忽略num_classes 部分,但这会导致一个错误,指出只允许间隔[0,1)。当然,我需要指定将允许间隔变为[0,2) 的类数,因为独占上限显然是num_classes

有人可以解释一下如何将我的输出图像转换为所需的 logits 吗?

代价函数的当前代码是:

self._loss_op = tf.reduce_mean((tf.nn.sparse_softmax_cross_entropy_with_logits(labels=tf.squeeze(self._target_placeholder, [3]), logits=self._model, name="Loss")))

挤压删除标签输入的最后一个维度,为[1 128 128] 的标签创建一个形状。这会导致以下异常:

tensorflow.python.framework.errors_impl.InvalidArgumentError: Received a label value of 1 which is outside the valid range of [0, 1).

编辑:

根据要求,这里有一个最小示例来验证成本函数在全卷积网络环境中的行为:

constructor 截图:

def __init__(self, img_channels=1, img_width=128, img_height=128):
    ...
    self._loss_op = None
    self._learning_rate_placeholder = tf.placeholder(tf.float32, [], 'lr')
    self._input_placeholder = tf.placeholder(tf.float32, [None, img_width, img_height, img_channels], 'x')
    self._target_placeholder = tf.placeholder(tf.float32, [None, img_width, img_height, img_channels], 'y')
    self._model = self.build_model()
    self.init_optimizer()

build_model() 截图:

 def build_model(self):
        with tf.variable_scope('conv1', reuse=tf.AUTO_REUSE):
            #not necessary
            x = tf.reshape(self._input_placeholder, [-1, self._img_width, self._img_height, self._img_channels])
            conv1 = tf.layers.conv2d(x, 32, 5, activation=tf.nn.relu)
            conv1 = tf.layers.max_pooling2d(conv1, 2, 2)

        with tf.variable_scope('conv2', reuse=tf.AUTO_REUSE):
            conv2 = tf.layers.conv2d(conv1, 64, 3, activation=tf.nn.relu)
            conv2 = tf.layers.max_pooling2d(conv2, 2, 2)
        with tf.variable_scope('conv3_red', reuse=tf.AUTO_REUSE):
            conv3 = tf.layers.conv2d(conv2, 1024, 30, strides=1, activation=tf.nn.relu)
        with tf.variable_scope('conv4_red', reuse=tf.AUTO_REUSE):
            conv4 = tf.layers.conv2d(conv3, 64, 1, strides=1, activation=tf.nn.relu)
        with tf.variable_scope('conv5_up', reuse=tf.AUTO_REUSE):
            conv5 = tf.layers.conv2d_transpose(conv4, 32, (128, 128), strides=1, activation=tf.nn.relu)
        with tf.variable_scope('conv6_1x1', reuse=tf.AUTO_REUSE):
            conv6 = tf.layers.conv2d(conv5, 1, 1, strides=1, activation=tf.nn.relu)
        return conv6

init_optimizer() 截图:

def init_optimizer(self):
    self._loss_op = tf.reduce_mean((tf.nn.sparse_softmax_cross_entropy_with_logits(labels=tf.squeeze(self._target_placeholder, [3]), logits=self._model, name="Loss")))
    optimizer = tf.train.AdamOptimizer(learning_rate=self._learning_rate_placeholder)
    self._train_op = optimizer.minimize(self._loss_op)

【问题讨论】:

【参考方案1】:

By definition logit 是一个未标度的概率(严格来说几率)或简单地放入任何数。长度为num_classes 的logits 序列可以解释为未缩放的概率分布。例如,在您的情况下,num_classes=2,然后logits=[125.0, -10.0] 是一个像素的未缩放概率分布(显然有利于0 而不是1)。这个数组可以被softmax 压缩成一个有效的分布,这就是tf.sparse_softmax_cross_entropy 在内部所做的。对于[125.0, -10.0],压缩后的分布将非常接近[1.0, 0.0]

再一次,数组[2] 用于单个像素。 如果要计算整个图像的交叉熵,网络必须批量输出所有像素和所有图像的二进制分布,即输出[batch_size, 128, 128, 2]张量。损失名称中的术语 sparse 指的是 labels 不是 one-hot 编码的事实(更多细节here)。当类的数量很大时,它最有用,即单热编码在内存方面变得太低效,但在你的情况下它是微不足道的。如果您决定使用tf.sparse_softmax_cross_entropy 损失,标签必须是[batch_size, 128, 128],它必须是tf.int32tf.int64,并且必须包含正确的类索引,零或一。就是这样:tensorflow 可以计算这两个数组之间的交叉熵。

【讨论】:

感谢您的详细解答。当我使用建议的形状时,我收到以下错误:收到的标签值 1 超出了 [0, 1) 的有效范围。标签值:...您有任何解决此问题的想法吗? 顺便说一下,您的 666 答案与您的个人资料图片非常匹配。我会这样 ;) @BastianSchoettle 你检查标签了吗?请注意,它们必须是二进制的 @Bastian ,我遇到了同样的问题,我认为问题在于 sparse_softmax_cross_entropy_with_logits 的输入:如果您有两个类,则输入需要具有形状 (batch_size, 2) 。每个类一个输出,= 2。(您可以将输出与一个向量连接起来,并将其输入到函数中。) 在你的情况下,你有 conv6 = tf.layers.conv2d(conv5, 1, 1, strides=1, activation=tf.nn.relu),所以可能输出大小为 1?

以上是关于TensorFlow 的 sparse_softmax_cross_entropy 中的 Logits 表示的主要内容,如果未能解决你的问题,请参考以下文章

java调用tensorflow训练好的模型

tensorflow的安装问题 求解

TensorFlow如何入门?

TensorFlow文档翻译-01-TensorFlow入门

tensorflow新手必看,tensorflow入门教程,tensorflow示例代码

Tensorflow 导入错误:没有名为“tensorflow”的模块