sdgaw erzswer
sdgaw erzswer

Reputation: 2382

Keras optimizing two outputs with a custom loss

I've been recently trying to implement a model, which can be described as following: Given an input matrix and a set of targets, let the model learn, simultaneously, the matrix representation, as well as the targets via a custom loss function.

The architecture (simplified):

input_matrix = Input(shape=(i_shape,))
layer1 = Dense(100)(input_matrix)
output = Dense(3)(layer1)

autoencoder_mid = Dense(100)(input_matrix)
autoencoder_output = Dense(i_shape)(autoencoder_mid)

My idea of a loss function:

def customLoss(true_matrix,pred_matrix):
    def combined_loss(y_true,y_pred):
        return K.abs(y_true-y_pred)
        a = K.mean( K.square(y_pred - y_true) * K.exp(-K.log(1.7) * (K.log(1. + K.exp((y_true - 3)/5 )))),axis=-1  )
        b = K.mean( K.square(pred_matrix - true_matrix) * K.exp(-K.log(1.7) * (K.log(1. + K.exp((true_matrix - 3)/5 )))),axis=-1)
        return a+b
    return combined_loss

I compile the model as:

net = Model(input_matrix, [output,autoencoder_output])
net = net.compile(optimizer='adam', loss=customLoss(true_matrix=X,pred_matrix=autoencoder_output))

Where I try to fit the network with a standard:

 net.fit(X,
         target,
         epochs=10,
         batch_size=10)

The error I get is:

ValueError: Tensor conversion requested dtype float32 for Tensor with dtype float64: 'Tensor("loss/dense_4_loss/Log_3:0", shape=(389, 3890), dtype=float64, device=/device:GPU:0)'

My question is, is there any other way of doing this? If so, could you please point me towards a possible solution. Thank you very much.

Upvotes: 4

Views: 5318

Answers (1)

ebeneditos
ebeneditos

Reputation: 2612

You can try this:

def customLoss(true_matrix):
    def combined_loss(y_true,y_pred):
        y_pred, pred_matrix = y_pred
        ...
    return combined_loss

net = Model(input_matrix, [output,autoencoder_output])
net.compile(optimizer='adam', loss=customLoss(X))

As the original y_pred will be a touple with (output,autoencoder_output).

Concerning the double return, the function will only return the first one, so I'd remove one of the two return lines or combine the two outputs such as:

alpha = 0.5
beta = 0.5
...
loss1, loss2 = K.abs(y_true-y_pred), a+b

return alpha*loss1 + beta*loss2 

Changing alpha and beta upon convenience.

Thus, the whole thing could be:

def customLoss(true_matrix, alpha = 0.5, beta = 0.5):
    def combined_loss(y_true,y_pred):
        y_pred, pred_matrix = y_pred
        a = K.mean( K.square(y_pred - y_true) * K.exp(-K.log(1.7) * (K.log(1. + K.exp((y_true - 3)/5 )))),axis=-1  )
        b = K.mean( K.square(pred_matrix - true_matrix) * K.exp(-K.log(1.7) * (K.log(1. + K.exp((true_matrix - 3)/5 )))),axis=-1)
        loss1, loss2 = K.abs(y_true-y_pred), a+b
        return alpha*loss1 + beta*loss2 
    return combined_loss

net = Model(input_matrix, [output,autoencoder_output])
net.compile(optimizer='adam', loss=customLoss(X))

Upvotes: 4

Related Questions