Вычисление косинусного сходства между двумя тензорами в Керасе

Я следовал учебному пособию, которое показывает, как сделать модель word2vec.

Этот учебник использует этот кусок кода:

similarity = merge([target, context], mode='cos', dot_axes=0) (никакой другой информации предоставлено не было, но я полагаю, что это keras.layers)

Теперь я немного исследовал merge метод, но я не мог найти много об этом. Из того, что я понимаю, было заменено много функций, таких как layers.Add(), layers.Concat()...,

Что я должен использовать? Там в .Dot(), который имеет axis параметр (который кажется правильным), но нет mode параметр.

Что я могу использовать в этом случае?

5 ответов

Решение

Есть несколько вещей, которые неясны из документации 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 создать слой, который мы можем использовать в модели.

Я нашел решение здесь:

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, например: K.mean() - Я думаю, что это необходимо при определении пользовательского слоя или даже функций потерь.

Надеюсь, мне было ясно, это был мой первый ТАК ответ!

Dot слой в Keras теперь поддерживает встроенное сходство косинусов, используя normalize = True параметр.

Из документов Кераса:

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

нормализовать: следует ли L2-нормализовать образцы вдоль оси точечного произведения, прежде чем брать точечное произведение. Если установлено значение "Истина", то выход точечного произведения представляет собой косинусную близость между двумя выборками.

Источник

Может это вам поможет (много времени потратил, чтобы убедиться, что это одни и те же вещи)

      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)

Это должно помочь:

      cos = tf.keras.layers.dot( [ tensor_a, tensor_b ], axes = 1, normalize = True )
cos_similarity = (-1.0) * cos

Кроме того, имейте это в виду:

tf.keras.layers.dot

  • 1, если два вектора имеют угол 0 (минимальное угловое расстояние).
  • 0, если два вектора имеют угол 90 (половина углового расстояния).
  • -1, если два вектора имеют угол 180 (максимальное угловое расстояние).

tf.keras.losses.CosineSimilarity()

  • -1, если два вектора имеют угол 0 (минимальное угловое расстояние).
  • 0, если два вектора имеют угол 90 (половина углового расстояния).
  • 1, если два вектора имеют угол 180 (максимальное угловое расстояние).

Если вы измените последний блок кода учебника следующим образом, вы увидите, что (средняя) потеря хорошо уменьшается с решением Dot, предложенным SantoshGuptaz7 (комментарий в вопросе выше):

      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()
Другие вопросы по тегам