我仅使用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)我不了解二进制交叉熵如何与这些值一起使用。二进制交叉熵是针对两个输出值的,对吧?
答案 0 :(得分:6)
在自动编码器的上下文中,模型的输入和输出相同。因此,如果输入值在[0,1]范围内,则可以使用sigmoid
作为最后一层的激活函数。否则,您需要在最后一层使用适当的激活功能(例如linear
是默认的激活功能)。
关于损失函数,它又回到输入数据的值。如果输入数据仅是零和一之间的 (而不是它们之间的值),则binary_crossentropy
作为损失函数是可以接受的。否则,您需要使用其他损失函数,例如'mse'
(即均方误差)或'mae'
(即均值绝对误差)。请注意,在输入值范围为[0,1]
的情况下,您可以使用通常使用的binary_crossentropy
(例如Keras autoencoder tutorial和this paper)。但是,不要指望损失值会为零,因为当预测和标签都不为零或一(无论它们是否相等)时,binary_crossentropy
不会返回零。 Here是Hugo Larochelle的视频,他解释了自动编码器中使用的损失函数(有关使用binary_crossentropy
并在[0,1]范围内输入的部分从5:30开始)
具体地,在您的示例中,您正在使用MNIST数据集。因此,默认情况下,MNIST的值是[0,255]范围内的整数。通常,您需要先对其进行标准化:
trainX = trainX.astype('float32')
trainX /= 255.
现在值将在[0,1]范围内。因此,sigmoid
可以用作激活函数,binary_crossentropy
或mse
可以用作损失函数。
为什么即使真实标签值(即地面真相)在[0,1]范围内,也可以使用binary_crossentropy
?
请注意,我们正在尝试最小化训练中的损失函数。因此,当预测等于真标签时,如果我们使用的损失函数达到最小值(不一定等于零),那么这是一个可以接受的选择。让我们验证一下binray交叉熵的情况,其定义如下:
bce_loss = -y*log(p) - (1-y)*log(1-p)
其中y
是真实标签,p
是预测值。让我们考虑y
是固定的,看看p
的值使该函数最小化:我们需要对p
取导数(我假设log
是自然的对数函数以简化计算):
bcd_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
时,即当真实标签等于预测标签时,二进制交叉熵具有最小值,这正是我们所要寻找的。