Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Multi class sparse_categorical_crossentropy TruePositives metric Incompatible shapes: [2,128] vs. [2,64]

I'm trying to add various simple metrics for each class. tf.keras.metrics.TruePositives, tf.keras.metrics.Precision ... This results in crash bellow when last Dense layer is two or more.

InvalidArgumentError: Incompatible shapes: [2,128] vs. [2,64]
     [[{{node metrics_12/fp/LogicalAnd}}]]

It works if I only use accuracy as metric. I am pretty sure I'm missing something fundamental. As I am but a dilettante when it come to TensorFlow and Deep Learning. What am I doing wrong? How do I get metrics for each class (True/False positives/negatives mainly)? (Sample code only has 0,1 classes, in real app there are more)

Colab link: https://colab.research.google.com/drive/1aAz1pfN6ttBp8nU6rZgo8OA_Hwdseyg8

#%%

from typing import List, Set, Dict, Tuple, Optional, Any
import numpy as np
import tensorflow as tf
from tensorflow.keras.models import Sequential
from tensorflow.keras.layers import Dense, Dropout, BatchNormalization, CuDNNLSTM, LSTM, Flatten

#%%

# Create random training values for demo purposes.
#
# train_x is [
#   [
#        [0.3, 0.54 ... 0.8],
#        [0.4, 0.6 ... 0.55],
#        ...
#   ],
#   [
#        [0.3, 0.54 ... 0.8],
#        [0.4, 0.6 ... 0.55],
#        ...
#   ],
#   ...
# ]
#
# train_y is corresponding classification of train_x sequences, always 0 or 1
# [0, 1, 0, 1, 0, ... 0]

SAMPLES_CNT = 1000

train_x = np.random.rand(SAMPLES_CNT,5,4)
train_y = np.vectorize(lambda x: int(round(x)))(np.random.rand(SAMPLES_CNT))

val_x = np.random.rand(int(SAMPLES_CNT * 0.1),5,4)
val_y = np.vectorize(lambda x: int(round(x)))(np.random.rand(int(SAMPLES_CNT * 0.1)))

#%%

shape = Tuple[int, int]
model = Sequential()
model.add(LSTM(32,input_shape=train_x.shape[1:], return_sequences=True, stateful=False))
model.add(Dropout(0.2))
model.add(BatchNormalization())
model.add(LSTM(32,input_shape=train_x.shape[1:], return_sequences=False, stateful=False))
model.add(Dropout(0.2))
model.add(BatchNormalization())
model.add(Dense(16, activation="relu"))
model.add(Dropout(0.2))
model.add(Dense(2, activation="softmax"))

metrics = [
    'accuracy',
    tf.keras.metrics.TruePositives(name='tp'),
    tf.keras.metrics.FalsePositives(thresholds=[0.5, 0.5], name='fp'),
    tf.keras.metrics.TrueNegatives(name='tn'),
    tf.keras.metrics.FalseNegatives(name='fn'),
    tf.keras.metrics.Precision(name='precision'),
    tf.keras.metrics.Recall(name='recall'),
    tf.keras.metrics.AUC(name='auc'),
]

model.compile(
    optimizer=tf.keras.optimizers.Adam(lr=0.001, decay=1e-6),
    loss='sparse_categorical_crossentropy',
    metrics=metrics
)

fit = model.fit(
    train_x, train_y,
    batch_size=64,
    epochs=2,
    validation_data=(val_x, val_y),
    shuffle=False,
)

for i, val in enumerate(model.metrics_names):
    print(model.metrics_names[i], fit.history[val][:1])

like image 312
stringCode Avatar asked Nov 16 '25 04:11

stringCode


1 Answers

Some of these metrics are supposed to work with one class only.

You need Dense(1, activation='sigmoid') and 'binary_crossentropy'.

Notice that these two problems are exactly the same:

  • Dense(1, activation='sigmoid'), with loss='binary_crossentropy'
  • Dense(2, activation='softmax'), with loss='sparse_categorical_crossentropy'
like image 54
Daniel Möller Avatar answered Nov 17 '25 22:11

Daniel Möller



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!