如何在 Keras 中进行逐点分类交叉熵损失?
Posted
技术标签:
【中文标题】如何在 Keras 中进行逐点分类交叉熵损失?【英文标题】:How to do point-wise categorical crossentropy loss in Keras? 【发布时间】:2017-08-19 09:28:51 【问题描述】:我有一个生成 4D 输出张量的网络,其中空间维度(~像素)中每个位置的值将被解释为该位置的类概率。换句话说,输出是(num_batches, height, width, num_classes)
。我有相同大小的标签,其中真正的类被编码为 one-hot。我想用这个来计算categorical-crossentropy
损失。
问题 #1: K.softmax
函数需要一个 2D
张量 (num_batches, num_classes)
问题 #2:我不确定应该如何组合每个位置的损失。 reshape
张量到(num_batches * height * width, num_classes)
然后调用K.categorical_crossentropy
是否正确?或者更确切地说,调用K.categorical_crossentropy(num_batches, num_classes)
height*width 次并平均结果?
【问题讨论】:
你使用哪个后端? @MarcinMożejko 我使用 TensorFlow - 可以使用 Keras 后端 api 或 TF 自己的函数,都可以。谢谢! 我已经回答了你的问题 :-) 老兄 - 你需要查看我们的答案,因为在其他方面,你的第一个答案(你在筹集赏金之前得到的这个答案)会赢:) 【参考方案1】:找到this issue确认我的直觉。
简而言之:softmax 将采用 2D 或 3D 输入。如果它们是 3D keras 将采用这样的形状(样本、时间维度、numclasses)并在最后一个上应用 softmax。由于一些奇怪的原因,它不会对 4D 张量这样做。
解决方案:将输出重塑为像素序列
reshaped_output = Reshape((height*width, num_classes))(output_tensor)
然后应用你的 softmax
new_output = Activation('softmax')(reshaped_output)
然后要么将目标张量重塑为 2D,要么将最后一层重塑为 (width, height, num_classes)。
否则,如果我现在不在手机上,我会尝试使用TimeDistributed(Activation('softmax'))
。但不知道这是否可行……稍后再试
我希望这会有所帮助:-)
【讨论】:
【参考方案2】:只需将输出展平为大小为(num_batches, height * width * num_classes)
的二维张量。您可以使用Flatten
层执行此操作。确保您的 y
以相同的方式展平(通常调用 y = y.reshape((num_batches, height * width * num_classes))
就足够了)。
对于第二个问题,对所有 width*height
预测使用分类交叉熵与为每个 width*height
预测平均分类交叉熵基本相同(根据分类交叉熵的定义)。
【讨论】:
谢谢!我对 (num_batches, height * width * num_classes) 感到困惑。这不是本质上计算交叉熵,就好像有 num_batches 个样本,每个样本都有 height * width * num_classes 个类?我很确定我希望将每个点都算作一个单独的样本,这与重塑为 (num_batches * height * width, num_classes) 不一样吗?请让我知道这两者在数学上是否相等。 抱歉,仅分类交叉熵在数学方面基本上是相同的。但是将它与 softmax 一起使用在数学方面不会是相同的,因为输出是标准化的,这在我的回答中是一个失误。我认为不可能改变模型中输入中点的批量大小。最好的方法可能是解决并实现您自己的 softmax 激活函数,对每个height * width
单元格的输出进行标准化。
谢谢!我仍然对如何将其转换为工作代码感到困惑,你能试一试吗?我开始了赏金:)【参考方案3】:
您也不能reshape
任何东西,而是自己定义softmax
和loss
。这是应用于最后一个输入维度的softmax
(如tf
后端):
def image_softmax(input):
label_dim = -1
d = K.exp(input - K.max(input, axis=label_dim, keepdims=True))
return d / K.sum(d, axis=label_dim, keepdims=True)
这里有loss
(无需重塑任何东西):
__EPS = 1e-5
def image_categorical_crossentropy(y_true, y_pred):
y_pred = K.clip(y_pred, __EPS, 1 - __EPS)
return -K.mean(y_true * K.log(y_pred) + (1 - y_true) * K.log(1 - y_pred))
无需进一步重塑。
【讨论】:
【参考方案4】:现在您似乎可以简单地在最后一个Conv2D
层上进行softmax
激活,然后指定categorical_crossentropy
损失并在图像上进行训练,而无需任何重塑技巧或任何新的损失函数。我尝试过使用虚拟数据集进行过度拟合,效果很好。试试吧~!
inp = keras.Input(...)
# define your model here
out = keras.layers.Conv2D(classes, (1, 1), activation='softmax') (...)
model = keras.Model(inputs=[inp], outputs=[out], name='unet')
model.compile(loss='categorical_crossentropy',
optimizer='adam',
metrics=['accuracy'])
model.fit(tensor4d, tensor4d)
您还可以使用sparse_categorical_crossentropy
进行编译,然后使用形状为(samples, height, width)
的输出进行训练,其中输出中的每个像素对应一个类标签:model.fit(tensor4d, tensor3d)
想法是softmax
和categorical_crossentropy
将应用于最后一个轴(您可以查看keras.backend.softmax
和keras.backend.categorical_crossentropy
文档)。
PS。我使用来自tensorflow.keras
的keras
(tensorflow 2)
更新:我已经对我的真实数据集进行了培训,并且它也可以正常工作。
【讨论】:
以上是关于如何在 Keras 中进行逐点分类交叉熵损失?的主要内容,如果未能解决你的问题,请参考以下文章
如何在 Keras 的 FCN(U-Net)上使用加权分类交叉熵?
如何在 keras 中创建自定义损失函数? (自定义加权二元交叉熵)
详解pytorch中的交叉熵损失函数nn.BCELoss()nn.BCELossWithLogits(),二分类任务如何定义损失函数,如何计算准确率如何预测