Problem Description
I am trying to train a network with Keras based on TensorFlow 2.3.0. The task is to create new pictures. In a first simple prototype / proof of concept I am trying to train the network to create pictures just with a given amount of non-black pixel. Therefore I need to define a custom loss function. Doing so I get the ValueError: No gradients provided for any variable
which I have not yet been able to solve.
On top I would prefer a way to code this loss function without having to run eagerly (see my previous question).
Code snippet
def custom_loss(y_true, y_pred):
ndarray = y_pred.numpy()
mse = np.zeros(ndarray.shape[0])
for i in range(ndarray.shape[0]):
true_area = int(y_true[i][0] * 100000).numpy()
pic = ndarray[i, :, :, :]
img_np = (pic * 255).astype(np.uint8)
img = tf.keras.preprocessing.image.array_to_img(img_np)
count_area = count_nonblack_pil(img)
mse[i] = ((count_area - true_area) / 100000)**2
#img.save(f"custom_loss {i:03d} True {true_area:06d} Count {count_area:06d} MSE {mse:0.4f}.jpg")
return mse
if __name__ == '__main__':
tf.config.run_functions_eagerly(True)
...
model.compile(loss=custom_loss, optimizer="adam", run_eagerly=True)
model.fit(x=train_data, y=train_data, batch_size=16, epochs=10)
Running this code gives me the error message:
ValueError: No gradients provided for any variable: ['dense/kernel:0', 'dense/bias:0', 'conv2d/kernel:0', 'conv2d/bias:0', 'conv2d_1/kernel:0', 'conv2d_1/bias:0', 'conv2d_2/kernel:0', 'conv2d_2/bias:0', 'conv2d_3/kernel:0', 'conv2d_3/bias:0'].
What I have tried so far
The error sounds like the loss function is not differentiable, but why shouldn't it be?
Googling for a solution I found the suggestion, that I might have missed to pass the labels, same here, but I already checked this by saving some pics with labels (see line commented out in the code above). This works just fine!
Other than that I was not able to find any useful hint, all in all not too many google hits anyway ... (seems to be exotic what I am trying to do?). Any thoughts?
Edit
Thank you for your quick feedback and sorry for not describing the task of the loss function very clearly, let me give it another try:
I have a model that creates a full 533x800 RGB picture based on a single float input, which is passed on to the loss function as y_true
. The picture created by the model is also passed on to the loss function as y_pred
. The loss function now calls a small function count_nonblack_pil
to count the number of non-black pixels in y_pred
. The loss is then calculated as the squared difference between y_true
and the counted pixels. By minimizing this difference I expect to train the model so that is able to create a picture with a number of non-black pixels close to the input value. Not really useful, but a simple proof of concept of what I plan to do later with different loss function (where I want to use other already trained models to calculate the loss for more useful and sophisticated tasks).
Hope that makes sense. To make it more clear:
y_true size : 16
y_pred size : 20467200
y_pred
contains 16 pictures of 533x800 with 3 colors, i.e. 20467200.
y_true
contains just the 16 target values of pixels.
Edit: Solution
I have now understood the problem, nicely summarized by JimBiardCics: "Keep in mind that the python function you write (custom_loss) is called to generate and compile a C function. The compiled function is what is called during training. When your python custom_loss function is called, the arguments are tensor objects that don't have data attached to them. The K.eval call will fail, as will the K.shape call."