在Keras中自定义损失函数在自编码器训练过程中产生误导性输出

我有大小为(100,100,4)的三阶张量,我试图用自编码器进行压缩和重建。我使用了一个基于物理原理的损失函数。数学上它是

L = – overlap(y_true,y_pred) + |1 – norm(y_pred)^2|

在代码中,它是这样的:

def physical_loss(y_true,y_pred,norm=None):    return - tf.tensordot(y_true,y_pred,axes=([0,1,2],[0,1,2])) + tf.math.abs(1 - tf.tensordot(y_pred,y_pred,axes=([0,1,2],[0,1,2])))

第一个项是输入和输出张量之间的重叠(我希望最大化),第二个项防止输出张量爆炸,并且最理想的情况是保持其范数为1(张量与自身的重叠=范数)。因此,理想情况下,损失会降到-1(即y_pred = y_true且norm(y_pred)=1)

我的模型是一个卷积自编码器,它将大小缩减到(50,50,4),(25,25,4),然后再次构建回来。

cnn.compile(loss=physical_loss,optimizer="adam")cnn.fit(x_train, x_train, epochs=num_epochs, batch_size=16,validation_data=(x_train,x_train))

现在,当我训练我的卷积神经网络时,损失在16个epoch内逐渐下降,最终达到val_loss = -0.67。但是当我手动检查结果(即直接计算x_train和cnn.predict(x_train)之间的损失),平均我得到的是0.75(正数!)。

所以我的问题是Keras/TensorFlow在评估时输出了什么?

这可能与另一个问题有关,但当我使用cnn.evaluate(x_train,x_train,batch_size=X)时,结果会根据我选择的batch size X在+0.88到-0.88之间变化(选择None时,即32时,结果为-0.67)。我知道Keras是以批次处理所有事情的,但这不应该改变整体输出,对吗?这也使得解释输出/训练成功变得困难。


回答:

我想我已经弄明白了,问题在于Keras/TensorFlow期望的是一个已经向量化的函数。上述定义适用于三阶张量,但Keras/TensorFlow总是处理批次,即不是实际的列表而是四阶张量(第一维是“列表”)。

我发现向量化这个损失函数并不简单,但我找到了一个使用tf.map_fn(function,listed_tensor,dtype)的有效解决方案,其中listed_tensor是提到的四阶批次。

def single_eval(duo):    return - tf.tensordot(duo[0],duo[1],axes=([0,1,2],[0,1,2])) + tf.keras.backend.abs(1 - tf.tensordot(duo[1],duo[1],axes=([0,1,2],[0,1,2])))def physical_loss(y_true,y_pred,norm=None):    return tf.map_fn(single_eval,(y_true,y_pred),dtype=(tf.float32))

指定dtype是必要的,以便能够使用元组作为参数(即使用两个参数)。

Related Posts

在使用k近邻算法时,有没有办法获取被使用的“邻居”?

我想找到一种方法来确定在我的knn算法中实际使用了哪些…

Theano在Google Colab上无法启用GPU支持

我在尝试使用Theano库训练一个模型。由于我的电脑内…

准确性评分似乎有误

这里是代码: from sklearn.metrics…

Keras Functional API: “错误检查输入时:期望input_1具有4个维度,但得到形状为(X, Y)的数组”

我在尝试使用Keras的fit_generator来训…

如何使用sklearn.datasets.make_classification在指定范围内生成合成数据?

我想为分类问题创建合成数据。我使用了sklearn.d…

如何处理预测时不在训练集中的标签

已关闭。 此问题与编程或软件开发无关。目前不接受回答。…

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注