自动编码器上的二元交叉熵损失是如何工作的?

32

我使用仅有的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教程 - desertnaut
谢谢回复。但是,我们还是要推导一下损失是如何计算的吗? - Whoami
所以,我猜您在标题中说的“error”实际上是指损失,对吗? - desertnaut
是的,没错。 - Whoami
我编辑了标题 - 请确认这是否是您要求的(我也添加了“自编码器”标签)... - desertnaut
正确,但需要与softmax输出对齐。 - Whoami
1个回答

41

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

关于损失函数,它与输入数据的值有关。如果输入数据仅在0和1之间(而不是它们之间的值),则可以使用二元交叉熵作为损失函数。否则,您需要使用其他损失函数,例如“ mse”(即均方误差)或“ mae”(即平均绝对误差)。请注意,在输入值范围为[0,1]的情况下,您可以使用二元交叉熵,因为它通常被使用(例如Keras自编码器教程这篇论文)。但是,不要期望损失值变为零,因为当预测值和标签都不是零或一时(无论它们是否相等),二元交叉熵不会返回零。这里是来自Hugo Larochelle的视频,他在其中解释了自编码器中使用的损失函数(关于在输入范围[0,1]内使用二元交叉熵的部分从5:30开始)。

具体而言,在您的示例中,您正在使用MNIST数据集。因此,默认情况下,MNIST的值是在[0,255]范围内的整数。通常,您需要先对它们进行标准化:

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

现在的值将在[0,1]范围内。因此,可以使用sigmoid作为激活函数,使用binary_crossentropy或mse中的任何一个作为损失函数。
为什么即使真实标签值(即地面真实值)在[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时,二元交叉熵函数取得最小值,这正是我们所期望的。

2
不是完全准确的,请查看Keras自编码器教程,其中对于MNIST数据(像素值),使用了二元交叉熵+sigmoid,这显然不是二进制... - desertnaut
2
@desertnaut 我想这有点不对。因为当预测和标签相同时,二元交叉熵并不返回零,并且它们也不是零和一。换句话说,你的预测是正确的,但损失不为零!请查看交叉验证上的这个答案获取更多信息。 - today
1
@desertnaut 尽管您可能没有时间,但我想让您知道我刚刚添加了数学证明,证明为什么 binary_crossentropy 可以是一个可接受的选择。我只是觉得您可能会对此感兴趣。干杯! - today
1
你赢得了应得的点赞;很高兴能够激励你编辑答案并纠正你最初不准确的说法(“而不是它们之间的值”);) - desertnaut
3
@desertnaut非常感谢你的提醒。由于那个触发,我学到了一些新知识。 - today
显示剩余4条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接