2

So I have multi-class classification. I want to compile my model:

feature_layer = DenseFeatures(feature_columns) # A layer that produces a dense Tensor
model = Sequential([

feature_layer,
  Dense(32, activation='relu'),
  Dense(3, activation='softmax')
])

So I use categorical_crossentropy loss:

model.compile(optimizer='adam',
              loss='categorical_crossentropy',
              metrics=['accuracy'])

model.fit(train_ds,
          validation_data=val_ds,
          epochs=10)

But, of course, it gives me an error. I know about to_categorical method, but it doesn't take BatchDataset as a parameter, which train_ds and val_ds are.

Please direct me

UPDATE: I tried to do something like this:

def df_to_dataset(df, shuffle=True, batch_size=32): 
  df = df.copy()
  labels = df.pop('class')
  ds = tf.data.Dataset.from_tensor_slices((dict(df), labels))
  if shuffle:
    ds = ds.shuffle(buffer_size=len(df))
    ds = ds.batch(batch_size).map(lambda x, y: (x, tf.one_hot(y, depth=3)))
  return ds

batch_size = 32
train_ds = df_to_dataset(train, batch_size=batch_size)  # error
val_ds = df_to_dataset(val, shuffle=False, batch_size=batch_size)
test_ds = df_to_dataset(test, shuffle=False, batch_size=batch_size)

And it gives me:

Value passed to parameter 'indices' has DataType string not in list of allowed values: uint8, int32, int64

My class column has string values (it tells if the object is star, galaxy or quazar, others are int/float), but I popped it:

def df_to_dataset(df, shuffle=True, batch_size=32): 
  df = df.copy()
  labels = df.pop('class')
  ds = tf.data.Dataset.from_tensor_slices((dict(df), labels))
  if shuffle:
    ds = ds.shuffle(buffer_size=len(df))
  return ds
df_to_dataset(df)

labels:

<ShuffleDataset shapes: ({objid: (), ra: (), dec: (), u: (), g: (), r: (), i: (), z: (), run: (), rerun: (), camcol: (), field: (), specobjid: (), redshift: (), plate: (), mjd: (), fiberid: ()}, ()), types: ({objid: tf.float64, ra: tf.float64, dec: tf.float64, u: tf.float64, g: tf.float64, r: tf.float64, i: tf.float64, z: tf.float64, run: tf.int64, rerun: tf.int64, camcol: tf.int64, field: tf.int64, specobjid: tf.float64, redshift: tf.float64, plate: tf.int64, mjd: tf.int64, fiberid: tf.int64}, tf.string)>
AloneTogether
  • 25,814
  • 5
  • 20
  • 39
Elizabeth Grant
  • 149
  • 1
  • 1
  • 12
  • 1
    Does this answer your question? [Tensorflow error in Colab - ValueError: Shapes (None, 1) and (None, 10) are incompatible](https://stackoverflow.com/questions/62449191/tensorflow-error-in-colab-valueerror-shapes-none-1-and-none-10-are-inco) – Nicolas Gervais Nov 09 '21 at 22:22
  • 1
    @NicolasGervais no – Elizabeth Grant Nov 09 '21 at 22:43

1 Answers1

3

You can either convert your labels to one-hot encoded labels and use the categorical_crossentropy loss function:

one_hot_encoded_train_ds = train_ds.map(lambda x, y: (x, tf.one_hot(y, depth=3)))
one_hot_encoded_val_ds = val_ds.map(lambda x, y: (x, tf.one_hot(y, depth=3)))

Or change your loss function to sparse_categorical_crossentropy and leave your labels the way they are as integers:

model.compile(optimizer='adam',
              loss='sparse_categorical_crossentropy',
              metrics=['accuracy'])

Update: Convert your string labels to integers:

def df_to_dataset(df, shuffle=True, batch_size=32): 
  df = df.copy()
  labels = df.pop('class')
  dicts = {'STAR': 0, 'GALAXY': 1, 'QSO': 2}
  converted_labels = np.array([dicts[l] for l in labels.to_list()])
  ds = tf.data.Dataset.from_tensor_slices((dict(df), converted_labels))
  if shuffle:
    ds = ds.shuffle(buffer_size=len(df))
  return ds
df_to_dataset(df)
AloneTogether
  • 25,814
  • 5
  • 20
  • 39
  • I'm not really sure that I got you right, could you please give an example for sparse_categorical_crossentropy? – Elizabeth Grant Nov 09 '21 at 22:16
  • Updated answer but note that your question will probably be removed because a lot of people have already asked the same or very similar question. The only thing that is unique about your question is that it asks how you can change your labels to one-hot encoded labels after creating `BatchDatasets`. – AloneTogether Nov 10 '21 at 07:32
  • Thank you so much for your response! I've already tried the second one, but it gives me another problem:) Could you please look at the edited question? – Elizabeth Grant Nov 10 '21 at 08:13
  • Can you show me what your labels look like? Print out a few samples of `labels` and add it to your question? – AloneTogether Nov 10 '21 at 08:21
  • Sure! I've edited – Elizabeth Grant Nov 10 '21 at 08:26
  • Yeah ok ...you can only use integer values ...you need to get rid of those strings or encode somehow before feeding them into your model... According to your output layer you only have 3 labels `Dense(3, activation='softmax')`. So I am really not sure what you want to do. – AloneTogether Nov 10 '21 at 08:29
  • Well, the number of neurons in the output layer should be the count of classes, isn't it? (if it's not binary classification) And then the value of each neuron we interpret like possibility of the object to be in the specific class – Elizabeth Grant Nov 10 '21 at 08:38
  • These are just float/int features that tell us if an object is star, quasar or galaxy, the target is only the last column - 'class' – Elizabeth Grant Nov 10 '21 at 08:44