如何在Keras中包装自定义TensorFlow损失函数?

Joh*_* L. 6 keras tensorflow

这是我开展深度学习项目的第三次尝试。我正在研究蛋白质序列。首先,我尝试了TFLearn,然后尝试了原始TensorFlow,现在我尝试了Keras。

前两次尝试教给了我很多东西,并给了我一些我可以重用的代码和概念。但是,总会有障碍,我问过开发人员无法回答的问题(在TFLearn的情况下),或者我只是陷入了困境(TensorFlow对象自省很乏味)。

我已经编写了这个TensorFlow损失函数,并且我知道它可以工作:

def l2_angle_distance(pred, tgt):
    with tf.name_scope("L2AngleDistance"):
        # Scaling factor
        count = tgt[...,0,0]
        scale = tf.to_float(tf.count_nonzero(tf.is_finite(count)))
        # Mask NaN in tgt
        tgt = tf.where(tf.is_nan(tgt), pred, tgt)
        # Calculate L1 losses
        losses = tf.losses.cosine_distance(pred, tgt, -1, reduction=tf.losses.Reduction.NONE)
        # Square the losses, then sum, to get L2 scalar loss.
        # Divide the loss result by the scaling factor.
        return tf.reduce_sum(losses * losses) / scale
Run Code Online (Sandbox Code Playgroud)

我的目标值(tgt)可以包含NaN,因为我的蛋白质序列是通过4D张量传递的,尽管各个序列的长度不同。在您询问之前,无法像图像一样对数据进行重新采样。因此,我在tgt张量中使用NaN来表示“此处无需预测”。在计算L2余弦损耗之前,我用预测(预测)中的匹配值替换每个NaN,因此每个NaN的损耗始终为零。

现在,如何在Keras中重用此功能?看来Keras Lambda核心层不是一个好选择,因为Lambda仅接受一个参数,而损失函数则需要两个参数。

或者,我可以在Keras中重写此功能吗?我永远不需要使用Theano或CNTK后端,因此对我而言,不必在Keras中重写函数。我会用任何可行的方法。

我只是查看了Keras loss.py文件以获得一些线索。我导入keras.backend并环顾四周。我还找到了https://keras.io/backend/。我似乎没有找到我碰巧使用的任何TensorFlow函数调用的包装器:to_float(),count_nonzero(),is_finite(),where(),is_nan(),cosine_distance()或reduce_sum()。

感谢您的建议!

Joh*_* L. 5

我回答了我自己的问题。我将解决方案发布给可能遇到相同问题的任何人。

Matias Valdenegro独立建议,我尝试直接在Keras中使用TF损失函数。我这样做并没有引起Keras的任何错误,但是损失值立即转到了NaN。

最终我找到了问题所在。Keras损失函数的调用约定是y_true(我称为tgt),然后是y_pred(我的pred)。但是,对于一个TensorFlow损失函数调用约定预解码,再TGT。因此,如果您希望保留Tensorflow本机版本的损失函数,则此修复程序有效:

def keras_l2_angle_distance(tgt, pred):
    return l2_angle_distance(pred, tgt)

<snip>

model.compile(loss = keras_l2_angle_distance, optimizer = "something")
Run Code Online (Sandbox Code Playgroud)

我不知道,也许Theano或CNTK使用与Keras相同的参数顺序。但是我又回来了。