如何在喀拉拉邦产生一个可变大小的距离矩阵? [英] How to produce a variable size distance matrix in keras?
问题描述
我现在想要实现的是在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屋!