计算Keras中两个张量之间的余弦相似度

时间:2018-06-23 16:27:01

标签: python keras

我一直在关注一个教程,该教程显示了如何制作word2vec模型。

本教程使用以下代码:

similarity = merge([target, context], mode='cos', dot_axes=0)(未提供其他信息,但我想这来自keras.layers

现在,我已经对merge方法进行了一些研究,但是找不到很多。 据我了解,它已被layers.Add(), layers.Concat()...之类的许多功能所取代。

我应该使用什么?有.Dot(),它有一个axis参数(看起来是正确的),但没有mode参数。

在这种情况下我可以使用什么?

3 个答案:

答案 0 :(得分:12)

Keras文档中有一些尚不清楚的地方,我认为必须理解:

在keras文档中,Merge的每个函数都有一个小写和一个大写的定义,即add()Add()

在Github上,farizrahman4u概述了差异:

Merge is a layer.
Merge takes layers as input
Merge is usually used with Sequential models

merge is a function.
merge takes tensors as input.
merge is a wrapper around Merge.
merge is used in Functional API

Using Merge:

left = Sequential()
left.add(...)
left.add(...)

right = Sequential()
right.add(...)
right.add(...)

model = Sequential()
model.add(Merge([left, right]))
model.add(...)

using merge:

a = Input((10,))
b = Dense(10)(a)
c = Dense(10)(a)
d = merge([b, c])
model = Model(a, d)

要回答您的问题,由于Merge已过时,我们必须为cosine similarity定义并构建一个层。通常,这将涉及使用小写的函数,这些函数将我们包装在Lambda中,以创建可在模型中使用的层。

我找到了解决方法here:

from keras import backend as K

def cosine_distance(vests):
    x, y = vests
    x = K.l2_normalize(x, axis=-1)
    y = K.l2_normalize(y, axis=-1)
    return -K.mean(x * y, axis=-1, keepdims=True)

def cos_dist_output_shape(shapes):
    shape1, shape2 = shapes
    return (shape1[0],1)

distance = Lambda(cosine_distance, output_shape=cos_dist_output_shape)([processed_a, processed_b]

根据您的数据,您可能需要删除L2规范化。需要注意的是该解决方案是使用Keras函数api构建的,例如K.mean()-我认为在定义自定义图层甚至损失函数时这是必要的。

希望我很清楚,这是我的第一个SO答案!

答案 1 :(得分:10)

Keras中的Dot层现在支持使用normalize = True参数的内置余弦相似度。

来自Keras文档:

  

keras.layers.Dot(axes, normalize=True)

     

归一化:在获取点积之前是否沿点积轴对样本进行L2归一化。如果设置为True,则点积的输出是两个样本之间的余弦接近度。

Source

答案 2 :(得分:0)

如果您按如下方式更改本教程的最后一个代码块,您可以看到(平均)损失在使用 SantoshGuptaz7 建议的 Dot 解决方案时很好地降低(在上述问题中的评论):

display_after_epoch = 10000
display_after_epoch_2 = 10 * display_after_epoch

loss_sum = 0

for cnt in range(epochs):
    
idx = np.random.randint(0, len(labels)-1)
arr_1[0,] = word_target[idx]
arr_2[0,] = word_context[idx]
arr_3[0,] = labels[idx]
loss = model.train_on_batch([arr_1, arr_2], arr_3)
loss_sum += loss
    
if cnt % display_after_epoch == 0 and cnt != 0:
    print("\nIteration {}, loss={}".format(cnt, loss_sum / cnt))
    loss_sum = 0
if cnt % display_after_epoch_2 == 0:
    sim_cb.run_sim()