是否可以使用Keras建立倒角距离的自定义损失函数

是否可以使用Keras建立倒角距离的自定义损失函数,keras,Keras,在我关于点云的作业中,我需要使用keras自定义的倒角距离损失函数,并将其应用到自动编码器中。但我发现该函数很难实现 我试着用这种方式写作。我希望有人能帮助我 def chamfer_loss_func(y_true,y_pred): ''' Calculate the chamfer distance,use euclidean metric :param y_true: :param y_pred: :return: ''' batch

在我关于点云的作业中,我需要使用keras自定义的倒角距离损失函数,并将其应用到自动编码器中。但我发现该函数很难实现

我试着用这种方式写作。我希望有人能帮助我

def chamfer_loss_func(y_true,y_pred):
    '''
    Calculate the chamfer distance,use euclidean metric
    :param y_true:
    :param y_pred:
    :return:
    '''
    batch_size = 32
    y_true = K.reshape(y_true,[batch_size,2048,3])
    y_pred = K.reshape(y_pred, [batch_size, 2048, 3])
    num_t = K.int_shape(y_true)[1]
    num_p = K.int_shape(y_pred)[1]
    dists_mat = K.zeros(shape=[num_t, num_p])
    sum = 0.0
    for bi in range(batch_size):
        for i in range(num_t):
            pnt_t = y_true[bi][i]
            for j in range(num_p):
                if (i <= j):
                    pnt_p = y_pred[bi][j]
                    dists_mat[i][j] = K.eval(K.sum(K.sqrt(tf.subtract(pnt_t, pnt_p))))
                else:
                    dists_mat[i][j] = dists_mat[j][i]
        dist_t_to_p = K.mean(K.min(dists_mat, axis=0))
        dist_p_to_t = K.mean(K.min(dists_mat, axis=1))
        sum += K.max([dist_p_to_t, dist_t_to_p])
    return sum / batch_size
以及使用损失函数的位置:

model = get_model(2048)
model.compile(optimizer='adam',loss=chamfer_loss_func,)

你能给我你参考的倒角距离的链接吗?
K.sum(K.sqrt(tf.subtract(pnt\t,pnt\u p))
对我来说很奇怪。要计算欧氏距离,应将
sqrt
替换为
square

不建议在tensorflow中使用for loop,因此我重新实现了它:

import numpy as np
import keras.backend as K
import tensorflow as tf
from keras.layers import Input, Dense, MaxPooling1D, Reshape, concatenate
from keras.models import Model

def dists_mat_calculater(pnts_t, pnts_p):
    """
    arguments:
        pnts_t : from y_true[bi], shape: (num_t, 3)
        pnts_p : from y_pred[bi], shape: (num_p, 3)

    return:
        dists_mat: shape: (num_t, num_p)
    """
    num_t = K.int_shape(pnts_t)[0]
    num_p = K.int_shape(pnts_p)[0]

    pnts_t = tf.reshape(tf.tile(tf.expand_dims(pnts_t, 1), [1, 1, num_p]), [-1, 3])
    pnts_p = tf.tile(pnts_p, [num_t, 1])

    dists_mat = K.sum(K.square(tf.subtract(pnts_t, pnts_p)), axis=1)
    dists_mat = tf.reshape(dists_mat, [num_t, num_p])
    dists_mat_upper = tf.matrix_band_part(dists_mat, 0, -1)
    dists_mat_symm = dists_mat_upper + tf.transpose(dists_mat_upper)
    dists_mat_symm = tf.matrix_set_diag(dists_mat_symm, tf.diag_part(dists_mat))  

    return dists_mat_symm

def dist_calculator(pnts):
    """
    arguments:
        pnts_t : from y_true[bi], shape: (num_t, 3)
        pnts_p : from y_pred[bi], shape: (num_p, 3)

    return:
        dist: shape: (1, )
    """
    pnts_t, pnts_p = pnts
    dists_mat = dists_mat_calculater(pnts_t, pnts_p)
    dist_t_to_p = K.mean(K.min(dists_mat, axis=0)) #shape: (1,)
    dist_p_to_t = K.mean(K.min(dists_mat, axis=1)) #shape: (1,)
    dist = K.max([dist_p_to_t, dist_t_to_p]) #shape: (1,)
    return dist

def chamfer_loss_func_tf(y_true,y_pred):
    '''
    Calculate the chamfer distance,use euclidean metric
    :param y_true:
    :param y_pred:
    :return:
    '''
    y_true = K.reshape(y_true,[-1, num_pnts, 3])
    y_pred = K.reshape(y_pred, [-1, num_pnts, 3])
    return K.mean(tf.map_fn(dist_calculator, elems=(y_true, y_pred), dtype=tf.float32))
dists\u mat\u calculator
计算距离矩阵,两两计算的部分受到启发

出于验证目的,我还实现了纯python版本:

def chamfer_loss_python(y_true,y_pred):
    '''
    Calculate the chamfer distance,use euclidean metric
    :param y_true:
    :param y_pred:
    :return:
    '''
    y_true = np.reshape(y_true,[-1,num_pnts,3])
    y_pred = np.reshape(y_pred, [-1,num_pnts, 3])
    batch_size = y_true.shape[0]
    num_t = y_true.shape[1]
    num_p = y_pred.shape[1]
    dists_mat = np.zeros((num_t, num_p))
    _sum = 0.0
    loss_before_mean_py = []
    for bi in range(batch_size):
        for i in range(num_t):
            pnt_t = y_true[bi][i]
            for j in range(num_p):
                pnt_p = y_pred[bi][j]
                if (i <= j):
                    pnt_p = y_pred[bi][j]
                    dists_mat[i][j] = np.sum((pnt_t - pnt_p)**2)
                else:
                    dists_mat[i][j] = dists_mat[j][i]

        dist_t_to_p = np.mean(np.min(dists_mat, axis=0))
        dist_p_to_t = np.mean(np.min(dists_mat, axis=1))
        _sum += np.max([dist_p_to_t, dist_t_to_p])
        loss_before_mean_py.append(np.max([dist_p_to_t, dist_t_to_p]))
    return _sum / batch_size

您收到任何错误消息了吗?是的。在这里。tensorflow.python.framework.errors\u impl.invalidargumeinterror:您必须为占位符张量'Reformate_1_target'提供一个值,该值包含dtype float和shape[?,?,?][[Node:Reformate_1_target=placeholder[dtype=DT_float,shape=[?,?,,?,?],[u device=“/job:localhost/replica:0/task:0/device:CPU:0]()]更奇怪的是,方法K.update\u sub不能代替方法tf.subtract。你能粘贴你调用的代码并运行这个函数吗?当然,已经添加了。哦,和以前一样的错误。您必须为占位符张量'Reformate_1_target'提供一个值,该值带有dtype float和shape[?,?,?][[Node:Reformate_1_target=placeholder[dtype=DT_float,shape=[?,?],shape=“/job:localhost/replica:0/task:0/device:CPU:0”()]”Hi bro,假设有两个点集S和S具有相同的点编号,例如2048,则其倒角距离=和(最小欧几里德距离(s,s'))。其中s是集合s中的点,s'是集合s中的点。最小欧几里得距离是指最小的距离。这就是为什么我需要在我的方法中建立一个距离矩阵。感谢您的关注。如果此解决方案对您有效,请接受。:)
def chamfer_loss_python(y_true,y_pred):
    '''
    Calculate the chamfer distance,use euclidean metric
    :param y_true:
    :param y_pred:
    :return:
    '''
    y_true = np.reshape(y_true,[-1,num_pnts,3])
    y_pred = np.reshape(y_pred, [-1,num_pnts, 3])
    batch_size = y_true.shape[0]
    num_t = y_true.shape[1]
    num_p = y_pred.shape[1]
    dists_mat = np.zeros((num_t, num_p))
    _sum = 0.0
    loss_before_mean_py = []
    for bi in range(batch_size):
        for i in range(num_t):
            pnt_t = y_true[bi][i]
            for j in range(num_p):
                pnt_p = y_pred[bi][j]
                if (i <= j):
                    pnt_p = y_pred[bi][j]
                    dists_mat[i][j] = np.sum((pnt_t - pnt_p)**2)
                else:
                    dists_mat[i][j] = dists_mat[j][i]

        dist_t_to_p = np.mean(np.min(dists_mat, axis=0))
        dist_p_to_t = np.mean(np.min(dists_mat, axis=1))
        _sum += np.max([dist_p_to_t, dist_t_to_p])
        loss_before_mean_py.append(np.max([dist_p_to_t, dist_t_to_p]))
    return _sum / batch_size
num_pnts = 8
np.random.seed(1)
Y_true = np.random.randn(32, num_pnts, 3).astype(np.float32)
Y_pred = np.random.randn(32, num_pnts, 3).astype(np.float32)

Y_true_ph = tf.placeholder(tf.float32, shape=(None, num_pnts, 3), name="Y_true_ph")
Y_pred_ph = tf.placeholder(tf.float32, shape=(None, num_pnts, 3), name="Y_pred_ph")

loss = chamfer_loss_func_tf(Y_true_ph, Y_pred_ph)

with tf.Session() as sess:
    sess.run(tf.global_variables_initializer())
    loss = sess.run(loss, feed_dict={
            Y_true_ph: Y_true,
            Y_pred_ph: Y_pred})

loss_py = chamfer_loss_python(Y_true,Y_pred)
print(loss)
print(loss_py)