import tensorflow as tf from keras._tf_keras.keras.utils import image_dataset_from_directory from keras._tf_keras.keras import Sequential, layers, models import numpy as np import os img_size = (224, 224) batch_size = 32 AUTOTUNE = tf.data.AUTOTUNE normalization_layer = layers.Rescaling(1./255) def preprocess_ds(ds, training=True): ds = ds.map(lambda x, y: (normalization_layer(x), y)) if training: ds = ds.cache().shuffle(1000).prefetch(buffer_size=AUTOTUNE) else: ds = ds.cache().prefetch(buffer_size=AUTOTUNE) return ds def build_model(num_classes): model = models.Sequential([ layers.Conv2D(32, (3, 3), activation="relu", input_shape=img_size + (3,)), layers.MaxPooling2D((2, 2)), layers.Conv2D(64, (3, 3), activation="relu"), layers.MaxPooling2D((2, 2)), layers.Conv2D(128, (3, 3), activation="relu"), layers.MaxPooling2D((2, 2)), layers.Flatten(), layers.Dense(128, activation="relu"), layers.Dropout(0.3), layers.Dense(num_classes, activation="softmax") ]) model.compile(optimizer="adam", loss="sparse_categorical_crossentropy", metrics=["accuracy"]) return model stage1_train = image_dataset_from_directory( "MelSpectrograms", labels="inferred", label_mode="int", validation_split=0.2, subset="training", seed=42, image_size=img_size, batch_size=batch_size ) stage1_val = image_dataset_from_directory( "MelSpectrograms", labels="inferred", label_mode="int", validation_split=0.2, subset="validation", seed=42, image_size=img_size, batch_size=batch_size ) stage1_classes = stage1_train.class_names print("Stage 1 Classes:", stage1_classes) stage1_train = preprocess_ds(stage1_train, training=True) stage1_val = preprocess_ds(stage1_val, training=False) print("Training Stage 1 (Normal vs Abnormal)...") stage1_model = build_model(len(stage1_classes)) stage1_model.fit(stage1_train, validation_data=stage1_val, epochs=10) abnormal_train = image_dataset_from_directory( "MelSpectrograms/00 - Abnormal", labels="inferred", label_mode="int", validation_split=0.2, subset="training", seed=42, image_size=img_size, batch_size=batch_size ) abnormal_val = image_dataset_from_directory( "MelSpectrograms/00 - Abnormal", labels="inferred", label_mode="int", validation_split=0.2, subset="validation", seed=42, image_size=img_size, batch_size=batch_size ) abnormal_classes = abnormal_train.class_names print("Stage 2 Abnormal Classes:", abnormal_classes) abnormal_train = preprocess_ds(abnormal_train, training=True) abnormal_val = preprocess_ds(abnormal_val, training=False) print("Training Stage 2 (Abnormal)...") abnormal_model = build_model(len(abnormal_classes)) abnormal_model.fit(abnormal_train, validation_data=abnormal_val, epochs=10) normal_train = image_dataset_from_directory( "MelSpectrograms/01 - Normal", labels="inferred", label_mode="int", validation_split=0.2, subset="training", seed=42, image_size=img_size, batch_size=batch_size ) normal_val = image_dataset_from_directory( "MelSpectrograms/01 - Normal", labels="inferred", label_mode="int", validation_split=0.2, subset="validation", seed=42, image_size=img_size, batch_size=batch_size ) normal_classes = normal_train.class_names print("Stage 2 Normal Classes:", normal_classes) normal_train = preprocess_ds(normal_train, training=True) normal_val = preprocess_ds(normal_val, training=False) print("Training Stage 2 (Normal)...") normal_model = build_model(len(normal_classes)) normal_model.fit(normal_train, validation_data=normal_val, epochs=10) class HierarchicalClassifier: def __init__(self, stage1_model, abnormal_model, normal_model, stage1_classes, abnormal_classes, normal_classes, img_size=(224, 224)): self.img_size = img_size self.stage1_model = stage1_model self.abnormal_model = abnormal_model self.normal_model = normal_model self.stage1_classes = stage1_classes self.abnormal_classes = abnormal_classes self.normal_classes = normal_classes def preprocess(self, image_path): img = tf.keras.utils.load_img(image_path, target_size=self.img_size) img_array = tf.keras.utils.img_to_array(img) / 255.0 img_array = tf.expand_dims(img_array, 0) return img_array def predict(self, image_path): img_array = self.preprocess(image_path) stage1_pred = self.stage1_model.predict(img_array) stage1_idx = np.argmax(stage1_pred) main_class = self.stage1_classes[stage1_idx] if main_class == "00 - Abnormal": sub_pred = self.abnormal_model.predict(img_array) sub_idx = np.argmax(sub_pred) sub_class = self.abnormal_classes[sub_idx] else: sub_pred = self.normal_model.predict(img_array) sub_idx = np.argmax(sub_pred) sub_class = self.normal_classes[sub_idx] return { "stage1_class": main_class, "stage1_confidence": float(np.max(stage1_pred)), "stage2_class": sub_class, "stage2_confidence": float(np.max(sub_pred)), "final_prediction": f"{main_class} → {sub_class}" } # classifier = HierarchicalClassifier(stage1_model, abnormal_model, normal_model, # stage1_classes, abnormal_classes, normal_classes) # result = classifier.predict("MelSpectrograms/00 - Abnormal/00-2 - Dehydration mode noise/01.png") # print(result["final_prediction"]) # Save models after training os.makedirs("saved_models", exist_ok=True) stage1_model.save("saved_models/stage1_model.h5") abnormal_model.save("saved_models/abnormal_model.h5") normal_model.save("saved_models/normal_model.h5") print("✅ Models saved in 'saved_models/' folder")