from_logits = True和from_logits = False获得针对UNet的tf.losses.CategoricalCrossentropy的不同训练结果

tid*_*idy 6 python image-segmentation keras tensorflow tf.keras

如果我Softmax Activation像这样设置最后一层,我正在用unet进行图像语义分割工作:

...
conv9 = Conv2D(n_classes, (3,3), padding = 'same')(conv9)
conv10 = (Activation('softmax'))(conv9)
model = Model(inputs, conv10)
return model
...
Run Code Online (Sandbox Code Playgroud)

然后使用即使只有一个训练图像loss = tf.keras.losses.CategoricalCrossentropy(from_logits=False) ,训练也不会收敛

但是,如果我没有Softmax Activation像这样设置最后一层:

...
conv9 = Conv2D(n_classes, (3,3), padding = 'same')(conv9)
model = Model(inputs, conv9)
return model
...
Run Code Online (Sandbox Code Playgroud)

然后使用loss = tf.keras.losses.CategoricalCrossentropy(from_logits=True) 训练将收敛为一个训练图像。

我的groundtruth数据集是这样生成的:

X = []
Y = []
im = cv2.imread(impath)
X.append(im)
seg_labels = np.zeros((height, width, n_classes))
for spath in segpaths:
    mask = cv2.imread(spath, 0)
    seg_labels[:, :, c] += mask
Y.append(seg_labels.reshape(width*height, n_classes))
Run Code Online (Sandbox Code Playgroud)

为什么?我的用法有问题吗?

这是我的git实验代码:https : //github.com/honeytidy/unet 您可以检出并运行(可以在cpu上运行)。您可以更改激活层和CategoricalCrossentropy的from_logits并查看我说的内容。

Sha*_*hai 10

将“softmax”激活推入交叉熵损失层显着简化了损失计算并使其在数值上更加稳定。
可能的情况是,在您的示例中,数值问题足以使该from_logits=False选项的训练过程无效。

您可以在这篇文章中找到交叉熵损失(“信息增益”损失的特例)的推导。这个推导说明了将 softmax 与交叉熵损失相结合时避免的数值问题。


use*_*244 8

默认情况下,Tensorflow 中实现的用于分类问题的所有损失函数都使用 from_logits=False。请记住,在分类问题的情况下,在预测结束时,通常希望根据概率产生输出。

\n

看看下图,网络的最后一层(就在softmax函数之前)

\n

在此输入图像描述

\n

所以序列是神经网络 \xe2\x87\x92 最后一层输出 \xe2\x87\x92 Softmax 或 Sigmoid 函数 \xe2\x87\x92 每个类的概率。

\n

例如,在多类分类问题的情况下,输出可以是 y1, y2, .... yn,人们希望以某种概率产生每个输出。(参见输出层)。现在,该输出层将在交叉熵损失函数中与真实标签进行比较。

\n

让我们举一个例子,我们的网络生成分类任务的输出。假设您的神经网络正在产生输出,然后使用 softmax 函数将该输出转换为概率,并使用交叉熵损失函数计算损失

\n
# output produced by the last layer of NN\nnn_output_before_softmax = [3.2, 1.3, 0.2, 0.8]\n\n# converting output of last layer of NN into probabilities by applying softmax\nnn_output_after_softmax = tf.nn.softmax(nn_output_before_softmax)\n\n# output converted into softmax after appling softmax\nprint(nn_output_after_softmax.numpy())\n[0.77514964 0.11593805 0.03859243 0.07031998]\n\ny_true = [1.0, 0.0, 0.0, 0.0]\n
Run Code Online (Sandbox Code Playgroud)\n

现在有两种情况:

\n
    \n
  1. 一种是明确使用 softmax(或 sigmoid)函数

    \n
  2. \n
  3. 一是不单独使用softmax函数,想包含在损失函数的计算中

    \n
  4. \n
\n

1)一种是明确使用softmax(或sigmoid)函数

\n

当明确使用softmax(或sigmoid)函数时,对于分类任务,TensorFlow损失函数中有一个默认选项,即from_logits=False。因此,这里 TensorFlow 假设您将输入到损失函数的任何输入都是概率,因此无需应用 softmax 函数。

\n
# By default from_logits=False\nloss_taking_prob = tf.keras.losses.CategoricalCrossentropy(from_logits=False) \n\nloss_1 = loss_taking_prob(y_true, nn_output_after_softmax)\nprint(loss_1)\ntf.Tensor(0.25469932, shape=(), dtype=float32)\n
Run Code Online (Sandbox Code Playgroud)\n

2)一是不单独使用softmax函数,想将其包含在损失函数的计算中。这意味着您向损失函数提供的任何输入都不会缩放(意味着输入只是从 -inf 到 +inf 的数字,而不是概率)。在这里,您将让 TensorFlow 为您执行 softmax 操作。

\n
loss_taking_logits = tf.keras.losses.CategoricalCrossentropy(from_logits=True)\n\nloss_2 = loss_taking_logits(y_true, nn_output_before_softmax)\nprint(loss_2)\ntf.Tensor(0.2546992, shape=(), dtype=float32)\n
Run Code Online (Sandbox Code Playgroud)\n

请记住,当它应该为 True 时使用 from_logits=False 会导致采用概率的 softmax 并生成错误的模型

\n


小智 5

from_logits = True表示模型获得的损失值未标准化,基本上在模型中没有任何 softmax 函数时使用。例如https://www.tensorflow.org/tutorials/generative/dcgan在这个模型中,他们没有使用 softmax 激活函数,或者换句话说,我们可以说它有助于数值稳定性。