【问题标题】:Computing cosine similarity between two tensors in Keras在 Keras 中计算两个张量之间的余弦相似度
【发布时间】:2018-12-02 19:44:06
【问题描述】:

我一直在学习如何制作word2vec 模型的教程。

本教程使用这段代码:

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

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

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

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

【问题讨论】:

  • 您是否接受过教程中的培训才能工作?我尝试了similarity = dot([target, context], axes=0, normalize=True)dot_product = dot([target, context], axes=1),但训练损失并没有减少,所以我认为必须有人离开,因为这两行代码是与原始教程的唯一区别。

标签: python keras


【解决方案1】:

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

来自 Keras 文档:

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

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

Source

【讨论】:

    【解决方案2】:

    我认为 Keras 文档中有一些不清楚的地方对于理解至关重要:

    对于Merge 的 keras 文档中的每个函数,定义了一个小写字母和一个大写字母,即 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 答案!

    【讨论】:

    • 谢谢!我会为您需要的任何未来访问者添加from keras import backend as K
    【解决方案3】:

    如果您按如下方式更改本教程的最后一个代码块,您可以看到(平均)损失在 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()
    

    【讨论】:

      【解决方案4】:

      也许这会对你有所帮助 (我花了很多时间来确保这些是相同的东西)

      import tensorflow as tf
      with tf.device('/CPU:' + str(0)):
          print(tf.losses.CosineSimilarity()([1.0,1.0,1.0,-1.0],[4.0,4.0,4.0,5.0]))
          print(tf.keras.layers.dot([tf.Variable([[1.0,1.0,1.0,-1.0]]),tf.Variable([[4.0,4.0,4.0,5.0]])], axes=1, normalize=True))
      

      输出(注意符号):

      tf.Tensor(-0.40964404, shape=(), dtype=float32)
      tf.Tensor([[0.40964404]], shape=(1, 1), dtype=float32)
      

      【讨论】:

        猜你喜欢
        • 2017-09-07
        • 2021-07-19
        • 2015-07-21
        • 2019-12-27
        • 2022-06-14
        • 2014-04-21
        • 2016-03-06
        • 2017-03-19
        • 2019-12-02
        相关资源
        最近更新 更多