如何在喀拉拉邦产生一个可变大小的距离矩阵? [英] How to produce a variable size distance matrix in keras?

查看:76
本文介绍了如何在喀拉拉邦产生一个可变大小的距离矩阵?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我现在想要实现的是在Keras中创建一个自定义损失函数,该函数具有两个分别具有形状(None, None, None)(None, None, 3)的张量(y_true, y_pred).但是,None是如此,因此每个(y_true, y_pred)的两个形状始终相等.我想从这些张量中生成两个距离矩阵,其中包含它们内部每个可能的点对之间的平方距离(第三个,长度3维包含x,y和z空间值),然后返回这些距离矩阵之间的差.我尝试的第一个代码是:

What I am trying to achieve now is to create a custom loss function in Keras that takes in two tensors (y_true, y_pred) with shapes (None, None, None) and (None, None, 3), respectively. However, the None's are so, that the two shapes are always equal for every (y_true, y_pred). From these tensors I want to produce two distance matrices that contain the squared distances between every possible point pair (the third, length 3 dimension contains x, y, and z spatial values) inside them and then return the difference between these distance matrices. The first code I tried was this:

def distanceMatrixLoss1(y_true, y_pred):
    distMatrix1 = [[K.sum(K.square(y_true[i] - y_true[j])) for j in range(i + 1, y_true.shape[1])] for j in range(y_true.shape[1])]
    distMatrix2 = [[K.sum(K.square(y_pred[i] - y_pred[j])) for j in range(i + 1, y_pred.shape[1])] for j in range(y_pred.shape[1])]
    return K.mean(K.square(K.flatten(distMatrix1) - K.flatten(distMatrix2)))

(K是TensorFlow后端.)不用说,我遇到了以下错误:

(K is the TensorFlow backend.) Needless to say, I got the following error:

'NoneType' object cannot be interpreted as an integer

这是可以理解的,因为range(None)没有多大意义,并且y_true.shape[0]y_pred.shape[0]None.我搜索了其他人是否也遇到了相同的问题,发现可以使用TensorFlow的scan功能:

This is understandable, since range(None) does not make a lot of sense and y_true.shape[0] or y_pred.shape[0] is None. I searched whether others got somehow the same problem or not and I found that I could use the scan function of TensorFlow:

def distanceMatrixLoss2(y_true, y_pred):

    subtractYfromXi = lambda x, y: tf.scan(lambda xi: K.sum(K.square(xi - y)), x)
    distMatrix = lambda x, y: K.flatten(tf.scan(lambda yi: subtractYfromXi(x, yi), y))

    distMatrix1 = distMatrix(y_true, y_true)
    distMatrix2 = distMatrix(y_pred, y_pred)

    return K.mean(K.square(distMatrix1-distMatrix2))

我从中得到的是另一个错误,我不完全理解.

What I got from this is a different error, that I do not fully understand.

TypeError: <lambda>() takes 1 positional argument but 2 were given

所以这也丢进了垃圾箱.我最后的尝试是使用后端的map_fn函数:

So this went into the trash too. My last try was using the backend's map_fn function:

def distanceMatrixLoss3(y_true, y_pred):

    subtractYfromXi = lambda x, y: K.map_fn(lambda xi: K.sum(K.square(xi - y)), x)
    distMatrix = lambda x, y: K.flatten(K.map_fn(lambda yi: subtractYfromXi(x, yi), y))

    distMatrix1 = distMatrix(y_true, y_true)
    distMatrix2 = distMatrix(y_pred, y_pred)

    return K.mean(K.square(distMatrix1-distMatrix2))

这没有引发错误,但是训练开始时,损失为常数0,并一直保持这种状态.所以现在我没主意了,请您帮助我解决这个问题.我已经尝试在Mathematica中执行相同操作,但也失败了(此处是指向相应问题的链接(如果有帮助).

This did not throw an error, but when the training started the loss was constant 0 and stayed that way. So now I am out of ideas and I kindly ask you to help me untangle this problem. I have already tried to do the same in Mathematica and also failed (here is the link to the corresponding question, if it helps).

推荐答案

假定维度0与往常一样是批次大小,并且您不想混合样品.
假设维度1是您要配对的维度
尽管模型返回None,但假定所有情况下的最后一个维度均为3.

Assuming that dimension 0 is the batch size as usual and you don't want to mix samples.
Assuming that dimension 1 is the one you want to make pairs
Assuming that the last dimension is 3 for all cases although your model returns None.

张量迭代是个坏主意.尽管具有重复的值,但最好是从原始1D生成2D矩阵.

Iterating tensors is a bad idea. It might be better just to make a 2D matrix from the original 1D, though having repeated values.

def distanceMatrix(true, pred): #shapes (None1, None2, 3)

    #------ creating the distance matrices 1D to 2D -- all vs all

    true1 = K.expand_dims(true, axis=1) #shapes (None1, 1, None2, 3)
    pred1 = K.expand_dims(pred, axis=1)

    true2 = K.expand_dims(true, axis=2) #shapes (None1, None2, 1, 3)
    pred2 = K.expand_dims(pred, axis=2) 

    trueMatrix = true1 - true2 #shapes (None1, None2, None2, 3)
    predMatrix = pred1 - pred2

    #--------- euclidean x, y, z distance

       #maybe needs a sqrt?
    trueMatrix = K.sum(K.square(trueMatrix), axis=-1) #shapes (None1, None2, None2)
    predMatrix = K.sum(K.square(predMatrix), axis=-1)


    #-------- loss for each pair

    loss = K.square(trueMatrix - predMatrix)  #shape (None1, None2, None2)

    #----------compensate the duplicated non-diagonals

    diagonal = K.eye(K.shape(true)[1])  #shape (None2, None2)
        #if Keras complains because the input is a tensor, use `tf.eye`

    diagonal = K.expand_dims(diagonal, axis=0) #shape (1, None2, None2)
    diagonal = 0.5 + (diagonal / 2.)

    loss = loss * diagonal

    #--------------

    return K.mean(loss, axis =[1,2])  #or just K.mean(loss) 

这篇关于如何在喀拉拉邦产生一个可变大小的距离矩阵?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆