我对TensorFlow中的sparse_softmax_cross_entropy
成本函数有疑问。
我想在语义分段上下文中使用它,我在其中使用自动编码器架构,该架构使用典型的卷积操作来下采样图像以创建特征向量。此向量不是上采样(使用conv2d_transpose
和逐个卷积来创建输出图像。
因此,我的输入包含形状为(1,128,128,1)
的单通道图像,其中第一个索引表示批量大小,最后一个索引表示通道数。图像的像素目前是0
或1
。因此每个像素都映射到一个类。自动编码器的输出图像遵循相同的规则。因此,我不能使用任何预定义的成本函数,而不是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)
答案 0 :(得分:1)
By definition logit是未缩放的概率(严格来说,赔率)或只是将任何号码。长度num_classes
的对数序列可以解释为未缩放的概率分布。例如,在您的情况下,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]
张量。损失名称中的术语稀疏指的是标签不是单热编码的事实(更多细节here)。当类的数量很大时,它是最有用的,即单热编码在内存方面变得太低效,但在你的情况下,它是无关紧要的。如果您决定使用tf.sparse_softmax_cross_entropy
丢失,则标签必须为[batch_size, 128, 128]
,必须为tf.int32
或tf.int64
且必须包含正确的类索引,零或一。这就是:tensorflow可以计算这两个数组之间的交叉熵。