在 CNN 的 keras 自定义损失函数中操作数据

Posted

技术标签:

【中文标题】在 CNN 的 keras 自定义损失函数中操作数据【英文标题】:Manipulating data in keras custom loss function for CNN 【发布时间】:2020-09-05 06:34:09 【问题描述】:

我正在尝试在 Keras 中为我正在研究的 CNN 编写自定义损失函数。 Y_true 和 Y_pred 都将是灰度图像的张量,所以我希望形状为 [a, x, y, 1],其中 x 和 y 是我的图像的尺寸,a 是批量大小。

计划是:

    通过平均像素强度对 Y_true 的每个图像进行阈值化 使用此掩码的非零元素从 Y_true 和 Y_pred 获取像素值数组 测量这些数组的余弦相似度(使用内置的 Keras 损失函数),并将批次的平均结果作为损失返回

我的主要问题是如何有效地实施这个过程? cosine_similarity 函数是否适用于一维数组?

我知道我应该避免 for 循环以保持效率,但这是我能想到的实现此功能的唯一方法。有没有更有效的方法来使用 Keras 后端或 numpy 来实现这个功能?

编辑

使用此函数编译模型时的基本实现和意外错误:

def masked_cosine_similarity(y_true, y_pred):
    loss = 0
    for i in range(y_true.shape[0]):
        true_y = y_true[i,:,:,0]
        pred_y = y_pred[i,:,:,0]
        mask = true_y > np.mean(true_y)
        elements = np.nonzero(mask)
        true_vals = np.array([true_y[x,y] for x, y in zip(elements[0], elements[1])])
        pred_vals = np.array([pred_y[x,y] for x, y in zip(elements[0], elements[1])])
        loss += cosine_similarity(true_vals, pred_vals)
    return loss / y_true.shape[0]

错误信息:

     64     loss = 0
---> 65     for i in range(y_true.shape[0]):
     66         true_y = y_true[i,:,:,0]
     67         pred_y = y_pred[i,:,:,0]

TypeError: 'NoneType' object cannot be interpreted as an integer

【问题讨论】:

【参考方案1】:

Keras/TF 中张量的形状通常为[None, height, width, channels]。 这是由于支持任意批量大小,您不想构建仅适用于特定批量大小的模型。因此,您的代码会崩溃:

for i in range(y_true.shape[0]):

y_true.shape[0] == None.

为什么要循环批处理?你不需要这样做。 例如,给定一些元素级损失函数(MSE/余弦损失等),您可以执行以下操作:

def my_loss(y_true, y_pred):
    mask = tf.keras.backend.cast(y_true >= tf.math.reduce_mean(y_true, axis=[1,2], keepdims=True), 'float32') 
    masked_loss = K.sum(mask * elementwize_loss(y_true, y_pred), axis=-1)
    num_valid_pixels = K.maximum(1.0, K.cast(K.sum(mask), 'float32'))
    return masked_loss / num_valid_pixels

【讨论】:

我已经实现了您的答案,并且收到了 InvalidArgumentError: Incompatible shapes: [2,1024,1024,1] vs. [2,1024,1024],如果我使用 1 的批量大小,则不会发生这种情况 您可以使用“channel_first”吗?请详细说明您到底在哪里得到了错误...如果我必须猜测,也许您需要在 K.sum() 操作中添加参数“axis=-1”。 另外,我注意到您想要执行每个通道的平均值,所以请查看对我原始评论的编辑(指定axis = [1,2]以独立执行每个示例的平均值+添加"keepdims=True" 运算符保持输入的 4 维)。 尝试了更新的代码。同样的错误:InvalidArgumentError: Incompatible shapes: [8,1024,1024,1] vs. [8,1024,1024] 当将 elementwize_loss 设置为简单的欧几里德距离时,一个具有完全相同代码的虚拟示例对我有用:(y_true-y_pred)。我的猜测是您对 cosine_similarity 的实现使最后一个维度(其值为 1 并代表单个通道)消失了。尝试使用 reshape((-1, h,w,1)) 或类似的方法来确保你不改变维度的数量。

以上是关于在 CNN 的 keras 自定义损失函数中操作数据的主要内容,如果未能解决你的问题,请参考以下文章

使用预训练 vgg19 tensorflow,Keras 在 CNN 自动编码器中定义自定义损失(感知损失)

Keras 自定义损失函数 dtype 错误

如何在 Keras 中创建这个自定义损失函数并确保它是可微的?

Keras CIFAR-10分类 自定义simple CNN篇

keras 自定义 metrics

Keras 后端自定义损失函数