Search code examples
pythonloss-functiontf.keras

Customized keras loss function using min_g(g, g*)


I am dealing with a regression problem where given an image, I want to predict the value of 3 parameters (cartesian coordinates) . For the same image I can have several acceptable coordinates. To do this, I use a neural network using keras. To train my network, I want to implement a custom loss function that will calculate the euclidian distance between the prediction and the closest acceptable value. In mathematical term it can be expressed like that :

my_stuff

The shape of ypred is size and the shape of my target size is ysize.

To calculate this loss, I first reshape ypred to have the correct shape. Then I perform the loss calculation (using tensorflow 1.13):

import tensorflow as tf
import tensorflow.keras.backend as K
config = tf.ConfigProto()
config.gpu_options.allow_growth = True

K.set_session(tf.Session(config=config))

from tensorflow.python.keras.applications import ResNet50
from tensorflow.python.keras.models import Sequential
from tensorflow.python.keras.layers import Dense, Dropout

import numpy as np


def min_mse(y_pred, y_true):
    y_pred_temp = K.repeat(y_pred, K.shape(y_true)[1])
    return K.min(K.sum(K.sqrt(y_pred_temp-y_true), axis=-1), axis=-1)


def resnet_model():
    model = Sequential()
    model.add(ResNet50(include_top=False, pooling='avg', weights='imagenet'))
    model.add(Dense(1024, activation='relu'))
    model.add(Dropout(rate=0.2))
    model.add(Dense(512, activation='relu'))
    model.add(Dropout(rate=0.2))
    model.add(Dense(3, activation='linear'))
    model.layers[0].trainable = False
    model.compile(optimizer=tf.keras.optimizers.Adam(lr=0.001), loss=min_mse)
    return model

X = np.random.random((200, 224, 224, 3))
Y = np.random.random((200, 10, 3))

model = resnet_model()
model.fit(X, Y)

However, this code outputs an error

tensorflow.python.framework.errors_impl.InvalidArgumentError: Expected multiples argument to be a vector of length 4 but got length 3 [[{{node loss/dense_2_loss/Tile}}]]

I have some trouble solving it as I can not easily print the shape of my different tensors to understand the problem. Do you have any clue of how to solve this problem (by fixing my code or using another method) ? Thanks in advance.


Solution

  • From Kera's documentation you can see that when you define a custom metric, labels come as the first argument and prediction as the second argument of the custom loss.

    Just swap y_true and y_pred and your code should run :

    def min_mse(y_true, y_pred):
        y_pred_temp = K.repeat(y_pred, K.shape(y_true)[1])
        return K.min(K.sum(K.sqrt(y_pred_temp-y_true), axis=-1), axis=-1)