TensorFlow 如何编写自定义 Aitchison 损失

Posted

技术标签:

【中文标题】TensorFlow 如何编写自定义 Aitchison 损失【英文标题】:Tensorflow how to write custom Aitchison loss 【发布时间】:2021-10-08 11:48:33 【问题描述】:

大家好

我需要实现 Aitchison 损失函数以在输入和输出数据集之间进行验证。数据是二维的(批次、特征)。暂时将批量昏暗构造为“无”尺寸维度

如果损失函数可以与 numpy 数组一起使用,则可以通过这种方式轻松完成

def loss_Aitch(yTrue, yPred):
    yTrue_np = yTrue.numpy()
    yPred_np = yPred.numpy()

    sample_dist_mean = 0

    for i in range(yTrue_np.shape[0]):
        mult1 = 1.
        mult2 = 1.
        for j in range(yTrue_np.shape[1]):
            mult1 *= yTrue_np[i, j]
            mult2 *= yPred_np[i, j]

        mult1 = np.sqrt(mult1)
        mult2 = np.sqrt(mult2)

        sample_dist = 0
        for j in range(yTrue_np.shape[1]):
            sample_dist += np.square( np.log( yTrue_np[i, j] / mult1) - np.log(yPred_np[i, j] / mult2 ) )

        sample_dist = np.sqrt(sample_dist)
        sample_dist_mean += sample_dist

    sample_dist_mean /= yTrue_np.shape[0]

    return sample_dist_mean

但由于张量是占位符,所以这是行不通的。

那么这个函数如何直接在张量上实现呢?

【问题讨论】:

【参考方案1】:

您只需将所有 NumPy 函数替换为 TensorFlow 内置函数即可完成此操作。代码如下:

def loss_Aitch(yTrue, yPred):
    sample_dist_mean = 0.

    for i in range(yTrue.shape[0]):
        mult1 = 1.
        mult2 = 1.
        for j in range(yTrue.shape[1]):
            mult1 *= yTrue[i, j]
            mult2 *= yPred[i, j]

        mult1 = tf.sqrt(mult1)
        mult2 = tf.sqrt(mult2)

        sample_dist = 0.
        for j in range(yTrue.shape[1]):
            sample_dist += tf.square(tf.math.log(yTrue[i, j] / mult1) - tf.math.log(yPred[i, j] / mult2))

        sample_dist = tf.sqrt(sample_dist)
        sample_dist_mean += sample_dist
        # print(sample_dist)
    sample_dist_mean /= yTrue.shape[0]

    return sample_dist_mean

您可以像使用任何其他 TensorFlow 内置损失一样使用此函数:

model = Sequential([
    layers.Dense(64, activation="relu", input_shape=(32,)),
    layers.Dense(128, activation="relu"),
    layers.Dense(5),
])

model.compile(optimizer="adam", loss=loss_Aitch)

然后你就可以用你的数据 fit() 了。

然而,我注意到这个损失函数可能会在 mult1 和 mult2 为 0 时导致 nan。当它们非常大时可能会导致 inf,但由于我不熟悉损失本身而且我不知道您的数据是什么样的,我也不确定您想在这种情况下做什么。一种可能的解决方案是在除以时将 epsilon 添加到分母,并在结果变得太大时除以一个值。

【讨论】:

对不起,但我猜张量上的 yTrue[i, j] 是不正确的。此外,它不能工作,因为那是占位符,首先变暗只是没有变暗 @Anton TensorFlow 会在你适合的情况下在运行时推断批量大小,至少我试过并且它运行没有问题,我不确定你所说的张量上的 "yTrue[i, j] 是什么意思不正确”,因为我已经尝试过,TensorFlow 访问它没有问题 好的,一般来说你的方法可能有效。但我自己的情况是我通过“add_loss”函数添加损失(由于许多内部原因,它比通过“compile”添加更方便),这样我猜你不能使用张量索引【参考方案2】:

似乎找到了关于在 tensorflow 中计算 geomean 的答案

geometric mean while calculationg tensorflow loss

所以,我的最终解决方案是

def loss_A(y1, y2):
    logY1 = tf.math.log(y1)
    logY2 = tf.math.log(y2)

    log_G1 = tf.reduce_mean(logY1, axis = 1 )
    log_G2 = tf.reduce_mean(logY2, axis = 1 )

    log_G1 = tf.expand_dims(log_G1, 1)
    log_G2 = tf.expand_dims(log_G2, 1)


    logY1_sub = logY1 - log_G1
    logY2_sub = logY2 - log_G2


    A_v = tf.math.sqrt ( tf.reduce_sum( tf.math.square( logY1_sub - logY2_sub ), axis = 1 ) )


    return tf.reduce_mean(A_v)

【讨论】:

以上是关于TensorFlow 如何编写自定义 Aitchison 损失的主要内容,如果未能解决你的问题,请参考以下文章

如何使用自定义protobuf构建tensorflow 1.13.1?

在 tensorflow 中编写自定义成本函数

在 Python 中编写和注册自定义 TensorFlow 操作

如何强制 TensorFlow 在 float16 下运行?

TensorFlow 自定义分配器和从 Tensor 访问数据

自定义 TensorFlow Keras 优化器