Resolved: "No loss to compute" for model with preprocessing

Hello,
I try to make a model with preprocessing for a categorical classification problem (for classes, using hot_one encoding of target).

I get a “ValueError: No loss to compute. Provide a loss argument in compile()” that I cannot understand nor resolve. Here is a gist with a minimal version of it https://gist.github.com/Bruno-891/6d0c2b38fb671a93538ec02a26d85ff5 .

Please help. Thank you.

Bruno

Here is the code (in case gist is not working;)

import numpy as np # linear algebra import pandas as pd # data processing, CSV file I/O (e.g. pd.read_csv) from pprint import pprint  import tensorflow as tf  BATCH_SIZE = 5  # Define the data data = {     'StringFeature': ['apple', 'banana', 'cherry', 'orange', 'mango'],     'target': [0, 1, 2, 3, 0], }  # Create the DataFrame train_df = pd.DataFrame(data)  train_target_df = train_df.pop('target') train_target_df = pd.get_dummies(train_target_df, columns=['target']) train_target_df = {key: value.to_numpy()[:,tf.newaxis] for key, value in train_target_df.items()}  train_ds =  tf.data.Dataset.from_tensor_slices((dict(train_df), train_target_df)).batch(BATCH_SIZE)   def get_category_encoding_layer(name, dataset):     # Create a layer that turns strings into integer indices.     index = tf.keras.layers.StringLookup()          # Prepare a `tf.data.Dataset` that only yields the feature.     feature_ds = dataset.map(lambda x, y: x[name])              # Learn the set of possible values and assign them a fixed integer index.     index.adapt(feature_ds)          # Encode the integer indices.     encoder = tf.keras.layers.CategoryEncoding(num_tokens=index.vocabulary_size(), output_mode='one_hot')          # Apply multi-hot encoding to the indices. The lambda function captures the     # layer, so you can use them, or include them in the Keras Functional model later.     return lambda feature: encoder(index(feature))  ##### train_all_inputs = {} train_preprocessed_features = []  ##### Categorical features str. categorical_col = tf.keras.Input(shape=(1,), name='StringFeature', dtype='string') encoding_layer = get_category_encoding_layer(name='StringFeature', dataset=train_ds)  encoded_categorical_col = encoding_layer(categorical_col) train_all_inputs['StringFeature'] = categorical_col train_preprocessed_features.append(encoded_categorical_col)  #### train_all_features = tf.keras.layers.concatenate(train_preprocessed_features)   #### output = tf.keras.layers.Dense(4)(train_all_features) model = tf.keras.Model(train_all_inputs, output)  model.compile(optimizer='adam', loss=tf.keras.losses.SparseCategoricalCrossentropy(), metrics=['accuracy']) #model.compile(optimizer='adam', loss='categorical_crossentropy', metrics=['accuracy'])   tf.keras.utils.plot_model(model, show_shapes=True, show_layer_names=True, rankdir="LR") history = model.fit(train_ds, epochs=2)#, validation_data=(validation_features, validation_target))  

Bruno

Hi @Bruno, while creating labels I can see you are creating a dictionary structure it is recommended to use array format. with that change I have executed the code in colab I did not face any error. Thank You.

1 Like

Hello,

Thank you. :tada:

Your answer made me find the solution I needed.

  1. Side note: one of the loss I used was “sparse*”, which was not the one to use here, I know use 'categorical_crossentropy'. But that was not the main issue there.

  2. The main issue was indeed the target size/dimensions. I had missed the point where I should have used an array (thanks again on that count, I lost some many hours on this one…). As I wanted the one_hot on the target (hopefully that is not a mistake), I had to change the dimension of the target so I used np.reshape. The full code below (still not familiar enough with gist).

I had to add a dimension, I believe it is due to the one_hot output_mode but not sure yet (probably won’t check if I don’t run into the problem again)

Bruno

import numpy as np # linear algebra import pandas as pd # data processing, CSV file I/O (e.g. pd.read_csv) from pprint import pprint  import tensorflow as tf  BATCH_SIZE = 5  # Define the data data = {     'StringFeature': ['apple', 'banana', 'cherry', 'orange', 'mango'],     'target': [0, 1, 2, 3, 0], }  # Create the DataFrame train_df = pd.DataFrame(data)  train_target_df = train_df.pop('target') train_target_numpy = pd.get_dummies(train_target_df, columns=['target']).to_numpy() #Solution here arr = train_target_numpy.reshape(5, 1, 4) #Solution and here #train_target_df = {key: value.to_numpy()[:,tf.newaxis] for key, value in train_target_df.items()}  train_ds =  tf.data.Dataset.from_tensor_slices((dict(train_df), arr)).batch(BATCH_SIZE)   def get_category_encoding_layer(name, dataset):     # Create a layer that turns strings into integer indices.     index = tf.keras.layers.StringLookup()          # Prepare a `tf.data.Dataset` that only yields the feature.     feature_ds = dataset.map(lambda x, y: x[name])              # Learn the set of possible values and assign them a fixed integer index.     index.adapt(feature_ds)          # Encode the integer indices.     encoder = tf.keras.layers.CategoryEncoding(num_tokens=index.vocabulary_size(), output_mode='one_hot')          # Apply multi-hot encoding to the indices. The lambda function captures the     # layer, so you can use them, or include them in the Keras Functional model later.     return lambda feature: encoder(index(feature))  ##### train_all_inputs = {} train_preprocessed_features = []  ##### Categorical features str. categorical_col = tf.keras.Input(shape=(1,), name='StringFeature', dtype='string') encoding_layer = get_category_encoding_layer(name='StringFeature', dataset=train_ds)  encoded_categorical_col = encoding_layer(categorical_col) train_all_inputs['StringFeature'] = categorical_col train_preprocessed_features.append(encoded_categorical_col)  #### train_all_features = tf.keras.layers.concatenate(train_preprocessed_features)   #### output = tf.keras.layers.Dense(4)(train_all_features) model = tf.keras.Model(train_all_inputs, output)  #model.compile(optimizer='adam', loss=tf.keras.losses.CategoricalCrossentropy(), metrics=['accuracy']) model.compile(optimizer='adam', loss='categorical_crossentropy', metrics=['accuracy'])   tf.keras.utils.plot_model(model, show_shapes=True, show_layer_names=True, rankdir="LR") history = model.fit(train_ds, epochs=2)#, validation_data=(validation_features, validation_target))