Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Implementing Triplet Loss inside Keras Layers

In this blog post, he implements the triple loss outside the Kears layers. He gets the anchor_out, pos_out and neg_out from the network and then passes them to the triplet_loss() function he defined.

I wonder if I can calculate the triplet_loss within the Keras layers by defining my own Lambda layers.

Here's my network design:

margin=1

anchor_input = Input((600, ), name='anchor')
positive_input = Input((600, ), name='positive_input')
negative_input = Input((600, ), name='negative_input')

# Shared embedding layer for positive and negative items
Shared_DNN = Dense(300)

encoded_anchor = Shared_DNN(anchor_input)
encoded_positive = Shared_DNN(positive_input)
encoded_negative = Shared_DNN(negative_input)

DAP = Lambda(lambda tensors:K.sum(K.square(tensors[0] - tensors[1]),axis=1,keepdims=True),name='DAP_loss') #Distance for Anchor-Positive pair
DAN = Lambda(lambda tensors:K.sum(K.square(tensors[0] - tensors[1]),axis=1,keepdims=True),name='DAN_loss') #Distance for Anchor-Negative pair
Triplet_loss = Lambda(lambda loss:K.max([(loss[0] - loss[1] + margin),0],axis=0),name='Triplet_loss') #Distance for Anchor-Negative pair

DAP_loss = DAP([encoded_anchor,encoded_positive])
DAN_loss = DAN([encoded_anchor,encoded_negative])

#call this layer on list of two input tensors.

Final_loss = Triplet_loss([DAP_loss,DAN_loss])

model = Model(inputs=[anchor_input,positive_input, negative_input], outputs=Final_loss)

However, it gives me the error:

Tried to convert 'input' to a tensor and failed. Error: Shapes must be equal rank, but are 2 and 0
    From merging shape 0 with other shapes. for 'Triplet_loss_4/Max/packed' (op: 'Pack') with input shapes: [?,1], []

The error is from the Triplet_loss layer. In the K.max() function, the first number loss[0] - loss[1] + margin has the shape (None,1). Yet the second number 0 has the shape (1). The two number are not of the same shape and therefore the K.max() function gives out an error.

My problem is, how to solve this error? I have tried replacing the 0 with K.constant(0,shape=(1,)) and K.constant(0,shape=(None,1)), but they doesn't work.

like image 926
Raven Cheuk Avatar asked Mar 06 '23 10:03

Raven Cheuk


1 Answers

Does this work?

Triplet_loss = Lambda(lambda loss: K.maximum(loss[0] - loss[1] + margin, 0.0),
                      name='Triplet_loss')

I think the issue with this line

Triplet_loss = Lambda(lambda loss:K.max([(loss[0] - loss[1] + margin), 0], 
                      axis=0),name='Triplet_loss') 

is that you are putting loss[0]-loss[1]+margin tensor and 0 in the list bracket, which keras interprets as concatenating two tensors. This fails due to the size mismatch; 0 is a scalar and has rank 0, while the first one is 2d array. This is what the error means.

To compare a tensor against a single value element-wise, use K.maximum, which broadcasts automatically when one of the arguments is a scalar.

like image 88
Kota Mori Avatar answered Mar 16 '23 17:03

Kota Mori