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?
在 Python 中编写和注册自定义 TensorFlow 操作
如何强制 TensorFlow 在 float16 下运行?