Mpizos Dimitris
Mpizos Dimitris

Reputation: 4991

Using merge in Keras

I am having 3 tensors in keras:

where ? is the batch size. And I want to compute the cosinus similarity/ies between:

To compute the cos between a and b the following can be done which is straight forward:

from keras.layers import Reshape, merge
cos_a_b = Reshape((1,))(merge([a, b], mode='cos', dot_axes=1))

The output is of format (?,1) as expected.

But I am unable to find the cos similarities between a and c (which output should be of the format (?, 2)). Using the same merge function (merge([a, c],mode='cos',dot_axes=1)) I have the error

ValueError: Only layers of same output shape can be merged using cos mode. Layer shapes: [(None, 4), (None, 2, 4)]

Any idea how to accomplish it?

Edit

Following blackplant's answer:

IF I do the following:

c_rep = RepeatVector(2)(c)
cos_a_c = merge([a,c_rep],mode='cos', dot_axes=1)

I got the following error:

Only layers of same output shape can be merged using cos mode. Layer shapes: [(None, Dimension(2), 4), (None, 2, 4)]

But if I do the following:

cos_a_c = merge([a, RepeatVector(2)(c)],mode='cos', dot_axes=1)

the code runs normally but the output is a tensor of shape (?, 1, 4, 4).

With dot_axes=2 the output is of shape (?,1, 2, 2).

Shouldn't it be (?,2)?

Upvotes: 0

Views: 497

Answers (2)

Daniel Möller
Daniel Möller

Reputation: 86600

I'm not sure this merge approach is well documented. I prefer using documented layers and perform the similarity manually. 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))

Now, we should just take some care to make the shapes of a and c compatible.

abSim = Lambda(similarity, output_shape=(1,))([a,b])

aCompatible = Reshape((1,4))(a)
acSim = Lambda(similarity, output_shape=(2,1))([aCompatible,c])

Maybe just applying the Reshape((1,4)) to a could be enough for using with your merge method. But I can't be sure.

Upvotes: 1

lmartens
lmartens

Reputation: 1502

Have you tried using RepeatVector? Using this you can repeat the "a " tensor and turn it into a tensor with shape (2,4), at which point you can merge it with c.

# Repeat a twice
a_r = RepeatVector(2)(a)
merge([a_r, b], mode='cos', dot_axes=1) 

EDIT: So it seems that instead of repeating 'a' in order to be able to merge it with 'c' you should instead split up c and apply the dot operation to each slice.

# 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) 

Upvotes: 0

Related Questions