二元交叉熵损失如何在自动编码器上起作用?

Posted

技术标签:

【中文标题】二元交叉熵损失如何在自动编码器上起作用?【英文标题】:How does binary cross entropy loss work on autoencoders? 【发布时间】:2019-02-25 18:06:21 【问题描述】:

我只使用Dense 层编写了一个香草自动编码器。 以下是我的代码:

iLayer = Input ((784,))
layer1 = Dense(128, activation='relu' ) (iLayer)
layer2 = Dense(64, activation='relu') (layer1)
layer3 = Dense(28, activation ='relu') (layer2)
layer4 = Dense(64, activation='relu') (layer3)
layer5 = Dense(128, activation='relu' ) (layer4)
layer6 = Dense(784, activation='softmax' ) (layer5)
model = Model (iLayer, layer6)
model.compile(loss='binary_crossentropy', optimizer='adam')

(trainX, trainY), (testX, testY) =  mnist.load_data()
print ("shape of the trainX", trainX.shape)
trainX = trainX.reshape(trainX.shape[0], trainX.shape[1]* trainX.shape[2])
print ("shape of the trainX", trainX.shape)
model.fit (trainX, trainX, epochs=5, batch_size=100)

问题:

1) softmax 提供概率分布。明白了。这意味着,我将有一个包含 784 个值的向量,概率在 0 和 1 之间。例如 [0.02, 0.03..... 最多 784 个项目],将所有 784 个元素相加得到 1。

2) 我不明白二元交叉熵如何处理这些值。二元交叉熵是针对两个输出值的吧?

【问题讨论】:

在这种情况下(自动编码器),通常使用 sigmoid 激活,而不是 softmax;你检查过(非常分析的)Keras tutorial 关于这个话题吗? 感谢您的回复。但是,我们还要推导出损失是如何计算的吗? 所以,我猜标题中的“错误”实际上是指loss,对吗? 是的,没错。 我编辑了标题 - 请确认这确实是您所要求的(我也添加了 autoencoder 标签)... 【参考方案1】:

在自动编码器的上下文中,模型的输入和输出是相同的。因此,如果输入值在 [0,1] 范围内,则可以使用sigmoid 作为最后一层的激活函数。否则,您需要为最后一层使用适当的激活函数(例如linear,这是默认的)。

至于损失函数,又回到了输入数据的值。如果输入数据在零和一之间(而不是它们之间的值),那么binary_crossentropy 是可接受的损失函数。否则,您需要使用其他损失函数,例如'mse'(即均方误差)或'mae'(即平均绝对误差)。请注意,对于[0,1] 范围内的输入值,您可以使用binary_crossentropy,因为它通常被使用(例如Keras autoencoder tutorial 和this paper)。但是,不要指望损失值会变为零,因为当预测和标签都不是零或一(无论它们是否相等)时,binary_crossentropy 不会返回零。 Here 是来自 Hugo Larochelle 的视频,其中他解释了自动编码器中使用的损失函数(关于在 [0,1] 范围内使用 binary_crossentropy 的部分从 5:30 开始)

具体来说,在您的示例中,您使用的是 MNIST 数据集。所以默认情况下,MNIST 的值是 [0, 255] 范围内的整数。通常你需要先对它们进行归一化:

trainX = trainX.astype('float32')
trainX /= 255.

现在值将在 [0,1] 范围内。所以sigmoid可以作为激活函数,binary_crossentropy或者mse作为损失函数。


为什么即使真正的标签值(即ground-truth)在[0,1]范围内也可以使用binary_crossentropy

请注意,我们正在尝试最小化训练中的损失函数。因此,如果我们使用的损失函数在预测等于真实标签时达到其最小值(可能不一定等于零),那么它是一个可以接受的选择。让我们验证一下二进制交叉熵的情况,其定义如下:

bce_loss = -y*log(p) - (1-y)*log(1-p)

其中y 是真实标签,p 是预测值。让我们将y 视为固定值,看看p 的哪个值最小化了这个函数:我们需要对p 求导(为了计算简单,我假设log 是自然对数函数):

bce_loss_derivative = -y*(1/p) - (1-y)*(-1/(1-p)) = 0 =>
                      -y/p + (1-y)/(1-p) = 0 =>
                      -y*(1-p) + (1-y)*p = 0 =>
                      -y + y*p + p - y*p = 0 =>
                       p - y = 0 => y = p

正如您所见,二元交叉熵在y=p 时具有最小值,即当真实标签等于预测标签时,这正是我们正在寻找的。

【讨论】:

不完全准确;请检查Keras tutorial on autoencoders,其中二进制交叉熵 + sigmoid 用于 MNIST 数据(像素值),它们肯定不是二进制... @desertnaut 我想这有点不对。因为,当预测和标签相同并且它们既不是零也不是一时,二元交叉熵不会返回零。换句话说,你预测正确,但损失不是零!查看交叉验证的answer 了解更多信息。 @desertnaut 他当然知道!我更新了我的答案。请看一看。 @desertnaut 虽然您可能没有时间,但我只是想让您知道,我刚刚添加了数学证明,证明为什么binary_crossentropy 可以成为可接受的选择。我只是想也许你有兴趣知道为什么。干杯! @desertnaut 非常感谢您的触发。因此我学到了一些新东西。

以上是关于二元交叉熵损失如何在自动编码器上起作用?的主要内容,如果未能解决你的问题,请参考以下文章

自定义 keras 损失函数二元交叉熵给出不正确的结果

pytorch 中的交叉熵损失如何工作?

Sigmoid 与二元交叉熵损失

为啥tf模型训练时的二元交叉熵损失与sklearn计算的不同?

实现二元交叉熵损失给出了与 Tensorflow 不同的答案

Quora Question Pairs 挑战,使用二元交叉熵损失预测两个问题是不是问同一个问题来评估预测