我在keras中有3个张量:
a
:(?,4)
b
:(?,4)
c
:(?, 2, 4)
其中?
是批量大小。我想计算之间的余弦相似度:
a
和b
以及a
以及c
的每一行(本例中为2行)要计算a
和b
之间的差值,可以直接进行以下操作:
from keras.layers import Reshape, merge
cos_a_b = Reshape((1,))(merge([a, b], mode='cos', dot_axes=1))
输出格式为(?,1)
,符合预期。
但是我无法找到a
和c
之间的cos相似性(哪个输出的格式应为(?, 2)
)。使用相同的merge
函数(merge([a, c],mode='cos',dot_axes=1)
)我有错误
ValueError: Only layers of same output shape can be merged using cos mode. Layer shapes: [(None, 4), (None, 2, 4)]
知道如何完成它吗?
修改
关注blackplant的答案:
如果我执行以下操作:
c_rep = RepeatVector(2)(c)
cos_a_c = merge([a,c_rep],mode='cos', dot_axes=1)
我收到以下错误:
Only layers of same output shape can be merged using cos mode. Layer shapes: [(None, Dimension(2), 4), (None, 2, 4)]
但如果我这样做:
cos_a_c = merge([a, RepeatVector(2)(c)],mode='cos', dot_axes=1)
代码正常运行,但输出是形状(?, 1, 4, 4)
的张量。
使用dot_axes=2
输出的形状为(?,1, 2, 2)
。
不应该是(?,2)
吗?
答案 0 :(得分:1)
我不确定这种merge
方法是否有详细记录。我更喜欢使用记录的图层并手动执行相似性。 Formula taken from Wikipedia:
import keras.backend as K
def getDivisor(x):
return K.sqrt(K.sum(K.square(x),axis=-1,keepdims=True))
def similarity(a, b):
dividend = K.sum(a*b,axis=-1,keepdims=True)
return dividend / (getDivisor(a) * getDivisor(b))
现在,我们应该注意使a
和c
的形状兼容。
abSim = Lambda(similarity, output_shape=(1,))([a,b])
aCompatible = Reshape((1,4))(a)
acSim = Lambda(similarity, output_shape=(2,1))([aCompatible,c])
将Reshape((1,4))
应用于a
可能就足以与merge
方法一起使用。但我无法确定。
答案 1 :(得分:0)
您是否尝试过使用RepeatVector?使用它你可以重复“a”张量并将其转换为形状(2,4)的张量,此时你可以将它与c合并。
# Repeat a twice
a_r = RepeatVector(2)(a)
merge([a_r, b], mode='cos', dot_axes=1)
编辑:所以似乎不是重复'a'以便能够将它与'c'合并,而是应该拆分c并将点操作应用于每个切片。
# Select first row
c_0 = Lambda(lambda x: x[0,:], output_shape=(4,))(c)
# Compute cos between first row and a
merge([a, c_0], mode='cos', dot_axes=1)