I suggest you train the cat/dog binary classification model independently, as well as the cat breed and dog breed models. Then, you can use a custom Keras model for inference. Here is a working example, you just need to load your own dataset, and adjust the model architectures to your liking.
import numpy as np
import tensorflow as tf
from tensorflow import keras
np.random.seed(1)
tf.random.set_seed(1)
num_images = 200
num_cat_breeds = 10
num_dog_breeds = 15
X_train = np.random.random([num_images, 32, 32, 3])
y_breed = np.random.randint(num_cat_breeds + num_dog_breeds, size=num_images)
y_is_cat = y_breed < num_cat_breeds
y_cat_breed = y_breed[y_is_cat]
y_dog_breed = y_breed[~y_is_cat] - num_cat_breeds
model_cat_or_dog = keras.Sequential([
keras.layers.Conv2D(filters=32, kernel_size=3, activation="relu"),
keras.layers.Flatten(),
keras.layers.Dense(1, activation="sigmoid")
])
model_cat_or_dog.compile(loss="binary_crossentropy", optimizer="adam")
model_cat_or_dog.fit(X_train, y_is_cat, epochs=2)
model_cat_breed = keras.Sequential([
keras.layers.Conv2D(filters=32, kernel_size=3, activation="relu"),
keras.layers.Flatten(),
keras.layers.Dense(num_cat_breeds, activation="softmax")
])
model_cat_breed.compile(loss="sparse_categorical_crossentropy", optimizer="adam")
model_cat_breed.fit(X_train[y_is_cat], y_cat_breed, epochs=2)
model_dog_breed = keras.Sequential([
keras.layers.Conv2D(filters=32, kernel_size=3, activation="relu"),
keras.layers.Flatten(),
keras.layers.Dense(num_dog_breeds, activation="softmax")
])
model_dog_breed.compile(loss="sparse_categorical_crossentropy", optimizer="adam")
model_dog_breed.fit(X_train[~y_is_cat], y_dog_breed, epochs=2)
class BreedModel(keras.Model):
def __init__(self, model_cat_or_dog, model_cat_breed, model_dog_breed, **kwargs):
super().__init__(**kwargs)
self.model_cat_or_dog = keras.models.clone_model(model_cat_or_dog)
self.model_cat_breed = keras.models.clone_model(model_cat_breed)
self.model_dog_breed = keras.models.clone_model(model_dog_breed)
def __call__(self, inputs):
y_proba_is_cat = self.model_cat_or_dog(inputs)
y_is_cat = tf.squeeze(y_proba_is_cat > 0.5)
cat_images = tf.boolean_mask(inputs, y_is_cat)
dog_images = tf.boolean_mask(inputs, ~y_is_cat)
Y_proba_cat_breed = self.model_cat_breed(cat_images)
Y_proba_dog_breed = self.model_dog_breed(dog_images)
return y_is_cat, y_proba_is_cat, Y_proba_cat_breed, Y_proba_dog_breed
num_test_images = 50
X_test = np.random.random([num_test_images, 32, 32, 3])
model = BreedModel(model_cat_or_dog, model_cat_breed, model_dog_breed)
y_is_cat, y_proba_is_cat, Y_proba_cat_breed, Y_proba_dog_breed = model(X_test)